FFMPEG编解码器

2022年9月8日 249点热度 0人点赞 0条评论

1. 列举

业界通用的编解码器有很多,有的纯粹用软件比如x264,有的依赖硬件,比如Nvidia的NVENC开发包使用自家显卡GPU加速,Intel的Quick Sync开发包使用Intel CPU上集成的GPU加速。

ffmpeg通过封装上述第三方编解码器,和少数自身实现的编解码器,抽象定义出一个AVCodec结构体,并支持通过命令ffmpeg -decoders来列举支持的所有解码器,由于内容太多,下面使用ffmpeg -decoders | grep h264来显示h264解码器:

VFS..D h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10V....D h264_qsv             H264 video (Intel Quick Sync Video acceleration) (codec h264)V..... h264_cuvid           Nvidia CUVID H264 decoder (codec h264)

第一个的解码实现是ffmpeg官方开发。通过名字也可以看出来,第二个基于Intel QSV,第三个基于Nvidia显卡。每个解码器开头部分的含义如下,当命令行中通过管道使用grep后,这些输出被过滤了:

Decoders:V..... = Video A..... = Audio S..... = Subtitle .F.... = Frame-level multithreading ..S... = Slice-level multithreading ...X.. = Codec is experimental ....B. = Supports draw_horiz_band .....D = Supports direct rendering method 1

同理,使用ffmpeg -encoders | grep h264显示h264编码器:

V..... libx264              libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (codec h264)V....D h264_amf             AMD AMF H.264 Encoder (codec h264)V....D h264_mf              H264 via MediaFoundation (codec h264)V....D h264_nvenc           NVIDIA NVENC H.264 encoder (codec h264)V..... h264_qsv             H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration) (codec h264)V..... nvenc                NVIDIA NVENC H.264 encoder (codec h264)V..... nvenc_h264           NVIDIA NVENC H.264 encoder (codec h264)

第一个基于x264,带qsv字样的基于Intel QSV,带nvenc字样的基于Nvidia显卡。开头部分的含义如下:

Encoders:V..... = Video A..... = Audio S..... = Subtitle .F.... = Frame-level multithreading ..S... = Slice-level multithreading ...X.. = Codec is experimental ....B. = Supports draw_horiz_band .....D = Supports direct rendering method 1

2. AVCodec

每个编解码器通过定义自己的AVCodec结构体变量,提供名称,类型、CodecId、若干关键回调函数等描述自身数据,使得外部访问者只要找到对应编解码器的AVCodec,即可屏蔽不同实现的差异:

Type

  • 音频AVMEDIA_TYPE_AUDIO

  • 视频AVMEDIA_TYPE_VIDEO

  • 字幕AVMEDIA_TYPE_AUDIO

CodecId

  • AV_CODEC_ID_H264

  • AV_CODEC_ID_AC3

回调函数

  • init

  • close

  • flush

  • receive_packet

  • decode

  • receive_frame

区分AVCodec的标准很简单,那些提供了decodereceive_frame函数指针的AVCodec代表解码器,否则就是编码器。下面是FFMPEG内置的h264解码器(采用CPU解码)定义,源自libavcodec/h264dec.c,只保留了关键数据:

AVCodec ff_h264_decoder = {    .name                  = "h264",    .long_name             = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),    .type                  = AVMEDIA_TYPE_VIDEO,    .id                    = AV_CODEC_ID_H264,    .priv_data_size        = sizeof(H264Context),    .init                  = h264_decode_init,    .close                 = h264_decode_end,    .decode                = h264_decode_frame,    .capabilities          = /*AV_CODEC_CAP_DRAW_HORIZ_BAND |*/ AV_CODEC_CAP_DR1 |AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS |AV_CODEC_CAP_FRAME_THREADS,                               HWACCEL_DXVA2(h264),    .caps_internal         = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING |                             FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP,    .flush                 = h264_decode_flush,    .update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context),    .profiles              = NULL_IF_CONFIG_SMALL(ff_h264_profiles),    .priv_class            = &h264_class,};

3. 硬件加速之Nvidia NvENC

ffmpeg支持Nvidia NvENC硬件编解码h264、h265、av1、vp9等多种视频格式,其在libavcodec/cuviddec.c中为每种视频格式分别定义不同的解码器对应AVCodec变量:

  • ff_av1_cuvid_decoder

  • ff_h264_cuvid_decoder

  • ff_hevc_cuvid_decoder

  • ff_vp9_cuvid_decoder

每个变量中的name字符串对应ffmpeg -decoders | grep cuvid列举出来的解码器名称:

  • av1_cuvid

  • h264_cuvid

  • hevc_cuvid

  • vp9_cuvid

4. 编解码器数组codec_list

在libavcodec/allcodecs.c中通过extern语法逐个声明散落在不同源代码中编解码器的变量,比如:

extern AVCodec ff_av1_cuvid_decoder;extern AVCodec ff_h264_cuvid_decoder;extern AVCodec ff_hevc_cuvid_decoder;extern AVCodec ff_vp9_cuvid_decoder;

随后执行configure时提取名称带encoder的编码器变量名填充到codec_list.c数组,同理继续提取解码器并填充,此后codec_list.c数组包含了ffmpeg支持的所有编解码器,并由libavcodec/allcodecs.c提供API来访问她。

下面是脚本中对应代码:

find_things_extern(){    thing=$1    pattern=$2    file=$source_path/$3    out=${4:-$thing}    sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$out/p" "$file"}
find_filters_extern(){ file=$source_path/$1 sed -n 's/^extern AVFilter ff_[avfsinkrc]\{2,5\}_\([[:alnum:]_]\{1,\}\);/\1_filter/p' $file}
ENCODER_LIST=$(find_things_extern encoder AVCodec libavcodec/allcodecs.c)DECODER_LIST=$(find_things_extern decoder AVCodec libavcodec/allcodecs.c)CODEC_LIST=" $ENCODER_LIST $DECODER_LIST"

82470FFMPEG编解码器

这个人很懒,什么都没留下

文章评论