ffmpeg[学习(四)](代码实现) 实现音频数据解码并且用SDL播放

0、作者杂谈

CSDN大多数都是落后的,要么是到处复制粘贴的,对于初学者我来说困惑了很久,大多数CSDN文章都是使用旧的API ,已经被否决了,于是我读一些官方文档,和一些开源项目音视频的输出过程,写出这篇文章希望能帮助到入门音视频的人。
感觉这个专栏没多少人看呃,哎~

一、流程导图

其实与视频解码播放流程差不了太多,前面部分和专栏(一)一样
ffmpeg学习(一)
后面的话是添加了回调函数用于声卡通过回调函数拉数据到声卡缓冲区
在这里插入图片描述

二、实现过程

在这里插入图片描述
这中间省略了很多步骤 其实和ffmpeg学习(三)类似

SDL参数

在这里插入图片描述

转码参数和一开始的参数

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/2d471a44ad4f45d99eac2af9ae05b400.pn
这里新API中将AVChannelLayout分离出来了,我们需要自己创建一个AVChannelLayout来获得声道布局为后面转码参数做铺垫

转码器

在这里插入图片描述

数据转换格式

在这里插入图片描述
这里SDL_Delay主要是防止声音播放过快。

回调函数

在这里插入图片描述

播放过程

在这里插入图片描述
😔 这里播放的是瓦罗兰特的die for you 可惜你们听不到 😄 希望这篇文章对读者有收获!

源代码

#include<iostream>
#include "vp_test.h"static uint8_t* audio_buf = new uint8_t[4096];static int audio_size;void read_audio_data(void* userdata, Uint8* stream,int len)
{if (audio_size == 0)return;int audio_buf_index = 0;int len1 = 0; while (len > 0){len1 = audio_size - audio_buf_index;if (len1 > len)len1 = len;memcpy(stream, audio_buf+audio_buf_index, len1);audio_buf_index += len1;stream += len1;len -= len1;}SDL_Delay(1);}int vp_audio(const char * filepath) {int ret = 0;AVFormatContext* is = NULL;AVCodecContext* ic = NULL;const AVCodec* codec = NULL;AVPacket* pkt = NULL;AVFrame* frame = NULL;int audio_index;//init ffmpegis = avformat_alloc_context();pkt = av_packet_alloc();frame = av_frame_alloc();//初始化网络库avformat_network_init();if (avformat_open_input(&is, filepath, NULL, NULL) != 0) {return -1;}if (avformat_find_stream_info(is, NULL) < 0) {return -1;}//查找音频解码器for (int i = 0; i < is->nb_streams; i++) {AVStream *stream = NULL;stream = is->streams[i];if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {codec = avcodec_find_decoder(stream->codecpar->codec_id);ic = avcodec_alloc_context3(codec);avcodec_parameters_to_context(ic,stream->codecpar);audio_index = i;}}//打开解码器if (avcodec_open2(ic, codec, NULL) != 0)return -1;//SDL 初始化音频模块SDL_Init(SDL_INIT_AUDIO | SDL_INIT_AUDIO);//初始化SDL中自己想设置的参数SDL_AudioSpec wanted_spec ;wanted_spec.freq = 44100;wanted_spec.format = AUDIO_S16SYS;wanted_spec.channels = 2;wanted_spec.samples = 1024;wanted_spec.callback = read_audio_data;wanted_spec.userdata = ic;//设置转码参数(转码成我们SDL播放的音频参数格式)AVChannelLayout out_ch;av_channel_layout_default(&out_ch, 2);int out_nb_samples = 1024;enum AVSampleFormat sample_fmt = AV_SAMPLE_FMT_S16;int out_sample_rate = 44100;// 解码前的格式参数AVChannelLayout in_ch ;av_channel_layout_default(&in_ch, 2);enum AVSampleFormat in_sample_fmt=ic->sample_fmt;int in_sample_rate=ic->sample_rate;//转码器SwrContext* swr_ctx = NULL;swr_alloc_set_opts2(&swr_ctx,&out_ch,sample_fmt,out_sample_rate,&in_ch,in_sample_fmt,in_sample_rate,0, NULL);swr_init(swr_ctx);//打开音频播放设备if (SDL_OpenAudio(&wanted_spec, NULL) < 0)return -1;//开始或暂停播放SDL_PauseAudio(0);//开始调用回调函数填充缓冲区while (true) {while (true) {if (av_read_frame(is, pkt))goto end;//读取完毕if (pkt->stream_index == audio_index)break;}//发送编码包avcodec_send_packet(ic, pkt);av_frame_unref(frame);if (avcodec_receive_frame(ic, frame) == 0) {//数据转换int upper_bound_samples = swr_get_out_samples(swr_ctx, frame->nb_samples);uint8_t* out[4] = { 0 };out[0] = (uint8_t*)av_malloc(upper_bound_samples * 2 * 2);int samples = swr_convert(swr_ctx,out,upper_bound_samples,(const uint8_t**)frame->data,frame->nb_samples);//将数据写入buffer区memcpy(audio_buf, out[0], samples * 4);audio_size = samples * 4;SDL_Delay(19);}}
end:if (is)avformat_free_context(is);if (ic)avcodec_free_context(&ic);if (pkt)av_packet_free(&pkt);if (frame)av_frame_free(&frame);if (swr_ctx)swr_free(&swr_ctx);SDL_CloseAudio();SDL_Quit();return 0;
}

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

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

