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

filesource.c
Go to the documentation of this file.
00001 /*
00002  * File Source Filter
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 #define NONAMELESSUNION
00022 #define NONAMELESSSTRUCT
00023 
00024 #include "quartz_private.h"
00025 
00026 #include "wine/debug.h"
00027 #include "wine/unicode.h"
00028 #include "pin.h"
00029 #include "uuids.h"
00030 #include "vfwmsgs.h"
00031 #include "winbase.h"
00032 #include "winreg.h"
00033 #include "shlwapi.h"
00034 #include <assert.h>
00035 
00036 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
00037 
00038 static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
00039 
00040 typedef struct AsyncReader
00041 {
00042     const IBaseFilterVtbl * lpVtbl;
00043     const IFileSourceFilterVtbl * lpVtblFSF;
00044 
00045     LONG refCount;
00046     FILTER_INFO filterInfo;
00047     FILTER_STATE state;
00048     CRITICAL_SECTION csFilter;
00049     DWORD lastpinchange;
00050 
00051     IPin * pOutputPin;
00052     LPOLESTR pszFileName;
00053     AM_MEDIA_TYPE * pmt;
00054 } AsyncReader;
00055 
00056 static const IBaseFilterVtbl AsyncReader_Vtbl;
00057 static const IFileSourceFilterVtbl FileSource_Vtbl;
00058 static const IAsyncReaderVtbl FileAsyncReader_Vtbl;
00059 
00060 static HRESULT FileAsyncReader_Construct(HANDLE hFile, IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
00061 
00062 static inline AsyncReader *impl_from_IFileSourceFilter( IFileSourceFilter *iface )
00063 {
00064     return (AsyncReader *)((char*)iface - FIELD_OFFSET(AsyncReader, lpVtblFSF));
00065 }
00066 
00067 static WCHAR const mediatype_name[11] = {
00068     'M', 'e', 'd', 'i', 'a', ' ', 'T', 'y', 'p', 'e', 0 };
00069 static WCHAR const subtype_name[8] = {
00070     'S', 'u', 'b', 't', 'y', 'p', 'e', 0 };
00071 
00072 static HRESULT process_extensions(HKEY hkeyExtensions, LPCOLESTR pszFileName, GUID * majorType, GUID * minorType)
00073 {
00074     WCHAR *extension;
00075     LONG l;
00076     HKEY hsub;
00077     WCHAR keying[39];
00078     DWORD size;
00079 
00080     if (!pszFileName)
00081         return E_POINTER;
00082 
00083     /* Get the part of the name that matters */
00084     extension = PathFindExtensionW(pszFileName);
00085     if (*extension != '.')
00086         return E_FAIL;
00087 
00088     l = RegOpenKeyExW(hkeyExtensions, extension, 0, KEY_READ, &hsub);
00089     if (l)
00090         return E_FAIL;
00091 
00092     size = sizeof(keying);
00093     l = RegQueryValueExW(hsub, mediatype_name, NULL, NULL, (LPBYTE)keying, &size);
00094     if (!l)
00095         CLSIDFromString(keying, majorType);
00096 
00097     size = sizeof(keying);
00098     if (!l)
00099         l = RegQueryValueExW(hsub, subtype_name, NULL, NULL, (LPBYTE)keying, &size);
00100 
00101     if (!l)
00102         CLSIDFromString(keying, minorType);
00103 
00104     RegCloseKey(hsub);
00105 
00106     if (!l)
00107         return S_OK;
00108     return E_FAIL;
00109 }
00110 
00111 static unsigned char byte_from_hex_char(WCHAR wHex)
00112 {
00113     switch (tolowerW(wHex))
00114     {
00115     case '0':
00116     case '1':
00117     case '2':
00118     case '3':
00119     case '4':
00120     case '5':
00121     case '6':
00122     case '7':
00123     case '8':
00124     case '9':
00125         return (wHex - '0') & 0xf;
00126     case 'a':
00127     case 'b':
00128     case 'c':
00129     case 'd':
00130     case 'e':
00131     case 'f':
00132         return (wHex - 'a' + 10) & 0xf;
00133     default:
00134         return 0;
00135     }
00136 }
00137 
00138 static HRESULT process_pattern_string(LPCWSTR wszPatternString, IAsyncReader * pReader)
00139 {
00140     ULONG ulOffset;
00141     ULONG ulBytes;
00142     BYTE * pbMask;
00143     BYTE * pbValue;
00144     BYTE * pbFile;
00145     HRESULT hr = S_OK;
00146     ULONG strpos;
00147 
00148     TRACE("\t\tPattern string: %s\n", debugstr_w(wszPatternString));
00149     
00150     /* format: "offset, bytestocompare, mask, value" */
00151 
00152     ulOffset = strtolW(wszPatternString, NULL, 10);
00153 
00154     if (!(wszPatternString = strchrW(wszPatternString, ',')))
00155         return E_INVALIDARG;
00156 
00157     wszPatternString++; /* skip ',' */
00158 
00159     ulBytes = strtolW(wszPatternString, NULL, 10);
00160 
00161     pbMask = HeapAlloc(GetProcessHeap(), 0, ulBytes);
00162     pbValue = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulBytes);
00163     pbFile = HeapAlloc(GetProcessHeap(), 0, ulBytes);
00164 
00165     /* default mask is match everything */
00166     memset(pbMask, 0xFF, ulBytes);
00167 
00168     if (!(wszPatternString = strchrW(wszPatternString, ',')))
00169         hr = E_INVALIDARG;
00170 
00171     if (hr == S_OK)
00172     {
00173         wszPatternString++; /* skip ',' */
00174         while (!isxdigitW(*wszPatternString) && (*wszPatternString != ',')) wszPatternString++;
00175 
00176         for (strpos = 0; isxdigitW(*wszPatternString) && (strpos/2 < ulBytes); wszPatternString++, strpos++)
00177         {
00178             if ((strpos % 2) == 1) /* odd numbered position */
00179                 pbMask[strpos / 2] |= byte_from_hex_char(*wszPatternString);
00180             else
00181                 pbMask[strpos / 2] = byte_from_hex_char(*wszPatternString) << 4;
00182         }
00183 
00184         if (!(wszPatternString = strchrW(wszPatternString, ',')))
00185             hr = E_INVALIDARG;
00186     
00187         wszPatternString++; /* skip ',' */
00188     }
00189 
00190     if (hr == S_OK)
00191     {
00192         for ( ; !isxdigitW(*wszPatternString) && (*wszPatternString != ','); wszPatternString++)
00193             ;
00194 
00195         for (strpos = 0; isxdigitW(*wszPatternString) && (strpos/2 < ulBytes); wszPatternString++, strpos++)
00196         {
00197             if ((strpos % 2) == 1) /* odd numbered position */
00198                 pbValue[strpos / 2] |= byte_from_hex_char(*wszPatternString);
00199             else
00200                 pbValue[strpos / 2] = byte_from_hex_char(*wszPatternString) << 4;
00201         }
00202     }
00203 
00204     if (hr == S_OK)
00205         hr = IAsyncReader_SyncRead(pReader, ulOffset, ulBytes, pbFile);
00206 
00207     if (hr == S_OK)
00208     {
00209         ULONG i;
00210         for (i = 0; i < ulBytes; i++)
00211             if ((pbFile[i] & pbMask[i]) != pbValue[i])
00212             {
00213                 hr = S_FALSE;
00214                 break;
00215             }
00216     }
00217 
00218     HeapFree(GetProcessHeap(), 0, pbMask);
00219     HeapFree(GetProcessHeap(), 0, pbValue);
00220     HeapFree(GetProcessHeap(), 0, pbFile);
00221 
00222     /* if we encountered no errors with this string, and there is a following tuple, then we
00223      * have to match that as well to succeed */
00224     if ((hr == S_OK) && (wszPatternString = strchrW(wszPatternString, ',')))
00225         return process_pattern_string(wszPatternString + 1, pReader);
00226     else
00227         return hr;
00228 }
00229 
00230 static HRESULT GetClassMediaFile(IAsyncReader * pReader, LPCOLESTR pszFileName, GUID * majorType, GUID * minorType)
00231 {
00232     HKEY hkeyMediaType = NULL;
00233     LONG lRet;
00234     HRESULT hr = S_OK;
00235     BOOL bFound = FALSE;
00236     static const WCHAR wszMediaType[] = {'M','e','d','i','a',' ','T','y','p','e',0};
00237 
00238     TRACE("(%p, %s, %p, %p)\n", pReader, debugstr_w(pszFileName), majorType, minorType);
00239 
00240     *majorType = GUID_NULL;
00241     *minorType = GUID_NULL;
00242 
00243     lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMediaType, 0, KEY_READ, &hkeyMediaType);
00244     hr = HRESULT_FROM_WIN32(lRet);
00245 
00246     if (SUCCEEDED(hr))
00247     {
00248         DWORD indexMajor;
00249 
00250         for (indexMajor = 0; !bFound; indexMajor++)
00251         {
00252             HKEY hkeyMajor;
00253             WCHAR wszMajorKeyName[CHARS_IN_GUID];
00254             DWORD dwKeyNameLength = sizeof(wszMajorKeyName) / sizeof(wszMajorKeyName[0]);
00255             static const WCHAR wszExtensions[] = {'E','x','t','e','n','s','i','o','n','s',0};
00256 
00257             if (RegEnumKeyExW(hkeyMediaType, indexMajor, wszMajorKeyName, &dwKeyNameLength, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
00258                 break;
00259             if (RegOpenKeyExW(hkeyMediaType, wszMajorKeyName, 0, KEY_READ, &hkeyMajor) != ERROR_SUCCESS)
00260                 break;
00261             TRACE("%s\n", debugstr_w(wszMajorKeyName));
00262             if (!strcmpW(wszExtensions, wszMajorKeyName))
00263             {
00264                 if (process_extensions(hkeyMajor, pszFileName, majorType, minorType) == S_OK)
00265                     bFound = TRUE;
00266             }
00267             else
00268             {
00269                 DWORD indexMinor;
00270 
00271                 for (indexMinor = 0; !bFound; indexMinor++)
00272                 {
00273                     HKEY hkeyMinor;
00274                     WCHAR wszMinorKeyName[CHARS_IN_GUID];
00275                     DWORD dwMinorKeyNameLen = sizeof(wszMinorKeyName) / sizeof(wszMinorKeyName[0]);
00276                     DWORD maxValueLen;
00277                     DWORD indexValue;
00278 
00279                     if (RegEnumKeyExW(hkeyMajor, indexMinor, wszMinorKeyName, &dwMinorKeyNameLen, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
00280                         break;
00281 
00282                     if (RegOpenKeyExW(hkeyMajor, wszMinorKeyName, 0, KEY_READ, &hkeyMinor) != ERROR_SUCCESS)
00283                         break;
00284 
00285                     TRACE("\t%s\n", debugstr_w(wszMinorKeyName));
00286         
00287                     if (RegQueryInfoKeyW(hkeyMinor, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &maxValueLen, NULL, NULL) != ERROR_SUCCESS)
00288                         break;
00289 
00290                     for (indexValue = 0; !bFound; indexValue++)
00291                     {
00292                         DWORD dwType;
00293                         WCHAR wszValueName[14]; /* longest name we should encounter will be "Source Filter" */
00294                         LPWSTR wszPatternString = HeapAlloc(GetProcessHeap(), 0, maxValueLen);
00295                         DWORD dwValueNameLen = sizeof(wszValueName) / sizeof(wszValueName[0]); /* remember this is in chars */
00296                         DWORD dwDataLen = maxValueLen; /* remember this is in bytes */
00297                         static const WCHAR wszSourceFilter[] = {'S','o','u','r','c','e',' ','F','i','l','t','e','r',0};
00298                         LONG temp;
00299 
00300                         if ((temp = RegEnumValueW(hkeyMinor, indexValue, wszValueName, &dwValueNameLen, NULL, &dwType, (LPBYTE)wszPatternString, &dwDataLen)) != ERROR_SUCCESS)
00301                         {
00302                             HeapFree(GetProcessHeap(), 0, wszPatternString);
00303                             break;
00304                         }
00305 
00306                         /* if it is not the source filter value */
00307                         if (strcmpW(wszValueName, wszSourceFilter))
00308                         {
00309                             if (process_pattern_string(wszPatternString, pReader) == S_OK)
00310                             {
00311                                 if (SUCCEEDED(CLSIDFromString(wszMajorKeyName, majorType)) &&
00312                                     SUCCEEDED(CLSIDFromString(wszMinorKeyName, minorType)))
00313                                     bFound = TRUE;
00314                             }
00315                         }
00316                         HeapFree(GetProcessHeap(), 0, wszPatternString);
00317                     }
00318                     CloseHandle(hkeyMinor);
00319                 }
00320             }
00321             CloseHandle(hkeyMajor);
00322         }
00323     }
00324     CloseHandle(hkeyMediaType);
00325 
00326     if (SUCCEEDED(hr) && !bFound)
00327     {
00328         ERR("Media class not found\n");
00329         hr = E_FAIL;
00330     }
00331     else if (bFound)
00332         TRACE("Found file's class: major = %s, subtype = %s\n", qzdebugstr_guid(majorType), qzdebugstr_guid(minorType));
00333 
00334     return hr;
00335 }
00336 
00337 HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv)
00338 {
00339     AsyncReader *pAsyncRead;
00340     
00341     if( pUnkOuter )
00342         return CLASS_E_NOAGGREGATION;
00343     
00344     pAsyncRead = CoTaskMemAlloc(sizeof(AsyncReader));
00345 
00346     if (!pAsyncRead)
00347         return E_OUTOFMEMORY;
00348 
00349     pAsyncRead->lpVtbl = &AsyncReader_Vtbl;
00350     pAsyncRead->lpVtblFSF = &FileSource_Vtbl;
00351     pAsyncRead->refCount = 1;
00352     pAsyncRead->filterInfo.achName[0] = '\0';
00353     pAsyncRead->filterInfo.pGraph = NULL;
00354     pAsyncRead->pOutputPin = NULL;
00355     pAsyncRead->lastpinchange = GetTickCount();
00356     pAsyncRead->state = State_Stopped;
00357 
00358     InitializeCriticalSection(&pAsyncRead->csFilter);
00359     pAsyncRead->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AsyncReader.csFilter");
00360 
00361     pAsyncRead->pszFileName = NULL;
00362     pAsyncRead->pmt = NULL;
00363 
00364     *ppv = pAsyncRead;
00365 
00366     TRACE("-- created at %p\n", pAsyncRead);
00367 
00368     return S_OK;
00369 }
00370 
00373 static HRESULT WINAPI AsyncReader_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
00374 {
00375     AsyncReader *This = (AsyncReader *)iface;
00376 
00377     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
00378 
00379     *ppv = NULL;
00380 
00381     if (IsEqualIID(riid, &IID_IUnknown))
00382         *ppv = This;
00383     else if (IsEqualIID(riid, &IID_IPersist))
00384         *ppv = This;
00385     else if (IsEqualIID(riid, &IID_IMediaFilter))
00386         *ppv = This;
00387     else if (IsEqualIID(riid, &IID_IBaseFilter))
00388         *ppv = This;
00389     else if (IsEqualIID(riid, &IID_IFileSourceFilter))
00390         *ppv = &This->lpVtblFSF;
00391 
00392     if (*ppv)
00393     {
00394         IUnknown_AddRef((IUnknown *)(*ppv));
00395         return S_OK;
00396     }
00397 
00398     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IMediaSeeking) &&
00399         !IsEqualIID(riid, &IID_IVideoWindow) && !IsEqualIID(riid, &IID_IBasicAudio))
00400         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
00401 
00402     return E_NOINTERFACE;
00403 }
00404 
00405 static ULONG WINAPI AsyncReader_AddRef(IBaseFilter * iface)
00406 {
00407     AsyncReader *This = (AsyncReader *)iface;
00408     ULONG refCount = InterlockedIncrement(&This->refCount);
00409     
00410     TRACE("(%p)->() AddRef from %d\n", This, refCount - 1);
00411     
00412     return refCount;
00413 }
00414 
00415 static ULONG WINAPI AsyncReader_Release(IBaseFilter * iface)
00416 {
00417     AsyncReader *This = (AsyncReader *)iface;
00418     ULONG refCount = InterlockedDecrement(&This->refCount);
00419     
00420     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
00421     
00422     if (!refCount)
00423     {
00424         if (This->pOutputPin)
00425         {
00426             IPin *pConnectedTo;
00427             if(SUCCEEDED(IPin_ConnectedTo(This->pOutputPin, &pConnectedTo)))
00428             {
00429                 IPin_Disconnect(pConnectedTo);
00430                 IPin_Release(pConnectedTo);
00431             }
00432             IPin_Disconnect(This->pOutputPin);
00433             IPin_Release(This->pOutputPin);
00434         }
00435         This->csFilter.DebugInfo->Spare[0] = 0;
00436         DeleteCriticalSection(&This->csFilter);
00437         This->lpVtbl = NULL;
00438         CoTaskMemFree(This->pszFileName);
00439         if (This->pmt)
00440             FreeMediaType(This->pmt);
00441         CoTaskMemFree(This);
00442         return 0;
00443     }
00444     else
00445         return refCount;
00446 }
00447 
00450 static HRESULT WINAPI AsyncReader_GetClassID(IBaseFilter * iface, CLSID * pClsid)
00451 {
00452     TRACE("(%p)\n", pClsid);
00453 
00454     *pClsid = CLSID_AsyncReader;
00455 
00456     return S_OK;
00457 }
00458 
00461 static HRESULT WINAPI AsyncReader_Stop(IBaseFilter * iface)
00462 {
00463     AsyncReader *This = (AsyncReader *)iface;
00464 
00465     TRACE("()\n");
00466 
00467     This->state = State_Stopped;
00468     
00469     return S_OK;
00470 }
00471 
00472 static HRESULT WINAPI AsyncReader_Pause(IBaseFilter * iface)
00473 {
00474     AsyncReader *This = (AsyncReader *)iface;
00475 
00476     TRACE("()\n");
00477 
00478     This->state = State_Paused;
00479 
00480     return S_OK;
00481 }
00482 
00483 static HRESULT WINAPI AsyncReader_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
00484 {
00485     AsyncReader *This = (AsyncReader *)iface;
00486 
00487     TRACE("(%x%08x)\n", (ULONG)(tStart >> 32), (ULONG)tStart);
00488 
00489     This->state = State_Running;
00490 
00491     return S_OK;
00492 }
00493 
00494 static HRESULT WINAPI AsyncReader_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
00495 {
00496     AsyncReader *This = (AsyncReader *)iface;
00497 
00498     TRACE("(%u, %p)\n", dwMilliSecsTimeout, pState);
00499 
00500     *pState = This->state;
00501     
00502     return S_OK;
00503 }
00504 
00505 static HRESULT WINAPI AsyncReader_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
00506 {
00507 /*    AsyncReader *This = (AsyncReader *)iface;*/
00508 
00509     TRACE("(%p)\n", pClock);
00510 
00511     return S_OK;
00512 }
00513 
00514 static HRESULT WINAPI AsyncReader_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
00515 {
00516 /*    AsyncReader *This = (AsyncReader *)iface;*/
00517 
00518     TRACE("(%p)\n", ppClock);
00519 
00520     return S_OK;
00521 }
00522 
00525 static HRESULT AsyncReader_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
00526 {
00527     AsyncReader *This = (AsyncReader *)iface;
00528 
00529     /* Our pins are almost static, not changing so setting static tick count is ok */
00530     *lastsynctick = This->lastpinchange;
00531 
00532     if (pos >= 1 || !This->pOutputPin)
00533         return S_FALSE;
00534 
00535     *pin = This->pOutputPin;
00536     IPin_AddRef(*pin);
00537     return S_OK;
00538 }
00539 
00540 static HRESULT WINAPI AsyncReader_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
00541 {
00542     AsyncReader *This = (AsyncReader *)iface;
00543 
00544     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
00545 
00546     return IEnumPinsImpl_Construct(ppEnum, AsyncReader_GetPin, iface);
00547 }
00548 
00549 static HRESULT WINAPI AsyncReader_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
00550 {
00551     FIXME("(%s, %p)\n", debugstr_w(Id), ppPin);
00552 
00553     return E_NOTIMPL;
00554 }
00555 
00556 static HRESULT WINAPI AsyncReader_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
00557 {
00558     AsyncReader *This = (AsyncReader *)iface;
00559 
00560     TRACE("(%p)\n", pInfo);
00561 
00562     strcpyW(pInfo->achName, This->filterInfo.achName);
00563     pInfo->pGraph = This->filterInfo.pGraph;
00564 
00565     if (pInfo->pGraph)
00566         IFilterGraph_AddRef(pInfo->pGraph);
00567     
00568     return S_OK;
00569 }
00570 
00571 static HRESULT WINAPI AsyncReader_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
00572 {
00573     AsyncReader *This = (AsyncReader *)iface;
00574 
00575     TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
00576 
00577     if (pName)
00578         strcpyW(This->filterInfo.achName, pName);
00579     else
00580         *This->filterInfo.achName = 0;
00581     This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
00582 
00583     return S_OK;
00584 }
00585 
00586 static HRESULT WINAPI AsyncReader_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
00587 {
00588     FIXME("(%p)\n", pVendorInfo);
00589 
00590     return E_NOTIMPL;
00591 }
00592 
00593 static const IBaseFilterVtbl AsyncReader_Vtbl =
00594 {
00595     AsyncReader_QueryInterface,
00596     AsyncReader_AddRef,
00597     AsyncReader_Release,
00598     AsyncReader_GetClassID,
00599     AsyncReader_Stop,
00600     AsyncReader_Pause,
00601     AsyncReader_Run,
00602     AsyncReader_GetState,
00603     AsyncReader_SetSyncSource,
00604     AsyncReader_GetSyncSource,
00605     AsyncReader_EnumPins,
00606     AsyncReader_FindPin,
00607     AsyncReader_QueryFilterInfo,
00608     AsyncReader_JoinFilterGraph,
00609     AsyncReader_QueryVendorInfo
00610 };
00611 
00612 static HRESULT WINAPI FileSource_QueryInterface(IFileSourceFilter * iface, REFIID riid, LPVOID * ppv)
00613 {
00614     AsyncReader *This = impl_from_IFileSourceFilter(iface);
00615 
00616     return IBaseFilter_QueryInterface((IFileSourceFilter*)&This->lpVtbl, riid, ppv);
00617 }
00618 
00619 static ULONG WINAPI FileSource_AddRef(IFileSourceFilter * iface)
00620 {
00621     AsyncReader *This = impl_from_IFileSourceFilter(iface);
00622 
00623     return IBaseFilter_AddRef((IFileSourceFilter*)&This->lpVtbl);
00624 }
00625 
00626 static ULONG WINAPI FileSource_Release(IFileSourceFilter * iface)
00627 {
00628     AsyncReader *This = impl_from_IFileSourceFilter(iface);
00629 
00630     return IBaseFilter_Release((IFileSourceFilter*)&This->lpVtbl);
00631 }
00632 
00633 static HRESULT WINAPI FileSource_Load(IFileSourceFilter * iface, LPCOLESTR pszFileName, const AM_MEDIA_TYPE * pmt)
00634 {
00635     HRESULT hr;
00636     HANDLE hFile;
00637     IAsyncReader * pReader = NULL;
00638     AsyncReader *This = impl_from_IFileSourceFilter(iface);
00639 
00640     TRACE("(%s, %p)\n", debugstr_w(pszFileName), pmt);
00641 
00642     /* open file */
00643     /* FIXME: check the sharing values that native uses */
00644     hFile = CreateFileW(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
00645 
00646     if (hFile == INVALID_HANDLE_VALUE)
00647     {
00648         return HRESULT_FROM_WIN32(GetLastError());
00649     }
00650 
00651     /* create pin */
00652     hr = FileAsyncReader_Construct(hFile, (IBaseFilter *)&This->lpVtbl, &This->csFilter, &This->pOutputPin);
00653     This->lastpinchange = GetTickCount();
00654 
00655     if (SUCCEEDED(hr))
00656         hr = IPin_QueryInterface(This->pOutputPin, &IID_IAsyncReader, (LPVOID *)&pReader);
00657 
00658     /* store file name & media type */
00659     if (SUCCEEDED(hr))
00660     {
00661         CoTaskMemFree(This->pszFileName);
00662         if (This->pmt)
00663             FreeMediaType(This->pmt);
00664 
00665         This->pszFileName = CoTaskMemAlloc((strlenW(pszFileName) + 1) * sizeof(WCHAR));
00666         strcpyW(This->pszFileName, pszFileName);
00667 
00668         This->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
00669         if (!pmt)
00670         {
00671             This->pmt->bFixedSizeSamples = TRUE;
00672             This->pmt->bTemporalCompression = FALSE;
00673             This->pmt->cbFormat = 0;
00674             This->pmt->pbFormat = NULL;
00675             This->pmt->pUnk = NULL;
00676             This->pmt->lSampleSize = 0;
00677             This->pmt->formattype = FORMAT_None;
00678             hr = GetClassMediaFile(pReader, pszFileName, &This->pmt->majortype, &This->pmt->subtype);
00679             if (FAILED(hr))
00680             {
00681                 CoTaskMemFree(This->pmt);
00682                 This->pmt = NULL;
00683             }
00684         }
00685         else
00686             CopyMediaType(This->pmt, pmt);
00687     }
00688 
00689     if (pReader)
00690         IAsyncReader_Release(pReader);
00691 
00692     if (FAILED(hr))
00693     {
00694         if (This->pOutputPin)
00695         {
00696             IPin_Release(This->pOutputPin);
00697             This->pOutputPin = NULL;
00698         }
00699 
00700         CoTaskMemFree(This->pszFileName);
00701         if (This->pmt)
00702             FreeMediaType(This->pmt);
00703         This->pszFileName = NULL;
00704         This->pmt = NULL;
00705 
00706         CloseHandle(hFile);
00707     }
00708 
00709     /* FIXME: check return codes */
00710     return hr;
00711 }
00712 
00713 static HRESULT WINAPI FileSource_GetCurFile(IFileSourceFilter * iface, LPOLESTR * ppszFileName, AM_MEDIA_TYPE * pmt)
00714 {
00715     AsyncReader *This = impl_from_IFileSourceFilter(iface);
00716     
00717     TRACE("(%p, %p)\n", ppszFileName, pmt);
00718 
00719     if (!ppszFileName)
00720         return E_POINTER;
00721 
00722     /* copy file name & media type if available, otherwise clear the outputs */
00723     if (This->pszFileName)
00724     {
00725         *ppszFileName = CoTaskMemAlloc((strlenW(This->pszFileName) + 1) * sizeof(WCHAR));
00726         strcpyW(*ppszFileName, This->pszFileName);
00727     }
00728     else
00729         *ppszFileName = NULL;
00730 
00731     if (pmt)
00732     {
00733         if (This->pmt)
00734             CopyMediaType(pmt, This->pmt);
00735         else
00736             ZeroMemory(pmt, sizeof(*pmt));
00737     }
00738 
00739     return S_OK;
00740 }
00741 
00742 static const IFileSourceFilterVtbl FileSource_Vtbl = 
00743 {
00744     FileSource_QueryInterface,
00745     FileSource_AddRef,
00746     FileSource_Release,
00747     FileSource_Load,
00748     FileSource_GetCurFile
00749 };
00750 
00751 
00752 /* the dwUserData passed back to user */
00753 typedef struct DATAREQUEST
00754 {
00755     IMediaSample * pSample; /* sample passed to us by user */
00756     DWORD_PTR dwUserData; /* user data passed to us */
00757     OVERLAPPED ovl; /* our overlapped structure */
00758 } DATAREQUEST;
00759 
00760 typedef struct FileAsyncReader
00761 {
00762     OutputPin pin;
00763     const struct IAsyncReaderVtbl * lpVtblAR;
00764 
00765     HANDLE hFile;
00766     BOOL bFlushing;
00767     /* Why would you need more? Every sample has its own handle */
00768     LONG queued_number;
00769     LONG samples;
00770     LONG oldest_sample;
00771     CRITICAL_SECTION csList; /* critical section to prevent concurrency issues */
00772     DATAREQUEST *sample_list;
00773 
00774     /* Have a handle for every sample, and then one more as flushing handle */
00775     HANDLE *handle_list;
00776 } FileAsyncReader;
00777 
00778 static inline FileAsyncReader *impl_from_IAsyncReader( IAsyncReader *iface )
00779 {
00780     return (FileAsyncReader *)((char*)iface - FIELD_OFFSET(FileAsyncReader, lpVtblAR));
00781 }
00782 
00783 static HRESULT AcceptProcAFR(LPVOID iface, const AM_MEDIA_TYPE *pmt)
00784 {
00785     AsyncReader *This = iface;
00786 
00787     FIXME("(%p, %p)\n", iface, pmt);
00788 
00789     if (IsEqualGUID(&pmt->majortype, &This->pmt->majortype) &&
00790         IsEqualGUID(&pmt->subtype, &This->pmt->subtype) &&
00791         IsEqualGUID(&pmt->formattype, &FORMAT_None))
00792         return S_OK;
00793     
00794     return S_FALSE;
00795 }
00796 
00797 /* overridden pin functions */
00798 
00799 static HRESULT WINAPI FileAsyncReaderPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
00800 {
00801     FileAsyncReader *This = (FileAsyncReader *)iface;
00802     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
00803 
00804     *ppv = NULL;
00805 
00806     if (IsEqualIID(riid, &IID_IUnknown))
00807         *ppv = This;
00808     else if (IsEqualIID(riid, &IID_IPin))
00809         *ppv = This;
00810     else if (IsEqualIID(riid, &IID_IAsyncReader))
00811         *ppv = &This->lpVtblAR;
00812 
00813     if (*ppv)
00814     {
00815         IUnknown_AddRef((IUnknown *)(*ppv));
00816         return S_OK;
00817     }
00818 
00819     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IMediaSeeking))
00820         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
00821 
00822     return E_NOINTERFACE;
00823 }
00824 
00825 static ULONG WINAPI FileAsyncReaderPin_Release(IPin * iface)
00826 {
00827     FileAsyncReader *This = (FileAsyncReader *)iface;
00828     ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
00829     int x;
00830 
00831     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
00832 
00833     if (!refCount)
00834     {
00835         CoTaskMemFree(This->sample_list);
00836         if (This->handle_list)
00837         {
00838             for (x = 0; x <= This->samples; ++x)
00839                 CloseHandle(This->handle_list[x]);
00840             CoTaskMemFree(This->handle_list);
00841         }
00842         CloseHandle(This->hFile);
00843         This->csList.DebugInfo->Spare[0] = 0;
00844         DeleteCriticalSection(&This->csList);
00845         CoTaskMemFree(This);
00846         return 0;
00847     }
00848     return refCount;
00849 }
00850 
00851 static HRESULT WINAPI FileAsyncReaderPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
00852 {
00853     ENUMMEDIADETAILS emd;
00854     FileAsyncReader *This = (FileAsyncReader *)iface;
00855 
00856     TRACE("(%p)\n", ppEnum);
00857 
00858     emd.cMediaTypes = 1;
00859     emd.pMediaTypes = ((AsyncReader *)This->pin.pin.pinInfo.pFilter)->pmt;
00860 
00861     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
00862 }
00863 
00864 static const IPinVtbl FileAsyncReaderPin_Vtbl = 
00865 {
00866     FileAsyncReaderPin_QueryInterface,
00867     IPinImpl_AddRef,
00868     FileAsyncReaderPin_Release,
00869     OutputPin_Connect,
00870     OutputPin_ReceiveConnection,
00871     IPinImpl_Disconnect,
00872     IPinImpl_ConnectedTo,
00873     IPinImpl_ConnectionMediaType,
00874     IPinImpl_QueryPinInfo,
00875     IPinImpl_QueryDirection,
00876     IPinImpl_QueryId,
00877     IPinImpl_QueryAccept,
00878     FileAsyncReaderPin_EnumMediaTypes,
00879     IPinImpl_QueryInternalConnections,
00880     OutputPin_EndOfStream,
00881     OutputPin_BeginFlush,
00882     OutputPin_EndFlush,
00883     OutputPin_NewSegment
00884 };
00885 
00886 /* Function called as a helper to IPin_Connect */
00887 /* specific AM_MEDIA_TYPE - it cannot be NULL */
00888 /* this differs from standard OutputPin_ConnectSpecific only in that it
00889  * doesn't need the IMemInputPin interface on the receiving pin */
00890 static HRESULT FileAsyncReaderPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
00891 {
00892     OutputPin *This = (OutputPin *)iface;
00893     HRESULT hr;
00894 
00895     TRACE("(%p, %p)\n", pReceivePin, pmt);
00896     dump_AM_MEDIA_TYPE(pmt);
00897 
00898     /* FIXME: call queryacceptproc */
00899 
00900     This->pin.pConnectedTo = pReceivePin;
00901     IPin_AddRef(pReceivePin);
00902     CopyMediaType(&This->pin.mtCurrent, pmt);
00903 
00904     hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
00905 
00906     if (FAILED(hr))
00907     {
00908         IPin_Release(This->pin.pConnectedTo);
00909         This->pin.pConnectedTo = NULL;
00910         FreeMediaType(&This->pin.mtCurrent);
00911     }
00912 
00913     TRACE(" -- %x\n", hr);
00914     return hr;
00915 }
00916 
00917 static HRESULT FileAsyncReader_Construct(HANDLE hFile, IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
00918 {
00919     PIN_INFO piOutput;
00920     HRESULT hr;
00921 
00922     *ppPin = NULL;
00923     piOutput.dir = PINDIR_OUTPUT;
00924     piOutput.pFilter = pBaseFilter;
00925     strcpyW(piOutput.achName, wszOutputPinName);
00926     hr = OutputPin_Construct(&FileAsyncReaderPin_Vtbl, sizeof(FileAsyncReader), &piOutput, NULL, pBaseFilter, AcceptProcAFR, pCritSec, ppPin);
00927 
00928     if (SUCCEEDED(hr))
00929     {
00930         FileAsyncReader *pPinImpl =  (FileAsyncReader *)*ppPin;
00931         pPinImpl->lpVtblAR = &FileAsyncReader_Vtbl;
00932         pPinImpl->hFile = hFile;
00933         pPinImpl->bFlushing = FALSE;
00934         pPinImpl->sample_list = NULL;
00935         pPinImpl->handle_list = NULL;
00936         pPinImpl->queued_number = 0;
00937         pPinImpl->pin.pConnectSpecific = FileAsyncReaderPin_ConnectSpecific;
00938         InitializeCriticalSection(&pPinImpl->csList);
00939         pPinImpl->csList.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FileAsyncReader.csList");
00940     }
00941     return hr;
00942 }
00943 
00944 /* IAsyncReader */
00945 
00946 static HRESULT WINAPI FileAsyncReader_QueryInterface(IAsyncReader * iface, REFIID riid, LPVOID * ppv)
00947 {
00948     FileAsyncReader *This = impl_from_IAsyncReader(iface);
00949 
00950     return IPin_QueryInterface((IPin *)This, riid, ppv);
00951 }
00952 
00953 static ULONG WINAPI FileAsyncReader_AddRef(IAsyncReader * iface)
00954 {
00955     FileAsyncReader *This = impl_from_IAsyncReader(iface);
00956 
00957     return IPin_AddRef((IPin *)This);
00958 }
00959 
00960 static ULONG WINAPI FileAsyncReader_Release(IAsyncReader * iface)
00961 {
00962     FileAsyncReader *This = impl_from_IAsyncReader(iface);
00963 
00964     return IPin_Release((IPin *)This);
00965 }
00966 
00967 #define DEF_ALIGNMENT 1
00968 
00969 static HRESULT WINAPI FileAsyncReader_RequestAllocator(IAsyncReader * iface, IMemAllocator * pPreferred, ALLOCATOR_PROPERTIES * pProps, IMemAllocator ** ppActual)
00970 {
00971     FileAsyncReader *This = impl_from_IAsyncReader(iface);
00972 
00973     HRESULT hr = S_OK;
00974 
00975     TRACE("(%p, %p, %p)\n", pPreferred, pProps, ppActual);
00976 
00977     if (!pProps->cbAlign || (pProps->cbAlign % DEF_ALIGNMENT) != 0)
00978         pProps->cbAlign = DEF_ALIGNMENT;
00979 
00980     if (pPreferred)
00981     {
00982         hr = IMemAllocator_SetProperties(pPreferred, pProps, pProps);
00983         /* FIXME: check we are still aligned */
00984         if (SUCCEEDED(hr))
00985         {
00986             IMemAllocator_AddRef(pPreferred);
00987             *ppActual = pPreferred;
00988             TRACE("FileAsyncReader_RequestAllocator -- %x\n", hr);
00989             goto done;
00990         }
00991     }
00992 
00993     pPreferred = NULL;
00994 
00995     hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC, &IID_IMemAllocator, (LPVOID *)&pPreferred);
00996 
00997     if (SUCCEEDED(hr))
00998     {
00999         hr = IMemAllocator_SetProperties(pPreferred, pProps, pProps);
01000         /* FIXME: check we are still aligned */
01001         if (SUCCEEDED(hr))
01002         {
01003             *ppActual = pPreferred;
01004             TRACE("FileAsyncReader_RequestAllocator -- %x\n", hr);
01005         }
01006     }
01007 
01008 done:
01009     if (SUCCEEDED(hr))
01010     {
01011         CoTaskMemFree(This->sample_list);
01012         if (This->handle_list)
01013         {
01014             int x;
01015             for (x = 0; x <= This->samples; ++x)
01016                 CloseHandle(This->handle_list[x]);
01017             CoTaskMemFree(This->handle_list);
01018         }
01019 
01020         This->samples = pProps->cBuffers;
01021         This->oldest_sample = 0;
01022         TRACE("Samples: %u\n", This->samples);
01023         This->sample_list = CoTaskMemAlloc(sizeof(This->sample_list[0]) * pProps->cBuffers);
01024         This->handle_list = CoTaskMemAlloc(sizeof(HANDLE) * pProps->cBuffers * 2);
01025 
01026         if (This->sample_list && This->handle_list)
01027         {
01028             int x;
01029             ZeroMemory(This->sample_list, sizeof(This->sample_list[0]) * pProps->cBuffers);
01030             for (x = 0; x < This->samples; ++x)
01031             {
01032                 This->sample_list[x].ovl.hEvent = This->handle_list[x] = CreateEventW(NULL, 0, 0, NULL);
01033                 if (x + 1 < This->samples)
01034                     This->handle_list[This->samples + 1 + x] = This->handle_list[x];
01035             }
01036             This->handle_list[This->samples] = CreateEventW(NULL, 1, 0, NULL);
01037             This->pin.allocProps = *pProps;
01038         }
01039         else
01040         {
01041             hr = E_OUTOFMEMORY;
01042             CoTaskMemFree(This->sample_list);
01043             CoTaskMemFree(This->handle_list);
01044             This->samples = 0;
01045             This->sample_list = NULL;
01046             This->handle_list = NULL;
01047         }
01048     }
01049 
01050     if (FAILED(hr))
01051     {
01052         *ppActual = NULL;
01053         if (pPreferred)
01054             IMemAllocator_Release(pPreferred);
01055     }
01056 
01057     TRACE("-- %x\n", hr);
01058     return hr;
01059 }
01060 
01061 /* we could improve the Request/WaitForNext mechanism by allowing out of order samples.
01062  * however, this would be quite complicated to do and may be a bit error prone */
01063 static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample * pSample, DWORD_PTR dwUser)
01064 {
01065     HRESULT hr = S_OK;
01066     REFERENCE_TIME Start;
01067     REFERENCE_TIME Stop;
01068     FileAsyncReader *This = impl_from_IAsyncReader(iface);
01069     LPBYTE pBuffer = NULL;
01070 
01071     TRACE("(%p, %lx)\n", pSample, dwUser);
01072 
01073     if (!pSample)
01074         return E_POINTER;
01075 
01076     /* get start and stop positions in bytes */
01077     if (SUCCEEDED(hr))
01078         hr = IMediaSample_GetTime(pSample, &Start, &Stop);
01079 
01080     if (SUCCEEDED(hr))
01081         hr = IMediaSample_GetPointer(pSample, &pBuffer);
01082 
01083     EnterCriticalSection(&This->csList);
01084     if (This->bFlushing)
01085     {
01086         LeaveCriticalSection(&This->csList);
01087         return VFW_E_WRONG_STATE;
01088     }
01089 
01090     if (SUCCEEDED(hr))
01091     {
01092         DWORD dwLength = (DWORD) BYTES_FROM_MEDIATIME(Stop - Start);
01093         DATAREQUEST *pDataRq;
01094         int x;
01095 
01096         /* Try to insert above the waiting sample if possible */
01097         for (x = This->oldest_sample; x < This->samples; ++x)
01098         {
01099             if (!This->sample_list[x].pSample)
01100                 break;
01101         }
01102 
01103         if (x >= This->samples)
01104             for (x = 0; x < This->oldest_sample; ++x)
01105             {
01106                 if (!This->sample_list[x].pSample)
01107                     break;
01108             }
01109 
01110         /* There must be a sample we have found */
01111         assert(x < This->samples);
01112         ++This->queued_number;
01113 
01114         pDataRq = This->sample_list + x;
01115 
01116         pDataRq->ovl.Offset = (DWORD) BYTES_FROM_MEDIATIME(Start);
01117         pDataRq->ovl.OffsetHigh = (DWORD)(BYTES_FROM_MEDIATIME(Start) >> (sizeof(DWORD) * 8));
01118         pDataRq->dwUserData = dwUser;
01119 
01120         /* we violate traditional COM rules here by maintaining
01121          * a reference to the sample, but not calling AddRef, but
01122          * that's what MSDN says to do */
01123         pDataRq->pSample = pSample;
01124 
01125         /* this is definitely not how it is implemented on Win9x
01126          * as they do not support async reads on files, but it is
01127          * sooo much easier to use this than messing around with threads!
01128          */
01129         if (!ReadFile(This->hFile, pBuffer, dwLength, NULL, &pDataRq->ovl))
01130             hr = HRESULT_FROM_WIN32(GetLastError());
01131 
01132         /* ERROR_IO_PENDING is not actually an error since this is what we want! */
01133         if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING))
01134             hr = S_OK;
01135     }
01136 
01137     LeaveCriticalSection(&This->csList);
01138 
01139     TRACE("-- %x\n", hr);
01140     return hr;
01141 }
01142 
01143 static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader * iface, DWORD dwTimeout, IMediaSample ** ppSample, DWORD_PTR * pdwUser)
01144 {
01145     HRESULT hr = S_OK;
01146     FileAsyncReader *This = impl_from_IAsyncReader(iface);
01147     DWORD buffer = ~0;
01148 
01149     TRACE("(%u, %p, %p)\n", dwTimeout, ppSample, pdwUser);
01150 
01151     *ppSample = NULL;
01152     *pdwUser = 0;
01153 
01154     EnterCriticalSection(&This->csList);
01155     if (!This->bFlushing)
01156     {
01157         LONG oldest = This->oldest_sample;
01158 
01159         if (!This->queued_number)
01160         {
01161             /* It could be that nothing is queued right now, but that can be fixed */
01162             WARN("Called without samples in queue and not flushing!!\n");
01163         }
01164         LeaveCriticalSection(&This->csList);
01165 
01166         /* wait for an object to read, or time out */
01167         buffer = WaitForMultipleObjectsEx(This->samples+1, This->handle_list + oldest, FALSE, dwTimeout, TRUE);
01168 
01169         EnterCriticalSection(&This->csList);
01170         if (buffer <= This->samples)
01171         {
01172             /* Re-scale the buffer back to normal */
01173             buffer += oldest;
01174 
01175             /* Uh oh, we overshot the flusher handle, renormalize it back to 0..Samples-1 */
01176             if (buffer > This->samples)
01177                 buffer -= This->samples + 1;
01178             assert(buffer <= This->samples);
01179         }
01180 
01181         if (buffer >= This->samples)
01182         {
01183             if (buffer != This->samples)
01184             {
01185                 FIXME("Returned: %u (%08x)\n", buffer, GetLastError());
01186                 hr = VFW_E_TIMEOUT;
01187             }
01188             else
01189                 hr = VFW_E_WRONG_STATE;
01190             buffer = ~0;
01191         }
01192         else
01193             --This->queued_number;
01194     }
01195 
01196     if (This->bFlushing && buffer == ~0)
01197     {
01198         for (buffer = 0; buffer < This->samples; ++buffer)
01199         {
01200             if (This->sample_list[buffer].pSample)
01201             {
01202                 ResetEvent(This->handle_list[buffer]);
01203                 break;
01204             }
01205         }
01206         if (buffer == This->samples)
01207         {
01208             assert(!This->queued_number);
01209             hr = VFW_E_TIMEOUT;
01210         }
01211         else
01212         {
01213             --This->queued_number;
01214             hr = S_OK;
01215         }
01216     }
01217 
01218     if (SUCCEEDED(hr))
01219     {
01220         REFERENCE_TIME rtStart, rtStop;
01221         REFERENCE_TIME rtSampleStart, rtSampleStop;
01222         DATAREQUEST *pDataRq = This->sample_list + buffer;
01223         DWORD dwBytes = 0;
01224 
01225         /* get any errors */
01226         if (!This->bFlushing && !GetOverlappedResult(This->hFile, &pDataRq->ovl, &dwBytes, FALSE))
01227             hr = HRESULT_FROM_WIN32(GetLastError());
01228 
01229         /* Return the sample no matter what so it can be destroyed */
01230         *ppSample = pDataRq->pSample;
01231         *pdwUser = pDataRq->dwUserData;
01232 
01233         if (This->bFlushing)
01234             hr = VFW_E_WRONG_STATE;
01235 
01236         if (FAILED(hr))
01237             dwBytes = 0;
01238 
01239         /* Set the time on the sample */
01240         IMediaSample_SetActualDataLength(pDataRq->pSample, dwBytes);
01241 
01242         rtStart = (DWORD64)pDataRq->ovl.Offset + ((DWORD64)pDataRq->ovl.OffsetHigh << 32);
01243         rtStart = MEDIATIME_FROM_BYTES(rtStart);
01244         rtStop = rtStart + MEDIATIME_FROM_BYTES(dwBytes);
01245 
01246         IMediaSample_GetTime(pDataRq->pSample, &rtSampleStart, &rtSampleStop);
01247         assert(rtStart == rtSampleStart);
01248         assert(rtStop <= rtSampleStop);
01249 
01250         IMediaSample_SetTime(pDataRq->pSample, &rtStart, &rtStop);
01251         assert(rtStart == rtSampleStart);
01252         if (hr == S_OK)
01253             assert(rtStop == rtSampleStop);
01254         else
01255             assert(rtStop == rtStart);
01256 
01257         This->sample_list[buffer].pSample = NULL;
01258         assert(This->oldest_sample < This->samples);
01259 
01260         if (buffer == This->oldest_sample)
01261         {
01262             LONG x;
01263             for (x = This->oldest_sample + 1; x < This->samples; ++x)
01264                 if (This->sample_list[x].pSample)
01265                     break;
01266             if (x >= This->samples)
01267                 for (x = 0; x < This->oldest_sample; ++x)
01268                     if (This->sample_list[x].pSample)
01269                         break;
01270             if (This->oldest_sample == x)
01271                 /* No samples found, reset to 0 */
01272                 x = 0;
01273             This->oldest_sample = x;
01274         }
01275     }
01276     LeaveCriticalSection(&This->csList);
01277 
01278     TRACE("-- %x\n", hr);
01279     return hr;
01280 }
01281 
01282 static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader * iface, LONGLONG llPosition, LONG lLength, BYTE * pBuffer);
01283 
01284 static HRESULT WINAPI FileAsyncReader_SyncReadAligned(IAsyncReader * iface, IMediaSample * pSample)
01285 {
01286     BYTE * pBuffer;
01287     REFERENCE_TIME tStart;
01288     REFERENCE_TIME tStop;
01289     HRESULT hr;
01290 
01291     TRACE("(%p)\n", pSample);
01292 
01293     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
01294 
01295     if (SUCCEEDED(hr))
01296         hr = IMediaSample_GetPointer(pSample, &pBuffer);
01297 
01298     if (SUCCEEDED(hr))
01299         hr = FileAsyncReader_SyncRead(iface, 
01300             BYTES_FROM_MEDIATIME(tStart),
01301             (LONG) BYTES_FROM_MEDIATIME(tStop - tStart),
01302             pBuffer);
01303 
01304     TRACE("-- %x\n", hr);
01305     return hr;
01306 }
01307 
01308 static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader * iface, LONGLONG llPosition, LONG lLength, BYTE * pBuffer)
01309 {
01310     OVERLAPPED ovl;
01311     HRESULT hr = S_OK;
01312     FileAsyncReader *This = impl_from_IAsyncReader(iface);
01313 
01314     TRACE("(%x%08x, %d, %p)\n", (ULONG)(llPosition >> 32), (ULONG)llPosition, lLength, pBuffer);
01315 
01316     ZeroMemory(&ovl, sizeof(ovl));
01317 
01318     ovl.hEvent = CreateEventW(NULL, 0, 0, NULL);
01319     /* NOTE: llPosition is the actual byte position to start reading from */
01320     ovl.Offset = (DWORD) llPosition;
01321     ovl.OffsetHigh = (DWORD) (llPosition >> (sizeof(DWORD) * 8));
01322 
01323     if (!ReadFile(This->hFile, pBuffer, lLength, NULL, &ovl))
01324         hr = HRESULT_FROM_WIN32(GetLastError());
01325 
01326     if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING))
01327         hr = S_OK;
01328 
01329     if (SUCCEEDED(hr))
01330     {
01331         DWORD dwBytesRead;
01332 
01333         if (!GetOverlappedResult(This->hFile, &ovl, &dwBytesRead, TRUE))
01334             hr = HRESULT_FROM_WIN32(GetLastError());
01335     }
01336 
01337     CloseHandle(ovl.hEvent);
01338 
01339     TRACE("-- %x\n", hr);
01340     return hr;
01341 }
01342 
01343 static HRESULT WINAPI FileAsyncReader_Length(IAsyncReader * iface, LONGLONG * pTotal, LONGLONG * pAvailable)
01344 {
01345     DWORD dwSizeLow;
01346     DWORD dwSizeHigh;
01347     FileAsyncReader *This = impl_from_IAsyncReader(iface);
01348 
01349     TRACE("(%p, %p)\n", pTotal, pAvailable);
01350 
01351     if (((dwSizeLow = GetFileSize(This->hFile, &dwSizeHigh)) == -1) &&
01352         (GetLastError() != NO_ERROR))
01353         return HRESULT_FROM_WIN32(GetLastError());
01354 
01355     *pTotal = (LONGLONG)dwSizeLow | (LONGLONG)dwSizeHigh << (sizeof(DWORD) * 8);
01356 
01357     *pAvailable = *pTotal;
01358 
01359     return S_OK;
01360 }
01361 
01362 static HRESULT WINAPI FileAsyncReader_BeginFlush(IAsyncReader * iface)
01363 {
01364     FileAsyncReader *This = impl_from_IAsyncReader(iface);
01365 
01366     TRACE("()\n");
01367 
01368     EnterCriticalSection(&This->csList);
01369     This->bFlushing = TRUE;
01370     CancelIo(This->hFile);
01371     SetEvent(This->handle_list[This->samples]);
01372     LeaveCriticalSection(&This->csList);
01373 
01374     return S_OK;
01375 }
01376 
01377 static HRESULT WINAPI FileAsyncReader_EndFlush(IAsyncReader * iface)
01378 {
01379     FileAsyncReader *This = impl_from_IAsyncReader(iface);
01380     int x;
01381 
01382     TRACE("()\n");
01383 
01384     EnterCriticalSection(&This->csList);
01385     ResetEvent(This->handle_list[This->samples]);
01386     This->bFlushing = FALSE;
01387     for (x = 0; x < This->samples; ++x)
01388         assert(!This->sample_list[x].pSample);
01389 
01390     LeaveCriticalSection(&This->csList);
01391 
01392     return S_OK;
01393 }
01394 
01395 static const IAsyncReaderVtbl FileAsyncReader_Vtbl = 
01396 {
01397     FileAsyncReader_QueryInterface,
01398     FileAsyncReader_AddRef,
01399     FileAsyncReader_Release,
01400     FileAsyncReader_RequestAllocator,
01401     FileAsyncReader_Request,
01402     FileAsyncReader_WaitForNext,
01403     FileAsyncReader_SyncReadAligned,
01404     FileAsyncReader_SyncRead,
01405     FileAsyncReader_Length,
01406     FileAsyncReader_BeginFlush,
01407     FileAsyncReader_EndFlush,
01408 };

Generated on Fri May 25 2012 04:19:47 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.