#include "combineVideo.h"
int combineVideo::open_input_file()
{
int ret = 0;
ifmt_ctx = (AVFormatContext**)av_malloc((global_ctx.video_num)*sizeof(AVFormatContext*));
for (int i = 0; i < global_ctx.video_num; i++)
{
*(ifmt_ctx + i) = NULL;
const char * Cfilename = global_ctx.filenames[i].toStdString().c_str();
if ((ret = avformat_open_input((ifmt_ctx + i),Cfilename , NULL, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
return ret;
}
if ((ret = avformat_find_stream_info(ifmt_ctx[i], NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
return ret;
}
av_dump_format(ifmt_ctx[i], 0, Cfilename, 0);
}
return 0;
}
int combineVideo::open_output_file()
{
int ret = -1;
const char * out_name = global_ctx.outfilename.toStdString().c_str();
if ((ret = avformat_alloc_output_context2(&out_fmtctx, NULL, NULL, out_name)) < 0)
{
printf("can not alloc context for output!\n");
return ret;
}
//new stream for out put
for (int i = 0; i < ifmt_ctx[0]->nb_streams; i++)
{
if (ifmt_ctx[0]->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
//video_stream_index = i;
out_video_stream = avformat_new_stream(out_fmtctx, NULL);
if (!out_video_stream)
{
printf("Failed allocating output1 video stream\n");
ret = AVERROR_UNKNOWN;
return ret;
}
if ((ret = avcodec_copy_context(out_video_stream->codec, ifmt_ctx[0]->streams[i]->codec)) < 0)
{
printf("can not copy the video codec context!\n");
return ret;
}
avcodec_parameters_from_context(out_video_stream->codecpar, out_video_stream->codec);
out_video_stream->codec->codec_tag = 0;
if(out_fmtctx->oformat->flags & AVFMT_GLOBALHEADER)
{
out_video_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
}
else if (ifmt_ctx[0]->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
//audio_stream_index = i;
out_audio_stream = avformat_new_stream(out_fmtctx, NULL);
if (!out_audio_stream)
{
printf("Failed allocating output1 video stream\n");
ret = AVERROR_UNKNOWN;
return ret;
}
if ((ret = avcodec_copy_context(out_audio_stream->codec, ifmt_ctx[0]->streams[i]->codec)) < 0)
{
printf("can not copy the video codec context!\n");
return ret;
}
avcodec_parameters_from_context(out_audio_stream->codecpar, out_audio_stream->codec);
out_audio_stream->codec->codec_tag = 0;
if(out_fmtctx->oformat->flags & AVFMT_GLOBALHEADER)
{
out_audio_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
}
}
//open output file
if (!(out_fmtctx->oformat->flags & AVFMT_NOFILE))
{
if ((ret = avio_open(&out_fmtctx->pb, out_name, AVIO_FLAG_WRITE)) < 0)
{
printf("can not open the out put file handle!\n");
return ret;
}
}
//write out file header
if ((ret = avformat_write_header(out_fmtctx, NULL)) < 0)
{
printf( "Error occurred when opening video output file\n");
return ret;
}
av_dump_format(out_fmtctx, 0, out_name, 1);
}
int combineVideo::videocombine(QStringList fileList,QString outputfilename)
{
AVPacket pkt;
int pts_v, pts_a, dts_v, dts_a;
//sprintf(out_name, "combine.%s", argv[3]);
int iRet = 0;
initfileInfo(fileList,outputfilename);
av_register_all();
if(iRet = open_input_file() < 0)
{
freeAllPointer();
return iRet;
}
if(iRet = open_output_file() < 0)
{
freeAllPointer();
return iRet;
}
for (int i = 0; i < global_ctx.video_num; i++)
{
while(1)
{
if(0 > av_read_frame(ifmt_ctx[i], &pkt))
{
float vedioDuraTime, audioDuraTime;
video_stream_index = getOutAVCodecContextIndex(ifmt_ctx[i],AVMEDIA_TYPE_VIDEO);
audio_stream_index = getOutAVCodecContextIndex(ifmt_ctx[i],AVMEDIA_TYPE_AUDIO);
//calc the first media dura time
vedioDuraTime = pts_v * av_q2d(ifmt_ctx[i]->streams[video_stream_index]->time_base);
audioDuraTime = pts_a * av_q2d(ifmt_ctx[i]->streams[audio_stream_index]->time_base);
//calc the pts and dts end of the first media
if (audioDuraTime > vedioDuraTime)//得出
{
dts_v = pts_v = audioDuraTime / av_q2d(ifmt_ctx[i]->streams[video_stream_index]->time_base);
dts_a++;
pts_a++;
}
else
{
dts_a = pts_a = vedioDuraTime / av_q2d(ifmt_ctx[i]->streams[audio_stream_index]->time_base);
dts_v++;
pts_v++;
}
//input_ctx = in2_fmtctx;
break;
}
AVStream *Newstream = ifmt_ctx[i]->streams[pkt.stream_index];
if (AVMEDIA_TYPE_VIDEO == Newstream->codec->codec_type)
{
if (i > 0)
{
pkt.pts += pts_v;
pkt.dts += dts_v;
}
else
{
pts_v = pkt.pts;
dts_v = pkt.dts;
}
}
else if (AVMEDIA_TYPE_AUDIO == Newstream->codec->codec_type)
{
if (i > 0)
{
pkt.pts += pts_a;
pkt.dts += dts_a;
}
else
{
pts_a = pkt.pts;
dts_a = pkt.dts;
}
}
pkt.pts = av_rescale_q_rnd(pkt.pts, ifmt_ctx[i]->streams[pkt.stream_index]->time_base,
out_fmtctx->streams[pkt.stream_index]->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, ifmt_ctx[i]->streams[pkt.stream_index]->time_base,
out_fmtctx->streams[pkt.stream_index]->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.pos = -1;
//double showtime2 = pkt.pts*av_q2d(out_fmtctx->streams[pkt.stream_index]->time_base);
//printf( "write packet\n");
if (av_interleaved_write_frame(out_fmtctx, &pkt) < 0)
{
printf( "Error muxing packet\n");
//break;
}
av_free_packet(&pkt);
}
}
av_write_trailer(out_fmtctx);
freeAllPointer();
printf( "write end\n");
}
void combineVideo::initfileInfo(QStringList fileList,QString outputfilename)
{
int Isize = fileList.size();
//global_ctx = (GlobalContext*)av_malloc(sizeof(GlobalContext));
for (int i = 0; i < Isize; ++i)
{
QString strText = fileList.at(i);
global_ctx.filenames.append(strText);
}
global_ctx.video_num = Isize;
global_ctx.outfilename = outputfilename;
}
void combineVideo::freeAllPointer()
{
for (int i = 0; i < global_ctx.video_num; i++)
avformat_close_input(&(ifmt_ctx[i]));
if (out_fmtctx && !(out_fmtctx->oformat->flags & AVFMT_NOFILE))
avio_close(out_fmtctx->pb);
avformat_free_context(out_fmtctx);