widl: Use for_each_iface in get_size_procformatstring.
[wine.git] / dlls / quartz / filesource.c
blobe5904dc876eb46320bf03c1aedc36bde15711203
1 /*
2 * File Source Filter
4 * Copyright 2003 Robert Shearman
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
24 #include "quartz_private.h"
26 #include "wine/debug.h"
27 #include "wine/unicode.h"
28 #include "pin.h"
29 #include "uuids.h"
30 #include "vfwmsgs.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "shlwapi.h"
34 #include <assert.h>
36 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
38 static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
40 typedef struct AsyncReader
42 BaseFilter filter;
43 IFileSourceFilter IFileSourceFilter_iface;
45 IPin * pOutputPin;
46 LPOLESTR pszFileName;
47 AM_MEDIA_TYPE * pmt;
48 } AsyncReader;
50 static inline AsyncReader *impl_from_BaseFilter(BaseFilter *iface)
52 return CONTAINING_RECORD(iface, AsyncReader, filter);
55 static inline AsyncReader *impl_from_IBaseFilter(IBaseFilter *iface)
57 return CONTAINING_RECORD(iface, AsyncReader, filter.IBaseFilter_iface);
60 static inline AsyncReader *impl_from_IFileSourceFilter(IFileSourceFilter *iface)
62 return CONTAINING_RECORD(iface, AsyncReader, IFileSourceFilter_iface);
65 static const IBaseFilterVtbl AsyncReader_Vtbl;
66 static const IFileSourceFilterVtbl FileSource_Vtbl;
67 static const IAsyncReaderVtbl FileAsyncReader_Vtbl;
69 static HRESULT FileAsyncReader_Construct(HANDLE hFile, IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
71 static const WCHAR mediatype_name[] = {
72 'M', 'e', 'd', 'i', 'a', ' ', 'T', 'y', 'p', 'e', 0 };
73 static const WCHAR subtype_name[] = {
74 'S', 'u', 'b', 't', 'y', 'p', 'e', 0 };
75 static const WCHAR source_filter_name[] = {
76 'S','o','u','r','c','e',' ','F','i','l','t','e','r',0};
78 static HRESULT process_extensions(HKEY hkeyExtensions, LPCOLESTR pszFileName, GUID * majorType, GUID * minorType, GUID * sourceFilter)
80 WCHAR *extension;
81 LONG l;
82 HKEY hsub;
83 WCHAR keying[39];
84 DWORD size;
86 if (!pszFileName)
87 return E_POINTER;
89 /* Get the part of the name that matters */
90 extension = PathFindExtensionW(pszFileName);
91 if (*extension != '.')
92 return E_FAIL;
94 l = RegOpenKeyExW(hkeyExtensions, extension, 0, KEY_READ, &hsub);
95 if (l)
96 return E_FAIL;
98 if (majorType)
100 size = sizeof(keying);
101 l = RegQueryValueExW(hsub, mediatype_name, NULL, NULL, (LPBYTE)keying, &size);
102 if (!l)
103 CLSIDFromString(keying, majorType);
106 if (minorType)
108 size = sizeof(keying);
109 if (!l)
110 l = RegQueryValueExW(hsub, subtype_name, NULL, NULL, (LPBYTE)keying, &size);
111 if (!l)
112 CLSIDFromString(keying, minorType);
115 if (sourceFilter)
117 size = sizeof(keying);
118 if (!l)
119 l = RegQueryValueExW(hsub, source_filter_name, NULL, NULL, (LPBYTE)keying, &size);
120 if (!l)
121 CLSIDFromString(keying, sourceFilter);
124 RegCloseKey(hsub);
126 if (!l)
127 return S_OK;
128 return E_FAIL;
131 static unsigned char byte_from_hex_char(WCHAR wHex)
133 switch (tolowerW(wHex))
135 case '0':
136 case '1':
137 case '2':
138 case '3':
139 case '4':
140 case '5':
141 case '6':
142 case '7':
143 case '8':
144 case '9':
145 return (wHex - '0') & 0xf;
146 case 'a':
147 case 'b':
148 case 'c':
149 case 'd':
150 case 'e':
151 case 'f':
152 return (wHex - 'a' + 10) & 0xf;
153 default:
154 return 0;
158 static HRESULT process_pattern_string(LPCWSTR wszPatternString, IAsyncReader * pReader)
160 ULONG ulOffset;
161 ULONG ulBytes;
162 BYTE * pbMask;
163 BYTE * pbValue;
164 BYTE * pbFile;
165 HRESULT hr = S_OK;
166 ULONG strpos;
168 TRACE("\t\tPattern string: %s\n", debugstr_w(wszPatternString));
170 /* format: "offset, bytestocompare, mask, value" */
172 ulOffset = strtolW(wszPatternString, NULL, 10);
174 if (!(wszPatternString = strchrW(wszPatternString, ',')))
175 return E_INVALIDARG;
177 wszPatternString++; /* skip ',' */
179 ulBytes = strtolW(wszPatternString, NULL, 10);
181 pbMask = HeapAlloc(GetProcessHeap(), 0, ulBytes);
182 pbValue = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulBytes);
183 pbFile = HeapAlloc(GetProcessHeap(), 0, ulBytes);
185 /* default mask is match everything */
186 memset(pbMask, 0xFF, ulBytes);
188 if (!(wszPatternString = strchrW(wszPatternString, ',')))
189 hr = E_INVALIDARG;
191 if (hr == S_OK)
193 wszPatternString++; /* skip ',' */
194 while (!isxdigitW(*wszPatternString) && (*wszPatternString != ',')) wszPatternString++;
196 for (strpos = 0; isxdigitW(*wszPatternString) && (strpos/2 < ulBytes); wszPatternString++, strpos++)
198 if ((strpos % 2) == 1) /* odd numbered position */
199 pbMask[strpos / 2] |= byte_from_hex_char(*wszPatternString);
200 else
201 pbMask[strpos / 2] = byte_from_hex_char(*wszPatternString) << 4;
204 if (!(wszPatternString = strchrW(wszPatternString, ',')))
205 hr = E_INVALIDARG;
206 else
207 wszPatternString++; /* skip ',' */
210 if (hr == S_OK)
212 for ( ; !isxdigitW(*wszPatternString) && (*wszPatternString != ','); wszPatternString++)
215 for (strpos = 0; isxdigitW(*wszPatternString) && (strpos/2 < ulBytes); wszPatternString++, strpos++)
217 if ((strpos % 2) == 1) /* odd numbered position */
218 pbValue[strpos / 2] |= byte_from_hex_char(*wszPatternString);
219 else
220 pbValue[strpos / 2] = byte_from_hex_char(*wszPatternString) << 4;
224 if (hr == S_OK)
225 hr = IAsyncReader_SyncRead(pReader, ulOffset, ulBytes, pbFile);
227 if (hr == S_OK)
229 ULONG i;
230 for (i = 0; i < ulBytes; i++)
231 if ((pbFile[i] & pbMask[i]) != pbValue[i])
233 hr = S_FALSE;
234 break;
238 HeapFree(GetProcessHeap(), 0, pbMask);
239 HeapFree(GetProcessHeap(), 0, pbValue);
240 HeapFree(GetProcessHeap(), 0, pbFile);
242 /* if we encountered no errors with this string, and there is a following tuple, then we
243 * have to match that as well to succeed */
244 if ((hr == S_OK) && (wszPatternString = strchrW(wszPatternString, ',')))
245 return process_pattern_string(wszPatternString + 1, pReader);
246 else
247 return hr;
250 HRESULT GetClassMediaFile(IAsyncReader * pReader, LPCOLESTR pszFileName, GUID * majorType, GUID * minorType, GUID * sourceFilter)
252 HKEY hkeyMediaType = NULL;
253 LONG lRet;
254 HRESULT hr = S_OK;
255 BOOL bFound = FALSE;
256 static const WCHAR wszMediaType[] = {'M','e','d','i','a',' ','T','y','p','e',0};
258 TRACE("(%p, %s, %p, %p)\n", pReader, debugstr_w(pszFileName), majorType, minorType);
260 if(majorType)
261 *majorType = GUID_NULL;
262 if(minorType)
263 *minorType = GUID_NULL;
264 if(sourceFilter)
265 *sourceFilter = GUID_NULL;
267 lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMediaType, 0, KEY_READ, &hkeyMediaType);
268 hr = HRESULT_FROM_WIN32(lRet);
270 if (SUCCEEDED(hr))
272 DWORD indexMajor;
274 for (indexMajor = 0; !bFound; indexMajor++)
276 HKEY hkeyMajor;
277 WCHAR wszMajorKeyName[CHARS_IN_GUID];
278 DWORD dwKeyNameLength = ARRAY_SIZE(wszMajorKeyName);
279 static const WCHAR wszExtensions[] = {'E','x','t','e','n','s','i','o','n','s',0};
281 if (RegEnumKeyExW(hkeyMediaType, indexMajor, wszMajorKeyName, &dwKeyNameLength, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
282 break;
283 if (RegOpenKeyExW(hkeyMediaType, wszMajorKeyName, 0, KEY_READ, &hkeyMajor) != ERROR_SUCCESS)
284 break;
285 TRACE("%s\n", debugstr_w(wszMajorKeyName));
286 if (!strcmpW(wszExtensions, wszMajorKeyName))
288 if (process_extensions(hkeyMajor, pszFileName, majorType, minorType, sourceFilter) == S_OK)
289 bFound = TRUE;
291 /* We need a reader interface to check bytes */
292 else if (pReader)
294 DWORD indexMinor;
296 for (indexMinor = 0; !bFound; indexMinor++)
298 HKEY hkeyMinor;
299 WCHAR wszMinorKeyName[CHARS_IN_GUID];
300 DWORD dwMinorKeyNameLen = ARRAY_SIZE(wszMinorKeyName);
301 WCHAR wszSourceFilterKeyName[CHARS_IN_GUID];
302 DWORD dwSourceFilterKeyNameLen = sizeof(wszSourceFilterKeyName);
303 DWORD maxValueLen;
304 DWORD indexValue;
306 if (RegEnumKeyExW(hkeyMajor, indexMinor, wszMinorKeyName, &dwMinorKeyNameLen, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
307 break;
309 if (RegOpenKeyExW(hkeyMajor, wszMinorKeyName, 0, KEY_READ, &hkeyMinor) != ERROR_SUCCESS)
310 break;
312 TRACE("\t%s\n", debugstr_w(wszMinorKeyName));
314 if (RegQueryInfoKeyW(hkeyMinor, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &maxValueLen, NULL, NULL) != ERROR_SUCCESS)
315 break;
317 for (indexValue = 0; !bFound; indexValue++)
319 DWORD dwType;
320 WCHAR wszValueName[14]; /* longest name we should encounter will be "Source Filter" */
321 LPWSTR wszPatternString = HeapAlloc(GetProcessHeap(), 0, maxValueLen);
322 DWORD dwValueNameLen = ARRAY_SIZE(wszValueName);
323 DWORD dwDataLen = maxValueLen; /* remember this is in bytes */
325 if (RegEnumValueW(hkeyMinor, indexValue, wszValueName, &dwValueNameLen, NULL, &dwType, (LPBYTE)wszPatternString, &dwDataLen) != ERROR_SUCCESS)
327 HeapFree(GetProcessHeap(), 0, wszPatternString);
328 break;
331 if (strcmpW(wszValueName, source_filter_name)==0) {
332 HeapFree(GetProcessHeap(), 0, wszPatternString);
333 continue;
336 /* if it is not the source filter value */
337 if (process_pattern_string(wszPatternString, pReader) == S_OK)
339 HeapFree(GetProcessHeap(), 0, wszPatternString);
340 if (majorType && FAILED(CLSIDFromString(wszMajorKeyName, majorType)))
341 break;
342 if (minorType && FAILED(CLSIDFromString(wszMinorKeyName, minorType)))
343 break;
344 if (sourceFilter)
346 /* Look up the source filter key */
347 if (RegQueryValueExW(hkeyMinor, source_filter_name, NULL, NULL, (LPBYTE)wszSourceFilterKeyName, &dwSourceFilterKeyNameLen))
348 break;
349 if (FAILED(CLSIDFromString(wszSourceFilterKeyName, sourceFilter)))
350 break;
352 bFound = TRUE;
353 } else
354 HeapFree(GetProcessHeap(), 0, wszPatternString);
356 CloseHandle(hkeyMinor);
359 CloseHandle(hkeyMajor);
362 CloseHandle(hkeyMediaType);
364 if (SUCCEEDED(hr) && !bFound)
366 ERR("Media class not found\n");
367 hr = E_FAIL;
369 else if (bFound)
371 TRACE("Found file's class:\n");
372 if(majorType)
373 TRACE("\tmajor = %s\n", qzdebugstr_guid(majorType));
374 if(minorType)
375 TRACE("\tsubtype = %s\n", qzdebugstr_guid(minorType));
376 if(sourceFilter)
377 TRACE("\tsource filter = %s\n", qzdebugstr_guid(sourceFilter));
380 return hr;
383 static IPin* WINAPI AsyncReader_GetPin(BaseFilter *iface, int pos)
385 AsyncReader *This = impl_from_BaseFilter(iface);
387 TRACE("%p->(%d)\n", This, pos);
389 if (pos >= 1 || !This->pOutputPin)
390 return NULL;
392 IPin_AddRef(This->pOutputPin);
393 return This->pOutputPin;
396 static LONG WINAPI AsyncReader_GetPinCount(BaseFilter *iface)
398 AsyncReader *This = impl_from_BaseFilter(iface);
400 TRACE("%p->()\n", This);
402 if (!This->pOutputPin)
403 return 0;
404 else
405 return 1;
408 static const BaseFilterFuncTable BaseFuncTable = {
409 AsyncReader_GetPin,
410 AsyncReader_GetPinCount
413 HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv)
415 AsyncReader *pAsyncRead;
417 if( pUnkOuter )
418 return CLASS_E_NOAGGREGATION;
420 pAsyncRead = CoTaskMemAlloc(sizeof(AsyncReader));
422 if (!pAsyncRead)
423 return E_OUTOFMEMORY;
425 BaseFilter_Init(&pAsyncRead->filter, &AsyncReader_Vtbl, &CLSID_AsyncReader, (DWORD_PTR)(__FILE__ ": AsyncReader.csFilter"), &BaseFuncTable);
427 pAsyncRead->IFileSourceFilter_iface.lpVtbl = &FileSource_Vtbl;
428 pAsyncRead->pOutputPin = NULL;
430 pAsyncRead->pszFileName = NULL;
431 pAsyncRead->pmt = NULL;
433 *ppv = pAsyncRead;
435 TRACE("-- created at %p\n", pAsyncRead);
437 return S_OK;
440 /** IUnknown methods **/
442 static HRESULT WINAPI AsyncReader_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
444 AsyncReader *This = impl_from_IBaseFilter(iface);
446 TRACE("%p->(%s, %p)\n", This, qzdebugstr_guid(riid), ppv);
448 *ppv = NULL;
450 if (IsEqualIID(riid, &IID_IUnknown))
451 *ppv = &This->filter.IBaseFilter_iface;
452 else if (IsEqualIID(riid, &IID_IPersist))
453 *ppv = &This->filter.IBaseFilter_iface;
454 else if (IsEqualIID(riid, &IID_IMediaFilter))
455 *ppv = &This->filter.IBaseFilter_iface;
456 else if (IsEqualIID(riid, &IID_IBaseFilter))
457 *ppv = &This->filter.IBaseFilter_iface;
458 else if (IsEqualIID(riid, &IID_IFileSourceFilter))
459 *ppv = &This->IFileSourceFilter_iface;
461 if (*ppv)
463 IUnknown_AddRef((IUnknown *)(*ppv));
464 return S_OK;
467 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IMediaSeeking) &&
468 !IsEqualIID(riid, &IID_IVideoWindow) && !IsEqualIID(riid, &IID_IBasicAudio))
469 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
471 return E_NOINTERFACE;
474 static ULONG WINAPI AsyncReader_Release(IBaseFilter * iface)
476 AsyncReader *This = impl_from_IBaseFilter(iface);
477 ULONG refCount = InterlockedDecrement(&This->filter.refCount);
479 TRACE("%p->() Release from %d\n", This, refCount + 1);
481 if (!refCount)
483 if (This->pOutputPin)
485 IPin *pConnectedTo;
486 if(SUCCEEDED(IPin_ConnectedTo(This->pOutputPin, &pConnectedTo)))
488 IPin_Disconnect(pConnectedTo);
489 IPin_Release(pConnectedTo);
491 IPin_Disconnect(This->pOutputPin);
492 IPin_Release(This->pOutputPin);
494 CoTaskMemFree(This->pszFileName);
495 if (This->pmt)
496 FreeMediaType(This->pmt);
497 BaseFilter_Destroy(&This->filter);
498 CoTaskMemFree(This);
499 return 0;
501 else
502 return refCount;
505 /** IMediaFilter methods **/
507 static HRESULT WINAPI AsyncReader_Stop(IBaseFilter * iface)
509 AsyncReader *This = impl_from_IBaseFilter(iface);
511 TRACE("%p->()\n", This);
513 This->filter.state = State_Stopped;
515 return S_OK;
518 static HRESULT WINAPI AsyncReader_Pause(IBaseFilter * iface)
520 AsyncReader *This = impl_from_IBaseFilter(iface);
522 TRACE("%p->()\n", This);
524 This->filter.state = State_Paused;
526 return S_OK;
529 static HRESULT WINAPI AsyncReader_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
531 AsyncReader *This = impl_from_IBaseFilter(iface);
533 TRACE("%p->(%s)\n", This, wine_dbgstr_longlong(tStart));
535 This->filter.state = State_Running;
537 return S_OK;
540 static const IBaseFilterVtbl AsyncReader_Vtbl =
542 AsyncReader_QueryInterface,
543 BaseFilterImpl_AddRef,
544 AsyncReader_Release,
545 BaseFilterImpl_GetClassID,
546 AsyncReader_Stop,
547 AsyncReader_Pause,
548 AsyncReader_Run,
549 BaseFilterImpl_GetState,
550 BaseFilterImpl_SetSyncSource,
551 BaseFilterImpl_GetSyncSource,
552 BaseFilterImpl_EnumPins,
553 BaseFilterImpl_FindPin,
554 BaseFilterImpl_QueryFilterInfo,
555 BaseFilterImpl_JoinFilterGraph,
556 BaseFilterImpl_QueryVendorInfo
559 static HRESULT WINAPI FileSource_QueryInterface(IFileSourceFilter * iface, REFIID riid, LPVOID * ppv)
561 AsyncReader *This = impl_from_IFileSourceFilter(iface);
563 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
566 static ULONG WINAPI FileSource_AddRef(IFileSourceFilter * iface)
568 AsyncReader *This = impl_from_IFileSourceFilter(iface);
570 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
573 static ULONG WINAPI FileSource_Release(IFileSourceFilter * iface)
575 AsyncReader *This = impl_from_IFileSourceFilter(iface);
577 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
580 static HRESULT WINAPI FileSource_Load(IFileSourceFilter * iface, LPCOLESTR pszFileName, const AM_MEDIA_TYPE * pmt)
582 HRESULT hr;
583 HANDLE hFile;
584 IAsyncReader * pReader = NULL;
585 AsyncReader *This = impl_from_IFileSourceFilter(iface);
587 TRACE("%p->(%s, %p)\n", This, debugstr_w(pszFileName), pmt);
589 if (!pszFileName)
590 return E_POINTER;
592 /* open file */
593 /* FIXME: check the sharing values that native uses */
594 hFile = CreateFileW(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
596 if (hFile == INVALID_HANDLE_VALUE)
598 return HRESULT_FROM_WIN32(GetLastError());
601 /* create pin */
602 hr = FileAsyncReader_Construct(hFile, &This->filter.IBaseFilter_iface, &This->filter.csFilter, &This->pOutputPin);
603 BaseFilterImpl_IncrementPinVersion(&This->filter);
605 if (SUCCEEDED(hr))
606 hr = IPin_QueryInterface(This->pOutputPin, &IID_IAsyncReader, (LPVOID *)&pReader);
608 /* store file name & media type */
609 if (SUCCEEDED(hr))
611 CoTaskMemFree(This->pszFileName);
612 if (This->pmt)
613 FreeMediaType(This->pmt);
615 This->pszFileName = CoTaskMemAlloc((strlenW(pszFileName) + 1) * sizeof(WCHAR));
616 strcpyW(This->pszFileName, pszFileName);
618 This->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
619 if (!pmt)
621 This->pmt->bFixedSizeSamples = TRUE;
622 This->pmt->bTemporalCompression = FALSE;
623 This->pmt->cbFormat = 0;
624 This->pmt->pbFormat = NULL;
625 This->pmt->pUnk = NULL;
626 This->pmt->lSampleSize = 0;
627 This->pmt->formattype = FORMAT_None;
628 hr = GetClassMediaFile(pReader, pszFileName, &This->pmt->majortype, &This->pmt->subtype, NULL);
629 if (FAILED(hr))
631 This->pmt->majortype = MEDIATYPE_Stream;
632 This->pmt->subtype = MEDIASUBTYPE_NULL;
633 hr = S_OK;
636 else
637 CopyMediaType(This->pmt, pmt);
640 if (pReader)
641 IAsyncReader_Release(pReader);
643 if (FAILED(hr))
645 if (This->pOutputPin)
647 IPin_Release(This->pOutputPin);
648 This->pOutputPin = NULL;
651 CoTaskMemFree(This->pszFileName);
652 if (This->pmt)
653 FreeMediaType(This->pmt);
654 This->pszFileName = NULL;
655 This->pmt = NULL;
657 CloseHandle(hFile);
660 /* FIXME: check return codes */
661 return hr;
664 static HRESULT WINAPI FileSource_GetCurFile(IFileSourceFilter * iface, LPOLESTR * ppszFileName, AM_MEDIA_TYPE * pmt)
666 AsyncReader *This = impl_from_IFileSourceFilter(iface);
668 TRACE("%p->(%p, %p)\n", This, ppszFileName, pmt);
670 if (!ppszFileName)
671 return E_POINTER;
673 /* copy file name & media type if available, otherwise clear the outputs */
674 if (This->pszFileName)
676 *ppszFileName = CoTaskMemAlloc((strlenW(This->pszFileName) + 1) * sizeof(WCHAR));
677 strcpyW(*ppszFileName, This->pszFileName);
679 else
680 *ppszFileName = NULL;
682 if (pmt)
684 if (This->pmt)
685 CopyMediaType(pmt, This->pmt);
686 else
687 ZeroMemory(pmt, sizeof(*pmt));
690 return S_OK;
693 static const IFileSourceFilterVtbl FileSource_Vtbl =
695 FileSource_QueryInterface,
696 FileSource_AddRef,
697 FileSource_Release,
698 FileSource_Load,
699 FileSource_GetCurFile
703 /* the dwUserData passed back to user */
704 typedef struct DATAREQUEST
706 IMediaSample * pSample; /* sample passed to us by user */
707 DWORD_PTR dwUserData; /* user data passed to us */
708 OVERLAPPED ovl; /* our overlapped structure */
709 } DATAREQUEST;
711 typedef struct FileAsyncReader
713 BaseOutputPin pin;
714 IAsyncReader IAsyncReader_iface;
716 ALLOCATOR_PROPERTIES allocProps;
717 HANDLE hFile;
718 BOOL bFlushing;
719 /* Why would you need more? Every sample has its own handle */
720 LONG queued_number;
721 LONG samples;
722 LONG oldest_sample;
723 CRITICAL_SECTION csList; /* critical section to prevent concurrency issues */
724 DATAREQUEST *sample_list;
726 /* Have a handle for every sample, and then one more as flushing handle */
727 HANDLE *handle_list;
728 } FileAsyncReader;
730 static inline FileAsyncReader *impl_from_IPin(IPin *iface)
732 return CONTAINING_RECORD(iface, FileAsyncReader, pin.pin.IPin_iface);
735 static inline FileAsyncReader *impl_from_BasePin(BasePin *iface)
737 return CONTAINING_RECORD(iface, FileAsyncReader, pin.pin);
740 static inline FileAsyncReader *impl_from_BaseOutputPin(BaseOutputPin *iface)
742 return CONTAINING_RECORD(iface, FileAsyncReader, pin);
745 static inline BaseOutputPin *impl_BaseOutputPin_from_BasePin(BasePin *iface)
747 return CONTAINING_RECORD(iface, BaseOutputPin, pin);
750 static inline FileAsyncReader *impl_from_IAsyncReader(IAsyncReader *iface)
752 return CONTAINING_RECORD(iface, FileAsyncReader, IAsyncReader_iface);
755 static HRESULT WINAPI FileAsyncReaderPin_CheckMediaType(BasePin *pin, const AM_MEDIA_TYPE *pmt)
757 AM_MEDIA_TYPE *pmt_filter = impl_from_IBaseFilter(pin->pinInfo.pFilter)->pmt;
759 FIXME("(%p, %p)\n", pin, pmt);
761 if (IsEqualGUID(&pmt->majortype, &pmt_filter->majortype) &&
762 IsEqualGUID(&pmt->subtype, &pmt_filter->subtype) &&
763 IsEqualGUID(&pmt->formattype, &FORMAT_None))
764 return S_OK;
766 return S_FALSE;
769 static HRESULT WINAPI FileAsyncReaderPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
771 FileAsyncReader *This = impl_from_BasePin(iface);
772 if (iPosition < 0)
773 return E_INVALIDARG;
774 if (iPosition > 0)
775 return VFW_S_NO_MORE_ITEMS;
776 CopyMediaType(pmt, impl_from_IBaseFilter(This->pin.pin.pinInfo.pFilter)->pmt);
777 return S_OK;
780 /* overridden pin functions */
782 static HRESULT WINAPI FileAsyncReaderPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
784 FileAsyncReader *This = impl_from_IPin(iface);
785 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
787 *ppv = NULL;
789 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
790 *ppv = &This->pin.pin.IPin_iface;
791 else if (IsEqualIID(riid, &IID_IAsyncReader))
792 *ppv = &This->IAsyncReader_iface;
794 if (*ppv)
796 IUnknown_AddRef((IUnknown *)*ppv);
797 return S_OK;
800 if (!IsEqualIID(riid, &IID_IMediaSeeking))
801 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
803 return E_NOINTERFACE;
806 static ULONG WINAPI FileAsyncReaderPin_Release(IPin * iface)
808 FileAsyncReader *This = impl_from_IPin(iface);
809 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
810 int x;
812 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
814 if (!refCount)
816 CoTaskMemFree(This->sample_list);
817 if (This->handle_list)
819 for (x = 0; x <= This->samples; ++x)
820 CloseHandle(This->handle_list[x]);
821 CoTaskMemFree(This->handle_list);
823 CloseHandle(This->hFile);
824 This->csList.DebugInfo->Spare[0] = 0;
825 DeleteCriticalSection(&This->csList);
826 BaseOutputPin_Destroy(&This->pin);
827 return 0;
829 return refCount;
832 static const IPinVtbl FileAsyncReaderPin_Vtbl =
834 FileAsyncReaderPin_QueryInterface,
835 BasePinImpl_AddRef,
836 FileAsyncReaderPin_Release,
837 BaseOutputPinImpl_Connect,
838 BaseOutputPinImpl_ReceiveConnection,
839 BasePinImpl_Disconnect,
840 BasePinImpl_ConnectedTo,
841 BasePinImpl_ConnectionMediaType,
842 BasePinImpl_QueryPinInfo,
843 BasePinImpl_QueryDirection,
844 BasePinImpl_QueryId,
845 BasePinImpl_QueryAccept,
846 BasePinImpl_EnumMediaTypes,
847 BasePinImpl_QueryInternalConnections,
848 BaseOutputPinImpl_EndOfStream,
849 BaseOutputPinImpl_BeginFlush,
850 BaseOutputPinImpl_EndFlush,
851 BasePinImpl_NewSegment
854 /* Function called as a helper to IPin_Connect */
855 /* specific AM_MEDIA_TYPE - it cannot be NULL */
856 /* this differs from standard OutputPin_AttemptConnection only in that it
857 * doesn't need the IMemInputPin interface on the receiving pin */
858 static HRESULT WINAPI FileAsyncReaderPin_AttemptConnection(BasePin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
860 BaseOutputPin *This = impl_BaseOutputPin_from_BasePin(iface);
861 HRESULT hr;
863 TRACE("%p->(%p, %p)\n", This, pReceivePin, pmt);
864 dump_AM_MEDIA_TYPE(pmt);
866 /* FIXME: call queryacceptproc */
868 This->pin.pConnectedTo = pReceivePin;
869 IPin_AddRef(pReceivePin);
870 CopyMediaType(&This->pin.mtCurrent, pmt);
872 hr = IPin_ReceiveConnection(pReceivePin, &iface->IPin_iface, pmt);
874 if (FAILED(hr))
876 IPin_Release(This->pin.pConnectedTo);
877 This->pin.pConnectedTo = NULL;
878 FreeMediaType(&This->pin.mtCurrent);
881 TRACE(" -- %x\n", hr);
882 return hr;
885 static HRESULT WINAPI FileAsyncReaderPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
887 FileAsyncReader *This = impl_from_BaseOutputPin(iface);
888 ALLOCATOR_PROPERTIES actual;
890 if (ppropInputRequest->cbAlign && ppropInputRequest->cbAlign != This->allocProps.cbAlign)
891 FIXME("Requested Buffer cbAlign mismatch %i,%i\n",This->allocProps.cbAlign, ppropInputRequest->cbAlign);
892 if (ppropInputRequest->cbPrefix)
893 FIXME("Requested Buffer cbPrefix mismatch %i,%i\n",This->allocProps.cbPrefix, ppropInputRequest->cbPrefix);
894 if (ppropInputRequest->cbBuffer)
895 FIXME("Requested Buffer cbBuffer mismatch %i,%i\n",This->allocProps.cbBuffer, ppropInputRequest->cbBuffer);
896 if (ppropInputRequest->cBuffers)
897 FIXME("Requested Buffer cBuffers mismatch %i,%i\n",This->allocProps.cBuffers, ppropInputRequest->cBuffers);
899 return IMemAllocator_SetProperties(pAlloc, &This->allocProps, &actual);
902 static const BaseOutputPinFuncTable output_BaseOutputFuncTable = {
904 FileAsyncReaderPin_CheckMediaType,
905 FileAsyncReaderPin_AttemptConnection,
906 BasePinImpl_GetMediaTypeVersion,
907 FileAsyncReaderPin_GetMediaType
909 FileAsyncReaderPin_DecideBufferSize,
910 BaseOutputPinImpl_DecideAllocator,
911 BaseOutputPinImpl_BreakConnect
914 static HRESULT FileAsyncReader_Construct(HANDLE hFile, IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
916 PIN_INFO piOutput;
917 HRESULT hr;
919 *ppPin = NULL;
920 piOutput.dir = PINDIR_OUTPUT;
921 piOutput.pFilter = pBaseFilter;
922 strcpyW(piOutput.achName, wszOutputPinName);
923 hr = BaseOutputPin_Construct(&FileAsyncReaderPin_Vtbl, sizeof(FileAsyncReader), &piOutput, &output_BaseOutputFuncTable, pCritSec, ppPin);
925 if (SUCCEEDED(hr))
927 FileAsyncReader *pPinImpl = (FileAsyncReader *)*ppPin;
928 pPinImpl->IAsyncReader_iface.lpVtbl = &FileAsyncReader_Vtbl;
929 pPinImpl->hFile = hFile;
930 pPinImpl->bFlushing = FALSE;
931 pPinImpl->sample_list = NULL;
932 pPinImpl->handle_list = NULL;
933 pPinImpl->queued_number = 0;
934 InitializeCriticalSection(&pPinImpl->csList);
935 pPinImpl->csList.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FileAsyncReader.csList");
937 return hr;
940 /* IAsyncReader */
942 static HRESULT WINAPI FileAsyncReader_QueryInterface(IAsyncReader * iface, REFIID riid, LPVOID * ppv)
944 FileAsyncReader *This = impl_from_IAsyncReader(iface);
946 return IPin_QueryInterface(&This->pin.pin.IPin_iface, riid, ppv);
949 static ULONG WINAPI FileAsyncReader_AddRef(IAsyncReader * iface)
951 FileAsyncReader *This = impl_from_IAsyncReader(iface);
953 return IPin_AddRef(&This->pin.pin.IPin_iface);
956 static ULONG WINAPI FileAsyncReader_Release(IAsyncReader * iface)
958 FileAsyncReader *This = impl_from_IAsyncReader(iface);
960 return IPin_Release(&This->pin.pin.IPin_iface);
963 #define DEF_ALIGNMENT 1
965 static HRESULT WINAPI FileAsyncReader_RequestAllocator(IAsyncReader * iface, IMemAllocator * pPreferred, ALLOCATOR_PROPERTIES * pProps, IMemAllocator ** ppActual)
967 FileAsyncReader *This = impl_from_IAsyncReader(iface);
969 HRESULT hr = S_OK;
971 TRACE("%p->(%p, %p, %p)\n", This, pPreferred, pProps, ppActual);
973 if (!pProps->cbAlign || (pProps->cbAlign % DEF_ALIGNMENT) != 0)
974 pProps->cbAlign = DEF_ALIGNMENT;
976 if (pPreferred)
978 hr = IMemAllocator_SetProperties(pPreferred, pProps, pProps);
979 /* FIXME: check we are still aligned */
980 if (SUCCEEDED(hr))
982 IMemAllocator_AddRef(pPreferred);
983 *ppActual = pPreferred;
984 TRACE("FileAsyncReader_RequestAllocator -- %x\n", hr);
985 goto done;
989 pPreferred = NULL;
991 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC, &IID_IMemAllocator, (LPVOID *)&pPreferred);
993 if (SUCCEEDED(hr))
995 hr = IMemAllocator_SetProperties(pPreferred, pProps, pProps);
996 /* FIXME: check we are still aligned */
997 if (SUCCEEDED(hr))
999 *ppActual = pPreferred;
1000 TRACE("FileAsyncReader_RequestAllocator -- %x\n", hr);
1004 done:
1005 if (SUCCEEDED(hr))
1007 CoTaskMemFree(This->sample_list);
1008 if (This->handle_list)
1010 int x;
1011 for (x = 0; x <= This->samples; ++x)
1012 CloseHandle(This->handle_list[x]);
1013 CoTaskMemFree(This->handle_list);
1016 This->samples = pProps->cBuffers;
1017 This->oldest_sample = 0;
1018 TRACE("Samples: %u\n", This->samples);
1019 This->sample_list = CoTaskMemAlloc(sizeof(This->sample_list[0]) * pProps->cBuffers);
1020 This->handle_list = CoTaskMemAlloc(sizeof(HANDLE) * pProps->cBuffers * 2);
1022 if (This->sample_list && This->handle_list)
1024 int x;
1025 ZeroMemory(This->sample_list, sizeof(This->sample_list[0]) * pProps->cBuffers);
1026 for (x = 0; x < This->samples; ++x)
1028 This->sample_list[x].ovl.hEvent = This->handle_list[x] = CreateEventW(NULL, 0, 0, NULL);
1029 if (x + 1 < This->samples)
1030 This->handle_list[This->samples + 1 + x] = This->handle_list[x];
1032 This->handle_list[This->samples] = CreateEventW(NULL, 1, 0, NULL);
1033 This->allocProps = *pProps;
1035 else
1037 hr = E_OUTOFMEMORY;
1038 CoTaskMemFree(This->sample_list);
1039 CoTaskMemFree(This->handle_list);
1040 This->samples = 0;
1041 This->sample_list = NULL;
1042 This->handle_list = NULL;
1046 if (FAILED(hr))
1048 *ppActual = NULL;
1049 if (pPreferred)
1050 IMemAllocator_Release(pPreferred);
1053 TRACE("-- %x\n", hr);
1054 return hr;
1057 /* we could improve the Request/WaitForNext mechanism by allowing out of order samples.
1058 * however, this would be quite complicated to do and may be a bit error prone */
1059 static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample * pSample, DWORD_PTR dwUser)
1061 HRESULT hr = S_OK;
1062 REFERENCE_TIME Start;
1063 REFERENCE_TIME Stop;
1064 FileAsyncReader *This = impl_from_IAsyncReader(iface);
1065 LPBYTE pBuffer = NULL;
1067 TRACE("%p->(%p, %lx)\n", This, pSample, dwUser);
1069 if (!pSample)
1070 return E_POINTER;
1072 /* get start and stop positions in bytes */
1073 if (SUCCEEDED(hr))
1074 hr = IMediaSample_GetTime(pSample, &Start, &Stop);
1076 if (SUCCEEDED(hr))
1077 hr = IMediaSample_GetPointer(pSample, &pBuffer);
1079 EnterCriticalSection(&This->csList);
1080 if (This->bFlushing)
1082 LeaveCriticalSection(&This->csList);
1083 return VFW_E_WRONG_STATE;
1086 if (SUCCEEDED(hr))
1088 DWORD dwLength = (DWORD) BYTES_FROM_MEDIATIME(Stop - Start);
1089 DATAREQUEST *pDataRq;
1090 int x;
1092 /* Try to insert above the waiting sample if possible */
1093 for (x = This->oldest_sample; x < This->samples; ++x)
1095 if (!This->sample_list[x].pSample)
1096 break;
1099 if (x >= This->samples)
1100 for (x = 0; x < This->oldest_sample; ++x)
1102 if (!This->sample_list[x].pSample)
1103 break;
1106 /* There must be a sample we have found */
1107 assert(x < This->samples);
1108 ++This->queued_number;
1110 pDataRq = This->sample_list + x;
1112 pDataRq->ovl.u.s.Offset = (DWORD) BYTES_FROM_MEDIATIME(Start);
1113 pDataRq->ovl.u.s.OffsetHigh = (DWORD)(BYTES_FROM_MEDIATIME(Start) >> (sizeof(DWORD) * 8));
1114 pDataRq->dwUserData = dwUser;
1116 /* we violate traditional COM rules here by maintaining
1117 * a reference to the sample, but not calling AddRef, but
1118 * that's what MSDN says to do */
1119 pDataRq->pSample = pSample;
1121 /* this is definitely not how it is implemented on Win9x
1122 * as they do not support async reads on files, but it is
1123 * sooo much easier to use this than messing around with threads!
1125 if (!ReadFile(This->hFile, pBuffer, dwLength, NULL, &pDataRq->ovl))
1126 hr = HRESULT_FROM_WIN32(GetLastError());
1128 /* ERROR_IO_PENDING is not actually an error since this is what we want! */
1129 if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING))
1130 hr = S_OK;
1133 LeaveCriticalSection(&This->csList);
1135 TRACE("-- %x\n", hr);
1136 return hr;
1139 static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader * iface, DWORD dwTimeout, IMediaSample ** ppSample, DWORD_PTR * pdwUser)
1141 HRESULT hr = S_OK;
1142 FileAsyncReader *This = impl_from_IAsyncReader(iface);
1143 DWORD buffer = ~0;
1145 TRACE("%p->(%u, %p, %p)\n", This, dwTimeout, ppSample, pdwUser);
1147 *ppSample = NULL;
1148 *pdwUser = 0;
1150 EnterCriticalSection(&This->csList);
1151 if (!This->bFlushing)
1153 LONG oldest = This->oldest_sample;
1155 if (!This->queued_number)
1157 /* It could be that nothing is queued right now, but that can be fixed */
1158 WARN("Called without samples in queue and not flushing!!\n");
1160 LeaveCriticalSection(&This->csList);
1162 /* wait for an object to read, or time out */
1163 buffer = WaitForMultipleObjectsEx(This->samples+1, This->handle_list + oldest, FALSE, dwTimeout, TRUE);
1165 EnterCriticalSection(&This->csList);
1166 if (buffer <= This->samples)
1168 /* Re-scale the buffer back to normal */
1169 buffer += oldest;
1171 /* Uh oh, we overshot the flusher handle, renormalize it back to 0..Samples-1 */
1172 if (buffer > This->samples)
1173 buffer -= This->samples + 1;
1174 assert(buffer <= This->samples);
1177 if (buffer >= This->samples)
1179 if (buffer != This->samples)
1181 FIXME("Returned: %u (%08x)\n", buffer, GetLastError());
1182 hr = VFW_E_TIMEOUT;
1184 else
1185 hr = VFW_E_WRONG_STATE;
1186 buffer = ~0;
1188 else
1189 --This->queued_number;
1192 if (This->bFlushing && buffer == ~0)
1194 for (buffer = 0; buffer < This->samples; ++buffer)
1196 if (This->sample_list[buffer].pSample)
1198 ResetEvent(This->handle_list[buffer]);
1199 break;
1202 if (buffer == This->samples)
1204 assert(!This->queued_number);
1205 hr = VFW_E_TIMEOUT;
1207 else
1209 --This->queued_number;
1210 hr = S_OK;
1214 if (SUCCEEDED(hr))
1216 REFERENCE_TIME rtStart, rtStop;
1217 REFERENCE_TIME rtSampleStart, rtSampleStop;
1218 DATAREQUEST *pDataRq = This->sample_list + buffer;
1219 DWORD dwBytes = 0;
1221 /* get any errors */
1222 if (!This->bFlushing && !GetOverlappedResult(This->hFile, &pDataRq->ovl, &dwBytes, FALSE))
1223 hr = HRESULT_FROM_WIN32(GetLastError());
1225 /* Return the sample no matter what so it can be destroyed */
1226 *ppSample = pDataRq->pSample;
1227 *pdwUser = pDataRq->dwUserData;
1229 if (This->bFlushing)
1230 hr = VFW_E_WRONG_STATE;
1232 if (FAILED(hr))
1233 dwBytes = 0;
1235 /* Set the time on the sample */
1236 IMediaSample_SetActualDataLength(pDataRq->pSample, dwBytes);
1238 rtStart = (DWORD64)pDataRq->ovl.u.s.Offset + ((DWORD64)pDataRq->ovl.u.s.OffsetHigh << 32);
1239 rtStart = MEDIATIME_FROM_BYTES(rtStart);
1240 rtStop = rtStart + MEDIATIME_FROM_BYTES(dwBytes);
1242 IMediaSample_GetTime(pDataRq->pSample, &rtSampleStart, &rtSampleStop);
1243 assert(rtStart == rtSampleStart);
1244 assert(rtStop <= rtSampleStop);
1246 IMediaSample_SetTime(pDataRq->pSample, &rtStart, &rtStop);
1247 assert(rtStart == rtSampleStart);
1248 if (hr == S_OK)
1249 assert(rtStop == rtSampleStop);
1250 else
1251 assert(rtStop == rtStart);
1253 This->sample_list[buffer].pSample = NULL;
1254 assert(This->oldest_sample < This->samples);
1256 if (buffer == This->oldest_sample)
1258 LONG x;
1259 for (x = This->oldest_sample + 1; x < This->samples; ++x)
1260 if (This->sample_list[x].pSample)
1261 break;
1262 if (x >= This->samples)
1263 for (x = 0; x < This->oldest_sample; ++x)
1264 if (This->sample_list[x].pSample)
1265 break;
1266 if (This->oldest_sample == x)
1267 /* No samples found, reset to 0 */
1268 x = 0;
1269 This->oldest_sample = x;
1272 LeaveCriticalSection(&This->csList);
1274 TRACE("-- %x\n", hr);
1275 return hr;
1278 static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader * iface, LONGLONG llPosition, LONG lLength, BYTE * pBuffer);
1280 static HRESULT WINAPI FileAsyncReader_SyncReadAligned(IAsyncReader * iface, IMediaSample * pSample)
1282 BYTE * pBuffer;
1283 REFERENCE_TIME tStart;
1284 REFERENCE_TIME tStop;
1285 HRESULT hr;
1287 TRACE("(%p)\n", pSample);
1289 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
1291 if (SUCCEEDED(hr))
1292 hr = IMediaSample_GetPointer(pSample, &pBuffer);
1294 if (SUCCEEDED(hr))
1295 hr = FileAsyncReader_SyncRead(iface,
1296 BYTES_FROM_MEDIATIME(tStart),
1297 (LONG) BYTES_FROM_MEDIATIME(tStop - tStart),
1298 pBuffer);
1300 TRACE("-- %x\n", hr);
1301 return hr;
1304 static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader * iface, LONGLONG llPosition, LONG lLength, BYTE * pBuffer)
1306 OVERLAPPED ovl;
1307 HRESULT hr = S_OK;
1308 FileAsyncReader *This = impl_from_IAsyncReader(iface);
1310 TRACE("%p->(%s, %d, %p)\n", This, wine_dbgstr_longlong(llPosition), lLength, pBuffer);
1312 ZeroMemory(&ovl, sizeof(ovl));
1314 ovl.hEvent = CreateEventW(NULL, 0, 0, NULL);
1315 /* NOTE: llPosition is the actual byte position to start reading from */
1316 ovl.u.s.Offset = (DWORD) llPosition;
1317 ovl.u.s.OffsetHigh = (DWORD) (llPosition >> (sizeof(DWORD) * 8));
1319 if (!ReadFile(This->hFile, pBuffer, lLength, NULL, &ovl))
1320 hr = HRESULT_FROM_WIN32(GetLastError());
1322 if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING))
1323 hr = S_OK;
1325 if (SUCCEEDED(hr))
1327 DWORD dwBytesRead;
1329 if (!GetOverlappedResult(This->hFile, &ovl, &dwBytesRead, TRUE))
1330 hr = HRESULT_FROM_WIN32(GetLastError());
1333 CloseHandle(ovl.hEvent);
1335 TRACE("-- %x\n", hr);
1336 return hr;
1339 static HRESULT WINAPI FileAsyncReader_Length(IAsyncReader * iface, LONGLONG * pTotal, LONGLONG * pAvailable)
1341 DWORD dwSizeLow;
1342 DWORD dwSizeHigh;
1343 FileAsyncReader *This = impl_from_IAsyncReader(iface);
1345 TRACE("%p->(%p, %p)\n", This, pTotal, pAvailable);
1347 if (((dwSizeLow = GetFileSize(This->hFile, &dwSizeHigh)) == -1) &&
1348 (GetLastError() != NO_ERROR))
1349 return HRESULT_FROM_WIN32(GetLastError());
1351 *pTotal = (LONGLONG)dwSizeLow | (LONGLONG)dwSizeHigh << (sizeof(DWORD) * 8);
1353 *pAvailable = *pTotal;
1355 return S_OK;
1358 static HRESULT WINAPI FileAsyncReader_BeginFlush(IAsyncReader * iface)
1360 FileAsyncReader *This = impl_from_IAsyncReader(iface);
1362 TRACE("%p->()\n", This);
1364 EnterCriticalSection(&This->csList);
1365 This->bFlushing = TRUE;
1366 CancelIo(This->hFile);
1367 SetEvent(This->handle_list[This->samples]);
1368 LeaveCriticalSection(&This->csList);
1370 return S_OK;
1373 static HRESULT WINAPI FileAsyncReader_EndFlush(IAsyncReader * iface)
1375 FileAsyncReader *This = impl_from_IAsyncReader(iface);
1376 int x;
1378 TRACE("%p->()\n", This);
1380 EnterCriticalSection(&This->csList);
1381 ResetEvent(This->handle_list[This->samples]);
1382 This->bFlushing = FALSE;
1383 for (x = 0; x < This->samples; ++x)
1384 assert(!This->sample_list[x].pSample);
1386 LeaveCriticalSection(&This->csList);
1388 return S_OK;
1391 static const IAsyncReaderVtbl FileAsyncReader_Vtbl =
1393 FileAsyncReader_QueryInterface,
1394 FileAsyncReader_AddRef,
1395 FileAsyncReader_Release,
1396 FileAsyncReader_RequestAllocator,
1397 FileAsyncReader_Request,
1398 FileAsyncReader_WaitForNext,
1399 FileAsyncReader_SyncReadAligned,
1400 FileAsyncReader_SyncRead,
1401 FileAsyncReader_Length,
1402 FileAsyncReader_BeginFlush,
1403 FileAsyncReader_EndFlush,