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 "AudioSinkInputPin.h" michael@0: #include "AudioSinkFilter.h" michael@0: #include "SampleSink.h" michael@0: #include "prlog.h" michael@0: michael@0: #include 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: AudioSinkInputPin::AudioSinkInputPin(wchar_t* aObjectName, michael@0: AudioSinkFilter* aFilter, michael@0: mozilla::CriticalSection* aLock, michael@0: HRESULT* aOutResult) michael@0: : BaseInputPin(aObjectName, aFilter, aLock, aOutResult, aObjectName), michael@0: mSegmentStartTime(0) michael@0: { michael@0: MOZ_COUNT_CTOR(AudioSinkInputPin); michael@0: mSampleSink = new SampleSink(); michael@0: } michael@0: michael@0: AudioSinkInputPin::~AudioSinkInputPin() michael@0: { michael@0: MOZ_COUNT_DTOR(AudioSinkInputPin); michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkInputPin::GetMediaType(int aPosition, MediaType* aOutMediaType) michael@0: { michael@0: NS_ENSURE_TRUE(aPosition >= 0, E_INVALIDARG); michael@0: NS_ENSURE_TRUE(aOutMediaType, E_POINTER); michael@0: michael@0: if (aPosition > 0) { michael@0: return S_FALSE; michael@0: } michael@0: michael@0: // Note: We set output as PCM, as IEEE_FLOAT only works when using the michael@0: // MP3 decoder as an MFT, and we can't do that while using DirectShow. michael@0: aOutMediaType->SetType(&MEDIATYPE_Audio); michael@0: aOutMediaType->SetSubtype(&MEDIASUBTYPE_PCM); michael@0: aOutMediaType->SetType(&FORMAT_WaveFormatEx); michael@0: aOutMediaType->SetTemporalCompression(FALSE); michael@0: michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkInputPin::CheckMediaType(const MediaType* aMediaType) michael@0: { michael@0: if (!aMediaType) { michael@0: return E_INVALIDARG; michael@0: } michael@0: michael@0: GUID majorType = *aMediaType->Type(); michael@0: if (majorType != MEDIATYPE_Audio && majorType != WMMEDIATYPE_Audio) { michael@0: return E_INVALIDARG; michael@0: } michael@0: michael@0: if (*aMediaType->Subtype() != MEDIASUBTYPE_PCM) { michael@0: return E_INVALIDARG; michael@0: } michael@0: michael@0: if (*aMediaType->FormatType() != FORMAT_WaveFormatEx) { michael@0: return E_INVALIDARG; michael@0: } michael@0: michael@0: // We accept the media type, stash its layout format! michael@0: WAVEFORMATEX* wfx = (WAVEFORMATEX*)(aMediaType->pbFormat); michael@0: GetSampleSink()->SetAudioFormat(wfx); michael@0: michael@0: return S_OK; michael@0: } michael@0: michael@0: AudioSinkFilter* michael@0: AudioSinkInputPin::GetAudioSinkFilter() michael@0: { michael@0: return reinterpret_cast(mFilter); michael@0: } michael@0: michael@0: SampleSink* michael@0: AudioSinkInputPin::GetSampleSink() michael@0: { michael@0: return mSampleSink; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkInputPin::SetAbsoluteMediaTime(IMediaSample* aSample) michael@0: { michael@0: HRESULT hr; michael@0: REFERENCE_TIME start = 0, end = 0; michael@0: hr = aSample->GetTime(&start, &end); michael@0: NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); michael@0: { michael@0: CriticalSectionAutoEnter lock(*mLock); michael@0: start += mSegmentStartTime; michael@0: end += mSegmentStartTime; michael@0: } michael@0: hr = aSample->SetMediaTime(&start, &end); michael@0: NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkInputPin::Receive(IMediaSample* aSample ) michael@0: { michael@0: HRESULT hr; michael@0: NS_ENSURE_TRUE(aSample, E_POINTER); michael@0: michael@0: hr = BaseInputPin::Receive(aSample); michael@0: if (SUCCEEDED(hr) && hr != S_FALSE) { // S_FALSE == flushing michael@0: // Set the timestamp of the sample after being adjusted for michael@0: // seeking/segments in the "media time" attribute. When we seek, michael@0: // DirectShow starts a new "segment", and starts labeling samples michael@0: // from time=0 again, so we need to correct for this to get the michael@0: // actual timestamps after seeking. michael@0: hr = SetAbsoluteMediaTime(aSample); michael@0: NS_ENSURE_TRUE(SUCCEEDED(hr), hr); michael@0: hr = GetSampleSink()->Receive(aSample); michael@0: NS_ENSURE_TRUE(SUCCEEDED(hr), hr); michael@0: } michael@0: return S_OK; michael@0: } michael@0: michael@0: TemporaryRef michael@0: AudioSinkInputPin::GetConnectedPinSeeking() michael@0: { michael@0: RefPtr peer = GetConnected(); michael@0: if (!peer) michael@0: return nullptr; michael@0: RefPtr seeking; michael@0: peer->QueryInterface(static_cast(byRef(seeking))); michael@0: return seeking; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkInputPin::BeginFlush() michael@0: { michael@0: HRESULT hr = media::BaseInputPin::BeginFlush(); michael@0: NS_ENSURE_TRUE(SUCCEEDED(hr), hr); michael@0: michael@0: GetSampleSink()->Flush(); michael@0: michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkInputPin::EndFlush() michael@0: { michael@0: HRESULT hr = media::BaseInputPin::EndFlush(); michael@0: NS_ENSURE_TRUE(SUCCEEDED(hr), hr); michael@0: michael@0: // Reset the EOS flag, so that if we're called after a seek we still work. michael@0: GetSampleSink()->Reset(); michael@0: michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: AudioSinkInputPin::EndOfStream(void) michael@0: { michael@0: HRESULT hr = media::BaseInputPin::EndOfStream(); michael@0: if (FAILED(hr) || hr == S_FALSE) { michael@0: // Pin is stil flushing. michael@0: return hr; michael@0: } michael@0: GetSampleSink()->SetEOS(); michael@0: michael@0: return S_OK; michael@0: } michael@0: michael@0: michael@0: HRESULT michael@0: AudioSinkInputPin::NewSegment(REFERENCE_TIME tStart, michael@0: REFERENCE_TIME tStop, michael@0: double dRate) michael@0: { michael@0: CriticalSectionAutoEnter lock(*mLock); michael@0: // Record the start time of the new segment, so that we can store the michael@0: // correct absolute timestamp in the "media time" each incoming sample. michael@0: mSegmentStartTime = tStart; michael@0: return S_OK; michael@0: } michael@0: michael@0: } // namespace mozilla michael@0: