#include <QtCore/QCoreApplication>
extern "C"
{
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVPacket pkt;
char *in_filename, *out_filename;
int ret, i;
int stream_index = 0;
int *stream_mapping = NULL;
int stream_mapping_size = 0;
if (argc < 3) {
printf("usage: %s input output\n"
"API example program to remux a media file with libavformat and libavcodec.\n"
"The output format is guessed according to the file extension.\n"
"\n", argv[0]);
return 1;
}
in_filename = argv[1];
out_filename = argv[2];
// 1. 打开输入
// 1.1 读取文件头,获取封装格式相关信息
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
printf("Could not open input file '%s'", in_filename);
goto end;
}
// 1.2 解码一段数据,获取流相关信息
if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
printf("Failed to retrieve input stream information");
goto end;
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
// 2. 打开输出
// 2.1 分配输出ctx
avformat_alloc_output_context2(&ofmt_ctx, NULL, "mpegts", out_filename);
if (!ofmt_ctx) {
printf("Could not create output context\n");
ret = AVERROR_UNKNOWN;
goto end;
}
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *out_stream;
AVStream *in_stream = ifmt_ctx->streams[i];
AVCodecParameters *in_codecpar = in_stream->codecpar;
// 2.2 将一个新流(out_stream)添加到输出文件(ofmt_ctx)
out_stream = avformat_new_stream(ofmt_ctx, NULL);
if (!out_stream) {
printf("Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
goto end;
}
// 2.3 将当前输入流中的参数拷贝到输出流中
ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
if (ret < 0) {
printf("Failed to copy codec parameters\n");
goto end;
}
out_stream->id = in_stream->id;
//printf("lvyunxiang test %d\n", out_stream->id);
out_stream->codecpar->codec_tag = 0;
}
int pmt_start_id = 0;
//重新设置节目号等信息
if (0 == strcmp(ifmt_ctx->iformat->name, "mpegts")) //如果输入封装是mpegts,拷贝节目信息
{
AVStream *out_stream = NULL;
AVStream *in_stream = NULL;
//遍历所有节目号
if (ifmt_ctx->nb_programs) {
int j, k, total = 0;
for (j = 0; j < ifmt_ctx->nb_programs; j++) {
AVDictionaryEntry *name = av_dict_get(ifmt_ctx->programs[j]->metadata,
"service_name", NULL, 0);
av_log(NULL, AV_LOG_INFO, " Program %d %s\n", ifmt_ctx->programs[j]->id,
name ? name->value : "");
if (j == 0)
{
pmt_start_id = ifmt_ctx->programs[j]->pmt_pid;
av_opt_set(ofmt_ctx->priv_data, "mpegts_pmt_start_pid",QString::number(pmt_start_id).toStdString().c_str(), 1); //设置pmt起始id
}
//为输出创建节目
AVProgram* program = av_new_program(ofmt_ctx, ifmt_ctx->programs[j]->id); //设置节目id
if(name)
av_dict_set(&program->metadata, "service_name", name->value, 0);
else
av_dict_set(&program->metadata, "service_name", "lvyunxiang test", 0); //设置节目名称
av_dict_set(&program->metadata, "service_provider", "lvyunxiang provide", 0); //服务提供者
program->pcr_pid = ifmt_ctx->programs[j]->pcr_pid;
program->pmt_version = ifmt_ctx->programs[j]->pmt_version;
//复制节目流信息
for (k = 0; k < ifmt_ctx->programs[j]->nb_stream_indexes; k++) //遍历该节目流下所有的流
{
int index = ifmt_ctx->programs[j]->stream_index[k];
av_program_add_stream_index(ofmt_ctx, ifmt_ctx->programs[j]->id,index);
}
}
}
}
else //如果输入类型不是mpegts ,创建节目号 节目id 1
{
AVProgram* program = av_new_program(ifmt_ctx, 1);
//av_dict_set(&program->metadata, "title", "", 0);
av_dict_set(&program->metadata, "service_name", "", 0);
av_dict_set(&program->metadata, "service_provider", "lvyunxiang provide", 0); //服务提供者
for (int i = 0; i < ofmt_ctx->nb_streams; i++)
{
av_program_add_stream_index(ofmt_ctx,1, ofmt_ctx->streams[i]->index);
}
program->pmt_version = 1;
}
av_dump_format(ofmt_ctx, 0, out_filename, 1);
//if(pmt_start_id != 0)
//av_opt_set(ofmt_ctx->priv_data, "mpegts_pmt_start_pid", QString::number(pmt_start_id).toStdString().c_str(), 0); //设置pmt起始id
ofmt = ofmt_ctx->oformat;
if (!(ofmt->flags & AVFMT_NOFILE)) { // TODO: 研究AVFMT_NOFILE标志
// 2.4 创建并初始化一个AVIOContext,用以访问URL(out_filename)指定的资源
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
printf("Could not open output file '%s'", out_filename);
goto end;
}
}
// 3. 数据处理
// 3.1 写输出文件头
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
printf("Error occurred when opening output file\n");
goto end;
}
while (1) {
AVStream *in_stream, *out_stream;
// 3.2 从输出流读取一个packet
ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
av_packet_rescale_ts(&pkt, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
// 3.4 将packet写入输出
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
if (ret < 0) {
printf("Error muxing packet\n");
break;
}
av_packet_unref(&pkt);
}
// 3.5 写输出文件尾
av_write_trailer(ofmt_ctx);
end:
avformat_close_input(&ifmt_ctx);
/* close output */
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
av_freep(&stream_mapping);
if (ret < 0 && ret != AVERROR_EOF) {
printf("Error occurred: %d\n", ret);
return 1;
}
printf("write ok\n");
return a.exec();
}