Ffmpeg对sps/pps的解析和格式转换

2018-09-12 19:04:29 浏览数 (1)

H264流的 SPS(序列参数集Sequence Parameter Set)和PPS(图像参数集Picture Parameter Set)记录了视频的基本编码信息,在进行视频处理的时候,难免会对其进行处理,下面介绍几个相关的API对其进行解析和格式转换。

首先来看两种格式:

Annex-B 和 AVCC/HVCC

H.264码流分Annex-B和AVCC两种格式。 H.265码流是Annex-B和HVCC格式。 (以下内容针对H.264,但大体也适用于H.265/HEVC)

别名

  • AVCC格式 也叫AVC1格式,MPEG-4格式,字节对齐,因此也叫Byte-Stream Format。用于mp4/flv/mkv, VideoToolbox。
  • Annex-B格式 也叫MPEG-2 transport stream format格式(ts格式), ElementaryStream格式

结构上的区别:

区别有两点:一个是参数集(SPS, PPS)组织格式;一个是分隔。 - Annex-B:使用start code分隔NAL(start code为三字节或四字节,0x000001或0x00000001,一般是四字节);SPS和PPS按流的方式写在头部。 - AVCC:使用NALU长度(固定字节,通常为4字节)分隔NAL;在头部包含extradata(或sequence header)的结构体。(extradata包含分隔的字节数、SPS和PPS)

举两个例子:

avcc格式:

01 64 00 1f ff e1 00 19 67 64 00 1f ac d9 40 50 05 ba 10 00 00 03 00 10 00 00 03 03 c8 f1 83 19 60 01 00 05 68 ea ec b2 2c

annex-b格式

00 00 00 01 67 64 00 28 ac b3 00 a0 0b 74 20 00 00 03 00 20 00 00 fa 01 e3 06 4d 00 00 00 01 68 e9 73 2c 8b

其中0x67表示SPS,0x68表示PPS

Annex-B格式转AVCC

int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)

在flvenc.c里面可以看到有以下调用:

代码语言:javascript复制
            avio_w8(pb, par->codec_tag | FLV_FRAME_KEY); // flags
            avio_w8(pb, 0); // AVC sequence header
            avio_wb24(pb, 0); // composition time
            ff_isom_write_avcc(pb, par->extradata, par->extradata_size);

将extradata以avcc的格式写入avc sequence header里面

AVCC格式转Annex-B

int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size)

解析Annex-B格式

代码语言:javascript复制
    AVCodec *const codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (codec != NULL) 
    {               
        AVCodecContext* ctx = avcodec_alloc_context3(codec);
        ctx->debug = ~0;
        ctx->extradata = (uint8_t *)av_malloc(size   FF_INPUT_BUFFER_PADDING_SIZE);
        ctx->extradata_size = size;
        memcpy(ctx->extradata, data,size); 
        memset(&ctx->extradata[ctx->extradata_size], 0, FF_INPUT_BUFFER_PADDING_SIZE); 

        if (avcodec_open2(ctx, codec, NULL) < 0) 
        {
            fprintf(stderr, "Failed to open codecn");
        }
        else
        {   
            char buf[1024];
            avcodec_string(buf, sizeof(buf), ctx, 0);
            fprintf(stderr, "[%sn", buf);

        }
        avcodec_close(ctx);
        av_free(ctx);
    }
     

0 人点赞