音视频学习(十八)——使用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;
}// 其他资源释放

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/155829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Win10系统强制固定任务栏的解决方法

Windows 10 桌面版“开始”菜单布局 XML (Windows 10) - Configure Windows | Microsoft Learn LayoutModification.xml位置&#xff1a; C:/Users/Default/Appdata/Local/Microsoft/Windows/Shell/LayoutModification.xml C:/Users/域账号/Appdata/Local/Microsoft/Windows…

2015-2020年全国地区生产总值及一二三产构成数据总览,shp/excel格式

今天我们来整理了2015-2020全国地区生产总值及一二三产构成数据&#xff0c;数据格式为shpexcel格式&#xff0c;数据精度可达各区县。 另外&#xff0c;需要说明的是&#xff1a;由于统计年鉴指标调整&#xff0c;每一年的数据并非字段相同&#xff0c;字段详情请参考已下载数…

梯度引导的分子生成扩散模型- GaUDI 评测

GaUDI模型来自于以色列理工Tomer Weiss的2023年发表在预印本ChemRxiv上的工作 《Guided Diffusion for Inverse Molecular Design》。原文链接&#xff1a;Guided Diffusion for Inverse Molecular Design | Materials Chemistry | ChemRxiv | Cambridge Open Engage GaUDI模型…

详解Python Tornado框架写一个Web应用全过程

Tornado是什么 之前在看Jupyter组件的源码的时候&#xff0c;发现了tornado这个web框架。 不仅仅做一个web框架&#xff0c; 通过使用非阻塞网络I/O&#xff0c;Tornado可以扩展到数万个开放连接。 这样非常适合 long polling &#xff0c; WebSockets 以及其他需要与每个用户…

shell脚本判断语句

目录 一. 判断语句 1. 判断文件是否存在 test 2. 数值比较 3. 字符串比较 4. 逻辑运算 5. [ ] 与 [ [ ] ] 6. ( ) 与 { } 7. if 语句 二. 脚本应用 一. 判断语句 1. 判断文件是否存在 test 选项 -a 和 -e 都可以判断文件是否存在 只是 -a 选项在取反时有问题&#xf…

Linux | 安装openGauss数据库

Linux 安装openGauss数据库 今天我们来安装一下国产数据库openGauss~~ 下载openGauss 首先在官网下载对应的安装包&#xff0c;我们这里下载LInux 极简版来演示安装 下载后,使用root用户上传到Linux ,这边上传到/usr/local/目录下, 使用root 用户创建安装目录 mkdir /usr/l…

C#实现网络通信共享库NetShare

前言 网络通信共享库NetShare用于保证客户端与服务器通信数据包的规范和统一&#xff0c;客户端与服务器共同使用本库&#xff0c;提升数据包序列化和反序列化的准确性和安全性&#xff0c;并且用于满足不同的通信数据需求。 NetShare&#xff1a;DataPacket&#xff08;通用…

C++刷题 -- 二分查找

C刷题 – 二分查找 文章目录 C刷题 -- 二分查找一、原理二、例题1.二分查找2.使用二分查找确定target左右边界3.x的平方根 一、原理 条件&#xff1a;数组为有序数组&#xff0c;数组中无重复元素&#xff0c;因为一旦有重复元素&#xff0c;使用二分查找法返回的元素下标可能…

JavaScript前端接收流式数据

在Java开发中&#xff0c;前端接收流式数据通常涉及到使用WebSocket 或Server-Sent Events&#xff08;SSE&#xff09;这样的技术。这两种技术都允许服务器推送实时数据到客户端&#xff0c;以便在浏览器中进行处理和更新。 1. WebSocket&#xff1a; WebSocket是一种在单个…

基于单片机预费电表控制系统(proteus仿真+源程序)

一、系统方案 1、本设计采用这51单片机作为主控器。 2、采集电量值送到液晶1602显示。 3、按键设置预设值&#xff0c;实际使用电量超过设置&#xff0c;蜂鸣器报警。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 void LCD_init(void) { …

SMART PLC累计流量功能块(梯形积分法+浮点数累加精度控制)

