ffmpeg封装和解封装介绍-(8)解封装和封装重构

头文件:

xformat.h


#pragma once/// 封装和解封装基类#include <mutex>
struct AVFormatContext;
struct AVCodecParameters;
struct AVPacket;
struct XRational
{int num; ///< Numeratorint den; ///< Denominator
};
class XFormat
{
public:/// <summary>/// 复制参数 线程安全/// </summary>/// <param name="stream_index">对应c_->streams 下标</param>/// <param name="dst">输出参数</param>/// <returns>是否成功</returns>bool CopyPara(int stream_index, AVCodecParameters* dst);/// <summary>/// 设置上下文,并且清理上次的设置的值,如果传递NULL,相当于关闭上下文3/// 线程安全/// </summary>/// <param name="c"></param>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};
};

xdemux.h

#pragma once
#include "xformat.h"
class XDemux :public XFormat
{
public:/// <summary>/// 打开解封装/// </summary>/// <param name="url">解封装地址 支持rtsp</param>/// <returns>失败返回nullptr</returns>static AVFormatContext* Open(const char* url);/// <summary>/// 读取一帧数据/// </summary>/// <param name="pkt">输出数据</param>/// <returns>是否成功</returns>bool Read(AVPacket* pkt);
};

xmux.h


#pragma once
#include "xformat.h"
//
/// 媒体封装class XMux :public XFormat
{
public://打开封装static AVFormatContext* Open(const char* url);bool WriteHead();bool Write(AVPacket* pkt);bool WriteEnd();
};

源文件:

main.cpp


#include <iostream>
#include <thread>
#include "xdemux.h"
#include "xmux.h"
using namespace std;
extern "C" { //指定函数是c语言函数,函数名不包含重载标注
//引用ffmpeg头文件
#include <libavformat/avformat.h>
}
//预处理指令导入库
#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;//写入音视频帧 会清理pktmux.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;
}

xformat.cpp

#include "xformat.h"
#include <iostream>
#include <thread>
using namespace std;
extern "C" { //指定函数是c语言函数,函数名不包含重载标注
//引用ffmpeg头文件
#include <libavformat/avformat.h>
}
//预处理指令导入库
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
using namespace std;
void XFormat::set_c(AVFormatContext* c)
{unique_lock<mutex> 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;}}
}/// <summary>
/// 复制参数 线程安全
/// </summary>
/// <param name="stream_index">对应c_->streams 下标</param>
/// <param name="dst">输出参数</param>
/// <returns>是否成功</returns>
bool XFormat::CopyPara(int stream_index, AVCodecParameters* dst)
{unique_lock<mutex> 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;
}

xdemux.cpp

#include "xdemux.h"
#include <iostream>
#include <thread>
using namespace std;
extern "C" { //指定函数是c语言函数,函数名不包含重载标注
//引用ffmpeg头文件
#include <libavformat/avformat.h>
}
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<mutex> lock(mux_);if (!c_)return false;auto re = av_read_frame(c_, pkt);BERR(re);return true;
}

xmux.cpp


