Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "AudioSinkInputPin.h"
8 #include "AudioSinkFilter.h"
9 #include "SampleSink.h"
10 #include "prlog.h"
12 #include <wmsdkidl.h>
14 using namespace mozilla::media;
16 namespace mozilla {
18 #ifdef PR_LOGGING
19 PRLogModuleInfo* GetDirectShowLog();
20 #define LOG(...) PR_LOG(GetDirectShowLog(), PR_LOG_DEBUG, (__VA_ARGS__))
21 #else
22 #define LOG(...)
23 #endif
25 AudioSinkInputPin::AudioSinkInputPin(wchar_t* aObjectName,
26 AudioSinkFilter* aFilter,
27 mozilla::CriticalSection* aLock,
28 HRESULT* aOutResult)
29 : BaseInputPin(aObjectName, aFilter, aLock, aOutResult, aObjectName),
30 mSegmentStartTime(0)
31 {
32 MOZ_COUNT_CTOR(AudioSinkInputPin);
33 mSampleSink = new SampleSink();
34 }
36 AudioSinkInputPin::~AudioSinkInputPin()
37 {
38 MOZ_COUNT_DTOR(AudioSinkInputPin);
39 }
41 HRESULT
42 AudioSinkInputPin::GetMediaType(int aPosition, MediaType* aOutMediaType)
43 {
44 NS_ENSURE_TRUE(aPosition >= 0, E_INVALIDARG);
45 NS_ENSURE_TRUE(aOutMediaType, E_POINTER);
47 if (aPosition > 0) {
48 return S_FALSE;
49 }
51 // Note: We set output as PCM, as IEEE_FLOAT only works when using the
52 // MP3 decoder as an MFT, and we can't do that while using DirectShow.
53 aOutMediaType->SetType(&MEDIATYPE_Audio);
54 aOutMediaType->SetSubtype(&MEDIASUBTYPE_PCM);
55 aOutMediaType->SetType(&FORMAT_WaveFormatEx);
56 aOutMediaType->SetTemporalCompression(FALSE);
58 return S_OK;
59 }
61 HRESULT
62 AudioSinkInputPin::CheckMediaType(const MediaType* aMediaType)
63 {
64 if (!aMediaType) {
65 return E_INVALIDARG;
66 }
68 GUID majorType = *aMediaType->Type();
69 if (majorType != MEDIATYPE_Audio && majorType != WMMEDIATYPE_Audio) {
70 return E_INVALIDARG;
71 }
73 if (*aMediaType->Subtype() != MEDIASUBTYPE_PCM) {
74 return E_INVALIDARG;
75 }
77 if (*aMediaType->FormatType() != FORMAT_WaveFormatEx) {
78 return E_INVALIDARG;
79 }
81 // We accept the media type, stash its layout format!
82 WAVEFORMATEX* wfx = (WAVEFORMATEX*)(aMediaType->pbFormat);
83 GetSampleSink()->SetAudioFormat(wfx);
85 return S_OK;
86 }
88 AudioSinkFilter*
89 AudioSinkInputPin::GetAudioSinkFilter()
90 {
91 return reinterpret_cast<AudioSinkFilter*>(mFilter);
92 }
94 SampleSink*
95 AudioSinkInputPin::GetSampleSink()
96 {
97 return mSampleSink;
98 }
100 HRESULT
101 AudioSinkInputPin::SetAbsoluteMediaTime(IMediaSample* aSample)
102 {
103 HRESULT hr;
104 REFERENCE_TIME start = 0, end = 0;
105 hr = aSample->GetTime(&start, &end);
106 NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
107 {
108 CriticalSectionAutoEnter lock(*mLock);
109 start += mSegmentStartTime;
110 end += mSegmentStartTime;
111 }
112 hr = aSample->SetMediaTime(&start, &end);
113 NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL);
114 return S_OK;
115 }
117 HRESULT
118 AudioSinkInputPin::Receive(IMediaSample* aSample )
119 {
120 HRESULT hr;
121 NS_ENSURE_TRUE(aSample, E_POINTER);
123 hr = BaseInputPin::Receive(aSample);
124 if (SUCCEEDED(hr) && hr != S_FALSE) { // S_FALSE == flushing
125 // Set the timestamp of the sample after being adjusted for
126 // seeking/segments in the "media time" attribute. When we seek,
127 // DirectShow starts a new "segment", and starts labeling samples
128 // from time=0 again, so we need to correct for this to get the
129 // actual timestamps after seeking.
130 hr = SetAbsoluteMediaTime(aSample);
131 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
132 hr = GetSampleSink()->Receive(aSample);
133 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
134 }
135 return S_OK;
136 }
138 TemporaryRef<IMediaSeeking>
139 AudioSinkInputPin::GetConnectedPinSeeking()
140 {
141 RefPtr<IPin> peer = GetConnected();
142 if (!peer)
143 return nullptr;
144 RefPtr<IMediaSeeking> seeking;
145 peer->QueryInterface(static_cast<IMediaSeeking**>(byRef(seeking)));
146 return seeking;
147 }
149 HRESULT
150 AudioSinkInputPin::BeginFlush()
151 {
152 HRESULT hr = media::BaseInputPin::BeginFlush();
153 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
155 GetSampleSink()->Flush();
157 return S_OK;
158 }
160 HRESULT
161 AudioSinkInputPin::EndFlush()
162 {
163 HRESULT hr = media::BaseInputPin::EndFlush();
164 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
166 // Reset the EOS flag, so that if we're called after a seek we still work.
167 GetSampleSink()->Reset();
169 return S_OK;
170 }
172 HRESULT
173 AudioSinkInputPin::EndOfStream(void)
174 {
175 HRESULT hr = media::BaseInputPin::EndOfStream();
176 if (FAILED(hr) || hr == S_FALSE) {
177 // Pin is stil flushing.
178 return hr;
179 }
180 GetSampleSink()->SetEOS();
182 return S_OK;
183 }
186 HRESULT
187 AudioSinkInputPin::NewSegment(REFERENCE_TIME tStart,
188 REFERENCE_TIME tStop,
189 double dRate)
190 {
191 CriticalSectionAutoEnter lock(*mLock);
192 // Record the start time of the new segment, so that we can store the
193 // correct absolute timestamp in the "media time" each incoming sample.
194 mSegmentStartTime = tStart;
195 return S_OK;
196 }
198 } // namespace mozilla