当前位置: 首页 > news >正文

FFmpeg-- c++实现:pcm和yuv编码

文章目录

      • 流程
        • 音频
        • 视频
      • api
      • 核心代码
        • audioencoder.h
        • audioencoder.cpp
        • videoencoder.h
        • videoencoder.cpp

pcm和yuv编码为aac和h264,封装为c++的AudioEncoder类和VideoEncoder类

流程

音频
  • 初始化音频参数
    int InitAAC(int channels, int sample_rate, int bit_rate);

  • 音频编码,pts需要转化为编码时的pts, 发送帧frame, 获取 packet
    AVPacket *Encode(AVFrame *farme, int stream_index, int64_t pts, int64_t time_base);

  • 获取一帧数据通道号的采样点
    int GetFrameSize()

  • 获取编码器需要的采样格式
    int GetSampleFormat()

  • 释放资源
    void DeInit();

视频
  • 初始化视频参数
    int InitH264(int width, int height, int fps, int bit_rate);

  • 视频编码,pts需要转化为编码时的pts, 需要初始化AVFrame结构体,发送帧frame, 获取 packet
    AVPacket *Encode(AVFrame *farme, int stream_index, int64_t pts, int64_t time_base);

  • 释放资源
    void DeInit();

api

  • 用于初始化一个AVFrame结构体,包括设置AVFrame中的各项参数,不需要重新分配buffer,需要传入一个指向AVFrame结构体的指针
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],const uint8_t *src,enum AVPixelFormat pix_fmt, int width, int height, int align);

核心代码

