找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1806|回复: 0
打印 上一主题 下一主题
收起左侧

音频格式细节

[复制链接]
跳转到指定楼层
楼主
ID:107189 发表于 2016-3-5 17:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

几个格式细节备记(混)

typedef struct  _MediaType {
    GUID      majortype;  
    GUID      subtype;
    BOOL      bFixedSizeSamples;
    BOOL      bTemporalCompression;
    ULONG     lSampleSize;
    GUID      formattype;
    IUnknown  *pUnk;                  //not use
    ULONG     cbFormat;
    BYTE *pbFormat;
} AM_MEDIA_TYPE;
主要有
   majortype  媒体类型大致说明
   subtype    更一步的细致说明
   formattype  
      包括有以下:其对应的不同的数据格式
       FORMAT_None
       FORMAT_DvInfo
       FORMAT_MPEGVideo
       FORMAT_MPEG2Video
       FORMAT_VideoInfo
       FORMAT_VideoInfo2  
       FORMAT_WaveFormatEx   
       GUID_NULL
  cbForamt成员指定了格式块pbFormat的大小.
  pbFormat指针指向格式子块。
            pbFormat是一个void*的指针,因为格式块会因为媒体类型
            的不同而有不同的指向。如音频填充的是WAVEFORMATEX结构
     数据.
     可以从中取出传来的数据格式。
     

//TWaveFormatEx 结构:
TWaveFormatEx = packed record
  wFormatTag: Word;       {指定格式类型; 默认 WAVE_FORMAT_PCM = 1;}
  nChannels: Word;        {指出波形数据的通道数; 单声道为 1, 立体声为 2}
  nSamplesPerSec: DWORD;  {指定样本速率(每秒的样本数)}一般为8000
  nAvgBytesPerSec: DWORD; {指定数据传输的平均速率(每秒的字节数)} 每秒的字节数:
  nBlockAlign: Word;      {指定块对齐(单位字节), 块对齐是数据的最小单位}
  wBitsPerSample: Word;   {采样大小(字节)}每个样本的BIT数目,一般为16
  cbSize: Word;           {应该是该结构的大小}
end;
nChannels       :   对于pcm,其nchannels不超过2,对于非pcm格式,则超过2.
nSamplesPerSec  :   通常为8kHz, 11.025 kHz, 22.05 kHz, and 44.1 kHz.
nAvgBytesPerSec :   每秒传送字节数 = nSamplesPerSec * nBlockAlign
nBlockAlign     :   对齐字节  = nChannels * wBitsPerSample / 8
                    就是表示一个样本的最小字节.
wBitsPerSample  :   在格式默认情况下,一般为8,16,表示的是样本的bit 数
对于一个8位,11k传输的立体声则
nChannels  = 2
nSamplesPerSec(每秒的样本数) = 11025  就是取样数
nBlockAlign  = 2 * 8 / 8= 2           对齐字节,最小样本字节数
nAvgBytesPerSec = 11025 *  2 = 22050
wBitsPerSample  = 8

下面的图列清楚从另一个方面表达样本

样本1 样本2...n
8位单声道0声道0声道
8位立体声0声道L         1声道R 0声道L  1声R道
16位单声道0声道(低字节)    0声道(高字节)0声道(低字节)    0声道(高字节)
16位立体声
0声道(低字节)0声道(高字节)1声道(低) 1声道(高)
同左
                                                                                                                     
                                       
                                    
---------
waveform-audio 缓存格式      
  typedef   struct   {     
          LPSTR     lpData;           //内存指针,放置音频pcm样本数据
          DWORD     dwBufferLength;   //长度     
          DWORD     dwBytesRecorded;  //已录音的字节长度   
          DWORD     dwUser;     
          DWORD     dwFlags;     
          DWORD     dwLoops;           //循环次数   
          struct   wavehdr_tag* lpNext; //保留     
          DWORD     reserved;           //保留
  }   WAVEHDR;  

  其中lpdata 即为pcm格式样本数据。
  
采样大小为8位,则采样的动态范围为20*log(256)分贝=48db。
样本大小为16位,则采样动态范围为20*log(65536)大约是96分贝
振幅大小:   20*log(A1/A2)分贝,A1,A2为两个声音的振幅。
则对于的音频:
          8位       20 * lg( lpData[0] /256)
   16位      20 * lg( lpData[0]--lpData[1] / 65536)
