| 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 "iodevicereader.h"
 | 
|---|
| 19 | #include "qasyncreader.h"
 | 
|---|
| 20 | 
 | 
|---|
| 21 | #include "mediagraph.h"
 | 
|---|
| 22 | 
 | 
|---|
| 23 | #include <phonon/streaminterface.h>
 | 
|---|
| 24 | 
 | 
|---|
| 25 | #include <dshow.h>
 | 
|---|
| 26 | #include <initguid.h>
 | 
|---|
| 27 | 
 | 
|---|
| 28 | QT_BEGIN_NAMESPACE
 | 
|---|
| 29 | 
 | 
|---|
| 30 | #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 31 | 
 | 
|---|
| 32 | namespace Phonon
 | 
|---|
| 33 | {
 | 
|---|
| 34 |     namespace DS9
 | 
|---|
| 35 |     {
 | 
|---|
| 36 |         //these mediatypes define a stream, its type will be autodetected by DirectShow
 | 
|---|
| 37 |         static QVector<AM_MEDIA_TYPE> getMediaTypes()
 | 
|---|
| 38 |         {
 | 
|---|
| 39 |             //the order here is important because otherwise,
 | 
|---|
| 40 |             //directshow might not be able to detect the stream type correctly
 | 
|---|
| 41 | 
 | 
|---|
| 42 |             AM_MEDIA_TYPE mt = { MEDIATYPE_Stream, MEDIASUBTYPE_Avi, TRUE, FALSE, 1, GUID_NULL, 0, 0, 0};
 | 
|---|
| 43 | 
 | 
|---|
| 44 |             QVector<AM_MEDIA_TYPE> ret;
 | 
|---|
| 45 |             //AVI stream
 | 
|---|
| 46 |             ret << mt;
 | 
|---|
| 47 |             //WAVE stream
 | 
|---|
| 48 |             mt.subtype = MEDIASUBTYPE_WAVE;
 | 
|---|
| 49 |             ret << mt;
 | 
|---|
| 50 |             //normal auto-detect stream (must be at the end!)
 | 
|---|
| 51 |             mt.subtype = MEDIASUBTYPE_NULL;
 | 
|---|
| 52 |             ret << mt;
 | 
|---|
| 53 |             return ret;
 | 
|---|
| 54 |         }
 | 
|---|
| 55 | 
 | 
|---|
| 56 |         class StreamReader : public QAsyncReader, public Phonon::StreamInterface
 | 
|---|
| 57 |         {
 | 
|---|
| 58 |         public:
 | 
|---|
| 59 |             StreamReader(QBaseFilter *parent, const Phonon::MediaSource &source, const MediaGraph *mg) : 
 | 
|---|
| 60 |               QAsyncReader(parent, getMediaTypes()),
 | 
|---|
| 61 |                   m_seekable(false), m_pos(0), m_size(-1), m_mediaGraph(mg)
 | 
|---|
| 62 |               {
 | 
|---|
| 63 |                   connectToSource(source);
 | 
|---|
| 64 |               }
 | 
|---|
| 65 | 
 | 
|---|
| 66 |               //for Phonon::StreamInterface
 | 
|---|
| 67 |               void writeData(const QByteArray &data)
 | 
|---|
| 68 |               {
 | 
|---|
| 69 |                   m_pos += data.size();
 | 
|---|
| 70 |                   m_buffer += data;
 | 
|---|
| 71 |               }
 | 
|---|
| 72 | 
 | 
|---|
| 73 |               void endOfData()
 | 
|---|
| 74 |               {
 | 
|---|
| 75 |               }
 | 
|---|
| 76 | 
 | 
|---|
| 77 |               void setStreamSize(qint64 newSize)
 | 
|---|
| 78 |               {
 | 
|---|
| 79 |                   QMutexLocker locker(&m_mutex);
 | 
|---|
| 80 |                   m_size = newSize;
 | 
|---|
| 81 |               }
 | 
|---|
| 82 | 
 | 
|---|
| 83 |               void setStreamSeekable(bool s)
 | 
|---|
| 84 |               {
 | 
|---|
| 85 |                   QMutexLocker locker(&m_mutex);
 | 
|---|
| 86 |                   m_seekable = s;
 | 
|---|
| 87 |               }
 | 
|---|
| 88 | 
 | 
|---|
| 89 |               //virtual pure members
 | 
|---|
| 90 | 
 | 
|---|
| 91 |               //implementation from IAsyncReader
 | 
|---|
| 92 |               STDMETHODIMP Length(LONGLONG *total, LONGLONG *available)
 | 
|---|
| 93 |               {
 | 
|---|
| 94 |                   QMutexLocker locker(&m_mutex);
 | 
|---|
| 95 |                   if (total) {
 | 
|---|
| 96 |                       *total = m_size;
 | 
|---|
| 97 |                   }
 | 
|---|
| 98 | 
 | 
|---|
| 99 |                   if (available) {
 | 
|---|
| 100 |                       *available = m_size;
 | 
|---|
| 101 |                   }
 | 
|---|
| 102 | 
 | 
|---|
| 103 |                   return S_OK;
 | 
|---|
| 104 |               }
 | 
|---|
| 105 | 
 | 
|---|
| 106 | 
 | 
|---|
| 107 |               HRESULT read(LONGLONG pos, LONG length, BYTE *buffer, LONG *actual)
 | 
|---|
| 108 |               {
 | 
|---|
| 109 |                   Q_ASSERT(!m_mutex.tryLock());
 | 
|---|
| 110 |                   if (m_mediaGraph->isStopping()) {
 | 
|---|
| 111 |                       return VFW_E_WRONG_STATE;
 | 
|---|
| 112 |                   }
 | 
|---|
| 113 | 
 | 
|---|
| 114 |                   if(m_size != 1 && pos + length > m_size) {
 | 
|---|
| 115 |                       //it tries to read outside of the boundaries
 | 
|---|
| 116 |                       return E_FAIL;
 | 
|---|
| 117 |                   }
 | 
|---|
| 118 | 
 | 
|---|
| 119 |                   if (m_pos - m_buffer.size() != pos) {
 | 
|---|
| 120 |                       if (!m_seekable) {
 | 
|---|
| 121 |                           return S_FALSE;
 | 
|---|
| 122 |                       }
 | 
|---|
| 123 |                       m_pos = pos;
 | 
|---|
| 124 |                       seekStream(pos);
 | 
|---|
| 125 |                       m_buffer.clear();
 | 
|---|
| 126 |                   }
 | 
|---|
| 127 | 
 | 
|---|
| 128 |                   int oldSize = m_buffer.size();
 | 
|---|
| 129 |                   while (m_buffer.size() < int(length)) {
 | 
|---|
| 130 |                       needData();
 | 
|---|
| 131 | 
 | 
|---|
| 132 |                       if (oldSize == m_buffer.size()) {
 | 
|---|
| 133 |                           break; //we didn't get any data
 | 
|---|
| 134 |                       }
 | 
|---|
| 135 |                       oldSize = m_buffer.size();
 | 
|---|
| 136 |                   }
 | 
|---|
| 137 | 
 | 
|---|
| 138 |                   int bytesRead = qMin(m_buffer.size(), int(length));
 | 
|---|
| 139 |                   qMemCopy(buffer, m_buffer.data(), bytesRead);
 | 
|---|
| 140 |                   //truncate the buffer
 | 
|---|
| 141 |                   m_buffer = m_buffer.mid(bytesRead);
 | 
|---|
| 142 | 
 | 
|---|
| 143 |                   if (actual) {
 | 
|---|
| 144 |                       *actual = bytesRead; //initialization
 | 
|---|
| 145 |                   }
 | 
|---|
| 146 | 
 | 
|---|
| 147 |                   return bytesRead == length ? S_OK : S_FALSE;
 | 
|---|
| 148 |               }
 | 
|---|
| 149 | 
 | 
|---|
| 150 |         public:
 | 
|---|
| 151 |             //for Phonon::StreamInterface
 | 
|---|
| 152 |             QByteArray m_buffer;
 | 
|---|
| 153 |             bool m_seekable;
 | 
|---|
| 154 |             qint64 m_pos;
 | 
|---|
| 155 |             qint64 m_size;
 | 
|---|
| 156 | 
 | 
|---|
| 157 |             const MediaGraph *m_mediaGraph;
 | 
|---|
| 158 |         };
 | 
|---|
| 159 | 
 | 
|---|
| 160 |         IODeviceReader::IODeviceReader(const Phonon::MediaSource &source, const MediaGraph *mg) :
 | 
|---|
| 161 |         QBaseFilter(CLSID_NULL)
 | 
|---|
| 162 |         {
 | 
|---|
| 163 |             //create the output pin
 | 
|---|
| 164 |             m_streamReader = new StreamReader(this, source, mg);
 | 
|---|
| 165 |         }
 | 
|---|
| 166 | 
 | 
|---|
| 167 |         IODeviceReader::~IODeviceReader()
 | 
|---|
| 168 |         {
 | 
|---|
| 169 |         }
 | 
|---|
| 170 |     }
 | 
|---|
| 171 | }
 | 
|---|
| 172 | 
 | 
|---|
| 173 | #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 174 | 
 | 
|---|
| 175 | QT_END_NAMESPACE
 | 
|---|