src/3rdparty/phonon/ds9/qmeminputpin.cpp
changeset 0 1918ee327afb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/3rdparty/phonon/ds9/qmeminputpin.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,316 @@
+/*  This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 2.1 or 3 of the License.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this library.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "qmeminputpin.h"
+#include "qbasefilter.h"
+#include "compointer.h"
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+    namespace DS9
+    {
+
+        QMemInputPin::QMemInputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt, bool transform, QPin *output) :
+            QPin(parent, PINDIR_INPUT, mt), m_shouldDuplicateSamples(true), m_transform(transform), m_output(output)
+        {
+        }
+
+        QMemInputPin::~QMemInputPin()
+        {
+        }
+
+        STDMETHODIMP QMemInputPin::QueryInterface(REFIID iid, void **out)
+        {
+            if (!out) {
+                return E_POINTER;
+            }
+
+            if (iid == IID_IMemInputPin) {
+                *out = static_cast<IMemInputPin*>(this);
+                AddRef();
+                return S_OK;
+            } else {
+                return QPin::QueryInterface(iid, out);
+            }
+        }
+
+        STDMETHODIMP_(ULONG) QMemInputPin::AddRef()
+        {
+            return QPin::AddRef();
+        }
+
+        STDMETHODIMP_(ULONG) QMemInputPin::Release()
+        {
+            return QPin::Release();
+        }
+
+        STDMETHODIMP QMemInputPin::EndOfStream()
+        {
+            //this allows to serialize with Receive calls
+            QMutexLocker locker(&m_mutexReceive);
+            IPin *conn = m_output ? m_output->connected() : 0;
+            if (conn) {
+                conn->EndOfStream();
+            }
+            return S_OK;
+        }
+
+        STDMETHODIMP QMemInputPin::BeginFlush()
+        {
+            //pass downstream
+            IPin *conn = m_output ? m_output->connected() : 0;
+            if (conn) {
+                conn->BeginFlush();
+            }
+            QMutexLocker locker(&m_mutex);
+            m_flushing = true;
+            return S_OK;
+        }
+
+        STDMETHODIMP QMemInputPin::EndFlush()
+        {
+            //pass downstream
+            IPin *conn = m_output ? m_output->connected() : 0;
+            if (conn) {
+                conn->EndFlush();
+            }
+            QMutexLocker locker(&m_mutex);
+            m_flushing = false;
+            return S_OK;
+        }
+
+        STDMETHODIMP QMemInputPin::NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
+        {
+            if (m_output)
+                m_output->NewSegment(start, stop, rate);
+            return S_OK;
+        }
+
+        //reimplementation to set the type for the output pin
+        //no need to make a deep copy here
+        STDMETHODIMP QMemInputPin::ReceiveConnection(IPin *pin ,const AM_MEDIA_TYPE *mt)
+        {
+            HRESULT hr = QPin::ReceiveConnection(pin, mt);
+            if (hr == S_OK &&
+                mt->majortype != MEDIATYPE_NULL &&
+                mt->subtype != MEDIASUBTYPE_NULL &&
+                mt->formattype != GUID_NULL && m_output) {
+                    //we tell the output pin that it should connect with this type
+                    hr = m_output->setAcceptedMediaType(connectedType());
+            }
+            return hr;
+        }
+
+        STDMETHODIMP QMemInputPin::GetAllocator(IMemAllocator **alloc)
+        {
+            if (!alloc) {
+                return E_POINTER;
+            }
+
+            *alloc = memoryAllocator(true);
+            if (*alloc) {
+                return S_OK;
+            }
+
+            return VFW_E_NO_ALLOCATOR;
+        }
+
+        STDMETHODIMP QMemInputPin::NotifyAllocator(IMemAllocator *alloc, BOOL readonly)
+        {
+            if (!alloc) {
+                return E_POINTER;
+            }
+
+            {
+                QMutexLocker locker(&m_mutex);
+                m_shouldDuplicateSamples = m_transform && readonly;
+            }
+
+            setMemoryAllocator(alloc);
+
+            if (m_output) {
+                ComPointer<IMemInputPin> input(m_output, IID_IMemInputPin);
+                input->NotifyAllocator(alloc, m_shouldDuplicateSamples);
+            }
+
+            return S_OK;
+        }
+
+        STDMETHODIMP QMemInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *prop)
+        {
+            if (!prop) {
+                return E_POINTER;
+            }
+
+            //we have no particular requirements
+            return E_NOTIMPL;
+        }
+
+        STDMETHODIMP QMemInputPin::Receive(IMediaSample *sample)
+        {
+            QMutexLocker locker(&m_mutexReceive);
+            if (!sample) {
+                return E_POINTER;
+            }
+
+            if (filterState() == State_Stopped) {
+                return VFW_E_WRONG_STATE;
+            }
+
+            if (isFlushing()) {
+                return S_FALSE; //we are still flushing
+            }
+
+            if (!m_shouldDuplicateSamples) {
+                //we do it just once
+                HRESULT hr = m_parent->processSample(sample);
+                if (!SUCCEEDED(hr)) {
+                    return hr;
+                }
+            }
+
+            if (m_output) {
+                IMediaSample *outSample = m_shouldDuplicateSamples ?
+                    duplicateSampleForOutput(sample, m_output->memoryAllocator())
+                    : sample;
+
+                if (m_shouldDuplicateSamples) {
+                    m_parent->processSample(outSample);
+                }
+
+                ComPointer<IMemInputPin> input(m_output->connected(), IID_IMemInputPin);
+                if (input) {
+                    input->Receive(outSample);
+                }
+
+                if (m_shouldDuplicateSamples) {
+                    outSample->Release();
+                }
+            }
+            return S_OK;
+        }
+
+        STDMETHODIMP QMemInputPin::ReceiveMultiple(IMediaSample **samples,long count,long *nbDone)
+        {
+            //no need to lock here: there is no access to member data
+            if (!samples || !nbDone) {
+                return E_POINTER;
+            }
+
+            *nbDone = 0; //initialization
+            while( *nbDone != count) {
+                HRESULT hr = Receive(samples[*nbDone]);
+                if (FAILED(hr)) {
+                    return hr;
+                }
+                (*nbDone)++;
+            }
+
+            return S_OK;
+        }
+
+        STDMETHODIMP QMemInputPin::ReceiveCanBlock()
+        {
+            //we test the output to see if it can block
+            if (m_output) {
+                ComPointer<IMemInputPin> meminput(m_output->connected(), IID_IMemInputPin);
+                if (meminput && meminput->ReceiveCanBlock() != S_FALSE) {
+                    return S_OK;
+                }
+            }
+            return S_FALSE;
+        }
+
+
+        ALLOCATOR_PROPERTIES QMemInputPin::getDefaultAllocatorProperties() const
+        {
+            //those values reduce buffering a lot (good for the volume effect)
+            ALLOCATOR_PROPERTIES prop = {4096, 1, 1, 0};
+            return prop;
+        }
+
+
+        IMediaSample *QMemInputPin::duplicateSampleForOutput(IMediaSample *sample, IMemAllocator *alloc)
+        {
+            LONG length = sample->GetActualDataLength();
+
+            HRESULT hr = alloc->Commit();
+            if (hr == HRESULT(VFW_E_SIZENOTSET)) {
+                ALLOCATOR_PROPERTIES prop = getDefaultAllocatorProperties();
+                prop.cbBuffer = qMax(prop.cbBuffer, length);
+                ALLOCATOR_PROPERTIES actual;
+                //we just try to set the properties...
+                alloc->SetProperties(&prop, &actual);
+                hr = alloc->Commit();
+            }
+
+            Q_ASSERT(SUCCEEDED(hr));
+
+            IMediaSample *out;
+            hr = alloc->GetBuffer(&out, 0, 0, AM_GBF_NOTASYNCPOINT);
+            Q_ASSERT(SUCCEEDED(hr));
+
+            //let's copy the sample
+            {
+                REFERENCE_TIME start, end;
+                sample->GetTime(&start, &end);
+                out->SetTime(&start, &end);
+            }
+
+            hr = out->SetActualDataLength(length);
+            Q_ASSERT(SUCCEEDED(hr));
+            hr = out->SetDiscontinuity(sample->IsDiscontinuity());
+            Q_ASSERT(SUCCEEDED(hr));
+
+            {
+                LONGLONG start, end;
+                hr = sample->GetMediaTime(&start, &end);
+                if (hr != HRESULT(VFW_E_MEDIA_TIME_NOT_SET)) {
+                    hr = out->SetMediaTime(&start, &end);
+                    Q_ASSERT(SUCCEEDED(hr));
+                }
+            }
+
+            AM_MEDIA_TYPE *type = 0;
+            hr = sample->GetMediaType(&type);
+            Q_ASSERT(SUCCEEDED(hr));
+            hr = out->SetMediaType(type);
+            Q_ASSERT(SUCCEEDED(hr));
+
+            hr = out->SetPreroll(sample->IsPreroll());
+            Q_ASSERT(SUCCEEDED(hr));
+            hr = out->SetSyncPoint(sample->IsSyncPoint());
+            Q_ASSERT(SUCCEEDED(hr));
+
+            BYTE *dest = 0, *src = 0;
+            hr = out->GetPointer(&dest);
+            Q_ASSERT(SUCCEEDED(hr));
+            hr = sample->GetPointer(&src);
+            Q_ASSERT(SUCCEEDED(hr));
+
+            qMemCopy(dest, src, sample->GetActualDataLength());
+
+            return out;
+        }
+    }
+}
+
+QT_END_NAMESPACE