#include "libavutil/avutil.h"
#include "libavformat/avformat.h"
/*
转封装流程
*/
int main(int argc, char const *argv[])
{
av_log_set_level(AV_LOG_DEBUG);
if (argc < 3)
{
av_log(NULL, AV_LOG_ERROR, "Usage: %s <infileName> <outfileName>\n", argv[0]);
return -1;
}
const char *infileName = argv[1];
const char *outfileName = argv[2];
AVFormatContext *inFmtCtx = NULL;
//1.打开输入媒体文件
int ret = avformat_open_input(&inFmtCtx, infileName, NULL, NULL);
if (ret != 0)
{
av_log(NULL, AV_LOG_ERROR, "open input format failed: %s\n", av_err2str(ret));
return -1;
}
//2.获取输入流信息
ret = avformat_find_stream_info(inFmtCtx, NULL);
if (ret != 0)
{
av_log(NULL, AV_LOG_ERROR, "find input stream failed: %s\n", av_err2str(ret));
goto fail;
}
AVFormatContext *outFmtCtx = NULL;
//3.创建输出流上下文
ret = avformat_alloc_output_context2(&outFmtCtx, NULL, NULL, outfileName);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "alloc output format failed: %s\n", av_err2str(ret));
goto fail;
}
int streamCount = inFmtCtx->nb_streams;
int *handleStreamIndexArray = av_mallocz_array(streamCount, sizeof(int));
if (handleStreamIndexArray == NULL)
{
av_log(NULL, AV_LOG_ERROR, "malloc handle stream index failed\n");
goto fail;
}
int streamIndex = 0;
for (int i = 0; i < streamCount; i++)
{
AVStream *inStream = inFmtCtx->streams[i];
if (inStream->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
inStream->codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
inStream->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
{
handleStreamIndexArray[i] = -1;
continue;
}
handleStreamIndexArray[i] = streamIndex++;
AVStream *outStream = NULL;
//4.创建输出码流的AVStream
outStream = avformat_new_stream(outFmtCtx, NULL);
if (outStream == NULL)
{
ret = -1;
av_log(NULL, AV_LOG_ERROR, "new output stream failed\n");
goto fail;
}
//5.拷贝编码参数
avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);
outStream->codecpar->codec_tag = 0;
}
if (!(outFmtCtx->oformat->flags & AVFMT_NOFILE))
{
ret = avio_open(&outFmtCtx->pb, outfileName, AVIO_FLAG_WRITE);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "open %s file failed\n", outfileName);
goto fail;
}
}
//6.写入视频文件头
ret = avformat_write_header(outFmtCtx, NULL);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "write header failed: %s\n", av_err2str(ret));
goto fail;
}
AVPacket packet;
av_init_packet(&packet);
//7.读取输入视频流
while (av_read_frame(inFmtCtx, &packet) == 0)
{
if (packet.stream_index >= streamCount || handleStreamIndexArray[packet.stream_index] == -1)
{
av_packet_unref(&packet);
continue;
}
AVStream *inStream = inFmtCtx->streams[packet.stream_index];
AVStream *outStream = outFmtCtx->streams[packet.stream_index];
packet.stream_index = handleStreamIndexArray[packet.stream_index];
//8.计算pts、dts、duration
packet.pts = av_rescale_q(packet.pts, inStream->time_base, outStream->time_base);
packet.dts = av_rescale_q(packet.dts, inStream->time_base, outStream->time_base);
packet.duration = av_rescale_q(packet.duration, inStream->time_base, outStream->time_base);
packet.pos = -1;
//9.写入视频流数据
ret = av_interleaved_write_frame(outFmtCtx, &packet);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "av_interleaved_write_frame failed\n");
return -1;
}
av_packet_unref(&packet);
}
//10.写入视频文件末尾
ret = av_write_trailer(outFmtCtx);
if (ret != 0)
{
av_log(NULL, AV_LOG_ERROR, "av_write_trailer failed\n");
return -1;
}
fail:
if (inFmtCtx)
{
avformat_close_input(&inFmtCtx);
}
if (outFmtCtx && !(outFmtCtx->oformat->flags & AVFMT_NOFILE))
{
avio_closep(&outFmtCtx->pb);
}
if (outFmtCtx)
{
avformat_free_context(outFmtCtx);
}
if (handleStreamIndexArray)
{
av_freep(&handleStreamIndexArray);
}
return ret;
}