ffmpeg解析MP4封装的avc1编码问题「建议收藏」(Windows下安装使用ffmpeg)
0、問題
??遇到的問題:使用ffmpeg直接讀取avc1編碼的mp4視頻,將讀取到的幀寫下來(H264碼流),播放失敗。
??原因: ffmpeg解碼獲取的AVPacket只包含視頻壓縮數據,并沒有包含相關的解碼信息(比如:h264的sps,pps頭信息),這些解碼信息包括編碼的profile,level,圖像的寬和高,deblock濾波器等。沒有這些編碼頭信息解碼器就不能進行解碼。
1、mp4封裝的avc1編碼
??mp4封裝的avc1編碼(不帶起始碼的H264編碼格式)視頻如果直接用av_read_frame接口讀取然后播放是不能播放成功的。因為讀取出來的數據不帶PPS/SPS、起始碼這三種信息。
必須添加上后才能播放。
sps,pps之后就是I幀的數據起始碼為00 00 00 01或00 00 01
上圖中黑框內就是sps和psp數據,藍色框為起始碼(00 00 00 01)及I幀標志碼(06 50)
2、SPS,PPS在ffmpeg
??H.264碼流的SPS和pps信息存儲在AVCidecContext結構體的extradata中,添加這些信息需要使用ffmpeg中名稱為”h264_mp4toannexb”的bitstream filter處理。
查看ffmpeg工具支持的Bitstream Filter類型命令
ffmpeg -bsfs
3、新舊接口
《1》、舊接口
int ParseH264ExtraDataInMp4(int stream_id, AVPacket* packet)
{
uint8_t *dummy = NULL; int dummy_size;
AVBitStreamFilterContext* bsfc = av_bitstream_filter_init("h264_mp4toannexb");
if (bsfc == NULL)
{
envir() << "cannot open the h264_mp4toannexb\n";
return -1;
}
av_bitstream_filter_filter(bsfc, format_ctx_->streams[stream_id]->codec,
NULL, &dummy, &dummy_size, NULL, 0, 0);
av_bitstream_filter_close(bsfc);
}
舊接口使用時需要特別注意,否則很容易導致內存泄漏。
《2》、新接口
int ParseH264ExtraDataInMp4(int stream_id, AVPacket* packet)
{
const AVBitStreamFilter * absFilter = NULL;
AVBSFContext *absCtx = NULL;
AVCodecParameters *codecpar = NULL;
absFilter = av_bsf_get_by_name("h264_mp4toannexb");
//過濾器分配內存
av_bsf_alloc(absFilter, &absCtx);
//添加解碼器屬性
codecpar = format_ctx_->streams[stream_id]->codecpar;
avcodec_parameters_copy(absCtx->par_in, codecpar);
absCtx->time_base_in = format_ctx_->streams[stream_id]->time_base;
//初始化過濾器上下文
av_bsf_init(absCtx);
//AVPacket處理
if (av_bsf_send_packet(absCtx, packet) < 0)
{
printf("av_bsf_send_packet faile \n");
av_bsf_free(&absCtx);
absCtx = NULL;
return -1;
}
if (av_bsf_receive_packet(absCtx, packet) == 0)
{
//printf("av_bsf_receive_packet faile \n");
//av_bsf_free(&absCtx);
//absCtx = NULL;
return 0;
}
av_bsf_free(&absCtx);
absCtx = NULL;
}
《3》、使用偽代碼
int main()
{
//ffmpeg的open接口打開MP4封裝的avc1碼流視頻 , AVFormatContext *format_ctx_
//讀取一幀av_read_frame,讀取到AVPacket packet中
if(視頻幀) //只處理視頻幀,音頻不處理
{
int stream_id = packet->stream_index;
AVCodecContext *codec = NULL;
codec = format_ctx_->streams[stream_id]->codec;
if (codec->codec_id == AV_CODEC_ID_H264)
{
//pps and sps
//const char start_code[4] = { 0, 0, 0, 1 };
//memcpy(packet->data, start_code, 4);
if ((codec->extradata[0] != 0) &&
(ParseH264ExtraDataInMp4(stream_id, packet) == 0))
{
has_extra_data = True;
}
#if 0
{
FILE* wfd = fopen("out.h264", "ab+");
if (wfd)
{
if (has_extra_data)
{
fwrite(codec->extradata, 1, codec->extradata_size, wfd);
}
fwrite(packet->data, 1, packet->size, wfd);
fflush(wfd);
fclose(wfd);
wfd = NULL;
}
}
#endif
}
}
}
4、參考
《1》、https://www.jianshu.com/p/e5e021ccc980
《2》、https://blogs.gentoo.org/lu_zero/2016/03/21/bitstream-filtering/
《3》、http://www.xuhj.top/2018/06/26/ffmpeg-convert-to-ts-stream/
《4》、https://cloud.tencent.com/developer/article/1333501
《5》、sps/pps數據結構
《6》、avc1余h264區別
總結
以上是生活随笔為你收集整理的ffmpeg解析MP4封装的avc1编码问题「建议收藏」(Windows下安装使用ffmpeg)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【合肥seo】网站通过SEO优化的好处
- 下一篇: FC游戏 《三国志2-霸王的大陆》攻略「