[FFmpeg + OpenGL + OpenSL ES] AVPacket添加接码头信息- 10

本文介绍了如何使用FFmpeg在解码过程中添加编解码头信息,如H264 SPS/PPS和AAC ADTS,以便MediaCodec能正确解析视频数据,确保硬解码的顺利进行。方法涉及AVBitStreamFilter和AVCodecContext的使用,以及在不同设备和编码格式间的适配。

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;
}

 

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值