source: trunk/src/3rdparty/phonon/ds9/qpin.cpp

Last change on this file was 561, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 17.8 KB
Line 
1/* This file is part of the KDE project.
2
3Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5This library is free software: you can redistribute it and/or modify
6it under the terms of the GNU Lesser General Public License as published by
7the Free Software Foundation, either version 2.1 or 3 of the License.
8
9This library is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU Lesser General Public License for more details.
13
14You should have received a copy of the GNU Lesser General Public License
15along with this library. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "qbasefilter.h"
19#include "qpin.h"
20#include "compointer.h"
21
22#include <QtCore/QMutex>
23
24QT_BEGIN_NAMESPACE
25
26namespace Phonon
27{
28 namespace DS9
29 {
30
31 static const AM_MEDIA_TYPE defaultMediaType = { MEDIATYPE_NULL, MEDIASUBTYPE_NULL, TRUE, FALSE, 1, GUID_NULL, 0, 0, 0};
32
33 class QEnumMediaTypes : public IEnumMediaTypes
34 {
35 public:
36 QEnumMediaTypes(QPin *pin) : m_refCount(1), m_pin(pin), m_index(0)
37 {
38 m_pin->AddRef();
39 }
40
41 ~QEnumMediaTypes()
42 {
43 m_pin->Release();
44 }
45
46 STDMETHODIMP QueryInterface(const IID &iid,void **out)
47 {
48 if (!out) {
49 return E_POINTER;
50 }
51
52 HRESULT hr = S_OK;
53 if (iid == IID_IEnumMediaTypes) {
54 *out = static_cast<IEnumMediaTypes*>(this);
55 } else if (iid == IID_IUnknown) {
56 *out = static_cast<IUnknown*>(this);
57 } else {
58 *out = 0;
59 hr = E_NOINTERFACE;
60 }
61
62 if (hr == S_OK) {
63 AddRef();
64 }
65 return hr;
66 }
67
68 STDMETHODIMP_(ULONG) AddRef()
69 {
70 return InterlockedIncrement(&m_refCount);
71 }
72
73 STDMETHODIMP_(ULONG) Release()
74 {
75 ULONG refCount = InterlockedDecrement(&m_refCount);
76 if (refCount == 0) {
77 delete this;
78 }
79
80 return refCount;
81 }
82
83 STDMETHODIMP Next(ULONG count, AM_MEDIA_TYPE **out, ULONG *fetched)
84 {
85 QMutexLocker locker(&m_mutex);
86 if (!out) {
87 return E_POINTER;
88 }
89
90 if (!fetched && count > 1) {
91 return E_INVALIDARG;
92 }
93
94 uint nbFetched = 0;
95 while (nbFetched < count && m_index < m_pin->mediaTypes().count()) {
96 //the caller will deallocate the memory
97 *out = static_cast<AM_MEDIA_TYPE *>(::CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)));
98 const AM_MEDIA_TYPE original = m_pin->mediaTypes().at(m_index);
99 **out = QPin::copyMediaType(original);
100 nbFetched++;
101 m_index++;
102 out++;
103 }
104
105 if (fetched) {
106 *fetched = nbFetched;
107 }
108
109 return nbFetched == count ? S_OK : S_FALSE;
110 }
111
112 STDMETHODIMP Skip(ULONG count)
113 {
114 QMutexLocker locker(&m_mutex);
115 m_index = qMin(m_index + int(count), m_pin->mediaTypes().count());
116 return (m_index == m_pin->mediaTypes().count()) ? S_FALSE : S_OK;
117 }
118
119 STDMETHODIMP Reset()
120 {
121 QMutexLocker locker(&m_mutex);
122 m_index = 0;
123 return S_OK;
124 }
125
126 STDMETHODIMP Clone(IEnumMediaTypes **out)
127 {
128 QMutexLocker locker(&m_mutex);
129 if (!out) {
130 return E_POINTER;
131 }
132
133 *out = new QEnumMediaTypes(m_pin);
134 (*out)->Skip(m_index);
135 return S_OK;
136 }
137
138
139 private:
140 LONG m_refCount;
141 QPin *m_pin;
142 int m_index;
143 QMutex m_mutex;
144 };
145
146
147 QPin::QPin(QBaseFilter *parent, PIN_DIRECTION dir, const QVector<AM_MEDIA_TYPE> &mt) :
148 m_parent(parent), m_flushing(false), m_refCount(1), m_connected(0),
149 m_direction(dir), m_mediaTypes(mt), m_connectedType(defaultMediaType),
150 m_memAlloc(0)
151 {
152 Q_ASSERT(m_parent);
153 m_parent->addPin(this);
154 }
155
156 QPin::~QPin()
157 {
158 m_parent->removePin(this);
159 setMemoryAllocator(0);
160 freeMediaType(m_connectedType);
161 }
162
163 //reimplementation from IUnknown
164 STDMETHODIMP QPin::QueryInterface(REFIID iid, void**out)
165 {
166 if (!out) {
167 return E_POINTER;
168 }
169
170 HRESULT hr = S_OK;
171
172 if (iid == IID_IPin) {
173 *out = static_cast<IPin*>(this);
174 } else if (iid == IID_IUnknown) {
175 *out = static_cast<IUnknown*>(this);
176 } else if (m_direction == PINDIR_OUTPUT && (iid == IID_IMediaSeeking || iid == IID_IMediaPosition)) {
177 return m_parent->QueryInterface(iid, out);
178 } else {
179 *out = 0;
180 hr = E_NOINTERFACE;
181 }
182
183 if (hr == S_OK) {
184 AddRef();
185 }
186 return hr;
187 }
188
189 STDMETHODIMP_(ULONG) QPin::AddRef()
190 {
191 return InterlockedIncrement(&m_refCount);
192 }
193
194 STDMETHODIMP_(ULONG) QPin::Release()
195 {
196 ULONG refCount = InterlockedDecrement(&m_refCount);
197 if (refCount == 0) {
198 delete this;
199 }
200
201 return refCount;
202 }
203
204 //this is called on the input pins
205 STDMETHODIMP QPin::ReceiveConnection(IPin *pin, const AM_MEDIA_TYPE *type)
206 {
207 if (!pin ||!type) {
208 return E_POINTER;
209 }
210
211 if (connected()) {
212 return VFW_E_ALREADY_CONNECTED;
213 }
214
215 if (filterState() != State_Stopped) {
216 return VFW_E_NOT_STOPPED;
217 }
218
219 if (QueryAccept(type) != S_OK) {
220 return VFW_E_TYPE_NOT_ACCEPTED;
221 }
222
223 setConnected(pin);
224 setConnectedType(*type);
225
226 return S_OK;
227 }
228
229 //this is called on the output pins
230 STDMETHODIMP QPin::Connect(IPin *pin, const AM_MEDIA_TYPE *type)
231 {
232 if (!pin) {
233 return E_POINTER;
234 }
235
236 if (connected()) {
237 return VFW_E_ALREADY_CONNECTED;
238 }
239
240 if (filterState() != State_Stopped) {
241 return VFW_E_NOT_STOPPED;
242 }
243
244 HRESULT hr = S_OK;
245
246 setConnected(pin);
247 if (!type) {
248
249 //let(s first try the output pin's mediaTypes
250 if (checkOutputMediaTypesConnection(pin) != S_OK &&
251 checkOwnMediaTypesConnection(pin) != S_OK) {
252 hr = VFW_E_NO_ACCEPTABLE_TYPES;
253 }
254 } else if (QueryAccept(type) == S_OK) {
255 setConnectedType(*type);
256 hr = pin->ReceiveConnection(this, type);
257 } else {
258 hr = VFW_E_TYPE_NOT_ACCEPTED;
259 }
260
261 if (FAILED(hr)) {
262 setConnected(0);
263 setConnectedType(defaultMediaType);
264 } else {
265 ComPointer<IMemInputPin> input(pin, IID_IMemInputPin);
266 if (input) {
267 ComPointer<IMemAllocator> alloc;
268 input->GetAllocator(alloc.pparam());
269 if (alloc) {
270 //be default we take the allocator from the input pin
271 //we have no reason to force using our own
272 setMemoryAllocator(alloc);
273 }
274 }
275 if (memoryAllocator() == 0) {
276 ALLOCATOR_PROPERTIES prop;
277 if (input && input->GetAllocatorRequirements(&prop) == S_OK) {
278 createDefaultMemoryAllocator(&prop);
279 } else {
280 createDefaultMemoryAllocator();
281 }
282 }
283
284 Q_ASSERT(memoryAllocator() != 0);
285 if (input) {
286 input->NotifyAllocator(memoryAllocator(), TRUE); //TRUE is arbitrarily chosen here
287 }
288
289 }
290
291 return hr;
292 }
293
294 STDMETHODIMP QPin::Disconnect()
295 {
296 if (!connected()) {
297 return S_FALSE;
298 }
299
300 if (filterState() != State_Stopped) {
301 return VFW_E_NOT_STOPPED;
302 }
303
304 setConnected(0);
305 setConnectedType(defaultMediaType);
306 setMemoryAllocator(0);
307 return S_OK;
308 }
309
310 STDMETHODIMP QPin::ConnectedTo(IPin **other)
311 {
312 if (!other) {
313 return E_POINTER;
314 }
315
316 *other = connected(true);
317 if (!(*other)) {
318 return VFW_E_NOT_CONNECTED;
319 }
320
321 return S_OK;
322 }
323
324 STDMETHODIMP QPin::ConnectionMediaType(AM_MEDIA_TYPE *type)
325 {
326 QMutexLocker locker(&m_mutex);
327 if (!type) {
328 return E_POINTER;
329 }
330
331 *type = copyMediaType(m_connectedType);
332 if (!m_connected) {
333 return VFW_E_NOT_CONNECTED;
334 } else {
335 return S_OK;
336 }
337 }
338
339 STDMETHODIMP QPin::QueryPinInfo(PIN_INFO *info)
340 {
341 if (!info) {
342 return E_POINTER;
343 }
344
345 info->dir = m_direction;
346 info->pFilter = m_parent;
347 m_parent->AddRef();
348 info->achName[0] = 0;
349 return S_OK;
350 }
351
352 STDMETHODIMP QPin::QueryDirection(PIN_DIRECTION *dir)
353 {
354 if (!dir) {
355 return E_POINTER;
356 }
357
358 *dir = m_direction;
359 return S_OK;
360 }
361
362 STDMETHODIMP QPin::QueryId(LPWSTR *id)
363 {
364 if (!id) {
365 return E_POINTER;
366 }
367
368 *id = static_cast<LPWSTR>(::CoTaskMemAlloc(2));
369 *id[0] = 0;
370 return S_OK;
371 }
372
373 STDMETHODIMP QPin::QueryAccept(const AM_MEDIA_TYPE *type)
374 {
375 QMutexLocker locker(&m_mutex);
376 if (!type) {
377 return E_POINTER;
378 }
379
380 for (int i = 0; i < m_mediaTypes.count(); ++i) {
381 const AM_MEDIA_TYPE &current = m_mediaTypes.at(i);
382 if ( (type->majortype == current.majortype) &&
383 (current.subtype == MEDIASUBTYPE_NULL || type->subtype == current.subtype) &&
384 (type->majortype == MEDIATYPE_Stream || type->formattype != GUID_NULL || current.formattype != GUID_NULL) &&
385 (current.formattype == GUID_NULL || type->formattype == current.formattype)
386 ) {
387 return S_OK;
388 }
389 }
390 return S_FALSE;
391 }
392
393
394 STDMETHODIMP QPin::EnumMediaTypes(IEnumMediaTypes **emt)
395 {
396 if (!emt) {
397 return E_POINTER;
398 }
399
400 *emt = new QEnumMediaTypes(this);
401 return S_OK;
402 }
403
404
405 STDMETHODIMP QPin::EndOfStream()
406 {
407 return E_UNEXPECTED;
408 }
409
410 STDMETHODIMP QPin::BeginFlush()
411 {
412 return E_UNEXPECTED;
413 }
414
415 STDMETHODIMP QPin::EndFlush()
416 {
417 return E_UNEXPECTED;
418 }
419
420 STDMETHODIMP QPin::NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
421 {
422 QMutexLocker locker(&m_mutex);
423 if (m_direction == PINDIR_OUTPUT && m_connected) {
424 //we deliver this downstream
425 m_connected->NewSegment(start, stop, rate);
426 }
427 return S_OK;
428 }
429
430 STDMETHODIMP QPin::QueryInternalConnections(IPin **, ULONG*)
431 {
432 //this is not implemented on purpose (the input pins are connected to all the output pins)
433 return E_NOTIMPL;
434 }
435
436
437 HRESULT QPin::checkOutputMediaTypesConnection(IPin *pin)
438 {
439 ComPointer<IEnumMediaTypes> emt;
440 HRESULT hr = pin->EnumMediaTypes(emt.pparam());
441 if (hr != S_OK) {
442 return hr;
443 }
444
445 AM_MEDIA_TYPE *type = 0;
446 while (emt->Next(1, &type, 0) == S_OK) {
447 if (QueryAccept(type) == S_OK) {
448 setConnectedType(*type);
449 if (pin->ReceiveConnection(this, type) == S_OK) {
450 freeMediaType(type);
451 return S_OK;
452 } else {
453 setConnectedType(defaultMediaType);
454 freeMediaType(type);
455 }
456 }
457 }
458
459 //we didn't find a suitable type
460 return S_FALSE;
461 }
462
463 HRESULT QPin::checkOwnMediaTypesConnection(IPin *pin)
464 {
465 for(int i = 0; i < m_mediaTypes.count(); ++i) {
466 const AM_MEDIA_TYPE &current = m_mediaTypes.at(i);
467 setConnectedType(current);
468 HRESULT hr = pin->ReceiveConnection(this, &current);
469 if (hr == S_OK) {
470 return S_OK;
471 }
472 }
473
474 //we didn't find a suitable type
475 return S_FALSE;
476 }
477
478 void QPin::freeMediaType(const AM_MEDIA_TYPE &type)
479 {
480 if (type.cbFormat) {
481 ::CoTaskMemFree(type.pbFormat);
482 }
483 if (type.pUnk) {
484 type.pUnk->Release();
485 }
486 }
487
488 void QPin::freeMediaType(AM_MEDIA_TYPE *type)
489 {
490 freeMediaType(*type);
491 ::CoTaskMemFree(type);
492 }
493
494 //addition
495
496 PIN_DIRECTION QPin::direction() const
497 {
498 return m_direction;
499 }
500
501 void QPin::setConnectedType(const AM_MEDIA_TYPE &type)
502 {
503 QMutexLocker locker(&m_mutex);
504
505 //1st we free memory
506 freeMediaType(m_connectedType);
507
508 m_connectedType = copyMediaType(type);
509 }
510
511 const AM_MEDIA_TYPE &QPin::connectedType() const
512 {
513 QMutexLocker locker(&m_mutex);
514 return m_connectedType;
515 }
516
517 void QPin::setConnected(IPin *pin)
518 {
519 QMutexLocker locker(&m_mutex);
520 if (pin) {
521 pin->AddRef();
522 }
523 if (m_connected) {
524 m_connected->Release();
525 }
526 m_connected = pin;
527 }
528
529 IPin *QPin::connected(bool addref) const
530 {
531 QMutexLocker locker(&m_mutex);
532 if (addref && m_connected) {
533 m_connected->AddRef();
534 }
535 return m_connected;
536 }
537
538 bool QPin::isFlushing() const
539 {
540 QMutexLocker locker(&m_mutex);
541 return m_flushing;
542 }
543
544 FILTER_STATE QPin::filterState() const
545 {
546 FILTER_STATE fstate = State_Stopped;
547 m_parent->GetState(0, &fstate);
548 return fstate;
549 }
550
551 QVector<AM_MEDIA_TYPE> QPin::mediaTypes() const
552 {
553 QMutexLocker locker(&m_mutex);
554 return m_mediaTypes;
555 }
556
557 HRESULT QPin::setAcceptedMediaType(const AM_MEDIA_TYPE &mt)
558 {
559 const QVector<AM_MEDIA_TYPE> oldMediaTypes = m_mediaTypes;
560 m_mediaTypes = QVector<AM_MEDIA_TYPE>() << mt;
561
562 HRESULT hr = S_OK;
563
564 IPin *conn = connected();
565 if (conn) {
566 //try to reconnect to redefine the media type
567 conn->Disconnect();
568 Disconnect();
569 hr = Connect(conn, 0);
570 if (FAILED(hr)) {
571 m_mediaTypes = oldMediaTypes;
572 Connect(conn, 0); //just redo the connection with the old media types
573 }
574 }
575 return hr;
576 }
577
578 void QPin::createDefaultMemoryAllocator(ALLOCATOR_PROPERTIES *prop)
579 {
580 ComPointer<IMemAllocator> alloc(CLSID_MemoryAllocator, IID_IMemAllocator);
581 if (prop) {
582 alloc->SetProperties(prop, 0);
583 }
584 setMemoryAllocator(alloc);
585 }
586
587 void QPin::setMemoryAllocator(IMemAllocator *alloc)
588 {
589 QMutexLocker locker(&m_mutex);
590 if (alloc) {
591 alloc->AddRef();
592 }
593 if (m_memAlloc) {
594 m_memAlloc->Release();
595 }
596 m_memAlloc = alloc;
597 }
598
599 IMemAllocator *QPin::memoryAllocator(bool addref) const
600 {
601 QMutexLocker locker(&m_mutex);
602 if (addref && m_memAlloc) {
603 m_memAlloc->AddRef();
604 }
605 return m_memAlloc;
606 }
607
608 AM_MEDIA_TYPE QPin::copyMediaType(const AM_MEDIA_TYPE &type)
609 {
610 AM_MEDIA_TYPE ret = type;
611
612 //make a deep copy here
613 if (ret.cbFormat == 0 || ret.pbFormat == 0) {
614 ret.cbFormat = 0;
615 ret.pbFormat = 0;
616 ret.formattype = GUID_NULL;
617 } else {
618 ret.pbFormat = reinterpret_cast<BYTE*>(::CoTaskMemAlloc(type.cbFormat));
619 qMemCopy(ret.pbFormat, type.pbFormat, type.cbFormat);
620 }
621
622 if (type.pUnk) {
623 type.pUnk->AddRef();
624 }
625 return ret;
626 }
627
628
629 }
630}
631
632QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.