|
参考雷神的mux代码,合成h264文件与aac文件为mp4,合成之后的mp4文件在Chrome以及mac的播放器播放会有卡顿,不知道什么原因,求助高手。代码:
// mux.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
extern "C"
{
#include "libavformat/avformat.h"
}
int main()
{
int ret = 0;
unsigned int iloop = 0;
int video_index = -1, audio_index = -1;
int64_t video_pts = 0, audio_pts = 0;
int64_t frame_index = 0;
int64_t frame_gap = 0;
const char* raw_video_file = "output.h264";
const char* raw_audio_file = "output.aac";
const char* out_video_file = "output.mp4";
AVStream* out_stream_video;
AVStream* out_stream_audio;
AVStream* in_stream;
AVFormatContext* ifmt_video = NULL;
AVFormatContext* ifmt_audio = NULL;
AVFormatContext* ofmt_ctx = NULL;
AVPacket* avpkt = av_packet_alloc();
// 打开输入视频文件
ret = avformat_open_input(&ifmt_video, raw_video_file, NULL, NULL);
if (ret < 0)
{
printf("avformat_open_input video fail,err=%d", ret);
ret = -1;
goto end;
}
ret = avformat_find_stream_info(ifmt_video, NULL);
if (ret < 0)
{
printf("avformat_find_stream_info video fail,err=%d", ret);
ret = -2;
goto end;
}
av_dump_format(ifmt_video,0,raw_video_file,0);
// 打开输入音频文件
ret = avformat_open_input(&ifmt_audio, raw_audio_file, NULL, NULL);
if (ret < 0)
{
printf("avformat_open_input audio fail,err=%d", ret);
ret = -3;
goto end;
}
ret = avformat_find_stream_info(ifmt_audio, NULL);
if (ret < 0)
{
printf("avformat_find_stream_info audio fail,err=%d", ret);
ret = -4;
goto end;
}
av_dump_format(ifmt_audio, 0, raw_audio_file, 0);
// 打开输出文件
ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_video_file);
if (ret < 0)
{
printf("avformat_alloc_output_context2 fail,err=%d", ret);
ret = -5;
goto end;
}
// 从视频文件中查找视频流,然后在输出文件添加流
for (iloop = 0; iloop < ifmt_video->nb_streams; iloop++)
{
if (ifmt_video->streams[iloop]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
out_stream_video = avformat_new_stream(ofmt_ctx, NULL);
in_stream = ifmt_video->streams[iloop];
avcodec_parameters_copy(out_stream_video->codecpar, in_stream->codecpar);
out_stream_video->codecpar->codec_tag = 0;
video_index =iloop;
}
else
{
continue;
}
}
//}
// 从音频文件中查找音频流,然后在输出文件添加流
for (iloop = 0; iloop < ifmt_audio->nb_streams; iloop++)
{
if (ifmt_audio->streams[iloop]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
out_stream_audio = avformat_new_stream(ofmt_ctx, NULL);
in_stream = ifmt_audio->streams[iloop];
avcodec_parameters_copy(out_stream_audio->codecpar, in_stream->codecpar);
out_stream_audio->codecpar->codec_tag = 0;
audio_index = iloop;
}
else
{
continue;
}
}
if (!(ofmt_ctx->flags & AVFMT_NOFILE))
{
avio_open(&ofmt_ctx->pb, out_video_file, AVIO_FLAG_WRITE);
}
// 写header
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0)
{
printf("avformat_write_header fail,err=%d\n", ret);
ret = -6;
goto end;
}
//封装
while (true)
{
if (av_compare_ts(video_pts, ifmt_video->streams[video_index]->time_base, audio_pts, ifmt_audio->streams[audio_index]->time_base) <= 0)
{
// 写视频
ret = av_read_frame(ifmt_video,avpkt);
if (ret < 0)
{
break;
}
if (avpkt->pts == AV_NOPTS_VALUE)
{
// h264视频文件没有pts,需要手动设置
frame_gap = (int64_t)(AV_TIME_BASE / av_q2d(ifmt_video->streams[video_index]->r_frame_rate));
avpkt->pts = av_rescale_q_rnd(frame_gap * frame_index, AVRational{1,AV_TIME_BASE}, ifmt_video->streams[video_index]->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
avpkt->dts = avpkt->pts;
avpkt->duration = av_rescale_q_rnd(frame_gap, AVRational{ 1,AV_TIME_BASE }, ifmt_video->streams[video_index]->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
/*avpkt->pts = (int64_t)(frame_index * frame_gap) / (int64_t)(av_q2d(ifmt_video->streams[video_index]->time_base) * AV_TIME_BASE);
avpkt->dts = avpkt->pts;
avpkt->duration = (int64_t)frame_gap / (int64_t)(av_q2d(ifmt_video->streams[video_index]->time_base) * AV_TIME_BASE);*/
frame_index++;
video_pts = avpkt->pts;
}
avpkt->stream_index = 0;
av_packet_rescale_ts(avpkt, ifmt_video->streams[video_index]->time_base, ofmt_ctx->streams[0]->time_base);
ret = av_interleaved_write_frame(ofmt_ctx, avpkt);
if (ret < 0)
{
printf("av_interleaved_write_frame video fail,err=%d\n", ret);
break;
}
}
else
{
// 写音频
ret = av_read_frame(ifmt_audio, avpkt);
if (ret < 0)
{
break;
}
audio_pts = avpkt->pts;
avpkt->stream_index = 1;
// aac文件是含有pts信息的
av_packet_rescale_ts(avpkt, ifmt_audio->streams[audio_index]->time_base, ofmt_ctx->streams[1]->time_base);
av_interleaved_write_frame(ofmt_ctx, avpkt);
}
av_packet_unref(avpkt);
}
av_write_trailer(ofmt_ctx);
end:
avformat_free_context(ifmt_video);
avformat_free_context(ifmt_audio);
//avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
return ret;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件
|
|