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