音视频学习(十八)——使用ffmepg实现视音频解码
视频解码
初始化
- 视频常用的编解码器id定义(以h264和h265为例)
// 定义在ffmpeg\include\libavcodec\avcodec.h
AV_CODEC_ID_H264
AV_CODEC_ID_H265
- 查找解码器:根据编解码id查看解码器
AVCodec* pCodecVideo = avcodec_find_decoder(codecID);
if (!pCodecVideo)
{printf("avcodec_find_decoder failed\n");return -1;
}
- 申请编码器上下文结构体内存,保存了视频编解码相关信息
AVCodecContext* pCodecCtxVideo = avcodec_alloc_context3(pCodecVideo);
if (!pCodecCtxVideo)
{printf("avcodec_alloc_context3 error\n");return -1;
}
- 打开解码器
if (avcodec_open2(pCodecCtxVideo, pCodecVideo, NULL) < 0)
{printf("avcodec_open2 failed\n");return -1;
}
- 申请帧内存:存储一帧解码后像素(采样)数据
AVFrame* pFrameVideo = av_frame_alloc();
if (!pFrameVideo)
{printf("av_frame_alloc failed\n");return -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;
}
- 获取帧大小
// 以YUV420为例
int frameSize = avpicture_get_size(AV_PIX_FMT_YUV420P, pFrameVideo->linesize[0], pFrameVideo->height);
- 获取上下文,获取用于转码的参数**(初始化一次)**
// 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);
- 缓冲区分配缓存**(初始化一次)**
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];
- 初始化缓冲区**(初始化一次)**
avpicture_fill((AVPicture *)m_picture, m_pictureBuf, AV_PIX_FMT_YUV420P, pFrameVideo->width, pFrameVideo->height);
- 图片转换**(针对实时流或读取的文件流,循环调用)**
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;
}
音频解码
初始化
- 音频常用的编解码器id定义
AV_CODEC_ID_PCM_ALAW
AV_CODEC_ID_PCM_MULAW
AV_CODEC_ID_FIRST_AUDIO
AV_CODEC_ID_AAC
- 查找解码器:根据编解码id查看解码器
AVCodec* pCodecAudio = avcodec_find_decoder(codecID);
if (!pCodecAudio)
{printf("audio avcodec_find_decoder failed\n");return -1;
}
- 申请编码器上下文结构体内存,保存了音频编解码相关信息
AVCodecContext* pCodecCtxAudio = avcodec_alloc_context3(pCodecAudio);
if (!pCodecCtxAudio)
{printf("audio avcodec_alloc_context3 failed\n");return -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;
}
- 申请内存和初始化参数
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);
音频解码
- 解码一帧音频数据
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;
}
- 接收一帧数据
ret = avcodec_receive_frame(m_pCodecCtxAudio, m_frameAudio);
if (ret < 0)
{return -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);
- 重采样转换(循环执行)
// 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定义(以h264和h265为例) // 定义在ffmpeg\include\libavcodec\avcodec.h AV_CODEC_ID_H264 AV_CODEC_ID_H265查找解码器:根据编解码id查看解码器 AVCodec* pCodecVideo avcodec_find_decoder(codec…...
nginx的GeoIP模块
使用场景 过滤指定地区/国家的IP,一般是国外IP禁止请求。 使用geoip模块实现不同国家的请求被转发到不同国家的nginx服务器,也就是根据国家负载均衡。 前置知识 GeoIP是什么? 官网地址 https://www.maxmind.com/en/home包含IP地址的地理位…...
mac控制台命令小技巧
shigen日更文章的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长,分享认知,留住感动。 hello伙伴们,作为忠实的mac骨灰级别的粉丝,它真的给我带来了很多效率上的提升。那作为接…...
Postman:API测试之Postman使用完全指南
Postman是一个可扩展的API开发和测试协同平台工具,可以快速集成到CI/CD管道中。旨在简化测试和开发中的API工作流。 Postman工具有Chrome扩展和独立客户端,推荐安装独立客户端。 Postman有个workspace的概念,workspace分personal和team类型…...
Flume学习笔记(3)—— Flume 自定义组件
前置知识: Flume学习笔记(1)—— Flume入门-CSDN博客 Flume学习笔记(2)—— Flume进阶-CSDN博客 Flume 自定义组件 自定义 Interceptor 需求分析:使用 Flume 采集服务器本地日志,需要按照日志…...
go的字符切片和字符串互转
Go 1.21 // 返回一个Slice,它的底层数组自ptr开始,长度和容量都是len func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType // 返回一个指针,指向底层的数组 func SliceData(slice []ArbitraryType) *ArbitraryType // 生成一…...
所见即所得的动画效果:Animate.css
我们可以在集成Animate.css来改善界面的用户体验,省掉大量手写css动画的时间。 官网:Animate.css 使用 1、安装依赖 npm install animate.css --save2、引入依赖 import animate.css;3、在项目中使用 在class类名上animate__animated是必须的&#x…...
ERR:Navicat连接Sql Server报错
错误信息:报错:未发现数据源名称并且未指定默认驱动程序。 原因:Navicat没有安装Sqlserver驱动。 解决方案:在Navicat安装目录下找到sqlncli_x64.msi安装即可。 一键安装即可。 Navicat链接SQL Server配置 - MarchXD - 博客园 …...
python算法例10 整数转换为罗马数字
1. 问题描述 给定一个整数,将其转换为罗马数字,要求返回结果的取值范围为1~3999。 2. 问题示例 4→Ⅳ,12→Ⅻ,21→XⅪ,99→XCIX。 3. 代码实现 def int_to_roman(num):val [1000, 900, 500, 400,100, 90, 50, 40…...
springboot引入第三方jar包放到项目目录中,添加web.xml
参考博客:https://www.cnblogs.com/mask-xiexie/p/16086612.html https://zhuanlan.zhihu.com/p/587605618 1、在resources目录下新建lib文件夹,将jar包放到lib文件夹中 2、修改pom.xml文件 <dependency><groupId>com.lanren312</grou…...
大数据研发工程师课前环境搭建
大数据研发工程师课前环境搭建 第一章 VMware Workstation 安装 在Windows的合适的目录来进行安装,如下图 1.1 双击打开 1.2 下一步,接受协议 1.3 选择安装位置 1.4 用户体验设置 1.5 快捷方式 已经准备好安装,点击安装 1.6 安装中 1.7 安装…...
Qt图形视图框架:QGraphicsItem详解
Qt图形视图框架:QGraphicsItem详解 Chapter1 Qt图形视图框架:QGraphicsItem详解Chapter2 自定义QGraphicsItem实现平移、改变尺寸和旋转1. 平移2. 改变尺寸3. 旋转完整代码如下:头文件源文件 Chapter1 Qt图形视图框架:QGraphicsIt…...
defer和async
如果两个属性浏览器都不兼容,推荐把<script>标签放到底部 一般情况下,浏览器在解析html源文件时,如果遇到外部的<script>标签,解析过程就会先暂停,这时会对script进行加载,执行两个过程&…...
数电实验-----实现74LS139芯片扩展为3-8译码器以及应用(Quartus II )
目录 一、74LS139芯片介绍 芯片管脚 芯片功能表 二、2-4译码器扩展为3-8译码器 1.扩展原理 2.电路图连接 3.仿真结果 三、3-8译码器的应用(基于74ls139芯片) 1.三变量表决器 2.奇偶校验电路 一、74LS139芯片介绍 74LS139芯片是属于2-4译码器…...
洋葱架构、三层架构及两者区别
前言 洋葱架构它的名称来源于洋葱的层次结构,即软件代码的各层次之间的关系。在这种架构中,应用程序的各个组件通过一系列层次结构被逐层包裹在一起,形成一个类似于洋葱的结构。 一、经典三层架构 三层架构是一种软件设计模式,…...
JavaEE进阶学习:Spring 的创建和使用
Spring 就是⼀个包含了众多工具方法的 IoC 容器。既然是容器那么它就具备两个最基本的功能: 将对象存储到容器(Spring)中从容器中将对象取出来 接下来使用 Maven 方式来创建一个 Spring 项目,创建 Spring 项目和 Servlet 类似&a…...
音视频项目—基于FFmpeg和SDL的音视频播放器解析(十四)
介绍 在本系列,我打算花大篇幅讲解我的 gitee 项目音视频播放器,在这个项目,您可以学到音视频解封装,解码,SDL渲染相关的知识。您对源代码感兴趣的话,请查看基于FFmpeg和SDL的音视频播放器 如果您不理解本…...
Tomcat无法映射到activiti-app导致activiti无法启动页面
原因之一:JDK版本与Tomcat版本不匹配,jdk8 yyds 我使用的是JDK11,Tomcat是9.0的,都是最新的,但还是不行,最后JDK改为8,tomcat的cmd后台没有报错,activiti-pp也可以正常访问了,很神奇…...
c语言常见的面试问题
在C语言编程中,面试官可能会询问你以下一些常见问题: 什么是C语言? C语言是一种通用的、过程式的计算机编程语言,由Dennis Ritchie在1972年创建。它是Unix操作系统的核心语言,也是许多其他编程语言(如Go、…...
image图片之间的间隙消除
多个图片排列展示,水平和垂直方向的间隔如何消除 垂直方向 vertical-align 原因: vertical-align属性主要用于改变行内元素的对齐方式,行内元素默认垂直对齐方式是基线对齐(baseline) 这是因为图片属于行内元素&…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
