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,一经查实,立即删除!

相关文章

安装docker+mysql的一些坑

yum -y install docker 提示missing signature(docker客户端太老了) 参考这里 https://www.8a.hk/news/content/8235.html 卸载旧的docker sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotat…

【数据结构(邓俊辉)学习笔记】图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算法…

Linux 内核的 notifier 机制

Linux内核使用通知链的机制在内核各子系统之间进行事件通知&#xff08;注&#xff1a;无法用于内核态和用户态之 Linux内核中的notifier机制是一种重要的组件间通信机制&#xff0c;它允许在内核中的某些事件发生时&#xff0c;相关的组件能够得到通知并作出相应的处理。这种…

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

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

React项目配置路径别名“@”

React项目配置路径别名“” 首先安装craco npm i craco/cracoalpha -D npm i npm i craco-less创建craco.config.js const path require(path) const CracoLessPlugin require(craco-less)const resolve (dir) > path.resolve(__dirname, dir)module.exports {plugin…

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

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

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

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

危化品经营单位(生产管理人员)题库

1.中华人民共和国境内的各类企业的职工和个体工商户的雇工,均有依照工伤保险条例的规定享受&#xff08; &#xff09;待遇的权利。 A.人身保险 B.医疗保险 C.工伤保险 答案:C 2.制定应急预案的目的是抑制&#xff08; &#xff09;,减少对人员、财产和环境的危害。 A.突…

PostgreSQL -public schema

文章目录 Overview查询Schema权限public schema的历史背景撤销权限Granting Privileges结论 Overview 在上一篇文章中&#xff0c;介绍了理解 PostgreSQL schema的基础知识、创建和删除机制&#xff0c;并回顾了几个用例。本文将扩展这些基础知识并探讨与schema相关的权限管理…

Redis入门与实践

Redis是一种开源的、基于内存的高性能键值存储系统&#xff0c;常用于缓存、会话管理、实时数据分析等场景。以下是Redis的入门指南和一些基本的实践示例&#xff0c;帮助你开始使用Redis。 1. 安装和基本配置 安装Redis Redis可以在多种操作系统上安装。以Ubuntu为例&#…

搭建Python虚拟环境(四):Pipenv

使用Pipenv搭建虚拟环境的详细指南 Pipenv 是一个Python包管理工具&#xff0c;它结合了pip和virtualenv的优点&#xff0c;用于创建和管理Python项目的虚拟环境。本文将详细介绍如何使用Pipenv搭建虚拟环境&#xff0c;包括安装Pipenv、创建虚拟环境、激活虚拟环境、退出虚拟…

前端学习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; 如下…

RAG PAPTOR 示例代码理解笔记

RAG PAPTOR 示例代码理解笔记 0. 源代码文件1. 部分代码理解笔记故事背景导入工具固定种子&#xff08;随机种子&#xff09;全局降维函数局部降维函数获取最佳聚类数函数GMM聚类函数执行聚类函数嵌入函数嵌入并聚类文本函数格式化文本函数嵌入、聚类并总结文本函数递归嵌入、聚…