[原创]讲一下IMedia 流播放的故事!

    技术2022-05-19  24

    IMedia作为强大的brew音频视频播放接口,其功能必然很完善。今天讲一下用IMedia 播放流声音,这个常用于用在网络音频在线播放等等。这次主要针对PCM和wav格式,这类是比较基础的流播放格式。个人理解流播放其实就是一个无头音乐的播放,网络传送来的buffer不会每次都带音频信息,所以我个人叫他“无头播放”。而一个音乐没有头信息怎么会被播放接口失败呢?识别了如何填充buffer持续播放?有几种填充方式呢?下面介绍第一种做法IFIFO实现:#include "AEEFIFO.h" #include "AEEIMedia.h"//首先定义两个结构体变量:AEEMediaDataEx MediaDataEx;//这个是用来填充IMedia 的结构体AEEMediaWaveSpec WaveSpec;//这个就是音频格式信息IFIFO   *m_pFIFO;IMedia * pIMedia;ISource *m_pISource =NULL;ISHELL_CreateInstance(pMe->applet.m_pIShell, AEECLSID_FIFO, (void**)&m_pFIFO);  ISHELL_CreateInstance(pMe->applet.m_pIShell,AEECLSID_MEDIAPCM,(void**)&pIMedia);IFIFO_OpenEx(GET_IFIFO(),"fifo://shared//test", AEEFIFO_MODE_RW);//fs:/shared/test这个目录IFIFO_QueryInterface(GET_IFIFO(), AEECLSID_SOURCE, (void**)&m_pISource);IFIFO_SetBufSize(GET_IFIFO(), 2048*4);//大小自己决定MEMSET(&WaveSpec, 0x00, sizeof(WaveSpec)); //初始化WaveSpec.wSize               = sizeof(WaveSpec);//spec的sizeWaveSpec.clsMedia            = AEECLSID_MEDIAPCM;//这里用PCM接口WaveSpec.wChannels           = 1;//channel,Number of channels. One for mono, two for stereo. WaveSpec.dwSamplesPerSec     = 8000;//Channel sample rate in samples per second(Hertz). 只能取值8000 16000 32000 这样的采样率WaveSpec.wBitsPerSample      = 16;// Number of bits per sample 取值8 或者 16WaveSpec.bUnsigned           = FALSE;    //这个填写falseWaveSpec.dwExtra    = 0;//填写0//上面这一堆复制其实就是说明这个音频的格式,比如采样率,channel等等MediaDataEx.clsData       = MMD_ISOURCE;     // pData is ISourceMediaDataEx.pData         = (void *)m_pISource;   // ISource objectMediaDataEx.dwSize        = 0; MediaDataEx.dwStructSize  = sizeof(MediaDataEx);  // Size of AEEMediaDataEx structureMediaDataEx.dwCaps        = 0;    // What capabilities to enable. 0 means all.   MediaDataEx.dwBufferSize  = 0;    // Internal buffer size. 0 means use default.MediaDataEx.bRaw          = TRUE;   // Is this Raw data? Set it to no (FALSE)MediaDataEx.pSpec         = &WaveSpec;   // Valid only for raw dataMediaDataEx.dwSpecSize    = sizeof(WaveSpec); // Valid only for raw data //上面赋值是用来初始化IMedia接口数组,然后传给 IMediaIMEDIA_SetMediaDataEx(pIMedia,&MediaDataEx, 1);IMEDIA_RegisterNotify(pIMedia,(PFNMEDIANOTIFY)CB_Play,pISource);IMEDIA_Play(pIMedia);//开始播放,但这个时候其实是没声音的!接下来在获得到buffer后只要做一件事:IFIFO_Write(m_pFIFO,(char *)music_buf, music_buf_len);//这样就看到音频播放比较流畅了这是一种做法,另一种做法参考下面的源代码:

    这个源码有些地方不是很适合,具体改动在这里:void SMISOURCE_UpdateWriteable(SMISource *pis)//更改 by狮子//里面的判断比较生硬,这样就动态多了{if ( pis->nWritePos < pis->nReadPos ){ if (( pis->nReadPos - pis->nWritePos ) < pis->nWriteSize ) {  pis->bWriteable = FALSE; } else {  pis->bWriteable = TRUE; }}else if ( pis->nWritePos > pis->nReadPos ){ if (( pis->nWritePos + pis->nWriteSize  ) >= pis->nBufSize ) {  if (( pis->nWritePos + pis->nWriteSize  - pis->nBufSize ) < pis->nReadPos )  {   pis->bWriteable = TRUE;  }  else  {   pis->bWriteable = FALSE;  } } else {  pis->bWriteable = TRUE; }}else//更改 by狮子//部分当指针相等时其实是可以写的{ pis->bWriteable = TRUE;}}int SMISOURCE_SourceFromMemory( int nBufLen, SMISource **ppis){SMISource *pis = NULL;int nRet = 0;//sf_dbgprintf("SMISOURCE|SMISOURCE_SourceFromMemory");if (/*( NULL == pBuf ) || */( nBufLen <= 0 )) return 1;pis = (SMISource*)MALLOC(sizeof(SMISource));if ( NULL == pis ){ //sf_dbgprintf("SMISOURCE|"); return ENOMEMORY;}pis->pVtbl = (ISourceVtbl*)MALLOC(sizeof(ISourceVtbl));if ( NULL == pis->pVtbl ){ //sf_dbgprintf("SMISOURCE|"); FREE(pis); return ENOMEMORY;}pis->pVtbl->AddRef = SMISOURCE_AddRef;pis->pVtbl->Release = SMISOURCE_Release;pis->pVtbl->QueryInterface = SMISOURCE_QueryInterface;pis->pVtbl->Read = SMISOURCE_Read;pis->pVtbl->Readable = SMISOURCE_Readable;pis->pDataBuf = MALLOC(nBufLen);//更改 by狮子//使用内部buffer,外部不再关心其存储方式pis->nBufSize = nBufLen;MEMSET(pis->pDataBuf,0x00,nBufLen);pis->nRefCnt = 1;pis->bWriteable = TRUE;pis->nDataSize = 0;pis->nReadPos = 0;pis->nWritePos = 0;pis->pReadableCB = NULL;*ppis = pis;return SUCCESS;}int SMISOURCE_SourceFree(SMISource *pis){//sf_dbgprintf("SMISOURCE|");if ( NULL != pis ){ FREEIF(pis->pVtbl); FREEIF(pis->pDataBuf); FREE(pis);}return 0;}具体的实现可以看源代码,不过源代码是用多线程的,其实每次buffer到了调用SMISource_Write 就OK了


    最新回复(0)