考虑到单双道,还需要相应取出左右声道的值。
考虑到lg求值为负48至0之间,则在实际转换中需要+48or96.

样本大小  数据格式      最大值  最小值
8位PCM    unsigned int   256     0
16位PCM   int            32767  -32767
8位音频是unsigned 存放波形,取振幅要-127.
而16位因其存放为int 类型,直接套用公式.


audiometer左右声道音量探测程序(参考代码(delphi版)

posted @ 2009-01-05 14:16 kenlistian 阅读(274) | 评论 (0) | 编辑 收藏

2008年12月28日 #
可播放rm,rmvb格式播放器的方法
RealMediaSplitter.ax

Source(.rm/.rmvb)->RealMediaSplitter->Video(Audio)->real a/v decoder->A/V   Render

其实复原并查找该ax很简单,安装暴风后在graphedit中,拖一个rm文件,
查看解码过程,然后在filter列表中找出该ax文件名,即可构建到自己的
播放器中。
posted @ 2008-12-28 11:21 kenlistian| 编辑 收藏


2008年12月27日 #
directsound的一些基本札记
1、配置DirectDound的开发环境
包含以下
#include <mmsystem.h>
#include <dsound.h>
添加Dsound.lib库
comctl32.lib dxerr9.lib winmm.lib dsound.lib dxguid.lib odbc32.lib odbccp32.lib,
2 DiectDound几个对象

  创建一个设备对象,后通过设备对象创建缓冲区对象。
  辅助缓冲区由应用程序创建和管理,DirectSound会自动地创建和管理主缓冲区,

3 播放音频文件开发的基本流程
 a 创建一个设备对象,设置设备对象的协作度。
    调用DirectSoundCreat8创建一个支持IDirectSound8接口的对象,
      这个对象通常代表缺省的播放设备。
   
       如果没有声音输出设备,这个函数就返回error,或者,在VXD驱动程序下,
      如果声音输出设备正被某个应用程序通过waveform格式的api函数所控制,
      该函数也返回error。
LPDIRECTSOUND8 lpDirectSound;
HRESULT hr
= DirectSoundCreate8(NULL,&lpDirectSound, NULL));

      当创建完设备对象后,调用IDirectSound8::SetCooperativeLevel来设置
      协作度,否则听不到声音.

  b.创建一个辅助Buffer,也叫后备缓冲区
      (IDirectSound8::CreateSoundBuffer)
      创建的buffer称作辅助缓冲区,Direcsound通过把几个后备缓冲区的声音
      混合到主缓冲区中,然后输出到声音输出设备上,达到混音的效果。
  c. 获取PCM类型的数据
   
  将WAV文件或者其他资源的数据读取到缓冲区中。
  d. 将数据读取到缓冲区
       其中用到以下来锁缓冲区。
          IDirectSoundBuffer8::Lock
          IDirectSoundBuffer8::Unlock.
  e. 播放缓冲区中的数据
       IDirectSoundBuffer8::Play  播放缓冲区中的音频数据,
       IDirectSoundBuffer8::Stop 暂停播放数据,
      
       获取或者设置正在播放的音频的音量的大小
   IDirectSoundBuffer8::GetVolume
         IDirectSoundBuffer8::SetVolume
      获取设置音频播放的频率
    IDirectSoundBuffer8::GetFrequency
         IDirectSoundBuffer8::SetFrequency   
              主缓冲区的频率不允许改动,
      设置音频在左右声道播放的位置
          IDirectSoundBuffer8::GetPan
          IDirectSoundBuffer8::SetPan
  包含全部音频数据的缓冲区我们称为静态的缓冲区,
        尽管不同的声音可能会反复使用同一个内存buffer,但静态缓冲区的数据只写入一次。
        静态缓冲区只填充一次数据,然后就可以play,

 给静态缓冲区加载数据分下面几个步骤
  1、用IDirectSoundBuffer8::Lock函数来锁定所有的内存,
            指定你锁定内存中你开始写入数据的偏移位置,并且取回该偏移位置的地址。
  2、采用标准的数据copy方法,将音频数据复制到返回的地址。
  3、调用IDirectSoundBuffer8::Unlock.,解锁该地址。

