splitter.h
上传用户:sunbaby
上传日期:2013-05-31
资源大小:242k
文件大小:15k
源码类别:

mpeg/mp3

开发平台:

Visual C++

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1996 - 1997  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. /*  Parser class - this class defines the object that actually splits
  12.     out the data
  13. */
  14. /*  CBaseParser class
  15.     This is the object that determines the nature of the data
  16.     and actually splits the stream
  17. */
  18. /*  Simple stream reader class */
  19. class CParseReader
  20. {
  21. public:
  22.     /*  Set the position */
  23.     virtual HRESULT Length(LONGLONG *pLength) = 0;
  24.     virtual HRESULT SetPointer(LONGLONG) = 0;
  25.     virtual HRESULT Read(PBYTE pbData, DWORD cbData) = 0;
  26. };
  27. /*  Parsing reader from CAsyncReader */
  28. class CParseReaderFromAsync : public CParseReader
  29. {
  30. public:
  31.     CParseReaderFromAsync(IAsyncReader *pRdr) :
  32.         m_pReader(pRdr), m_llPos(0) {};
  33.     HRESULT Length(LONGLONG *pLength)
  34.     {
  35.         LONGLONG llAvailable;
  36.         return m_pReader->Length(pLength, &llAvailable);
  37.     }
  38.     HRESULT SetPointer(LONGLONG llPos)
  39.     {
  40.         m_llPos = 0;
  41.         return S_OK;
  42.     }
  43.     HRESULT Read(PBYTE pbData, DWORD cbData)
  44.     {
  45.         HRESULT hr = m_pReader->SyncRead(m_llPos, (LONG)cbData, pbData);
  46.         if (S_OK == hr) {
  47.             m_llPos += cbData;
  48.         }
  49.         return hr;
  50.     }
  51. private:
  52.     IAsyncReader *m_pReader;
  53.     LONGLONG      m_llPos;
  54. };
  55. class CParserNotify;
  56. class CBaseParser
  57. {
  58. public:
  59.     /*  Instantiate a parser
  60.         pNotify - to call back the calling object to create streams etc
  61.     */
  62.     CBaseParser(CParserNotify *pNotify,
  63.                 HRESULT *phr) : m_pNotify(pNotify) {};
  64.     /*  Initialize a parser
  65.         pmt     - type of stream if known - can be NULL
  66.         pRdr    - way to read the source medium - can be NULL
  67.     */
  68.     virtual HRESULT Init(
  69.         CParseReader *pRdr
  70.     ) = 0;
  71.     /*  Get the size and count of buffers preferred based on the
  72.         actual content
  73.     */
  74.     virtual void GetSizeAndCount(LONG *plSize, LONG *plCount) = 0;
  75.     /*  Call this to reinitialize for a new stream */
  76.     virtual void StreamReset() = 0;
  77.     /*  Call this to pass new stream data :
  78.         pbData        - pointer to data
  79.         lData         - length of data
  80.         plProcessed   - Amount of data consumed
  81.     */
  82.     virtual HRESULT Process(
  83.         const BYTE *pbData,
  84.         LONG lData,
  85.         LONG *plProcessed
  86.     ) = 0;
  87. protected:
  88.     CParserNotify * const m_pNotify;
  89. };
  90. /*  Parser calls back to create streams and spit out
  91.     buffers
  92. */
  93. class CStreamNotify;
  94. class CParserNotify
  95. {
  96. public:
  97.     /*  Create an output stream with type *pmt, notifications
  98.         to this stream passed to the **pStreamNotify object
  99.     */
  100.     virtual HRESULT CreateStream(
  101.         LPCWSTR pszName,
  102.         CStreamNotify **pStreamNotify) = 0;
  103. };
  104. class CStreamNotify
  105. {
  106. public:
  107.     virtual HRESULT SendSample(
  108.         const BYTE *pbData,
  109.         LONG lData,
  110.         REFERENCE_TIME rtStart,
  111.         BOOL bSync
  112.     ) = 0;
  113.     /*  Add a media type that's supported */
  114.     virtual HRESULT AddMediaType(CMediaType const *pmt) = 0;
  115.     /*  Return the current type */
  116.     virtual void CurrentMediaType(AM_MEDIA_TYPE *pmt) = 0;
  117. };
  118. /*  Splitter filter base classes */
  119. /*  Design :
  120.     A splitter filter will have 1 input pin and multiple output pins
  121.     CBaseSplitterFilter defines a base filter with 1 input pin and
  122.     a list of output pins.
  123.     This base class provides for pin enumeration, correct distribution
  124.     of EndOfStream and handling of errors.
  125.     The object structure is :
  126.                             IsA
  127.     CBaseSplitterFilter  <--------  CBaseFilter
  128.     Allocators:
  129.         This class relies on use CSequentialAllocator
  130.         The input pin is designed around CPullPin which hooks up
  131.         to IAsyncReader on the upstream output pin
  132. */
  133. class CBaseSplitterFilter;
  134. class CBaseParser;
  135. /*  Input pin stuff
  136.     The input pin deletes all the output pins when it's disconnected
  137.     On connection the output pins are created based on the media type
  138.     and possibly on the file content
  139.     The base class handles things like flushing and end of stream
  140. */
  141. /*  Special output pin type to handle lifetime */
  142. class CSplitterOutputPin : public CBaseOutputPin
  143. {
  144. public:
  145.     //  Constructor
  146.     CSplitterOutputPin(
  147.         CBaseSplitterFilter *pFilter,
  148.         HRESULT *phr,
  149.         LPCWSTR pName);
  150.     ~CSplitterOutputPin();
  151.     //  CUnknown methods
  152.     STDMETHODIMP_(ULONG) NonDelegatingAddRef();
  153.     STDMETHODIMP_(ULONG) NonDelegatingRelease();
  154.     //  CBaseOutputPin methods - we just override these to do
  155.     //  our own hack allocator
  156.     STDMETHOD(Notify)(IBaseFilter* pSender, Quality q);
  157.     // override this to set the buffer size and count. Return an error
  158.     // if the size/count is not to your liking
  159.     virtual HRESULT DecideBufferSize(
  160.                         IMemAllocator * pAlloc,
  161.                         ALLOCATOR_PROPERTIES * pProp);
  162.     // negotiate the allocator and its buffer size/count
  163.     // calls DecideBufferSize to call SetCountAndSize
  164.     virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);
  165.     // override this to control the connection
  166.     virtual HRESULT InitAllocator(IMemAllocator **ppAlloc);
  167.     // Check the media type proposed
  168.     HRESULT CheckMediaType(const CMediaType *);
  169.     // returns the preferred formats for a pin
  170.     HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);
  171.     // Send sample generated by parser
  172.     HRESULT SendSample(
  173.         const BYTE *pbData,
  174.         LONG lData,
  175.         REFERENCE_TIME rtStart,
  176.         BOOL bSync
  177.     );
  178.     /*  Add a media type */
  179.     HRESULT AddMediaType(
  180.         CMediaType const *pmt
  181.     );
  182.     HRESULT DeliverEndOfStream()
  183.     {
  184.         m_pOutputQueue->EOS();
  185.         return S_OK;
  186.     }
  187.     //  Delete our output queue on inactive
  188.     HRESULT Inactive()
  189.     {
  190.         HRESULT hr = CBaseOutputPin::Inactive();
  191.         if (FAILED(hr)) {
  192.             return hr;
  193.         }
  194.         delete m_pOutputQueue;
  195.         m_pOutputQueue = NULL;
  196.         return S_OK;
  197.     }
  198.     /*  Wrapper to call output queue to flush samples */
  199.     void SendAnyway()
  200.     {
  201.         if (NULL != m_pOutputQueue) {
  202.             m_pOutputQueue->SendAnyway();
  203.         }
  204.     }
  205.     //  Override Active and EndFlush to set the discontinuity flag
  206.     HRESULT Active()
  207.     {
  208.         m_bDiscontinuity = TRUE;
  209.         /*  If we're not connected we don't participate so it's OK */
  210.         if (!IsConnected()) {
  211.             return S_OK;
  212.         }
  213.         HRESULT hr = CBaseOutputPin::Active();
  214.         if (FAILED(hr)) {
  215.             return hr;
  216.         }
  217.         /*  Create our batch list */
  218.         ASSERT(m_pOutputQueue == NULL);
  219.         hr = S_OK;
  220.         m_pOutputQueue = new COutputQueue(GetConnected(), // input pin
  221.                                           &hr,            // return code
  222.                                           FALSE,          // Auto detect
  223.                                           TRUE,           // ignored
  224.                                           50,             // batch size
  225.                                           TRUE,           // exact batch
  226.                                           50);            // queue size
  227.         if (m_pOutputQueue == NULL) {
  228.             return E_OUTOFMEMORY;
  229.         }
  230.         if (FAILED(hr)) {
  231.             delete m_pOutputQueue;
  232.             m_pOutputQueue = NULL;
  233.         }
  234.         return hr;
  235.     }
  236.     HRESULT DeliverBeginFlush()
  237.     {
  238.         /*  We're already locked via the input pin */
  239.         m_pOutputQueue->BeginFlush();
  240.         return S_OK;
  241.     }
  242.     HRESULT DeliverEndFlush()
  243.     {
  244.         /*  We're already locked via the input pin */
  245.         m_bDiscontinuity = TRUE;
  246.         m_pOutputQueue->EndFlush();
  247.         return S_OK;
  248.     }
  249.     //  Get our notify object
  250.     CStreamNotify *GetNotify()
  251.     {
  252.         return &m_Notify;
  253.     }
  254. protected:
  255.     //  Get a pointer to our allocator
  256.     CSubAllocator *Allocator()
  257.     {
  258.         return (CSubAllocator *)m_pAllocator;
  259.     }
  260.     //  Get a properly cast pointer to our filter
  261.     CBaseSplitterFilter *Filter()
  262.     {
  263.         return (CBaseSplitterFilter *)m_pFilter;
  264.     }
  265. protected:
  266.     //  Stream notify stuff
  267.     class CImplStreamNotify : public CStreamNotify
  268.     {
  269.     public:
  270.         CImplStreamNotify(CSplitterOutputPin *pPin) : m_pPin(pPin) {}
  271.         HRESULT SendSample(
  272.             const BYTE *pbData,
  273.             LONG lData,
  274.             REFERENCE_TIME rtStart,
  275.             BOOL bSync
  276.         )
  277.         {
  278.             return m_pPin->SendSample(pbData, lData, rtStart, bSync);
  279.         }
  280.         HRESULT AddMediaType(CMediaType const *pmt)
  281.         {
  282.             return m_pPin->AddMediaType(pmt);
  283.         }
  284.         void CurrentMediaType(AM_MEDIA_TYPE *pmt)
  285.         {
  286.             m_pPin->ConnectionMediaType(pmt);
  287.         }
  288.     private:
  289.         CSplitterOutputPin * const m_pPin;
  290.     };
  291.     CImplStreamNotify  m_Notify;
  292.     //  Remember when to send NewSegment and discontinuity */
  293.     BOOL               m_bDiscontinuity;
  294.     //  Output queue
  295.     COutputQueue      *m_pOutputQueue;
  296.     //  List of media types we support
  297.     CGenericList<CMediaType> m_lTypes;
  298. };
  299. /*  Base CSplitterInputPin on CPullPin
  300. */
  301. class CSplitterInputPin : public CBaseInputPin
  302. {
  303. public:
  304.     CSplitterInputPin(
  305.         CBaseSplitterFilter *pFilter,
  306.         HRESULT *phr);
  307.     /*  NonDelegating IUnknown methods - we don't support IMemInputPin */
  308.     STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv)
  309.     {
  310.         if (riid == IID_IMemInputPin) {
  311.             return E_NOINTERFACE;
  312.         }
  313.         return CBaseInputPin::NonDelegatingQueryInterface(riid, ppv);
  314.     }
  315.     /*  IPin methods */
  316.     STDMETHODIMP EndOfStream();
  317.     STDMETHODIMP BeginFlush();
  318.     STDMETHODIMP EndFlush();
  319.     STDMETHODIMP Receive(IMediaSample *pSample);
  320.     /*  IMemInputPin methods */
  321.     /*  Where we're told which allocator we are using */
  322.     STDMETHODIMP NotifyAllocator(IMemAllocator *pAllocator)
  323.     {
  324.         if (pAllocator != (IMemAllocator *)m_pAllocator) {
  325.             return E_FAIL;
  326.         } else {
  327.             return S_OK;
  328.         }
  329.     }
  330.     /*  Say if we're blocking */
  331.     STDMETHODIMP ReceiveCanBlock()
  332.     {
  333.         return S_FALSE;
  334.     }
  335.     /*  CBasePin methods */
  336.     HRESULT BreakConnect();  //  Override to release puller
  337.     HRESULT CheckConnect(IPin *pPin);  //  Override to connect to puller
  338.     HRESULT Active();
  339.     HRESULT Inactive();
  340.     HRESULT CheckMediaType(const CMediaType *pmt);
  341.     HRESULT CompleteConnect(IPin *pReceivePin);
  342.     /*  Report filter from reader */
  343.     void NotifyError(HRESULT hr)
  344.     {
  345.         if (FAILED(hr)) {
  346.             m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
  347.         }
  348.         EndOfStream();
  349.     };
  350.     /*  Convenient way to get the allocator */
  351.     CSequentialAllocator *Allocator()
  352.     {
  353.         return (CSequentialAllocator *)m_pAllocator;
  354.     }
  355.     /*  Point to our media type */
  356.     CMediaType *MediaType()
  357.     {
  358.         return &m_mt;
  359.     }
  360.     /*  Return our async reader */
  361.     IAsyncReader *Reader()
  362.     {
  363.         IAsyncReader *pReader = m_puller.GetReader();
  364.         pReader->Release();
  365.         return pReader;
  366.     }
  367. private:
  368.     //  Get a properly case pointer to our filter
  369.     CBaseSplitterFilter *Filter()
  370.     {
  371.         return (CBaseSplitterFilter *)m_pFilter;
  372.     }
  373.     // class to pull data from IAsyncReader if we detect that interface
  374.     // on the output pin
  375.     class CImplPullPin : public CPullPin
  376.     {
  377.         // forward everything to containing pin
  378.         CSplitterInputPin * const m_pPin;
  379.     public:
  380.         CImplPullPin(CSplitterInputPin* pPin)
  381.           : m_pPin(pPin)
  382.         {
  383.         };
  384.         // forward this to the pin's IMemInputPin::Receive
  385.         HRESULT Receive(IMediaSample* pSample) {
  386.             return m_pPin->Receive(pSample);
  387.         };
  388.         // override this to handle end-of-stream
  389.         HRESULT EndOfStream(void) {
  390.             return m_pPin->EndOfStream();
  391.         };
  392.         // these errors have already been reported to the filtergraph
  393.         // by the upstream filter so ignore them
  394.         void OnError(HRESULT hr) {
  395.             // ignore VFW_E_WRONG_STATE since this happens normally
  396.             // during stopping and seeking
  397.             if (hr != VFW_E_WRONG_STATE) {
  398.                 m_pPin->NotifyError(hr);
  399.             }
  400.         };
  401.         // flush the pin and all downstream
  402.         HRESULT BeginFlush() {
  403.             return m_pPin->BeginFlush();
  404.         };
  405.         // Tell the next guy we've finished flushing
  406.         HRESULT EndFlush() {
  407.             return m_pPin->EndFlush();
  408.         };
  409.     };
  410.     CImplPullPin m_puller;
  411. };
  412. class CBaseSplitterFilter : public CBaseFilter
  413. {
  414. friend class CSplitterOutputPin;
  415. friend class CSplitterInputPin;
  416. public:
  417.     //  Constructor and destructor
  418.     CBaseSplitterFilter(
  419.        TCHAR *pName,
  420.        LPUNKNOWN pUnk,
  421.        REFCLSID rclsid,
  422.        HRESULT *phr);
  423.     ~CBaseSplitterFilter();
  424.     //  IMediaFilter methods - override these to manage locking
  425.     STDMETHODIMP Stop();
  426.     STDMETHODIMP Pause();
  427.     /*  Stream control stuff */
  428.     virtual HRESULT BeginFlush();
  429.     virtual HRESULT EndFlush();
  430.     virtual void    EndOfStream();
  431.     virtual HRESULT Receive(IMediaSample *pSample);
  432.     virtual HRESULT CheckInputType(const CMediaType *pmt) = 0;
  433.     virtual HRESULT CompleteConnect(IPin *pReceivePin);
  434.     //  Create the parser
  435.     virtual CBaseParser *CreateParser(
  436.         CParserNotify *pNotify,
  437.         CMediaType *pType) = 0;
  438.     //  CBaseFilter methods
  439.     int GetPinCount();     // 0 pins
  440.     CBasePin *GetPin(int iPin);
  441.     /*  Add a new output pin */
  442.     BOOL AddOutputPin(CSplitterOutputPin *pOutputPin);
  443.     /*  Destroy the output pins */
  444.     void DestroyOutputPins();
  445.     /*  Destroy the input pin */
  446.     void DestroyInputPin();
  447.     /*  Notify to create a new stream
  448.         Called back through CParseNotify
  449.     */
  450.     HRESULT CreateStream(
  451.         LPCWSTR         pszName,
  452.         CStreamNotify **ppStreamNotify
  453.     );
  454.     /*  Called when BreakConnect called on the input pin */
  455.     virtual void BreakConnect();
  456. protected:
  457.     /*  Utility to get the allocator */
  458.     CSequentialAllocator *Allocator()
  459.     {
  460.         return InputPin()->Allocator();
  461.     }
  462.     /*  Reset the states of the allocator and parser
  463.         ready to receive a new stream
  464.     */
  465.     void ResetAllocatorAndParser()
  466.     {
  467.         Allocator()->Flush();
  468.         m_pParser->StreamReset();
  469.     }
  470.     CSplitterInputPin *InputPin()
  471.     {
  472.         return (CSplitterInputPin *)m_pInput;
  473.     }
  474. protected:
  475.     //  Our input pin - created by derived classes
  476.     CBaseInputPin           *m_pInput;
  477.     //  Our output pin list - Derived classes append to this
  478.     CGenericList<CSplitterOutputPin> m_OutputPins;
  479.     //  Filter locking
  480.     CCritSec                 m_csFilter;
  481.     //  Streaming lock
  482.     CCritSec                 m_csStream;
  483.     //  Pin database lock
  484.     CCritSec                 m_csPins;
  485.     //  Parser - created when we're connected
  486.     CBaseParser             *m_pParser;
  487.     //  Parser notify - use member variable to avoid mulitple inheritance
  488.     class CImplParserNotify : public CParserNotify
  489.     {
  490.     public:
  491.         CImplParserNotify(CBaseSplitterFilter *pFilter) : m_pFilter(pFilter) {};
  492.         HRESULT CreateStream(
  493.             LPCWSTR         pszName,
  494.             CStreamNotify **ppStreamNotify
  495.         )
  496.         {
  497.             return m_pFilter->CreateStream(pszName, ppStreamNotify);
  498.         }
  499.     private:
  500.         CBaseSplitterFilter * const m_pFilter;
  501.     };
  502.     CImplParserNotify        m_Notify;
  503. };