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

音视频学习(十八)——使用ffmepg实现视音频解码

视频解码

初始化

  1. 视频常用的编解码器id定义(以h264和h265为例)
// 定义在ffmpeg\include\libavcodec\avcodec.h
AV_CODEC_ID_H264
AV_CODEC_ID_H265
  1. 查找解码器:根据编解码id查看解码器
AVCodec* pCodecVideo = avcodec_find_decoder(codecID);
if (!pCodecVideo)
{printf("avcodec_find_decoder failed\n");return -1;
}
  1. 申请编码器上下文结构体内存,保存了视频编解码相关信息
AVCodecContext* pCodecCtxVideo = avcodec_alloc_context3(pCodecVideo);
if (!pCodecCtxVideo)
{printf("avcodec_alloc_context3 error\n");return -1;
}
  1. 打开解码器
if (avcodec_open2(pCodecCtxVideo, pCodecVideo, NULL) < 0)
{printf("avcodec_open2 failed\n");return -1;
}
  1. 申请帧内存:存储一帧解码后像素(采样)数据
AVFrame* pFrameVideo = av_frame_alloc(); 
if (!pFrameVideo)
{printf("av_frame_alloc failed\n");return -1;
}

视频解码

  1. 解码一帧压缩数据
// data和len为压缩数据的指针和大小AVPacket packet;
av_init_packet(&packet);
packet.data = (uint8_t*)data;
packet.size = len;int got_picture = 0;
if (avcodec_decode_video2(pCodecCtxVideo, pFrameVideo, &got_picture, &packet) < 0)
{printf("avcodec_decode_video2 failed\n");return -1;
}
  1. 获取帧大小
// 以YUV420为例
int frameSize = avpicture_get_size(AV_PIX_FMT_YUV420P, pFrameVideo->linesize[0], pFrameVideo->height);
  1. 获取上下文,获取用于转码的参数**(初始化一次)**
