FFMPEG解码过慢(avcodec_send_packet() / avcodec_receive_frame())

8
我正在使用ffmpeg库来解码、缩放和重新编码MPEG传输流中的视频。我刚刚从源代码重新编译到v3.3.2,并从旧的avcodec_decode_video2() API更改为新的send/receive API。无论是旧API还是新API,都会非常慢地解码视频。
25fps的视频=每40ms 1帧。然而,我看到每帧需要70至120毫秒的时间进行解码。这是一个文件转换器,所以需要它比实时运行更快。
以下是代码概述。有没有人有任何想法如何提高解码速度?有关弃用的avcodec_decode_video2()速度慢的其他帖子,没有一个得到解决。新API也不会更快...
gettimeofday(&tv1, NULL);
int rc = av_read_frame(pFormatContext, pESPacket);
gettimeofday(&tv2, NULL);

int ret = avcodec_send_packet(pDecoderContext, pESPacket);
if (ret < 0)
    continue;

ret = avcodec_receive_frame(pDecoderContext, pFrameDec);
if (ret != 0)
{
    printf("avcodec_receive_frame error: %d\n", ret);
    continue;
}
gettimeofday(&tv3, 0);

u_long twoMinusOne   = (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec;
u_long threeMinusTwo = (tv3.tv_sec - tv2.tv_sec) * 1000000 + tv3.tv_usec - tv2.tv_usec;

size_t pktSize = mPacketQueue.getTsPktListSize();
printf("  DECODE ReadFrame %lu usec, DecodeVideo %lu usec. mTsPacketList %u items\n", twoMinusOne, threeMinusTwo, pktSize);

transcodeFrame(pFrameDec);

// Scale and re-encode //
-- call avscale to downsample
-- call avcodec_encode_video2() to encode

一些输出

DECODE ReadFrame 6 usec, DecodeVideo 154273 usec.
Dump mpFrameEnc with DateTime: 
  AVFrame Info frame 720 X 406. PTS = 305700353  PKT_PTS = 305700353 Linesize[0]=720. Linesize[1]=360. Linesize[2]=360.   
Time taken to ENCODE video frame = 3685 usec. Scaling time 4 usec

DECODE ReadFrame 8 usec, DecodeVideo 128203 usec.
Time taken to ENCODE video frame = 3724 usec. Scaling time 3 usec

DECODE ReadFrame 8 usec, DecodeVideo 69321 usec.
Time taken to ENCODE video frame = 3577 usec. Scaling time 3 usec

FFMPEG版本

测试运行在双核2.3 GHz,32位Centos 6系统上。

bin/ffmpeg
ffmpeg version 3.3.2 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 4.4.7 (GCC) 20120313 (Red Hat 4.4.7-11)
  configuration: --prefix=/mnt/swdevel/DVStor/source_build/ext/ffmpeg-build --libdir=/mnt/swdevel/DVStor/source_build/ext/ffmpeg-build/lib3p_build --shlibdir=/mnt/swdevel/DVStor/source_build/ext/ffmpeg-build/lib3p_build --disable-static --enable-shared --disable-cuda --disable-cuvid --disable-nvenc --enable-libx264 --enable-gpl --extra-cflags=-I/usr/local/include/libx264
  libavutil      55. 58.100 / 55. 58.100
  libavcodec     57. 89.100 / 57. 89.100
  libavformat    57. 71.100 / 57. 71.100
  libavdevice    57.  6.100 / 57.  6.100
  libavfilter     6. 82.100 /  6. 82.100
  libswscale      4.  6.100 /  4.  6.100
  libswresample   2.  7.100 /  2.  7.100
  libpostproc    54.  5.100 / 54.  5.100
Hyper fast Audio and Video encoder

你是在同一线程上抓取数据包、解码帧、缩放和编码吗? - WLGfx
一个线程用TS包填充队列,但代码中没有显示。第二个线程使用AVIO来读取帧,解码,然后编码。但真正的问题是,当输入一帧时,解码器需要很长时间。 - Danny
1
你好丹尼!我现在也面临着ffmpeg解码速度缓慢的问题。我很好奇你是否找到了解决这个问题的方法?如果找到了,请告诉我。谢谢。 - Eugene Alexeev
2个回答

6
一个未来参考的可能解决方案如下:
为解码器启用多线程。默认情况下,解码器只使用一个线程,根据解码器的不同,多线程可以极大地加速解码。
假设您有AVFormatContext *format_ctx、匹配的编解码器AVCodec* codecAVCodecContext* codec_ctx(使用avcodec_alloc_context3分配)。
在打开编解码上下文(使用avcodec_open2)之前,您可以配置多线程。检查编解码器的功能以决定可以使用哪种类型的多线程。
// set codec to automatically determine how many threads suits best for the decoding job
codec_ctx->thread_count = 0;

if (codec->capabilities & AV_CODEC_CAP_FRAME_THREADS)
   codec_ctx->thread_type = FF_THREAD_FRAME;
else if (codec->capabilities & AV_CODEC_CAP_SLICE_THREADS)
   codec_ctx->thread_type = FF_THREAD_SLICE;
else
   codec_ctx->thread_count = 1; //don't use multithreading

1
你是不是想写 if (codec->capabilities & AV_CODEC_CAP_FRAME_THREADS)(即使用 & 而不是 |)?我认为你现有的代码总是在使用 FF_THREAD_FRAME - Alexis Wilke
1
@AlexisWilke 没错,我已经相应地更改了代码。 - imikbox

0

如果您仍在寻求帮助。

根据视频的像素格式,VLC 可能会使用 GPU 进行解码。为确保您使用 GPU-Z(仅适用于 Windows,Linux 有类似工具)来测量视频负载引擎。 如果是这种情况,您可能需要检查您的库是否支持 GPU 编码/解码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接