音视频开发(五)——转码


我的大部分学习都来自雷神,没有基础去雷神博客转转,每次都有很多收获。
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;
}

猜你喜欢

转载自blog.csdn.net/Mr__Hu/article/details/92780233