音视频开发:基于sdl的pcm播放器
源码
/*** SDL2播放PCM*** 本程序使用SDL2播放PCM音频采样数据。SDL实际上是对底层绘图* API(Direct3D,OpenGL)的封装,使用起来明显简单于直接调用底层* API。* 测试的PCM数据采用采样率44.1k, 采用精度S16SYS, 通道数2** 函数调用步骤如下:** [初始化]* SDL_Init(): 初始化SDL。* SDL_OpenAudio(): 根据参数(存储于SDL_AudioSpec)打开音频设备。* SDL_PauseAudio(): 播放音频数据。** [循环播放数据]* SDL_Delay(): 延时等待播放完成。**/#include <stdio.h>
#include <SDL.h>
#include <iostream>// 每次读取2帧数据, 以1024个采样点一帧 2通道 16bit采样点为例// 一个采样点为16bit
#define PCM_BUFFER_SIZE (1024*2*2*2)// 音频PCM数据缓存
static Uint8* s_audio_buf = NULL;
// 目前读取的位置
static Uint8* s_audio_pos = NULL;
// 缓存结束位置
static Uint8* s_audio_end = NULL;//音频设备回调函数
void fill_audio_pcm(void* udata, Uint8* stream, int len)
{std::cout << "fill_audio_pcm" << std::endl;SDL_memset(stream, 0, len);if (s_audio_pos >= s_audio_end) // 数据读取完毕{return;}// 数据够了就读预设长度,数据不够就只读部分(不够的时候剩多少就读取多少)int remain_buffer_len = s_audio_end - s_audio_pos;len = (len < remain_buffer_len) ? len : remain_buffer_len;// 拷贝数据到stream并调整音量SDL_MixAudio(stream, s_audio_pos, len, SDL_MIX_MAXVOLUME / 8);printf("len = %d\n", len);s_audio_pos += len; // 移动缓存指针
}// 提取PCM文件
// ffmpeg -i input.mp4 -t 20 -codec:a pcm_s16le -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm
// 测试PCM文件
// ffplay -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm
#undef main
int main(int argc, char* argv[])
{int ret = -1;FILE* audio_fd = NULL;SDL_AudioSpec spec;//音频设备const char* path = "44100_16bit_2ch.pcm";// 每次缓存的长度size_t read_buffer_len = 0;//SDL initializeif (SDL_Init(SDL_INIT_AUDIO)) // 支持AUDIO{fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());return ret;}//打开PCM文件fopen_s(&audio_fd,path, "rb");if (!audio_fd){fprintf(stderr, "Failed to open pcm file!\n");// goto _FAIL;}s_audio_buf = (uint8_t*)malloc(PCM_BUFFER_SIZE);// 音频参数设置SDL_AudioSpecspec.freq = 44100; // 采样频率spec.format = AUDIO_S16SYS; // 采样点格式spec.channels = 2; // 2通道spec.silence = 0;spec.samples = 1024; // 23.2ms -> 46.4ms 每次读取的采样数量,多久产生一次回调和 samplesspec.callback = fill_audio_pcm; // 回调函数spec.userdata = NULL;//打开音频设备if (SDL_OpenAudio(&spec, NULL)){fprintf(stderr, "Failed to open audio device, %s\n", SDL_GetError());//goto _FAIL;}//play audioSDL_PauseAudio(0);int data_count = 0;while (1){// 从文件读取PCM数据read_buffer_len = fread(s_audio_buf, 1, PCM_BUFFER_SIZE, audio_fd);if (read_buffer_len == 0){break;}data_count += read_buffer_len; // 统计读取的数据总字节数printf("now playing %10d bytes data.\n", data_count);s_audio_end = s_audio_buf + read_buffer_len; // 更新buffer的结束位置s_audio_pos = s_audio_buf; // 更新buffer的起始位置//the main thread wait for a momentwhile (s_audio_pos < s_audio_end){SDL_Delay(10); // 等待PCM数据消耗}}printf("play PCM finish\n");// 关闭音频设备SDL_CloseAudio();_FAIL://release some resourcesif (s_audio_buf)free(s_audio_buf);if (audio_fd)fclose(audio_fd);//quit SDLSDL_Quit();return 0;
}
音频播放的时机
当使用SDL_PauseAudio(0)时, 表示音频开始播放
-参数 0:
当参数为 0 时,表示恢复音频播放。相反,如果传入 1,则表示暂停音频播放。
SDL_PauseAudio(0);
读取数据
如果对c++指针不熟悉的, 可能这里不太明白, 在一开始, 就声明了pcm的三个字段, 其中一个是缓存, 剩下的是起始位置和结束位置, !!! 这里注意, 他们使用的类型都是Uint8*, 这是指向一段内存的地址, 如果使用s_audio_buf可以存储缓存, 那么其他两个也可以
// 音频PCM数据缓存
static Uint8* s_audio_buf = NULL;
// 目前读取的位置
static Uint8* s_audio_pos = NULL;
// 缓存结束位置
static Uint8* s_audio_end = NULL;
这个函数的功能是将缓存的数据存放到stream中, 但是这里使用的并不是s_audio_buf, 而是s_audio_pos, 其实s_audio_pos也指向缓存(这里刚刚解释过了)
// 拷贝数据到stream并调整音量
SDL_MixAudio(stream, s_audio_pos, len, SDL_MIX_MAXVOLUME / 8);
什么时候更新数据
音频的数据和视频还不太一样, 视频是以帧为单位播放的, 可以指定单位时间内播放的帧的数量并且视频帧是需要在显示屏上停留一段微小的时间, 但是音频是连续的, 无法直接给定时间. 当给stream的值消耗完成后, 及s_audio_pos ==s_audio_end, 重新从文件中获取数据
// 等待PCM数据消耗,
while (s_audio_pos < s_audio_end)
{SDL_Delay(10); // 每次循环延时10ms
}
pcm采样率
首先, pcm是一种纯文本格式, 也就是说, pcm的播放速度是人为指定的, 这个就是我们使用的采样率
spec.freq = 44100; // 采样频率
当使用不同采样率的时候, 播放速度是不一样的, 可以通过计时器来验证一下
当采样频率比较小的时候, 播放时间就会比较长, 但是并不是所有的音频都可以通过修改Player的采样频率来实现是否倍数播放, 比如非纯文本格式的mp3是不可以的, 这样做的后果只是video的清晰度而已

