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