AVPacket添加解码头信息
FFmpeg解码获得的AVPacket只包含视频压缩数据,并没有包含相关的解码信息(比如:h264的sps pps头信息,AAC的adts头信息),没有这些编码头信息解码器(MediaCodec)是识别不到不能解码的。在FFmpeg中,这些头信息是保存在解码器上下文(AVCodecContext)的extradata中的,所以我们需要为每一种格式的视频添加相应的解码头信息,这样解码器(MediaCodec)才能正确解析每一个AVPacket里的视频数据。
使用AVBitStreamFilter
1.找到相应解码器的过滤器:
bsfilter = av_bsf_get_by_name("h264_mp4toannexb");
2.根据过滤器开辟过滤器上下文内存空间 :
av_bsf_alloc(bsfilter, &bsf_ctx); //AVBSFContext;
3.添加解码器属性:
avcodec_parameters_copy(bsf_ctx->par_in, video->codecpar);
4.初始化过滤器上下文
av_bsf_init(video->bsf_ctx);
5.送入AVPacket过滤
av_bsf_send_packet(bsf_ctx, avPacket);
6.接收过滤后的AVPacket:
av_bsf_receive_packet(bsf_ctx, avPacket);
7.释放资源:
av_bsf_free(&bsf_ctx);
在 WlFFmpeg.h 中声明过滤器
//声明
const AVBitStreamFilter *bsFilter = NULL;
在 WlVideo.h 中声明过滤器上下文
//过滤器上下文
AVBSFContext *abs_ctx = NULL;
在 WlFFmpeg.cpp void WlFFmpeg::start() 方法中
//判断是否支持硬解码
const char *codecName = ((const AVCodec *) video->avCodecContext->codec)->name;
if (supportMediaCodec = callJava->onCallIsSupportVideo(codecName)) {
LOGE("当前设备支持硬解码");
//strcasecmp相当于equals
if (strcasecmp(codecName, "h264") == 0) {
bsFilter = av_bsf_get_by_name("h264_mp4toannexb");
} else if (strcasecmp(codecName, "h265") == 0) {
bsFilter = av_bsf_get_by_name("hevc_mp4toannexb");
}
if (bsFilter == NULL) {
goto end;
}
if (av_bsf_alloc(bsFilter, &video->abs_ctx) != 0) {
supportMediaCodec = false;
goto end;
}
if (avcodec_parameters_copy(video->abs_ctx->par_in, video->codecpar) < 0) {
supportMediaCodec = false;
av_bsf_free(&video->abs_ctx);
video->abs_ctx = NULL;
goto end;
}
if (av_bsf_init(video->abs_ctx) != 0) {
supportMediaCodec = false;
av_bsf_free(&video->abs_ctx);
video->abs_ctx = NULL;
goto end;
}
//重新设置时间基
video->abs_ctx->time_base_in = video->time_base;
}
end:
if (supportMediaCodec) {
video->codectype = CODEC_MEDIACODEC;
}
在 WlVideo.cpp 的 void *playVideo(void *data)
if (video->codectype == CODEC_MEDIACODEC) {
if (av_bsf_send_packet(video->abs_ctx, avPacket) != 0) {
av_packet_free(&avPacket);
av_free(avPacket);
avPacket = NULL;
continue;
}
while (av_bsf_receive_packet(video->abs_ctx, avPacket) == 0) {
//渲染
LOGE("开始硬解码");
av_packet_free(&avPacket);
av_free(avPacket);
continue;
}
avPacket = NULL;
最后 在 WlVideo.cpp void WlVideo::release() 中释放资源
if (abs_ctx != NULL) {
av_bsf_free(&abs_ctx);
abs_ctx = NULL;
}
本文介绍了如何使用FFmpeg在解码过程中添加编解码头信息,如H264 SPS/PPS和AAC ADTS,以便MediaCodec能正确解析视频数据,确保硬解码的顺利进行。方法涉及AVBitStreamFilter和AVCodecContext的使用,以及在不同设备和编码格式间的适配。
1万+





