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

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

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

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

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

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

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

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

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

    直接上代码,如果有需要可以直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用了(注意将声道和频率与你自己的文件对应哦).当然我自己也用VS2008(VS2013好用太多,强烈推荐还是用V ...

  2. C++ 採集音频流(PCM裸流)实现录音功能

    与上一篇的"C++ 播放音频流(PCM裸流)" 点击打开链接 相相应,本篇是关于用C++实现录音功能的.相同是直接建一个win32控制台程序然后将代码拷过去改个文件名称就能够用,也 ...

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

    与上一篇的“C++ 播放音频流(PCM裸流)” 点击打开链接 相对应,本篇是关于用C++实现录音功能的.同样是直接建一个win32控制台程序然后将代码拷过去改个文件名就可以用,也可以下载本人上传的相关 ...

  4. 全志Tina_dolphin播放音视频裸流(h264,pcm)验证

    最近在验证tina对裸流音视频的支持,主要指h264视频裸流及pcm音频裸流. 在原始sdk中有针对很多video和audio类型的parser,但就是没有找到pcm和h264的parser,所以需要 ...

  5. ffplay播放PCM裸流

    ffplay -f s16le -ar 48000 -ac 2 d:\lei.pcm

  6. ffmpeg学习(二) 通过rtsp获取H264裸流并保存到mp4文件

    本篇将使用上节http://www.cnblogs.com/wenjingu/p/3977015.html中编译好的库文件通过rtsp获取网络上的h264裸流并保存到mp4文件中. 1.VS2010建 ...

  7. 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

    既然已经可以通过 RTSP 获取h264 裸流了.那么通过 FFmpeg 将其保存到文件中怎么做呢? 一.首先RTSP获取 h264 裸流 我们上面两篇文章主要讲的是通过 rtsp://Your ip ...

  8. H264裸流分析中,能获取哪些信息?

    从H264的裸流中,PPS,SPS中,一定可以获取到的,有图像的宽,高信息. 这部分信息的提取,用Stream eye 分析: 这里需要特别提一下这两个参数:  pic_width_in_mbs_mi ...

  9. 【嵌入式开发】用 VLC 显示 树莓派摄像头 H264 裸流

    首先树莓派连上网络,并和电脑在同一网段. 树莓派的IP是: 192.168.3.13 电脑的IP是: 192.168.3.6 1.在树莓派上采集 H264裸流,并用UDP发送到电脑. pi@Neil- ...

随机推荐

  1. Flask错误收集 【转】

    感谢大佬 ---> 原文链接 一.pydev debugger: process XXXXX is connecting 这个错误网上找了很多资料都无法解决,尝试过多种方法后,对我来说,下面这个 ...

  2. Servlet过滤器---简介

    过滤器的基本概念 Servlet过滤器从字面上的字意理解为经过一层次的过滤处理才达到使用的要求,而其实Servlet过滤器就是服务器与客户端请求与响应的中间层组件,在实际项目开发中Servlet过滤器 ...

  3. [Django]我的第一个网页,报错啦~(自己实现过程中遇到问题以及解决办法)

    环境配置: python :2.7.13 django:1.10.5 OS:Win7(64位)& Centos7 问题描述  解决办法   global name 'render' is no ...

  4. 1 Django初探

    1.理解MTV request 向服务器请求 response发送数据给用户 M:数据库取出数据 T: 模板渲染 V:渲染好的网页返回给用户 URL找到特定的views 2.创建django项目 (1 ...

  5. error: unknown host service 的详细解决办法

    问题情况描述: 有时候,你在cmd 窗口 adb shell 的时候,出现error: unknown host service. 问题解决办法: 这就要怪可恶的360手机助手了,你在任务管理器里面把 ...

  6. 使用Matrix-tree与它的行列式来解决生成树计数问题

    我又把Matrix写错啦 这东西讲课的时候竟然一笔带过了,淦 好吧这东西我不会证 那我们来愉快的看结论吧 啦啦啦 预备工作 你有一个 $ n $ 个点的图 比如说 5 /|\ / | \ 2--1-- ...

  7. 剑指Offer - 九度1506 - 求1+2+3+...+n

    剑指Offer - 九度1506 - 求1+2+3+...+n2013-11-29 19:22 题目描述: 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switc ...

  8. DOS程序员手册(九)

    第14章参考手册概述     本书余下的章节将向读者们介绍BIOS.DOS各种各样API函数和服务,作为一名程 序员,了解和掌握这些知识是很有好处的.在所介绍的参考手册中,每部手册都汇集了大 量的资源 ...

  9. python学习笔记四:lambda表达式和switch

    一.定义 lambda arg1,arg2... : returnValue 二.示例 #!/usr/bin/python def f(x,y): return x*y print f(2,3) g ...

  10. 【多线程学习(1)】创建java多线程

    1)java多线程的创建方式有三种: 1.继承Thread类 2.实现Runnable接口 3.实现Callable接口 第一种: //继承Thread类 class ExtendsThread ex ...