相关文章

开源的RNA-Seq分析软件Trinity的详细介绍和使用方法

介绍 GitHub - trinityrnaseq/trinityrnaseq: Trinity RNA-Seq de novo transcriptome assembly Trinity是一种开源的RNA-Seq分析软件&#xff0c;用于转录组的de novo组装。转录组de novo组装是通过将RNA-Seq数据中的短序列片段&#xff08;reads&#xff09;重新组装成完整的…

模型容器与AlexNet构建

一、模型容器——Containers nn.Sequential 是 nn.module的容器&#xff0c;用于按顺序包装一组网络层 Sequential 容器 nn.Sequential 是 nn.module的容器&#xff0c;用于按顺序包装一组网络层 • 顺序性&#xff1a;各网络层之间严格按照顺序构建 • 自带forward()&#xf…

x-cmd pkg | grex - 用于生成正则表达的命令行工具

目录 简介首次用户生成的正则表达式与 perl 和 rust 兼容支持 Unicode 符号友好的用户体验进一步阅读 简介 grex 是一个旨在简化创作正则表达式的复杂且繁琐任务的库和命令行程序。这个项目最初是 Devon Govett 编写的 JavaScript 工具 regexgen 的 Rust 移植。但 regexgen 在…

AArch64 Exception Model学习

提示 该博客主要为个人学习&#xff0c;通过阅读官网手册整理而来&#xff08;个人觉得阅读官网的英文文档非常有助于理解各个IP特性&#xff09;。若有不对之处请参考参考文档&#xff0c;以官网文档为准。 1 Privilege and Exception Levels 1.1 为什么要划分权限&#xf…

MySQL基础笔记(3)DML数据操作语句

顾名思义&#xff0c;全称是数据操作语言&#xff0c;用来对数据库中表的数据记录进行增删改操作~ 目录 一.添加数据 1.给指定字段添加数据 2.给全部字段添加数据 3.批量添加数据 二.修改数据 三.删除数据 一.添加数据 1.给指定字段添加数据 insert into 表名 (字段名…

java数据结构与算法刷题-----LeetCode343. 整数拆分(TODO)

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难&#xff0c;但它就是固定套路而已。其实动态规划只…

jenkins构建git项目timeout

问题点&#xff1a; Started by user unknown or anonymous Running as SYSTEM Building in workspace /var/jenkins_home/workspace/test-one using credential f28d956-8ee1-4f20-a32b-06879b487c70 Cloning the remote Git repository Cloning repository http://git.cc.co…

Flink CDC使用

Flink 环境准备 Flink 版本对应的CDC版本 两个jar包上传到flink bin目录下 flink-sql-connector-mysql-cdc mysql-connector-java 重启Flink集群

stm32的FMC数据访问与突发模式

