/* 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 "qasyncreader.h" | |
#include "qbasefilter.h" | |
QT_BEGIN_NAMESPACE | |
namespace Phonon | |
{ | |
namespace DS9 | |
{ | |
QAsyncReader::QAsyncReader(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mediaTypes) : QPin(parent, PINDIR_OUTPUT, mediaTypes) | |
{ | |
} | |
QAsyncReader::~QAsyncReader() | |
{ | |
} | |
STDMETHODIMP QAsyncReader::QueryInterface(REFIID iid, void **out) | |
{ | |
if (!out) { | |
return E_POINTER; | |
} | |
if (iid == IID_IAsyncReader) { | |
AddRef(); | |
*out = static_cast<IAsyncReader*>(this); | |
return S_OK; | |
} | |
return QPin::QueryInterface(iid, out); | |
} | |
STDMETHODIMP_(ULONG) QAsyncReader::AddRef() | |
{ | |
return QPin::AddRef(); | |
} | |
STDMETHODIMP_(ULONG) QAsyncReader::Release() | |
{ | |
return QPin::Release(); | |
} | |
STDMETHODIMP QAsyncReader::RequestAllocator(IMemAllocator *preferred, ALLOCATOR_PROPERTIES *prop,IMemAllocator **actual) | |
{ | |
ALLOCATOR_PROPERTIES prop2; | |
if (prop->cbAlign == 0) { | |
prop->cbAlign = 1; //align on 1 char | |
} | |
if (preferred && preferred->SetProperties(prop, &prop2) == S_OK) { | |
preferred->AddRef(); | |
*actual = preferred; | |
return S_OK; | |
} | |
//we should try to create one memory allocator ourselves here | |
return E_FAIL; | |
} | |
STDMETHODIMP QAsyncReader::Request(IMediaSample *sample,DWORD_PTR user) | |
{ | |
QMutexLocker locker(&m_mutex); | |
if (m_flushing) { | |
return VFW_E_WRONG_STATE; | |
} | |
m_requestQueue.enqueue(AsyncRequest(sample, user)); | |
m_requestWait.wakeOne(); | |
return S_OK; | |
} | |
STDMETHODIMP QAsyncReader::WaitForNext(DWORD timeout, IMediaSample **sample, DWORD_PTR *user) | |
{ | |
QMutexLocker locker(&m_mutex); | |
if (!sample ||!user) { | |
return E_POINTER; | |
} | |
//msdn says to return immediately if we're flushing but that doesn't seem to be true | |
//since it triggers a dead-lock somewhere inside directshow (see task 258830) | |
*sample = 0; | |
*user = 0; | |
if (m_requestQueue.isEmpty()) { | |
if (m_requestWait.wait(&m_mutex, timeout) == false) { | |
return VFW_E_TIMEOUT; | |
} | |
if (m_requestQueue.isEmpty()) { | |
return VFW_E_WRONG_STATE; | |
} | |
} | |
AsyncRequest r = m_requestQueue.dequeue(); | |
//at this point we're sure to have a request to proceed | |
if (r.sample == 0) { | |
return E_FAIL; | |
} | |
*sample = r.sample; | |
*user = r.user; | |
return syncReadAlignedUnlocked(r.sample); | |
} | |
STDMETHODIMP QAsyncReader::BeginFlush() | |
{ | |
QMutexLocker locker(&m_mutex); | |
m_flushing = true; | |
m_requestWait.wakeOne(); | |
return S_OK; | |
} | |
STDMETHODIMP QAsyncReader::EndFlush() | |
{ | |
QMutexLocker locker(&m_mutex); | |
m_flushing = false; | |
return S_OK; | |
} | |
STDMETHODIMP QAsyncReader::SyncReadAligned(IMediaSample *sample) | |
{ | |
QMutexLocker locker(&m_mutex); | |
return syncReadAlignedUnlocked(sample); | |
} | |
STDMETHODIMP QAsyncReader::SyncRead(LONGLONG pos, LONG length, BYTE *buffer) | |
{ | |
QMutexLocker locker(&m_mutex); | |
return read(pos, length, buffer, 0); | |
} | |
STDMETHODIMP QAsyncReader::syncReadAlignedUnlocked(IMediaSample *sample) | |
{ | |
Q_ASSERT(!m_mutex.tryLock()); | |
if (!sample) { | |
return E_POINTER; | |
} | |
REFERENCE_TIME start = 0, | |
stop = 0; | |
HRESULT hr = sample->GetTime(&start, &stop); | |
if(FAILED(hr)) { | |
return hr; | |
} | |
LONGLONG startPos = start / 10000000; | |
LONG length = static_cast<LONG>((stop - start) / 10000000); | |
BYTE *buffer; | |
hr = sample->GetPointer(&buffer); | |
if(FAILED(hr)) { | |
return hr; | |
} | |
LONG actual = 0; | |
read(startPos, length, buffer, &actual); | |
return sample->SetActualDataLength(actual); | |
} | |
} | |
} | |
QT_END_NAMESPACE |