AVC sequence header (也叫extra_data或者AVCDecoderConfigurationRecord)
结合上边的二进制和AVC sequence header数据格式分析
结合上边的二进制分析可以看到avc sequence header以AVCDecoderConfigurationRecord格式组织的数据,nalu又以start_code格式分割,也就是annex-b。
其实已经发现问题,如果是annex-b格式的话其实nalu都是以start_code分割的(sps,pps也是nalu),而avcc才是通过AVCDecoderConfigurationRecord格式把sps,pps发送到服务端的,并且数据以NALU Length + NALU Data的方式来组织。上边的码流avc sequence header以AVCDecoderConfigurationRecord格式组织sps pps 而视频数据又是以start_code分割的有明显的问题。
不加bsf一直没问题
,怀疑bsf有可能将avcc流转成annex-b。static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx,CodedBitstreamFragment *frag)
{uint8_t *data;size_t max_size, dp, sp;int err, i, zero_run;for (i &#61; 0; i < frag->nb_units; i&#43;&#43;) {// Data should already all have been written when we get here.av_assert0(frag->units[i].data);}max_size &#61; 0;for (i &#61; 0; i < frag->nb_units; i&#43;&#43;) {// Start code &#43; content with worst-case emulation prevention.max_size &#43;&#61; 3 &#43; frag->units[i].data_size * 3 / 2;}data &#61; av_malloc(max_size &#43; AV_INPUT_BUFFER_PADDING_SIZE);if (!data)return AVERROR(ENOMEM);dp &#61; 0;for (i &#61; 0; i < frag->nb_units; i&#43;&#43;) {CodedBitstreamUnit *unit &#61; &frag->units[i];if (unit->data_bit_padding > 0) {if (i < frag->nb_units - 1)av_log(ctx->log_ctx, AV_LOG_WARNING, "Probably invalid ""unaligned padding on non-final NAL unit.\n");elsefrag->data_bit_padding &#61; unit->data_bit_padding;}&#96;&#96;&#96;以下代码以start_code的方式组织码率&#96;&#96;&#96;if ((ctx->codec->codec_id &#61;&#61; AV_CODEC_ID_H264 &&(unit->type &#61;&#61; H264_NAL_SPS ||unit->type &#61;&#61; H264_NAL_PPS)) ||(ctx->codec->codec_id &#61;&#61; AV_CODEC_ID_HEVC &&(unit->type &#61;&#61; HEVC_NAL_VPS ||unit->type &#61;&#61; HEVC_NAL_SPS ||unit->type &#61;&#61; HEVC_NAL_PPS)) ||i &#61;&#61; 0 /* (Assume this is the start of an access unit.) */) {// zero_bytedata[dp&#43;&#43;] &#61; 0;}// start_code_prefix_one_3bytesdata[dp&#43;&#43;] &#61; 0;data[dp&#43;&#43;] &#61; 0;data[dp&#43;&#43;] &#61; 1;zero_run &#61; 0;for (sp &#61; 0; sp < unit->data_size; sp&#43;&#43;) {if (zero_run < 2) {if (unit->data[sp] &#61;&#61; 0)&#43;&#43;zero_run;elsezero_run &#61; 0;} else {if ((unit->data[sp] & ~3) &#61;&#61; 0) {// emulation_prevention_three_bytedata[dp&#43;&#43;] &#61; 3;}zero_run &#61; unit->data[sp] &#61;&#61; 0;}data[dp&#43;&#43;] &#61; unit->data[sp];}}av_assert0(dp <&#61; max_size);err &#61; av_reallocp(&data, dp &#43; AV_INPUT_BUFFER_PADDING_SIZE);if (err)return err;memset(data &#43; dp, 0, AV_INPUT_BUFFER_PADDING_SIZE);frag->data_ref &#61; av_buffer_create(data, dp &#43; AV_INPUT_BUFFER_PADDING_SIZE,NULL, NULL, 0);if (!frag->data_ref) {av_freep(&data);return AVERROR(ENOMEM);}frag->data &#61; data;frag->data_size &#61; dp;return 0;
}
if (par->codec_id &#61;&#61; AV_CODEC_ID_H264 || par->codec_id &#61;&#61; AV_CODEC_ID_MPEG4) {/* check if extradata looks like mp4 formatted */av_log(NULL, AV_LOG_INFO, "extradata_size---par->extradata_size&#61;%d,par->extradata&#61;%d\n", par->extradata_size,*(uint8_t *) par->extradata);if (par->extradata_size > 0 && *(uint8_t *) par->extradata !&#61; 1)//将annex-b转成avccif ((ret &#61; ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0)return ret;}
if (type &#61;&#61; 0 && (!st->codecpar->extradata || st->codecpar->codec_id &#61;&#61; AV_CODEC_ID_AAC ||st->codecpar->codec_id &#61;&#61; AV_CODEC_ID_H264 || st->codecpar->codec_id &#61;&#61; AV_CODEC_ID_HEVC)) {AVDictionaryEntry *t;//extra_data 不为空if (st->codecpar->extradata) {if ((ret &#61; flv_queue_extradata(flv, s->pb, stream_type, size)) < 0)return ret;av_log(NULL, AV_LOG_ERROR, "flv_queue_extradata&#61;&#61;&#61;&#61;&#61;&#61;st->codecpar->extradata&#61;%d,size&#61;%d,stream_type&#61;%d\n", *(uint8_t*)st->codecpar->extradata,size,stream_type);ret &#61; FFERROR_REDO;goto leave;}//填充extra_dataif ((ret &#61; flv_get_extradata(s, st, size)) < 0) {return ret;}av_log(NULL, AV_LOG_ERROR, "flv_queue_extradata&#61;&#61;&#61;&#61;&#61;&#61;st->codecpar->extradata&#61;%d,size&#61;%d,stream_type&#61;%d\n", *(uint8_t*)st->codecpar->extradata,size,stream_type);/* Workaround for buggy Omnia A/XE encoder */t &#61; av_dict_get(s->metadata, "Encoder", NULL, 0);if (st->codecpar->codec_id &#61;&#61; AV_CODEC_ID_AAC && t && !strcmp(t->value, "Omnia A/XE"))st->codecpar->extradata_size &#61; 2;if (st->codecpar->codec_id &#61;&#61; AV_CODEC_ID_AAC && 0) {MPEG4AudioConfig cfg;if (avpriv_mpeg4audio_get_config(&cfg, st->codecpar->extradata,st->codecpar->extradata_size * 8, 1) >&#61; 0) {st->codecpar->channels &#61; cfg.channels;st->codecpar->channel_layout &#61; 0;if (cfg.ext_sample_rate)st->codecpar->sample_rate &#61; cfg.ext_sample_rate;elsest->codecpar->sample_rate &#61; cfg.sample_rate;av_log(s, AV_LOG_TRACE, "mp4a config channels %d sample rate %d\n",st->codecpar->channels, st->codecpar->sample_rate);}}ret &#61; FFERROR_REDO;goto leave;}}
if (flv->new_extradata[stream_type]) {//新建side_datauint8_t *side &#61; av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,flv->new_extradata_size[stream_type]);if (side) {memcpy(side, flv->new_extradata[stream_type],flv->new_extradata_size[stream_type]);av_freep(&flv->new_extradata[stream_type]);flv->new_extradata_size[stream_type] &#61; 0;}}
if (par->codec_id &#61;&#61; AV_CODEC_ID_AAC || par->codec_id &#61;&#61; AV_CODEC_ID_H264|| par->codec_id &#61;&#61; AV_CODEC_ID_MPEG4 || par->codec_id &#61;&#61; AV_CODEC_ID_HEVC) {int side_size &#61; 0;uint8_t *side &#61; av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);//如果extradata_size和side_data_size不一致会认为extradata发生改变&#xff0c;本来bsf是annex-b&#xff0c;却被更新成avcc&#xff08;par->extradata&#61;1&#xff09;if (side && side_size > 0 && (side_size !&#61; par->extradata_size || memcmp(side, par->extradata, side_size))) || {av_log(NULL, AV_LOG_ERROR, "flv_write_packet---side_size&#61;%d----extradata_size&#61;%d,extradata&#61;%d\n", side_size,par->extradata_size, *(uint8_t *) par->extradata);av_free(par->extradata);par->extradata &#61; av_mallocz(side_size &#43; AV_INPUT_BUFFER_PADDING_SIZE);if (!par->extradata) {par->extradata_size &#61; 0;return AVERROR(ENOMEM);}memcpy(par->extradata, side, side_size);par->extradata_size &#61; side_size;flv_write_codec_header(s, par, pkt->dts);}}
if (par->codec_id &#61;&#61; AV_CODEC_ID_H264 || par->codec_id &#61;&#61; AV_CODEC_ID_MPEG4) {/* check if extradata looks like mp4 formatted */av_log(NULL, AV_LOG_INFO, "extradata_size---par->extradata_size&#61;%d,par->extradata&#61;%d\n", par->extradata_size,*(uint8_t *) par->extradata);if (par->extradata_size > 0 && *(uint8_t *) par->extradata !&#61; 1)//annex-b转avccif ((ret &#61; ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0)return ret;}