粉丝福利,博主耗时2个月整理了一份详细的音视频开发学习教程,涵盖了音视频开发FFmmpeg、流媒体客户端、流媒体服务器、WebRTC、Android NDK开发、IOS音视频开发等等全栈技术栈,并提供了配套的免费领取C++音视频学习资料包、技术视频/代码,内容包括(FFmpeg ,WebRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs流媒体服务器,音视频通话等等)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
相关文章:
音视频开发:基于sdl的pcm播放器
源码 /*** SDL2播放PCM*** 本程序使用SDL2播放PCM音频采样数据。SDL实际上是对底层绘图* API(Direct3D,OpenGL)的封装,使用起来明显简单于直接调用底层* API。* 测试的PCM数据采用采样率44.1k, 采用精度S16SYS, 通道数2** 函数调…...
[产品管理-6]:NPDP新产品开发 - 4 - 战略 - 创新支持战略,支持组织的总体创新战略(平台战略、技术战略、营销战略、知识产权战略、能力建设战略)
目录 一、创新支持战略概述 二、平台战略:大平台小产品战略 2.1 概述 1、平台战略的定义 2、平台战略的特点 3、平台战略的应用领域 4、平台战略的成功案例 5、平台战略的发展趋势 2.2 大平台小产品战略 1)大平台的建设 2)、小产品…...
Cursor:程序员的AI助手,开启智能编程新时代
在当今快节奏的软件开发世界,效率和准确性是成功的关键。而 Cursor,作为一款创新的人工智能编程工具,正在极大地改变着编程的面貌,为开发者带来前所未有的便捷与惊喜。 智能代码生成 Cursor 利用强大的人工智能模型,…...
OpenAI 刚刚发布了新的Sora视频——实现的真人效果令人惊叹
在 YouTube 上发布了两段由专业创作者制作的新的“Sora Showcase”视频。这些视频展示了尚未发布的 Sora AI 视频模型的惊人潜力。 Sora 于今年二月首次宣布,但由于生成时间、成本和错误信息的潜在风险,光年AI 仅向一小部分创作者 开放了该模型。 自So…...
计算机视觉学习路线
计算机视觉是一门让机器理解和解释视觉世界的科学,它涉及到图像识别、图像处理、模式识别等多个方向。学习计算机视觉的路线通常包括以下几个阶段: 数学和编程基础:需要掌握微积分、线性代数、概率论等数学知识,以及Python或C等编…...
JNPF快速开发平台在企业中的应用
随着数字化转型的浪潮席卷全球,企业纷纷寻求高效、灵活的解决方案以适应快速变化的市场需求。在这一背景下,低代码开发平台应运而生,成为数字经济的“软基建”。今天,我们就来探讨JNPF快速开发平台如何在企业中发挥作用࿰…...
Mysql高级篇(中)—— 索引优化
Mysql高级篇(中)—— 索引优化 一、索引分析案例案例 1:单表查询案例 2:两表连接查询案例 3:三表连接查询 二、避免索引失效常见索引失效场景简述场景 1场景 2场景 3场景 4场景 5场景 6 三、索引优化文字版示例版 一、…...
electron: 将网址打包成exe桌面应用
项目场景: 在项目开发的过程中,需要将应用搭建在不同的硬件上。如需要在一个触屏显示器上展示企业相关的应用。 如果专门去开发一个这样的应用,不划算;这时候考虑将网址打包成exe应用,并安装触屏器上,就可…...
【Python篇】PyQt5 超详细教程——由入门到精通(中篇二)
文章目录 PyQt5超详细教程前言第7部分:生成图表与数据可视化7.1 matplotlib 与 PyQt5 的结合7.2 在 PyQt5 中嵌入 matplotlib 图表示例 1:嵌入简单的 matplotlib 图表代码详解: 7.3 动态生成图表示例 2:动态更新图表代码详解&…...
2024/9/10 小型PLC典型应用1:含步进电机+变频器+触摸屏
主要是讲脉冲控制步进,因为etherCat是标准化的,直接通过轴控指令即可控制;canopen也涉及轴控指令,但配置稍微有点不一样。 控制本体端口的步进,通过发脉冲或者脉冲定位信号。 但这个4PM只有单独的轴控指令,…...
RGB与CMYK互转
先定义一个CMYK数据结构: typedef struct struCMYK {int m_nC;int m_nM;int m_nY;int m_nK; }CMYK;RGB转CMYK void CvtRGB2CMYK(COLORREF& clr, CMYK& cmyk) {double dR GetBValue(clr) / 255.0;double dG GetGValue(clr) / 255.0;double dB GetRValue…...
滴~“TOP期刊体验卡”已到期!公认水刊的尽头,还得是你MDPI
【SciencePub学术】本期,给大家介绍的是1本MDPI旗下的计算机类SCI——《Remote Sensing》。 优点VS缺点 • 期刊分区一直维持在较高水平 • 审稿速度极快,1-2个月录用见刊 • 年刊文量大,收稿多 • 期刊自引率较高 • 期刊系统初筛较难 • …...
ASUS华硕ROG幻16 Air 2024款锐龙AI版GA605WI,GA605WV工厂模式原厂Win11系统,含MyASUS WinRE恢复重置还原功能
适用型号:【GA605WI、GA605WV】,原装出厂Windows11系统工厂包下载 链接:https://pan.baidu.com/s/1IVolLwB7fddGKZY0IxOqaA?pwd62e2 提取码:62e2 华硕原装系统工厂安装包,带有MyASUS WinRE RECOVERY恢复功能、自带…...
想入行在线教育?你必须知道的十件事
在最近几年受新冠疫情和异常天气的影响,越来越多的教育活动被迫转移到线上。然而,在线课程的短板也很明显,大部分在线教育工作者难以有效地引导学生集中注意力,并且无法像线下授课一样进行同步考试。 那么,有什么办法…...
EasyExcel相关整理
一、实体类常用注解 1、字段注解ExcelProperty,一般常用value标明表头,index标明列 2、实体类注解(导出样式设置) 3、导出特殊类型转换 二、导出 1、导出多个sheet 2、导出数据量大导致内存溢出 三、导入 待更新...
2024年【汽车驾驶员(技师)】考试题及汽车驾驶员(技师)找解析
题库来源:安全生产模拟考试一点通公众号小程序 汽车驾驶员(技师)考试题根据新汽车驾驶员(技师)考试大纲要求,安全生产模拟考试一点通将汽车驾驶员(技师)模拟考试试题进行汇编&#…...
[C#学习笔记]接口的特性与用法
视频地址:一期视频看透C#接口的全部特性及用法_哔哩哔哩_bilibili 强烈推荐学习C#和WPF的朋友关注此UP,知识点巨多,讲解透彻! 一、总览 public interface IOverall {/// <summary>/// 最普通的方法/// </summary>v…...
java发送邮件报错,Could not connect to SMTP host: smtp.exmail.qq.com, port: 465
发现问题 我使用的 docker 运行的 jdk 环境,服务调用发送邮件报错 javax.mail.MessagingException: Could not connect to SMTP host: smtp.exmail.qq.com, port: 465;nested exception is:javax.net.ssl.SSLHandshakeException: No appropriate protocol (protoc…...
开放式耳机有哪些好处?性价比排行前十的四款蓝牙耳机推荐
开放式耳机有以下好处: 佩戴舒适:开放式耳机不入耳,不堵塞耳道,长时间佩戴耳朵不易感到闷热和疼痛,相比传统入耳式耳机,能减少对耳道的压迫感和摩擦,让耳朵更舒适。 更健康卫生:不入…...
FreeRTOS(速记版)
第一章 初识 FreeRTOS 1.1 FreeRTOS简介 FreeRTOS 采用了 MIT 开源许可,这允许将 FreeRTOS 操作系统用于商业应用,并且不需要公开源代码。此外,FreeRTOS 还衍生出了另外两个操作系统:OpenRTOS 和 SafeRTOS,其中 OpenR…...
TPS5450同步降压转换器设计:从宽压输入到5V/3.3V输出的工程实践
1. 项目概述与芯片选型考量最近在做一个需要从较高直流电压(比如12V或24V)降压到5V和3.3V为系统供电的项目,电流需求还不小,峰值可能达到3A以上。这种场景下,传统的线性稳压器(LDO)效率太低&…...
win挂载liunx目录
服务器能 SSH 登录时,在 Windows 上把远程目录映射成盘符。 步骤: 安装 WinFsp (https://winfsp.dev/rel/) 安装 SSHFS-Win(或商店版 WinFsp SSHFS)资源管理器地址栏输入,或命令行:…...
CentOS 7服务器部署:NFS共享、Nginx-RTMP流媒体与Qt无GUI环境全攻略
1. 项目概述与核心思路最近在华为云的一台CentOS 7.4 64位服务器版ECS上,完整部署了一套用于音视频处理和后台服务的开发环境。这个环境的核心目标,是为一个需要处理视频流、提供Web服务,并能方便地进行跨机文件共享和Qt程序编译的后台系统打…...
告别复制粘贴:如何在 Cursor / 各种 IDE 中丝滑接入本地 AI 模型?
引言:AI 编程时代的囚徒困境 2026 年,AI 编程助手已经像 Git 一样成为每个开发者的标配。Cursor 的订阅量持续暴涨,GitHub Copilot 的免费版已经吸引了上千万用户,JetBrains 全线 IDE 都深度集成了 AI Agent。但在这个表面繁荣的生态之下,每一位开发者都在不知不觉中交出…...
掌握Simscape Electrical电机控制器设计:减少硬件测试成本60%的专业解决方案
掌握Simscape Electrical电机控制器设计:减少硬件测试成本60%的专业解决方案 【免费下载链接】Design-motor-controllers-with-Simscape-Electrical This repository contains MATLAB and Simulink files used in the "How to design motor controllers using …...
避坑指南:为什么你的mqtt.fx连不上OneNET?Token生成与参数配置的3个关键细节
避坑指南:为什么你的mqtt.fx连不上OneNET?Token生成与参数配置的3个关键细节 当你深夜调试MQTT设备,反复检查代码却依然看到刺眼的"离线"状态时,那种挫败感我深有体会。OneNET作为国内主流物联网平台,其MQTT…...
BUUCTF [ZJCTF 2019]NiZhuanSiWei 通关详解:从PHP伪协议到反序列化的三层渗透
1. 题目初探与源码分析 第一次看到这道题的时候,我盯着屏幕上的PHP源码看了足足五分钟。题目给出了一个简单的PHP文件,要求我们通过三个参数来获取flag。这种层层递进的题目设计在CTF中很常见,但每一步都需要仔细思考。 源码的核心逻辑是这样…...
手把手教你用MP1470芯片设计一个12V转5V的DCDC降压模块(附完整原理图与PCB布局避坑指南)
手把手教你用MP1470芯片设计一个12V转5V的DCDC降压模块(附完整原理图与PCB布局避坑指南) 在嵌入式系统开发中,稳定可靠的电源设计往往是项目成功的关键前提。当我们需要为STM32、ESP32等微控制器或各类传感器供电时,如何将常见的1…...
STM32F103移植FreeRTOS实战:从零构建多任务系统
1. 项目概述:为什么要在STM32F103上跑RTOS? 如果你玩过一阵子STM32,特别是经典的“蓝桥杯”神板——STM32F103C8T6,那你大概率已经习惯了在 main 函数里写一个 while(1) 大循环,里面塞满了各种 HAL_Delay 和状态…...
Unity交通仿真入门:从零到一搭建十字路口红绿灯与车辆AI(附完整C#源码)
Unity交通仿真实战:十字路口红绿灯与车辆AI开发指南 在游戏开发和城市模拟领域,交通仿真一直是个充满挑战又极具实用价值的课题。想象一下,你正站在一个繁忙的十字路口,观察着红绿灯有节奏地变换,车辆井然有序地通过—…...
