src/3rdparty/phonon/ds9/qmeminputpin.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 "qmeminputpin.h"
       
    19 #include "qbasefilter.h"
       
    20 #include "compointer.h"
       
    21 
       
    22 #include <QtCore/QDebug>
       
    23 
       
    24 QT_BEGIN_NAMESPACE
       
    25 
       
    26 namespace Phonon
       
    27 {
       
    28     namespace DS9
       
    29     {
       
    30 
       
    31         QMemInputPin::QMemInputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt, bool transform, QPin *output) :
       
    32             QPin(parent, PINDIR_INPUT, mt), m_shouldDuplicateSamples(true), m_transform(transform), m_output(output)
       
    33         {
       
    34         }
       
    35 
       
    36         QMemInputPin::~QMemInputPin()
       
    37         {
       
    38         }
       
    39 
       
    40         STDMETHODIMP QMemInputPin::QueryInterface(REFIID iid, void **out)
       
    41         {
       
    42             if (!out) {
       
    43                 return E_POINTER;
       
    44             }
       
    45 
       
    46             if (iid == IID_IMemInputPin) {
       
    47                 *out = static_cast<IMemInputPin*>(this);
       
    48                 AddRef();
       
    49                 return S_OK;
       
    50             } else {
       
    51                 return QPin::QueryInterface(iid, out);
       
    52             }
       
    53         }
       
    54 
       
    55         STDMETHODIMP_(ULONG) QMemInputPin::AddRef()
       
    56         {
       
    57             return QPin::AddRef();
       
    58         }
       
    59 
       
    60         STDMETHODIMP_(ULONG) QMemInputPin::Release()
       
    61         {
       
    62             return QPin::Release();
       
    63         }
       
    64 
       
    65         STDMETHODIMP QMemInputPin::EndOfStream()
       
    66         {
       
    67             //this allows to serialize with Receive calls
       
    68             QMutexLocker locker(&m_mutexReceive);
       
    69             IPin *conn = m_output ? m_output->connected() : 0;
       
    70             if (conn) {
       
    71                 conn->EndOfStream();
       
    72             }
       
    73             return S_OK;
       
    74         }
       
    75 
       
    76         STDMETHODIMP QMemInputPin::BeginFlush()
       
    77         {
       
    78             //pass downstream
       
    79             IPin *conn = m_output ? m_output->connected() : 0;
       
    80             if (conn) {
       
    81                 conn->BeginFlush();
       
    82             }
       
    83             QMutexLocker locker(&m_mutex);
       
    84             m_flushing = true;
       
    85             return S_OK;
       
    86         }
       
    87 
       
    88         STDMETHODIMP QMemInputPin::EndFlush()
       
    89         {
       
    90             //pass downstream
       
    91             IPin *conn = m_output ? m_output->connected() : 0;
       
    92             if (conn) {
       
    93                 conn->EndFlush();
       
    94             }
       
    95             QMutexLocker locker(&m_mutex);
       
    96             m_flushing = false;
       
    97             return S_OK;
       
    98         }
       
    99 
       
   100         STDMETHODIMP QMemInputPin::NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
       
   101         {
       
   102             if (m_output)
       
   103                 m_output->NewSegment(start, stop, rate);
       
   104             return S_OK;
       
   105         }
       
   106 
       
   107         //reimplementation to set the type for the output pin
       
   108         //no need to make a deep copy here
       
   109         STDMETHODIMP QMemInputPin::ReceiveConnection(IPin *pin ,const AM_MEDIA_TYPE *mt)
       
   110         {
       
   111             HRESULT hr = QPin::ReceiveConnection(pin, mt);
       
   112             if (hr == S_OK &&
       
   113                 mt->majortype != MEDIATYPE_NULL &&
       
   114                 mt->subtype != MEDIASUBTYPE_NULL &&
       
   115                 mt->formattype != GUID_NULL && m_output) {
       
   116                     //we tell the output pin that it should connect with this type
       
   117                     hr = m_output->setAcceptedMediaType(connectedType());
       
   118             }
       
   119             return hr;
       
   120         }
       
   121 
       
   122         STDMETHODIMP QMemInputPin::GetAllocator(IMemAllocator **alloc)
       
   123         {
       
   124             if (!alloc) {
       
   125                 return E_POINTER;
       
   126             }
       
   127 
       
   128             *alloc = memoryAllocator(true);
       
   129             if (*alloc) {
       
   130                 return S_OK;
       
   131             }
       
   132 
       
   133             return VFW_E_NO_ALLOCATOR;
       
   134         }
       
   135 
       
   136         STDMETHODIMP QMemInputPin::NotifyAllocator(IMemAllocator *alloc, BOOL readonly)
       
   137         {
       
   138             if (!alloc) {
       
   139                 return E_POINTER;
       
   140             }
       
   141 
       
   142             {
       
   143                 QMutexLocker locker(&m_mutex);
       
   144                 m_shouldDuplicateSamples = m_transform && readonly;
       
   145             }
       
   146 
       
   147             setMemoryAllocator(alloc);
       
   148 
       
   149             if (m_output) {
       
   150                 ComPointer<IMemInputPin> input(m_output, IID_IMemInputPin);
       
   151                 input->NotifyAllocator(alloc, m_shouldDuplicateSamples);
       
   152             }
       
   153 
       
   154             return S_OK;
       
   155         }
       
   156 
       
   157         STDMETHODIMP QMemInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *prop)
       
   158         {
       
   159             if (!prop) {
       
   160                 return E_POINTER;
       
   161             }
       
   162 
       
   163             //we have no particular requirements
       
   164             return E_NOTIMPL;
       
   165         }
       
   166 
       
   167         STDMETHODIMP QMemInputPin::Receive(IMediaSample *sample)
       
   168         {
       
   169             QMutexLocker locker(&m_mutexReceive);
       
   170             if (!sample) {
       
   171                 return E_POINTER;
       
   172             }
       
   173 
       
   174             if (filterState() == State_Stopped) {
       
   175                 return VFW_E_WRONG_STATE;
       
   176             }
       
   177 
       
   178             if (isFlushing()) {
       
   179                 return S_FALSE; //we are still flushing
       
   180             }
       
   181 
       
   182             if (!m_shouldDuplicateSamples) {
       
   183                 //we do it just once
       
   184                 HRESULT hr = m_parent->processSample(sample);
       
   185                 if (!SUCCEEDED(hr)) {
       
   186                     return hr;
       
   187                 }
       
   188             }
       
   189 
       
   190             if (m_output) {
       
   191                 IMediaSample *outSample = m_shouldDuplicateSamples ?
       
   192                     duplicateSampleForOutput(sample, m_output->memoryAllocator())
       
   193                     : sample;
       
   194 
       
   195                 if (m_shouldDuplicateSamples) {
       
   196                     m_parent->processSample(outSample);
       
   197                 }
       
   198 
       
   199                 ComPointer<IMemInputPin> input(m_output->connected(), IID_IMemInputPin);
       
   200                 if (input) {
       
   201                     input->Receive(outSample);
       
   202                 }
       
   203 
       
   204                 if (m_shouldDuplicateSamples) {
       
   205                     outSample->Release();
       
   206                 }
       
   207             }
       
   208             return S_OK;
       
   209         }
       
   210 
       
   211         STDMETHODIMP QMemInputPin::ReceiveMultiple(IMediaSample **samples,long count,long *nbDone)
       
   212         {
       
   213             //no need to lock here: there is no access to member data
       
   214             if (!samples || !nbDone) {
       
   215                 return E_POINTER;
       
   216             }
       
   217 
       
   218             *nbDone = 0; //initialization
       
   219             while( *nbDone != count) {
       
   220                 HRESULT hr = Receive(samples[*nbDone]);
       
   221                 if (FAILED(hr)) {
       
   222                     return hr;
       
   223                 }
       
   224                 (*nbDone)++;
       
   225             }
       
   226 
       
   227             return S_OK;
       
   228         }
       
   229 
       
   230         STDMETHODIMP QMemInputPin::ReceiveCanBlock()
       
   231         {
       
   232             //we test the output to see if it can block
       
   233             if (m_output) {
       
   234                 ComPointer<IMemInputPin> meminput(m_output->connected(), IID_IMemInputPin);
       
   235                 if (meminput && meminput->ReceiveCanBlock() != S_FALSE) {
       
   236                     return S_OK;
       
   237                 }
       
   238             }
       
   239             return S_FALSE;
       
   240         }
       
   241 
       
   242 
       
   243         ALLOCATOR_PROPERTIES QMemInputPin::getDefaultAllocatorProperties() const
       
   244         {
       
   245             //those values reduce buffering a lot (good for the volume effect)
       
   246             ALLOCATOR_PROPERTIES prop = {4096, 1, 1, 0};
       
   247             return prop;
       
   248         }
       
   249 
       
   250 
       
   251         IMediaSample *QMemInputPin::duplicateSampleForOutput(IMediaSample *sample, IMemAllocator *alloc)
       
   252         {
       
   253             LONG length = sample->GetActualDataLength();
       
   254 
       
   255             HRESULT hr = alloc->Commit();
       
   256             if (hr == HRESULT(VFW_E_SIZENOTSET)) {
       
   257                 ALLOCATOR_PROPERTIES prop = getDefaultAllocatorProperties();
       
   258                 prop.cbBuffer = qMax(prop.cbBuffer, length);
       
   259                 ALLOCATOR_PROPERTIES actual;
       
   260                 //we just try to set the properties...
       
   261                 alloc->SetProperties(&prop, &actual);
       
   262                 hr = alloc->Commit();
       
   263             }
       
   264 
       
   265             Q_ASSERT(SUCCEEDED(hr));
       
   266 
       
   267             IMediaSample *out;
       
   268             hr = alloc->GetBuffer(&out, 0, 0, AM_GBF_NOTASYNCPOINT);
       
   269             Q_ASSERT(SUCCEEDED(hr));
       
   270 
       
   271             //let's copy the sample
       
   272             {
       
   273                 REFERENCE_TIME start, end;
       
   274                 sample->GetTime(&start, &end);
       
   275                 out->SetTime(&start, &end);
       
   276             }
       
   277 
       
   278             hr = out->SetActualDataLength(length);
       
   279             Q_ASSERT(SUCCEEDED(hr));
       
   280             hr = out->SetDiscontinuity(sample->IsDiscontinuity());
       
   281             Q_ASSERT(SUCCEEDED(hr));
       
   282 
       
   283             {
       
   284                 LONGLONG start, end;
       
   285                 hr = sample->GetMediaTime(&start, &end);
       
   286                 if (hr != HRESULT(VFW_E_MEDIA_TIME_NOT_SET)) {
       
   287                     hr = out->SetMediaTime(&start, &end);
       
   288                     Q_ASSERT(SUCCEEDED(hr));
       
   289                 }
       
   290             }
       
   291 
       
   292             AM_MEDIA_TYPE *type = 0;
       
   293             hr = sample->GetMediaType(&type);
       
   294             Q_ASSERT(SUCCEEDED(hr));
       
   295             hr = out->SetMediaType(type);
       
   296             Q_ASSERT(SUCCEEDED(hr));
       
   297 
       
   298             hr = out->SetPreroll(sample->IsPreroll());
       
   299             Q_ASSERT(SUCCEEDED(hr));
       
   300             hr = out->SetSyncPoint(sample->IsSyncPoint());
       
   301             Q_ASSERT(SUCCEEDED(hr));
       
   302 
       
   303             BYTE *dest = 0, *src = 0;
       
   304             hr = out->GetPointer(&dest);
       
   305             Q_ASSERT(SUCCEEDED(hr));
       
   306             hr = sample->GetPointer(&src);
       
   307             Q_ASSERT(SUCCEEDED(hr));
       
   308 
       
   309             qMemCopy(dest, src, sample->GetActualDataLength());
       
   310 
       
   311             return out;
       
   312         }
       
   313     }
       
   314 }
       
   315 
       
   316 QT_END_NAMESPACE