// pFrameVideo->width:输入帧数据宽
// pFrameVideo->height:输入帧数据高
// pCodecCtxVideo->pix_fmt:帧数据格式
// pFrameVideo->width:输出帧数据宽
// pFrameVideo->height:输出帧数据高
// AV_PIX_FMT_YUV420P:输出帧数据格式,例如YUV420、RGB32等
// SWS_BICUBIC:视频像素数据格式转换算法类型
SwsContext* imgConvertCtx = sws_getContext(pFrameVideo->width, pFrameVideo->height,pCodecCtxVideo->pix_fmt,pFrameVideo->width, pFrameVideo->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
  1. 缓冲区分配缓存**(初始化一次)**
int frameSize = avpicture_get_size(AV_PIX_FMT_YUV420P, pFrameVideo->width, pFrameVideo->height);
AVFrame* picture = av_frame_alloc();
uint8_t* pictureBuf = new uint8_t[frameSize];
  1. 初始化缓冲区**(初始化一次)**
avpicture_fill((AVPicture *)m_picture, m_pictureBuf, AV_PIX_FMT_YUV420P, pFrameVideo->width, pFrameVideo->height);
  1. 图片转换**(针对实时流或读取的文件流,循环调用)**
sws_scale(imgConvertCtx, (const uint8_t* const*)pFrameVideo->data, pFrameVideo->linesize, 0, pFrameVideo->height, picture->data, picture->linesize);

解码关闭

if (nullptr != pCodecCtxVideo)
{avcodec_close(pCodecCtxVideo);av_free(pCodecCtxVideo);pCodecCtxVideo = nullptr;
}if (nullptr != pFrameVideo)
{av_frame_free(&pFrameVideo);pFrameVideo = nullptr;
}if (nullptr != picture)
{av_frame_free(&picture);picture = nullptr;
}if (nullptr != pictureBuf)
{delete[] pictureBuf;pictureBuf = nullptr;
}if (nullptr != imgConvertCtx)
{sws_freeContext(imgConvertCtx);imgConvertCtx = nullptr;
}

音频解码

初始化

  1. 音频常用的编解码器id定义
AV_CODEC_ID_PCM_ALAW
AV_CODEC_ID_PCM_MULAW
AV_CODEC_ID_FIRST_AUDIO
AV_CODEC_ID_AAC
  1. 查找解码器:根据编解码id查看解码器
AVCodec* pCodecAudio = avcodec_find_decoder(codecID);
if (!pCodecAudio)
{printf("audio avcodec_find_decoder failed\n");return -1;
}
  1. 申请编码器上下文结构体内存,保存了音频编解码相关信息
AVCodecContext* pCodecCtxAudio = avcodec_alloc_context3(pCodecAudio);
if (!pCodecCtxAudio)
{printf("audio avcodec_alloc_context3 failed\n");return -1;
}
  1. 打开解码器
int audioCodecType = (int)codec;
switch (audioCodecType)
{case CODEC_AUDIO_AAC:break;case CODEC_AUDIO_MP3:break;case CODEC_AUDIO_G711:case CODEC_AUDIO_G711U:pCodecCtxAudio->codec_type = AVMEDIA_TYPE_AUDIO;pCodecCtxAudio->sample_fmt = AV_SAMPLE_FMT_S16;pCodecCtxAudio->sample_rate = 8000;pCodecCtxAudio->channel_layout = AV_CH_LAYOUT_MONO;pCodecCtxAudio->channels = 1;break;case CODEC_AUDIO_G7231:break;case CODEC_AUDIO_G7221:break;default:break;
}pCodecCtxAudio->codec_id = codecID;
int ret = avcodec_open2(pCodecCtxAudio, pCodecAudio, NULL);
if (ret < 0)
{printf("audio avcodec_open2 failed\n");return -1;
}
  1. 申请内存和初始化参数
AVFrame* frameAudio = av_frame_alloc();
if (!frameAudio)
{printf("audio av_frame_alloc failed\n");return -1;
}AVPacket* audioPacket = av_packet_alloc();
if (!audioPacket)
{printf("av_packet_alloc failed\n");return -1;
}
av_init_packet(audioPacket);

音频解码

  1. 解码一帧音频数据
audioPacket->data = (uint8_t*)data;
audioPacket->size = datalen;int ret = avcodec_send_packet(m_pCodecCtxAudio, m_audioPacket);
if (ret < 0) 
{av_packet_unref(audioPacket);printf("audio avcodec_send_packet failed\n");return -1;
}
  1. 接收一帧数据
ret = avcodec_receive_frame(m_pCodecCtxAudio, m_frameAudio);
if (ret < 0)
{return -1;
}
  1. 设置输入和输出音频信息**(执行一次)**
// 分配SwrContext
SwrContext* audioSwrCtx = swr_alloc();
int channelLayout = av_get_default_channel_layout(frameAudio->channels);// audioSwrCtx:重采样申请的内存。如果传NULL,内部会申请一块内存,非NULL可以复用之前的内存
// AV_CH_LAYOUT_MONO:目标声道
// AV_SAMPLE_FMT_S16:目标采样格式
// frameAudio->sample_rate:目标采样率
// channelLayout:原始声道布局
// pCodecCtxAudio->sample_fmt:原始采样格式
// frameAudio->sample_rate:原始采样率
// 设置输入和输出的音频信息
swr_alloc_set_opts(audioSwrCtx, AV_CH_LAYOUT_MONO, AV_SAMPLE_FMT_S16,frameAudio->sample_rate,channelLayout, pCodecCtxAudio->sample_fmt, frameAudio->sample_rate, 0, NULL);// 设置用户参数后初始化上下文
swr_init(audioSwrCtx);
  1. 重采样转换(循环执行)
// audioSwrCtx:音频重采样的上下文
// audioBuffer:输出的指针。传递的输出的数组
// 1024*256:输出的样本数量,不是字节数。单通道的样本数量。
// (const uint8_t**)frameAudio->data:输入的数组,AVFrame解码出来的DATA
// frameAudio->nb_samples:输入的单通道的样本数量。
// 以单声道为例
int len = swr_convert(audioSwrCtx, &audioBuffer, 1024*256,(const uint8_t**)frameAudio->data,frameAudio->nb_samples);// 获取音频大小
av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO);
int bufSize = av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO),frameAudio->nb_samples,AV_SAMPLE_FMT_S16, 0);

解码关闭

if (nullptr != pCodecCtxAudio)
{avcodec_close(pCodecCtxAudio);av_free(pCodecCtxAudio);pCodecCtxAudio = nullptr;
}if (nullptr != frameAudio)
{av_frame_free(&frameAudio);frameAudio = nullptr;
}if (nullptr != audioPacket)
{av_packet_unref(audioPacket);av_packet_free(&audioPacket);audioPacket = nullptr;
}if (nullptr != audioSwrCtx)
{swr_free(&audioSwrCtx);audioSwrCtx = nullptr;
}// 其他资源释放

