最简单的基于FFMPEG的封装格式转换器(无编解码)
2019獨角獸企業(yè)重金招聘Python工程師標準>>>
本文介紹一個基于FFMPEG的封裝格式轉換器。所謂的封裝格式轉換,就是在AVI,FLV,MKV,MP4這些格式之間轉換(對應.avi,.flv,.mkv,.mp4文件)。需要注意的是,本程序并不進行視音頻的編碼和解碼工作。而是直接將視音頻壓縮碼流從一種封裝格式文件中獲取出來然后打包成另外一種封裝格式的文件。傳統(tǒng)的轉碼程序工作原理如下圖所示:
上圖例舉了一個舉例:FLV(視頻:H.264,音頻:AAC)轉碼為AVI(視頻:MPEG2,音頻MP3)的例子。可見視頻轉碼的過程通俗地講相當于把視頻和音頻重新“錄”了一遍。
本程序的工作原理如下圖所示:
由圖可見,本程序并不進行視頻和音頻的編解碼工作,因此本程序和普通的轉碼軟件相比,有以下兩個特點:
處理速度極快。視音頻編解碼算法十分復雜,占據(jù)了轉碼的絕大部分時間。因為不需要進行視音頻的編碼和解碼,所以節(jié)約了大量的時間。
視音頻質量無損。因為不需要進行視音頻的編碼和解碼,所以不會有視音頻的壓縮損傷。 ?
下面貼上代碼,代碼是從FFmpeg的例子改編的,平臺是VC2010。
/**最簡單的基于FFmpeg的封裝格式轉換器*Simplest?FFmpeg?Remuxer**雷霄驊?Lei?Xiaohua*leixiaohua1020@126.com*中國傳媒大學/數(shù)字電視技術*Communication?University?of?China?/?Digital?TV?Technology*http://blog.csdn.net/leixiaohua1020**本程序實現(xiàn)了視頻封裝格式之間的轉換。*需要注意的是本程序并不改變視音頻的編碼格式。**?This?software?converts?a?media?file?from?one?container?format*?to?another?container?format?without?encoding/decoding?video?files.*/#include?"stdafx.h"extern?"C" { #include?"libavformat/avformat.h" };int?_tmain(int?argc,?_TCHAR*?argv[]) {AVOutputFormat?*ofmt?=?NULL;//輸入對應一個AVFormatContext,輸出對應一個AVFormatContext//(Input?AVFormatContext?and?Output?AVFormatContext)AVFormatContext?*ifmt_ctx?=?NULL,?*ofmt_ctx?=?NULL;AVPacket?pkt;const?char?*in_filename,?*out_filename;int?ret,?i;if?(argc?<?3)?{printf("usage:?%s?input?output\n""Remux?a?media?file?with?libavformat?and?libavcodec.\n""The?output?format?is?guessed?according?to?the?file?extension.\n""Modified?by?Lei?Xiaohua,?leixiaohua1020@126.com\n""Communication?University?of?China?/?Digital?TV?Technology\n""http://blog.csdn.net/leixiaohua1020",?argv[0]);return?1;}in_filename??=?argv[1];//輸入文件名(Input?file?URL)out_filename?=?argv[2];//輸出文件名(Output?file?URL)av_register_all();//輸入(Input)if?((ret?=?avformat_open_input(&ifmt_ctx,?in_filename,?0,?0))?<?0)?{printf(?"Could?not?open?input?file.");goto?end;}if?((ret?=?avformat_find_stream_info(ifmt_ctx,?0))?<?0)?{printf(?"Failed?to?retrieve?input?stream?information");goto?end;}av_dump_format(ifmt_ctx,?0,?in_filename,?0);//輸出(Output)avformat_alloc_output_context2(&ofmt_ctx,?NULL,?NULL,?out_filename);if?(!ofmt_ctx)?{printf(?"Could?not?create?output?context\n");ret?=?AVERROR_UNKNOWN;goto?end;}ofmt?=?ofmt_ctx->oformat;for?(i?=?0;?i?<?ifmt_ctx->nb_streams;?i++)?{//根據(jù)輸入流創(chuàng)建輸出流(Create?output?AVStream?according?to?input?AVStream)AVStream?*in_stream?=?ifmt_ctx->streams[i];AVStream?*out_stream?=?avformat_new_stream(ofmt_ctx,?in_stream->codec->codec);if?(!out_stream)?{printf(?"Failed?allocating?output?stream\n");ret?=?AVERROR_UNKNOWN;goto?end;}//復制AVCodecContext的設置(Copy?the?settings?of?AVCodecContext)ret?=?avcodec_copy_context(out_stream->codec,?in_stream->codec);if?(ret?<?0)?{printf(?"Failed?to?copy?context?from?input?to?output?stream?codec?context\n");goto?end;}out_stream->codec->codec_tag?=?0;if?(ofmt_ctx->oformat->flags?&?AVFMT_GLOBALHEADER)out_stream->codec->flags?|=?CODEC_FLAG_GLOBAL_HEADER;}//輸出一下格式------------------av_dump_format(ofmt_ctx,?0,?out_filename,?1);//打開輸出文件(Open?output?file)if?(!(ofmt->flags?&?AVFMT_NOFILE))?{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;}}//寫文件頭(Write?file?header)ret?=?avformat_write_header(ofmt_ctx,?NULL);if?(ret?<?0)?{printf(?"Error?occurred?when?opening?output?file\n");goto?end;}int?frame_index=0;while?(1)?{AVStream?*in_stream,?*out_stream;//獲取一個AVPacket(Get?an?AVPacket)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];/*?copy?packet?*///轉換PTS/DTS(Convert?PTS/DTS)pkt.pts?=?av_rescale_q_rnd(pkt.pts,?in_stream->time_base,?out_stream->time_base,?(AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));pkt.dts?=?av_rescale_q_rnd(pkt.dts,?in_stream->time_base,?out_stream->time_base,?(AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));pkt.duration?=?av_rescale_q(pkt.duration,?in_stream->time_base,?out_stream->time_base);pkt.pos?=?-1;//寫入(Write)ret?=?av_interleaved_write_frame(ofmt_ctx,?&pkt);if?(ret?<?0)?{printf(?"Error?muxing?packet\n");break;}printf("Write?%8d?frames?to?output?file\n",frame_index);av_free_packet(&pkt);frame_index++;}//寫文件尾(Write?file?trailer)av_write_trailer(ofmt_ctx); end:avformat_close_input(&ifmt_ctx);/*?close?output?*/if?(ofmt_ctx?&&?!(ofmt->flags?&?AVFMT_NOFILE))avio_close(ofmt_ctx->pb);avformat_free_context(ofmt_ctx);if?(ret?<?0?&&?ret?!=?AVERROR_EOF)?{printf(?"Error?occurred.\n");return?-1;}return?0; }
調試的時候,只需要“右鍵工程->調試->命令行參數(shù)”里面設置輸入的文件名和輸出的文件名就可以了。
下圖顯示了一個測試的輸入文件的視音頻參數(shù)。
?
下圖顯示了輸出文件的視音頻參數(shù)。可以看出除了視頻的封裝格式從flv轉換成了mp4,其他有關視音頻編碼的參數(shù)沒有任何變化。
完整工程下載地址:
http://download.csdn.net/detail/leixiaohua1020/7323491
轉載于:https://my.oschina.net/leixiaohua1020/blog/302150
總結
以上是生活随笔為你收集整理的最简单的基于FFMPEG的封装格式转换器(无编解码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL学习笔记_4_MySQL创建数
- 下一篇: WebSocket剖析