ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pin.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.