操作系统:ubuntu
注意事项:
1.ts文件顺序必须正确,也就是下一帧的dst和pst要比上一帧的大,否则会报错
2.codecpar->codec_tag要设置为0,否则报错Tag [27][0][0][0] incompatible with output codec id ‘27’ (avc1)
3.设置output的max_streams数目,默认是1000,超过此数目就会报错
#include <iostream>
#include <dirent.h>
#include <vector>
extern "C" {
#include "include/libavformat/avformat.h"
#include "include/libavcodec/avcodec.h"
}
//#pragma comment(lib,"avformat.lib")
//#pragma comment(lib,"avcodec.lib")
using namespace std;
int ts2Mp4(const string,const string,int);
int main(int argc, char* argv[])
{
//const string ts_filename = argv[1];
//const string output_filename = "../1.mp4";//argv[2];
ts2Mp4(argv[1],argv[2],atoi(argv[3]));
return 0;
}
int ts2Mp4(const string ts_path,const string mp4_path,int ts_count){
/*vector<string> ts_list;
DIR *pDir;
struct dirent* ptr;
if(!(pDir = opendir(ts_path.c_str()))){
printf("cannot open ts dir\n");
return -1;
}
while((ptr = readdir(pDir))!=0) {
if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name,"..")!=0){
ts_list.push_back(ptr->d_name);
}
}
closedir(pDir);*/
// create output context
AVFormatContext* output_ctx = NULL;
if (avformat_alloc_output_context2(&output_ctx, NULL, NULL, mp4_path.c_str()) < 0) {
fprintf(stderr, "Failed to create output context\n");
return -1;
}
//set the max streams number,default is 1000
output_ctx->max_streams=3000;
int video_stream_idx = -1;
vector<AVFormatContext*> input_ctx_list;
for(int i=0;i<ts_count;i++){
// open input file
char ts[256];
sprintf(ts,"%s%s%d%s",ts_path.c_str(),"/",i,".ts");
//string ts=tmp;
printf("%s\n",ts);
if(strcmp(".ts",strstr(ts,".ts"))!=0) continue;
AVFormatContext* input_ctx = NULL;
if (avformat_open_input(&input_ctx, ts, NULL, NULL) != 0) {
fprintf(stderr, "Failed to open input file '%s'\n", ts);
return -1;
}
if (avformat_find_stream_info(input_ctx, NULL) < 0) {
fprintf(stderr, "Failed to retrieve input stream information\n");
return -1;
}
input_ctx_list.push_back(input_ctx);
// add streams
for (int i = 0; i < input_ctx->nb_streams; i++) {
AVStream* in_stream = input_ctx->streams[i];
AVCodecParameters* in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type == AVMEDIA_TYPE_VIDEO || in_codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
AVStream* out_stream = avformat_new_stream(output_ctx, NULL);
if (!out_stream) {
fprintf(stderr, "Failed to allocate output stream\n");
return -1;
}
if (avcodec_parameters_copy(out_stream->codecpar, in_codecpar) < 0) {
fprintf(stderr, "Failed to copy codec parameters\n");
return -1;
}
out_stream->codecpar->codec_tag = 0;
if (in_codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
video_stream_idx = out_stream->index;
}
}
}
// open output file
if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&output_ctx->pb, mp4_path.c_str(), AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "Could not open output file '%s'\n", mp4_path.c_str());
return -1;
}
}
// write header
if (avformat_write_header(output_ctx, NULL) < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
return -1;
}
int pkt_cnt = 0;
// copy packets
//int stream_index = 0;
for(int i=0;i<input_ctx_list.size();i++){
AVFormatContext* input_ctx=input_ctx_list[i];
AVPacket packet;
int ret = 0;
while (av_read_frame(input_ctx, &packet) >= 0) {
//printf("%d,%d\n",video_stream_idx,packet.stream_index);
AVStream* in_stream = input_ctx->streams[packet.stream_index];
AVStream* out_stream = output_ctx->streams[packet.stream_index];
// copy packet
packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base,
(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base,
(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
//printf("%ld,%ld,%ld\n",packet.pts,packet.dts,packet.duration);
packet.pos = -1;
if (packet.stream_index == video_stream_idx) {
//printf("Send video %8d\n", pkt_cnt);
pkt_cnt++;
}
ret = av_interleaved_write_frame(output_ctx, &packet);
if (ret < 0) {
fprintf(stderr, "Error muxing packet\n");
break;
}
av_packet_unref(&packet);
}
// close input
avformat_close_input(&input_ctx);
}
// write trailer
if (av_write_trailer(output_ctx) < 0) {
fprintf(stderr, "Error occurred when writing trailer\n");
return -1;
}
// close output
if (output_ctx && !(output_ctx->oformat->flags & AVFMT_NOFILE))
avio_closep(&output_ctx->pb);
avformat_free_context(output_ctx);
printf("convert success!\n");
return 0;
}