hevc_mp4toannexb_bsf.c/h264_mp4toannexb_bsf.c

本文主要分析mp4封装的h265/h264,copy转hls,红色为自己添加的注释。

动态添加此filter
    for (i = 0; i < nb_output_streams; i++) {
        ost = output_streams[i];
        if(ost->st->codec->codec_type  == AVMEDIA_TYPE_VIDEO && ost->st->codec->codec_id == AV_CODEC_ID_H264)
        {
           AVBitStreamFilterContext * avFilter = av_bitstream_filter_init("h264_mp4toannexb");
           ost->bitstream_filters = avFilter;
        }else if(ost->st->codec->codec_type  == AVMEDIA_TYPE_VIDEO && ost->st->codec->codec_id == AV_CODEC_ID_HEVC)
        {
           AVBitStreamFilterContext * avFilter = av_bitstream_filter_init("hevc_mp4toannexb");
           ost->bitstream_filters = avFilter;
        }

}

hevc->hls

如果不加 -bsf:v hevc_mp4toannex,就会报如下错误:

原因如下:

check_hevc_startcode会发现没有00000001字段。

hevc_mp4toannexb_bsf.c/h264_mp4toannexb_bsf.c_第1张图片


相关代码有:hevc_mp4toannexb_bsf.c

前缀(vps,sps,pps)例子如下:

hevc_mp4toannexb_bsf.c/h264_mp4toannexb_bsf.c_第2张图片

typedef structHEVCBSFContext {

    uint8_t length_size;

    int     extradata_parsed;

}HEVCBSFContext;


static inthevc_extradata_to_annexb(AVBSFContext *ctx)

{

    GetByteContext gb;

    int length_size, num_arrays, i, j;

    int ret = 0;

    uint8_t *new_extradata = NULL;

    size_t  new_extradata_size = 0;

    bytestream2_init(&gb,ctx->par_in->extradata, ctx->par_in->extradata_size);

    bytestream2_skip(&gb, 21); 

    //跳过21个字节

    length_size =(bytestream2_get_byte(&gb) & 3) + 1;

    //22个字节(0x03)后两位加上1

    num_arrays = bytestream2_get_byte(&gb);

    //23个字节(0x03

    for (i = 0; i < num_arrays; i++) {

        int type =bytestream2_get_byte(&gb) & 0x3f;

        //对应0x200x210x22

        int cnt = bytestream2_get_be16(&gb);

        //对应0x00 0x01 0x00 0x01 0x00 0x01,

        if (!(type == NAL_VPS || type ==NAL_SPS || type == NAL_PPS ||

              type == NAL_SEI_PREFIX || type ==NAL_SEI_SUFFIX || type == 0)) {

            av_log(ctx, AV_LOG_ERROR,"Invalid NAL unit type in extradata: %d\n",

                   type);

            ret = AVERROR_INVALIDDATA;

            goto fail;

        }

        for (j = 0; j < cnt; j++) {

            int nalu_len =bytestream2_get_be16(&gb);

            //对应0x00 0x170x40~0x59),0x00 0x270x42~0x40),0x00 0x070x44~0x20

            if (4 +AV_INPUT_BUFFER_PADDING_SIZE + nalu_len > SIZE_MAX - new_extradata_size) {

                ret = AVERROR_INVALIDDATA;

                goto fail;

            }

            ret =av_reallocp(&new_extradata, new_extradata_size + nalu_len + 4 +AV_INPUT_BUFFER_PADDING_SIZE);

            if (ret < 0)

                goto fail;

            AV_WB32(new_extradata +new_extradata_size, 1);

            // addthe startcode,也就是00 00 00 01

            bytestream2_get_buffer(&gb,new_extradata + new_extradata_size + 4, nalu_len);

            new_extradata_size += 4 + nalu_len;

            memset(new_extradata + new_extradata_size,0, AV_INPUT_BUFFER_PADDING_SIZE);

        }

    }

   av_freep(&ctx->par_out->extradata);

    ctx->par_out->extradata      = new_extradata;

    ctx->par_out->extradata_size =new_extradata_size;

    //得到新的字符串,长度。

    if (!new_extradata_size)

        av_log(ctx, AV_LOG_WARNING, "Noparameter sets in the extradata\n");

    return length_size;

fail:

    av_freep(&new_extradata);

    return ret;

}

 

static inthevc_mp4toannexb_init(AVBSFContext *ctx)

{

  ...

}

 

//对于每一帧,都会进入hevc_mp4toannexb_filter函数,如下:

hevc_mp4toannexb_bsf.c/h264_mp4toannexb_bsf.c_第3张图片

static inthevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out)

{

    HEVCBSFContext *s = ctx->priv_data;

    AVPacket *in;

    GetByteContext gb;

    int got_irap = 0;

    int i, ret = 0;

    ret = ff_bsf_get_packet(ctx, &in);

    if (ret < 0)

        return ret;

    if (!s->extradata_parsed) {

        av_packet_move_ref(out, in);

        av_packet_free(&in);

        return 0;

    }

    bytestream2_init(&gb, in->data,in->size);

    while (bytestream2_get_bytes_left(&gb)){

        uint32_t nalu_size = 0;

        int     nalu_type;

        int is_irap, add_extradata, extra_size,prev_size;

        for (i = 0; i < s->length_size;i++)

            nalu_size = (nalu_size << 8)| bytestream2_get_byte(&gb);

        //4位表示数据大小。

        nalu_type =(bytestream2_peek_byte(&gb) >> 1) & 0x3f;

        //对应0x26

        /* prepend extradata to IRAP frames */

        is_irap       = nalu_type >= 16 &&nalu_type <= 23;

        //帧类型在1623之间,都会被强插入vps等前缀。

        add_extradata = is_irap &&!got_irap;

        extra_size    = add_extradata *ctx->par_out->extradata_size;

        got_irap     |= is_irap;

        if (SIZE_MAX - nalu_size < 4 ||

            SIZE_MAX - 4 - nalu_size

            ret = AVERROR_INVALIDDATA;

            goto fail;

        }

        prev_size = out->size;

        ret = av_grow_packet(out, 4 + nalu_size+ extra_size);

        if (ret < 0)

            goto fail;

        if (add_extradata)

            memcpy(out->data + prev_size,ctx->par_out->extradata, extra_size);

        //插入vps等前缀。

        AV_WB32(out->data + prev_size +extra_size, 1);

        // add thestartcode,也就是00 00 00 01

        bytestream2_get_buffer(&gb,out->data + prev_size + 4 + extra_size, nalu_size);

        //拷贝帧数据。

    }

    ret = av_packet_copy_props(out, in);

    if (ret < 0)

        goto fail;

fail:

    if (ret < 0)

        av_packet_unref(out);

    av_packet_free(&in);

    return ret;

}

...

h264->hls

解析mp4的块,得到sps,pps总数据,在h264_mp4toannexb_filter中去除头,得到sps,pps(只做一次),然后在每个关键帧前插sps,pps数据。

你可能感兴趣的:(ffmpeg--mp4)