src/3rdparty/phonon/ds9/qpin.cpp
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /*  This file is part of the KDE project.
       
     2 
       
     3 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 
       
     5 This library is free software: you can redistribute it and/or modify
       
     6 it under the terms of the GNU Lesser General Public License as published by
       
     7 the Free Software Foundation, either version 2.1 or 3 of the License.
       
     8 
       
     9 This library is distributed in the hope that it will be useful,
       
    10 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 GNU Lesser General Public License for more details.
       
    13 
       
    14 You should have received a copy of the GNU Lesser General Public License
       
    15 along with this library.  If not, see <http://www.gnu.org/licenses/>.
       
    16 */
       
    17 
       
    18 #include "qbasefilter.h"
       
    19 #include "qpin.h"
       
    20 #include "compointer.h"
       
    21 
       
    22 #include <QtCore/QMutex>
       
    23 
       
    24 QT_BEGIN_NAMESPACE
       
    25 
       
    26 namespace Phonon
       
    27 {
       
    28     namespace DS9
       
    29     {
       
    30 
       
    31         static const AM_MEDIA_TYPE defaultMediaType = { MEDIATYPE_NULL, MEDIASUBTYPE_NULL, TRUE, FALSE, 1, GUID_NULL, 0, 0, 0};
       
    32 
       
    33         class QEnumMediaTypes : public IEnumMediaTypes
       
    34         {
       
    35         public:
       
    36             QEnumMediaTypes(QPin *pin) :  m_refCount(1), m_pin(pin), m_index(0)
       
    37             {
       
    38                 m_pin->AddRef();
       
    39             }
       
    40 
       
    41             ~QEnumMediaTypes()
       
    42             {
       
    43                 m_pin->Release();
       
    44             }
       
    45 
       
    46             STDMETHODIMP QueryInterface(const IID &iid,void **out)
       
    47             {
       
    48                 if (!out) {
       
    49                     return E_POINTER;
       
    50                 }
       
    51 
       
    52                 HRESULT hr = S_OK;
       
    53                 if (iid == IID_IEnumMediaTypes) {
       
    54                     *out = static_cast<IEnumMediaTypes*>(this);
       
    55                 } else if (iid == IID_IUnknown) {
       
    56                     *out = static_cast<IUnknown*>(this);
       
    57                 } else {
       
    58                     *out = 0;
       
    59                     hr = E_NOINTERFACE;
       
    60                 }
       
    61 
       
    62                 if (hr == S_OK) {
       
    63                     AddRef();
       
    64                 }
       
    65                 return hr;
       
    66             }
       
    67 
       
    68             STDMETHODIMP_(ULONG) AddRef()
       
    69             {
       
    70                 return InterlockedIncrement(&m_refCount);
       
    71             }
       
    72 
       
    73             STDMETHODIMP_(ULONG) Release()
       
    74             {
       
    75                 ULONG refCount = InterlockedDecrement(&m_refCount);
       
    76                 if (refCount == 0) {
       
    77                     delete this;
       
    78                 }
       
    79 
       
    80                 return refCount;
       
    81             }
       
    82 
       
    83             STDMETHODIMP Next(ULONG count, AM_MEDIA_TYPE **out, ULONG *fetched)
       
    84             {
       
    85                 QMutexLocker locker(&m_mutex);
       
    86                 if (!out) {
       
    87                     return E_POINTER;
       
    88                 }
       
    89 
       
    90                 if (!fetched && count > 1) {
       
    91                     return E_INVALIDARG;
       
    92                 }
       
    93 
       
    94                 uint nbFetched = 0;
       
    95                 while (nbFetched < count && m_index < m_pin->mediaTypes().count()) {
       
    96                     //the caller will deallocate the memory
       
    97                     *out = static_cast<AM_MEDIA_TYPE *>(::CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)));
       
    98                     const AM_MEDIA_TYPE original = m_pin->mediaTypes().at(m_index);
       
    99                     **out = QPin::copyMediaType(original);
       
   100                     nbFetched++;
       
   101                     m_index++;
       
   102                     out++;
       
   103                 }
       
   104 
       
   105                 if (fetched) {
       
   106                     *fetched = nbFetched;
       
   107                 }
       
   108 
       
   109                 return nbFetched == count ? S_OK : S_FALSE;
       
   110             }
       
   111 
       
   112             STDMETHODIMP Skip(ULONG count)
       
   113             {
       
   114                 QMutexLocker locker(&m_mutex);
       
   115                 m_index = qMin(m_index + int(count), m_pin->mediaTypes().count());
       
   116                 return  (m_index == m_pin->mediaTypes().count()) ? S_FALSE : S_OK;
       
   117             }
       
   118 
       
   119             STDMETHODIMP Reset()
       
   120             {
       
   121                 QMutexLocker locker(&m_mutex);
       
   122                 m_index = 0;
       
   123                 return S_OK;
       
   124             }
       
   125 
       
   126             STDMETHODIMP Clone(IEnumMediaTypes **out)
       
   127             {
       
   128                 QMutexLocker locker(&m_mutex);
       
   129                 if (!out) {
       
   130                     return E_POINTER;
       
   131                 }
       
   132 
       
   133                 *out = new QEnumMediaTypes(m_pin);
       
   134                 (*out)->Skip(m_index);
       
   135                 return S_OK;
       
   136             }
       
   137 
       
   138 
       
   139         private:
       
   140             LONG m_refCount;
       
   141             QPin *m_pin;
       
   142             int m_index;
       
   143             QMutex m_mutex;
       
   144         };
       
   145 
       
   146 
       
   147         QPin::QPin(QBaseFilter *parent, PIN_DIRECTION dir, const QVector<AM_MEDIA_TYPE> &mt) :
       
   148             m_parent(parent), m_flushing(false), m_refCount(1),  m_connected(0),
       
   149             m_direction(dir), m_mediaTypes(mt), m_connectedType(defaultMediaType),
       
   150             m_memAlloc(0)
       
   151         {
       
   152             Q_ASSERT(m_parent);
       
   153             m_parent->addPin(this);
       
   154         }
       
   155 
       
   156         QPin::~QPin()
       
   157         {
       
   158             m_parent->removePin(this);
       
   159             setMemoryAllocator(0);
       
   160             freeMediaType(m_connectedType);
       
   161         }
       
   162 
       
   163         //reimplementation from IUnknown
       
   164         STDMETHODIMP QPin::QueryInterface(REFIID iid, void**out)
       
   165         {
       
   166             if (!out) {
       
   167                 return E_POINTER;
       
   168             }
       
   169 
       
   170             HRESULT hr = S_OK;
       
   171 
       
   172             if (iid == IID_IPin) {
       
   173                 *out = static_cast<IPin*>(this);
       
   174             } else if (iid == IID_IUnknown) {
       
   175                 *out = static_cast<IUnknown*>(this);
       
   176             } else if (m_direction == PINDIR_OUTPUT && (iid == IID_IMediaSeeking || iid == IID_IMediaPosition)) {
       
   177                 return m_parent->QueryInterface(iid, out);
       
   178             } else {
       
   179                 *out = 0;
       
   180                 hr = E_NOINTERFACE;
       
   181             }
       
   182 
       
   183             if (hr == S_OK) {
       
   184                 AddRef();
       
   185             }
       
   186             return hr;
       
   187         }
       
   188 
       
   189         STDMETHODIMP_(ULONG) QPin::AddRef()
       
   190         {
       
   191             return InterlockedIncrement(&m_refCount);
       
   192         }
       
   193 
       
   194         STDMETHODIMP_(ULONG) QPin::Release()
       
   195         {
       
   196             ULONG refCount = InterlockedDecrement(&m_refCount);
       
   197             if (refCount == 0) {
       
   198                 delete this;
       
   199             }
       
   200 
       
   201             return refCount;
       
   202         }
       
   203 
       
   204         //this is called on the input pins
       
   205         STDMETHODIMP QPin::ReceiveConnection(IPin *pin, const AM_MEDIA_TYPE *type)
       
   206         {
       
   207             if (!pin ||!type) {
       
   208                 return E_POINTER;
       
   209             }
       
   210 
       
   211             if (connected()) {
       
   212                 return VFW_E_ALREADY_CONNECTED;
       
   213             }
       
   214 
       
   215             if (filterState() != State_Stopped) {
       
   216                 return VFW_E_NOT_STOPPED;
       
   217             }
       
   218 
       
   219             if (QueryAccept(type) != S_OK) {
       
   220                 return VFW_E_TYPE_NOT_ACCEPTED;
       
   221             }
       
   222 
       
   223             setConnected(pin);
       
   224             setConnectedType(*type);
       
   225 
       
   226             return S_OK;
       
   227         }
       
   228 
       
   229         //this is called on the output pins
       
   230         STDMETHODIMP QPin::Connect(IPin *pin, const AM_MEDIA_TYPE *type)
       
   231         {
       
   232             if (!pin) {
       
   233                 return E_POINTER;
       
   234             }
       
   235 
       
   236             if (connected()) {
       
   237                 return VFW_E_ALREADY_CONNECTED;
       
   238             }
       
   239 
       
   240             if (filterState() != State_Stopped) {
       
   241                 return VFW_E_NOT_STOPPED;
       
   242             }
       
   243 
       
   244             HRESULT hr = S_OK;
       
   245 
       
   246             setConnected(pin);
       
   247             if (!type) {
       
   248 
       
   249                 //let(s first try the output pin's mediaTypes
       
   250                 if (checkOutputMediaTypesConnection(pin) != S_OK &&
       
   251                     checkOwnMediaTypesConnection(pin) != S_OK) {
       
   252                         hr = VFW_E_NO_ACCEPTABLE_TYPES;
       
   253                 }
       
   254             } else if (QueryAccept(type) == S_OK) {
       
   255                 setConnectedType(*type);
       
   256                 hr = pin->ReceiveConnection(this, type);
       
   257             } else {
       
   258                 hr = VFW_E_TYPE_NOT_ACCEPTED;
       
   259             }
       
   260 
       
   261             if (FAILED(hr)) {
       
   262                 setConnected(0);
       
   263                 setConnectedType(defaultMediaType);
       
   264             } else {
       
   265                 ComPointer<IMemInputPin> input(pin, IID_IMemInputPin);
       
   266                 if (input) {
       
   267                     ComPointer<IMemAllocator> alloc;
       
   268                     input->GetAllocator(alloc.pparam());
       
   269                     if (alloc) {
       
   270                         //be default we take the allocator from the input pin
       
   271                         //we have no reason to force using our own
       
   272                         setMemoryAllocator(alloc);
       
   273                     }
       
   274                 }
       
   275                 if (memoryAllocator() == 0) {
       
   276                     ALLOCATOR_PROPERTIES prop;
       
   277                     if (input && input->GetAllocatorRequirements(&prop) == S_OK) {
       
   278                         createDefaultMemoryAllocator(&prop);
       
   279                     } else {
       
   280                         createDefaultMemoryAllocator();
       
   281                     }
       
   282                 }
       
   283 
       
   284                 Q_ASSERT(memoryAllocator() != 0);
       
   285                 if (input) {
       
   286                     input->NotifyAllocator(memoryAllocator(), TRUE); //TRUE is arbitrarily chosen here
       
   287                 }
       
   288 
       
   289             }
       
   290 
       
   291             return hr;
       
   292         }
       
   293 
       
   294         STDMETHODIMP QPin::Disconnect()
       
   295         {
       
   296             if (!connected()) {
       
   297                 return S_FALSE;
       
   298             }
       
   299 
       
   300             if (filterState() != State_Stopped) {
       
   301                 return VFW_E_NOT_STOPPED;
       
   302             }
       
   303 
       
   304             setConnected(0);
       
   305             setConnectedType(defaultMediaType);
       
   306             setMemoryAllocator(0);
       
   307             return S_OK;
       
   308         }
       
   309 
       
   310         STDMETHODIMP QPin::ConnectedTo(IPin **other)
       
   311         {
       
   312             if (!other) {
       
   313                 return E_POINTER;
       
   314             }
       
   315 
       
   316             *other = connected(true);
       
   317             if (!(*other)) {
       
   318                 return VFW_E_NOT_CONNECTED;
       
   319             }
       
   320 
       
   321             return S_OK;
       
   322         }
       
   323 
       
   324         STDMETHODIMP QPin::ConnectionMediaType(AM_MEDIA_TYPE *type)
       
   325         {
       
   326             QMutexLocker locker(&m_mutex);
       
   327             if (!type) {
       
   328                 return E_POINTER;
       
   329             }
       
   330 
       
   331             *type = copyMediaType(m_connectedType);
       
   332             if (!m_connected) {
       
   333                 return VFW_E_NOT_CONNECTED;
       
   334             } else {
       
   335                 return S_OK;
       
   336             }
       
   337         }
       
   338 
       
   339         STDMETHODIMP QPin::QueryPinInfo(PIN_INFO *info)
       
   340         {
       
   341             if (!info) {
       
   342                 return E_POINTER;
       
   343             }
       
   344 
       
   345             info->dir = m_direction;
       
   346             info->pFilter = m_parent;
       
   347             m_parent->AddRef();
       
   348             info->achName[0] = 0;
       
   349             return S_OK;
       
   350         }
       
   351 
       
   352         STDMETHODIMP QPin::QueryDirection(PIN_DIRECTION *dir)
       
   353         {
       
   354             if (!dir) {
       
   355                 return E_POINTER;
       
   356             }
       
   357 
       
   358             *dir = m_direction;
       
   359             return S_OK;
       
   360         }
       
   361 
       
   362         STDMETHODIMP QPin::QueryId(LPWSTR *id)
       
   363         {
       
   364             if (!id) {
       
   365                 return E_POINTER;
       
   366             }
       
   367 
       
   368             *id = static_cast<LPWSTR>(::CoTaskMemAlloc(2));
       
   369             *id[0] = 0;
       
   370             return S_OK;
       
   371         }
       
   372 
       
   373         STDMETHODIMP QPin::QueryAccept(const AM_MEDIA_TYPE *type)
       
   374         {
       
   375             QMutexLocker locker(&m_mutex);
       
   376             if (!type) {
       
   377                 return E_POINTER;
       
   378             }
       
   379 
       
   380             for (int i = 0; i < m_mediaTypes.count(); ++i) {
       
   381                 const AM_MEDIA_TYPE &current = m_mediaTypes.at(i);
       
   382                 if ( (type->majortype == current.majortype) &&
       
   383                     (current.subtype == MEDIASUBTYPE_NULL || type->subtype == current.subtype) &&
       
   384                     (type->majortype == MEDIATYPE_Stream || type->formattype != GUID_NULL || current.formattype != GUID_NULL) &&
       
   385                     (current.formattype == GUID_NULL || type->formattype == current.formattype)
       
   386                     ) {
       
   387                         return S_OK;
       
   388                 }
       
   389             }
       
   390             return S_FALSE;
       
   391         }
       
   392 
       
   393 
       
   394         STDMETHODIMP QPin::EnumMediaTypes(IEnumMediaTypes **emt)
       
   395         {
       
   396             if (!emt) {
       
   397                 return E_POINTER;
       
   398             }
       
   399 
       
   400             *emt = new QEnumMediaTypes(this);
       
   401             return S_OK;
       
   402         }
       
   403 
       
   404 
       
   405         STDMETHODIMP QPin::EndOfStream()
       
   406         {
       
   407             return E_UNEXPECTED;
       
   408         }
       
   409 
       
   410         STDMETHODIMP QPin::BeginFlush()
       
   411         {
       
   412             return E_UNEXPECTED;
       
   413         }
       
   414 
       
   415         STDMETHODIMP QPin::EndFlush()
       
   416         {
       
   417             return E_UNEXPECTED;
       
   418         }
       
   419 
       
   420         STDMETHODIMP QPin::NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
       
   421         {
       
   422             QMutexLocker locker(&m_mutex);
       
   423             if (m_direction == PINDIR_OUTPUT && m_connected) {
       
   424                 //we deliver this downstream
       
   425                 m_connected->NewSegment(start, stop, rate);
       
   426             }
       
   427             return S_OK;
       
   428         }
       
   429 
       
   430         STDMETHODIMP QPin::QueryInternalConnections(IPin **, ULONG*)
       
   431         {
       
   432             //this is not implemented on purpose (the input pins are connected to all the output pins)
       
   433             return E_NOTIMPL;
       
   434         }
       
   435 
       
   436 
       
   437         HRESULT QPin::checkOutputMediaTypesConnection(IPin *pin)
       
   438         {
       
   439             ComPointer<IEnumMediaTypes> emt;
       
   440             HRESULT hr = pin->EnumMediaTypes(emt.pparam());
       
   441             if (hr != S_OK) {
       
   442                 return hr;
       
   443             }
       
   444 
       
   445             AM_MEDIA_TYPE *type = 0;
       
   446             while (emt->Next(1, &type, 0) == S_OK) {
       
   447                 if (QueryAccept(type) == S_OK) {
       
   448                     setConnectedType(*type);
       
   449                     if (pin->ReceiveConnection(this, type) == S_OK) {
       
   450                         freeMediaType(type);
       
   451                         return S_OK;
       
   452                     } else {
       
   453                         setConnectedType(defaultMediaType);
       
   454                         freeMediaType(type);
       
   455                     }
       
   456                 }
       
   457             }
       
   458 
       
   459             //we didn't find a suitable type
       
   460             return S_FALSE;
       
   461         }
       
   462 
       
   463         HRESULT QPin::checkOwnMediaTypesConnection(IPin *pin)
       
   464         {   
       
   465             for(int i = 0; i < m_mediaTypes.count(); ++i) {
       
   466                 const AM_MEDIA_TYPE &current = m_mediaTypes.at(i);
       
   467                 setConnectedType(current);
       
   468                 HRESULT hr = pin->ReceiveConnection(this, &current);
       
   469                 if (hr == S_OK) {
       
   470                     return S_OK;
       
   471                 }
       
   472             }
       
   473 
       
   474             //we didn't find a suitable type
       
   475             return S_FALSE;
       
   476         }
       
   477 
       
   478         void QPin::freeMediaType(const AM_MEDIA_TYPE &type)
       
   479         {
       
   480             if (type.cbFormat) {
       
   481                 ::CoTaskMemFree(type.pbFormat);
       
   482             }
       
   483             if (type.pUnk) {
       
   484                 type.pUnk->Release();
       
   485             }
       
   486         }
       
   487 
       
   488         void QPin::freeMediaType(AM_MEDIA_TYPE *type)
       
   489         {
       
   490             freeMediaType(*type);
       
   491             ::CoTaskMemFree(type);
       
   492         }
       
   493 
       
   494         //addition
       
   495 
       
   496         PIN_DIRECTION QPin::direction() const
       
   497         {
       
   498             return m_direction;
       
   499         }
       
   500 
       
   501         void QPin::setConnectedType(const AM_MEDIA_TYPE &type)
       
   502         {
       
   503             QMutexLocker locker(&m_mutex);
       
   504 
       
   505             //1st we free memory
       
   506             freeMediaType(m_connectedType);
       
   507 
       
   508             m_connectedType = copyMediaType(type);
       
   509         }
       
   510 
       
   511         const AM_MEDIA_TYPE &QPin::connectedType() const 
       
   512         {
       
   513             QMutexLocker locker(&m_mutex);
       
   514             return m_connectedType;
       
   515         }
       
   516 
       
   517         void QPin::setConnected(IPin *pin)
       
   518         {
       
   519             QMutexLocker locker(&m_mutex);
       
   520             if (pin) {
       
   521                 pin->AddRef();
       
   522             }
       
   523             if (m_connected) {
       
   524                 m_connected->Release();
       
   525             }
       
   526             m_connected = pin;
       
   527         }
       
   528 
       
   529         IPin *QPin::connected(bool addref) const
       
   530         {
       
   531             QMutexLocker locker(&m_mutex);
       
   532             if (addref && m_connected) {
       
   533                 m_connected->AddRef();
       
   534             }
       
   535             return m_connected;
       
   536         }
       
   537 
       
   538         bool QPin::isFlushing() const
       
   539         {
       
   540             QMutexLocker locker(&m_mutex);
       
   541             return m_flushing;
       
   542         }
       
   543 
       
   544         FILTER_STATE QPin::filterState() const
       
   545         {
       
   546             FILTER_STATE fstate = State_Stopped;
       
   547             m_parent->GetState(0, &fstate);
       
   548             return fstate;
       
   549         }
       
   550 
       
   551         QVector<AM_MEDIA_TYPE> QPin::mediaTypes() const
       
   552         {
       
   553             QMutexLocker locker(&m_mutex);
       
   554             return m_mediaTypes;
       
   555         }
       
   556 
       
   557         HRESULT QPin::setAcceptedMediaType(const AM_MEDIA_TYPE &mt)
       
   558         {
       
   559             const QVector<AM_MEDIA_TYPE> oldMediaTypes = m_mediaTypes;
       
   560             m_mediaTypes = QVector<AM_MEDIA_TYPE>() << mt;
       
   561 
       
   562             HRESULT hr = S_OK;
       
   563 
       
   564             IPin *conn = connected();
       
   565             if (conn) {
       
   566                 //try to reconnect to redefine the media type
       
   567                 conn->Disconnect();
       
   568                 Disconnect();
       
   569                 hr = Connect(conn, 0);
       
   570                 if (FAILED(hr)) {
       
   571                     m_mediaTypes = oldMediaTypes;
       
   572                     Connect(conn, 0); //just redo the connection with the old media types
       
   573                 }
       
   574             }
       
   575             return hr;
       
   576         }
       
   577 
       
   578         void QPin::createDefaultMemoryAllocator(ALLOCATOR_PROPERTIES *prop)
       
   579         {
       
   580             ComPointer<IMemAllocator> alloc(CLSID_MemoryAllocator, IID_IMemAllocator);
       
   581             if (prop) {
       
   582                 alloc->SetProperties(prop, 0);
       
   583             }
       
   584             setMemoryAllocator(alloc);
       
   585         }
       
   586 
       
   587         void QPin::setMemoryAllocator(IMemAllocator *alloc)
       
   588         {
       
   589             QMutexLocker locker(&m_mutex);
       
   590             if (alloc) {
       
   591                 alloc->AddRef();
       
   592             }
       
   593             if (m_memAlloc) {
       
   594                 m_memAlloc->Release();
       
   595             }
       
   596             m_memAlloc = alloc;
       
   597         }
       
   598 
       
   599         IMemAllocator *QPin::memoryAllocator(bool addref) const
       
   600         {
       
   601             QMutexLocker locker(&m_mutex);
       
   602             if (addref && m_memAlloc) {
       
   603                 m_memAlloc->AddRef();
       
   604             }
       
   605             return m_memAlloc;
       
   606         }
       
   607 
       
   608         AM_MEDIA_TYPE QPin::copyMediaType(const AM_MEDIA_TYPE &type)
       
   609         {
       
   610             AM_MEDIA_TYPE ret = type;
       
   611 
       
   612             //make a deep copy here
       
   613             if (ret.cbFormat == 0 || ret.pbFormat == 0) {
       
   614                 ret.cbFormat = 0;
       
   615                 ret.pbFormat = 0;
       
   616                 ret.formattype = GUID_NULL;
       
   617             } else {
       
   618                 ret.pbFormat = reinterpret_cast<BYTE*>(::CoTaskMemAlloc(type.cbFormat));
       
   619                 qMemCopy(ret.pbFormat, type.pbFormat, type.cbFormat);
       
   620             }
       
   621 
       
   622             if (type.pUnk) {
       
   623                 type.pUnk->AddRef();
       
   624             }
       
   625             return ret;
       
   626         }
       
   627 
       
   628 
       
   629     }
       
   630 }
       
   631 
       
   632 QT_END_NAMESPACE