/*******************
程序功能:
将".h264"格式的视频流和".aac"格式的音频流封装成基本上同步的".ts"影视文件(打开注释部分,则可封装成".mp4"影视文件)
*******************/
extern "C"
{
#include "libavformat\avformat.h"
};
int StreamToMedia(char* VideoName,char *AudioName,char *MediaName)
{
AVFormatContext *pFormatContext_I_V = NULL;
if(avformat_open_input(&pFormatContext_I_V,VideoName,0,0) < 0)
return -1;
if(avformat_find_stream_info(pFormatContext_I_V,0) < 0)
{
avformat_close_input(&pFormatContext_I_V);
return -2;
}
AVFormatContext *pFormatContext_I_A = NULL;
if(avformat_open_input(&pFormatContext_I_A,AudioName,0,0) < 0)
{
avformat_close_input(&pFormatContext_I_V);
return -3;
}
if(avformat_find_stream_info(pFormatContext_I_A,0) < 0)
{
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
return -4;
}
AVFormatContext *pFormatContext_O = NULL;
avformat_alloc_output_context2(&pFormatContext_O,NULL,NULL,MediaName);
if(pFormatContext_O == NULL)
{
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
return -5;
}
AVOutputFormat *pOutputFormat = NULL;
pOutputFormat = pFormatContext_O->oformat;
int i = 0,VideoIndex_I = -1,VideoIndex_O = -1;
for(i=0;i<pFormatContext_I_V->nb_streams;i++)
{
if(pFormatContext_I_V->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
VideoIndex_I = i;
AVStream *StreamIn = pFormatContext_I_V->streams[i];
AVStream *StreamOut = avformat_new_stream(pFormatContext_O,StreamIn->codec->codec);
if(!StreamOut)
{
avformat_free_context(pFormatContext_O);
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
return -6;
}
VideoIndex_O = StreamOut->index;
if(avcodec_copy_context(StreamOut->codec,StreamIn->codec) < 0)
{
avformat_free_context(pFormatContext_O);
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
return -7;
}
StreamOut->codec->codec_tag = 0;
if(pFormatContext_O->oformat->flags & AVFMT_GLOBALHEADER)
StreamOut->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
break;
}
}
int AudioIndex_I = -1,AudioIndex_O = -1;
for(i=0;i<pFormatContext_I_A->nb_streams;i++)
{
if(pFormatContext_I_A->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
AudioIndex_I = i;
AVStream *StreamIn = pFormatContext_I_A->streams[i];
AVStream *StreamOut = avformat_new_stream(pFormatContext_O,StreamIn->codec->codec);
if(!StreamOut)
{
avformat_free_context(pFormatContext_O);
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
return -8;
}
AudioIndex_O = StreamOut->index;
if(avcodec_copy_context(StreamOut->codec,StreamIn->codec) < 0)
{
avformat_free_context(pFormatContext_O);
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
return -9;
}
StreamOut->codec->codec_tag = 0;
if(pFormatContext_O->oformat->flags & AVFMT_GLOBALHEADER)
StreamOut->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
break;
}
}
if(!(pOutputFormat->flags & AVFMT_NOFILE))
{
if(avio_open(&pFormatContext_O->pb,MediaName,AVIO_FLAG_WRITE) < 0)
{
avformat_free_context(pFormatContext_O);
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
return -10;
}
}
if(avformat_write_header(pFormatContext_O,NULL) < 0)
{
avio_close(pFormatContext_O->pb);
avformat_free_context(pFormatContext_O);
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
return -11;
}
// AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
// AVBitStreamFilterContext* aacbsfc = av_bitstream_filter_init("aac_adtstoasc");
AVPacket pPacket;
int StreamFrameIndex = 0;
int64_t ts_a = 0,ts_b = 0;
while(1)
{
AVStream *StreamIn,*StreamOut;
int StreamIndex = 0;
if(av_compare_ts(ts_a,pFormatContext_I_V->streams[VideoIndex_I]->time_base,ts_b,pFormatContext_I_A->streams[AudioIndex_I]->time_base) <= 0)
{
StreamIndex = VideoIndex_O;
if(av_read_frame(pFormatContext_I_V,&pPacket) >= 0)
{
do{
StreamIn = pFormatContext_I_V->streams[pPacket.stream_index];
StreamOut = pFormatContext_O->streams[VideoIndex_O];
if(pPacket.stream_index == VideoIndex_I)
{
if(pPacket.pts == AV_NOPTS_VALUE)
{
AVRational TimeBase = StreamIn->time_base;
int64_t Duration = (double)AV_TIME_BASE/av_q2d(StreamIn->r_frame_rate);
pPacket.pts = (double)(StreamFrameIndex*Duration)/(double)(av_q2d(TimeBase)*AV_TIME_BASE);
pPacket.dts = pPacket.pts;
pPacket.duration=(double)Duration/(double)(av_q2d(TimeBase)*AV_TIME_BASE);
StreamFrameIndex++;
}
ts_a = pPacket.pts;
break;
}
}while(av_read_frame(pFormatContext_I_V,&pPacket) >= 0);
}
else
break;
}
else
{
StreamIndex = AudioIndex_O;
if(av_read_frame(pFormatContext_I_A,&pPacket) >= 0)
{
do{
StreamIn = pFormatContext_I_A->streams[pPacket.stream_index];
StreamOut = pFormatContext_O->streams[AudioIndex_O];
if(pPacket.stream_index == AudioIndex_I)
{
if(pPacket.pts == AV_NOPTS_VALUE)
{
AVRational TimeBase = StreamIn->time_base;
int64_t Duration = (double)AV_TIME_BASE/av_q2d(StreamIn->r_frame_rate);
pPacket.pts = (double)(StreamFrameIndex*Duration)/(double)(av_q2d(TimeBase)*AV_TIME_BASE);
pPacket.dts = pPacket.pts;
pPacket.duration=(double)Duration/(double)(av_q2d(TimeBase)*AV_TIME_BASE);
StreamFrameIndex++;
}
ts_b = pPacket.pts;
break;
}
}while(av_read_frame(pFormatContext_I_A,&pPacket) >= 0);
}
else
break;
}
// av_bitstream_filter_filter(h264bsfc,StreamIn->codec,NULL,&pPacket.data,&pPacket.size,pPacket.data,pPacket.size,0);
// av_bitstream_filter_filter(aacbsfc,StreamOut->codec,NULL,&pPacket.data,&pPacket.size,pPacket.data,pPacket.size,0);
pPacket.pts = av_rescale_q_rnd(pPacket.pts,StreamIn->time_base,StreamOut->time_base,(AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pPacket.dts = av_rescale_q_rnd(pPacket.dts,StreamIn->time_base,StreamOut->time_base,(AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pPacket.duration = av_rescale_q(pPacket.duration,StreamIn->time_base,StreamOut->time_base);
pPacket.pos = -1;
pPacket.stream_index = StreamIndex;
if(av_interleaved_write_frame(pFormatContext_O,&pPacket) < 0)
break;
av_free_packet(&pPacket);
}
av_write_trailer(pFormatContext_O);
// av_bitstream_filter_close(h264bsfc);
// av_bitstream_filter_close(aacbsfc);
avio_close(pFormatContext_O->pb);
avformat_free_context(pFormatContext_O);
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
return 0;
}
int main()
{
av_register_all();
StreamToMedia("Video.h264","Audio.aac","Media.ts");
// StreamToMedia("Video.h264","Audio.aac","Media.mp4");
return 0;
}