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/. */
6
7 #include "SampleSink.h"
8 #include "AudioSinkFilter.h"
9 #include "AudioSinkInputPin.h"
10 #include "VideoUtils.h"
11 #include "mozilla/Logging.h"
12
13
14 #include <initguid.h>
15 #include <wmsdkidl.h>
16
17 #define DELETE_RESET(p) { delete (p) ; (p) = nullptr ;}
18
19 DEFINE_GUID(CLSID_MozAudioSinkFilter, 0x1872d8c8, 0xea8d, 0x4c34, 0xae, 0x96, 0x69, 0xde,
20 0xf1, 0x33, 0x7b, 0x33);
21
22 using namespace mozilla::media;
23
24 namespace mozilla {
25
26 static LazyLogModule gDirectShowLog("DirectShowDecoder");
27 #define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
28
AudioSinkFilter(const wchar_t * aObjectName,HRESULT * aOutResult)29 AudioSinkFilter::AudioSinkFilter(const wchar_t* aObjectName, HRESULT* aOutResult)
30 : BaseFilter(aObjectName, CLSID_MozAudioSinkFilter),
31 mFilterCritSec("AudioSinkFilter::mFilterCritSec")
32 {
33 (*aOutResult) = S_OK;
34 mInputPin = new AudioSinkInputPin(L"AudioSinkInputPin",
35 this,
36 &mFilterCritSec,
37 aOutResult);
38 }
39
~AudioSinkFilter()40 AudioSinkFilter::~AudioSinkFilter()
41 {
42 }
43
44 int
GetPinCount()45 AudioSinkFilter::GetPinCount()
46 {
47 return 1;
48 }
49
50 BasePin*
GetPin(int aIndex)51 AudioSinkFilter::GetPin(int aIndex)
52 {
53 CriticalSectionAutoEnter lockFilter(mFilterCritSec);
54 return (aIndex == 0) ? static_cast<BasePin*>(mInputPin) : nullptr;
55 }
56
57 HRESULT
Pause()58 AudioSinkFilter::Pause()
59 {
60 CriticalSectionAutoEnter lockFilter(mFilterCritSec);
61 if (mState == State_Stopped) {
62 // Change the state, THEN activate the input pin.
63 mState = State_Paused;
64 if (mInputPin && mInputPin->IsConnected()) {
65 mInputPin->Active();
66 }
67 } else if (mState == State_Running) {
68 mState = State_Paused;
69 }
70 return S_OK;
71 }
72
73 HRESULT
Stop()74 AudioSinkFilter::Stop()
75 {
76 CriticalSectionAutoEnter lockFilter(mFilterCritSec);
77 mState = State_Stopped;
78 if (mInputPin) {
79 mInputPin->Inactive();
80 }
81
82 GetSampleSink()->Flush();
83
84 return S_OK;
85 }
86
87 HRESULT
Run(REFERENCE_TIME tStart)88 AudioSinkFilter::Run(REFERENCE_TIME tStart)
89 {
90 LOG("AudioSinkFilter::Run(%lld) [%4.2lf]",
91 RefTimeToUsecs(tStart),
92 double(RefTimeToUsecs(tStart)) / USECS_PER_S);
93 return media::BaseFilter::Run(tStart);
94 }
95
96 HRESULT
GetClassID(OUT CLSID * pCLSID)97 AudioSinkFilter::GetClassID( OUT CLSID * pCLSID )
98 {
99 (* pCLSID) = CLSID_MozAudioSinkFilter;
100 return S_OK;
101 }
102
103 HRESULT
QueryInterface(REFIID aIId,void ** aInterface)104 AudioSinkFilter::QueryInterface(REFIID aIId, void **aInterface)
105 {
106 if (aIId == IID_IMediaSeeking) {
107 *aInterface = static_cast<IMediaSeeking*>(this);
108 AddRef();
109 return S_OK;
110 }
111 return mozilla::media::BaseFilter::QueryInterface(aIId, aInterface);
112 }
113
114 ULONG
AddRef()115 AudioSinkFilter::AddRef()
116 {
117 return ::InterlockedIncrement(&mRefCnt);
118 }
119
120 ULONG
Release()121 AudioSinkFilter::Release()
122 {
123 unsigned long newRefCnt = ::InterlockedDecrement(&mRefCnt);
124 if (!newRefCnt) {
125 delete this;
126 }
127 return newRefCnt;
128 }
129
130 SampleSink*
GetSampleSink()131 AudioSinkFilter::GetSampleSink()
132 {
133 return mInputPin->GetSampleSink();
134 }
135
136
137 // IMediaSeeking implementation.
138 //
139 // Calls to IMediaSeeking are forwarded to the output pin that the
140 // AudioSinkInputPin is connected to, i.e. upstream towards the parser and
141 // source filters, which actually implement seeking.
142 #define ENSURE_CONNECTED_PIN_SEEKING \
143 if (!mInputPin) { \
144 return E_NOTIMPL; \
145 } \
146 RefPtr<IMediaSeeking> pinSeeking = mInputPin->GetConnectedPinSeeking(); \
147 if (!pinSeeking) { \
148 return E_NOTIMPL; \
149 }
150
151 HRESULT
GetCapabilities(DWORD * aCapabilities)152 AudioSinkFilter::GetCapabilities(DWORD* aCapabilities)
153 {
154 ENSURE_CONNECTED_PIN_SEEKING
155 return pinSeeking->GetCapabilities(aCapabilities);
156 }
157
158 HRESULT
CheckCapabilities(DWORD * aCapabilities)159 AudioSinkFilter::CheckCapabilities(DWORD* aCapabilities)
160 {
161 ENSURE_CONNECTED_PIN_SEEKING
162 return pinSeeking->CheckCapabilities(aCapabilities);
163 }
164
165 HRESULT
IsFormatSupported(const GUID * aFormat)166 AudioSinkFilter::IsFormatSupported(const GUID* aFormat)
167 {
168 ENSURE_CONNECTED_PIN_SEEKING
169 return pinSeeking->IsFormatSupported(aFormat);
170 }
171
172 HRESULT
QueryPreferredFormat(GUID * aFormat)173 AudioSinkFilter::QueryPreferredFormat(GUID* aFormat)
174 {
175 ENSURE_CONNECTED_PIN_SEEKING
176 return pinSeeking->QueryPreferredFormat(aFormat);
177 }
178
179 HRESULT
GetTimeFormat(GUID * aFormat)180 AudioSinkFilter::GetTimeFormat(GUID* aFormat)
181 {
182 ENSURE_CONNECTED_PIN_SEEKING
183 return pinSeeking->GetTimeFormat(aFormat);
184 }
185
186 HRESULT
IsUsingTimeFormat(const GUID * aFormat)187 AudioSinkFilter::IsUsingTimeFormat(const GUID* aFormat)
188 {
189 ENSURE_CONNECTED_PIN_SEEKING
190 return pinSeeking->IsUsingTimeFormat(aFormat);
191 }
192
193 HRESULT
SetTimeFormat(const GUID * aFormat)194 AudioSinkFilter::SetTimeFormat(const GUID* aFormat)
195 {
196 ENSURE_CONNECTED_PIN_SEEKING
197 return pinSeeking->SetTimeFormat(aFormat);
198 }
199
200 HRESULT
GetDuration(LONGLONG * aDuration)201 AudioSinkFilter::GetDuration(LONGLONG* aDuration)
202 {
203 ENSURE_CONNECTED_PIN_SEEKING
204 return pinSeeking->GetDuration(aDuration);
205 }
206
207 HRESULT
GetStopPosition(LONGLONG * aStop)208 AudioSinkFilter::GetStopPosition(LONGLONG* aStop)
209 {
210 ENSURE_CONNECTED_PIN_SEEKING
211 return pinSeeking->GetStopPosition(aStop);
212 }
213
214 HRESULT
GetCurrentPosition(LONGLONG * aCurrent)215 AudioSinkFilter::GetCurrentPosition(LONGLONG* aCurrent)
216 {
217 ENSURE_CONNECTED_PIN_SEEKING
218 return pinSeeking->GetCurrentPosition(aCurrent);
219 }
220
221 HRESULT
ConvertTimeFormat(LONGLONG * aTarget,const GUID * aTargetFormat,LONGLONG aSource,const GUID * aSourceFormat)222 AudioSinkFilter::ConvertTimeFormat(LONGLONG* aTarget,
223 const GUID* aTargetFormat,
224 LONGLONG aSource,
225 const GUID* aSourceFormat)
226 {
227 ENSURE_CONNECTED_PIN_SEEKING
228 return pinSeeking->ConvertTimeFormat(aTarget,
229 aTargetFormat,
230 aSource,
231 aSourceFormat);
232 }
233
234 HRESULT
SetPositions(LONGLONG * aCurrent,DWORD aCurrentFlags,LONGLONG * aStop,DWORD aStopFlags)235 AudioSinkFilter::SetPositions(LONGLONG* aCurrent,
236 DWORD aCurrentFlags,
237 LONGLONG* aStop,
238 DWORD aStopFlags)
239 {
240 ENSURE_CONNECTED_PIN_SEEKING
241 return pinSeeking->SetPositions(aCurrent,
242 aCurrentFlags,
243 aStop,
244 aStopFlags);
245 }
246
247 HRESULT
GetPositions(LONGLONG * aCurrent,LONGLONG * aStop)248 AudioSinkFilter::GetPositions(LONGLONG* aCurrent,
249 LONGLONG* aStop)
250 {
251 ENSURE_CONNECTED_PIN_SEEKING
252 return pinSeeking->GetPositions(aCurrent, aStop);
253 }
254
255 HRESULT
GetAvailable(LONGLONG * aEarliest,LONGLONG * aLatest)256 AudioSinkFilter::GetAvailable(LONGLONG* aEarliest,
257 LONGLONG* aLatest)
258 {
259 ENSURE_CONNECTED_PIN_SEEKING
260 return pinSeeking->GetAvailable(aEarliest, aLatest);
261 }
262
263 HRESULT
SetRate(double aRate)264 AudioSinkFilter::SetRate(double aRate)
265 {
266 ENSURE_CONNECTED_PIN_SEEKING
267 return pinSeeking->SetRate(aRate);
268 }
269
270 HRESULT
GetRate(double * aRate)271 AudioSinkFilter::GetRate(double* aRate)
272 {
273 ENSURE_CONNECTED_PIN_SEEKING
274 return pinSeeking->GetRate(aRate);
275 }
276
277 HRESULT
GetPreroll(LONGLONG * aPreroll)278 AudioSinkFilter::GetPreroll(LONGLONG* aPreroll)
279 {
280 ENSURE_CONNECTED_PIN_SEEKING
281 return pinSeeking->GetPreroll(aPreroll);
282 }
283
284 } // namespace mozilla
285
286