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