FFmpeg 4.0解码H264比旧版本(n2.8.14)慢。

3
我使用ffmpeg解码h264并将其转换为jpeg。
我之前使用的是2.8版本,现在改用4.0版本。
新版本中avcodec_decode_video2已经弃用,所以我使用了新的API(send、receive)。
我发现新版本的ffmpeg在解码h264时比旧版本要慢得多。
为什么会这样?如何恢复原有速度?
以下是解码器初始化代码:
version 2.8
//2.8
if (avformat_open_input(&format_, path, NULL, &options) != 0) {
    printf("FileMediaBase: open input failed\n");
    return -1;
}
if (avformat_find_stream_info(format_, NULL) < 0) {
    printf("FileMediaBase: avformat_find_stream_info failed\n");
    avformat_close_input(&format_);
    return -1;
}
AVCodecContext *code_ctx = 0;
AVCodec *codec = 0;
// Find the first audio and video stream
for (int i = 0; i < format_->nb_streams; i++) {
    code_ctx = format_->streams[i]->codec;
    codec = avcodec_find_decoder(code_ctx->codec_id);
    if (code_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
        vcode_ctx_ = code_ctx;
        vstream_ = format_->streams[i];
    }else if (code_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
        acode_ctx_ = code_ctx;
        astream_ = format_->streams[i];
    }
    // Open the codec
    if (!codec || (avcodec_open2(code_ctx, codec, NULL) < 0)) {
        printf("avcodec_open2() failed\n");
        avformat_close_input(&format_);
        return -1;
    }

版本 4.0

if (avformat_open_input(&format_, path, NULL, &options) != 0) {
    printf("FileMediaBase: open input failed\n");
    return -1;
}
if (avformat_find_stream_info(format_, NULL) < 0) {
    printf("FileMediaBase: avformat_find_stream_info failed\n");
    avformat_close_input(&format_);
    return -1;
}
AVStream *st;
AVCodec *dec = NULL;
AVDictionary *opts = NULL;

ret = av_find_best_stream(format_, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (ret < 0) {
    return ret;
}
else {
    stream_index = ret;
    st = format_->streams[stream_index];

    /* find decoder for the stream */
    dec = avcodec_find_decoder(st->codecpar->codec_id);
    if (!dec) {
        fprintf(stderr, "Failed to find %s codec\n",
            av_get_media_type_string(type));
        return AVERROR(EINVAL);
    }

    /* Allocate a codec context for the decoder */
    *dec_ctx = avcodec_alloc_context3(dec);
    if (!*dec_ctx) {
        fprintf(stderr, "Failed to allocate the %s codec context\n",
            av_get_media_type_string(type));
        return AVERROR(ENOMEM);
    }

    /* Copy codec parameters from input stream to output codec context */
    if ((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) {
        fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",
            av_get_media_type_string(type));
        avcodec_free_context(dec_ctx);
        return ret;
    }

    /*if (dec->id == AV_CODEC_ID_H264) {
        (*dec_ctx)->flags |= AV_CODEC_FLAG_TRUNCATED;
    }*/

    /* Init the decoders, with or without reference counting */
    //av_dict_set(&opts, "refcounted_frames", refcount ? "1" : "0", 0);
    if ((ret = avcodec_open2(*dec_ctx, dec, &opts)) < 0) {
        fprintf(stderr, "Failed to open %s codec\n",
            av_get_media_type_string(type));
        avcodec_free_context(dec_ctx);
        return ret;
    }

我打印出了一些API所花费的时间。
在此输入图片描述

尝试使用libav ML - http://ffmpeg.org/mailman/listinfo/libav-user - Gyan
现在该项目不仅由我进行维护,其他人也在使用相同的共享库,除非其他人同意替换为libav。 - somebytes
libav-user 邮件列表是用于涉及 FFmpeg libav* 库的用户问题。它与 Libav 分支没有任何关系(因为他们选择了一个已被 FFmpeg 使用的名称,给用户带来了不便)。 - llogan
2个回答

6

我已经解决了这个问题,将解码线程的数量更改为6个(在版本4.0中默认为1个,在版本2.8中默认为6个)。

(*dec_ctx)->thread_count = 6;

这太蠢了。我一直在使用更新版本的FFMPEG,却不知道为什么avcodec_send_packet运行比旧版本的FFMPEG慢得多,原因是默认线程数为1。感谢您的答案。 - user654628

5

在使用ffmpeg 2.8.14和4.0.1版本解码h264视频流时,我遇到了同样的问题。在调用avformat_find_stream_info()函数后,无论哪种情况下访问编解码器上下文都会出现问题。

AVFormatContext *pFormatCtx;
AVCodecContext* pCodecCtxOrig;
...
avformat_find_stream_info(pFormatCtx, NULL)
...
for (uint i = 0; i < pFormatCtx->nb_streams; i++)
{
  if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  {
    pCodecCtxOrig = pFormatCtx->streams[i]->codec;
    ...

  }
}

如果使用avcodec_open2()打开编解码器上下文,那么pCodecCtxOrig::thread_count实际上会被设置为0,这意味着ffmpeg库会根据CPU核心自行确定适合的线程数。在我的情况下,线程数被设置为5。

而在2.8.14版本中,pCodecCtxOrig::thread_count被设置为0,当从中进行复制时

AVCodecContext* pCodecCtxOrig;
AVCodecContext* pCodecCtx;
....
avcodec_copy_context(pCodecCtx, pCodecCtxOrig)

线程数也会被复制。

在4.0.1版本中,avcodec_copy_context()已经被弃用,应该使用avcodec_parameters_to_context()。复制结构体AVCodecParameters不包含线程数信息,因此该信息会丢失。线程数仍然保持默认值1,由avcodec_alloc_context3设置。为了解决这个问题,在打开编解码器上下文之前将thread_count设置为0。


这真的很有帮助,将thread_count设置为0就可以解决问题了。 - neevek

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