S7-200SMART PLC数值积分器相关知识请参考下面文章链接: SMART PLC数值积分器功能块(矩形+梯形积分法完整源代码)-CSDN博客文章浏览阅读153次。PLC的数值积分器算法也可以参考下面文章链接:PLC算法系列之数值积分器(Integrator)-CSDN博客数值积分和微分在工程上的重要意义不…

前端CSS实现响应式TimeLine效果(附源码)

文章目录 纯CSS搭建&#xff0c;先上效果图&#xff08;附有源码&#xff09;视图层 index.htmlindex.css 公用样式文件Main.css 主要的样式文件 纯CSS搭建&#xff0c;先上效果图&#xff08;附有源码&#xff09; 本效果为纯CSS搭建&#xff0c;适配移动端和PC端&#xff01…

CMap数据库筛选化学药物

数据库clue.io 文献链接&#xff1a;连接图谱&#xff1a;使用基因表达特征连接小分子、基因和疾病 |科学 (science.org) 基本模式&#xff1a;利用CMap将差异基因列表与数据库参考数据集比对&#xff1b;根据差异表达基因在参考基因表达谱富集情况得到一个相关性分数&#…

CSS选择器 前端开发入门笔记(十)

CSS选择器 CSS选择器是用来选择需要改变样式的HTML元素的模式。到CSS3为止&#xff0c;支持的选择器类型有6种&#xff0c;包括标签选择器、派生选择器&#xff08;上下文选择器&#xff09;、id选择器、class选择器、属性选择器和通配符*选择器。以下是这六种选择器的简要介绍…

DS5上ARM编译器样例工程改为GCC编译

想问一下&#xff0c;DS5上ARM编译器通过的样例工程&#xff0c;换成aarch64-none-elf-gcc工具链&#xff0c;是不是需要把startup.S改成gcc支持的格式呀&#xff1f;怎么改呢&#xff0c;求助大神们指点一下&#xff01;谢谢&#xff01;

leetcode40.组合总和II(去重思路精讲,经典题也可以有困难的思考!)

首先感谢您&#xff0c;打开本文章&#xff0c;一道网上很多题解的一道经典回溯题&#xff0c;能讲出什么花来呢&#xff1f; 看了这篇文章&#xff0c;希望能使您眼前一新。 大概的思路对于一些读者可能很简单&#xff0c;我也简单提一嘴解题思路&#xff0c;因为可能有新读…

C# 22H2之后的windows版本使用SetDynamicTimeZoneInformation设置时区失败处理

使用SetDynamicTimeZoneInformation设置时区返回false&#xff0c;设置失败。 使用PowerShell设置Set-TimeZone成功。 /// <summary> /// 设置本地时区 /// 参数取值"China Standard Time"&#xff0c;即可设置为中国时区 /// </summary> /// <param …

Redis从入门到精通(二)- 入门篇

文章目录 0. 前言1. 入门篇[【入门篇】1.1 redis 基础数据类型详解和示例](https://icepip.blog.csdn.net/article/details/134438573)[【入门篇】1.2 Redis 客户端之 Jedis 详解和示例](https://icepip.blog.csdn.net/article/details/134440061)[【入门篇】1.3 redis客户端之…

(六)什么是Vite——热更新时vite、webpack做了什么

vite分享ppt&#xff0c;感兴趣的可以下载&#xff1a; ​​​​​​​Vite分享、原理介绍ppt 什么是vite系列目录&#xff1a; &#xff08;一&#xff09;什么是Vite——vite介绍与使用-CSDN博客 &#xff08;二&#xff09;什么是Vite——Vite 和 Webpack 区别&#xff0…

LR学习笔记——基本面板

文章目录 面板介绍色彩调整区域明暗调整区域纹理及质感色彩饱和 面板介绍 面板如上图所示 基本可分为几个板块&#xff1a;色彩、明暗、纹理及质感、色彩饱和 色彩调整区域 色温&#xff1a;由蓝色和黄色控制色调&#xff1a;由绿色和洋红控制 互补色&#xff1a;蓝色对黄色&…