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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "SourceFilter.h"
8 #include "MediaResource.h"
9 #include "mozilla/RefPtr.h"
10 #include "DirectShowUtils.h"
11 #include "MP3FrameParser.h"
12 #include "mozilla/Logging.h"
13 #include <algorithm>
14
15 using namespace mozilla::media;
16
17 namespace mozilla {
18
19 // Define to trace what's on...
20 //#define DEBUG_SOURCE_TRACE 1
21
22 #if defined (DEBUG_SOURCE_TRACE)
23 static LazyLogModule gDirectShowLog("DirectShowDecoder");
24 #define DIRECTSHOW_LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
25 #else
26 #define DIRECTSHOW_LOG(...)
27 #endif
28
29 static HRESULT
DoGetInterface(IUnknown * aUnknown,void ** aInterface)30 DoGetInterface(IUnknown* aUnknown, void** aInterface)
31 {
32 if (!aInterface)
33 return E_POINTER;
34 *aInterface = aUnknown;
35 aUnknown->AddRef();
36 return S_OK;
37 }
38
39 // Stores details of IAsyncReader::Request().
40 class ReadRequest {
41 public:
42
ReadRequest(IMediaSample * aSample,DWORD_PTR aDwUser,uint32_t aOffset,uint32_t aCount)43 ReadRequest(IMediaSample* aSample,
44 DWORD_PTR aDwUser,
45 uint32_t aOffset,
46 uint32_t aCount)
47 : mSample(aSample),
48 mDwUser(aDwUser),
49 mOffset(aOffset),
50 mCount(aCount)
51 {
52 MOZ_COUNT_CTOR(ReadRequest);
53 }
54
~ReadRequest()55 ~ReadRequest() {
56 MOZ_COUNT_DTOR(ReadRequest);
57 }
58
59 RefPtr<IMediaSample> mSample;
60 DWORD_PTR mDwUser;
61 uint32_t mOffset;
62 uint32_t mCount;
63 };
64
65 // A wrapper around media resource that presents only a partition of the
66 // underlying resource to the caller to use. The partition returned is from
67 // an offset to the end of stream, and this object deals with ensuring
68 // the offsets and lengths etc are translated from the reduced partition
69 // exposed to the caller, to the absolute offsets of the underlying stream.
70 class MediaResourcePartition {
71 public:
MediaResourcePartition(MediaResource * aResource,int64_t aDataStart)72 MediaResourcePartition(MediaResource* aResource,
73 int64_t aDataStart)
74 : mResource(aResource),
75 mDataOffset(aDataStart)
76 {}
77
GetLength()78 int64_t GetLength() {
79 int64_t len = mResource.GetLength();
80 if (len == -1) {
81 return len;
82 }
83 return std::max<int64_t>(0, len - mDataOffset);
84 }
ReadAt(int64_t aOffset,char * aBuffer,uint32_t aCount,uint32_t * aBytes)85 nsresult ReadAt(int64_t aOffset, char* aBuffer,
86 uint32_t aCount, uint32_t* aBytes)
87 {
88 return mResource.ReadAt(aOffset + mDataOffset,
89 aBuffer,
90 aCount,
91 aBytes);
92 }
GetCachedDataEnd()93 int64_t GetCachedDataEnd() {
94 int64_t tell = mResource.GetResource()->Tell();
95 int64_t dataEnd =
96 mResource.GetResource()->GetCachedDataEnd(tell) - mDataOffset;
97 return dataEnd;
98 }
99 private:
100 // MediaResource from which we read data.
101 MediaResourceIndex mResource;
102 int64_t mDataOffset;
103 };
104
105
106 // Output pin for SourceFilter, which implements IAsyncReader, to
107 // allow downstream filters to pull/read data from it. Downstream pins
108 // register to read data using Request(), and asynchronously wait for the
109 // reads to complete using WaitForNext(). They may also synchronously read
110 // using SyncRead(). This class is a delegate (tear off) of
111 // SourceFilter.
112 //
113 // We can expose only a segment of the MediaResource to the filter graph.
114 // This is used to strip off the ID3v2 tags from the stream, as DirectShow
115 // has trouble parsing some headers.
116 //
117 // Implements:
118 // * IAsyncReader
119 // * IPin
120 // * IQualityControl
121 // * IUnknown
122 //
123 class DECLSPEC_UUID("18e5cfb2-1015-440c-a65c-e63853235894")
124 OutputPin : public IAsyncReader,
125 public BasePin
126 {
127 public:
128
129 OutputPin(MediaResource* aMediaResource,
130 SourceFilter* aParent,
131 CriticalSection& aFilterLock,
132 int64_t aMP3DataStart);
133 virtual ~OutputPin();
134
135 // IUnknown
136 // Defer to ref counting to BasePin, which defers to owning nsBaseFilter.
AddRef()137 STDMETHODIMP_(ULONG) AddRef() override { return BasePin::AddRef(); }
Release()138 STDMETHODIMP_(ULONG) Release() override { return BasePin::Release(); }
139 STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override;
140
141 // BasePin Overrides.
142 // Determines if the pin accepts a specific media type.
143 HRESULT CheckMediaType(const MediaType* aMediaType) override;
144
145 // Retrieves a preferred media type, by index value.
146 HRESULT GetMediaType(int aPosition, MediaType* aMediaType) override;
147
148 // Releases the pin from a connection.
149 HRESULT BreakConnect(void) override;
150
151 // Determines whether a pin connection is suitable.
152 HRESULT CheckConnect(IPin* aPin) override;
153
154
155 // IAsyncReader overrides
156
157 // The RequestAllocator method requests an allocator during the
158 // pin connection.
159 STDMETHODIMP RequestAllocator(IMemAllocator* aPreferred,
160 ALLOCATOR_PROPERTIES* aProps,
161 IMemAllocator** aActual) override;
162
163 // The Request method queues an asynchronous request for data. Downstream
164 // will call WaitForNext() when they want to retrieve the result.
165 STDMETHODIMP Request(IMediaSample* aSample, DWORD_PTR aUserData) override;
166
167 // The WaitForNext method waits for the next pending read request
168 // to complete. This method fails if the graph is flushing.
169 // Defers to SyncRead/5.
170 STDMETHODIMP WaitForNext(DWORD aTimeout,
171 IMediaSample** aSamples,
172 DWORD_PTR* aUserData) override;
173
174 // The SyncReadAligned method performs a synchronous read. The method
175 // blocks until the request is completed. Defers to SyncRead/5. This
176 // method does not fail if the graph is flushing.
177 STDMETHODIMP SyncReadAligned(IMediaSample* aSample) override;
178
179 // The SyncRead method performs a synchronous read. The method blocks
180 // until the request is completed. Defers to SyncRead/5. This
181 // method does not fail if the graph is flushing.
182 STDMETHODIMP SyncRead(LONGLONG aPosition, LONG aLength, BYTE* aBuffer) override;
183
184 // The Length method retrieves the total length of the stream.
185 STDMETHODIMP Length(LONGLONG* aTotal, LONGLONG* aAvailable) override;
186
187 // IPin Overrides
188 STDMETHODIMP BeginFlush(void) override;
189 STDMETHODIMP EndFlush(void) override;
190
191 uint32_t GetAndResetBytesConsumedCount();
192
193 private:
194
195 // Protects thread-shared data/structures (mFlushCount, mPendingReads).
196 // WaitForNext() also waits on this monitor
197 CriticalSection& mPinLock;
198
199 // Signal used with mPinLock to implement WaitForNext().
200 Signal mSignal;
201
202 // The filter that owns us. Weak reference, as we're a delegate (tear off).
203 SourceFilter* mParentSource;
204
205 MediaResourcePartition mResource;
206
207 // Counter, inc'd in BeginFlush(), dec'd in EndFlush(). Calls to this can
208 // come from multiple threads and can interleave, hence the counter.
209 int32_t mFlushCount;
210
211 // Number of bytes that have been read from the output pin since the last
212 // time GetAndResetBytesConsumedCount() was called.
213 uint32_t mBytesConsumed;
214
215 // Deque of ReadRequest* for reads that are yet to be serviced.
216 // nsReadRequest's are stored on the heap, popper must delete them.
217 nsDeque mPendingReads;
218
219 // Flags if the downstream pin has QI'd for IAsyncReader. We refuse
220 // connection if they don't query, as it means they're assuming that we're
221 // a push filter, and we're not.
222 bool mQueriedForAsyncReader;
223
224 };
225
226 // For mingw __uuidof support
227 #ifdef __CRT_UUID_DECL
228 }
229 __CRT_UUID_DECL(mozilla::OutputPin, 0x18e5cfb2,0x1015,0x440c,0xa6,0x5c,0xe6,0x38,0x53,0x23,0x58,0x94);
230 namespace mozilla {
231 #endif
232
OutputPin(MediaResource * aResource,SourceFilter * aParent,CriticalSection & aFilterLock,int64_t aMP3DataStart)233 OutputPin::OutputPin(MediaResource* aResource,
234 SourceFilter* aParent,
235 CriticalSection& aFilterLock,
236 int64_t aMP3DataStart)
237 : BasePin(static_cast<BaseFilter*>(aParent),
238 &aFilterLock,
239 L"MozillaOutputPin",
240 PINDIR_OUTPUT),
241 mPinLock(aFilterLock),
242 mSignal(&mPinLock),
243 mParentSource(aParent),
244 mResource(aResource, aMP3DataStart),
245 mFlushCount(0),
246 mBytesConsumed(0),
247 mQueriedForAsyncReader(false)
248 {
249 MOZ_COUNT_CTOR(OutputPin);
250 DIRECTSHOW_LOG("OutputPin::OutputPin()");
251 }
252
~OutputPin()253 OutputPin::~OutputPin()
254 {
255 MOZ_COUNT_DTOR(OutputPin);
256 DIRECTSHOW_LOG("OutputPin::~OutputPin()");
257 }
258
259 HRESULT
BreakConnect()260 OutputPin::BreakConnect()
261 {
262 mQueriedForAsyncReader = false;
263 return BasePin::BreakConnect();
264 }
265
266 STDMETHODIMP
QueryInterface(REFIID aIId,void ** aInterface)267 OutputPin::QueryInterface(REFIID aIId, void** aInterface)
268 {
269 if (aIId == IID_IAsyncReader) {
270 mQueriedForAsyncReader = true;
271 return DoGetInterface(static_cast<IAsyncReader*>(this), aInterface);
272 }
273
274 if (aIId == __uuidof(OutputPin)) {
275 AddRef();
276 *aInterface = this;
277 return S_OK;
278 }
279
280 return BasePin::QueryInterface(aIId, aInterface);
281 }
282
283 HRESULT
CheckConnect(IPin * aPin)284 OutputPin::CheckConnect(IPin* aPin)
285 {
286 // Our connection is only suitable if the downstream pin knows
287 // that we're asynchronous (i.e. it queried for IAsyncReader).
288 return mQueriedForAsyncReader ? S_OK : S_FALSE;
289 }
290
291 HRESULT
CheckMediaType(const MediaType * aMediaType)292 OutputPin::CheckMediaType(const MediaType* aMediaType)
293 {
294 const MediaType *myMediaType = mParentSource->GetMediaType();
295
296 if (IsEqualGUID(aMediaType->majortype, myMediaType->majortype) &&
297 IsEqualGUID(aMediaType->subtype, myMediaType->subtype) &&
298 IsEqualGUID(aMediaType->formattype, myMediaType->formattype))
299 {
300 DIRECTSHOW_LOG("OutputPin::CheckMediaType() Match: major=%s minor=%s TC=%d FSS=%d SS=%u",
301 GetDirectShowGuidName(aMediaType->majortype),
302 GetDirectShowGuidName(aMediaType->subtype),
303 aMediaType->TemporalCompression(),
304 aMediaType->bFixedSizeSamples,
305 aMediaType->SampleSize());
306 return S_OK;
307 }
308
309 DIRECTSHOW_LOG("OutputPin::CheckMediaType() Failed to match: major=%s minor=%s TC=%d FSS=%d SS=%u",
310 GetDirectShowGuidName(aMediaType->majortype),
311 GetDirectShowGuidName(aMediaType->subtype),
312 aMediaType->TemporalCompression(),
313 aMediaType->bFixedSizeSamples,
314 aMediaType->SampleSize());
315 return S_FALSE;
316 }
317
318 HRESULT
GetMediaType(int aPosition,MediaType * aMediaType)319 OutputPin::GetMediaType(int aPosition, MediaType* aMediaType)
320 {
321 if (!aMediaType)
322 return E_POINTER;
323
324 if (aPosition == 0) {
325 aMediaType->Assign(mParentSource->GetMediaType());
326 return S_OK;
327 }
328 return VFW_S_NO_MORE_ITEMS;
329 }
330
331 static inline bool
IsPowerOf2(int32_t x)332 IsPowerOf2(int32_t x) {
333 return ((-x & x) != x);
334 }
335
336 STDMETHODIMP
RequestAllocator(IMemAllocator * aPreferred,ALLOCATOR_PROPERTIES * aProps,IMemAllocator ** aActual)337 OutputPin::RequestAllocator(IMemAllocator* aPreferred,
338 ALLOCATOR_PROPERTIES* aProps,
339 IMemAllocator** aActual)
340 {
341 // Require the downstream pin to suggest what they want...
342 if (!aPreferred) return E_POINTER;
343 if (!aProps) return E_POINTER;
344 if (!aActual) return E_POINTER;
345
346 // We only care about alignment - our allocator will reject anything
347 // which isn't power-of-2 aligned, so so try a 4-byte aligned allocator.
348 ALLOCATOR_PROPERTIES props;
349 memcpy(&props, aProps, sizeof(ALLOCATOR_PROPERTIES));
350 if (aProps->cbAlign == 0 || IsPowerOf2(aProps->cbAlign)) {
351 props.cbAlign = 4;
352 }
353
354 // Limit allocator's number of buffers. We know that the media will most
355 // likely be bound by network speed, not by decoding speed. We also
356 // store the incoming data in a Gecko stream, if we don't limit buffers
357 // here we'll end up duplicating a lot of storage. We must have enough
358 // space for audio key frames to fit in the first batch of buffers however,
359 // else pausing may fail for some downstream decoders.
360 if (props.cBuffers > BaseFilter::sMaxNumBuffers) {
361 props.cBuffers = BaseFilter::sMaxNumBuffers;
362 }
363
364 // The allocator properties that are actually used. We don't store
365 // this, we need it for SetProperties() below to succeed.
366 ALLOCATOR_PROPERTIES actualProps;
367 HRESULT hr;
368
369 if (aPreferred) {
370 // Play nice and prefer the downstream pin's preferred allocator.
371 hr = aPreferred->SetProperties(&props, &actualProps);
372 if (SUCCEEDED(hr)) {
373 aPreferred->AddRef();
374 *aActual = aPreferred;
375 return S_OK;
376 }
377 }
378
379 // Else downstream hasn't requested a specific allocator, so create one...
380
381 // Just create a default allocator. It's highly unlikely that we'll use
382 // this anyway, as most parsers insist on using their own allocators.
383 RefPtr<IMemAllocator> allocator;
384 hr = CoCreateInstance(CLSID_MemoryAllocator,
385 0,
386 CLSCTX_INPROC_SERVER,
387 IID_IMemAllocator,
388 getter_AddRefs(allocator));
389 if(FAILED(hr) || (allocator == nullptr)) {
390 NS_WARNING("Can't create our own DirectShow allocator.");
391 return hr;
392 }
393
394 // See if we can make it suitable
395 hr = allocator->SetProperties(&props, &actualProps);
396 if (SUCCEEDED(hr)) {
397 // We need to release our refcount on pAlloc, and addref
398 // it to pass a refcount to the caller - this is a net nothing.
399 allocator.forget(aActual);
400 return S_OK;
401 }
402
403 NS_WARNING("Failed to pick an allocator");
404 return hr;
405 }
406
407 STDMETHODIMP
Request(IMediaSample * aSample,DWORD_PTR aDwUser)408 OutputPin::Request(IMediaSample* aSample, DWORD_PTR aDwUser)
409 {
410 if (!aSample) return E_FAIL;
411
412 CriticalSectionAutoEnter lock(*mLock);
413 NS_ASSERTION(!mFlushCount, "Request() while flushing");
414
415 if (mFlushCount)
416 return VFW_E_WRONG_STATE;
417
418 REFERENCE_TIME refStart = 0, refEnd = 0;
419 if (FAILED(aSample->GetTime(&refStart, &refEnd))) {
420 NS_WARNING("Sample incorrectly timestamped");
421 return VFW_E_SAMPLE_TIME_NOT_SET;
422 }
423
424 // Convert reference time to bytes.
425 uint32_t start = (uint32_t)(refStart / 10000000);
426 uint32_t end = (uint32_t)(refEnd / 10000000);
427
428 uint32_t numBytes = end - start;
429
430 ReadRequest* request = new ReadRequest(aSample,
431 aDwUser,
432 start,
433 numBytes);
434 // Memory for |request| is free when it's popped from the completed
435 // reads list.
436
437 // Push this onto the queue of reads to be serviced.
438 mPendingReads.Push(request);
439
440 // Notify any threads blocked in WaitForNext() which are waiting for mPendingReads
441 // to become non-empty.
442 mSignal.Notify();
443
444 return S_OK;
445 }
446
447 STDMETHODIMP
WaitForNext(DWORD aTimeout,IMediaSample ** aOutSample,DWORD_PTR * aOutDwUser)448 OutputPin::WaitForNext(DWORD aTimeout,
449 IMediaSample** aOutSample,
450 DWORD_PTR* aOutDwUser)
451 {
452 NS_ASSERTION(aTimeout == 0 || aTimeout == INFINITE,
453 "Oops, we don't handle this!");
454
455 *aOutSample = nullptr;
456 *aOutDwUser = 0;
457
458 LONGLONG offset = 0;
459 LONG count = 0;
460 BYTE* buf = nullptr;
461
462 {
463 CriticalSectionAutoEnter lock(*mLock);
464
465 // Wait until there's a pending read to service.
466 while (aTimeout && mPendingReads.GetSize() == 0 && !mFlushCount) {
467 // Note: No need to guard against shutdown-during-wait here, as
468 // typically the thread doing the pull will have already called
469 // Request(), so we won't Wait() here anyway. SyncRead() will fail
470 // on shutdown.
471 mSignal.Wait();
472 }
473
474 nsAutoPtr<ReadRequest> request(reinterpret_cast<ReadRequest*>(mPendingReads.PopFront()));
475 if (!request)
476 return VFW_E_WRONG_STATE;
477
478 *aOutSample = request->mSample;
479 *aOutDwUser = request->mDwUser;
480
481 offset = request->mOffset;
482 count = request->mCount;
483 buf = nullptr;
484 request->mSample->GetPointer(&buf);
485 NS_ASSERTION(buf != nullptr, "Invalid buffer!");
486
487 if (mFlushCount) {
488 return VFW_E_TIMEOUT;
489 }
490 }
491
492 return SyncRead(offset, count, buf);
493 }
494
495 STDMETHODIMP
SyncReadAligned(IMediaSample * aSample)496 OutputPin::SyncReadAligned(IMediaSample* aSample)
497 {
498 {
499 // Ignore reads while flushing.
500 CriticalSectionAutoEnter lock(*mLock);
501 if (mFlushCount) {
502 return S_FALSE;
503 }
504 }
505
506 if (!aSample)
507 return E_FAIL;
508
509 REFERENCE_TIME lStart = 0, lEnd = 0;
510 if (FAILED(aSample->GetTime(&lStart, &lEnd))) {
511 NS_WARNING("Sample incorrectly timestamped");
512 return VFW_E_SAMPLE_TIME_NOT_SET;
513 }
514
515 // Convert reference time to bytes.
516 int32_t start = (int32_t)(lStart / 10000000);
517 int32_t end = (int32_t)(lEnd / 10000000);
518
519 int32_t numBytes = end - start;
520
521 // If the range extends off the end of stream, truncate to the end of stream
522 // as per IAsyncReader specificiation.
523 int64_t streamLength = mResource.GetLength();
524 if (streamLength != -1) {
525 // We know the exact length of the stream, fail if the requested offset
526 // is beyond it.
527 if (start > streamLength) {
528 return VFW_E_BADALIGN;
529 }
530
531 // If the end of the chunk to read is off the end of the stream,
532 // truncate it to the end of the stream.
533 if ((start + numBytes) > streamLength) {
534 numBytes = (uint32_t)(streamLength - start);
535 }
536 }
537
538 BYTE* buf=0;
539 aSample->GetPointer(&buf);
540
541 return SyncRead(start, numBytes, buf);
542 }
543
544 STDMETHODIMP
SyncRead(LONGLONG aPosition,LONG aLength,BYTE * aBuffer)545 OutputPin::SyncRead(LONGLONG aPosition,
546 LONG aLength,
547 BYTE* aBuffer)
548 {
549 MOZ_ASSERT(!NS_IsMainThread());
550 NS_ENSURE_TRUE(aPosition >= 0, E_FAIL);
551 NS_ENSURE_TRUE(aLength > 0, E_FAIL);
552 NS_ENSURE_TRUE(aBuffer, E_POINTER);
553
554 DIRECTSHOW_LOG("OutputPin::SyncRead(%lld, %d)", aPosition, aLength);
555 {
556 // Ignore reads while flushing.
557 CriticalSectionAutoEnter lock(*mLock);
558 if (mFlushCount) {
559 return S_FALSE;
560 }
561 }
562
563 uint32_t totalBytesRead = 0;
564 nsresult rv = mResource.ReadAt(aPosition,
565 reinterpret_cast<char*>(aBuffer),
566 aLength,
567 &totalBytesRead);
568 if (NS_FAILED(rv)) {
569 return E_FAIL;
570 }
571 if (totalBytesRead > 0) {
572 CriticalSectionAutoEnter lock(*mLock);
573 mBytesConsumed += totalBytesRead;
574 }
575 return (totalBytesRead == aLength) ? S_OK : S_FALSE;
576 }
577
578 STDMETHODIMP
Length(LONGLONG * aTotal,LONGLONG * aAvailable)579 OutputPin::Length(LONGLONG* aTotal, LONGLONG* aAvailable)
580 {
581 HRESULT hr = S_OK;
582 int64_t length = mResource.GetLength();
583 if (length == -1) {
584 hr = VFW_S_ESTIMATED;
585 // Don't have a length. Just lie, it seems to work...
586 *aTotal = INT32_MAX;
587 } else {
588 *aTotal = length;
589 }
590 if (aAvailable) {
591 *aAvailable = mResource.GetCachedDataEnd();
592 }
593
594 DIRECTSHOW_LOG("OutputPin::Length() len=%lld avail=%lld", *aTotal, *aAvailable);
595
596 return hr;
597 }
598
599 STDMETHODIMP
BeginFlush()600 OutputPin::BeginFlush()
601 {
602 CriticalSectionAutoEnter lock(*mLock);
603 mFlushCount++;
604 mSignal.Notify();
605 return S_OK;
606 }
607
608 STDMETHODIMP
EndFlush(void)609 OutputPin::EndFlush(void)
610 {
611 CriticalSectionAutoEnter lock(*mLock);
612 mFlushCount--;
613 return S_OK;
614 }
615
616 uint32_t
GetAndResetBytesConsumedCount()617 OutputPin::GetAndResetBytesConsumedCount()
618 {
619 CriticalSectionAutoEnter lock(*mLock);
620 uint32_t bytesConsumed = mBytesConsumed;
621 mBytesConsumed = 0;
622 return bytesConsumed;
623 }
624
SourceFilter(const GUID & aMajorType,const GUID & aSubType)625 SourceFilter::SourceFilter(const GUID& aMajorType,
626 const GUID& aSubType)
627 : BaseFilter(L"MozillaDirectShowSource", __uuidof(SourceFilter))
628 {
629 MOZ_COUNT_CTOR(SourceFilter);
630 mMediaType.majortype = aMajorType;
631 mMediaType.subtype = aSubType;
632
633 DIRECTSHOW_LOG("SourceFilter Constructor(%s, %s)",
634 GetDirectShowGuidName(aMajorType),
635 GetDirectShowGuidName(aSubType));
636 }
637
~SourceFilter()638 SourceFilter::~SourceFilter()
639 {
640 MOZ_COUNT_DTOR(SourceFilter);
641 DIRECTSHOW_LOG("SourceFilter Destructor()");
642 }
643
644 BasePin*
GetPin(int n)645 SourceFilter::GetPin(int n)
646 {
647 if (n == 0) {
648 NS_ASSERTION(mOutputPin != 0, "GetPin with no pin!");
649 return static_cast<BasePin*>(mOutputPin);
650 } else {
651 return nullptr;
652 }
653 }
654
655 // Get's the media type we're supplying.
656 const MediaType*
GetMediaType() const657 SourceFilter::GetMediaType() const
658 {
659 return &mMediaType;
660 }
661
662 nsresult
Init(MediaResource * aResource,int64_t aMP3Offset)663 SourceFilter::Init(MediaResource* aResource, int64_t aMP3Offset)
664 {
665 DIRECTSHOW_LOG("SourceFilter::Init()");
666
667 mOutputPin = new OutputPin(aResource,
668 this,
669 mLock,
670 aMP3Offset);
671 NS_ENSURE_TRUE(mOutputPin != nullptr, NS_ERROR_FAILURE);
672
673 return NS_OK;
674 }
675
676 uint32_t
GetAndResetBytesConsumedCount()677 SourceFilter::GetAndResetBytesConsumedCount()
678 {
679 return mOutputPin->GetAndResetBytesConsumedCount();
680 }
681
682
683 } // namespace mozilla
684