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: 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: SampleSink::SampleSink() michael@0: : mMonitor("SampleSink"), michael@0: mIsFlushing(false), michael@0: mAtEOS(false) michael@0: { michael@0: MOZ_COUNT_CTOR(SampleSink); michael@0: } michael@0: michael@0: SampleSink::~SampleSink() michael@0: { michael@0: MOZ_COUNT_DTOR(SampleSink); michael@0: } michael@0: michael@0: void michael@0: SampleSink::SetAudioFormat(const WAVEFORMATEX* aInFormat) michael@0: { michael@0: NS_ENSURE_TRUE(aInFormat, ); michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: memcpy(&mAudioFormat, aInFormat, sizeof(WAVEFORMATEX)); michael@0: } michael@0: michael@0: void michael@0: SampleSink::GetAudioFormat(WAVEFORMATEX* aOutFormat) michael@0: { michael@0: MOZ_ASSERT(aOutFormat); michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: memcpy(aOutFormat, &mAudioFormat, sizeof(WAVEFORMATEX)); michael@0: } michael@0: michael@0: HRESULT michael@0: SampleSink::Receive(IMediaSample* aSample) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: michael@0: while (true) { michael@0: if (mIsFlushing) { michael@0: return S_FALSE; michael@0: } michael@0: if (!mSample) { michael@0: break; michael@0: } michael@0: if (mAtEOS) { michael@0: return E_UNEXPECTED; michael@0: } michael@0: // Wait until the consumer thread consumes the sample. michael@0: mon.Wait(); michael@0: } michael@0: michael@0: #ifdef PR_LOGGING michael@0: REFERENCE_TIME start = 0, end = 0; michael@0: HRESULT hr = aSample->GetMediaTime(&start, &end); michael@0: LOG("SampleSink::Receive() [%4.2lf-%4.2lf]", michael@0: (double)RefTimeToUsecs(start) / USECS_PER_S, michael@0: (double)RefTimeToUsecs(end) / USECS_PER_S); michael@0: #endif michael@0: michael@0: mSample = aSample; michael@0: // Notify the signal, to awaken the consumer thread in WaitForSample() michael@0: // if necessary. michael@0: mon.NotifyAll(); michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: SampleSink::Extract(RefPtr& aOutSample) michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: // Loop until we have a sample, or we should abort. michael@0: while (true) { michael@0: if (mIsFlushing) { michael@0: return S_FALSE; michael@0: } michael@0: if (mSample) { michael@0: break; michael@0: } michael@0: if (mAtEOS) { michael@0: // Order is important here, if we have a sample, we should return it michael@0: // before reporting EOS. michael@0: return E_UNEXPECTED; michael@0: } michael@0: // Wait until the producer thread gives us a sample. michael@0: mon.Wait(); michael@0: } michael@0: aOutSample = mSample; michael@0: michael@0: #ifdef PR_LOGGING michael@0: int64_t start = 0, end = 0; michael@0: mSample->GetMediaTime(&start, &end); michael@0: LOG("SampleSink::Extract() [%4.2lf-%4.2lf]", michael@0: (double)RefTimeToUsecs(start) / USECS_PER_S, michael@0: (double)RefTimeToUsecs(end) / USECS_PER_S); michael@0: #endif michael@0: michael@0: mSample = nullptr; michael@0: // Notify the signal, to awaken the producer thread in Receive() michael@0: // if necessary. michael@0: mon.NotifyAll(); michael@0: return S_OK; michael@0: } michael@0: michael@0: void michael@0: SampleSink::Flush() michael@0: { michael@0: LOG("SampleSink::Flush()"); michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: mIsFlushing = true; michael@0: mSample = nullptr; michael@0: mon.NotifyAll(); michael@0: } michael@0: michael@0: void michael@0: SampleSink::Reset() michael@0: { michael@0: LOG("SampleSink::Reset()"); michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: mIsFlushing = false; michael@0: mAtEOS = false; michael@0: } michael@0: michael@0: void michael@0: SampleSink::SetEOS() michael@0: { michael@0: LOG("SampleSink::SetEOS()"); michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: mAtEOS = true; michael@0: // Notify to unblock any threads waiting for samples in michael@0: // Extract() or Receive(). Now that we're at EOS, no more samples michael@0: // will come! michael@0: mon.NotifyAll(); michael@0: } michael@0: michael@0: bool michael@0: SampleSink::AtEOS() michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mMonitor); michael@0: return mAtEOS && !mSample; michael@0: } michael@0: michael@0: } // namespace mozilla michael@0: