- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# 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 }