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.
更多資料參考: