-
- #pragma once
-
- /// 封装和解封装基类
-
- #include
- struct AVFormatContext;
- struct AVCodecParameters;
- struct AVPacket;
- struct XRational
- {
- int num; ///< Numerator
- int den; ///< Denominator
- };
- class XFormat
- {
- public:
- ///
- /// 复制参数 线程安全
- ///
- /// 对应c_->streams 下标
- /// 输出参数
- ///
是否成功 - bool CopyPara(int stream_index, AVCodecParameters* dst);
-
- ///
- /// 设置上下文,并且清理上次的设置的值,如果传递NULL,相当于关闭上下文3
- /// 线程安全
- ///
- ///
- void set_c(AVFormatContext* c);
- int audio_index() { return audio_index_; }
- int video_index() { return video_index_; }
- XRational video_time_base(){ return video_time_base_; }
- XRational audio_time_base() { return audio_time_base_; }
- protected:
- AVFormatContext* c_ = nullptr; //封装解封装上下文
- std::mutex mux_; //c_ 资源互斥
- int video_index_ = 0;//video和audio在stream中索引
- int audio_index_ = 1;
- XRational video_time_base_ = {1,25};
- XRational audio_time_base_ = {1,9000};
- };
-
-
-
- #pragma once
- #include "xformat.h"
- class XDemux :public XFormat
- {
- public:
- ///
- /// 打开解封装
- ///
- /// 解封装地址 支持rtsp
- ///
失败返回nullptr - static AVFormatContext* Open(const char* url);
-
- ///
- /// 读取一帧数据
- ///
- /// 输出数据
- ///
是否成功 - bool Read(AVPacket* pkt);
- };
-
-
- #pragma once
- #include "xformat.h"
- //
- /// 媒体封装
-
- class XMux :public XFormat
- {
- public:
- //
- 打开封装
- static AVFormatContext* Open(const char* url);
-
- bool WriteHead();
-
- bool Write(AVPacket* pkt);
- bool WriteEnd();
- };
-
-
- #include
- #include
- #include "xdemux.h"
- #include "xmux.h"
- using namespace std;
- extern "C" { //指定函数是c语言函数,函数名不包含重载标注
- //引用ffmpeg头文件
- #include
- }
- //预处理指令导入库
- #pragma comment(lib,"avformat.lib")
- #pragma comment(lib,"avutil.lib")
- #pragma comment(lib,"avcodec.lib")
- void PrintErr(int err)
- {
- char buf[1024] = { 0 };
- av_strerror(err, buf, sizeof(buf) - 1);
- cerr << endl;
- }
- #define CERR(err) if(err!=0){ PrintErr(err);getchar();return -1;}
-
- int main(int argc, char* argv[])
- {
- //打开媒体文件
- const char* url = "v1080.mp4";
-
- /// 解封装
- //解封装输入上下文
-
- XDemux demux;
- auto demux_c = demux.Open(url);
-
- demux.set_c(demux_c);
-
-
-
-
- /// 封装
- //编码器上下文
- const char* out_url = "test_mux.mp4";
-
- XMux mux;
- auto mux_c = mux.Open(out_url);
- mux.set_c(mux_c);
- auto mvs = mux_c->streams[mux.video_index()]; //视频流信息
- auto mas = mux_c->streams[mux.audio_index()]; //视频流信息
-
- //有视频
- if (demux.video_index() >= 0)
- {
- mvs->time_base.num = demux.video_time_base().num;
- mvs->time_base.den = demux.video_time_base().den;
-
- //复制视频参数
- demux.CopyPara(demux.video_index(), mvs->codecpar);
-
- }
- //有音频
- if (demux.audio_index() >= 0)
- {
- mas->time_base.num = demux.audio_time_base().num;
- mas->time_base.den = demux.audio_time_base().den;
- //复制音频参数
- demux.CopyPara(demux.audio_index(), mas->codecpar);
- }
-
- mux.WriteHead();
-
-
- /// 截取10 ~ 20 秒之间的音频视频 取多不取少
- // 假定 9 11秒有关键帧 我们取第9秒
- double begin_sec = 10.0; //截取开始时间
- double end_sec = 20.0; //截取结束时间
- long long begin_pts = 0;
- long long begin_audio_pts = 0; //音频的开始时间
- long long end_pts = 0;
-
-
- AVPacket pkt;
- for (;;)
- {
- if (!demux.Read(&pkt))
- {
- break;
- }
-
- pkt.pos = -1;
-
-
-
- //写入音视频帧 会清理pkt
- mux.Write(&pkt);
-
- }
-
- //写入结尾 包含文件偏移索引
- mux.WriteEnd();
- /*re = av_write_trailer(ec);
- if (re != 0)PrintErr(re);*/
-
- //avformat_close_input(&ic);
- demux.set_c(nullptr);
- mux.set_c(nullptr);
-
- getchar();
- return 0;
- }
-
-
-
- #include "xformat.h"
- #include
- #include
- using namespace std;
- extern "C" { //指定函数是c语言函数,函数名不包含重载标注
- //引用ffmpeg头文件
- #include
- }
- //预处理指令导入库
- #pragma comment(lib,"avformat.lib")
- #pragma comment(lib,"avutil.lib")
- using namespace std;
- void XFormat::set_c(AVFormatContext* c)
- {
- unique_lock
lock(mux_) ; - if (c_) //清理原值
- {
- if (c_->oformat) //输出上下文
- {
- if (c_->pb)
- avio_closep(&c_->pb);
- avformat_free_context(c_);
- }
- else if (c_->iformat) //输入上下文
- {
- avformat_close_input(&c_);
- }
- else
- {
- avformat_free_context(c_);
- }
- }
- c_ = c;
- if (!c_)return;
- //用于区分是否有音频或者视频流
- audio_index_ = -1;
- video_index_ = -1;
- //区分音视频stream 索引
- for (int i = 0; i < c->nb_streams; i++)
- {
- //音频
- if (c->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
- {
- audio_index_ = i;
- audio_time_base_.den = c->streams[i]->time_base.den;
- audio_time_base_.num = c->streams[i]->time_base.num;
- }
- else if (c->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
- {
- video_index_ = i;
- video_time_base_.den = c->streams[i]->time_base.den;
- video_time_base_.num = c->streams[i]->time_base.num;
- }
- }
- }
-
-
- ///
- /// 复制参数 线程安全
- ///
- /// 对应c_->streams 下标
- /// 输出参数
- ///
是否成功 - bool XFormat::CopyPara(int stream_index, AVCodecParameters* dst)
- {
- unique_lock
lock(mux_) ; - if (!c_)
- {
- return false;
- }
- if (stream_index<0 || stream_index>c_->nb_streams)
- return false;
- auto re = avcodec_parameters_copy(dst, c_->streams[stream_index]->codecpar);
- if (re < 0)
- {
- return false;
- }
-
-
- return true;
- }
-
-
- #include "xdemux.h"
- #include
- #include
- using namespace std;
- extern "C" { //指定函数是c语言函数,函数名不包含重载标注
- //引用ffmpeg头文件
- #include
- }
- static void PrintErr(int err)
- {
- char buf[1024] = { 0 };
- av_strerror(err, buf, sizeof(buf) - 1);
- cerr << buf << endl;
- }
- #define BERR(err) if(err!= 0){PrintErr(err);return 0;}
- AVFormatContext* XDemux::Open(const char* url)
- {
- AVFormatContext* c = nullptr;
- //打开封装上下文
- auto re = avformat_open_input(&c, url, nullptr, nullptr);
- BERR(re);
- //获取媒体信息
- re = avformat_find_stream_info(c, nullptr);
- BERR(re);
- //打印输入封装信息
- av_dump_format(c, 0, url, 0);
-
- return c;
- }
-
- bool XDemux::Read(AVPacket* pkt)
- {
- unique_lock
lock(mux_) ; - if (!c_)return false;
- auto re = av_read_frame(c_, pkt);
- BERR(re);
- return true;
- }
-
- #include "xmux.h"
-
- #include
- #include
- using namespace std;
- extern "C" { //指定函数是c语言函数,函数名不包含重载标注
- //引用ffmpeg头文件
- #include
- }
- static void PrintErr(int err)
- {
- char buf[1024] = { 0 };
- av_strerror(err, buf, sizeof(buf) - 1);
- cerr << buf << endl;
- }
- #define BERR(err) if(err!= 0){PrintErr(err);return 0;}
-
- //
- 打开封装
- AVFormatContext* XMux::Open(const char* url)
- {
- AVFormatContext* c = nullptr;
- //创建上下文
- auto re = avformat_alloc_output_context2(&c, NULL, NULL, url);
- BERR(re);
-
- //添加视频音频流
- auto vs = avformat_new_stream(c, NULL); //视频流
- vs->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
- auto as = avformat_new_stream(c, NULL); //音频流
- as->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
-
-
- //打开IO
- re = avio_open(&c->pb, url, AVIO_FLAG_WRITE);
- BERR(re);
- return c;
- }
- bool XMux::Write(AVPacket* pkt)
- {
- unique_lock
lock(mux_) ; - if (!c_)return false;
- //写入一帧数据,内部缓冲排序dts,通过pkt=null 可以写入缓冲
- auto re = av_interleaved_write_frame(c_,pkt);
- BERR(re);
- return true;
- }
-
- bool XMux::WriteEnd()
- {
- unique_lock
lock(mux_) ; - if (!c_)return false;
- av_interleaved_write_frame(c_, nullptr);//写入排序缓冲
- auto re = av_write_trailer(c_);
- BERR(re);
- return true;
- }
- bool XMux::WriteHead()
- {
- unique_lock
lock(mux_) ; - if (!c_)return false;
- auto re = avformat_write_header(c_, nullptr);
- BERR(re);
-
- //打印输出上下文
- av_dump_format(c_, 0, c_->url, 1);
-
- return true;
- }
重新生成了一个名字为test_mux.mp4文件