预置模块
协议protocol
URLContext - av_class是预置ffurl_context_class;
预置URLProtocol,对应外部URLContext (url_protocols预置列表,包含ff_file_protocol)
URLContext- prot和priv_data ,以file为例,分别为ff_file_protocol和FileContext对象指针;
原生protocols.c包含所有的URLProtocol,新生protocol_list.c包含预置的URLProtocol;
ff_file_protocol 如下:(详见file.c)
const URLProtocol ff_file_protocol = {
.name = "file",
.url_open = file_open,
.url_read = file_read,
.url_write = file_write,
.url_seek = file_seek,
.url_close = file_close,
.url_get_file_handle = file_get_handle,
.url_check = file_check,
.url_delete = file_delete,
.url_move = file_move,
.priv_data_size = sizeof(FileContext),
.priv_data_class = &file_class,
.url_open_dir = file_open_dir,
.url_read_dir = file_read_dir,
.url_close_dir = file_close_dir,
.default_whitelist = "file,crypto,data"
};
AVFormatContext聚合了AVIOContext(pb),AVIOContext聚合了URLContext(opaque)
创建URLContext,成员prot关联URLProtocol,成员priv_data关联FileContext(file文件协议,只是分配大小,根据业务强转对应Context),详见avio.c的url_alloc_for_protocol函数)
创建AVIOContext,ffio_fdopen内部avio_alloc_context,实际通过ffio_init_context关联URLContext
常见协议包含:file(file.c) crypto(crypto.c) http(http.c) rtp(rtpproto.c)等
查看FileContext对应AVClass(priv_data_class)的AVOption设置项,avio_open2通过字典设置;
解封装demuxer和封装muxer
AVFormatContext - av_class是预置av_format_context_class;
AVFormatContext - iformat和priv_data(以mp4为例,分别为ff_mov_demuxer和MOVContext)
预置AVInputFormat,获取预置(详见新生demuxer_list.c)
// iterate - all AVInputFormat
const AVInputFormat* pIFormat = NULL;
void* iter = NULL;
while ((pIFormat = av_demuxer_iterate(&iter))){ ; }
ff_mov_demuxer 如下:(详见movenc.c)
// 描述信息,私有数据,读取操作,标志
AVInputFormat ff_mov_demuxer = {
.name = "mov,mp4,m4a,3gp,3g2,mj2",
.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
.priv_class = &mov_class,
.priv_data_size = sizeof(MOVContext),
.extensions = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v",
.read_probe = mov_probe,
.read_header = mov_read_header,
.read_packet = mov_read_packet,
.read_close = mov_read_close,
.read_seek = mov_read_seek,
.flags = AVFMT_NO_BYTE_SEEK | AVFMT_SEEK_TO_PTS,
};
// 第一步 mov_probe
// 通过mov_probe、extensions和mime_type来决定迭代出的demuxer是否符合
// 第二步 mov_read_header
// 从mov_read_default开始读取box,读取size和type进入mov_read_xxx
// mov_read_xxx是容器box,又进入mov_read_default
// 其中mov_read_trak内部avformat_new_stream
AVFormatContext - oformat和priv_data(以mp4为例,分别为ff_mov_muxer和MOVMuxContext)
预置AVOutputFormat,获取预置(详见新生muxer_list.c)
ff_mov_muxer 如下:(详见movenc.c)
AVOutputFormat ff_mov_muxer = {
.name = "mov",
.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
.extensions = "mov",
.priv_data_size = sizeof(MOVMuxContext),
.audio_codec = AV_CODEC_ID_AAC,
.video_codec = CONFIG_LIBX264_ENCODER ?
AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
.init = mov_init,
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
.deinit = mov_free,
.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
.codec_tag = ...
.check_bitstream = mov_check_bitstream,
.priv_class = &mov_muxer_class,
};
成员解释
priv_data_size用于分配空间返回的指针给priv_data(MOVMuxContext *mov = s->priv_data)
priv_class是AVClass指针用于抽象设置相关参数AVOption(static const AVOption options[])
函数说明
init_muxer 用于通过AVDictionary初始化muxer,从字典中取出键值对,通过键对比从priv_data的AVClass的默认AVOption找出默认配置,并设置到priv_data成员中。例如{ "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}表明frag_size用于设置MOVMuxContext结构体中max_fragment_size的成员。
解码decoder和编码encoder
AVCodecContext - av_class是预置avcodec_options;
预置AVCodec,对应外部AVCodecContext,获取预置
// iterate - all AVCodec
const AVCodec *pCodec = NULL;
void *iter = NULL;
while ((pCodec = av_codec_iterate(&iter))) { ; }
// AVCodec - h264_cuvid h264_qsv h264
AVCodec* pVideoCodec = avcodec_find_decoder_by_name("h264");
AVCodec* pVideoCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
AVCodecContext生命周期(类似面向对象的说法),AVCodec成员priv_data_size和priv_class决定了它的priv_data(强转AVClass)
AVCodecContext - codec和priv_data (以h264为例,分别为ff_h264_decoder和H264Context对象指针)
// alloc open - 通过预置解码器分配解码对象,然后设置参数,再打开
AVCodecContext* pVideoCodecCtx = avcodec_alloc_context3(pVideoCodec);
avcodec_parameters_to_context(pVideoCodecCtx, codecparamter); // 非必须
avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL);
// use - 送AVPacket收AVFrame
avcodec_send_packet(pVideoCodecCtx, &sMediapacket);
avcodec_receive_frame(pVideoCodecCtx, pMediaFrame);
// close free -
avcodec_close(pVideoCodecCtx);
avcodec_free_context(&pVideoCodecCtx);
pVideoCodecCtx = NULL;
ff_h264_decoder 中priv_data_size赋值决定了AVCodecContext的priv_data 如下:
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,
......
.priv_class = &h264_class,
}
av_codec_is_decoder(pCodec);
av_codec_is_encoder(pCodec);
ff_alloc_extradata和ff_get_extradata
ff_h2645_extract_rbsp 从内存中nalu读到H2645NAL结构体
ff_h264_decode_seq_parameter_set 解析sps
ff_h264_decode_picture_parameter_set 解析pps
位流过滤器
预置AVBitStreamFilter,对应外部AVBSFContext,获取预置
const AVBitStreamFilter* pBitStreamFilter = av_bsf_get_by_name("h264_mp4toannexb");
const AVBitStreamFilter* pBitStreamFilter = av_bsf_get_by_name("aac_adtstoasc");
const AVBitStreamFilter* pBitStreamFilter = av_bsf_get_by_name("extract_extradata");
AVBSFContext生命周期
// alloc
AVBSFContext* pBsfCtx = nullptr;
av_bsf_alloc(pBitStreamFilter, &pBsfCtx);
// init
avcodec_parameters_copy(pBsfCtx->par_in, codecparamter); // 有待研究
av_bsf_init(pBsfCtx);
// use
av_bsf_send_packet(pBsfCtx, &sMediapacket);
av_bsf_receive_packet(pBsfCtx, &sMediapacket);
// free
av_bsf_free(&pBsfCtx);
硬件加速
AVCodecContext 相关成员hw_device_ctx、hw_frames_ctx和函数get_format
AVBufferRef(AVHWDeviceContext)、AVBufferRef(AVHWFramesContext)和AVPixelFormat [](AVCodecContext *,const enum AVPixelFormat *)
预置HWContextType
const HWContextType ff_hwcontext_type_vulkan = {
.type = AV_HWDEVICE_TYPE_VULKAN,
.name = "Vulkan",
.device_hwctx_size = sizeof(AVVulkanDeviceContext),
.device_priv_size = sizeof(VulkanDevicePriv),
.frames_hwctx_size = sizeof(AVVulkanFramesContext),
.frames_priv_size = sizeof(VulkanFramesPriv),
.device_init = &vulkan_device_init,
.device_create = &vulkan_device_create,
.device_derive = &vulkan_device_derive,
.frames_get_constraints = &vulkan_frames_get_constraints,
.frames_init = vulkan_frames_init,
.frames_get_buffer = vulkan_get_buffer,
.frames_uninit = vulkan_frames_uninit,
.transfer_get_formats = vulkan_transfer_get_formats,
.transfer_data_to = vulkan_transfer_data_to,
.transfer_data_from = vulkan_transfer_data_from,
...
.pix_fmts = (const enum AVPixelFormat []) { AV_PIX_FMT_VULKAN, AV_PIX_FMT_NONE},
};
av_hwdevice_ctx_alloc
AVHWDeviceContext - av_class是hwdevice_ctx_class;
AVHWDeviceContext - internal->hw_type、hwctx和internal->priv(以vulkan为例,分别为ff_hwcontext_type_vulkan、AVVulkanDeviceContext和VulkanDevicePriv);
av_hwdevice_find_type_by_name通过hw_type_names查看
avcodec_get_hw_config 通过这个找到预置解码AVCodec硬件配置和支持能力和方法
av_hwdevice_ctx_create
av_hwframe_transfer_data
av_dict_parse_string(&opts,"priority=vod,loglevel=6", "=", ",", 0);
av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VULKAN,"/dev/transcoder0",
opts, 0);
av_hwframe_ctx_alloc
AVHWFramesContext - av_class是hwframe_ctx_class;
AVHWFramesContext -internal->hw_type、hwctx和internal->priv(以vulkan为例,分别为ff_hwcontext_type_vulkan、AVVulkanFramesContext和VulkanFramesPriv);
IO模块
avio_alloc_context
probe模块
通过分析数据buffer得到预置demuxer
- av_probe_input_buffer -> 通过AVIOContext分析得到AVInputFormat
- av_probe_input_format3 -> 通过AVProbeData分析得到AVInputFormat
遍历demuxer,根据demuxer的read_probe、extensions和mime_type得到返回demuxer的分数
其他
AVOption - 设置参数集合,与结构体绑定指出相关参数在结构体中偏移;
typedef struct AVOption {
const char *name; // 设置名称
const char *help; // 设置解释
int offset; // 对应结构体中偏移
enum AVOptionType type; // 值类型(bool,string,int等)
union {
int64_t i64;
double dbl;
const char *str;
AVRational q;
} default_val;
double min; double max; // 最小值最大值
int flags; // 只读,编码参数解码参数等
const char *unit;
} AVOption;
av_opt_set_defaults 将context内部第一个成员AVClass的AVOption值赋值给成员变量;
av_strdup - 分配字符串,并复制内容
av_q2d - 分数转化小数
av_compare_ts - 基于timebase比较两个时间戳(AV_TIME_BASE us单位)
set_string_binary 用于设置二进制字符串,30313233343536373839616263646566变成0123456789abcdef
url.h
typedef struct URLContext {
const AVClass * av_class;
const struct URLProtocol *prot;
void * priv_data;
char * filename;
int flags;
int max_packet_size;
int is_streamed;
int is_connected;
AVIOInterruptCB interrupt_callback;
int64_t rw_timeout;
const char * protocol_whitelist;
const char * protocol_blacklist;
int min_packet_size;
} URLContext;