基于QT+FFMPEG的音视频开发(五)——转码
我的大部分学习都来自雷神,没有基础去雷神博客转转,每次都有很多收获。
https://blog.csdn.net/leixiaohua1020/article/details/42658139
转码,就是将一个不需要的格式转换成为自己需要的格式。
首先,研究不带编解码的转码(更换后缀名??)。
本次实验把avi转码为mp4。
一、输入初始化
const char *url = "my.avi";
AVFormatContext *ic = avformat_alloc_context();
然后获取信息(就不加错误判定了,具体前面解码有讲)
int ret = avformat_open_input(&ic, url, NULL, NULL);
ret = avformat_find_stream_info(ic, NULL);
av_dump_format(ic, 0, url, 0);
二、输出初始化
这步比较简单
AVFormatContext *oc;
const char *outputPath = "out.mp4";
avformat_alloc_output_context2(&oc, NULL, NULL, outputPath);
三、创建输出流
根据输入 in 创建输出 out
使用的都是最新的API
1.使用codecpar替代codec
AVCodec *codec = avcodec_find_decoder(ic->streams[i]->codecpar->codec_id);
AVCodecContext *codecCtx = avcodec_alloc_context3(codec);
AVStream *in = ic->streams[i];
AVStream *out = avformat_new_stream(oc, codec);
2.使用avcodec_parameters_to_context(),avcodec_parameters_from_context()代替了avcodec_copy_context()
ret = avcodec_parameters_to_context(codecCtx, in->codecpar);
codecCtx->codec_tag = 0;
if(oc->oformat->flags & AVFMT_GLOBALHEADER)
codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_parameters_from_context(out->codecpar, codecCtx);
四、打开输出文件获取信息,写文件头
if (avio_open(&oc->pb, outputPath, AVIO_FLAG_READ_WRITE) < 0)
av_dump_format(oc, 0, outputPath, 1);
ret = avformat_write_header(oc, NULL);
五、转换pts、dts并写入
pkt.pts = av_rescale_q_rnd(pkt.pts, in->time_base, out->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in->time_base, out->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in->time_base, out->time_base);
av_interleaved_write_frame(oc, &pkt);
六、写文件尾,释放空间
av_write_trailer(oc);
avformat_close_input(&ic);
if (oc && !(oc->oformat->flags & AVFMT_NOFILE))
avio_close(oc->pb);
avformat_free_context(oc);
下一步研究带编解码的转码。最后,附上源码。
附源码
int main()
{
const char *url = "my.avi";
AVFormatContext *ic = avformat_alloc_context();
int ret = avformat_open_input(&ic, url, NULL, NULL);
ret = avformat_find_stream_info(ic, NULL);
av_dump_format(ic, 0, url, 0);
AVFormatContext *oc;
const char *outputPath = "out.mp4";
avformat_alloc_output_context2(&oc, NULL, NULL, outputPath);
unsigned int i;
for(i = 0; i < ic->nb_streams; i++)
{
AVStream *in = ic->streams[i];
AVCodec *codec = avcodec_find_decoder(ic->streams[i]->codecpar->codec_id);
AVCodecContext *codecCtx = avcodec_alloc_context3(codec);
AVStream *out = avformat_new_stream(oc, codec);
ret = avcodec_parameters_to_context(codecCtx, in->codecpar);
if(ret < 0)
{
//failed
return -1;
}
codecCtx->codec_tag = 0;
if(oc->oformat->flags & AVFMT_GLOBALHEADER)
codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_parameters_from_context(out->codecpar, codecCtx);
if(ret < 0)
{
//failed
return -1;
}
}
if (avio_open(&oc->pb, outputPath, AVIO_FLAG_READ_WRITE) < 0)
{
cout << "Failed to open output file!" << endl;
return -1;
}
av_dump_format(oc, 0, outputPath, 1);
ret = avformat_write_header(oc, NULL);
AVPacket pkt;
av_new_packet(&pkt, 192000);
while(av_read_frame(ic, &pkt) >= 0)
{
AVStream *in = ic->streams[pkt.stream_index];
AVStream *out = oc->streams[pkt.stream_index];
pkt.pts = av_rescale_q_rnd(pkt.pts, in->time_base, out->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in->time_base, out->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in->time_base, out->time_base);
pkt.pos = -1;
av_interleaved_write_frame(oc, &pkt);
av_packet_unref(&pkt);
}
av_write_trailer(oc);
avformat_close_input(&ic);
if (oc && !(oc->oformat->flags & AVFMT_NOFILE))
avio_close(oc->pb);
avformat_free_context(oc);
return 0;
}