相关文章:

音视频学习(十八)——使用ffmepg实现视音频解码

视频解码 初始化 视频常用的编解码器id定义&#xff08;以h264和h265为例&#xff09; // 定义在ffmpeg\include\libavcodec\avcodec.h AV_CODEC_ID_H264 AV_CODEC_ID_H265查找解码器&#xff1a;根据编解码id查看解码器 AVCodec* pCodecVideo avcodec_find_decoder(codec…...

nginx的GeoIP模块

使用场景 过滤指定地区/国家的IP&#xff0c;一般是国外IP禁止请求。 使用geoip模块实现不同国家的请求被转发到不同国家的nginx服务器&#xff0c;也就是根据国家负载均衡。 前置知识 GeoIP是什么&#xff1f; 官网地址 https://www.maxmind.com/en/home包含IP地址的地理位…...

mac控制台命令小技巧

shigen日更文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 hello伙伴们&#xff0c;作为忠实的mac骨灰级别的粉丝&#xff0c;它真的给我带来了很多效率上的提升。那作为接…...

Postman:API测试之Postman使用完全指南

Postman是一个可扩展的API开发和测试协同平台工具&#xff0c;可以快速集成到CI/CD管道中。旨在简化测试和开发中的API工作流。 Postman工具有Chrome扩展和独立客户端&#xff0c;推荐安装独立客户端。 Postman有个workspace的概念&#xff0c;workspace分personal和team类型…...

Flume学习笔记(3)—— Flume 自定义组件

前置知识&#xff1a; Flume学习笔记&#xff08;1&#xff09;—— Flume入门-CSDN博客 Flume学习笔记&#xff08;2&#xff09;—— Flume进阶-CSDN博客 Flume 自定义组件 自定义 Interceptor 需求分析&#xff1a;使用 Flume 采集服务器本地日志&#xff0c;需要按照日志…...

go的字符切片和字符串互转

Go 1.21 // 返回一个Slice&#xff0c;它的底层数组自ptr开始&#xff0c;长度和容量都是len func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType // 返回一个指针&#xff0c;指向底层的数组 func SliceData(slice []ArbitraryType) *ArbitraryType // 生成一…...

所见即所得的动画效果:Animate.css

我们可以在集成Animate.css来改善界面的用户体验&#xff0c;省掉大量手写css动画的时间。 官网&#xff1a;Animate.css 使用 1、安装依赖 npm install animate.css --save2、引入依赖 import animate.css;3、在项目中使用 在class类名上animate__animated是必须的&#x…...

ERR:Navicat连接Sql Server报错

错误信息&#xff1a;报错&#xff1a;未发现数据源名称并且未指定默认驱动程序。 原因&#xff1a;Navicat没有安装Sqlserver驱动。 解决方案&#xff1a;在Navicat安装目录下找到sqlncli_x64.msi安装即可。 一键安装即可。 Navicat链接SQL Server配置 - MarchXD - 博客园 …...

python算法例10 整数转换为罗马数字

1. 问题描述 给定一个整数&#xff0c;将其转换为罗马数字&#xff0c;要求返回结果的取值范围为1~3999。 2. 问题示例 4→Ⅳ&#xff0c;12→Ⅻ&#xff0c;21→XⅪ&#xff0c;99→XCIX。 3. 代码实现 def int_to_roman(num):val [1000, 900, 500, 400,100, 90, 50, 40…...

springboot引入第三方jar包放到项目目录中,添加web.xml

参考博客&#xff1a;https://www.cnblogs.com/mask-xiexie/p/16086612.html https://zhuanlan.zhihu.com/p/587605618 1、在resources目录下新建lib文件夹&#xff0c;将jar包放到lib文件夹中 2、修改pom.xml文件 <dependency><groupId>com.lanren312</grou…...

大数据研发工程师课前环境搭建

大数据研发工程师课前环境搭建 第一章 VMware Workstation 安装 在Windows的合适的目录来进行安装&#xff0c;如下图 1.1 双击打开 1.2 下一步&#xff0c;接受协议 1.3 选择安装位置 1.4 用户体验设置 1.5 快捷方式 已经准备好安装&#xff0c;点击安装 1.6 安装中 1.7 安装…...

