ffmpeg封装H246为MP4.docx
- 文档编号:7239377
- 上传时间:2023-01-22
- 格式:DOCX
- 页数:17
- 大小:20.57KB
ffmpeg封装H246为MP4.docx
《ffmpeg封装H246为MP4.docx》由会员分享,可在线阅读,更多相关《ffmpeg封装H246为MP4.docx(17页珍藏版)》请在冰豆网上搜索。
ffmpeg封装H246为MP4
ffmpeg封装H246为MP4
前言
文章主要对H264视频流封装为MP4格式文件的讲述,有实时H264视频流的封装和h264文件的封装,本文主要针对飞思卡尔I.MX6Q-vpu视频编码后的视频封装,所以没涉及到音频,
一、h264视频文件的封装
这部分代码主要是从雷博那里借鉴过来的,雷博的文章是音频和视频封装,我这里只实现视频的封装,具体实现方法差不多,就是少了音频这一路,代码如下:
#include
#define__STDC_CONSTANT_MACROS
#include
/*
FIX:
H.264insomecontainerformat(FLV,MP4,MKVetc.)need
"h264_mp4toannexb"bitstreamfilter(BSF)
*AddSPS,PPSinfrontofIDRframe
*Addstartcode("0,0,0,1")infrontofNALU
H.264insomecontainer(MPEG2TS)don'tneedthisBSF.
*/
//'1':
UseH.264BitstreamFilter
#defineUSE_H264BSF0
/*
FIX:
AACinsomecontainerformat(FLV,MP4,MKVetc.)need
"aac_adtstoasc"bitstreamfilter(BSF)
*/
//'1':
UseAACBitstreamFilter
#defineUSE_AACBSF0
intmain(intargc,char*argv[])
{
AVOutputFormat*ofmt=NULL;
//InputAVFormatContextandOutputAVFormatContext
AVFormatContext*ifmt_ctx_v=NULL,*ifmt_ctx_a=NULL,*ofmt_ctx=NULL;
AVPacketpkt;
intret,i;
intvideoindex_v=0,videoindex_out=0;
intframe_index=0;
int64_tcur_pts_v=0,cur_pts_a=0;
//constchar*in_filename_v="cuc_ieschool.ts";//InputfileURL
constchar*in_filename_v="vpu.h264";
//constchar*in_filename_a="cuc_ieschool.mp3";
//constchar*in_filename_a="gowest.m4a";
//constchar*in_filename_a="gowest.aac";
constchar*in_filename_a="huoyuanjia.mp3";
constchar*out_filename="vpu.mp4";//OutputfileURL
av_register_all();
//Input
if((ret=avformat_open_input(&ifmt_ctx_v,in_filename_v,0,0))<0){
printf("Couldnotopeninputfile.");
gotoend;
}
if((ret=avformat_find_stream_info(ifmt_ctx_v,0))<0){
printf("Failedtoretrieveinputstreaminformation");
gotoend;
}
/*if((ret=avformat_open_input(&ifmt_ctx_a,in_filename_a,0,0))<0){
printf("Couldnotopeninputfile.");
gotoend;
}
if((ret=avformat_find_stream_info(ifmt_ctx_a,0))<0){
printf("Failedtoretrieveinputstreaminformation");
gotoend;
}*/
printf("===========InputInformation==========\n");
av_dump_format(ifmt_ctx_v,0,in_filename_v,0);
//av_dump_format(ifmt_ctx_a,0,in_filename_a,0);
printf("======================================\n");
//Output
avformat_alloc_output_context2(&ofmt_ctx,NULL,NULL,out_filename);
if(!
ofmt_ctx){
printf("Couldnotcreateoutputcontext\n");
ret=AVERROR_UNKNOWN;
gotoend;
}
ofmt=ofmt_ctx->oformat;
printf("ifmt_ctx_v->nb_streams=%d\n",ifmt_ctx_v->nb_streams);
for(i=0;i
//CreateoutputAVStreamaccordingtoinputAVStream
//if(ifmt_ctx_v->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
AVStream*in_stream=ifmt_ctx_v->streams[i];
AVStream*out_stream=avformat_new_stream(ofmt_ctx,in_stream->codec->codec);
videoindex_v=i;
if(!
out_stream){
printf("Failedallocatingoutputstream\n");
ret=AVERROR_UNKNOWN;
gotoend;
}
videoindex_out=out_stream->index;
//CopythesettingsofAVCodecContext
if(avcodec_copy_context(out_stream->codec,in_stream->codec)<0){
printf("Failedtocopycontextfrominputtooutputstreamcodeccontext\n");
gotoend;
}
out_stream->codec->codec_tag=0;
if(ofmt_ctx->oformat->flags&AVFMT_GLOBALHEADER)
out_stream->codec->flags|=CODEC_FLAG_GLOBAL_HEADER;
//break;
}
}
/*
for(i=0;i
//CreateoutputAVStreamaccordingtoinputAVStream
if(ifmt_ctx_a->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){
AVStream*in_stream=ifmt_ctx_a->streams[i];
AVStream*out_stream=avformat_new_stream(ofmt_ctx,in_stream->codec->codec);
audioindex_a=i;
if(!
out_stream){
printf("Failedallocatingoutputstream\n");
ret=AVERROR_UNKNOWN;
gotoend;
}
audioindex_out=out_stream->index;
//CopythesettingsofAVCodecContext
if(avcodec_copy_context(out_stream->codec,in_stream->codec)<0){
printf("Failedtocopycontextfrominputtooutputstreamcodeccontext\n");
gotoend;
}
out_stream->codec->codec_tag=0;
if(ofmt_ctx->oformat->flags&AVFMT_GLOBALHEADER)
out_stream->codec->flags|=CODEC_FLAG_GLOBAL_HEADER;
break;
}
}
*/
printf("==========OutputInformation==========\n");
av_dump_format(ofmt_ctx,0,out_filename,1);
printf("======================================\n");
//Openoutputfile
if(!
(ofmt->flags&AVFMT_NOFILE)){
if(avio_open(&ofmt_ctx->pb,out_filename,AVIO_FLAG_WRITE)<0){
printf("Couldnotopenoutputfile'%s'",out_filename);
gotoend;
}
}
//Writefileheader
if(avformat_write_header(ofmt_ctx,NULL)<0){
printf("Erroroccurredwhenopeningoutputfile\n");
gotoend;
}
//FIX
#ifUSE_H264BSF
AVBitStreamFilterContext*h264bsfc=av_bitstream_filter_init("h264_mp4toannexb");
#endif
#ifUSE_AACBSF
AVBitStreamFilterContext*aacbsfc=av_bitstream_filter_init("aac_adtstoasc");
#endif
while
(1){
AVFormatContext*ifmt_ctx;
intstream_index=0;
AVStream*in_stream,*out_stream;
//GetanAVPacket
//if(av_compare_ts(cur_pts_v,ifmt_ctx_v->streams[videoindex_v]->time_base,cur_pts_a,ifmt_ctx_a->streams[audioindex_a]->time_base)<=0)
{
ifmt_ctx=ifmt_ctx_v;
stream_index=videoindex_out;
if(av_read_frame(ifmt_ctx,&pkt)>=0){
do{
in_stream=ifmt_ctx->streams[pkt.stream_index];
out_stream=ofmt_ctx->streams[stream_index];
printf("stream_index==%d,pkt.stream_index==%d,videoindex_v=%d\n",stream_index,pkt.stream_index,videoindex_v);
if(pkt.stream_index==videoindex_v){
//FIX:
NoPTS(Example:
RawH.264)
//SimpleWritePTS
if(pkt.pts==AV_NOPTS_VALUE){
printf("frame_index==%d\n",frame_index);
//WritePTS
AVRationaltime_base1=in_stream->time_base;
//Durationbetween2frames(us)
int64_tcalc_duration=(double)AV_TIME_BASE/av_q2d(in_stream->r_frame_rate);
//Parameters
pkt.pts=(double)(frame_index*calc_duration)/(double)(av_q2d(time_base1)*AV_TIME_BASE);
pkt.dts=pkt.pts;
pkt.duration=(double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);
frame_index++;
}
cur_pts_v=pkt.pts;
break;
}
}while(av_read_frame(ifmt_ctx,&pkt)>=0);
}else{
break;
}
}
/*else
{
ifmt_ctx=ifmt_ctx_a;
stream_index=audioindex_out;
if(av_read_frame(ifmt_ctx,&pkt)>=0){
do{
in_stream=ifmt_ctx->streams[pkt.stream_index];
out_stream=ofmt_ctx->streams[stream_index];
if(pkt.stream_index==audioindex_a){
//FIX:
NoPTS
//SimpleWritePTS
if(pkt.pts==AV_NOPTS_VALUE){
//WritePTS
AVRationaltime_base1=in_stream->time_base;
//Durationbetween2frames(us)
int64_tcalc_duration=(double)AV_TIME_BASE/av_q2d(in_stream->r_frame_rate);
//Parameters
pkt.pts=(double)(frame_index*calc_duration)/(double)(av_q2d(time_base1)*AV_TIME_BASE);
pkt.dts=pkt.pts;
pkt.duration=(double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);
frame_index++;
}
cur_pts_a=pkt.pts;
break;
}
}while(av_read_frame(ifmt_ctx,&pkt)>=0);
}else{
break;
}
}*/
//FIX:
BitstreamFilter
#ifUSE_H264BSF
av_bitstream_filter_filter(h264bsfc,in_stream->codec,NULL,&pkt.data,&pkt.size,pkt.data,pkt.size,0);
#endif
#ifUSE_AACBSF
av_bitstream_filter_filter(aacbsfc,out_stream->codec,NULL,&pkt.data,&pkt.size,pkt.data,pkt.size,0);
#endif
//ConvertPTS/DTS
pkt.pts=av_rescale_q_rnd(pkt.pts,in_stream->time_base,out_stream->time_base,(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts=av_rescale_q_rnd(pkt.dts,in_stream->time_base,out_stream->time_base,(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration=av_rescale_q(pkt.duration,in_stream->time_base,out_stream->time_base);
pkt.pos=-1;
pkt.stream_index=stream_index;
printf("Write1Packet.size:
%5d\tpts:
%lld\n",pkt.size,pkt.pts);
//Write
if(av_interleaved_write_frame(ofmt_ctx,&pkt)<0){
printf("Errormuxingpacket\n");
break;
}
av_free_packet(&pkt);
}
//Writefiletrailer
av_write_trailer(ofmt_ctx);
#ifUSE_H264BSF
av_bitstream_filter_close(h264bsfc);
#endif
#ifUSE_AACBSF
av_bitstream_filter_close(aacbsfc);
#endif
end:
avformat_close_input(&ifmt_ctx_v);
//avformat_close_input(&ifmt_ctx_a);
/*closeoutput*/
if(ofmt_ctx&&!
(ofmt->flags&AVFMT_NOFILE))
avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
if(ret<0&&ret!
=AVERROR_EOF){
printf("Erroroccurred.\n");
return-1;
}
return0;
}
二、h264视频实时流的封装
大体思路和上面文件操作是差不多的,区别在于不能像上面一样可以获取文件中视频流的信息,这样你就得自己去设置这些参数,下面程序是根据我自己的视频流设置的,如果你的不同,需要修改;具体参数如下:
(1)AVCodecContext的配置参数
enumAVMediaTypecodec_type:
编解码器的类型(视频,音频...)
structAVCodec *codec:
采用的解码器AVCodec(H.264,MPEG2...)
intbit_rate:
平均比特率
uint8_t*extradata; intextradata_size:
针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)
AVRationaltime_base:
根据该参数,可以把PTS转化为实际的时间(单位为秒s)
intwidth,height:
如果是视频的话,代表宽和高
intrefs:
运动估计参考帧的个数(H.264的话会有多帧,MPEG2这类的一般就没有了)
intsample_rate:
采样率(音频)
intchannels:
声道数(音频)
enumAVSampleFormatsample_fmt:
采样格式
intprofile:
型(H.264里面就有,其他编码标准应该也有)
intlevel:
级(和profile差不太多)
(2)还有一个结构体参数也需要去设置,在AVPacket结构体中,重要的变量有以下几个:
uint8_t*data:
压缩编码的数据。
例如对于H.264来说。
1个AVPacket的data通常对应一个NAL。
注意:
在这里只是对应,而不是一模一样。
他们之间有微小的差别:
使用FFMPEG类库分离出多媒体文件中的H.264码流
因此在使用FFMPEG进行视音频处理的时候,常常可以将得到的AVPacket的data数据直接写成文件,从而得到视音频的码流文件。
int size:
data的大小
int64_tpts:
显示时间戳
int64_tdts:
解码时间戳
int stream_index:
标识该AVPacket所属的视频/音频流。
总体代码如下:
#include"ffmpeg_mp4.h"
intgetVopType(constvoid*p,intlen)
{
if(!
p||6>=len)
return-1;
unsignedchar*b=(unsignedchar*)p;
//VerifyNALmarker
if(b[0]||b[1
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ffmpeg 封装 H246 MP4