几个格式细节备记(混)
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的辅助缓冲区。
|