Loading... ## 1、前言 本文不涉及音频和视频的编解码操作,仅仅是转换视频的封装格式,比如mp4转flv,mp4转mkv等,也可以认为仅仅是为文件重命名,更改了文件后缀而已。 由于不涉及音视频的转码操作,因此此程序处理速度极快。需要知道的是,音视频编解码的算法非常复杂,占用了很多的CPU,这部分也消耗了是视频转码的绝大部分时间。关于视频转码的API使用方法将在之后的博客中详细介绍,本文只关注于转封装。 只转封装的工作原理如下图所示:  ## 2、转封装流程  ### 2.1 打开媒体文件,读取音视频流信息 ```cpp int ret; //打开媒体文件 if(avformat_open_input(&ifmt_ctx_, this->input_file_.c_str(), NULL, NULL) < 0){ printf("file open error!"); return; } //读取音视频流信息 if(avformat_find_stream_info(ifmt_ctx_, 0) < 0){ printf("stream info error!"); return; } //打印视频信息 av_dump_format(ifmt_ctx_, 0, input_file_.c_str(), 0); ``` ### 2.2 创建输出对象 ```cpp //给AVFormatContext分配动态内存 avformat_alloc_output_context2(&ofmt_ctx_, NULL, NULL, output_file_.c_str()); if(!ofmt_ctx_){ printf("can not create output"); return; } //得到AVOutputFormat对象 ofmt = ofmt_ctx_->oformat; ``` ### 2.3 数据拷贝 #### 2.3.1 读取音视频流,复制参数信息 ```cpp //读取音视频流 for(unsigned int i = 0; i < ifmt_ctx_->nb_streams; i++){ AVStream* out_stream = NULL; AVStream* in_stream = ifmt_ctx_->streams[i]; AVCodecParameters* in_codepar = in_stream->codecpar; if(in_codepar->codec_type != AVMEDIA_TYPE_VIDEO && in_codepar->codec_type != AVMEDIA_TYPE_AUDIO && in_codepar->codec_type != AVMEDIA_TYPE_SUBTITLE){ continue; } //新建输出流 out_stream = avformat_new_stream(ofmt_ctx_, NULL); if(!out_stream){ printf("Failed allocat output stream"); return; } //copy编码参数,上下文信息 ret = avcodec_parameters_copy(out_stream->codecpar, in_codepar); if(ret < 0){ printf("codec copy error!"); return; } out_stream->codecpar->codec_tag = 0; } ``` ### 2.3.2 初始化内存 ```cpp //初始化AVIOContext,文件操作由他完成 if(!(ofmt->flags & AVFMT_NOFILE)){ ret = avio_open(&ofmt_ctx_->pb, output_file_.c_str(), AVIO_FLAG_WRITE); if(ret < 0){ printf("can not open file"); return; } } ``` ### 2.3.3 拷贝数据 ```cpp //写入媒体头文件 ret = avformat_write_header(ofmt_ctx_, NULL); if(ret < 0){ printf("can not write"); return; } while(1){ AVStream *in_stream, *out_stream; //读出每一帧数据 ret = av_read_frame(ifmt_ctx_, pkt); if(ret < 0){ printf("over"); 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); //数据在媒体流中的为止,未知设为-1 pkt->pos = -1; //将包写入输出媒体文件 ret = av_interleaved_write_frame(ofmt_ctx_, pkt); if(ret < 0){ printf("erroe muxing packet"); break; } //减少引用计数,避免内存泄漏 av_packet_unref(pkt); } //写入尾部信息 av_write_trailer(ofmt_ctx_); ``` ### 2.4 释放内存 ```cpp //释放AVPacket av_packet_free(&pkt); //打印输出文件信息 av_dump_format(ofmt_ctx_, 0, output_file_.c_str(), 1); //关闭内存 if (ofmt_ctx_ && !(ofmt->flags & AVFMT_NOFILE)) avio_close(ofmt_ctx_->pb); //在析构函数中释放内存 ``` ## 3、代码 - 类头文件代码(remuxing.h) ```cpp // Copyright (c) 2021 LucasNan <nanche@mail.hfut.edu.cn> <www.kevinnan.org.cn> // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. #ifndef REMUXING_H #define REMUXING_H #include <iostream> #include <string> extern "C"{ #include "libavformat/avformat.h" #include "libavcodec/avcodec.h" } class ReMuxing { public: ReMuxing(); ~ReMuxing(); //@brief: 得到输入文件 //@param: input_file: 输入文件 //@ret : void //@birth: created by LucasNan on 20210220 void getInputFile(std::string input_file){ this->input_file_ = input_file; } //@brief: 得到输出文件 //@param: output_file: 输出文件 //@ret : void //@birth: created by LucasNan on 20210220 void getOutputFile(std::string output_file){ this->output_file_ = output_file; } //@brief: 视频转封装 //@param: void //@ret : void //@birth: created by LucasNan on 20210220 void reMuxing(); private: //输出文件AVFormatContext AVFormatContext* ifmt_ctx_; //输出文件AVFormatContext AVFormatContext* ofmt_ctx_; std::string input_file_; std::string output_file_; }; #endif // REMUXING_H ``` - 类实现代码(remuxing.cpp) ```cpp // Copyright (c) 2021 LucasNan <nanche@mail.hfut.edu.cn> <www.kevinnan.org.cn> // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. #include "remuxing.h" ReMuxing::ReMuxing() { ifmt_ctx_ = avformat_alloc_context(); ofmt_ctx_ = avformat_alloc_context(); } ReMuxing::~ReMuxing(){ avformat_free_context(ifmt_ctx_); avformat_free_context(ofmt_ctx_); } void ReMuxing::reMuxing(){ AVOutputFormat* ofmt; AVPacket *pkt = av_packet_alloc(); int ret; //打开媒体文件 if(avformat_open_input(&ifmt_ctx_, this->input_file_.c_str(), NULL, NULL) < 0){ printf("file open error!"); return; } //读取音视频流信息 if(avformat_find_stream_info(ifmt_ctx_, 0) < 0){ printf("stream info error!"); return; } //打印视频信息 av_dump_format(ifmt_ctx_, 0, input_file_.c_str(), 0); //给AVFormatContext分配动态内存 avformat_alloc_output_context2(&ofmt_ctx_, NULL, NULL, output_file_.c_str()); if(!ofmt_ctx_){ printf("can not create output"); return; } //得到AVOutputFormat对象 ofmt = ofmt_ctx_->oformat; //读取音视频流 for(unsigned int i = 0; i < ifmt_ctx_->nb_streams; i++){ AVStream* out_stream = NULL; AVStream* in_stream = ifmt_ctx_->streams[i]; AVCodecParameters* in_codepar = in_stream->codecpar; if(in_codepar->codec_type != AVMEDIA_TYPE_VIDEO && in_codepar->codec_type != AVMEDIA_TYPE_AUDIO && in_codepar->codec_type != AVMEDIA_TYPE_SUBTITLE){ continue; } std::cout<<"one"<<std::endl; //新建输出流 out_stream = avformat_new_stream(ofmt_ctx_, NULL); if(!out_stream){ printf("Failed allocat output stream"); return; } //copy编码参数,上下文信息 ret = avcodec_parameters_copy(out_stream->codecpar, in_codepar); if(ret < 0){ printf("codec copy error!"); return; } out_stream->codecpar->codec_tag = 0; } av_dump_format(ofmt_ctx_, 0, output_file_.c_str(), 1); //如果flags没有设置为AVFMT_NOFILE,则使用pb //处初始化AVIOContext,文件操作由他完成 if(!(ofmt->flags & AVFMT_NOFILE)){ ret = avio_open(&ofmt_ctx_->pb, output_file_.c_str(), AVIO_FLAG_WRITE); if(ret < 0){ printf("can not open file"); return; } } //写入媒体头文件 ret = avformat_write_header(ofmt_ctx_, NULL); if(ret < 0){ printf("can not write"); return; } while(1){ AVStream *in_stream, *out_stream; //读出每一帧数据 ret = av_read_frame(ifmt_ctx_, pkt); if(ret < 0){ printf("over"); 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); //数据在媒体流中的为止,未知设为-1 pkt->pos = -1; //将包写入输出媒体文件 ret = av_interleaved_write_frame(ofmt_ctx_, pkt); if(ret < 0){ printf("erroe muxing packet"); break; } //减少引用计数,避免内存泄漏 av_packet_unref(pkt); } //写入尾部信息 av_write_trailer(ofmt_ctx_); //释放AVPacket av_packet_free(&pkt); //打印输出文件信息 av_dump_format(ofmt_ctx_, 0, output_file_.c_str(), 1); //关闭内存 if (ofmt_ctx_ && !(ofmt->flags & AVFMT_NOFILE)) avio_close(ofmt_ctx_->pb); //在析构函数中释放内存 } ``` - main.cpp ```cpp // Copyright (c) 2021 LucasNan <nanche@mail.hfut.edu.cn> <www.kevinnan.org.cn>// Permission is hereby granted, free of charge, to any person// obtaining a copy of this software and associated documentation// files (the "Software"), to deal in the Software without// restriction, including without limitation the rights to use,// copy, modify, merge, publish, distribute, sublicense, and/or sell// copies of the Software, and to permit persons to whom the// Software is furnished to do so, subject to the following// conditions:// The above copyright notice and this permission notice shall be// included in all copies or substantial portions of the Software.// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR// OTHER DEALINGS IN THE SOFTWARE.#include <QCoreApplication>#include <iostream>#include "remuxing.h"int main(int argc, char *argv[]){ QCoreApplication a(argc, argv); const char* file = "F:/google/durant.mp4"; ReMuxing* re = new ReMuxing(); re->getInputFile(file); re->getOutputFile("./output.flv"); re->reMuxing(); return a.exec();} ``` Last modification:June 15th, 2021 at 06:02 pm © 允许规范转载