用static buffer 播放wav方法


LPDIRECTSOUNDBUFFER8    g_pDSBuffer8 = NULL; //buffer
LPDIRECTSOUND8                   g_pDsd = NULL; //dsound
CWaveFile                                   *g_pWaveFile= NULL;

//初始化DirectSound工作
HRESULT hr;
if(FAILED(hr = DirectSoundCreate8(NULL,&g_pDsd,NULL)))
 
return FALSE;

//设置设备的协作度
if(FAILED(hr = g_pDsd->SetCooperativeLevel(m_hWnd,DSSCL_PRIORITY)))
 
return FALSE;

g_pWaveFile
= new CWaveFile;
g_pWaveFile
->Open(_T("c:\\test.wav"), NULL, WAVEFILE_READ);

DSBUFFERDESC dsbd;
ZeroMemory(
&dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize
= sizeof(DSBUFFERDESC);
dsbd.dwFlags
= DSBCAPS_GLOBALFOCUS               //设置主播
                                | DSBCAPS_CTRLFX
                                
| DSBCAPS_CTRLPOSITIONNOTIFY
                                
| DSBCAPS_GETCURRENTPOSITION2;

dsbd.dwBufferBytes
= g_pWaveFile->GetSize();   
dsbd.lpwfxFormat
= g_pWaveFile->m_pwfx;

LPDIRECTSOUNDBUFFER lPBuffer;

//创建辅助缓冲区对象
if(FAILED(hr = g_pDsd->CreateSoundBuffer(&dsbd,&lpbuffer,NULL)))
 
return ;
if( FAILED(hr = lpbuffer->QueryInterface( IID_IDirectSoundBuffer8, (LPVOID*) &g_pDSBuffer8) ) )
 
return ;
lpbuffer
->Release();

//播放
LPVOID lplockbuf;
DWORD len;
DWORD dwWrite;

g_pDSBuffer8
->Lock(0,0, &lplockbuf,  &len,  NULL,  NULL, DSBLOCK_ENTIREBUFFER);

//g_pWaveFile 声音写入到lplockbuf所指地址
g_pWaveFile->Read((BYTE*)lplockbuf, len, &dwWrite);

g_pDSBuffer8
->Unlock(lplockbuf,len,NULL,0);

g_pDSBuffer8
->SetCurrentPosition(0);

g_pDSBuffer8
->Play(0,0,DSBPLAY_LOOPING);




   f  流缓冲区播放超大型的wave文件
   流缓冲区就是播放那些比较长的音频文件,边播放,边填充DirectSound缓冲区。
   DirectSound的通知机制
      因为Stream buffer 大小只够容纳一部分数据,在播放完缓冲区中的数据后,
      DirectSound就会通知应用程序,将新的数据填充到DirectSound的缓冲区中。


#define MAX_AUDIO_BUF 4                        //设置4个buffer
#define BUFFERNOTIFYSIZE 1920               //每个buffer尺寸为1920

BOOL g_bPlaying     
= FALSE;                                            //是否正在播放
LPDIRECTSOUNDNOTIFY8 g_pDSNotify = NULL;
DSBPOSITIONNOTIFY        g_aPosNotify[MAX_AUDIO_BUF];     
//设置通知标志的数组

HANDLE g_event[MAX_AUDIO_BUF];
for(int i =0; i< MAX_AUDIO_BUF;i++)
{
 g_aPosNotify.dwOffset
= i* BUFFERNOTIFYSIZE ;   
    g_aPosNotify.hEventNotify
= g_event;
}

if(FAILED(hr = g_pDSBuffer8->QueryInterface(IID_IDirectSoundNotify,(LPVOID *) &g_pDSNotify )))
 
return ;

g_pDSNotify
->SetNotificationPositions(MAX_AUDIO_BUF,g_aPosNotify);

g_pDSNotify
->Release();


     当DirectSound播放到buffer的1920,3840,5760,7680等位置时,
Directsound就会通知应用程序,将g_event,设置为通知态;
  应用程序就通过WaitForMultipleObjects 函数等待DirectSound的通知,
将数据填充到DirectSoun的辅助缓冲区。




分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表