前言
内容为个人总结的一些理解,如果有错误感谢提出交流~
1. 何时会用到?
一句话:BitStreamFilter一般用在同一编码间不同格式的转换,这过程不重新编解码。
举个例子,比如h264编码有Annex B格式和AVCC 格式(也叫 AVC1 格式或 MPEG-4 格式)。其中Annex B格式是编解码器需要的格式,但是mp4一般封装的是AVCC格式,这时就有可以用BitStreamFilter做格式的转换。
2. 如何使用?
FFmpeg针对BitStreamFilter在4.4版本做了改动,
旧的 AVBitStreamFilterContext 👉 在新 API 里被 AVBSFContext 替代,
旧的 AVBitStreamFilter 👉 在新 API 里变成只读的 const AVBitStreamFilter 描述符,
同时,一些api也被废弃。
比如旧版本的使用,简单写就是
//初始化:
bsfc = av_bitstream_filter_init("h264_mp4toannexb");
//使用
av_bitstream_filter_filter(bsfc,&CodecCtx,NULL,&dummy,&dummy_size,
(const uint8_t*)pBuffer,
lUseLen,0);
这里不对旧版本api说明,毕竟在新版本已经废弃不能使用了,写出来只是为了与后面的新版本做一个对比。
相比过去BitStreamFilter一行代码解决,现在采用send 和 receive的方式,同时将CodocCtx解藕出去(可以看上面旧代码使用的过程中传入codec作为参数)。
先贴简化代码,然后再探讨探讨
//初始化
int InitBSFContext(AVBSFContext** bsf_ctx, char* filter_name, AVCodecContext *CodecCtx)
{
AVBSFContext *ctx = nullptr;
const AVBitStreamFilter *filter = nullptr;
//获取需要的const AVBitStreamFilter描述符
filter = av_bsf_get_by_name(filter_name);
//使用filter alloc AVBSFContext
av_bsf_alloc(filter, &ctx);
//获取codecCtx中参数到ctx
avcodec_parameters_from_context(ctx->par_in, CodecCtx);
//初始化ctx
av_bsf_init(ctx);
*bsf_ctx = ctx;
return 0;
}
//使用(大致替代旧的av_bitstream_filter_filter)
/*
bsfc:AVBSFContext
poutbuf:处理后的data buf,外部管理
poutbuf_size:处理后的data size
buf:需要处理的data buf,外部管理
buf_size:需要处理的data size
is_keyframe:是否是关键帧
*/
int DoBSFFilter(AVBSFContext* bsfc, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, bool is_keyframe)
{
AVPacket* pkt = ...
av_packet_from_data(pkt, buf, buf_size);
pkt->flags |= is_keyframe ? AV_PKT_FLAG_KEY : 0;
av_bsf_send_packet(bsfc, pkt);
av_bsf_receive_packet(bsfc, pkt);
memcpy(*poutbuf, pkt->data, pkt->size);
*poutbuf_size = pkt->size;
av_packet_unref(pkt);
return 0;
}
3. 探讨
3.1 AVBSFContext 和 AVBitStreamFilter内部是什么?
typedef struct AVBSFContext {
const AVClass *av_class;
//BSF描述符,后面详细再说
const struct AVBitStreamFilter *filter;
//运行时状态,保存bfs生命周期间的一些信息
void *priv_data;
//输入流的编码参数,从codec上下文中获取
//在初始化代码中,avcodec_parameters_from_context(ctx->par_in, CodecCtx);
AVCodecParameters *par_in;
//这个输出流的编码参数,一般使用者不去操作他,这个是给内部filter操作的,使用者读就好
AVCodecParameters *par_out;
//时间基,和上面类似,用的比较少
AVRational time_base_in;
AVRational time_base_out;
} AVBSFContext;
typedef struct AVBitStreamFilter {
//filter描述符名,比如h264_mp4toannexb
//在刚刚初始化代码中,av_bsf_get_by_name(filter_name);
const char *name;
//当前这个filter支持的codec
const enum AVCodecID *codec_ids;
//私有参数配置,这里不关注
const AVClass *priv_class;
} AVBitStreamFilter;
3.2 AVBitStreamFilter内部是怎么实现的?
AVBitStreamFilter在ffmpeg内部实际是下面这个样子的,各变量什么作用看名字就能知道,这里不做说明。
typedef struct FFBitStreamFilter {
AVBitStreamFilter p;
int priv_data_size;
int (*init)(AVBSFContext *ctx);
int (*filter)(AVBSFContext *ctx, AVPacket *pkt);
void (*close)(AVBSFContext *ctx);
void (*flush)(AVBSFContext *ctx);
} FFBitStreamFilter;
ffmpeg在内部定义了多个这个的filter描述符,这里用h264_mp4toannexb来作为例子。ffmpeg会在libavcodec下通过h264_mp4toannexb_bsf.c文件来编写这个filter。
1.
首先是H264BSFContext,这就是该filter运行时需要保存的状态信息,记录在AVBSFContext的priv_data中。

2.
通过函数指针,实现该filter的功能,这里三个函数指针不做说明,看名字也大概可以知道干什么,每个filter的实现去看对应的c文件就行,其中filter函数指针就是数据流过滤的实现。

3.
av_bsf_get_by_name就是找到对应的filter,然后给到AVBSFContext。这里值的一提的是,这个函数会在bitstream_filters 数组中寻找,而这个数组的来源是"libavcodec/bsf_list.c",这是在执行 ./configure 时根据输入的参数 --enable-XXX 动态生成的。
3.3 av_bsf_init干了什么?
这个是在获取avcodec_parameters_from_context后调用的bsf初始化接口,源代码内部总的来说做了三件事
- 判断codec和filter是不是适配,avcodec_parameters_from_context(ctx->par_in, CodecCtx);中的CodecCtx在不在AVBitStreamFilter的codec_ids中
- 出入参、出入time_base拷贝
- 调用上面提到filter的init函数指针
1380

被折叠的 条评论
为什么被折叠?



