如何使用 libavcodec/x264 对 h.264 进行编码?
Posted
技术标签:
【中文标题】如何使用 libavcodec/x264 对 h.264 进行编码?【英文标题】:How to encode h.264 with libavcodec/x264? 【发布时间】:2011-04-02 22:52:03 【问题描述】:我正在尝试使用 libavcodec/libavformat 对视频进行编码。音频效果很好,但是当我尝试对视频进行编码时,出现以下错误:
[libx264 @ 0x10182a000]broken ffmpeg default settings detected
[libx264 @ 0x10182a000]use an encoding preset (vpre)
使用命令行 ffmpeg 很容易修复,但我正在尝试在 C 中执行此操作。 我的选择是
AVStream *pVideoOutStream = av_new_stream(pOutFormatCtx, 0);
AVCodecContext *pVideoOutCodecCtx = pVideoOutStream->codec;
pVideoOutCodecCtx->codec_id = CODEC_ID_H264;
pVideoOutCodecCtx->codec_type = CODEC_TYPE_VIDEO;
pVideoOutCodecCtx->bit_rate = pVideoInCodecCtx->bit_rate;
pVideoOutCodecCtx->width = pVideoInCodecCtx->width;
pVideoOutCodecCtx->height = pVideoInCodecCtx->height;
pVideoOutCodecCtx->pix_fmt = pVideoInCodecCtx->pix_fmt;
pVideoOutCodecCtx->sample_rate = pVideoInCodecCtx->sample_rate;
pVideoOutCodecCtx->gop_size = 30;
但 avcodec_open() 失败。
我还需要设置哪些其他值才能使 x264 满意?
【问题讨论】:
查看工作示例:官方github.com/FFmpeg/FFmpeg/tree/n3.0/doc/examples,我的:***.com/a/36405714/895245 【参考方案1】:不要忘记使用 x264 私有选项。 您可以随时设置个人资料:
av_dict_set(&This->opts, "vprofile", "baseline", 0)
或者设置最低编码延迟:
av_dict_set(&This->opts, "tune", "zerolatency", 0);
或者选择一个预设:
av_dict_set(&This->opts, "preset","ultrafast",0);
在打开编解码器之前
avcodec_open2(This->context, This->codec, &This->opts)
【讨论】:
【参考方案2】:以下是如何解读ffmpeg的x264预设。
不幸的是,我不知道像 ffmpeg 那样导入预设的简单方法。 您可以查找所有存储在 /usr/local/share/ffmpeg/libx264-name.ffpreset 中的 x264 预设值,其中 name 为 ffmpeg 指定为 -vpre name 命令行参数。 所以通常 ffmpeg 会包含 libx264-medium.ffpreset 然后是 libx264-main.ffpreset,指定为 ffmpeg -vpre medium -vpre main
您可以通过查看 libavcodec/options.c 文件来查找所有选项(如 libx264-name.ffpreset 文件中定义的)以获取其结构名称,该文件可在 ffmpeg SVN 存储库中找到。
下面是媒介和主要预设如何被翻译成 C 代码:
// libx264-medium.ffpreset preset
ctx->coder_type = 1; // coder = 1
ctx->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop
ctx->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1
ctx->partitions|=X264_PART_I8X8+X264_PART_I4X4+X264_PART_P8X8+X264_PART_B8X8; // partitions=+parti8x8+parti4x4+partp8x8+partb8x8
ctx->me_method=ME_HEX; // me_method=hex
ctx->me_subpel_quality = 7; // subq=7
ctx->me_range = 16; // me_range=16
ctx->gop_size = 250; // g=250
ctx->keyint_min = 25; // keyint_min=25
ctx->scenechange_threshold = 40; // sc_threshold=40
ctx->i_quant_factor = 0.71; // i_qfactor=0.71
ctx->b_frame_strategy = 1; // b_strategy=1
ctx->qcompress = 0.6; // qcomp=0.6
ctx->qmin = 10; // qmin=10
ctx->qmax = 51; // qmax=51
ctx->max_qdiff = 4; // qdiff=4
ctx->max_b_frames = 3; // bf=3
ctx->refs = 3; // refs=3
ctx->directpred = 1; // directpred=1
ctx->trellis = 1; // trellis=1
ctx->flags2|=CODEC_FLAG2_BPYRAMID+CODEC_FLAG2_MIXED_REFS+CODEC_FLAG2_WPRED+CODEC_FLAG2_8X8DCT+CODEC_FLAG2_FASTPSKIP; // flags2=+bpyramid+mixed_refs+wpred+dct8x8+fastpskip
ctx->weighted_p_pred = 2; // wpredp=2
// libx264-main.ffpreset preset
ctx->flags2|=CODEC_FLAG2_8X8DCT;c->flags2^=CODEC_FLAG2_8X8DCT; // flags2=-dct8x8
如果你想自动解析这些预设,你必须查看 ffmpeg 源代码。
我希望我刚才提供的信息能对你有所帮助:)
【讨论】:
感谢您清除 ffpreset 文件中的值与 AVCodecContext 设置之间的映射...乍一看绝对不明显 :)【参考方案3】:不确定你是否让它工作,但以下参数对我有用。
ctx->bit_rate = 500*1000;
ctx->bit_rate_tolerance = 0;
ctx->rc_max_rate = 0;
ctx->rc_buffer_size = 0;
ctx->gop_size = 40;
ctx->max_b_frames = 3;
ctx->b_frame_strategy = 1;
ctx->coder_type = 1;
ctx->me_cmp = 1;
ctx->me_range = 16;
ctx->qmin = 10;
ctx->qmax = 51;
ctx->scenechange_threshold = 40;
ctx->flags |= CODEC_FLAG_LOOP_FILTER;
ctx->me_method = ME_HEX;
ctx->me_subpel_quality = 5;
ctx->i_quant_factor = 0.71;
ctx->qcompress = 0.6;
ctx->max_qdiff = 4;
ctx->directpred = 1;
ctx->flags2 |= CODEC_FLAG2_FASTPSKIP;
错误消息broken ffmpeg default settings detected
显示在x264/encoder/encoder.c 的x264 库中,当太多设置是默认的ffmpeg 设置(例如qmin = 2, qmax = 31, qcompress = 0.5
)时,将这三个值更改为其他值,例如qmin = 10, qmax = 51, qcompress = 0.6
,解决了错误。
【讨论】:
我需要更深入地了解ctx->flags
和ctx->flags2
。我在哪里可以找到?
之后我遇到了Malformed AAC bitstream detected
问题【参考方案4】:
我使用不同的编解码器将 YUV420P 图片编码为不同的格式。使用 guess_format(...) 函数后我从 AVOutputFormat 获取的 CodecID。但其他编解码器设置是 (全部取自 ffmpeg 示例的源代码):
c->codec_id = (CodecID)CODEC_ID_H264; //This is your codec id
c->codec_type = CODEC_TYPE_VIDEO;
c->bit_rate = 1000000;
c->width = <...>;
c->height = <...>;
c->time_base.den = 25;
c->time_base.num = 1;
c->gop_size = 12;
c->pix_fmt = PIX_FMT_YUV420P;
if (c->codec_id == CODEC_ID_MPEG1VIDEO) //It not necessary for you
c->mb_decision=2;
// some formats want stream headers to be separate
if(oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
此设置必须适用于大多数编解码器,但我遇到了 fps 问题:并非所有编解码器都支持任何 fps 值(以及一些其他参数)。
【讨论】:
谢谢!我今天会尝试一下,看看会发生什么。 嗨,c->flags |= CODEC_FLAG_GLOBAL_HEADER
是否也应该设置为流媒体目的?它能做什么?它会重复(或一次)将此 Non-VCL 标头添加到 VCL 有效负载中,还是单独提供 non-VCL NALU 数据,我们应该单独发送?【参考方案5】:
似乎 ffmpeg 版本 20130302 需要类似的东西
c->profile = FF_PROFILE_H264_BASELINE;
【讨论】:
以上是关于如何使用 libavcodec/x264 对 h.264 进行编码?的主要内容,如果未能解决你的问题,请参考以下文章