目录

ffmpeg合并复用音频和视频文件,组成mp4

目录

ffmpeg合并(复用)音频和视频文件,组成mp4

ffmpeg合并(复用)音频和视频文件,组成mp4。程序如下:

/*
合并音频和视频,形成音视频
*/

extern "C"
{
#include "libavutil/avutil.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavcodec/avcodec.h"
}


#pragma warning(disable:4996)


int main()
{
	//
	const char *srcMedia1 = "out/t2Video.h264";
	const char *srcMedia2 = "out/T2audio.aac";
	const char *destMedia = "out/T2.mp4";
	char errors[200] = { 0 };
	AVFormatContext *inFormatContext1 = NULL;
	AVFormatContext *inFormatContext2 = NULL;
	AVFormatContext *outFormatContext = NULL;

	//输入上下文1-视频
	int ret = 0;
	av_log_set_level(AV_LOG_INFO);
	av_register_all();
	ret = avformat_open_input(&inFormatContext1, srcMedia1, NULL, NULL);
	if (ret != 0)
	{
		av_strerror(ret, errors, 200);
		av_log(NULL, AV_LOG_WARNING, "error, ret=%d, msg=%s\n", ret, errors);
		return -1;
	}
	avformat_find_stream_info(inFormatContext1, NULL);
	av_dump_format(inFormatContext1, -1, srcMedia1, 0);
	//输入上下文1-音频
	ret = avformat_open_input(&inFormatContext2, srcMedia2, NULL, NULL);
	avformat_find_stream_info(inFormatContext2, NULL);
	av_dump_format(inFormatContext2, -1, srcMedia2, 0);
	//输出上下文
	avformat_alloc_output_context2(&outFormatContext, NULL, NULL, destMedia);
	AVOutputFormat *outFormat = outFormatContext->oformat;
	int stream1 = 0;
	AVStream *inStream1 = NULL;
	//复制流信息
	if(inFormatContext1->nb_streams > 0)
	{
		stream1 = 1;
		inStream1 = inFormatContext1->streams[0];
		AVStream *outStream = avformat_new_stream(outFormatContext, NULL);
		avcodec_parameters_copy(outStream->codecpar, inStream1->codecpar);
		outStream->codecpar->codec_tag = 0;
	}
	int stream2 = 0;
	AVStream *inStream2 = NULL;
	if (inFormatContext2->nb_streams > 0)
	{
		stream2 = 1;
		inStream2 = inFormatContext2->streams[0];
		AVStream *outStream = avformat_new_stream(outFormatContext, NULL);
		avcodec_parameters_copy(outStream->codecpar, inStream2->codecpar);
		outStream->codecpar->codec_tag = 0;
	}
	av_dump_format(outFormatContext, -1, destMedia, 1);
	//打开文件
	avio_open(&outFormatContext->pb, destMedia, AVIO_FLAG_WRITE);
	avformat_write_header(outFormatContext, NULL);
	int64_t curPts1 = 0;
	int64_t curPts2 = 0;
	
	AVPacket avPacket;
	av_init_packet(&avPacket);
	//输入流时间基
	AVRational inStream1time = inStream1->time_base;
	AVRational inStream2time = inStream2->time_base;
	int frameIndex = 0;
	//交替写入音频和视频数据
	while (stream1 || stream2)
	{
		if (stream1 && (!stream2 || av_compare_ts(curPts1, inStream1time, curPts2, inStream2time) <= 0))
		{
			ret = av_read_frame(inFormatContext1, &avPacket);
			if (ret < 0)
			{
				stream1 = 0;
				continue;
			}
			//raw h264无pts,手动添加
			if (avPacket.pts == AV_NOPTS_VALUE)
			{
				AVRational timeBase = inStream1time;
				int64_t calcDuration = AV_TIME_BASE / av_q2d(inStream1->r_frame_rate);
				avPacket.pts = (double)(frameIndex*calcDuration) / (av_q2d(timeBase)*AV_TIME_BASE);
				avPacket.dts = avPacket.pts;
				avPacket.duration = (double)calcDuration / (av_q2d(timeBase)*AV_TIME_BASE);
				frameIndex++;
			}
			curPts1 = avPacket.pts;
			AVStream *outStream = outFormatContext->streams[0];
			avPacket.pts = av_rescale_q_rnd(avPacket.pts, inStream1time, outStream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
			avPacket.dts = avPacket.pts;
			avPacket.duration = av_rescale_q(avPacket.duration, inStream1time, outStream->time_base);
			avPacket.pos = -1;
			avPacket.stream_index = 0;
			//av_log(NULL, AV_LOG_INFO, "xxxxxxxxx%d, dts=%lld, pts=%lld, duration=%lld\n", frameIndex, avPacket.dts, avPacket.pts, avPacket.duration);
			stream1 = !av_interleaved_write_frame(outFormatContext, &avPacket);
		}
		else if (stream2)
		{
			ret = av_read_frame(inFormatContext2, &avPacket);
			if (ret < 0)
			{
				stream2 = 0;
				continue;
			}
			//raw aac无pts,手动添加
			if (avPacket.pts == AV_NOPTS_VALUE)
			{
				AVRational timeBase = inStream2time;
				int64_t calcDuration = AV_TIME_BASE / av_q2d(inStream2->r_frame_rate);
				avPacket.pts = (double)(frameIndex*calcDuration) / (av_q2d(timeBase)*AV_TIME_BASE);
				avPacket.dts = avPacket.pts;
				avPacket.duration = (double)calcDuration / (av_q2d(timeBase)*AV_TIME_BASE);
				frameIndex++;
			}
			curPts2 = avPacket.pts;
			AVStream *outStream = outFormatContext->streams[1];
			avPacket.pts = av_rescale_q_rnd(avPacket.pts, inStream2time, outStream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
			avPacket.dts = avPacket.pts;
			avPacket.duration = av_rescale_q(avPacket.duration, inStream2time, outStream->time_base);
			avPacket.pos = -1;
			avPacket.stream_index = 1;
			av_log(NULL, AV_LOG_INFO, "xxxxxxxxx%d, size:%5d, dts=%lld, pts=%lld, duration=%lld\n", frameIndex, avPacket.size, avPacket.dts, avPacket.pts, avPacket.duration);
			stream2 = !av_interleaved_write_frame(outFormatContext, &avPacket);
		}
		av_packet_unref(&avPacket);
	}
	ret = av_write_trailer(outFormatContext);
	if (ret != 0)
	{
		av_strerror(ret, errors, 200);
		av_log(NULL, AV_LOG_WARNING, "av_write_trailer error: ret=%d, msg=%s\n", ret, errors);
	}

	//释放资源
	avformat_close_input(&inFormatContext1);
	avformat_close_input(&inFormatContext2);
	avio_close(outFormatContext->pb);

	return 0;
}

相关链接: