蓬莱建设管理局网站/苏州seo网站公司
头文件:
xencode.h
#pragma once
#include <mutex>
#include<vector>
struct AVCodecContext;
struct AVPacket;
struct AVFrame;
class XEncode
{
public:///// 创建编码上下文/// @para codec_id 编码器ID号,对应ffmpeg/// @return 编码上下文 ,失败返回nullptrstatic AVCodecContext* Create(int codec_id);///// 设置对象的编码器上下文 上下文传递到对象中,资源由XEncode维护/// 加锁 线程安全/// @para c 编码器上下文 如果c_不为nullptr,则先清理资源void set_c(AVCodecContext* c);//// 设置编码参数,线程安全bool SetOpt(const char* key, const char* val);bool SetOpt(const char* key, int val);///// 打开编码器 线程安全bool Open();///// 编码数据 线程安全 每次新创建AVPacket/// @para frame 空间由用户维护/// @return 失败范围nullptr 返回的AVPacket用户需要通过av_packet_free 清理AVPacket* Encode(const AVFrame* frame);/////根据AVCodecContext 创建一个AVFrame,需要调用者释放av_frame_freeAVFrame* CreateFrame();//返回所有编码缓存中的AVPacket,解决丢帧问题std::vector<AVPacket*> End();private:AVCodecContext* c_ = nullptr; //编码器上下文std::mutex mux_; //编码器上下文锁
};
源文件:
xencode.cpp
#include "xencode.h"
#include <iostream>
using namespace std;
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
}
//预处理指令导入库
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")static void PrintErr(int err)
{char buf[1024] = { 0 };av_strerror(err, buf, sizeof(buf) - 1);cerr << buf << endl;
}//
/// 创建编码上下文
/// @para codec_id 编码器ID号,对应ffmpeg
/// @return 编码上下文 ,失败返回nullptr
AVCodecContext* XEncode::Create(int codec_id)
{//1 找到编码器auto codec = avcodec_find_encoder((AVCodecID)codec_id);if (!codec){cerr << "avcodec_find_encoder failed!" << codec_id << endl;return nullptr;}//创建上下文auto c = avcodec_alloc_context3(codec);if (!c){cerr << "avcodec_alloc_context3 failed!" << codec_id << endl;return nullptr;}//设置参数默认值c->time_base = { 1,25 };c->pix_fmt = AV_PIX_FMT_YUV420P;c->thread_count = 16;return c;
}//
/// 设置对象的编码器上下文 上下文传递到对象中,资源由XEncode维护
/// 加锁 线程安全
/// @para c 编码器上下文 如果c_不为nullptr,则先清理资源
void XEncode::set_c(AVCodecContext* c)
{unique_lock<mutex>lock(mux_);if (c_){avcodec_free_context(&c_);}this->c_ = c;
}bool XEncode::SetOpt(const char* key, const char* val)
{unique_lock<mutex>lock(mux_);if (!c_)return false;auto re = av_opt_set(c_->priv_data, key, val, 0);if (re != 0){cerr << "av_opt_set failed!";PrintErr(re);}return true;
}bool XEncode::SetOpt(const char* key, int val)
{unique_lock<mutex>lock(mux_);if (!c_)return false;auto re = av_opt_set_int(c_->priv_data, key, val, 0);if (re != 0){cerr << "av_opt_set failed!";PrintErr(re);}return true;
}//
/// 打开编码器 线程安全
bool XEncode::Open()
{unique_lock<mutex>lock(mux_);if (!c_)return false;auto re = avcodec_open2(c_, NULL, NULL);if (re != 0){PrintErr(re);return false;}return true;
}
//
/// 编码数据 线程安全 每次新创建AVPacket
/// @para frame 空间由用户维护
/// @return 失败范围nullptr 返回的AVPacket用户需要通过av_packet_free 清理
AVPacket* XEncode::Encode(const AVFrame* frame)
{if (!frame)return nullptr;unique_lock<mutex>lock(mux_);if (!c_)return nullptr;//发送到编码线程auto re = avcodec_send_frame(c_, frame);if (re != 0)return nullptr;auto pkt = av_packet_alloc();//接收编码线程数据re = avcodec_receive_packet(c_, pkt);if (re == 0){return pkt;}av_packet_free(&pkt);if (re == AVERROR(EAGAIN) || re == AVERROR_EOF){return nullptr;}if (re < 0){PrintErr(re);}return nullptr;
}//返回所有编码缓存中的AVPacket,解决丢帧问题
std::vector<AVPacket*> XEncode::End()
{std::vector<AVPacket*> res;//类似一个数组,存的是AVPacket 对象指针unique_lock<mutex>lock(mux_);if (!c_)return res;auto re = avcodec_send_frame(c_, NULL);//发送NULL到编码器中,获取编码器中的缓存区if (re != 0)return res;while (re >= 0){auto pkt = av_packet_alloc();re = avcodec_receive_packet(c_,pkt);//avpacket从编码器c_中读取编码数据。if (re != 0){av_packet_free(&pkt);break;}res.push_back(pkt);}return res;}///
//根据AVCodecContext 创建一个AVFrame,需要调用者释放av_frame_free
AVFrame* XEncode::CreateFrame()
{unique_lock<mutex>lock(mux_);if (!c_)return nullptr;auto frame = av_frame_alloc();frame->width = c_->width;frame->height = c_->height;frame->format = c_->pix_fmt;auto re = av_frame_get_buffer(frame, 0);if (re != 0){av_frame_free(&frame);PrintErr(re);return nullptr;}return frame;
}
main.cpp
#include <iostream>
#include <fstream>
#include "xencode.h"
using namespace std;
extern "C" { //指定函数是c语言函数,函数名不包含重载标注
//引用ffmpeg头文件
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
}int main(int argc, char* argv[])
{string filename = "400_300_25_preset";AVCodecID codec_id = AV_CODEC_ID_H264;if (argc > 1){string codec = argv[1];if (codec == "h265" || codec == "hevc"){codec_id = AV_CODEC_ID_HEVC;}}if (codec_id == AV_CODEC_ID_H264){filename += ".h264";}else if (codec_id == AV_CODEC_ID_HEVC){filename += ".h265";}//输出文件ofstream ofs;ofs.open(filename, ios::binary);XEncode en;auto c = en.Create(codec_id);c->width = 400;c->height = 300;en.set_c(c);en.SetOpt("crf", 18); //恒定速率因子(CRF)en.Open();auto frame = en.CreateFrame();int count = 0;//写入文件的帧数,看是否有500,SPS PPS IDR放在一帧中for (int i = 0; i < 500; i++){//生成AVFrame 数据 每帧数据不同//Yfor (int y = 0; y < c->height; y++){for (int x = 0; x < c->width; x++){frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;}}//UVfor (int y = 0; y < c->height / 2; y++){for (int x = 0; x < c->width / 2; x++){frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;}}frame->pts = i;//显示的时间auto pkt = en.Encode(frame);if (pkt){count++;ofs.write((char*)pkt->data, pkt->size);av_packet_free(&pkt);}}auto missing_pkt = en.End();for (auto pkt : missing_pkt){count++;ofs.write((char*)pkt->data, pkt->size);av_packet_free(&pkt);}ofs.close();en.set_c(nullptr);cout << "encode" << count << endl;getchar();return 0;
}
讨论:
1.上一篇文章提到的丢帧问题得到了解决,原因是编码器缓存不够
2.封装使得代码更加简洁
相关文章:

ffmpeg视频编码原理和实战-(5)对编码过程进行封装并解决丢帧问题
头文件: xencode.h #pragma once #include <mutex> #include<vector> struct AVCodecContext; struct AVPacket; struct AVFrame; class XEncode { public:///// 创建编码上下文/// para codec_id 编码器ID号,对应ffmpeg/// return 编码上…...

halo进阶-主题插件使用
开始捣鼓捣鼓halo,换换主题,加个页面 可参考:Halo 文档 安装/更新主题 主题如同壁纸,萝卜青菜各有所爱,大家按需更换即可; Halo好在一键更换主题,炒鸡方便。 安装/更新插件 此插件还扩展了插件…...

资深开发推荐的IDEA 插件
开发如虎添翼 工欲善其事,必先利其器。想要提升编程开发效率,必须选择一款顺手的开发工具,插件不在多,而在精,作为从业10年的程序员,我目前用到这十几个插件,在平时开发,代码review…...

数学题目系列(一)|丑数|各位和|埃氏筛|欧拉筛
一.丑数 链接:丑数 分析: 丑数只有2,3,5这三个质因数,num 2a 3b 5c也就是一个丑数是由若干个2,3,5组成,那么丑数除以这若干个数字最后一定变为1 代码 class Solution {publi…...

k8s学习--Secret详细解释与应用
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 Secret什么是Secret?Secret四种类型及其特点Secret应用案例(1)将明文密码进行base64编码(2)编写创建secret的YAML文…...

功能问题:如何防止接口重复请求?
大家好,我是大澈! 本文约 1400 字,整篇阅读约需 3 分钟。 防止接口重复请求在软件开发中非常重要,重复请求必然会导致服务器资源的浪费。 因为每次请求都需要服务器进行处理,如果请求是重复的,那么服务…...

系统架构设计师【第5章】: 软件工程基础知识 (核心总结)
文章目录 5.1 软件工程5.1.1 软件工程定义5.1.2 软件过程模型5.1.3 敏捷模型5.1.4 统一过程模型(RUP)5.1.5 软件能力成熟度模型 5.2 需求工程5.2.1 需求获取5.2.2 需求变更5.2.3 需求追踪 5.3 系统分析与设计5.3.1 结构化方法5.3.2 面向对象…...

嵌入式Linux系统编程 — 2.2 标准I/O库:检查或复位状态
目录 1 检查或复位状态简介 2 feof()函数 2.1 feof()函数简介 2.2 示例程序 3 ferror()函数 4 clearerr()函数 4.1 clearerr()函数简介 4.2 示例程序 1 检查或复位状态简介 调用 fread() 函数读取数据时,如果返回值小于参数 nmemb 所指定的值,这…...

pESC-HIS是什么,怎么看?-实验操作系列-2
01 典型的pESC-HIS质粒遗传图谱 02 介绍 质粒类型:酿酒酵母蛋白表达载体 表达水平:高拷贝 诱导方法:半乳糖 启动子:GAL1和GAL10 克隆方法:多克隆位点,限制性内切酶 载体大小:6706bp 5 测…...

树形表/树形数据接口的开发
数据表格式 需要返回的json格式 点击查看json数据 [{"childrenTreeNodes" : [{"childrenTreeNodes" : null,"id" : "1-1-1","isLeaf" : null,"isShow" : null,"label" : "HTML/CSS","na…...

二叉树的镜像--c++【做题记录】
【问题描述】 给定扩展二叉树的前序序列,构建二叉树。 求这课二叉树的镜像,并输出其前序遍历序列。 【输入形式】 输入扩展二叉树的前序序列。 【输出形式】 输出镜像二叉树的前序遍历序列。 【样例输入】 ab##cd##e## 【样例输出】 镜像后二叉树的前序遍…...

redis安裝启动
1、下载redis解压 https://github.com/tporadowski/redis/releases 2、打开cmd,切换到解压的文件夹 3、redis-server.exe redis.windows.conf 启动redis redis可通过命令行输入config set requirepass password和直接修改redis.config文件中修改 requirepass 来设…...

为什么Java中的main方法必须是public static void的?
当我们创建main方法时,首先都是public、都是static,返回值都是void,方法名都是main,入参都是一个字符串数组。 在以上的方法声明中,唯一可以改变的部分就是方法的参数名,我们可以吧args改成任意我们想要使…...

shell的编程方式
文章目录 变量俩种方式第一种方式第二种方式 取消变量数组创建数组获取数组元素的方式 read输出的方式限制输入的方式 流程控制方式for循环输出的方式第一种方式第二种方式while循环输出的方式select选择输出的方式 判断方式判断的四种方式第一种方式第二种方式第三种方式 算术…...

前端面试项目细节重难点(已工作|做分享)想(八)
面试官:请你讲讲你在该项目中遇到的印象深刻的问题是什么? 答:我的回答:该项目的实现过程中我确实遇到了问题:【我会给大家整理回答思路和角度,那那么遇到这样的问题也可借鉴这种思路进行阐述】 第一层面…...

Loguru,一个 Python 日志神器
大家好!我是爱摸鱼的小鸿,关注我,收看每期的编程干货。 一个简单的库,也许能够开启我们的智慧之门, 一个普通的方法,也许能在危急时刻挽救我们于水深火热, 一个新颖的思维方式,也许能激发我们无尽的创造力, 一个独特的技巧,也许能成为我们的隐形盾牌…… 神奇的 Pyth…...

C++ 反转单词
在C中,反转一个字符串中的单词(单词之间通过空格分隔,但单词内部保持原有顺序)可以通过以下步骤实现: 找到字符串中的所有单词,这可以通过查找空格来实现。将单词存储在一个容器中(例如 std::v…...

Apache Doris 基础 -- 数据表设计(表索引)
1、索引概述 索引用于帮助快速过滤或搜索数据。目前,Doris支持两种类型的索引:内置智能索引和用户创建的二级索引。 内置智能索引 排序键和前缀索引:Apache Doris基于排序键以有序的方式存储数据。它为每1024行数据创建一个前缀索引。索引中的键是当前1024行组的…...

资源描述框架的用途及实际应用解析
什么是RDF? RDF代表 资源描述框架 RDF是用于描述网络资源的框架 RDF旨在被计算机阅读和理解 RDF并非设计用于供人阅读 RDF以 XML 编写 示例 描述购物商品的属性,如价格和可用性描述网络活动的时间表描述网页的信息(内容,作者&a…...

工业级物联网边缘网关解决方案-天拓四方
随着工业4.0时代的到来,越来越多的企业开始寻求智能化升级,以提高生产效率、降低运营成本并增强市场竞争力。然而,在实际的转型升级过程中,许多企业面临着数据孤岛、设备兼容性差、网络安全风险高等问题,这些问题严重制…...

认识微服务,认识Spring Cloud
1. 介绍 本博客探讨的内容如下所示 什么是微服务?什么是springcloud?微服务和springcloud有什么关系? 首先,没有在接触springcloud之前,我写的项目都是单体结构, 但随着网站的用户量越来越大,…...

电脑设置密码怎么设置?让你的电脑更安全!
在如今信息化的社会中,保护个人电脑的安全至关重要。设置密码是最基本的电脑安全措施之一,它可以有效防止未经授权的访问和保护个人隐私,可是电脑设置密码怎么设置?本文将介绍三种设置电脑密码的方法,帮助您加强电脑的…...

搜维尔科技:SenseGlove Nova2使用主动接触反馈来模拟手掌的感觉,结合力反馈和振动触觉反馈,使其成为市场上第一款具有手掌反馈的无线触觉手套
SenseGlove Nova2使用主动接触反馈来模拟手掌的感觉,结合力反馈和振动触觉反馈,使其成为市场上第一款具有手掌反馈的无线触觉手套。 搜维尔科技:SenseGlove Nova2使用主动接触反馈来模拟手掌的感觉,结合力反馈和振动触觉反馈&…...

基于Python的实验室管理系统的设计与实现(论文+源码)_kaic
摘 要 随着实验室设备越来越多,实验室及其设备管理工作变得越来越繁重,还存在些管理模式仍旧处于手工管理模式和一些抢占实验室的不文明现象,传统的手工模式已经满足不了日益增长的管理需求,而本系统摒弃传统模式,开启…...

Windows系统WDS+MDT网络启动自动化安装
Windows系统WDS+MDT网络启动自动化安装 适用于在Windows系统上WDS+MDT网络启动自动化安装 1. 安装准备 1.下载windows server 2019、windows 10 pro的ISO文件,并安装好windows server 2019 2.下载windows 10 2004版ADK及镜像包 1.1 安装平台 Windows 111.2. 软件信息 软件…...

Apple开发者证书创建完整过程
1.创建CSR文件: 打开钥匙串访问程序 选择从证书颁发机构请求 创建证书 保存CSR文件到桌面 成功如下: 开始创建证书: 选择...

for深入学习
目录 练习: 例1: 求解0-100中整除3的数有哪些 例2: 求0-100中含数字9个个数 作业: 练习: 例1: 求解0-100中整除3的数有哪些 代码: #include<stdio.h> int main() {printf("整…...

引用(C++)和内联函数
前言:本文主要讲解C语法中引用如何使用和使用时的一些技巧 基本语法 引用就是取别名 #include <iostream> using namespace std; int main() {int a 10;int& b a;//给a取别名为bcout << a << endl;cout << b << endl;return 0…...

【stm32/CubeMX、HAL库】swjtu嵌入式实验七 ADC 实验
相关电路与IO引脚 注意:串口打印重定向后使用printf打印需要在keil里勾选 Use MicroLIB ,否则会卡住。 参看:https://zhuanlan.zhihu.com/p/565613666 串口重定向: /* USER CODE BEGIN Includes */#include <stdio.h>//…...

springboot 解耦、隔离、异步的原则以及实战
在Spring Boot中实现解耦、隔离和异步的原则,能够提升应用程序的可维护性、可扩展性和性能。下面我会先介绍这三个原则的基本概念和意义,然后通过实战示例展示如何在Spring Boot应用中应用这些原则。 解耦 解耦是减少或消除应用程序组件之间依赖关系的过程,以提高模块的独…...