#include "xmux.h"#include <iostream>
#include <thread>
using namespace std;
extern "C" { //指定函数是c语言函数,函数名不包含重载标注
//引用ffmpeg头文件
#include <libavformat/avformat.h>
}
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;//打开IOre = avio_open(&c->pb, url, AVIO_FLAG_WRITE);BERR(re);return c;
}
bool XMux::Write(AVPacket* pkt)
{unique_lock<mutex> 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<mutex> 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<mutex> 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文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/27693.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构(邓俊辉)学习笔记】图03——拓扑排序

文章目录 0. 概述1. 零入度算法1. 1 拓扑排序1. 2 算法 2. 零出度算法2.1 算法2.2 实现2.3. 复杂度 0. 概述 学习下拓扑排序 1. 零入度算法 1. 1 拓扑排序 首先理解下拓扑排序 其实老师经常干这事&#xff0c;如编讲义&#xff0c;将已经知道的知识点串起来变成讲课序列。那…

比特币全节点搭建

比特币全节点搭建 参考: https://www.cnblogs.com/elvi/p/10203927.html

SM3国密算法:优秀的密码散列函数

随着信息技术的飞速发展&#xff0c;信息安全已成为全球关注的焦点。密码学作为保障信息安全的核心技术&#xff0c;其重要性不言而喻。中国在密码学领域也取得了显著的成就&#xff0c;其中SM3国密算法就是中国自主设计并推广使用的密码学标准之一。 一、SM3算法概述 SM3算法…

【机器学习】集成学习方法:Bagging与Boosting的应用与优势

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 引言一、集成学习的定义二、Bagging方法1. 随机森林&#xff08;Random Forest&#xff09;2. 其他Bagging方法 二、Boosting方法1. 梯度提升树&#xff08;Gradient Boosting Machine, GBM&#xff09;解释GBM的基本原理和…

【网络编程】进程间的通信

进程间通信意味着两个不同进程间交换数据&#xff0c;操作系统中应提供两个进程可以同时访问内存空间。 管道实现进程间通信 管道不属于进程资源&#xff0c;与套接字一样属于操作系统。两个进程通过操作系统提供内存空间进行通信 #include<unistd.h> int pipe(int fil…

IS022000认证:食品安全管理的金标准

食品安全是食品行业的命脉&#xff0c;IS022000食品安全管理体系认证作为最权威的认证之一&#xff0c;为企业提供了强有力的保障。要理解IS022000认证的意义&#xff0c;我们需要先了解它与HACCP和IS09001认证的关系。 HACCP&#xff08;Hazard Analysis and Critical Control…

前端学习CSS之神奇的块浮动

在盒子模型的基础上就可以对网页进行设计 不知道盒子模型的可以看前面关于盒子模型的内容 而普通的网页设计具有一定的原始规律,这个原始规律就是文档流 文档流 标签在网页二维平面内默认的一种排序方式,块级标签不管怎么设置都会占一行,而同一行不能放置两个块级标签 行级…

[Kubernetes] etcd 单机和集群部署

文章目录 1.etcd基本概念2.etcd的基本知识3.etcd优势4.etcd单机部署4.1 linux部署4.2 windows部署4.3 docker安装etcd 5.etcd集群部署 1.etcd基本概念 etcd是一个高可用的分布式键值存储系统&#xff0c;是CoreOS&#xff08;现在隶属于Red Hat&#xff09;公司开发的一个开源…

0614,表达式,语句

题目一&#xff1a; 许多简单的交互式程序都是基于菜单的&#xff1a;它们向用户显示可供选择的命令列表&#xff1b;一旦用户选择了某条命令&#xff0c;程序就执行相应的操作&#xff0c;然后提示用户输入下一条命令&#xff1b;这个过程一直会持续到用户选择 "退出&qu…

关于如何使用不到 ¥800 实现电动升降桌自由(双电机)

前言 在房子装修之前&#xff0c;就想着拥有一个书房。但是如果书房里面没有书桌&#xff0c;那不扯淡么&#xff1f;之后想着天天坐这么久&#xff0c;腰部颈部经常不适&#xff0c;所以又开始纠结买哪款人体工学椅子比较合适。 说时迟那时快。当天偶然刷小红书的时候&#x…

微信小游戏插件申请,微信小程序插件管理

微信小游戏的插件申请与小程序不一样&#xff0c;官方没有提供一个统一的管理入口进行申请插件&#xff0c;以及查看插件&#xff0c;没有小程序方便的&#xff1b; 小程序申请查看插件入口如下图所示&#xff1a; 小游戏的插件可以通过以下的方式进行申请&#xff1a; 如下…

建筑八大员证报名一寸彩色照片要求及手机自拍方法解读

在建筑行业&#xff0c;八大员证的持有者是广受尊重的专业人士。然而&#xff0c;要成为一名合格的八大员&#xff0c;首先必须通过资格审核和报名流程。其中重要的一步就是提交一寸彩色照片&#xff0c;以确保个人信息准确无误。那么&#xff0c;你是否清楚报名时照片的要求以…

Linux笔记--权限与属性命令、查找指令、压缩命令、网络指令

权限 使用ls指令查看详细信息时 rwx分别代表读写执行三种权限&#xff0c;book代表book用户&#xff0c;对于权限来说三种权限分别代表二进制一位&#xff0c;即同时拥有rwx就是111&#xff0c;此时这个文件权限为775 改变权限为rw-rwxr-w指令 book100ask:~/Desktop$ chmod …

Vue I18n国际化插件

Vue I18n国际化插件 安装目录结构及文件内容./locales/lang/zh.js./locales/lang/en.js./locales/index.js main.js引入页面具体使用及语言切换&#xff08;Vue3&#xff09;刷新保存原语言&#xff0c;App.vue添加路由守卫注意点 中文文档&#xff1a; https://kazupon.githu…

sprintboot容器功能

容器 容器功能Spring注入组件的注解Component&#xff0c;Controller&#xff0c;Service&#xff0c;Repository案例演示 Configuration应用实例传统方式使用Configuration 注意事项和细节 Import应用实例 ConditionalConditional介绍应用实例 ImportResource应用实例 配置绑定…

【微信小程序开发实战项目】——如何去申请腾讯地图账号和在微信公众平台,配置request路径和添加地图插件

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

【算法-力扣】73.矩阵置零,一文彻底搞懂!

目录 一、题目描述 二、解题思路 三、参考答案 一、题目描述 矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 进阶&#xff1a; 一个直观的解决方案是使用 O(mn) 的额外空间&#x…

【机器学习】机器学习与物流科技在智能配送中的融合应用与性能优化新探索

文章目录 引言机器学习与物流科技的基本概念机器学习概述监督学习无监督学习强化学习 物流科技概述路径优化车辆调度需求预测 机器学习与物流科技的融合应用实时物流数据分析数据预处理特征工程 路径优化与优化模型训练模型评估 车辆调度与优化深度学习应用 需求预测与优化强化…

远程连接路由器:方法大全与优缺点解析

远程连接路由器的方式主要有以下几种&#xff0c;以下是每种方式的详细说明及其优缺点&#xff1a; 使用Web浏览器登录 方法&#xff1a;通过配置路由器的远程管理功能&#xff0c;允许用户通过互联网浏览器访问路由器的管理界面。用户只需输入路由器的公网IP地址或域名&#…