audioencoder.h
#ifndef AUDIOENCODER_H
#define AUDIOENCODER_Hextern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
}
class AudioEncoder
{
public:AudioEncoder();~AudioEncoder();int InitAAC(int channels, int sample_rate, int bit_rate);
//    int InitMP3(/*int channels, int sample_rate, int bit_rate*/);void DeInit();  // 释放资源AVPacket *Encode(AVFrame *farme, int stream_index, int64_t pts, int64_t time_base);int GetFrameSize(); // 获取一帧数据 每个通道需要多少个采样点int GetSampleFormat();  // 编码器需要的采样格式
private:int channels_ = 2;int sample_rate_ = 44100;int bit_rate_ = 128*1024;int64_t pts_ = 0;AVCodecContext * codec_ctx_ = NULL;
};#endif // AUDIOENCODER_H
audioencoder.cpp
#include "audioencoder.h"AudioEncoder::AudioEncoder()
{}AudioEncoder::~AudioEncoder()
{if(codec_ctx_) {DeInit();}
}int AudioEncoder::InitAAC(int channels, int sample_rate, int bit_rate)
{channels_ = channels;sample_rate_ = sample_rate;bit_rate_ = bit_rate;AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);if(!codec) {printf("avcodec_find_encoder AV_CODEC_ID_AAC failed\n");return -1;}codec_ctx_ = avcodec_alloc_context3(codec);if(!codec_ctx_) {printf("avcodec_alloc_context3 AV_CODEC_ID_AAC failed\n");return -1;}codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;codec_ctx_->bit_rate = bit_rate_;codec_ctx_->sample_rate = sample_rate_;codec_ctx_->sample_fmt = AV_SAMPLE_FMT_FLTP;codec_ctx_->channels = channels_;codec_ctx_->channel_layout = av_get_default_channel_layout(codec_ctx_->channels);int ret = avcodec_open2(codec_ctx_, NULL, NULL);if(ret != 0) {char errbuf[1024] = {0};av_strerror(ret, errbuf, sizeof(errbuf) - 1);printf("avcodec_open2 failed:%s\n", errbuf);return -1;}printf("InitAAC success\n");return 0;
}void AudioEncoder::DeInit()
{if(codec_ctx_) {avcodec_free_context(&codec_ctx_);  // codec_ctx_被设置为NULL
//        codec_ctx_ = NULL;  // 不需要再写}
}AVPacket *AudioEncoder::Encode(AVFrame *frame, int stream_index, int64_t pts, int64_t time_base)
{if(!codec_ctx_) {printf("codec_ctx_ null\n");return NULL;}pts = av_rescale_q(pts, AVRational{1, (int)time_base}, codec_ctx_->time_base);if(frame) {frame->pts = pts;}int ret = avcodec_send_frame(codec_ctx_, frame);if(ret != 0) {char errbuf[1024] = {0};av_strerror(ret, errbuf, sizeof(errbuf) - 1);printf("avcodec_send_frame failed:%s\n", errbuf);return NULL;}AVPacket *packet = av_packet_alloc();ret = avcodec_receive_packet(codec_ctx_, packet);if(ret != 0) {char errbuf[1024] = {0};av_strerror(ret, errbuf, sizeof(errbuf) - 1);printf("avcodec_receive_packet failed:%s\n", errbuf);av_packet_free(&packet);return NULL;}packet->stream_index = stream_index;return packet;
}int AudioEncoder::GetFrameSize()
{if(codec_ctx_)return codec_ctx_->frame_size;return 0;
}int AudioEncoder::GetSampleFormat()
{if(codec_ctx_)return codec_ctx_->sample_fmt;return -1;  // AV_SAMPLE_FMT_NONE
}
videoencoder.h
#ifndef VIDEOENCODER_H
#define VIDEOENCODER_H
extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
}class VideoEncoder
{
public:VideoEncoder();~VideoEncoder();int InitH264(int width, int height, int fps, int bit_rate);void DeInit();AVPacket *Encode(uint8_t *yuv_data, int yuv_size,int stream_index, int64_t pts, int64_t time_base);private:int width_ = 0;int height_ = 0;int fps_ = 25;int bit_rate_ = 500*1024;int64_t pts_ = 0;AVCodecContext * codec_ctx_ = NULL;AVFrame *frame_ = NULL;
};#endif // VIDEOENCODER_H
videoencoder.cpp
#include "videoencoder.h"
extern "C"
{
#include "libavutil/imgutils.h"
}
VideoEncoder::VideoEncoder()
{}VideoEncoder::~VideoEncoder()
{if(codec_ctx_) {DeInit();}
}int VideoEncoder::InitH264(int width, int height, int fps, int bit_rate)
{width_ = width;height_ = height;fps_ = fps;bit_rate_ = bit_rate;AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);if(!codec) {printf("avcodec_find_encoder AV_CODEC_ID_H264 failed\n");return -1;}codec_ctx_ = avcodec_alloc_context3(codec);if(!codec_ctx_) {printf("avcodec_alloc_context3 AV_CODEC_ID_H264 failed\n");return -1;}codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;codec_ctx_->bit_rate = bit_rate_;codec_ctx_->width = width_;codec_ctx_->height = height_;codec_ctx_->framerate = {fps_, 1};codec_ctx_->time_base = {1, 1000000};   // 单位为微妙codec_ctx_->gop_size = fps_;codec_ctx_->max_b_frames = 0;codec_ctx_->pix_fmt = AV_PIX_FMT_YUV420P;int ret = avcodec_open2(codec_ctx_, NULL, NULL);if(ret != 0) {char errbuf[1024] = {0};av_strerror(ret, errbuf, sizeof(errbuf) - 1);printf("avcodec_open2 failed:%s\n", errbuf);return -1;}frame_ = av_frame_alloc();if(!frame_) {printf("av_frame_alloc failed\n");return -1;}frame_->width = width_;frame_->height = height_;frame_->format = codec_ctx_->pix_fmt;printf("Inith264 success\n");return 0;
}void VideoEncoder::DeInit()
{if(codec_ctx_) {avcodec_free_context(&codec_ctx_);}if(frame_) {av_frame_free(&frame_);}
}AVPacket *VideoEncoder::Encode(uint8_t *yuv_data, int yuv_size, int stream_index, int64_t pts, int64_t time_base)
{if(!codec_ctx_) {printf("codec_ctx_ null\n");return NULL;}int ret = 0;pts = av_rescale_q(pts, AVRational{1, (int)time_base}, codec_ctx_->time_base);frame_->pts = pts;if(yuv_data) {//该函数用于初始化一个AVFrame结构体,包括设置AVFrame中的各项参数,不需要重新分配buffer//使用该函数需要传入一个指向AVFrame结构体的指针int ret_size = av_image_fill_arrays(frame_->data, frame_->linesize,yuv_data, (AVPixelFormat)frame_->format,frame_->width, frame_->height, 1);if(ret_size != yuv_size) {printf("ret_size:%d != yuv_size:%d -> failed\n", ret_size, yuv_size);return NULL;}ret = avcodec_send_frame(codec_ctx_, frame_);} else {ret = avcodec_send_frame(codec_ctx_, NULL);}if(ret != 0) {char errbuf[1024] = {0};av_strerror(ret, errbuf, sizeof(errbuf) - 1);printf("avcodec_send_frame failed:%s\n", errbuf);return NULL;}AVPacket *packet = av_packet_alloc();ret = avcodec_receive_packet(codec_ctx_, packet);if(ret != 0) {char errbuf[1024] = {0};av_strerror(ret, errbuf, sizeof(errbuf) - 1);printf("avcodec_receive_packet failed:%s\n", errbuf);av_packet_free(&packet);return NULL;}packet->stream_index = stream_index;return packet;
}

相关文章:

FFmpeg-- c++实现:pcm和yuv编码

文章目录 流程音频视频 api核心代码audioencoder.haudioencoder.cppvideoencoder.hvideoencoder.cpp pcm和yuv编码为aac和h264,封装为c的AudioEncoder类和VideoEncoder类 流程 音频 初始化音频参数 int InitAAC(int channels, int sample_rate, int bit_rate); 音…...

图解CodeWhisperer的安装使用

🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! ​ 目录 📘 CodeWhisperer简介 &#…...

Python内置对象

Python是一种强大的、动态类型的高级编程语言,其内置对象是构成程序的基础元素。Python的内置对象包括数字、字符串、列表、元组、字典、集合、布尔值和None等,每种对象都有特定的类型和用途。 01 什么是内置对象 这些对象是编程语言的基础构建块&…...

开源数据集 nuScenes 之 3D Occupancy Prediction

数据总体结构 Nuscenes 数据结构 可以看一下我的blog如何下载完整版 mmdetection3d ├── mmdet3d ├── tools ├── configs ├── data │ ├── nuscenes │ │ ├── maps │ │ ├── samples │ │ ├── sweeps │ │ ├── lidarseg (o…...

物联网竞赛板CubMx全部功能简洁配置汇总

目录 前言:1、按键&LED灯配置:2、OLED配置:3、继电器配置:4、LORA模块配置:5、矩阵模块:6、串口模块:7、RTC配置:8、ADC模块配置:9、温度传感器模块:后续…...

使用Redis做缓存的小案例

如果不了解Redis,可以查看本人博客:Redis入门 Redis基于内存,因此查询速度快,常常可以用来作为缓存使用,缓存就是我们在内存中开辟一段区域来存储我们查询比较频繁的数据,这样,我们在下一次查询…...

剧本杀小程序功能介绍

剧本杀功能介绍 剧本杀,一种融合了角色扮演与推理解谜的社交游戏,近年来在年轻人中越来越受欢迎。它不仅可以锻炼参与者的逻辑推理能力,还能增进朋友间的感情,提升团队协作能力。下面,我们将详细介绍剧本杀的核心功能…...

C#基础语法学习笔记(传智播客学习)

最近在学习C#开发知识,跟着传智播客的视频学习了一下,感觉还不错,整理一下学习笔记。 C#基础语法学习笔记 1.背景知识2.Visual Studio使用3.基础知识4.变量5.运算符与表达式6.程序调试7.判断结构8.循环结构9.常量、枚举类型10.结构体类型11.数…...

图论01-DFS和BFS(深搜和广搜邻接矩阵和邻接表/Java)

1.深度优先理论基础(dfs) dfs的两个关键操作 搜索方向,是认准一个方向搜,直到碰壁之后再换方向 换方向是撤销原路径,改为节点链接的下一个路径,回溯的过程。dfs解题模板 void dfs(参数) {if (终止条件) {存放结果;return;}for …...

【Python】Miniconda+Vscode+Jupyter 环境搭建

1.安装 Miniconda Conda 是一个开源的包管理和环境管理系统,可在 Windows、macOS 和 Linux 上运行,它可以快速安装、运行和更新软件包及其依赖项。使用 Conda,我们可以轻松在本地计算机上创建、保存、加载和切换不同的环境 Conda 分为 Anaco…...

Redis消息队列与thinkphp/queue操作

业务场景 场景一 用户完成注册后需要发送欢迎注册的问候邮件、同时后台要发送实时消息给用户对应的业务员有新的客户注册、最后将用户的注册数据通过接口推送到一个营销用的第三方平台。 遇到两个问题: 由于代码是串行方式,流程大致为:开…...

【Ubuntu】常用命令

一般操作 pwd(present working directory) 显示当前的工作目录/路径。 cd (change directory) 改变目录,用于输入需要前往的路径/目录。 有一些特殊命令也很常用 : 解释 前往同一级的另一个目录 cd ../directory name cd .. 表示进入上…...

稀碎从零算法笔记Day22-LeetCode:

题型:链表 链接:2. 两数相加 - 力扣(LeetCode) 来源:Leet 题目描述 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 …...

Nacos下载和安装

(1)下载地址和版本 下载地址:Releases alibaba/nacos GitHub 解压在没有中文及空格的文件夹 (2)启动nacos服务 在bin目录下,打开命令行,输入 启动命令:sh startup.sh -m standalone - Linux/Unix/Mac …...

pandas简介(python)

pandas是什么 Pandas 是一个开源的第三方 Python 库,从 Numpy 和 Matplotlib 的基础上构建而来,享有数据分析“三剑客之一”的盛名(NumPy、Matplotlib、Pandas)。Pandas 已经成为 Python 数据分析的必备高级工具,它的…...

个人网站制作 Part 13 添加搜索功能[Elasticsearch] | Web开发项目

文章目录 👩‍💻 基础Web开发练手项目系列:个人网站制作🚀 添加搜索功能🔨使用Elasticsearch🔧步骤 1: 安装Elasticsearch🔧步骤 2: 配置Elasticsearch🔧步骤 3: 创建索引 &#x1f…...

Springboot+vue的仓库管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频: Springbootvue的仓库管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。 项目介绍: 采用M(model)V(view)C(controller)三层…...

vue3 + vite 实现一个动态路由加载功能

假设后端返回的格式是这样子 {"menu": [{"path": "/admin","name": "adminLayout","redirect": "/admin/index","componentPath": "/layout/admin/index.vue","children&quo…...

【征稿进行时|见刊、检索快速稳定】2024年区块链、物联网与复合材料与国际学术会议 (ICBITC 2024)

【征稿进行时|见刊、检索快速稳定】2024年区块链、物联网与复合材料与国际学术会议 (ICBITC 2024) 大会主题: (主题包括但不限于, 更多主题请咨询会务组苏老师) 区块链: 区块链技术和系统 分布式一致性算法和协议 块链性能 信息储存系统 区块链可扩展性 区块…...

若依jar包运行脚本,从零到一:用Bash脚本实现JAR应用的启动、停止与监控

脚本使用说明: 启动应用:sh app.sh start停止应用:sh app.sh stop检查应用状态:sh app.sh status重启应用:sh app.sh restart 注意事项: 请确保你的系统上安装了 Java 环境,并且 ruoyi-admin…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage)&#xff1a…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 ​ 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂&#xff…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

DiscuzX3.5发帖json api

参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...