--- /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