C++ 播放音频流(PCM裸流)--改善
直接上代码,如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了(注意将声道和频率与你自己的文件对应)。当然我自己也用VS2008写了个例子上传了,如果有需要下载地址如下:点击打开链接。
这份代码是打开文件截取一段数据然后播放的,可以轻松的经过加一条线程的方式改成网络传输的形式,但经过本人测试,因为没有缓存机制会有“哒哒”的噪声,也就是说这份代码在网络实时音频上的表现并不太好。为了解决这个问题,可以加上缓存机制,本人因为一开始用的是事件响应方式,所以一直困在这个框架里,不能很好的利用缓存的机制解决上面提到的问题,后来尝试了用回调函数的方式来响应数据播放完成的消息,问题就轻松的解决了。那部分的代码会在稍候放上去。
- #include "stdafx.h"
- #include <stdio.h>
- #include <Windows.h>
- #pragma comment(lib, "winmm.lib")
- char buf[1024 * 1024 * 4];
- int _tmain(int argc, _TCHAR* argv[]) {
- FILE* thbgm;//文件
- int cnt;
- HWAVEOUT hwo;
- WAVEHDR wh;
- WAVEFORMATEX wfx;
- HANDLE wait;
- wfx.wFormatTag = WAVE_FORMAT_PCM;//设置波形声音的格式
- wfx.nChannels = 1;//设置音频文件的通道数量
- wfx.nSamplesPerSec = 8000;//设置每个声道播放和记录时的样本频率
- wfx.nAvgBytesPerSec = 16000;//设置请求的平均数据传输率,单位byte/s。这个值对于创建缓冲大小是很有用的
- wfx.nBlockAlign = 2;//以字节为单位设置块对齐
- wfx.wBitsPerSample = 16;
- wfx.cbSize = 0;//额外信息的大小
- wait = CreateEvent(NULL, 0, 0, NULL);
- waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD_PTR)wait, 0L, CALLBACK_EVENT);//打开一个给定的波形音频输出装置来进行回放
- fopen_s(&thbgm, "paomo.pcm", "rb");
- cnt = fread(buf, sizeof(char), 1024 * 1024 * 4, thbgm);//读取文件4M的数据到内存来进行播放,通过这个部分的修改,增加线程可变成网络音频数据的实时传输。当然如果希望播放完整的音频文件,也是要在这里稍微改一改
- int dolenght = 0;
- int playsize = 1024;
- while (cnt) {//这一部分需要特别注意的是在循环回来之后不能花太长的时间去做读取数据之类的工作,不然在每个循环的间隙会有“哒哒”的噪音
- wh.lpData = buf + dolenght;
- wh.dwBufferLength = playsize;
- wh.dwFlags = 0L;
- wh.dwLoops = 1L;
- waveOutPrepareHeader(hwo, &wh, sizeof(WAVEHDR));//准备一个波形数据块用于播放
- waveOutWrite(hwo, &wh, sizeof(WAVEHDR));//在音频媒体中播放第二个函数wh指定的数据
- WaitForSingleObject(wait, INFINITE);//用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的INFINITE毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回
- dolenght = dolenght + playsize;
- cnt = cnt - playsize;
- }
- waveOutClose(hwo);
- fclose(thbgm);
- return 0;
- }
离写上面部分已经过了快一年,现在回看之前写的代码感觉略为坑爹,或许是进步了吧。之前说要把双缓存的代码放出来,哪知道后来忙别的项目去了,这部分就丢到一边,去老项目中提取代码感觉好烦一直没弄。在这一年中不少人发私信问我关于这部分代码如何写的事,没想到现在做音频的人还真不少呢。Ok,既然挖了坑就要填,今天乘着周末写了一个双缓存的Demo工程,代码如下:
- #include <stdio.h>
- #include <Windows.h>
- #pragma comment(lib, "winmm.lib")
- #define DATASIZE 1024*512 //分次截取数据大小
- FILE* pcmfile; //音频文件
- HWAVEOUT hwo;
- void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance, DWORD dw1, DWORD dw2)//回调函数
- {
- switch (uMsg)
- {
- case WOM_DONE://上次缓存播放完成,触发该事件
- {
- LPWAVEHDR pWaveHeader = (LPWAVEHDR)dw1;
- pWaveHeader->dwBufferLength = fread(pWaveHeader->lpData, 1, DATASIZE, pcmfile);;
- waveOutPrepareHeader(hwo, pWaveHeader, sizeof(WAVEHDR));
- waveOutWrite(hwo, pWaveHeader, sizeof(WAVEHDR));
- break;
- }
- }
- }
- void main()
- {
- int cnt;
- WAVEHDR wh1;
- WAVEHDR wh2;
- WAVEFORMATEX wfx;
- fopen_s(&pcmfile, "paomo.pcm", "rb");//打开文件
- wfx.wFormatTag = WAVE_FORMAT_PCM;//设置波形声音的格式
- wfx.nChannels = 1;//设置音频文件的通道数量
- wfx.nSamplesPerSec = 8000;//设置每个声道播放和记录时的样本频率
- wfx.nAvgBytesPerSec = 16000;//设置请求的平均数据传输率,单位byte/s。这个值对于创建缓冲大小是很有用的
- wfx.nBlockAlign = 2;//以字节为单位设置块对齐
- wfx.wBitsPerSample = 16;
- wfx.cbSize = 0;//额外信息的大小
- waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD)WaveCallback, 0L, CALLBACK_FUNCTION);//打开一个给定的波形音频输出装置来进行声音播放,方式为回调函数方式。如果是对话框程序,可以将第五个参数改为(DWORD)this,操作跟本Demo程序相似
- wh1.dwLoops = 0L;//播放区一
- wh1.lpData = new char[DATASIZE];
- wh1.dwBufferLength = DATASIZE;
- fread(wh1.lpData, 1, DATASIZE, pcmfile);
- wh1.dwFlags = 0L;
- waveOutPrepareHeader(hwo, &wh1, sizeof(WAVEHDR));//准备一个波形数据块用于播放
- waveOutWrite(hwo, &wh1, sizeof(WAVEHDR));//在音频媒体中播放第二个参数指定的数据,也相当于开启一个播放区的意思
- wh2.dwLoops = 0L;//播放区二,基本同上
- wh2.lpData = new char[DATASIZE];
- wh2.dwBufferLength = DATASIZE;
- fread(wh2.lpData, 1, DATASIZE, pcmfile);
- wh2.dwFlags = 0L;
- waveOutPrepareHeader(hwo, &wh2, sizeof(WAVEHDR));
- waveOutWrite(hwo, &wh2, sizeof(WAVEHDR));
- while (wh1.dwBufferLength != 0 || wh2.dwBufferLength != 0)//如果文件还在没播放完则等待500ms
- {
- Sleep(500);
- }
- waveOutUnprepareHeader(hwo, &wh1, sizeof(WAVEHDR));//清理数据
- waveOutUnprepareHeader(hwo, &wh2, sizeof(WAVEHDR));
- delete []wh1.lpData;
- delete []wh2.lpData;
- fclose(pcmfile);//关闭文件
- return;
- }
同上面一样,如果想要这个工程的可以到这个链接去下载。不过提醒下,本人已然抛弃了VS2008,直接用VS2013,如果还在用老平台的话要用还是要折腾一会的。
from:http://blog.csdn.net/weixinhum/article/details/29943973?utm_source=tuicool&utm_medium=referral
C++ 播放音频流(PCM裸流)--改善的更多相关文章
- C++ 播放音频流(PCM裸流)
直接上代码,如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了(注意将声道和频率与你自己的文件对应哦).当然我自己也用VS2008(VS2013好用太多,强烈推荐还是用V ...
- C++ 採集音频流(PCM裸流)实现录音功能
与上一篇的"C++ 播放音频流(PCM裸流)" 点击打开链接 相相应,本篇是关于用C++实现录音功能的.相同是直接建一个win32控制台程序然后将代码拷过去改个文件名称就能够用,也 ...
- C++ 采集音频流(PCM裸流)实现录音功能
与上一篇的“C++ 播放音频流(PCM裸流)” 点击打开链接 相对应,本篇是关于用C++实现录音功能的.同样是直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用,也可以下载本人上传的相关 ...
- 全志Tina_dolphin播放音视频裸流(h264,pcm)验证
最近在验证tina对裸流音视频的支持,主要指h264视频裸流及pcm音频裸流. 在原始sdk中有针对很多video和audio类型的parser,但就是没有找到pcm和h264的parser,所以需要 ...
- ffplay播放PCM裸流
ffplay -f s16le -ar 48000 -ac 2 d:\lei.pcm
- ffmpeg学习(二) 通过rtsp获取H264裸流并保存到mp4文件
本篇将使用上节http://www.cnblogs.com/wenjingu/p/3977015.html中编译好的库文件通过rtsp获取网络上的h264裸流并保存到mp4文件中. 1.VS2010建 ...
- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中
既然已经可以通过 RTSP 获取h264 裸流了.那么通过 FFmpeg 将其保存到文件中怎么做呢? 一.首先RTSP获取 h264 裸流 我们上面两篇文章主要讲的是通过 rtsp://Your ip ...
- H264裸流分析中,能获取哪些信息?
从H264的裸流中,PPS,SPS中,一定可以获取到的,有图像的宽,高信息. 这部分信息的提取,用Stream eye 分析: 这里需要特别提一下这两个参数: pic_width_in_mbs_mi ...
- 【嵌入式开发】用 VLC 显示 树莓派摄像头 H264 裸流
首先树莓派连上网络,并和电脑在同一网段. 树莓派的IP是: 192.168.3.13 电脑的IP是: 192.168.3.6 1.在树莓派上采集 H264裸流,并用UDP发送到电脑. pi@Neil- ...
随机推荐
- 集合源码分析之 HashSet
一 知识准备 HashSet 是Set接口的实现类,Set存在的最大意义区别于List就是,Set中存放的元素不能够重复,就是不能够有两个相同的元素存放在Set中,那么怎样的两个元素才算是相同的,这里 ...
- Androd安全——混淆技术完全解析
.前言 在上一篇Androd安全--反编译技术完全解析中介绍了反编译方面的知识,因此我们认识到为了安全我们需要对代码进行混淆. 混淆代码并不是让代码无法被反编译,而是将代码中的类.方法.变量等信息进行 ...
- [bzoj3450]Tyvj1952Easy
瓜皮期望真是弱成渣.. 完全不理解的感觉qwq...题面%了一发千古神犇WJMZBMR哈~ Description 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(我们来简化 ...
- Windows下使用Nginx+tomcat配置负载均衡
Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.由俄罗斯的程序设计师Igor Sysoev所开发,供俄国大型的入口 ...
- Android通过用代码画虚线椭圆边框背景来学习一下shape的用法
在Android程序开发中,我们经常会去用到Shape这个东西去定义各种各样的形状,shape可以绘制矩形环形以及椭圆,所以只需要用椭圆即可,在使用的时候将控件比如imageview或textview ...
- 利用jsoup抓取网页图片
jsoup简介 jsoup is a Java library for working with real-world HTML. It provides a very convenient API ...
- HDU 3887 Counting Offspring (树状数组+人工模拟栈)
对这棵树DFS遍历一遍,同一节点入栈和出栈之间访问的节点就是这个节点的子树. 因此节点入栈时求一次 小于 i 的节点个数 和,出栈时求一次 小于 i 的节点个数 和,两次之差就是答案. PS.这题直接 ...
- beta版本前准备
目录 过去存在的问题 任务分工 开发规范 后端总结 卉卉 家灿 前端总结 绪佩 青元 恺琳 宇恒 丹丹 算法&API接口 家伟 鸿杰 一好 文档&博客撰写 政演 产品功能 我们已经做了 ...
- 团队Alpha版本(九)
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...
- 【DNS】DNS的几个基本概念
一. 根域 就是所谓的“.”,其实我们的网址www.baidu.com在配置当中应该是www.baidu.com.(最后有一点),一般我们在浏览器里输入时会省略后面的点,而这也已经成为了习惯. 根域服 ...