|
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 "qmeminputpin.h" |
|
19 #include "qbasefilter.h" |
|
20 #include "compointer.h" |
|
21 |
|
22 #include <QtCore/QDebug> |
|
23 |
|
24 QT_BEGIN_NAMESPACE |
|
25 |
|
26 namespace Phonon |
|
27 { |
|
28 namespace DS9 |
|
29 { |
|
30 |
|
31 QMemInputPin::QMemInputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt, bool transform, QPin *output) : |
|
32 QPin(parent, PINDIR_INPUT, mt), m_shouldDuplicateSamples(true), m_transform(transform), m_output(output) |
|
33 { |
|
34 } |
|
35 |
|
36 QMemInputPin::~QMemInputPin() |
|
37 { |
|
38 } |
|
39 |
|
40 STDMETHODIMP QMemInputPin::QueryInterface(REFIID iid, void **out) |
|
41 { |
|
42 if (!out) { |
|
43 return E_POINTER; |
|
44 } |
|
45 |
|
46 if (iid == IID_IMemInputPin) { |
|
47 *out = static_cast<IMemInputPin*>(this); |
|
48 AddRef(); |
|
49 return S_OK; |
|
50 } else { |
|
51 return QPin::QueryInterface(iid, out); |
|
52 } |
|
53 } |
|
54 |
|
55 STDMETHODIMP_(ULONG) QMemInputPin::AddRef() |
|
56 { |
|
57 return QPin::AddRef(); |
|
58 } |
|
59 |
|
60 STDMETHODIMP_(ULONG) QMemInputPin::Release() |
|
61 { |
|
62 return QPin::Release(); |
|
63 } |
|
64 |
|
65 STDMETHODIMP QMemInputPin::EndOfStream() |
|
66 { |
|
67 //this allows to serialize with Receive calls |
|
68 QMutexLocker locker(&m_mutexReceive); |
|
69 IPin *conn = m_output ? m_output->connected() : 0; |
|
70 if (conn) { |
|
71 conn->EndOfStream(); |
|
72 } |
|
73 return S_OK; |
|
74 } |
|
75 |
|
76 STDMETHODIMP QMemInputPin::BeginFlush() |
|
77 { |
|
78 //pass downstream |
|
79 IPin *conn = m_output ? m_output->connected() : 0; |
|
80 if (conn) { |
|
81 conn->BeginFlush(); |
|
82 } |
|
83 QMutexLocker locker(&m_mutex); |
|
84 m_flushing = true; |
|
85 return S_OK; |
|
86 } |
|
87 |
|
88 STDMETHODIMP QMemInputPin::EndFlush() |
|
89 { |
|
90 //pass downstream |
|
91 IPin *conn = m_output ? m_output->connected() : 0; |
|
92 if (conn) { |
|
93 conn->EndFlush(); |
|
94 } |
|
95 QMutexLocker locker(&m_mutex); |
|
96 m_flushing = false; |
|
97 return S_OK; |
|
98 } |
|
99 |
|
100 STDMETHODIMP QMemInputPin::NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate) |
|
101 { |
|
102 if (m_output) |
|
103 m_output->NewSegment(start, stop, rate); |
|
104 return S_OK; |
|
105 } |
|
106 |
|
107 //reimplementation to set the type for the output pin |
|
108 //no need to make a deep copy here |
|
109 STDMETHODIMP QMemInputPin::ReceiveConnection(IPin *pin ,const AM_MEDIA_TYPE *mt) |
|
110 { |
|
111 HRESULT hr = QPin::ReceiveConnection(pin, mt); |
|
112 if (hr == S_OK && |
|
113 mt->majortype != MEDIATYPE_NULL && |
|
114 mt->subtype != MEDIASUBTYPE_NULL && |
|
115 mt->formattype != GUID_NULL && m_output) { |
|
116 //we tell the output pin that it should connect with this type |
|
117 hr = m_output->setAcceptedMediaType(connectedType()); |
|
118 } |
|
119 return hr; |
|
120 } |
|
121 |
|
122 STDMETHODIMP QMemInputPin::GetAllocator(IMemAllocator **alloc) |
|
123 { |
|
124 if (!alloc) { |
|
125 return E_POINTER; |
|
126 } |
|
127 |
|
128 *alloc = memoryAllocator(true); |
|
129 if (*alloc) { |
|
130 return S_OK; |
|
131 } |
|
132 |
|
133 return VFW_E_NO_ALLOCATOR; |
|
134 } |
|
135 |
|
136 STDMETHODIMP QMemInputPin::NotifyAllocator(IMemAllocator *alloc, BOOL readonly) |
|
137 { |
|
138 if (!alloc) { |
|
139 return E_POINTER; |
|
140 } |
|
141 |
|
142 { |
|
143 QMutexLocker locker(&m_mutex); |
|
144 m_shouldDuplicateSamples = m_transform && readonly; |
|
145 } |
|
146 |
|
147 setMemoryAllocator(alloc); |
|
148 |
|
149 if (m_output) { |
|
150 ComPointer<IMemInputPin> input(m_output, IID_IMemInputPin); |
|
151 input->NotifyAllocator(alloc, m_shouldDuplicateSamples); |
|
152 } |
|
153 |
|
154 return S_OK; |
|
155 } |
|
156 |
|
157 STDMETHODIMP QMemInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *prop) |
|
158 { |
|
159 if (!prop) { |
|
160 return E_POINTER; |
|
161 } |
|
162 |
|
163 //we have no particular requirements |
|
164 return E_NOTIMPL; |
|
165 } |
|
166 |
|
167 STDMETHODIMP QMemInputPin::Receive(IMediaSample *sample) |
|
168 { |
|
169 QMutexLocker locker(&m_mutexReceive); |
|
170 if (!sample) { |
|
171 return E_POINTER; |
|
172 } |
|
173 |
|
174 if (filterState() == State_Stopped) { |
|
175 return VFW_E_WRONG_STATE; |
|
176 } |
|
177 |
|
178 if (isFlushing()) { |
|
179 return S_FALSE; //we are still flushing |
|
180 } |
|
181 |
|
182 if (!m_shouldDuplicateSamples) { |
|
183 //we do it just once |
|
184 HRESULT hr = m_parent->processSample(sample); |
|
185 if (!SUCCEEDED(hr)) { |
|
186 return hr; |
|
187 } |
|
188 } |
|
189 |
|
190 if (m_output) { |
|
191 IMediaSample *outSample = m_shouldDuplicateSamples ? |
|
192 duplicateSampleForOutput(sample, m_output->memoryAllocator()) |
|
193 : sample; |
|
194 |
|
195 if (m_shouldDuplicateSamples) { |
|
196 m_parent->processSample(outSample); |
|
197 } |
|
198 |
|
199 ComPointer<IMemInputPin> input(m_output->connected(), IID_IMemInputPin); |
|
200 if (input) { |
|
201 input->Receive(outSample); |
|
202 } |
|
203 |
|
204 if (m_shouldDuplicateSamples) { |
|
205 outSample->Release(); |
|
206 } |
|
207 } |
|
208 return S_OK; |
|
209 } |
|
210 |
|
211 STDMETHODIMP QMemInputPin::ReceiveMultiple(IMediaSample **samples,long count,long *nbDone) |
|
212 { |
|
213 //no need to lock here: there is no access to member data |
|
214 if (!samples || !nbDone) { |
|
215 return E_POINTER; |
|
216 } |
|
217 |
|
218 *nbDone = 0; //initialization |
|
219 while( *nbDone != count) { |
|
220 HRESULT hr = Receive(samples[*nbDone]); |
|
221 if (FAILED(hr)) { |
|
222 return hr; |
|
223 } |
|
224 (*nbDone)++; |
|
225 } |
|
226 |
|
227 return S_OK; |
|
228 } |
|
229 |
|
230 STDMETHODIMP QMemInputPin::ReceiveCanBlock() |
|
231 { |
|
232 //we test the output to see if it can block |
|
233 if (m_output) { |
|
234 ComPointer<IMemInputPin> meminput(m_output->connected(), IID_IMemInputPin); |
|
235 if (meminput && meminput->ReceiveCanBlock() != S_FALSE) { |
|
236 return S_OK; |
|
237 } |
|
238 } |
|
239 return S_FALSE; |
|
240 } |
|
241 |
|
242 |
|
243 ALLOCATOR_PROPERTIES QMemInputPin::getDefaultAllocatorProperties() const |
|
244 { |
|
245 //those values reduce buffering a lot (good for the volume effect) |
|
246 ALLOCATOR_PROPERTIES prop = {4096, 1, 1, 0}; |
|
247 return prop; |
|
248 } |
|
249 |
|
250 |
|
251 IMediaSample *QMemInputPin::duplicateSampleForOutput(IMediaSample *sample, IMemAllocator *alloc) |
|
252 { |
|
253 LONG length = sample->GetActualDataLength(); |
|
254 |
|
255 HRESULT hr = alloc->Commit(); |
|
256 if (hr == HRESULT(VFW_E_SIZENOTSET)) { |
|
257 ALLOCATOR_PROPERTIES prop = getDefaultAllocatorProperties(); |
|
258 prop.cbBuffer = qMax(prop.cbBuffer, length); |
|
259 ALLOCATOR_PROPERTIES actual; |
|
260 //we just try to set the properties... |
|
261 alloc->SetProperties(&prop, &actual); |
|
262 hr = alloc->Commit(); |
|
263 } |
|
264 |
|
265 Q_ASSERT(SUCCEEDED(hr)); |
|
266 |
|
267 IMediaSample *out; |
|
268 hr = alloc->GetBuffer(&out, 0, 0, AM_GBF_NOTASYNCPOINT); |
|
269 Q_ASSERT(SUCCEEDED(hr)); |
|
270 |
|
271 //let's copy the sample |
|
272 { |
|
273 REFERENCE_TIME start, end; |
|
274 sample->GetTime(&start, &end); |
|
275 out->SetTime(&start, &end); |
|
276 } |
|
277 |
|
278 hr = out->SetActualDataLength(length); |
|
279 Q_ASSERT(SUCCEEDED(hr)); |
|
280 hr = out->SetDiscontinuity(sample->IsDiscontinuity()); |
|
281 Q_ASSERT(SUCCEEDED(hr)); |
|
282 |
|
283 { |
|
284 LONGLONG start, end; |
|
285 hr = sample->GetMediaTime(&start, &end); |
|
286 if (hr != HRESULT(VFW_E_MEDIA_TIME_NOT_SET)) { |
|
287 hr = out->SetMediaTime(&start, &end); |
|
288 Q_ASSERT(SUCCEEDED(hr)); |
|
289 } |
|
290 } |
|
291 |
|
292 AM_MEDIA_TYPE *type = 0; |
|
293 hr = sample->GetMediaType(&type); |
|
294 Q_ASSERT(SUCCEEDED(hr)); |
|
295 hr = out->SetMediaType(type); |
|
296 Q_ASSERT(SUCCEEDED(hr)); |
|
297 |
|
298 hr = out->SetPreroll(sample->IsPreroll()); |
|
299 Q_ASSERT(SUCCEEDED(hr)); |
|
300 hr = out->SetSyncPoint(sample->IsSyncPoint()); |
|
301 Q_ASSERT(SUCCEEDED(hr)); |
|
302 |
|
303 BYTE *dest = 0, *src = 0; |
|
304 hr = out->GetPointer(&dest); |
|
305 Q_ASSERT(SUCCEEDED(hr)); |
|
306 hr = sample->GetPointer(&src); |
|
307 Q_ASSERT(SUCCEEDED(hr)); |
|
308 |
|
309 qMemCopy(dest, src, sample->GetActualDataLength()); |
|
310 |
|
311 return out; |
|
312 } |
|
313 } |
|
314 } |
|
315 |
|
316 QT_END_NAMESPACE |