Qt图形视图框架:QGraphicsItem详解

Qt图形视图框架&#xff1a;QGraphicsItem详解 Chapter1 Qt图形视图框架&#xff1a;QGraphicsItem详解Chapter2 自定义QGraphicsItem实现平移、改变尺寸和旋转1. 平移2. 改变尺寸3. 旋转完整代码如下&#xff1a;头文件源文件 Chapter1 Qt图形视图框架&#xff1a;QGraphicsIt…...

defer和async

如果两个属性浏览器都不兼容&#xff0c;推荐把<script>标签放到底部 一般情况下&#xff0c;浏览器在解析html源文件时&#xff0c;如果遇到外部的<script>标签&#xff0c;解析过程就会先暂停&#xff0c;这时会对script进行加载&#xff0c;执行两个过程&…...

数电实验-----实现74LS139芯片扩展为3-8译码器以及应用(Quartus II )

目录 一、74LS139芯片介绍 芯片管脚 芯片功能表 二、2-4译码器扩展为3-8译码器 1.扩展原理 2.电路图连接 3.仿真结果 三、3-8译码器的应用&#xff08;基于74ls139芯片&#xff09; 1.三变量表决器 2.奇偶校验电路 一、74LS139芯片介绍 74LS139芯片是属于2-4译码器…...

洋葱架构、三层架构及两者区别

前言 洋葱架构它的名称来源于洋葱的层次结构&#xff0c;即软件代码的各层次之间的关系。在这种架构中&#xff0c;应用程序的各个组件通过一系列层次结构被逐层包裹在一起&#xff0c;形成一个类似于洋葱的结构。 一、经典三层架构 三层架构是一种软件设计模式&#xff0c;…...

JavaEE进阶学习:Spring 的创建和使用

Spring 就是⼀个包含了众多工具方法的 IoC 容器。既然是容器那么它就具备两个最基本的功能&#xff1a; 将对象存储到容器&#xff08;Spring&#xff09;中从容器中将对象取出来 接下来使用 Maven 方式来创建一个 Spring 项目&#xff0c;创建 Spring 项目和 Servlet 类似&a…...

音视频项目—基于FFmpeg和SDL的音视频播放器解析(十四)

介绍 在本系列&#xff0c;我打算花大篇幅讲解我的 gitee 项目音视频播放器&#xff0c;在这个项目&#xff0c;您可以学到音视频解封装&#xff0c;解码&#xff0c;SDL渲染相关的知识。您对源代码感兴趣的话&#xff0c;请查看基于FFmpeg和SDL的音视频播放器 如果您不理解本…...

Tomcat无法映射到activiti-app导致activiti无法启动页面

原因之一&#xff1a;JDK版本与Tomcat版本不匹配&#xff0c;jdk8 yyds 我使用的是JDK11&#xff0c;Tomcat是9.0的&#xff0c;都是最新的&#xff0c;但还是不行&#xff0c;最后JDK改为8&#xff0c;tomcat的cmd后台没有报错&#xff0c;activiti-pp也可以正常访问了,很神奇…...

c语言常见的面试问题

在C语言编程中&#xff0c;面试官可能会询问你以下一些常见问题&#xff1a; 什么是C语言&#xff1f; C语言是一种通用的、过程式的计算机编程语言&#xff0c;由Dennis Ritchie在1972年创建。它是Unix操作系统的核心语言&#xff0c;也是许多其他编程语言&#xff08;如Go、…...

image图片之间的间隙消除

多个图片排列展示&#xff0c;水平和垂直方向的间隔如何消除 垂直方向 vertical-align 原因&#xff1a; vertical-align属性主要用于改变行内元素的对齐方式&#xff0c;行内元素默认垂直对齐方式是基线对齐&#xff08;baseline&#xff09; 这是因为图片属于行内元素&…...

Kandinsky-5.0-I2V-Lite-5s部署教程:Ubuntu 22.04 LTS环境完整安装与验证

Kandinsky-5.0-I2V-Lite-5s部署教程&#xff1a;Ubuntu 22.04 LTS环境完整安装与验证 1. 环境准备与快速部署 Kandinsky-5.0-I2V-Lite-5s是一款轻量级图生视频模型&#xff0c;能够将静态图片转换为5秒左右的短视频。在开始之前&#xff0c;请确保你的系统满足以下要求&#…...

