1. 程式人生 > >h264手動新增sps和pps到AVCodecContext->extradata

h264手動新增sps和pps到AVCodecContext->extradata

最近編碼的時候發現生成的視訊不能用Windows Media Player等系統自帶的播放器播放,也沒有縮圖。找了很久,最後才發現在avcodec_open2之前新增一行程式碼就行了:

codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

codec_ctx定義:AVCodecContext* codec_ctx;

呼叫該行程式碼後,FFmpeg會在呼叫avcodec_open2裡,在寫header時填充sps,pps等資訊。不填充編碼出來的視訊就不能正常解碼,當然使用專業的播放器(potplayer等)還是可以。

在沒發現新增這行程式碼就可以之前,我是直接嘗試手動新增sps/pps到extradata的。

在avcodec_open2之前新增如下程式碼,生成的視屏就能用系統自帶播放器播放,也有了縮圖。但是Windows資源管理器看的幀高度和寬度不正確,所以還要修改sps_pps陣列。

unsigned char sps_pps[23] = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x0a, 0xf8, 0x0f, 0x00, 0x44, 0xbe, 0x8,
			      0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x38, 0x80 }; 
		codec_ctx->extradata_size = 23;
		codec_ctx->extradata = (uint8_t*)av_malloc(23 + AV_INPUT_BUFFER_PADDING_SIZE);
		if (codec_ctx->extradata == NULL) {
			printf("could not av_malloc the video params extradata!\n");
			return -1;
		}
		memcpy(codec_ctx->extradata, sps_pps, 23);

sps和pps的結構參考:h264編碼 裡面的Sequence parameter set RBSP syntax

0x00000001或者0x000001是起始碼,0x67是sps的開頭,0x68是pps的開頭。

0x42代表profile_idc,後面八位是constraint_set0_flag和reserved_zero_4bits,都設為0,0x0a是level_idc,接著後面為圖方便能用0表示的都用了。這裡要注意是ue(v)表示該域是可變位,使用的我的目的主要是設定正確幀高度和幀高度,所以只要填充   pic_width_in_mbs_minus1和  pic_height_in_map_units_minus1,將它們的十六進位制數寫入sps_pps,如果寬度和高度不是16的倍數,要填frame_cropping_flag,具體的做法參考大神部落格和SO.

更多資料參考: