C++ 播放音频流(PCM裸流)--改善

直接上代码,如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了(注意将声道和频率与你自己的文件对应)。当然我自己也用VS2008写了个例子上传了,如果有需要下载地址如下:点击打开链接

    这份代码是打开文件截取一段数据然后播放的,可以轻松的经过加一条线程的方式改成网络传输的形式,但经过本人测试,因为没有缓存机制会有“哒哒”的噪声,也就是说这份代码在网络实时音频上的表现并不太好。为了解决这个问题,可以加上缓存机制,本人因为一开始用的是事件响应方式,所以一直困在这个框架里,不能很好的利用缓存的机制解决上面提到的问题,后来尝试了用回调函数的方式来响应数据播放完成的消息,问题就轻松的解决了。那部分的代码会在稍候放上去。

 

[cpp] view plain copy

 

  1. #include "stdafx.h"  
  2. #include <stdio.h>  
  3. #include <Windows.h>  
  4. #pragma comment(lib, "winmm.lib")  
  5.   
  6. char buf[1024 * 1024 * 4];  
  7.   
  8. int _tmain(int argc, _TCHAR* argv[]) {  
  9.     FILE*           thbgm;//文件  
  10.     int             cnt;  
  11.     HWAVEOUT        hwo;  
  12.     WAVEHDR         wh;  
  13.     WAVEFORMATEX    wfx;  
  14.     HANDLE          wait;  
  15.   
  16.     wfx.wFormatTag = WAVE_FORMAT_PCM;//设置波形声音的格式  
  17.     wfx.nChannels = 1;//设置音频文件的通道数量  
  18.     wfx.nSamplesPerSec = 8000;//设置每个声道播放和记录时的样本频率  
  19.     wfx.nAvgBytesPerSec = 16000;//设置请求的平均数据传输率,单位byte/s。这个值对于创建缓冲大小是很有用的  
  20.     wfx.nBlockAlign = 2;//以字节为单位设置块对齐  
  21.     wfx.wBitsPerSample = 16;  
  22.     wfx.cbSize = 0;//额外信息的大小  
  23.     wait = CreateEvent(NULL, 0, 0, NULL);  
  24.     waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD_PTR)wait, 0L, CALLBACK_EVENT);//打开一个给定的波形音频输出装置来进行回放  
  25.     fopen_s(&thbgm, "paomo.pcm", "rb");  
  26.     cnt = fread(buf, sizeof(char), 1024 * 1024 * 4, thbgm);//读取文件4M的数据到内存来进行播放,通过这个部分的修改,增加线程可变成网络音频数据的实时传输。当然如果希望播放完整的音频文件,也是要在这里稍微改一改  
  27.     int dolenght = 0;  
  28.     int playsize = 1024;  
  29.     while (cnt) {//这一部分需要特别注意的是在循环回来之后不能花太长的时间去做读取数据之类的工作,不然在每个循环的间隙会有“哒哒”的噪音  
  30.         wh.lpData = buf + dolenght;  
  31.         wh.dwBufferLength = playsize;  
  32.         wh.dwFlags = 0L;  
  33.         wh.dwLoops = 1L;  
  34.         waveOutPrepareHeader(hwo, &wh, sizeof(WAVEHDR));//准备一个波形数据块用于播放  
  35.         waveOutWrite(hwo, &wh, sizeof(WAVEHDR));//在音频媒体中播放第二个函数wh指定的数据  
  36.         WaitForSingleObject(wait, INFINITE);//用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的INFINITE毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回  
  37.         dolenght = dolenght + playsize;  
  38.         cnt = cnt - playsize;  
  39.     }  
  40.     waveOutClose(hwo);  
  41.     fclose(thbgm);  
  42.     return 0;  
  43. }  

 

    离写上面部分已经过了快一年,现在回看之前写的代码感觉略为坑爹,或许是进步了吧。之前说要把双缓存的代码放出来,哪知道后来忙别的项目去了,这部分就丢到一边,去老项目中提取代码感觉好烦一直没弄。在这一年中不少人发私信问我关于这部分代码如何写的事,没想到现在做音频的人还真不少呢。Ok,既然挖了坑就要填,今天乘着周末写了一个双缓存的Demo工程,代码如下:

 

[cpp] view plain copy

 

  1. #include <stdio.h>  
  2. #include <Windows.h>  
  3.   
  4. #pragma comment(lib, "winmm.lib")  
  5.   
  6. #define DATASIZE 1024*512 //分次截取数据大小  
  7. FILE*           pcmfile;  //音频文件  
  8. HWAVEOUT        hwo;  
  9.   
  10. void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance, DWORD dw1, DWORD dw2)//回调函数  
  11. {  
  12.     switch (uMsg)  
  13.     {  
  14.         case WOM_DONE://上次缓存播放完成,触发该事件  
  15.         {  
  16.             LPWAVEHDR pWaveHeader = (LPWAVEHDR)dw1;  
  17.             pWaveHeader->dwBufferLength = fread(pWaveHeader->lpData, 1, DATASIZE, pcmfile);;  
  18.             waveOutPrepareHeader(hwo, pWaveHeader, sizeof(WAVEHDR));  
  19.             waveOutWrite(hwo, pWaveHeader, sizeof(WAVEHDR));  
  20.             break;  
  21.         }  
  22.     }  
  23. }  
  24.   
  25. void main()   
  26. {  
  27.     int             cnt;  
  28.     WAVEHDR         wh1;  
  29.     WAVEHDR         wh2;  
  30.     WAVEFORMATEX    wfx;  
  31.   
  32.     fopen_s(&pcmfile, "paomo.pcm", "rb");//打开文件  
  33.   
  34.     wfx.wFormatTag = WAVE_FORMAT_PCM;//设置波形声音的格式  
  35.     wfx.nChannels = 1;//设置音频文件的通道数量  
  36.     wfx.nSamplesPerSec = 8000;//设置每个声道播放和记录时的样本频率  
  37.     wfx.nAvgBytesPerSec = 16000;//设置请求的平均数据传输率,单位byte/s。这个值对于创建缓冲大小是很有用的  
  38.     wfx.nBlockAlign = 2;//以字节为单位设置块对齐  
  39.     wfx.wBitsPerSample = 16;  
  40.     wfx.cbSize = 0;//额外信息的大小  
  41.   
  42.     waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD)WaveCallback, 0L, CALLBACK_FUNCTION);//打开一个给定的波形音频输出装置来进行声音播放,方式为回调函数方式。如果是对话框程序,可以将第五个参数改为(DWORD)this,操作跟本Demo程序相似  
  43.   
  44.     wh1.dwLoops = 0L;//播放区一  
  45.     wh1.lpData = new char[DATASIZE];  
  46.     wh1.dwBufferLength = DATASIZE;   
  47.     fread(wh1.lpData, 1, DATASIZE, pcmfile);  
  48.     wh1.dwFlags = 0L;  
  49.     waveOutPrepareHeader(hwo, &wh1, sizeof(WAVEHDR));//准备一个波形数据块用于播放  
  50.     waveOutWrite(hwo, &wh1, sizeof(WAVEHDR));//在音频媒体中播放第二个参数指定的数据,也相当于开启一个播放区的意思  
  51.   
  52.     wh2.dwLoops = 0L;//播放区二,基本同上  
  53.     wh2.lpData = new char[DATASIZE];  
  54.     wh2.dwBufferLength = DATASIZE;  
  55.     fread(wh2.lpData, 1, DATASIZE, pcmfile);  
  56.     wh2.dwFlags = 0L;  
  57.     waveOutPrepareHeader(hwo, &wh2, sizeof(WAVEHDR));  
  58.     waveOutWrite(hwo, &wh2, sizeof(WAVEHDR));  
  59.   
  60.     while (wh1.dwBufferLength != 0 || wh2.dwBufferLength != 0)//如果文件还在没播放完则等待500ms  
  61.     {  
  62.         Sleep(500);  
  63.     }  
  64.     waveOutUnprepareHeader(hwo, &wh1, sizeof(WAVEHDR));//清理数据  
  65.     waveOutUnprepareHeader(hwo, &wh2, sizeof(WAVEHDR));  
  66.   
  67.     delete []wh1.lpData;  
  68.     delete []wh2.lpData;  
  69.     fclose(pcmfile);//关闭文件  
  70.     return;  
  71. }  

    同上面一样,如果想要这个工程的可以到这个链接去下载。不过提醒下,本人已然抛弃了VS2008,直接用VS2013,如果还在用老平台的话要用还是要折腾一会的。

 

from:http://blog.csdn.net/weixinhum/article/details/29943973?utm_source=tuicool&utm_medium=referral

时间: 2024-10-31 12:33:59

C++ 播放音频流(PCM裸流)--改善的相关文章

C++ 播放音频流(PCM裸流)

直接上代码,如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了(注意将声道和频率与你自己的文件对应哦).当然我自己也用VS2008(VS2013好用太多,强烈推荐还是用VS2013,只是它的工程太大,上传起来相当费劲,所以还是用VS2008重写了..)写了个例子上传了,如果有需要下载地址如下(自己没什么下载分了,所以弄了3分,见谅哈哈):点击打开链接 这份代码是打开文件截取一段数据然后播放的,可以轻松的经过加一条线程的方式改成网络传输的形式.  #include "

C++ 采集音频流(PCM裸流)实现录音功能

与上一篇的"C++ 播放音频流(PCM裸流)" 点击打开链接 相对应,本篇是关于用C++实现录音功能的.同样是直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用,也可以下载本人上传的相关工程,这个工程是用VS2013写的,如果是较低的版本就呵呵了.点击打开链接 代码部分如下:   [cpp] view plain copy   #include "stdafx.h"   #include <stdio.h>     #include <

sdp-TS裸流以每次188个字节通过RTP的方式发送给VLC合理吗?为什么VLC播放不了?

问题描述 TS裸流以每次188个字节通过RTP的方式发送给VLC合理吗?为什么VLC播放不了? 这是我的sdp文件,请大神帮我看看我的sdp文件是否正确? v=2 t=0 0 m=video 9400 RTP/AVP 96 a=rtpmap:96 MP2T a=framerate:25 c=IN IP4 10.1.1.117 解决方案 188个字节太小了,设置大一些看看.

视频-基于UDP的h264实时裸流播放

问题描述 基于UDP的h264实时裸流播放 本人想用<最简单的基于FFmpeg的解码器-纯净版>该项目中的解码器直接解码socket到的h264裸流,请问可以吗???该项目是解码本地文件视频的一个简单的播放器,可解码h264裸流.我想把socket到的裸流直接喂给里面的解码器. 解决方案 http://blog.csdn.net/wxl1986622/article/details/37835935

视音频同步推送-是否有视音频裸流一起推送的例子?

问题描述 是否有视音频裸流一起推送的例子? SRS设计理念真好,我们很喜欢. 文章中给出单独推送H.264 及AAC裸流的例子,是否有视音频裸流一起推送的例子?因为实际中大多是视音频一起的. 解决方案 http://download.csdn.net/detail/ganhuanghuang/4984256 解决方案二: 谢谢! 我需要的是视音频裸码流同步推送,你推荐的是"SDL播放PCM音频裸流",不是一回事.

在ubuntu下通过RTP(tcp)的方式往window发送h264裸流,VLC接收问题

问题描述 在ubuntu下通过RTP(tcp)的方式往window发送h264裸流,VLC接收问题 在ubuntu下通过RTP(tcp)的方式往window发送h264裸流,用VLC打开SDP文件的方式为什么接不到数据?在windows下发给自己就可以接收到数据,能播放

surface-android mediaPlayer播放标清ts流是4:3的比例显示的

问题描述 android mediaPlayer播放标清ts流是4:3的比例显示的 5C 如题,现在使用surfaceView+mediaPlayer播放标清ts流,在机顶盒上视频是以4:3的比例显示,全屏的时候左右两端有一块黑屏,无法全屏显示:请问下如何设置使视频能够以16:9的比例显示.我用了mSurfaceHolder.setFixedSize(surfaceHeight surfaceWidth)方法设置surface的大小,还是没用 解决方案 好烦啊,用videoView也是一样不会全

计算音频帧的播放时间(音频码流 音频帧)

音频码流(冗余数据占的比例):先简单讲一下对于ADTS header的结构的理解: 1)ADTS header位于每一个aac帧的开头,长度一般是7字节(也可以是9字节的,没见过). 2)每个aac帧的长度固定为1024个sample(可以是1024*n,没见过n>1的情况). 3)ADTS header中大部分信息无用,有用的只有采样率(4bit).声道数(3bit)和帧的大小(13bit),这三项总共只有20bit. mp4格式会集中存放每一个frame的index,每个index占4个字节

(100)C# 实现播放RTSP 标准协议码流播放。录制 ==在线等

问题描述 RT,有没有这方面的源码或者控件,谢谢各位大侠了... 解决方案 解决方案二:该回复于2014-10-12 22:58:48被版主删除解决方案三:这种标准化的流媒体读取方式肯定是可以实现的不过想要免费的下载或者代码的可能性不大都是需要收费的解决方案四:http://www.codeproject.com/Articles/507218/Managed-Media-Aggregation-using-Rtsp-and-Rtphttp://www.streamcoders.com/http