提升无线传输性能:手把手教你优化Si4463的Data Rate配置与SPI通信稳定性

突破Si4463无线传输瓶颈&#xff1a;从寄存器配置到SPI时序的全链路优化实战 当你的无线模块能够通信但性能不尽如人意时&#xff0c;就像驾驶一辆引擎未调校的跑车——它能跑&#xff0c;但永远达不到理想的极速。Si4463作为工业级无线收发芯片&#xff0c;其默认配置往往无法…...

RTX 50系显卡用户看过来:在Windows上为CUDA 12.8和PyTorch Nightly版安装Triton的实战记录

RTX 50系显卡用户看过来&#xff1a;在Windows上为CUDA 12.8和PyTorch Nightly版安装Triton的实战记录 当GeForce RTX 50系列显卡遇上PyTorch Nightly和CUDA 12.8&#xff0c;这可能是目前最前沿的AI开发环境组合。但官方文档和主流教程往往跟不上硬件迭代的速度&#xff0c;让…...

InfluxDB(一)——一个高效处理数据的时序数据库

目录 一、什么是时序数据库InfluxDB&#xff1f; 关系型数据库&#xff08;行式存储&#xff09;是怎么存的&#xff1f; 时序数据库&#xff08;列式存储&#xff09;是怎么存的&#xff1f; 二、InfluxDB的特点 1. 极致的写入性能 2. 高效的存储压缩 3. 独特的数据模型…...

内网渗透零基础入门教程!小白也能轻松搞懂内网渗透基础知识点

内网渗透初探 | 小白简单学习内网渗透 0x01 基础知识 内网渗透&#xff0c;从字面上理解便是对目标服务器所在内网进行渗透并最终获取域控权限的一种渗透。内网渗透的前提需要获取一个Webshell&#xff0c;可以是低权限的Webshell&#xff0c;因为可以通过提权获取高权限。 …...

CUDA12.4环境适配:OpenClaw调用Qwen3-14B镜像的驱动配置详解

CUDA12.4环境适配&#xff1a;OpenClaw调用Qwen3-14B镜像的驱动配置详解 1. 为什么需要关注CUDA环境适配 上周我在本地部署Qwen3-14B镜像时&#xff0c;遇到了一个典型问题&#xff1a;模型加载到一半突然崩溃&#xff0c;控制台只留下一行模糊的CUDA错误提示。经过两天排查才…...

TEST文件夹:Pytest,集成测试,单元测试

在复杂的自动驾驶项目中&#xff0c;哪怕你只改了一行代码&#xff0c;都可能导致整个感知或控制系统崩溃。如果直接去训练&#xff0c;还会消耗大量算力。所以当你新写了一个功能&#xff08;比如你改了采样逻辑&#xff09;&#xff0c;先不要急着去跑训练。先跑一下测试&…...

**管线流程**:模型矩阵 × 视图矩阵 × 投影矩阵 × 顶点 → GPU自动完成裁剪/光栅化

一、二进制、八进制、十六进制的转换方法&#xff08;通俗版&#xff09; 本质&#xff1a;都是“逢几进一”的计数法&#xff0c;只是“底数”不同&#xff08;2/8/16&#xff09;。 二进制&#xff08;Base-2&#xff09;&#xff1a;只用 0 和 1&#xff0c;是计算机硬件唯一…...

COMSOL混凝土碳化模型

COMSOL 混凝土碳化模型混凝土表面那层白霜般的碳化层&#xff0c;总让我想起实验室里放了三个月的苏打饼干。这层碳酸钙的生成过程&#xff0c;在COMSOL里建模就像在模拟一场微观世界的化学舞会——二氧化碳分子突破混凝土保护层&#xff0c;与氢氧化钙在孔隙溶液里跳起离子交换…...

【GitLab npm Registry 非标准端口安装问题解决方案】

GitLab npm Registry 非标准端口安装问题解决方案 问题类型: npm/pnpm 客户端与 GitLab npm Registry 集成 影响范围: 使用非标准端口的 GitLab npm Registry 解决时间: 2026-04-03 文档版本: v1.0 一、问题背景 1.1 业务场景 团队需要将内部组件库发布到私有 npm registry,选…...