Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpin.c
Go to the documentation of this file.
00001 /* 00002 * Generic Implementation of IPin Interface 00003 * 00004 * Copyright 2003 Robert Shearman 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #include "quartz_private.h" 00022 #include "pin.h" 00023 00024 #include "wine/debug.h" 00025 #include "wine/unicode.h" 00026 #include "uuids.h" 00027 #include "vfwmsgs.h" 00028 #include <assert.h> 00029 00030 WINE_DEFAULT_DEBUG_CHANNEL(quartz); 00031 00032 static const IPinVtbl InputPin_Vtbl; 00033 static const IPinVtbl OutputPin_Vtbl; 00034 static const IMemInputPinVtbl MemInputPin_Vtbl; 00035 static const IPinVtbl PullPin_Vtbl; 00036 00037 #define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary)) 00038 #define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary))) 00039 00040 typedef HRESULT (*SendPinFunc)( IPin *to, LPVOID arg ); 00041 00048 HRESULT updatehres( HRESULT original, HRESULT new ) 00049 { 00050 if (FAILED( original ) || new == E_NOTIMPL) 00051 return original; 00052 00053 if (FAILED( new ) || original == S_OK) 00054 return new; 00055 00056 return original; 00057 } 00058 00066 static HRESULT SendFurther( IPin *from, SendPinFunc fnMiddle, LPVOID arg, SendPinFunc fnEnd ) 00067 { 00068 PIN_INFO pin_info; 00069 ULONG amount = 0; 00070 HRESULT hr = S_OK; 00071 HRESULT hr_return = S_OK; 00072 IEnumPins *enumpins = NULL; 00073 BOOL foundend = TRUE; 00074 PIN_DIRECTION from_dir; 00075 00076 IPin_QueryDirection( from, &from_dir ); 00077 00078 hr = IPin_QueryInternalConnections( from, NULL, &amount ); 00079 if (hr != E_NOTIMPL && amount) 00080 FIXME("Use QueryInternalConnections!\n"); 00081 hr = S_OK; 00082 00083 pin_info.pFilter = NULL; 00084 hr = IPin_QueryPinInfo( from, &pin_info ); 00085 if (FAILED(hr)) 00086 goto out; 00087 00088 hr = IBaseFilter_EnumPins( pin_info.pFilter, &enumpins ); 00089 if (FAILED(hr)) 00090 goto out; 00091 00092 hr = IEnumPins_Reset( enumpins ); 00093 while (hr == S_OK) { 00094 IPin *pin = NULL; 00095 hr = IEnumPins_Next( enumpins, 1, &pin, NULL ); 00096 if (hr == VFW_E_ENUM_OUT_OF_SYNC) 00097 { 00098 hr = IEnumPins_Reset( enumpins ); 00099 continue; 00100 } 00101 if (pin) 00102 { 00103 PIN_DIRECTION dir; 00104 00105 IPin_QueryDirection( pin, &dir ); 00106 if (dir != from_dir) 00107 { 00108 IPin *connected = NULL; 00109 00110 foundend = FALSE; 00111 IPin_ConnectedTo( pin, &connected ); 00112 if (connected) 00113 { 00114 HRESULT hr_local; 00115 00116 hr_local = fnMiddle( connected, arg ); 00117 hr_return = updatehres( hr_return, hr_local ); 00118 IPin_Release(connected); 00119 } 00120 } 00121 IPin_Release( pin ); 00122 } 00123 else 00124 { 00125 hr = S_OK; 00126 break; 00127 } 00128 } 00129 00130 if (!foundend) 00131 hr = hr_return; 00132 else if (fnEnd) { 00133 HRESULT hr_local; 00134 00135 hr_local = fnEnd( from, arg ); 00136 hr_return = updatehres( hr_return, hr_local ); 00137 } 00138 00139 out: 00140 if (pin_info.pFilter) 00141 IBaseFilter_Release( pin_info.pFilter ); 00142 return hr; 00143 } 00144 00145 00146 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc) 00147 { 00148 /* Tempting to just do a memcpy, but the name field is 00149 128 characters long! We will probably never exceed 10 00150 most of the time, so we are better off copying 00151 each field manually */ 00152 strcpyW(pDest->achName, pSrc->achName); 00153 pDest->dir = pSrc->dir; 00154 pDest->pFilter = pSrc->pFilter; 00155 } 00156 00157 /*** Common pin functions ***/ 00158 00159 ULONG WINAPI IPinImpl_AddRef(IPin * iface) 00160 { 00161 IPinImpl *This = (IPinImpl *)iface; 00162 ULONG refCount = InterlockedIncrement(&This->refCount); 00163 00164 TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1); 00165 00166 return refCount; 00167 } 00168 00169 HRESULT WINAPI IPinImpl_Disconnect(IPin * iface) 00170 { 00171 HRESULT hr; 00172 IPinImpl *This = (IPinImpl *)iface; 00173 00174 TRACE("()\n"); 00175 00176 EnterCriticalSection(This->pCritSec); 00177 { 00178 if (This->pConnectedTo) 00179 { 00180 IPin_Release(This->pConnectedTo); 00181 This->pConnectedTo = NULL; 00182 FreeMediaType(&This->mtCurrent); 00183 ZeroMemory(&This->mtCurrent, sizeof(This->mtCurrent)); 00184 hr = S_OK; 00185 } 00186 else 00187 hr = S_FALSE; 00188 } 00189 LeaveCriticalSection(This->pCritSec); 00190 00191 return hr; 00192 } 00193 00194 HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin) 00195 { 00196 HRESULT hr; 00197 IPinImpl *This = (IPinImpl *)iface; 00198 00199 TRACE("(%p)\n", ppPin); 00200 00201 EnterCriticalSection(This->pCritSec); 00202 { 00203 if (This->pConnectedTo) 00204 { 00205 *ppPin = This->pConnectedTo; 00206 IPin_AddRef(*ppPin); 00207 hr = S_OK; 00208 } 00209 else 00210 { 00211 hr = VFW_E_NOT_CONNECTED; 00212 *ppPin = NULL; 00213 } 00214 } 00215 LeaveCriticalSection(This->pCritSec); 00216 00217 return hr; 00218 } 00219 00220 HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt) 00221 { 00222 HRESULT hr; 00223 IPinImpl *This = (IPinImpl *)iface; 00224 00225 TRACE("(%p/%p)->(%p)\n", This, iface, pmt); 00226 00227 EnterCriticalSection(This->pCritSec); 00228 { 00229 if (This->pConnectedTo) 00230 { 00231 CopyMediaType(pmt, &This->mtCurrent); 00232 hr = S_OK; 00233 } 00234 else 00235 { 00236 ZeroMemory(pmt, sizeof(*pmt)); 00237 hr = VFW_E_NOT_CONNECTED; 00238 } 00239 } 00240 LeaveCriticalSection(This->pCritSec); 00241 00242 return hr; 00243 } 00244 00245 HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo) 00246 { 00247 IPinImpl *This = (IPinImpl *)iface; 00248 00249 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo); 00250 00251 Copy_PinInfo(pInfo, &This->pinInfo); 00252 IBaseFilter_AddRef(pInfo->pFilter); 00253 00254 return S_OK; 00255 } 00256 00257 HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir) 00258 { 00259 IPinImpl *This = (IPinImpl *)iface; 00260 00261 TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir); 00262 00263 *pPinDir = This->pinInfo.dir; 00264 00265 return S_OK; 00266 } 00267 00268 HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id) 00269 { 00270 IPinImpl *This = (IPinImpl *)iface; 00271 00272 TRACE("(%p/%p)->(%p)\n", This, iface, Id); 00273 00274 *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR)); 00275 if (!*Id) 00276 return E_OUTOFMEMORY; 00277 00278 strcpyW(*Id, This->pinInfo.achName); 00279 00280 return S_OK; 00281 } 00282 00283 HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt) 00284 { 00285 IPinImpl *This = (IPinImpl *)iface; 00286 00287 TRACE("(%p/%p)->(%p)\n", This, iface, pmt); 00288 00289 return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE); 00290 } 00291 00292 HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) 00293 { 00294 IPinImpl *This = (IPinImpl *)iface; 00295 ENUMMEDIADETAILS emd; 00296 00297 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); 00298 00299 /* override this method to allow enumeration of your types */ 00300 emd.cMediaTypes = 0; 00301 emd.pMediaTypes = NULL; 00302 00303 return IEnumMediaTypesImpl_Construct(&emd, ppEnum); 00304 } 00305 00306 HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin) 00307 { 00308 IPinImpl *This = (IPinImpl *)iface; 00309 00310 TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin); 00311 00312 return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */ 00313 } 00314 00315 /*** IPin implementation for an input pin ***/ 00316 00317 HRESULT WINAPI InputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) 00318 { 00319 InputPin *This = (InputPin *)iface; 00320 00321 TRACE("(%p)->(%s, %p)\n", iface, qzdebugstr_guid(riid), ppv); 00322 00323 *ppv = NULL; 00324 00325 if (IsEqualIID(riid, &IID_IUnknown)) 00326 *ppv = iface; 00327 else if (IsEqualIID(riid, &IID_IPin)) 00328 *ppv = iface; 00329 else if (IsEqualIID(riid, &IID_IMemInputPin)) 00330 *ppv = &This->lpVtblMemInput; 00331 else if (IsEqualIID(riid, &IID_IMediaSeeking)) 00332 { 00333 return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); 00334 } 00335 00336 if (*ppv) 00337 { 00338 IUnknown_AddRef((IUnknown *)(*ppv)); 00339 return S_OK; 00340 } 00341 00342 FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); 00343 00344 return E_NOINTERFACE; 00345 } 00346 00347 ULONG WINAPI InputPin_Release(IPin * iface) 00348 { 00349 InputPin *This = (InputPin *)iface; 00350 ULONG refCount = InterlockedDecrement(&This->pin.refCount); 00351 00352 TRACE("(%p)->() Release from %d\n", iface, refCount + 1); 00353 00354 if (!refCount) 00355 { 00356 FreeMediaType(&This->pin.mtCurrent); 00357 if (This->pAllocator) 00358 IMemAllocator_Release(This->pAllocator); 00359 This->pAllocator = NULL; 00360 This->pin.lpVtbl = NULL; 00361 CoTaskMemFree(This); 00362 return 0; 00363 } 00364 else 00365 return refCount; 00366 } 00367 00368 HRESULT WINAPI InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt) 00369 { 00370 ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector, pmt); 00371 00372 return E_UNEXPECTED; 00373 } 00374 00375 00376 HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 00377 { 00378 InputPin *This = (InputPin *)iface; 00379 PIN_DIRECTION pindirReceive; 00380 HRESULT hr = S_OK; 00381 00382 TRACE("(%p, %p)\n", pReceivePin, pmt); 00383 dump_AM_MEDIA_TYPE(pmt); 00384 00385 EnterCriticalSection(This->pin.pCritSec); 00386 { 00387 if (This->pin.pConnectedTo) 00388 hr = VFW_E_ALREADY_CONNECTED; 00389 00390 if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK) 00391 hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 00392 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */ 00393 00394 if (SUCCEEDED(hr)) 00395 { 00396 IPin_QueryDirection(pReceivePin, &pindirReceive); 00397 00398 if (pindirReceive != PINDIR_OUTPUT) 00399 { 00400 ERR("Can't connect from non-output pin\n"); 00401 hr = VFW_E_INVALID_DIRECTION; 00402 } 00403 } 00404 00405 if (SUCCEEDED(hr)) 00406 { 00407 CopyMediaType(&This->pin.mtCurrent, pmt); 00408 This->pin.pConnectedTo = pReceivePin; 00409 IPin_AddRef(pReceivePin); 00410 } 00411 } 00412 LeaveCriticalSection(This->pin.pCritSec); 00413 00414 return hr; 00415 } 00416 00417 static HRESULT deliver_endofstream(IPin* pin, LPVOID unused) 00418 { 00419 return IPin_EndOfStream( pin ); 00420 } 00421 00422 HRESULT WINAPI InputPin_EndOfStream(IPin * iface) 00423 { 00424 HRESULT hr = S_OK; 00425 InputPin *This = (InputPin *)iface; 00426 00427 TRACE("(%p)\n", This); 00428 00429 EnterCriticalSection(This->pin.pCritSec); 00430 if (This->flushing) 00431 hr = S_FALSE; 00432 else 00433 This->end_of_stream = 1; 00434 LeaveCriticalSection(This->pin.pCritSec); 00435 00436 if (hr == S_OK) 00437 hr = SendFurther( iface, deliver_endofstream, NULL, NULL ); 00438 return hr; 00439 } 00440 00441 static HRESULT deliver_beginflush(IPin* pin, LPVOID unused) 00442 { 00443 return IPin_BeginFlush( pin ); 00444 } 00445 00446 HRESULT WINAPI InputPin_BeginFlush(IPin * iface) 00447 { 00448 InputPin *This = (InputPin *)iface; 00449 HRESULT hr; 00450 TRACE("() semi-stub\n"); 00451 00452 EnterCriticalSection(This->pin.pCritSec); 00453 This->flushing = 1; 00454 00455 if (This->fnCleanProc) 00456 This->fnCleanProc(This->pin.pUserData); 00457 00458 hr = SendFurther( iface, deliver_beginflush, NULL, NULL ); 00459 LeaveCriticalSection(This->pin.pCritSec); 00460 00461 return hr; 00462 } 00463 00464 static HRESULT deliver_endflush(IPin* pin, LPVOID unused) 00465 { 00466 return IPin_EndFlush( pin ); 00467 } 00468 00469 HRESULT WINAPI InputPin_EndFlush(IPin * iface) 00470 { 00471 InputPin *This = (InputPin *)iface; 00472 HRESULT hr; 00473 TRACE("(%p)\n", This); 00474 00475 EnterCriticalSection(This->pin.pCritSec); 00476 This->flushing = This->end_of_stream = 0; 00477 00478 hr = SendFurther( iface, deliver_endflush, NULL, NULL ); 00479 LeaveCriticalSection(This->pin.pCritSec); 00480 00481 return hr; 00482 } 00483 00484 typedef struct newsegmentargs 00485 { 00486 REFERENCE_TIME tStart, tStop; 00487 double rate; 00488 } newsegmentargs; 00489 00490 static HRESULT deliver_newsegment(IPin *pin, LPVOID data) 00491 { 00492 newsegmentargs *args = data; 00493 return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate); 00494 } 00495 00496 HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) 00497 { 00498 InputPin *This = (InputPin *)iface; 00499 newsegmentargs args; 00500 00501 TRACE("(%x%08x, %x%08x, %e)\n", (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate); 00502 00503 args.tStart = This->tStart = tStart; 00504 args.tStop = This->tStop = tStop; 00505 args.rate = This->dRate = dRate; 00506 00507 return SendFurther( iface, deliver_newsegment, &args, NULL ); 00508 } 00509 00510 static const IPinVtbl InputPin_Vtbl = 00511 { 00512 InputPin_QueryInterface, 00513 IPinImpl_AddRef, 00514 InputPin_Release, 00515 InputPin_Connect, 00516 InputPin_ReceiveConnection, 00517 IPinImpl_Disconnect, 00518 IPinImpl_ConnectedTo, 00519 IPinImpl_ConnectionMediaType, 00520 IPinImpl_QueryPinInfo, 00521 IPinImpl_QueryDirection, 00522 IPinImpl_QueryId, 00523 IPinImpl_QueryAccept, 00524 IPinImpl_EnumMediaTypes, 00525 IPinImpl_QueryInternalConnections, 00526 InputPin_EndOfStream, 00527 InputPin_BeginFlush, 00528 InputPin_EndFlush, 00529 InputPin_NewSegment 00530 }; 00531 00532 /*** IMemInputPin implementation ***/ 00533 00534 static inline InputPin *impl_from_IMemInputPin( IMemInputPin *iface ) 00535 { 00536 return (InputPin *)((char*)iface - FIELD_OFFSET(InputPin, lpVtblMemInput)); 00537 } 00538 00539 static HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv) 00540 { 00541 InputPin *This = impl_from_IMemInputPin(iface); 00542 00543 return IPin_QueryInterface((IPin *)&This->pin, riid, ppv); 00544 } 00545 00546 static ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface) 00547 { 00548 InputPin *This = impl_from_IMemInputPin(iface); 00549 00550 return IPin_AddRef((IPin *)&This->pin); 00551 } 00552 00553 static ULONG WINAPI MemInputPin_Release(IMemInputPin * iface) 00554 { 00555 InputPin *This = impl_from_IMemInputPin(iface); 00556 00557 return IPin_Release((IPin *)&This->pin); 00558 } 00559 00560 static HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator) 00561 { 00562 InputPin *This = impl_from_IMemInputPin(iface); 00563 00564 TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator); 00565 00566 *ppAllocator = This->pAllocator; 00567 if (*ppAllocator) 00568 IMemAllocator_AddRef(*ppAllocator); 00569 00570 return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR; 00571 } 00572 00573 static HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly) 00574 { 00575 InputPin *This = impl_from_IMemInputPin(iface); 00576 00577 TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly); 00578 00579 if (bReadOnly) 00580 FIXME("Read only flag not handled yet!\n"); 00581 00582 /* FIXME: Should we release the allocator on disconnection? */ 00583 if (!pAllocator) 00584 { 00585 WARN("Null allocator\n"); 00586 return E_POINTER; 00587 } 00588 00589 if (This->preferred_allocator && pAllocator != This->preferred_allocator) 00590 return E_FAIL; 00591 00592 if (This->pAllocator) 00593 IMemAllocator_Release(This->pAllocator); 00594 This->pAllocator = pAllocator; 00595 if (This->pAllocator) 00596 IMemAllocator_AddRef(This->pAllocator); 00597 00598 return S_OK; 00599 } 00600 00601 static HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps) 00602 { 00603 InputPin *This = impl_from_IMemInputPin(iface); 00604 00605 TRACE("(%p/%p)->(%p)\n", This, iface, pProps); 00606 00607 /* override this method if you have any specific requirements */ 00608 00609 return E_NOTIMPL; 00610 } 00611 00612 static HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample) 00613 { 00614 InputPin *This = impl_from_IMemInputPin(iface); 00615 HRESULT hr; 00616 00617 /* this trace commented out for performance reasons */ 00618 /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/ 00619 hr = This->fnSampleProc(This->pin.pUserData, pSample); 00620 return hr; 00621 } 00622 00623 static HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, LONG nSamples, LONG *nSamplesProcessed) 00624 { 00625 HRESULT hr = S_OK; 00626 InputPin *This = impl_from_IMemInputPin(iface); 00627 00628 TRACE("(%p/%p)->(%p, %d, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed); 00629 00630 for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++) 00631 { 00632 hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]); 00633 if (hr != S_OK) 00634 break; 00635 } 00636 00637 return hr; 00638 } 00639 00640 static HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface) 00641 { 00642 InputPin *This = impl_from_IMemInputPin(iface); 00643 00644 TRACE("(%p/%p)->()\n", This, iface); 00645 00646 return S_OK; 00647 } 00648 00649 static const IMemInputPinVtbl MemInputPin_Vtbl = 00650 { 00651 MemInputPin_QueryInterface, 00652 MemInputPin_AddRef, 00653 MemInputPin_Release, 00654 MemInputPin_GetAllocator, 00655 MemInputPin_NotifyAllocator, 00656 MemInputPin_GetAllocatorRequirements, 00657 MemInputPin_Receive, 00658 MemInputPin_ReceiveMultiple, 00659 MemInputPin_ReceiveCanBlock 00660 }; 00661 00662 /*** OutputPin implementation ***/ 00663 00664 HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) 00665 { 00666 OutputPin *This = (OutputPin *)iface; 00667 00668 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); 00669 00670 *ppv = NULL; 00671 00672 if (IsEqualIID(riid, &IID_IUnknown)) 00673 *ppv = iface; 00674 else if (IsEqualIID(riid, &IID_IPin)) 00675 *ppv = iface; 00676 else if (IsEqualIID(riid, &IID_IMediaSeeking)) 00677 { 00678 return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); 00679 } 00680 00681 if (*ppv) 00682 { 00683 IUnknown_AddRef((IUnknown *)(*ppv)); 00684 return S_OK; 00685 } 00686 00687 FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); 00688 00689 return E_NOINTERFACE; 00690 } 00691 00692 ULONG WINAPI OutputPin_Release(IPin * iface) 00693 { 00694 OutputPin *This = (OutputPin *)iface; 00695 ULONG refCount = InterlockedDecrement(&This->pin.refCount); 00696 00697 TRACE("(%p)->() Release from %d\n", iface, refCount + 1); 00698 00699 if (!refCount) 00700 { 00701 FreeMediaType(&This->pin.mtCurrent); 00702 CoTaskMemFree(This); 00703 return 0; 00704 } 00705 return refCount; 00706 } 00707 00708 HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 00709 { 00710 HRESULT hr; 00711 OutputPin *This = (OutputPin *)iface; 00712 00713 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); 00714 dump_AM_MEDIA_TYPE(pmt); 00715 00716 /* If we try to connect to ourself, we will definitely deadlock. 00717 * There are other cases where we could deadlock too, but this 00718 * catches the obvious case */ 00719 assert(pReceivePin != iface); 00720 00721 EnterCriticalSection(This->pin.pCritSec); 00722 { 00723 /* if we have been a specific type to connect with, then we can either connect 00724 * with that or fail. We cannot choose different AM_MEDIA_TYPE */ 00725 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL)) 00726 hr = This->pConnectSpecific(iface, pReceivePin, pmt); 00727 else 00728 { 00729 /* negotiate media type */ 00730 00731 IEnumMediaTypes * pEnumCandidates; 00732 AM_MEDIA_TYPE * pmtCandidate = NULL; /* Candidate media type */ 00733 00734 if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates))) 00735 { 00736 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ 00737 00738 /* try this filter's media types first */ 00739 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) 00740 { 00741 assert(pmtCandidate); 00742 dump_AM_MEDIA_TYPE(pmtCandidate); 00743 if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype) 00744 && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype)) 00745 assert(pmtCandidate->pbFormat); 00746 if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 00747 (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) 00748 { 00749 hr = S_OK; 00750 DeleteMediaType(pmtCandidate); 00751 break; 00752 } 00753 DeleteMediaType(pmtCandidate); 00754 pmtCandidate = NULL; 00755 } 00756 IEnumMediaTypes_Release(pEnumCandidates); 00757 } 00758 00759 /* then try receiver filter's media types */ 00760 if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */ 00761 { 00762 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ 00763 00764 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) 00765 { 00766 assert(pmtCandidate); 00767 dump_AM_MEDIA_TYPE(pmtCandidate); 00768 if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 00769 (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) 00770 { 00771 hr = S_OK; 00772 DeleteMediaType(pmtCandidate); 00773 break; 00774 } 00775 DeleteMediaType(pmtCandidate); 00776 pmtCandidate = NULL; 00777 } /* while */ 00778 IEnumMediaTypes_Release(pEnumCandidates); 00779 } /* if not found */ 00780 } /* if negotiate media type */ 00781 } /* if succeeded */ 00782 LeaveCriticalSection(This->pin.pCritSec); 00783 00784 TRACE(" -- %x\n", hr); 00785 return hr; 00786 } 00787 00788 HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 00789 { 00790 ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt); 00791 00792 return E_UNEXPECTED; 00793 } 00794 00795 HRESULT WINAPI OutputPin_Disconnect(IPin * iface) 00796 { 00797 HRESULT hr; 00798 OutputPin *This = (OutputPin *)iface; 00799 00800 TRACE("()\n"); 00801 00802 EnterCriticalSection(This->pin.pCritSec); 00803 { 00804 if (This->pMemInputPin) 00805 { 00806 IMemInputPin_Release(This->pMemInputPin); 00807 This->pMemInputPin = NULL; 00808 } 00809 if (This->pin.pConnectedTo) 00810 { 00811 IPin_Release(This->pin.pConnectedTo); 00812 This->pin.pConnectedTo = NULL; 00813 FreeMediaType(&This->pin.mtCurrent); 00814 ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); 00815 hr = S_OK; 00816 } 00817 else 00818 hr = S_FALSE; 00819 } 00820 LeaveCriticalSection(This->pin.pCritSec); 00821 00822 return hr; 00823 } 00824 00825 HRESULT WINAPI OutputPin_EndOfStream(IPin * iface) 00826 { 00827 TRACE("()\n"); 00828 00829 /* not supposed to do anything in an output pin */ 00830 00831 return E_UNEXPECTED; 00832 } 00833 00834 HRESULT WINAPI OutputPin_BeginFlush(IPin * iface) 00835 { 00836 TRACE("(%p)->()\n", iface); 00837 00838 /* not supposed to do anything in an output pin */ 00839 00840 return E_UNEXPECTED; 00841 } 00842 00843 HRESULT WINAPI OutputPin_EndFlush(IPin * iface) 00844 { 00845 TRACE("(%p)->()\n", iface); 00846 00847 /* not supposed to do anything in an output pin */ 00848 00849 return E_UNEXPECTED; 00850 } 00851 00852 HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) 00853 { 00854 TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate); 00855 00856 /* not supposed to do anything in an output pin */ 00857 00858 return E_UNEXPECTED; 00859 } 00860 00861 static const IPinVtbl OutputPin_Vtbl = 00862 { 00863 OutputPin_QueryInterface, 00864 IPinImpl_AddRef, 00865 OutputPin_Release, 00866 OutputPin_Connect, 00867 OutputPin_ReceiveConnection, 00868 OutputPin_Disconnect, 00869 IPinImpl_ConnectedTo, 00870 IPinImpl_ConnectionMediaType, 00871 IPinImpl_QueryPinInfo, 00872 IPinImpl_QueryDirection, 00873 IPinImpl_QueryId, 00874 IPinImpl_QueryAccept, 00875 IPinImpl_EnumMediaTypes, 00876 IPinImpl_QueryInternalConnections, 00877 OutputPin_EndOfStream, 00878 OutputPin_BeginFlush, 00879 OutputPin_EndFlush, 00880 OutputPin_NewSegment 00881 }; 00882 00883 HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags) 00884 { 00885 HRESULT hr; 00886 00887 TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags); 00888 00889 EnterCriticalSection(This->pin.pCritSec); 00890 { 00891 if (!This->pin.pConnectedTo) 00892 hr = VFW_E_NOT_CONNECTED; 00893 else 00894 { 00895 IMemAllocator * pAlloc = NULL; 00896 00897 hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); 00898 00899 if (SUCCEEDED(hr)) 00900 hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags); 00901 00902 if (SUCCEEDED(hr)) 00903 hr = IMediaSample_SetTime(*ppSample, tStart, tStop); 00904 00905 if (pAlloc) 00906 IMemAllocator_Release(pAlloc); 00907 } 00908 } 00909 LeaveCriticalSection(This->pin.pCritSec); 00910 00911 return hr; 00912 } 00913 00914 HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample) 00915 { 00916 HRESULT hr = S_OK; 00917 IMemInputPin * pMemConnected = NULL; 00918 PIN_INFO pinInfo; 00919 00920 EnterCriticalSection(This->pin.pCritSec); 00921 { 00922 if (!This->pin.pConnectedTo || !This->pMemInputPin) 00923 hr = VFW_E_NOT_CONNECTED; 00924 else 00925 { 00926 /* we don't have the lock held when using This->pMemInputPin, 00927 * so we need to AddRef it to stop it being deleted while we are 00928 * using it. Same with its filter. */ 00929 pMemConnected = This->pMemInputPin; 00930 IMemInputPin_AddRef(pMemConnected); 00931 hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo); 00932 } 00933 } 00934 LeaveCriticalSection(This->pin.pCritSec); 00935 00936 if (SUCCEEDED(hr)) 00937 { 00938 /* NOTE: if we are in a critical section when Receive is called 00939 * then it causes some problems (most notably with the native Video 00940 * Renderer) if we are re-entered for whatever reason */ 00941 hr = IMemInputPin_Receive(pMemConnected, pSample); 00942 00943 /* If the filter's destroyed, tell upstream to stop sending data */ 00944 if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr)) 00945 hr = S_FALSE; 00946 } 00947 if (pMemConnected) 00948 IMemInputPin_Release(pMemConnected); 00949 00950 return hr; 00951 } 00952 00953 HRESULT OutputPin_CommitAllocator(OutputPin * This) 00954 { 00955 HRESULT hr = S_OK; 00956 00957 TRACE("(%p)->()\n", This); 00958 00959 EnterCriticalSection(This->pin.pCritSec); 00960 { 00961 if (!This->pin.pConnectedTo || !This->pMemInputPin) 00962 hr = VFW_E_NOT_CONNECTED; 00963 else 00964 { 00965 IMemAllocator * pAlloc = NULL; 00966 00967 hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); 00968 00969 if (SUCCEEDED(hr)) 00970 hr = IMemAllocator_Commit(pAlloc); 00971 00972 if (pAlloc) 00973 IMemAllocator_Release(pAlloc); 00974 } 00975 } 00976 LeaveCriticalSection(This->pin.pCritSec); 00977 00978 TRACE("--> %08x\n", hr); 00979 return hr; 00980 } 00981 00982 HRESULT OutputPin_DecommitAllocator(OutputPin * This) 00983 { 00984 HRESULT hr = S_OK; 00985 00986 TRACE("(%p)->()\n", This); 00987 00988 EnterCriticalSection(This->pin.pCritSec); 00989 { 00990 if (!This->pin.pConnectedTo || !This->pMemInputPin) 00991 hr = VFW_E_NOT_CONNECTED; 00992 else 00993 { 00994 IMemAllocator * pAlloc = NULL; 00995 00996 hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); 00997 00998 if (SUCCEEDED(hr)) 00999 hr = IMemAllocator_Decommit(pAlloc); 01000 01001 if (pAlloc) 01002 IMemAllocator_Release(pAlloc); 01003 } 01004 } 01005 LeaveCriticalSection(This->pin.pCritSec); 01006 01007 TRACE("--> %08x\n", hr); 01008 return hr; 01009 } 01010 01011 HRESULT OutputPin_DeliverDisconnect(OutputPin * This) 01012 { 01013 HRESULT hr; 01014 01015 TRACE("(%p)->()\n", This); 01016 01017 EnterCriticalSection(This->pin.pCritSec); 01018 { 01019 if (!This->pin.pConnectedTo || !This->pMemInputPin) 01020 hr = VFW_E_NOT_CONNECTED; 01021 else if (!This->custom_allocator) 01022 { 01023 IMemAllocator * pAlloc = NULL; 01024 01025 hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); 01026 01027 if (SUCCEEDED(hr)) 01028 hr = IMemAllocator_Decommit(pAlloc); 01029 01030 if (pAlloc) 01031 IMemAllocator_Release(pAlloc); 01032 01033 if (SUCCEEDED(hr)) 01034 hr = IPin_Disconnect(This->pin.pConnectedTo); 01035 } 01036 else /* Kill the allocator! */ 01037 { 01038 hr = IPin_Disconnect(This->pin.pConnectedTo); 01039 } 01040 IPin_Disconnect((IPin *)This); 01041 } 01042 LeaveCriticalSection(This->pin.pCritSec); 01043 01044 return hr; 01045 } 01046 01047 /*** PullPin implementation ***/ 01048 01049 static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, 01050 QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl) 01051 { 01052 /* Common attributes */ 01053 pPinImpl->pin.lpVtbl = PullPin_Vtbl; 01054 pPinImpl->pin.refCount = 1; 01055 pPinImpl->pin.pConnectedTo = NULL; 01056 pPinImpl->pin.fnQueryAccept = pQueryAccept; 01057 pPinImpl->pin.pUserData = pUserData; 01058 pPinImpl->pin.pCritSec = pCritSec; 01059 Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); 01060 ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); 01061 01062 /* Input pin attributes */ 01063 pPinImpl->fnSampleProc = pSampleProc; 01064 pPinImpl->fnCleanProc = pCleanUp; 01065 pPinImpl->fnDone = pDone; 01066 pPinImpl->fnPreConnect = NULL; 01067 pPinImpl->pAlloc = NULL; 01068 pPinImpl->pReader = NULL; 01069 pPinImpl->hThread = NULL; 01070 pPinImpl->hEventStateChanged = CreateEventW(NULL, TRUE, TRUE, NULL); 01071 pPinImpl->thread_sleepy = CreateEventW(NULL, FALSE, FALSE, NULL); 01072 01073 pPinImpl->rtStart = 0; 01074 pPinImpl->rtCurrent = 0; 01075 pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff; 01076 pPinImpl->dRate = 1.0; 01077 pPinImpl->state = Req_Die; 01078 pPinImpl->fnCustomRequest = pCustomRequest; 01079 pPinImpl->stop_playback = 1; 01080 01081 InitializeCriticalSection(&pPinImpl->thread_lock); 01082 pPinImpl->thread_lock.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": PullPin.thread_lock"); 01083 01084 return S_OK; 01085 } 01086 01087 HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) 01088 { 01089 PullPin * pPinImpl; 01090 01091 *ppPin = NULL; 01092 01093 if (pPinInfo->dir != PINDIR_INPUT) 01094 { 01095 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir); 01096 return E_INVALIDARG; 01097 } 01098 01099 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl)); 01100 01101 if (!pPinImpl) 01102 return E_OUTOFMEMORY; 01103 01104 if (SUCCEEDED(PullPin_Init(PullPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCustomRequest, pDone, pCritSec, pPinImpl))) 01105 { 01106 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); 01107 return S_OK; 01108 } 01109 01110 CoTaskMemFree(pPinImpl); 01111 return E_FAIL; 01112 } 01113 01114 static HRESULT PullPin_InitProcessing(PullPin * This); 01115 01116 HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 01117 { 01118 PIN_DIRECTION pindirReceive; 01119 HRESULT hr = S_OK; 01120 PullPin *This = (PullPin *)iface; 01121 01122 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); 01123 dump_AM_MEDIA_TYPE(pmt); 01124 01125 EnterCriticalSection(This->pin.pCritSec); 01126 if (!This->pin.pConnectedTo) 01127 { 01128 ALLOCATOR_PROPERTIES props; 01129 01130 props.cBuffers = 3; 01131 props.cbBuffer = 64 * 1024; /* 64k bytes */ 01132 props.cbAlign = 1; 01133 props.cbPrefix = 0; 01134 01135 if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)) 01136 hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 01137 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */ 01138 01139 if (SUCCEEDED(hr)) 01140 { 01141 IPin_QueryDirection(pReceivePin, &pindirReceive); 01142 01143 if (pindirReceive != PINDIR_OUTPUT) 01144 { 01145 ERR("Can't connect from non-output pin\n"); 01146 hr = VFW_E_INVALID_DIRECTION; 01147 } 01148 } 01149 01150 This->pReader = NULL; 01151 This->pAlloc = NULL; 01152 if (SUCCEEDED(hr)) 01153 { 01154 hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader); 01155 } 01156 01157 if (SUCCEEDED(hr) && This->fnPreConnect) 01158 { 01159 hr = This->fnPreConnect(iface, pReceivePin, &props); 01160 } 01161 01162 if (SUCCEEDED(hr)) 01163 { 01164 hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc); 01165 } 01166 01167 if (SUCCEEDED(hr)) 01168 { 01169 CopyMediaType(&This->pin.mtCurrent, pmt); 01170 This->pin.pConnectedTo = pReceivePin; 01171 IPin_AddRef(pReceivePin); 01172 hr = IMemAllocator_Commit(This->pAlloc); 01173 } 01174 01175 if (SUCCEEDED(hr)) 01176 hr = PullPin_InitProcessing(This); 01177 01178 if (FAILED(hr)) 01179 { 01180 if (This->pReader) 01181 IAsyncReader_Release(This->pReader); 01182 This->pReader = NULL; 01183 if (This->pAlloc) 01184 IMemAllocator_Release(This->pAlloc); 01185 This->pAlloc = NULL; 01186 } 01187 } 01188 else 01189 hr = VFW_E_ALREADY_CONNECTED; 01190 LeaveCriticalSection(This->pin.pCritSec); 01191 return hr; 01192 } 01193 01194 HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) 01195 { 01196 PullPin *This = (PullPin *)iface; 01197 01198 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); 01199 01200 *ppv = NULL; 01201 01202 if (IsEqualIID(riid, &IID_IUnknown)) 01203 *ppv = iface; 01204 else if (IsEqualIID(riid, &IID_IPin)) 01205 *ppv = iface; 01206 else if (IsEqualIID(riid, &IID_IMediaSeeking)) 01207 { 01208 return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); 01209 } 01210 01211 if (*ppv) 01212 { 01213 IUnknown_AddRef((IUnknown *)(*ppv)); 01214 return S_OK; 01215 } 01216 01217 FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); 01218 01219 return E_NOINTERFACE; 01220 } 01221 01222 ULONG WINAPI PullPin_Release(IPin *iface) 01223 { 01224 PullPin *This = (PullPin *)iface; 01225 ULONG refCount = InterlockedDecrement(&This->pin.refCount); 01226 01227 TRACE("(%p)->() Release from %d\n", This, refCount + 1); 01228 01229 if (!refCount) 01230 { 01231 WaitForSingleObject(This->hEventStateChanged, INFINITE); 01232 assert(!This->hThread); 01233 01234 if(This->pAlloc) 01235 IMemAllocator_Release(This->pAlloc); 01236 if(This->pReader) 01237 IAsyncReader_Release(This->pReader); 01238 CloseHandle(This->thread_sleepy); 01239 CloseHandle(This->hEventStateChanged); 01240 This->thread_lock.DebugInfo->Spare[0] = 0; 01241 DeleteCriticalSection(&This->thread_lock); 01242 CoTaskMemFree(This); 01243 return 0; 01244 } 01245 return refCount; 01246 } 01247 01248 static void PullPin_Flush(PullPin *This) 01249 { 01250 IMediaSample *pSample; 01251 TRACE("Flushing!\n"); 01252 01253 if (This->pReader) 01254 { 01255 /* Flush outstanding samples */ 01256 IAsyncReader_BeginFlush(This->pReader); 01257 01258 for (;;) 01259 { 01260 DWORD_PTR dwUser; 01261 01262 IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser); 01263 01264 if (!pSample) 01265 break; 01266 01267 assert(!IMediaSample_GetActualDataLength(pSample)); 01268 01269 IMediaSample_Release(pSample); 01270 } 01271 01272 IAsyncReader_EndFlush(This->pReader); 01273 } 01274 } 01275 01276 static void PullPin_Thread_Process(PullPin *This) 01277 { 01278 HRESULT hr; 01279 IMediaSample * pSample = NULL; 01280 ALLOCATOR_PROPERTIES allocProps; 01281 01282 hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps); 01283 01284 This->cbAlign = allocProps.cbAlign; 01285 01286 if (This->rtCurrent < This->rtStart) 01287 This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), This->cbAlign)); 01288 01289 TRACE("Start\n"); 01290 01291 if (This->rtCurrent >= This->rtStop) 01292 { 01293 IPin_EndOfStream((IPin *)This); 01294 return; 01295 } 01296 01297 /* There is no sample in our buffer */ 01298 hr = This->fnCustomRequest(This->pin.pUserData); 01299 01300 if (FAILED(hr)) 01301 ERR("Request error: %x\n", hr); 01302 01303 EnterCriticalSection(This->pin.pCritSec); 01304 SetEvent(This->hEventStateChanged); 01305 LeaveCriticalSection(This->pin.pCritSec); 01306 01307 if (SUCCEEDED(hr)) 01308 do 01309 { 01310 DWORD_PTR dwUser; 01311 01312 TRACE("Process sample\n"); 01313 01314 pSample = NULL; 01315 hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser); 01316 01317 /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */ 01318 if (SUCCEEDED(hr)) 01319 { 01320 hr = This->fnSampleProc(This->pin.pUserData, pSample, dwUser); 01321 } 01322 else 01323 { 01324 /* FIXME: This is not well handled yet! */ 01325 ERR("Processing error: %x\n", hr); 01326 if (hr == VFW_E_TIMEOUT) 01327 { 01328 assert(!pSample); 01329 hr = S_OK; 01330 continue; 01331 } 01332 } 01333 01334 if (pSample) 01335 { 01336 IMediaSample_Release(pSample); 01337 pSample = NULL; 01338 } 01339 } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback); 01340 01341 /* Sample was rejected, and we are asked to terminate */ 01342 if (pSample) 01343 { 01344 IMediaSample_Release(pSample); 01345 } 01346 01347 /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us 01348 * Flush remaining samples 01349 */ 01350 if (This->fnDone) 01351 This->fnDone(This->pin.pUserData); 01352 01353 TRACE("End: %08x, %d\n", hr, This->stop_playback); 01354 } 01355 01356 static void PullPin_Thread_Pause(PullPin *This) 01357 { 01358 PullPin_Flush(This); 01359 01360 EnterCriticalSection(This->pin.pCritSec); 01361 This->state = Req_Sleepy; 01362 SetEvent(This->hEventStateChanged); 01363 LeaveCriticalSection(This->pin.pCritSec); 01364 } 01365 01366 static void PullPin_Thread_Stop(PullPin *This) 01367 { 01368 TRACE("(%p)->()\n", This); 01369 01370 EnterCriticalSection(This->pin.pCritSec); 01371 { 01372 CloseHandle(This->hThread); 01373 This->hThread = NULL; 01374 SetEvent(This->hEventStateChanged); 01375 } 01376 LeaveCriticalSection(This->pin.pCritSec); 01377 01378 IBaseFilter_Release(This->pin.pinInfo.pFilter); 01379 01380 CoUninitialize(); 01381 ExitThread(0); 01382 } 01383 01384 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv) 01385 { 01386 PullPin *This = pv; 01387 CoInitializeEx(NULL, COINIT_MULTITHREADED); 01388 01389 PullPin_Flush(This); 01390 01391 for (;;) 01392 { 01393 WaitForSingleObject(This->thread_sleepy, INFINITE); 01394 01395 TRACE("State: %d\n", This->state); 01396 01397 switch (This->state) 01398 { 01399 case Req_Die: PullPin_Thread_Stop(This); break; 01400 case Req_Run: PullPin_Thread_Process(This); break; 01401 case Req_Pause: PullPin_Thread_Pause(This); break; 01402 case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break; 01403 default: ERR("Unknown state request: %d\n", This->state); break; 01404 } 01405 } 01406 return 0; 01407 } 01408 01409 static HRESULT PullPin_InitProcessing(PullPin * This) 01410 { 01411 HRESULT hr = S_OK; 01412 01413 TRACE("(%p)->()\n", This); 01414 01415 /* if we are connected */ 01416 if (This->pAlloc) 01417 { 01418 DWORD dwThreadId; 01419 01420 WaitForSingleObject(This->hEventStateChanged, INFINITE); 01421 EnterCriticalSection(This->pin.pCritSec); 01422 01423 assert(!This->hThread); 01424 assert(This->state == Req_Die); 01425 assert(This->stop_playback); 01426 assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); 01427 This->state = Req_Sleepy; 01428 01429 /* AddRef the filter to make sure it and it's pins will be around 01430 * as long as the thread */ 01431 IBaseFilter_AddRef(This->pin.pinInfo.pFilter); 01432 01433 01434 This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId); 01435 if (!This->hThread) 01436 { 01437 hr = HRESULT_FROM_WIN32(GetLastError()); 01438 IBaseFilter_Release(This->pin.pinInfo.pFilter); 01439 } 01440 01441 if (SUCCEEDED(hr)) 01442 { 01443 SetEvent(This->hEventStateChanged); 01444 /* If assert fails, that means a command was not processed before the thread previously terminated */ 01445 } 01446 LeaveCriticalSection(This->pin.pCritSec); 01447 } 01448 01449 TRACE(" -- %x\n", hr); 01450 01451 return hr; 01452 } 01453 01454 HRESULT PullPin_StartProcessing(PullPin * This) 01455 { 01456 /* if we are connected */ 01457 TRACE("(%p)->()\n", This); 01458 if(This->pAlloc) 01459 { 01460 assert(This->hThread); 01461 01462 PullPin_WaitForStateChange(This, INFINITE); 01463 01464 assert(This->state == Req_Sleepy); 01465 01466 /* Wake up! */ 01467 assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); 01468 This->state = Req_Run; 01469 This->stop_playback = 0; 01470 ResetEvent(This->hEventStateChanged); 01471 SetEvent(This->thread_sleepy); 01472 } 01473 01474 return S_OK; 01475 } 01476 01477 HRESULT PullPin_PauseProcessing(PullPin * This) 01478 { 01479 /* if we are connected */ 01480 TRACE("(%p)->()\n", This); 01481 if(This->pAlloc) 01482 { 01483 assert(This->hThread); 01484 01485 PullPin_WaitForStateChange(This, INFINITE); 01486 01487 EnterCriticalSection(This->pin.pCritSec); 01488 01489 assert(!This->stop_playback); 01490 assert(This->state == Req_Run|| This->state == Req_Sleepy); 01491 01492 assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); 01493 This->state = Req_Pause; 01494 This->stop_playback = 1; 01495 ResetEvent(This->hEventStateChanged); 01496 SetEvent(This->thread_sleepy); 01497 01498 LeaveCriticalSection(This->pin.pCritSec); 01499 } 01500 01501 return S_OK; 01502 } 01503 01504 static HRESULT PullPin_StopProcessing(PullPin * This) 01505 { 01506 TRACE("(%p)->()\n", This); 01507 01508 /* if we are alive */ 01509 assert(This->hThread); 01510 01511 PullPin_WaitForStateChange(This, INFINITE); 01512 01513 assert(This->state == Req_Pause || This->state == Req_Sleepy); 01514 01515 This->stop_playback = 1; 01516 This->state = Req_Die; 01517 assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); 01518 ResetEvent(This->hEventStateChanged); 01519 SetEvent(This->thread_sleepy); 01520 return S_OK; 01521 } 01522 01523 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds) 01524 { 01525 if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT) 01526 return S_FALSE; 01527 return S_OK; 01528 } 01529 01530 HRESULT WINAPI PullPin_EndOfStream(IPin * iface) 01531 { 01532 FIXME("(%p)->() stub\n", iface); 01533 01534 return SendFurther( iface, deliver_endofstream, NULL, NULL ); 01535 } 01536 01537 HRESULT WINAPI PullPin_BeginFlush(IPin * iface) 01538 { 01539 PullPin *This = (PullPin *)iface; 01540 TRACE("(%p)->()\n", This); 01541 01542 EnterCriticalSection(This->pin.pCritSec); 01543 { 01544 SendFurther( iface, deliver_beginflush, NULL, NULL ); 01545 } 01546 LeaveCriticalSection(This->pin.pCritSec); 01547 01548 EnterCriticalSection(&This->thread_lock); 01549 { 01550 if (This->pReader) 01551 IAsyncReader_BeginFlush(This->pReader); 01552 PullPin_WaitForStateChange(This, INFINITE); 01553 01554 if (This->hThread && This->state == Req_Run) 01555 { 01556 PullPin_PauseProcessing(This); 01557 PullPin_WaitForStateChange(This, INFINITE); 01558 } 01559 } 01560 LeaveCriticalSection(&This->thread_lock); 01561 01562 EnterCriticalSection(This->pin.pCritSec); 01563 { 01564 This->fnCleanProc(This->pin.pUserData); 01565 } 01566 LeaveCriticalSection(This->pin.pCritSec); 01567 01568 return S_OK; 01569 } 01570 01571 HRESULT WINAPI PullPin_EndFlush(IPin * iface) 01572 { 01573 PullPin *This = (PullPin *)iface; 01574 01575 TRACE("(%p)->()\n", iface); 01576 01577 /* Send further first: Else a race condition might terminate processing early */ 01578 EnterCriticalSection(This->pin.pCritSec); 01579 SendFurther( iface, deliver_endflush, NULL, NULL ); 01580 LeaveCriticalSection(This->pin.pCritSec); 01581 01582 EnterCriticalSection(&This->thread_lock); 01583 { 01584 FILTER_STATE state; 01585 01586 if (This->pReader) 01587 IAsyncReader_EndFlush(This->pReader); 01588 01589 IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state); 01590 01591 if (state != State_Stopped) 01592 PullPin_StartProcessing(This); 01593 01594 PullPin_WaitForStateChange(This, INFINITE); 01595 } 01596 LeaveCriticalSection(&This->thread_lock); 01597 01598 return S_OK; 01599 } 01600 01601 HRESULT WINAPI PullPin_Disconnect(IPin *iface) 01602 { 01603 HRESULT hr; 01604 PullPin *This = (PullPin *)iface; 01605 01606 TRACE("()\n"); 01607 01608 EnterCriticalSection(This->pin.pCritSec); 01609 { 01610 if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc))) 01611 ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr); 01612 01613 if (This->pin.pConnectedTo) 01614 { 01615 IPin_Release(This->pin.pConnectedTo); 01616 This->pin.pConnectedTo = NULL; 01617 PullPin_StopProcessing(This); 01618 01619 FreeMediaType(&This->pin.mtCurrent); 01620 ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); 01621 hr = S_OK; 01622 } 01623 else 01624 hr = S_FALSE; 01625 } 01626 LeaveCriticalSection(This->pin.pCritSec); 01627 01628 return hr; 01629 } 01630 01631 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) 01632 { 01633 newsegmentargs args; 01634 FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate); 01635 01636 args.tStart = tStart; 01637 args.tStop = tStop; 01638 args.rate = dRate; 01639 01640 return SendFurther( iface, deliver_newsegment, &args, NULL ); 01641 } 01642 01643 static const IPinVtbl PullPin_Vtbl = 01644 { 01645 PullPin_QueryInterface, 01646 IPinImpl_AddRef, 01647 PullPin_Release, 01648 InputPin_Connect, 01649 PullPin_ReceiveConnection, 01650 PullPin_Disconnect, 01651 IPinImpl_ConnectedTo, 01652 IPinImpl_ConnectionMediaType, 01653 IPinImpl_QueryPinInfo, 01654 IPinImpl_QueryDirection, 01655 IPinImpl_QueryId, 01656 IPinImpl_QueryAccept, 01657 IPinImpl_EnumMediaTypes, 01658 IPinImpl_QueryInternalConnections, 01659 PullPin_EndOfStream, 01660 PullPin_BeginFlush, 01661 PullPin_EndFlush, 01662 PullPin_NewSegment 01663 }; 01664 01665 /*** The Construct functions ***/ 01666 01667 /* Function called as a helper to IPin_Connect */ 01668 /* specific AM_MEDIA_TYPE - it cannot be NULL */ 01669 /* NOTE: not part of standard interface */ 01670 static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) 01671 { 01672 OutputPin *This = (OutputPin *)iface; 01673 HRESULT hr; 01674 IMemAllocator * pMemAlloc = NULL; 01675 ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */ 01676 01677 TRACE("(%p, %p)\n", pReceivePin, pmt); 01678 dump_AM_MEDIA_TYPE(pmt); 01679 01680 /* FIXME: call queryacceptproc */ 01681 01682 This->pin.pConnectedTo = pReceivePin; 01683 IPin_AddRef(pReceivePin); 01684 CopyMediaType(&This->pin.mtCurrent, pmt); 01685 01686 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt); 01687 01688 /* get the IMemInputPin interface we will use to deliver samples to the 01689 * connected pin */ 01690 if (SUCCEEDED(hr)) 01691 { 01692 This->pMemInputPin = NULL; 01693 hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin); 01694 01695 if (SUCCEEDED(hr) && !This->custom_allocator) 01696 { 01697 hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc); 01698 01699 if (hr == VFW_E_NO_ALLOCATOR) 01700 /* Input pin provides no allocator, use standard memory allocator */ 01701 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc); 01702 01703 if (SUCCEEDED(hr)) 01704 hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual); 01705 01706 if (SUCCEEDED(hr)) 01707 hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, This->readonly); 01708 01709 if (pMemAlloc) 01710 IMemAllocator_Release(pMemAlloc); 01711 } 01712 else if (SUCCEEDED(hr)) 01713 { 01714 if (This->alloc) 01715 { 01716 hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, This->alloc, This->readonly); 01717 } 01718 else 01719 hr = VFW_E_NO_ALLOCATOR; 01720 } 01721 01722 /* break connection if we couldn't get the allocator */ 01723 if (FAILED(hr)) 01724 { 01725 if (This->pMemInputPin) 01726 IMemInputPin_Release(This->pMemInputPin); 01727 This->pMemInputPin = NULL; 01728 01729 IPin_Disconnect(pReceivePin); 01730 } 01731 } 01732 01733 if (FAILED(hr)) 01734 { 01735 IPin_Release(This->pin.pConnectedTo); 01736 This->pin.pConnectedTo = NULL; 01737 FreeMediaType(&This->pin.mtCurrent); 01738 } 01739 01740 TRACE(" -- %x\n", hr); 01741 return hr; 01742 } 01743 01744 static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, 01745 QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, InputPin * pPinImpl) 01746 { 01747 TRACE("\n"); 01748 01749 /* Common attributes */ 01750 pPinImpl->pin.refCount = 1; 01751 pPinImpl->pin.pConnectedTo = NULL; 01752 pPinImpl->pin.fnQueryAccept = pQueryAccept; 01753 pPinImpl->pin.pUserData = pUserData; 01754 pPinImpl->pin.pCritSec = pCritSec; 01755 Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); 01756 ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); 01757 01758 /* Input pin attributes */ 01759 pPinImpl->fnSampleProc = pSampleProc; 01760 pPinImpl->fnCleanProc = pCleanUp; 01761 pPinImpl->pAllocator = pPinImpl->preferred_allocator = allocator; 01762 if (pPinImpl->preferred_allocator) 01763 IMemAllocator_AddRef(pPinImpl->preferred_allocator); 01764 pPinImpl->tStart = 0; 01765 pPinImpl->tStop = 0; 01766 pPinImpl->dRate = 1.0; 01767 pPinImpl->pin.lpVtbl = InputPin_Vtbl; 01768 pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl; 01769 pPinImpl->flushing = pPinImpl->end_of_stream = 0; 01770 01771 return S_OK; 01772 } 01773 01774 static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES * props, LPVOID pUserData, 01775 QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl) 01776 { 01777 TRACE("\n"); 01778 01779 /* Common attributes */ 01780 pPinImpl->pin.lpVtbl = OutputPin_Vtbl; 01781 pPinImpl->pin.refCount = 1; 01782 pPinImpl->pin.pConnectedTo = NULL; 01783 pPinImpl->pin.fnQueryAccept = pQueryAccept; 01784 pPinImpl->pin.pUserData = pUserData; 01785 pPinImpl->pin.pCritSec = pCritSec; 01786 Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); 01787 ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); 01788 01789 /* Output pin attributes */ 01790 pPinImpl->pMemInputPin = NULL; 01791 pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific; 01792 /* If custom_allocator is set, you will need to specify an allocator 01793 * in the alloc member of the struct before an output pin can connect 01794 */ 01795 pPinImpl->custom_allocator = 0; 01796 pPinImpl->alloc = NULL; 01797 pPinImpl->readonly = FALSE; 01798 if (props) 01799 { 01800 pPinImpl->allocProps = *props; 01801 if (pPinImpl->allocProps.cbAlign == 0) 01802 pPinImpl->allocProps.cbAlign = 1; 01803 } 01804 else 01805 ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps)); 01806 01807 return S_OK; 01808 } 01809 01810 HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, IPin ** ppPin) 01811 { 01812 InputPin * pPinImpl; 01813 01814 *ppPin = NULL; 01815 01816 if (pPinInfo->dir != PINDIR_INPUT) 01817 { 01818 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir); 01819 return E_INVALIDARG; 01820 } 01821 01822 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl)); 01823 01824 if (!pPinImpl) 01825 return E_OUTOFMEMORY; 01826 01827 if (SUCCEEDED(InputPin_Init(InputPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCritSec, allocator, pPinImpl))) 01828 { 01829 *ppPin = (IPin *)pPinImpl; 01830 return S_OK; 01831 } 01832 01833 CoTaskMemFree(pPinImpl); 01834 return E_FAIL; 01835 } 01836 01837 HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, LONG outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) 01838 { 01839 OutputPin * pPinImpl; 01840 01841 *ppPin = NULL; 01842 01843 if (pPinInfo->dir != PINDIR_OUTPUT) 01844 { 01845 ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir); 01846 return E_INVALIDARG; 01847 } 01848 01849 assert(outputpin_size >= sizeof(OutputPin)); 01850 01851 pPinImpl = CoTaskMemAlloc(outputpin_size); 01852 01853 if (!pPinImpl) 01854 return E_OUTOFMEMORY; 01855 01856 if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl))) 01857 { 01858 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); 01859 return S_OK; 01860 } 01861 01862 CoTaskMemFree(pPinImpl); 01863 return E_FAIL; 01864 } Generated on Sat May 26 2012 04:20:32 for ReactOS by
1.7.6.1
|