// 环境: Qt5.7.1 64位
// 只需要把LOG的宏定义和Qt的头文件改了,就可以直接编译
#include <QDebug>
#include <QString>
#include <stdio.h>
#include <stdlib.h>
#include <qbytearray.h>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavutil/timestamp.h>
}
#define STR(str) QString::fromLocal8Bit((char*)str)
#define LOG qDebug()
int main()
{
char* ifname= "D:/fmt.mp4";
char* ofname= "D:/dst.mkv";
int ret=-1;
AVFormatContext* ic=0, *oc=0;
ret=avformat_open_input(&ic, ifname, 0, 0);
avformat_find_stream_info(ic, 0);
if(ret<0)
exit(1);
av_dump_format(ic, 0, "input", 0);
ret=avformat_alloc_output_context2(&oc, 0, 0,ofname);
if(ret<0)
exit(1);
// 创建一个和ic流数量相同大小的数组,保存ic的st的判断值
// 若流有效则写入创建的oc流索引,否则设为无效值(-1)
int nb_st=0;
int st_mp_sz= ic->nb_streams;
int* st_info= (int*)av_mallocz_array(ic->nb_streams, sizeof(int));
AVStream* ist=0, *ost=0;
for(int i=0; i<ic->nb_streams; ++i)
{
ist= ic->streams[i];
if(ist->codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
ist->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
ist->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE){
LOG << "not media type stream:" << i;
st_info[i]= -1;
continue;
}
st_info[i]= nb_st++;
ost= avformat_new_stream(oc, 0); // no need to encode, so codec is NULL
avcodec_parameters_copy(ost->codecpar, ist->codecpar);
ost->codecpar->codec_tag= 0; // The info of codec is Empty
}
av_dump_format(oc, 0, "output", 1);
if(!(oc->oformat->flags & AVFMT_NOFILE)){ // 若不是自动打开文件的模式,则需要此手动操作
avio_open2(&oc->pb, ofname, AVIO_FLAG_WRITE, 0, 0);
}
AVPacket* pkt= av_packet_alloc();
avformat_write_header(oc, 0);
while(av_read_frame(ic, pkt)>=0)
{
ist= ic->streams[pkt->stream_index];
if(pkt->stream_index >=st_mp_sz || st_info[pkt->stream_index]<0){
LOG << "this pkt is not media type, idx:" << pkt->stream_index;
av_packet_unref(pkt);
continue;
}
// 再封装pkt
pkt->stream_index= st_info[pkt->stream_index];
ost= oc->streams[pkt->stream_index];
pkt->pts= av_rescale_q_rnd(pkt->pts,ist->time_base,ost->time_base,AVRounding(AV_ROUND_INF|AV_ROUND_PASS_MINMAX));
pkt->dts= av_rescale_q_rnd(pkt->dts,ist->time_base,ost->time_base, AVRounding(AV_ROUND_INF|AV_ROUND_PASS_MINMAX));
pkt->duration= av_rescale_q(pkt->duration, ist->time_base, ost->time_base);
pkt->pos= -1;
av_interleaved_write_frame(oc, pkt);
av_packet_unref(pkt);
LOG << "sucess write pkt, pts:" << pkt->pts;
}
av_write_trailer(oc);
end:
avformat_close_input(&ic);
if(oc && !(oc->oformat->flags & AVFMT_NOFILE))
avio_closep(&oc->pb);
avformat_free_context(oc);
av_packet_free(&pkt);
av_freep(&st_info);
return 0;
}
需要注意的是, 转封装时可能需要转换pts.
转自: https://blog.csdn.net/weixin_42881084/article/details/82534567
网友评论