数据访问 配置外部存储器的宽度为 16 位&#xff0c; FMC 将使用内部的 ADDR[25:1]地址来作为对外部存储器的寻址地址 FMC_A[24:0]&#xff0c;这段描述是在解释在STM32的FMC&#xff08;Flexible Memory Controller&#xff09;中&#xff0c;如何配置外部存储器的宽度为16位…

资产信息管理系统-前后端开发

题目要求&#xff1a; 资产管理系统 利用H5规范&#xff0c;CSS样式与JS脚本独立于HTML页面&#xff0c;Javascript调用jQuery库&#xff0c;CRUD后端使用FastAPI封装&#xff0c;前端页面在Nginx中运行&#xff0c;调用API模块&#xff0c; 实现CURD的课设总结 基本设计&am…

【已解决】c语言编写的lib如何调用

本博文源于笔者在vs2015正在编写的lib想要调用的问题&#xff0c;正常的操作是将项目生成lib&#xff0c;但是然后又如何操作呢&#xff0c;本博文就是解决这样的问题 文章目录 问题再现步骤1&#xff1a;编写lib.h与lib.c步骤2&#xff1a;生成lib步骤3&#xff1a;添加用得到…

7 集中式日志和分布式跟踪

文章目录 日志聚合模式日志集中化的简单解决方案使用日志并输出分布式跟踪Spring Cloud Sleuth实现分布式跟踪 小结 前面的文章&#xff1a; 1、 1 一个测试驱动的Spring Boot应用程序开发 2、 2 使用React构造前端应用 3、 3 试驱动的Spring Boot应用程序开发数据层示例 4、…

中国京津冀国际光伏展

中国京津冀国际光伏展是一个专门展示光伏技术和产品的展览会。该展览会旨在促进光伏产业的发展和推广&#xff0c;推动太阳能光伏的应用和利用。 这个展览会通常会邀请国内外的光伏企业和专家参加&#xff0c;展示最新的光伏技术和产品&#xff0c;包括太阳能电池板、光伏组件、…

RequestMapping注解的使用和常见的GET和POST请求方式

RequestMapping注解的使用和常见的GET和POST请求方式 1、使用说明 作用&#xff1a;用于建立请求URL和处理请求方法之间的对应关系。 出现位置&#xff1a; 类上&#xff1a; 请求 URL的第一级访问目录。此处不写的话&#xff0c;就相当于应用的根目录。写的话需要以/开头。它…

计算机科学速成课【学习笔记】(4)——二进制

本集课程B站链接&#xff1a; 4. 二进制-Representing Numbers and Letters with Binary_BiliBili_哔哩哔哩_bilibili4. 二进制-Representing Numbers and Letters with Binary_BiliBili是【计算机科学速成课】[40集全/精校] - Crash Course Computer Science的第4集视频&…

Vue生命周期图解

生命周期四个阶段&#xff1a; ① 创建 ② 挂载 ③ 更新 ④ 销毁 图解&#xff1a; 包含8个钩子函数

C# 日期转换“陷阱”

在 C# 中&#xff0c;日期转换可能会遇到一些陷阱。以下是一些常见的陷阱和如何避免它们&#xff1a; 时区问题 日期和时间通常与时区相关&#xff0c;但在转换时可能会忽略或混淆时区信息。确保在转换日期时始终考虑到时区&#xff0c;并使用正确的时区进行转换。 DateTime…

vue购物车案例、v-model进阶、与后端交互

一 购物车案例 - 结算 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>购物车结算</title><script src"https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></scr…

Spark与Elasticsearch的集成与全文搜索

Apache Spark和Elasticsearch是在大数据处理和全文搜索领域中非常流行的工具。在本文中&#xff0c;将深入探讨如何在Spark中集成Elasticsearch&#xff0c;并演示如何进行全文搜索和数据分析。将提供丰富的示例代码&#xff0c;以便更好地理解这一集成过程。 Spark与Elastics…

视频监控系统EasyCVR如何通过调用API接口查询和下载设备录像?

智慧安防平台EasyCVR是基于各种IP流媒体协议传输的视频汇聚和融合管理平台。视频流媒体服务器EasyCVR采用了开放式的网络结构&#xff0c;支持高清视频的接入和传输、分发&#xff0c;平台提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联…