michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "SampleSink.h" michael@0: #include "AudioSinkFilter.h" michael@0: #include "AudioSinkInputPin.h" michael@0: #include "VideoUtils.h" michael@0: #include "prlog.h" michael@0: michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #define DELETE_RESET(p) { delete (p) ; (p) = nullptr ;} michael@0: michael@0: DEFINE_GUID(CLSID_MozAudioSinkFilter, 0x1872d8c8, 0xea8d, 0x4c34, 0xae, 0x96, 0x69, 0xde, michael@0: 0xf1, 0x33, 0x7b, 0x33); michael@0: michael@0: using namespace mozilla::media; michael@0: michael@0: namespace mozilla { michael@0: michael@0: #ifdef PR_LOGGING michael@0: PRLogModuleInfo* GetDirectShowLog(); michael@0: #define LOG(...) PR_LOG(GetDirectShowLog(), PR_LOG_DEBUG, (__VA_ARGS__)) michael@0: #else michael@0: #define LOG(...) michael@0: #endif michael@0: michael@0: AudioSinkFilter::AudioSinkFilter(const wchar_t* aObjectName, HRESULT* aOutResult) michael@0: : BaseFilter(aObjectName, CLSID_MozAudioSinkFilter), michael@0: mFilterCritSec("AudioSinkFilter::mFilterCritSec") michael@0: { michael@0: (*aOutResult) = S_OK; michael@0: mInputPin = new AudioSinkInputPin(L"AudioSinkInputPin", michael@0: this, michael@0: &mFilterCritSec, michael@0: aOutResult); michael@0: } michael@0: michael@0: AudioSinkFilter::~AudioSinkFilter() michael@0: { michael@0: } michael@0: michael@0: int michael@0: AudioSinkFilter::GetPinCount() michael@0: { michael@0: return 1; michael@0: } michael@0: michael@0: BasePin* michael@0: AudioSinkFilter::GetPin(int aIndex) michael@0: { michael@0: CriticalSectionAutoEnter lockFilter(mFilterCritSec); michael@0: return (aIndex == 0) ? static_cast(mInputPin) : nullptr; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::Pause() michael@0: { michael@0: CriticalSectionAutoEnter lockFilter(mFilterCritSec); michael@0: if (mState == State_Stopped) { michael@0: // Change the state, THEN activate the input pin. michael@0: mState = State_Paused; michael@0: if (mInputPin && mInputPin->IsConnected()) { michael@0: mInputPin->Active(); michael@0: } michael@0: } else if (mState == State_Running) { michael@0: mState = State_Paused; michael@0: } michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::Stop() michael@0: { michael@0: CriticalSectionAutoEnter lockFilter(mFilterCritSec); michael@0: mState = State_Stopped; michael@0: if (mInputPin) { michael@0: mInputPin->Inactive(); michael@0: } michael@0: michael@0: GetSampleSink()->Flush(); michael@0: michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::Run(REFERENCE_TIME tStart) michael@0: { michael@0: LOG("AudioSinkFilter::Run(%lld) [%4.2lf]", michael@0: RefTimeToUsecs(tStart), michael@0: double(RefTimeToUsecs(tStart)) / USECS_PER_S); michael@0: return media::BaseFilter::Run(tStart); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetClassID( OUT CLSID * pCLSID ) michael@0: { michael@0: (* pCLSID) = CLSID_MozAudioSinkFilter; michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::QueryInterface(REFIID aIId, void **aInterface) michael@0: { michael@0: if (aIId == IID_IMediaSeeking) { michael@0: *aInterface = static_cast(this); michael@0: AddRef(); michael@0: return S_OK; michael@0: } michael@0: return mozilla::media::BaseFilter::QueryInterface(aIId, aInterface); michael@0: } michael@0: michael@0: ULONG michael@0: AudioSinkFilter::AddRef() michael@0: { michael@0: return ::InterlockedIncrement(&mRefCnt); michael@0: } michael@0: michael@0: ULONG michael@0: AudioSinkFilter::Release() michael@0: { michael@0: unsigned long newRefCnt = ::InterlockedDecrement(&mRefCnt); michael@0: if (!newRefCnt) { michael@0: delete this; michael@0: } michael@0: return newRefCnt; michael@0: } michael@0: michael@0: SampleSink* michael@0: AudioSinkFilter::GetSampleSink() michael@0: { michael@0: return mInputPin->GetSampleSink(); michael@0: } michael@0: michael@0: michael@0: // IMediaSeeking implementation. michael@0: // michael@0: // Calls to IMediaSeeking are forwarded to the output pin that the michael@0: // AudioSinkInputPin is connected to, i.e. upstream towards the parser and michael@0: // source filters, which actually implement seeking. michael@0: #define ENSURE_CONNECTED_PIN_SEEKING \ michael@0: if (!mInputPin) { \ michael@0: return E_NOTIMPL; \ michael@0: } \ michael@0: RefPtr pinSeeking = mInputPin->GetConnectedPinSeeking(); \ michael@0: if (!pinSeeking) { \ michael@0: return E_NOTIMPL; \ michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetCapabilities(DWORD* aCapabilities) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->GetCapabilities(aCapabilities); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::CheckCapabilities(DWORD* aCapabilities) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->CheckCapabilities(aCapabilities); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::IsFormatSupported(const GUID* aFormat) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->IsFormatSupported(aFormat); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::QueryPreferredFormat(GUID* aFormat) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->QueryPreferredFormat(aFormat); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetTimeFormat(GUID* aFormat) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->GetTimeFormat(aFormat); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::IsUsingTimeFormat(const GUID* aFormat) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->IsUsingTimeFormat(aFormat); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::SetTimeFormat(const GUID* aFormat) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->SetTimeFormat(aFormat); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetDuration(LONGLONG* aDuration) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->GetDuration(aDuration); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetStopPosition(LONGLONG* aStop) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->GetStopPosition(aStop); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetCurrentPosition(LONGLONG* aCurrent) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->GetCurrentPosition(aCurrent); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::ConvertTimeFormat(LONGLONG* aTarget, michael@0: const GUID* aTargetFormat, michael@0: LONGLONG aSource, michael@0: const GUID* aSourceFormat) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->ConvertTimeFormat(aTarget, michael@0: aTargetFormat, michael@0: aSource, michael@0: aSourceFormat); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::SetPositions(LONGLONG* aCurrent, michael@0: DWORD aCurrentFlags, michael@0: LONGLONG* aStop, michael@0: DWORD aStopFlags) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->SetPositions(aCurrent, michael@0: aCurrentFlags, michael@0: aStop, michael@0: aStopFlags); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetPositions(LONGLONG* aCurrent, michael@0: LONGLONG* aStop) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->GetPositions(aCurrent, aStop); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetAvailable(LONGLONG* aEarliest, michael@0: LONGLONG* aLatest) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->GetAvailable(aEarliest, aLatest); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::SetRate(double aRate) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->SetRate(aRate); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetRate(double* aRate) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->GetRate(aRate); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkFilter::GetPreroll(LONGLONG* aPreroll) michael@0: { michael@0: ENSURE_CONNECTED_PIN_SEEKING michael@0: return pinSeeking->GetPreroll(aPreroll); michael@0: } michael@0: michael@0: } // namespace mozilla michael@0: