1/*
2 Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
3 Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
4 Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
5 Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "streamreader.h"
22
23#include <QtCore/QMutexLocker>
24
25#include <phonon/streaminterface.h>
26
27#include "utils/debug.h"
28#include "media.h"
29#include "mediaobject.h"
30#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
31
32namespace Phonon {
33namespace VLC {
34
35#define BLOCKSIZE 32768
36
37StreamReader::StreamReader(MediaObject *parent)
38 : QObject(parent)
39 , m_pos(0)
40 , m_size(0)
41 , m_eos(false)
42 , m_seekable(false)
43 , m_unlocked(false)
44 , m_mediaObject(parent)
45{
46}
47
48StreamReader::~StreamReader()
49{
50}
51
52void StreamReader::addToMedia(Media *media)
53{
54 lock(); // Make sure we can lock in read().
55
56 media->addOption(option: QLatin1String("imem-cat=4"));
57 media->addOption(option: QLatin1String("imem-data="), INTPTR_PTR(this));
58 media->addOption(option: QLatin1String("imem-get="), INTPTR_FUNC(readCallback));
59 media->addOption(option: QLatin1String("imem-release="), INTPTR_FUNC(readDoneCallback));
60 media->addOption(option: QLatin1String("imem-seek="), INTPTR_FUNC(seekCallback));
61
62 // if stream has known size, we may pass it
63 // imem module will use it and pass it to demux
64 if (streamSize() > 0) {
65 media->addOption(option: QString("imem-size=%1").arg(a: streamSize()));
66 }
67}
68
69void StreamReader::lock()
70{
71 QMutexLocker lock(&m_mutex);
72 DEBUG_BLOCK;
73 m_unlocked = false;
74}
75
76void StreamReader::unlock()
77{
78 QMutexLocker lock(&m_mutex);
79 DEBUG_BLOCK;
80 m_unlocked = true;
81 m_waitingForData.wakeAll();
82}
83
84int StreamReader::readCallback(void *data, const char *cookie,
85 int64_t *dts, int64_t *pts, unsigned *flags, // krazy:exclude=typedefs
86 size_t *bufferSize, void **buffer)
87{
88 Q_UNUSED(cookie);
89 Q_UNUSED(dts);
90 Q_UNUSED(pts);
91 Q_UNUSED(flags);
92
93 StreamReader *that = static_cast<StreamReader *>(data);
94 size_t length = BLOCKSIZE;
95
96 *buffer = new char[length];
97
98 int size = length;
99 bool ret = that->read(offset: that->currentPos(), length: &size, buffer: static_cast<char*>(*buffer));
100
101 *bufferSize = static_cast<size_t>(size);
102
103 return ret ? 0 : -1;
104}
105
106int StreamReader::readDoneCallback(void *data, const char *cookie,
107 size_t bufferSize, void *buffer)
108{
109 Q_UNUSED(data);
110 Q_UNUSED(cookie);
111 Q_UNUSED(bufferSize);
112 delete[] static_cast<char *>(buffer);
113 return 0;
114}
115
116int StreamReader::seekCallback(void *data, const uint64_t pos)
117{
118 StreamReader *that = static_cast<StreamReader *>(data);
119 if (static_cast<int64_t>(pos) > that->streamSize()) { // krazy:exclude=typedefs
120 // attempt to seek past the end of our data.
121 return -1;
122 }
123
124 that->setCurrentPos(pos);
125 // this should return a true/false, but it doesn't, so assume success.
126
127 return 0;
128}
129
130quint64 StreamReader::currentBufferSize() const
131{
132 return m_buffer.size();
133}
134
135bool StreamReader::read(quint64 pos, int *length, char *buffer)
136{
137 QMutexLocker lock(&m_mutex);
138 DEBUG_BLOCK;
139 bool ret = true;
140
141 if (m_unlocked) {
142 return ret;
143 }
144
145 if (currentPos() != pos) {
146 if (!streamSeekable()) {
147 return false;
148 }
149 setCurrentPos(pos);
150 }
151
152 if (m_buffer.capacity() < *length) {
153 m_buffer.reserve(asize: *length);
154 }
155
156 while (currentBufferSize() < static_cast<unsigned int>(*length)) {
157 quint64 oldSize = currentBufferSize();
158 needData();
159
160 m_waitingForData.wait(lockedMutex: &m_mutex);
161
162 if (oldSize == currentBufferSize()) {
163 if (m_eos && m_buffer.isEmpty()) {
164 return false;
165 }
166 // We didn't get any more data
167 *length = static_cast<int>(oldSize);
168 // If we have some data to return, why tell to reader that we failed?
169 // Remember that length argument is more like maxSize not requiredSize
170 ret = true;
171 }
172 }
173
174 if (m_mediaObject->state() != Phonon::BufferingState &&
175 m_mediaObject->state() != Phonon::LoadingState) {
176 enoughData();
177 }
178
179 memcpy(dest: buffer, src: m_buffer.data(), n: *length);
180 m_pos += *length;
181 // trim the buffer by the amount read
182 m_buffer = m_buffer.mid(index: *length);
183
184 return ret;
185}
186
187void StreamReader::endOfData()
188{
189 m_eos = true;
190 m_waitingForData.wakeAll();
191}
192
193void StreamReader::writeData(const QByteArray &data)
194{
195 QMutexLocker lock(&m_mutex);
196 DEBUG_BLOCK;
197 m_buffer.append(a: data);
198 m_waitingForData.wakeAll();
199}
200
201quint64 StreamReader::currentPos() const
202{
203 return m_pos;
204}
205
206void StreamReader::setCurrentPos(qint64 pos)
207{
208 QMutexLocker lock(&m_mutex);
209 m_pos = pos;
210 m_buffer.clear(); // Not optimal, but meh
211
212 // Do not touch m_size here, it reflects the size of the stream not the size of the buffer,
213 // and generally seeking does not change the size!
214
215 seekStream(seekTo: pos);
216}
217
218void StreamReader::setStreamSize(qint64 newSize)
219{
220 m_size = newSize;
221}
222
223qint64 StreamReader::streamSize() const
224{
225 return m_size;
226}
227
228void StreamReader::setStreamSeekable(bool seekable)
229{
230 m_seekable = seekable;
231 emit streamSeekableChanged(seekable);
232}
233
234bool StreamReader::streamSeekable() const
235{
236 return m_seekable;
237}
238
239} // namespace VLC
240} // namespace Phonon
241
242#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
243

source code of phonon-vlc/src/streamreader.cpp