Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfilesource.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
1.7.6.1
|