doorxp

Blog

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 & lt; 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 & lt; 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;
}

发表评论:

Powered By Z-BlogPHP 1.5.1 Zero

Copyright doorxp.com Rights Reserved.