content/media/directshow/SourceFilter.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

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

mercurial