AudioSwitcher.cpp

00001 /* 
00002  *      Copyright (C) 2003-2005 Gabest
00003  *      http://www.gabest.org
00004  *
00005  *  This Program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2, or (at your option)
00008  *  any later version.
00009  *   
00010  *  This Program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *   
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with GNU Make; see the file COPYING.  If not, write to
00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
00018  *  http://www.gnu.org/copyleft/gpl.html
00019  *
00020  */
00021 
00022 #include "StdAfx.h"
00023 
00024 #include "Shlwapi.h"
00025 #include <atlpath.h>
00026 #include <mmreg.h>
00027 #include <ks.h>
00028 #include <ksmedia.h>
00029 #include "AudioSwitcher.h"
00030 #include "Audio.h"
00031 #include "..\..\..\DSUtil\DSUtil.h"
00032 
00033 #include <initguid.h>
00034 #include "..\..\..\..\include\Ogg\OggDS.h"
00035 
00036 
00037 #ifdef REGISTER_FILTER
00038 
00039 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
00040 {
00041         {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL}
00042 };
00043 
00044 const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
00045 {
00046         {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL}
00047 };
00048 
00049 const AMOVIESETUP_PIN sudpPins[] =
00050 {
00051     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
00052     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut}
00053 };
00054 
00055 const AMOVIESETUP_FILTER sudFilter[] =
00056 {
00057         {&__uuidof(CAudioSwitcherFilter), L"AudioSwitcher", MERIT_DO_NOT_USE, countof(sudpPins), sudpPins}
00058 };
00059 
00060 CFactoryTemplate g_Templates[] =
00061 {
00062     {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CAudioSwitcherFilter>, NULL, &sudFilter[0]}
00063 };
00064 
00065 int g_cTemplates = countof(g_Templates);
00066 
00067 STDAPI DllRegisterServer()
00068 {
00069         return AMovieDllRegisterServer2(TRUE);
00070 }
00071 
00072 STDAPI DllUnregisterServer()
00073 {
00074         return AMovieDllRegisterServer2(FALSE);
00075 }
00076 
00077 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
00078 
00079 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
00080 {
00081     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
00082 }
00083 
00084 #endif
00085 
00086 //
00087 // CAudioSwitcherFilter
00088 //
00089 
00090 CAudioSwitcherFilter::CAudioSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr)
00091         : CStreamSwitcherFilter(lpunk, phr, __uuidof(this))
00092 {
00093         if(phr)
00094         {
00095                 if(FAILED(*phr)) return;
00096                 else *phr = S_OK;
00097         }
00098 
00099         m_fCustomChannelMapping = false;
00100         memset(m_pSpeakerToChannelMap, 0, sizeof(m_pSpeakerToChannelMap));
00101         m_fDownSampleTo441 = false;
00102         m_rtAudioTimeShift = 0;
00103         m_rtNextStart = 0;
00104         m_rtNextStop = 1;
00105 }
00106 
00107 STDMETHODIMP CAudioSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00108 {
00109         return
00110                 QI(IAudioSwitcherFilter)
00111                 __super::NonDelegatingQueryInterface(riid, ppv);
00112 }
00113 
00114 HRESULT CAudioSwitcherFilter::CheckMediaType(const CMediaType* pmt)
00115 {
00116         if(pmt->formattype == FORMAT_WaveFormatEx
00117         && ((WAVEFORMATEX*)pmt->pbFormat)->nChannels > 2
00118         && ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag != WAVE_FORMAT_EXTENSIBLE)
00119                 return VFW_E_INVALIDMEDIATYPE; // stupid iviaudio tries to fool us
00120 
00121         return (pmt->majortype == MEDIATYPE_Audio
00122                         && pmt->formattype == FORMAT_WaveFormatEx
00123                         && (((WAVEFORMATEX*)pmt->pbFormat)->wBitsPerSample == 8
00124                                 || ((WAVEFORMATEX*)pmt->pbFormat)->wBitsPerSample == 16
00125                                 || ((WAVEFORMATEX*)pmt->pbFormat)->wBitsPerSample == 24
00126                                 || ((WAVEFORMATEX*)pmt->pbFormat)->wBitsPerSample == 32)
00127                         && (((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_PCM
00128                                 || ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_IEEE_FLOAT
00129                                 || ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF
00130                                 || ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_EXTENSIBLE))
00131                 ? S_OK
00132                 : VFW_E_TYPE_NOT_ACCEPTED;
00133 }
00134 
00135 #define mixchannels(type, sumtype, mintype, maxtype) \
00136         sumtype sum = 0; \
00137         int num = 0; \
00138         for(int j = 0; j < 18 && j < wfe->nChannels; j++) \
00139         { \
00140                 if(Channel&(1<<j)) \
00141                 { \
00142                         num++; \
00143                         sum += *(type*)&pDataIn[bps*(j + wfe->nChannels*k)]; \
00144                 } \
00145         } \
00146         sum = min(max(sum, mintype), maxtype); \
00147         *(type*)&pDataOut[bps*(i + wfeout->nChannels*k)] = (type)sum; \
00148 
00149 HRESULT CAudioSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut)
00150 {
00151         CStreamSwitcherInputPin* pInPin = GetInputPin();
00152         CStreamSwitcherOutputPin* pOutPin = GetOutputPin();
00153         if(!pInPin || !pOutPin) 
00154                 return __super::Transform(pIn, pOut);
00155 
00156         WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat;
00157         WAVEFORMATEX* wfeout = (WAVEFORMATEX*)pOutPin->CurrentMediaType().pbFormat;
00158         WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe;
00159         WAVEFORMATEXTENSIBLE* wfexout = (WAVEFORMATEXTENSIBLE*)wfeout;
00160 
00161         int bps = wfe->wBitsPerSample>>3;
00162 
00163         int len = pIn->GetActualDataLength() / (bps*wfe->nChannels);
00164         int lenout = len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec;
00165 
00166         REFERENCE_TIME rtStart, rtStop;
00167         if(SUCCEEDED(pIn->GetTime(&rtStart, &rtStop)))
00168         {
00169                 rtStart += m_rtAudioTimeShift;
00170                 rtStop += m_rtAudioTimeShift;
00171                 pOut->SetTime(&rtStart, &rtStop);
00172 
00173                 m_rtNextStart = rtStart;
00174                 m_rtNextStop = rtStop;
00175         }
00176         else
00177         {
00178                 pOut->SetTime(&m_rtNextStart, &m_rtNextStop);
00179         }
00180 
00181         m_rtNextStart += 10000000i64*len/wfe->nSamplesPerSec;
00182         m_rtNextStop += 10000000i64*len/wfe->nSamplesPerSec;
00183 
00184         bool fPCM = wfe->wFormatTag == WAVE_FORMAT_PCM
00185                 || wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM;
00186 
00187         bool fFloat = wfe->wFormatTag == WAVE_FORMAT_IEEE_FLOAT
00188                 || wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
00189 
00190         if(!fPCM && !fFloat)
00191                 return __super::Transform(pIn, pOut);
00192 
00193         BYTE* pDataIn = NULL;
00194         BYTE* pDataOut = NULL;
00195 
00196         HRESULT hr;
00197         if(FAILED(hr = pIn->GetPointer(&pDataIn))) return hr;
00198         if(FAILED(hr = pOut->GetPointer(&pDataOut))) return hr;
00199 
00200         if(!pDataIn || !pDataOut || len <= 0 || lenout <= 0) return S_FALSE;
00201 
00202         memset(pDataOut, 0, pOut->GetSize());
00203 
00204         if(m_fCustomChannelMapping)
00205         {
00206                 if(m_chs[wfe->nChannels-1].GetCount() > 0)
00207                 {
00208                         for(int i = 0; i < wfeout->nChannels; i++)
00209                         {
00210                                 DWORD Channel = m_chs[wfe->nChannels-1][i].Channel, nChannels = 0;
00211 
00212                                 for(int k = 0; k < len; k++)
00213                                 {
00214                                         if(fPCM && wfe->wBitsPerSample == 8)
00215                                         {
00216                                                 mixchannels(unsigned char, __int64, 0, UCHAR_MAX);
00217                                         }
00218                                         else if(fPCM && wfe->wBitsPerSample == 16)
00219                                         {
00220                                                 mixchannels(short, __int64, SHRT_MIN, SHRT_MAX);
00221                                         }
00222                                         else if(fPCM && wfe->wBitsPerSample == 24)
00223                                         {
00224 //                                              mixchannels(_int24, __int64, _INT24_MIN, _INT24_MAX);
00225 
00226                                                 __int64 sum = 0;
00227                                                 int num = 0;
00228                                                 for(int j = 0; j < 18 && j < wfe->nChannels; j++)
00229                                                 {
00230                                                         if(Channel&(1<<j))
00231                                                         {
00232                                                                 num++;
00233                                                                 int tmp;
00234                                                                 memcpy((BYTE*)&tmp+1, &pDataIn[bps*(j + wfe->nChannels*k)], 3);
00235                                                                 tmp>>=8;
00236                                                                 sum += tmp;
00237                                                         }
00238                                                 }
00239                                                 sum = min(max(sum, -(1<<24)), (1<<24)-1);
00240                                                 memcpy(&pDataOut[bps*(i + wfeout->nChannels*k)], (BYTE*)&sum, 3);
00241                                         }
00242                                         else if(fPCM && wfe->wBitsPerSample == 32)
00243                                         {
00244                                                 mixchannels(int, __int64, INT_MIN, INT_MAX);
00245                                         }
00246                                         else if(fFloat && wfe->wBitsPerSample == 32)
00247                                         {
00248                                                 mixchannels(float, double, -1, 1);
00249                                         }
00250                                         else if(fFloat && wfe->wBitsPerSample == 64)
00251                                         {
00252                                                 mixchannels(double, double, -1, 1);
00253                                         }
00254                                 }
00255                         }
00256                 }
00257                 else
00258                 {
00259                         BYTE* pDataOut = NULL;
00260                         HRESULT hr;
00261                         if(FAILED(hr = pOut->GetPointer(&pDataOut)) || !pDataOut) return hr;
00262                         memset(pDataOut, 0, pOut->GetSize());
00263                 }
00264         }
00265         else
00266         {
00267                 HRESULT hr;
00268                 if(S_OK != (hr = __super::Transform(pIn, pOut)))
00269                         return hr;
00270         }
00271 
00272         if(m_fDownSampleTo441
00273         && wfe->nSamplesPerSec > 44100 && wfeout->nSamplesPerSec == 44100 
00274         && wfe->wBitsPerSample <= 16 && fPCM)
00275         {
00276                 if(BYTE* buff = new BYTE[len*bps])
00277                 {
00278                         for(int ch = 0; ch < wfeout->nChannels; ch++)
00279                         {
00280                                 memset(buff, 0, len*bps);
00281 
00282                                 for(int i = 0; i < len; i++)
00283                                         memcpy(buff + i*bps, (char*)pDataOut + (ch + i*wfeout->nChannels)*bps, bps);
00284 
00285                                 m_pResamplers[ch]->Downsample(buff, len, buff, lenout);
00286 
00287                                 for(int i = 0; i < lenout; i++)
00288                                         memcpy((char*)pDataOut + (ch + i*wfeout->nChannels)*bps, buff + i*bps, bps);
00289                         }
00290 
00291                         delete [] buff;
00292                 }
00293         }
00294 
00295         pOut->SetActualDataLength(lenout*bps*wfeout->nChannels);
00296 
00297         return S_OK;
00298 }
00299 
00300 CMediaType CAudioSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer)
00301 {
00302         CStreamSwitcherInputPin* pInPin = GetInputPin();
00303         CStreamSwitcherOutputPin* pOutPin = GetOutputPin();
00304         if(!pInPin || !pOutPin || ((WAVEFORMATEX*)mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF) 
00305                 return __super::CreateNewOutputMediaType(mt, cbBuffer);
00306 
00307         WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat;
00308 
00309         if(m_fCustomChannelMapping)
00310         {
00311                 m_chs[wfe->nChannels-1].RemoveAll();
00312 
00313                 DWORD mask = DWORD((__int64(1)<<wfe->nChannels)-1);
00314                 for(int i = 0; i < 18; i++)
00315                 {
00316                         if(m_pSpeakerToChannelMap[wfe->nChannels-1][i]&mask)
00317                         {
00318                                 ChMap cm = {1<<i, m_pSpeakerToChannelMap[wfe->nChannels-1][i]};
00319                                 m_chs[wfe->nChannels-1].Add(cm);
00320                         }
00321                 }
00322 
00323                 if(m_chs[wfe->nChannels-1].GetCount() > 0)
00324                 {
00325                         mt.ReallocFormatBuffer(sizeof(WAVEFORMATEXTENSIBLE));
00326                         WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)mt.pbFormat;
00327                         wfex->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
00328                         wfex->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
00329                         wfex->Samples.wValidBitsPerSample = wfe->wBitsPerSample;
00330                         wfex->SubFormat = 
00331                                 wfe->wFormatTag == WAVE_FORMAT_PCM ? KSDATAFORMAT_SUBTYPE_PCM :
00332                                 wfe->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT :
00333                                 wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? ((WAVEFORMATEXTENSIBLE*)wfe)->SubFormat :
00334                                 KSDATAFORMAT_SUBTYPE_PCM; // can't happen
00335 
00336                         wfex->dwChannelMask = 0;
00337                         for(int i = 0; i < m_chs[wfe->nChannels-1].GetCount(); i++)
00338                                 wfex->dwChannelMask |= m_chs[wfe->nChannels-1][i].Speaker;
00339 
00340                         wfex->Format.nChannels = (WORD)m_chs[wfe->nChannels-1].GetCount();
00341                         wfex->Format.nBlockAlign = wfex->Format.nChannels*wfex->Format.wBitsPerSample>>3;
00342                         wfex->Format.nAvgBytesPerSec = wfex->Format.nBlockAlign*wfex->Format.nSamplesPerSec;
00343                 }
00344         }
00345 
00346         WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mt.pbFormat;
00347 
00348         if(m_fDownSampleTo441)
00349         {
00350                 if(wfeout->nSamplesPerSec > 44100 && wfeout->wBitsPerSample <= 16)
00351                 {
00352                         wfeout->nSamplesPerSec = 44100;
00353                         wfeout->nAvgBytesPerSec = wfeout->nBlockAlign*wfeout->nSamplesPerSec;
00354                 }
00355         }
00356 
00357         int bps = wfe->wBitsPerSample>>3;
00358         int len = cbBuffer / (bps*wfe->nChannels);
00359         int lenout = len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec;
00360         cbBuffer = lenout*bps*wfeout->nChannels;
00361 
00362 //      mt.lSampleSize = (ULONG)max(mt.lSampleSize, wfe->nAvgBytesPerSec * rtLen / 10000000i64);
00363 //      mt.lSampleSize = (mt.lSampleSize + (wfe->nBlockAlign-1)) & ~(wfe->nBlockAlign-1);
00364 
00365         return mt;
00366 }
00367 
00368 void CAudioSwitcherFilter::OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut)
00369 {
00370         const WAVEFORMATEX* wfe = (WAVEFORMATEX*)mtIn.pbFormat;
00371         const WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mtOut.pbFormat;
00372 
00373         m_pResamplers.RemoveAll();
00374         for(int i = 0; i < wfeout->nChannels; i++)
00375         {
00376                 CAutoPtr<AudioStreamResampler> pResampler;
00377                 pResampler.Attach(new AudioStreamResampler(wfeout->wBitsPerSample>>3, wfe->nSamplesPerSec, wfeout->nSamplesPerSec, true));
00378                 m_pResamplers.Add(pResampler);
00379         }
00380 }
00381 
00382 // IAudioSwitcherFilter
00383 
00384 STDMETHODIMP CAudioSwitcherFilter::GetInputSpeakerConfig(DWORD* pdwChannelMask)
00385 {
00386         if(!pdwChannelMask) 
00387                 return E_POINTER;
00388 
00389         *pdwChannelMask = 0;
00390 
00391         CStreamSwitcherInputPin* pInPin = GetInputPin();
00392         if(!pInPin || !pInPin->IsConnected())
00393                 return E_UNEXPECTED;
00394 
00395         WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat;
00396 
00397         if(wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
00398         {
00399                 WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe;
00400                 *pdwChannelMask = wfex->dwChannelMask;
00401         }
00402         else
00403         {
00404                 *pdwChannelMask = 0/*wfe->nChannels == 1 ? 4 : wfe->nChannels == 2 ? 3 : 0*/;
00405         }
00406 
00407         return S_OK;
00408 }
00409 
00410 STDMETHODIMP CAudioSwitcherFilter::GetSpeakerConfig(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[18][18])
00411 {
00412         if(pfCustomChannelMapping) *pfCustomChannelMapping = m_fCustomChannelMapping;
00413         memcpy(pSpeakerToChannelMap, m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap));
00414 
00415         return S_OK;
00416 }
00417 
00418 STDMETHODIMP CAudioSwitcherFilter::SetSpeakerConfig(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[18][18])
00419 {
00420         if(m_State == State_Stopped || m_fCustomChannelMapping != fCustomChannelMapping
00421         || memcmp(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)))
00422         {
00423                 PauseGraph;
00424                 
00425                 CStreamSwitcherInputPin* pInput = GetInputPin();
00426 
00427                 SelectInput(NULL);
00428 
00429                 m_fCustomChannelMapping = fCustomChannelMapping;
00430                 memcpy(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap));
00431 
00432                 SelectInput(pInput);
00433 
00434                 ResumeGraph;
00435         }
00436 
00437         return S_OK;
00438 }
00439 
00440 STDMETHODIMP_(int) CAudioSwitcherFilter::GetNumberOfInputChannels()
00441 {
00442         CStreamSwitcherInputPin* pInPin = GetInputPin();
00443         return pInPin ? ((WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat)->nChannels : 0;
00444 }
00445 
00446 STDMETHODIMP_(bool) CAudioSwitcherFilter::IsDownSamplingTo441Enabled()
00447 {
00448         return(m_fDownSampleTo441);
00449 }
00450 
00451 STDMETHODIMP CAudioSwitcherFilter::EnableDownSamplingTo441(bool fEnable)
00452 {
00453         if(m_fDownSampleTo441 != fEnable)
00454         {
00455                 PauseGraph;
00456 
00457                 m_fDownSampleTo441 = fEnable;
00458 
00459                 ResumeGraph;
00460         }
00461 
00462         return S_OK;
00463 }
00464 
00465 STDMETHODIMP_(REFERENCE_TIME) CAudioSwitcherFilter::GetAudioTimeShift()
00466 {
00467         return(m_rtAudioTimeShift);
00468 }
00469 
00470 STDMETHODIMP CAudioSwitcherFilter::SetAudioTimeShift(REFERENCE_TIME rtAudioTimeShift)
00471 {
00472         m_rtAudioTimeShift = rtAudioTimeShift;
00473         return S_OK;
00474 }

Generated on Tue Dec 13 14:47:26 2005 for guliverkli by  doxygen 1.4.5