/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AudioSinkInputPin.h" #include "AudioSinkFilter.h" #include "SampleSink.h" #include "mozilla/Logging.h" #include using namespace mozilla::media; namespace mozilla { static LazyLogModule gDirectShowLog("DirectShowDecoder"); #define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) AudioSinkInputPin::AudioSinkInputPin(wchar_t* aObjectName, AudioSinkFilter* aFilter, mozilla::CriticalSection* aLock, HRESULT* aOutResult) : BaseInputPin(aObjectName, aFilter, aLock, aOutResult, aObjectName), mSegmentStartTime(0) { MOZ_COUNT_CTOR(AudioSinkInputPin); mSampleSink = new SampleSink(); } AudioSinkInputPin::~AudioSinkInputPin() { MOZ_COUNT_DTOR(AudioSinkInputPin); } HRESULT AudioSinkInputPin::GetMediaType(int aPosition, MediaType* aOutMediaType) { NS_ENSURE_TRUE(aPosition >= 0, E_INVALIDARG); NS_ENSURE_TRUE(aOutMediaType, E_POINTER); if (aPosition > 0) { return S_FALSE; } // Note: We set output as PCM, as IEEE_FLOAT only works when using the // MP3 decoder as an MFT, and we can't do that while using DirectShow. aOutMediaType->SetType(&MEDIATYPE_Audio); aOutMediaType->SetSubtype(&MEDIASUBTYPE_PCM); aOutMediaType->SetType(&FORMAT_WaveFormatEx); aOutMediaType->SetTemporalCompression(FALSE); return S_OK; } HRESULT AudioSinkInputPin::CheckMediaType(const MediaType* aMediaType) { if (!aMediaType) { return E_INVALIDARG; } GUID majorType = *aMediaType->Type(); if (majorType != MEDIATYPE_Audio && majorType != WMMEDIATYPE_Audio) { return E_INVALIDARG; } if (*aMediaType->Subtype() != MEDIASUBTYPE_PCM) { return E_INVALIDARG; } if (*aMediaType->FormatType() != FORMAT_WaveFormatEx) { return E_INVALIDARG; } // We accept the media type, stash its layout format! WAVEFORMATEX* wfx = (WAVEFORMATEX*)(aMediaType->pbFormat); GetSampleSink()->SetAudioFormat(wfx); return S_OK; } AudioSinkFilter* AudioSinkInputPin::GetAudioSinkFilter() { return reinterpret_cast(mFilter); } SampleSink* AudioSinkInputPin::GetSampleSink() { return mSampleSink; } HRESULT AudioSinkInputPin::SetAbsoluteMediaTime(IMediaSample* aSample) { HRESULT hr; REFERENCE_TIME start = 0, end = 0; hr = aSample->GetTime(&start, &end); NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); { CriticalSectionAutoEnter lock(*mLock); start += mSegmentStartTime; end += mSegmentStartTime; } hr = aSample->SetMediaTime(&start, &end); NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); return S_OK; } HRESULT AudioSinkInputPin::Receive(IMediaSample* aSample ) { HRESULT hr; NS_ENSURE_TRUE(aSample, E_POINTER); hr = BaseInputPin::Receive(aSample); if (SUCCEEDED(hr) && hr != S_FALSE) { // S_FALSE == flushing // Set the timestamp of the sample after being adjusted for // seeking/segments in the "media time" attribute. When we seek, // DirectShow starts a new "segment", and starts labeling samples // from time=0 again, so we need to correct for this to get the // actual timestamps after seeking. hr = SetAbsoluteMediaTime(aSample); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); hr = GetSampleSink()->Receive(aSample); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); } return S_OK; } already_AddRefed AudioSinkInputPin::GetConnectedPinSeeking() { RefPtr peer = GetConnected(); if (!peer) return nullptr; RefPtr seeking; peer->QueryInterface(static_cast(getter_AddRefs(seeking))); return seeking.forget(); } HRESULT AudioSinkInputPin::BeginFlush() { HRESULT hr = media::BaseInputPin::BeginFlush(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); GetSampleSink()->Flush(); return S_OK; } HRESULT AudioSinkInputPin::EndFlush() { HRESULT hr = media::BaseInputPin::EndFlush(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Reset the EOS flag, so that if we're called after a seek we still work. GetSampleSink()->Reset(); return S_OK; } HRESULT AudioSinkInputPin::EndOfStream(void) { HRESULT hr = media::BaseInputPin::EndOfStream(); if (FAILED(hr) || hr == S_FALSE) { // Pin is stil flushing. return hr; } GetSampleSink()->SetEOS(); return S_OK; } HRESULT AudioSinkInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) { CriticalSectionAutoEnter lock(*mLock); // Record the start time of the new segment, so that we can store the // correct absolute timestamp in the "media time" each incoming sample. mSegmentStartTime = tStart; return S_OK; } } // namespace mozilla