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..... = VideoA..... = AudioS..... = 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..... = VideoA..... = AudioS..... = 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的标准很简单,那些提供了decode或receive_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=$1pattern=$2file=$source_path/$3out=${4:-$thing}sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$out/p" "$file"}find_filters_extern(){file=$source_path/$1sed -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"
文章评论