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"
34 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
36 static const AM_MEDIA_TYPE default_mt
=
38 {0xe436eb83,0x524f,0x11ce,{0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70}}, /* MEDIATYPE_Stream */
39 {0,0,0,{0,0,0,0,0,0,0,0}},
43 {0,0,0,{0,0,0,0,0,0,0,0}},
56 typedef struct AsyncReader
58 struct strmbase_filter filter
;
59 IFileSourceFilter IFileSourceFilter_iface
;
61 struct strmbase_source source
;
62 IAsyncReader IAsyncReader_iface
;
66 ALLOCATOR_PROPERTIES allocProps
;
67 HANDLE file
, port
, io_thread
;
68 CRITICAL_SECTION sample_cs
;
70 struct request
*requests
;
71 unsigned int max_requests
;
72 CONDITION_VARIABLE sample_cv
;
75 static const struct strmbase_source_ops source_ops
;
77 static inline AsyncReader
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
79 return CONTAINING_RECORD(iface
, AsyncReader
, filter
);
82 static inline AsyncReader
*impl_from_IFileSourceFilter(IFileSourceFilter
*iface
)
84 return CONTAINING_RECORD(iface
, AsyncReader
, IFileSourceFilter_iface
);
87 static const IFileSourceFilterVtbl FileSource_Vtbl
;
88 static const IAsyncReaderVtbl FileAsyncReader_Vtbl
;
90 static int byte_from_hex_char(WCHAR c
)
92 if ('0' <= c
&& c
<= '9') return c
- '0';
93 if ('a' <= c
&& c
<= 'f') return c
- 'a' + 10;
94 if ('A' <= c
&& c
<= 'F') return c
- 'A' + 10;
98 static BOOL
process_pattern_string(const WCHAR
*pattern
, HANDLE file
)
100 ULONG size
, offset
, i
, ret_size
;
101 BYTE
*mask
, *expect
, *actual
;
105 /* format: "offset, size, mask, value" */
107 offset
= wcstol(pattern
, NULL
, 10);
109 if (!(pattern
= wcschr(pattern
, ',')))
113 size
= wcstol(pattern
, NULL
, 10);
114 mask
= heap_alloc(size
);
115 expect
= heap_alloc(size
);
116 memset(mask
, 0xff, size
);
118 if (!(pattern
= wcschr(pattern
, ',')))
125 while (byte_from_hex_char(*pattern
) == -1 && (*pattern
!= ','))
128 for (i
= 0; (d
= byte_from_hex_char(*pattern
)) != -1 && (i
/2 < size
); pattern
++, i
++)
133 mask
[i
/ 2] = d
<< 4;
136 if (!(pattern
= wcschr(pattern
, ',')))
143 while (byte_from_hex_char(*pattern
) == -1 && (*pattern
!= ','))
146 for (i
= 0; (d
= byte_from_hex_char(*pattern
)) != -1 && (i
/2 < size
); pattern
++, i
++)
151 expect
[i
/ 2] = d
<< 4;
154 actual
= heap_alloc(size
);
155 SetFilePointer(file
, offset
, NULL
, FILE_BEGIN
);
156 if (!ReadFile(file
, actual
, size
, &ret_size
, NULL
) || ret_size
!= size
)
164 for (i
= 0; i
< size
; ++i
)
166 if ((actual
[i
] & mask
[i
]) != expect
[i
])
177 /* If there is a following tuple, then we must match that as well. */
178 if (ret
&& (pattern
= wcschr(pattern
, ',')))
179 return process_pattern_string(pattern
+ 1, file
);
184 BOOL
get_media_type(const WCHAR
*filename
, GUID
*majortype
, GUID
*subtype
, GUID
*source_clsid
)
186 WCHAR extensions_path
[278] = {'M','e','d','i','a',' ','T','y','p','e','\\','E','x','t','e','n','s','i','o','n','s','\\',0};
187 static const WCHAR wszExtensions
[] = {'E','x','t','e','n','s','i','o','n','s',0};
188 static const WCHAR wszMediaType
[] = {'M','e','d','i','a',' ','T','y','p','e',0};
189 DWORD majortype_idx
, size
;
194 if ((ext
= wcsrchr(filename
, '.')))
199 wcscat(extensions_path
, ext
);
200 if (!RegOpenKeyExW(HKEY_CLASSES_ROOT
, extensions_path
, 0, KEY_READ
, &key
))
202 size
= sizeof(guidstr
);
203 if (majortype
&& !RegQueryValueExW(key
, L
"Media Type", NULL
, NULL
, (BYTE
*)guidstr
, &size
))
204 CLSIDFromString(guidstr
, majortype
);
206 size
= sizeof(guidstr
);
207 if (subtype
&& !RegQueryValueExW(key
, L
"Subtype", NULL
, NULL
, (BYTE
*)guidstr
, &size
))
208 CLSIDFromString(guidstr
, subtype
);
210 size
= sizeof(guidstr
);
211 if (source_clsid
&& !RegQueryValueExW(key
, L
"Source Filter", NULL
, NULL
, (BYTE
*)guidstr
, &size
))
212 CLSIDFromString(guidstr
, source_clsid
);
219 if ((file
= CreateFileW(filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
220 OPEN_EXISTING
, 0, NULL
)) == INVALID_HANDLE_VALUE
)
222 WARN("Failed to open file %s, error %u.\n", debugstr_w(filename
), GetLastError());
226 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszMediaType
, 0, KEY_READ
, &parent_key
))
232 for (majortype_idx
= 0; ; ++majortype_idx
)
234 WCHAR majortype_str
[39];
238 size
= ARRAY_SIZE(majortype_str
);
239 if (RegEnumKeyExW(parent_key
, majortype_idx
, majortype_str
, &size
, NULL
, NULL
, NULL
, NULL
))
242 if (!wcscmp(majortype_str
, wszExtensions
))
245 if (RegOpenKeyExW(parent_key
, majortype_str
, 0, KEY_READ
, &majortype_key
))
248 for (subtype_idx
= 0; ; ++subtype_idx
)
250 WCHAR subtype_str
[39], *pattern
;
251 DWORD value_idx
, max_size
;
254 size
= ARRAY_SIZE(subtype_str
);
255 if (RegEnumKeyExW(majortype_key
, subtype_idx
, subtype_str
, &size
, NULL
, NULL
, NULL
, NULL
))
258 if (RegOpenKeyExW(majortype_key
, subtype_str
, 0, KEY_READ
, &subtype_key
))
261 if (RegQueryInfoKeyW(subtype_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_size
, NULL
, NULL
))
264 pattern
= heap_alloc(max_size
);
266 for (value_idx
= 0; ; ++value_idx
)
268 /* The longest name we should encounter is "Source Filter". */
269 WCHAR value_name
[14], source_clsid_str
[39];
270 DWORD value_len
= ARRAY_SIZE(value_name
);
273 if (RegEnumValueW(subtype_key
, value_idx
, value_name
, &value_len
,
274 NULL
, NULL
, (BYTE
*)pattern
, &max_size
))
277 if (!wcscmp(value_name
, L
"Source Filter"))
280 if (!process_pattern_string(pattern
, file
))
284 CLSIDFromString(majortype_str
, majortype
);
286 CLSIDFromString(subtype_str
, subtype
);
287 size
= sizeof(source_clsid_str
);
288 if (source_clsid
&& !RegQueryValueExW(subtype_key
, L
"Source Filter",
289 NULL
, NULL
, (BYTE
*)source_clsid_str
, &size
))
290 CLSIDFromString(source_clsid_str
, source_clsid
);
293 RegCloseKey(subtype_key
);
294 RegCloseKey(majortype_key
);
295 RegCloseKey(parent_key
);
301 RegCloseKey(subtype_key
);
304 RegCloseKey(majortype_key
);
307 RegCloseKey(parent_key
);
312 static struct strmbase_pin
*async_reader_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
314 AsyncReader
*filter
= impl_from_strmbase_filter(iface
);
316 if (!index
&& filter
->pszFileName
)
317 return &filter
->source
.pin
;
321 static void async_reader_destroy(struct strmbase_filter
*iface
)
323 AsyncReader
*filter
= impl_from_strmbase_filter(iface
);
325 if (filter
->pszFileName
)
329 if (filter
->source
.pin
.peer
)
330 IPin_Disconnect(filter
->source
.pin
.peer
);
332 IPin_Disconnect(&filter
->source
.pin
.IPin_iface
);
334 if (filter
->requests
)
336 for (i
= 0; i
< filter
->max_requests
; ++i
)
337 CloseHandle(filter
->requests
[i
].ovl
.hEvent
);
338 free(filter
->requests
);
340 CloseHandle(filter
->file
);
341 filter
->sample_cs
.DebugInfo
->Spare
[0] = 0;
342 DeleteCriticalSection(&filter
->sample_cs
);
343 strmbase_source_cleanup(&filter
->source
);
345 CoTaskMemFree(filter
->pszFileName
);
346 FreeMediaType(&filter
->mt
);
349 PostQueuedCompletionStatus(filter
->port
, 0, 1, NULL
);
350 WaitForSingleObject(filter
->io_thread
, INFINITE
);
351 CloseHandle(filter
->io_thread
);
352 CloseHandle(filter
->port
);
354 strmbase_filter_cleanup(&filter
->filter
);
357 InterlockedDecrement(&object_locks
);
360 static HRESULT
async_reader_query_interface(struct strmbase_filter
*iface
, REFIID iid
, void **out
)
362 AsyncReader
*filter
= impl_from_strmbase_filter(iface
);
364 if (IsEqualGUID(iid
, &IID_IFileSourceFilter
))
366 *out
= &filter
->IFileSourceFilter_iface
;
367 IUnknown_AddRef((IUnknown
*)*out
);
371 return E_NOINTERFACE
;
374 static const struct strmbase_filter_ops filter_ops
=
376 .filter_get_pin
= async_reader_get_pin
,
377 .filter_destroy
= async_reader_destroy
,
378 .filter_query_interface
= async_reader_query_interface
,
381 static DWORD CALLBACK
io_thread(void *arg
)
383 AsyncReader
*filter
= arg
;
392 ret
= GetQueuedCompletionStatus(filter
->port
, &size
, &key
, &ovl
, INFINITE
);
397 EnterCriticalSection(&filter
->sample_cs
);
399 req
= CONTAINING_RECORD(ovl
, struct request
, ovl
);
400 TRACE("Got sample %u.\n", req
- filter
->requests
);
401 assert(req
>= filter
->requests
&& req
< filter
->requests
+ filter
->max_requests
);
404 WakeConditionVariable(&filter
->sample_cv
);
407 ERR("GetQueuedCompletionStatus() returned failure, error %u.\n", GetLastError());
411 LeaveCriticalSection(&filter
->sample_cs
);
417 HRESULT
async_reader_create(IUnknown
*outer
, IUnknown
**out
)
421 if (!(object
= calloc(1, sizeof(*object
))))
422 return E_OUTOFMEMORY
;
424 strmbase_filter_init(&object
->filter
, outer
, &CLSID_AsyncReader
, &filter_ops
);
426 object
->IFileSourceFilter_iface
.lpVtbl
= &FileSource_Vtbl
;
427 object
->IAsyncReader_iface
.lpVtbl
= &FileAsyncReader_Vtbl
;
429 InitializeCriticalSection(&object
->sample_cs
);
430 object
->sample_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": FileAsyncReader.sample_cs");
431 InitializeConditionVariable(&object
->sample_cv
);
432 object
->port
= CreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 0);
433 object
->io_thread
= CreateThread(NULL
, 0, io_thread
, object
, 0, NULL
);
435 TRACE("Created file source %p.\n", object
);
436 *out
= &object
->filter
.IUnknown_inner
;
440 static HRESULT WINAPI
FileSource_QueryInterface(IFileSourceFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
442 AsyncReader
*This
= impl_from_IFileSourceFilter(iface
);
444 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
447 static ULONG WINAPI
FileSource_AddRef(IFileSourceFilter
* iface
)
449 AsyncReader
*This
= impl_from_IFileSourceFilter(iface
);
451 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
454 static ULONG WINAPI
FileSource_Release(IFileSourceFilter
* iface
)
456 AsyncReader
*This
= impl_from_IFileSourceFilter(iface
);
458 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
461 static HRESULT WINAPI
FileSource_Load(IFileSourceFilter
* iface
, LPCOLESTR pszFileName
, const AM_MEDIA_TYPE
* pmt
)
464 AsyncReader
*This
= impl_from_IFileSourceFilter(iface
);
466 TRACE("%p->(%s, %p)\n", This
, debugstr_w(pszFileName
), pmt
);
467 strmbase_dump_media_type(pmt
);
473 /* FIXME: check the sharing values that native uses */
474 hFile
= CreateFileW(pszFileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, NULL
);
476 if (hFile
== INVALID_HANDLE_VALUE
)
478 return HRESULT_FROM_WIN32(GetLastError());
481 if (This
->pszFileName
)
483 free(This
->pszFileName
);
484 FreeMediaType(&This
->mt
);
487 if (!(This
->pszFileName
= wcsdup(pszFileName
)))
490 return E_OUTOFMEMORY
;
493 strmbase_source_init(&This
->source
, &This
->filter
, L
"Output", &source_ops
);
494 BaseFilterImpl_IncrementPinVersion(&This
->filter
);
497 This
->flushing
= FALSE
;
498 This
->requests
= NULL
;
502 CopyMediaType(&This
->mt
, &default_mt
);
503 if (get_media_type(pszFileName
, &This
->mt
.majortype
, &This
->mt
.subtype
, NULL
))
505 TRACE("Found major type %s, subtype %s.\n",
506 debugstr_guid(&This
->mt
.majortype
), debugstr_guid(&This
->mt
.subtype
));
510 CopyMediaType(&This
->mt
, pmt
);
515 static HRESULT WINAPI
FileSource_GetCurFile(IFileSourceFilter
*iface
, LPOLESTR
*ppszFileName
, AM_MEDIA_TYPE
*mt
)
517 AsyncReader
*This
= impl_from_IFileSourceFilter(iface
);
519 TRACE("filter %p, filename %p, mt %p.\n", This
, ppszFileName
, mt
);
524 /* copy file name & media type if available, otherwise clear the outputs */
525 if (This
->pszFileName
)
527 *ppszFileName
= CoTaskMemAlloc((wcslen(This
->pszFileName
) + 1) * sizeof(WCHAR
));
528 wcscpy(*ppszFileName
, This
->pszFileName
);
530 CopyMediaType(mt
, &This
->mt
);
534 *ppszFileName
= NULL
;
536 memset(mt
, 0, sizeof(AM_MEDIA_TYPE
));
542 static const IFileSourceFilterVtbl FileSource_Vtbl
=
544 FileSource_QueryInterface
,
548 FileSource_GetCurFile
551 static inline AsyncReader
*impl_from_strmbase_pin(struct strmbase_pin
*iface
)
553 return CONTAINING_RECORD(iface
, AsyncReader
, source
.pin
);
556 static inline AsyncReader
*impl_from_strmbase_source(struct strmbase_source
*iface
)
558 return CONTAINING_RECORD(iface
, AsyncReader
, source
);
561 static inline AsyncReader
*impl_from_IAsyncReader(IAsyncReader
*iface
)
563 return CONTAINING_RECORD(iface
, AsyncReader
, IAsyncReader_iface
);
566 static HRESULT
source_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
568 AsyncReader
*filter
= impl_from_strmbase_pin(iface
);
570 if (IsEqualGUID(&mt
->majortype
, &filter
->mt
.majortype
)
571 && (!IsEqualGUID(&mt
->subtype
, &GUID_NULL
)
572 || IsEqualGUID(&filter
->mt
.subtype
, &GUID_NULL
)))
578 static HRESULT
source_get_media_type(struct strmbase_pin
*iface
, unsigned int index
, AM_MEDIA_TYPE
*mt
)
580 AsyncReader
*filter
= impl_from_strmbase_pin(iface
);
583 return VFW_S_NO_MORE_ITEMS
;
586 CopyMediaType(mt
, &filter
->mt
);
588 CopyMediaType(mt
, &default_mt
);
592 static HRESULT
source_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
594 AsyncReader
*filter
= impl_from_strmbase_pin(iface
);
596 if (IsEqualGUID(iid
, &IID_IAsyncReader
))
597 *out
= &filter
->IAsyncReader_iface
;
599 return E_NOINTERFACE
;
601 IUnknown_AddRef((IUnknown
*)*out
);
605 /* Function called as a helper to IPin_Connect */
606 /* specific AM_MEDIA_TYPE - it cannot be NULL */
607 /* this differs from standard OutputPin_AttemptConnection only in that it
608 * doesn't need the IMemInputPin interface on the receiving pin */
609 static HRESULT WINAPI
FileAsyncReaderPin_AttemptConnection(struct strmbase_source
*This
,
610 IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
614 TRACE("%p->(%p, %p)\n", This
, pReceivePin
, pmt
);
616 if (This
->pin
.ops
->pin_query_accept(&This
->pin
, pmt
) != S_OK
)
617 return VFW_E_TYPE_NOT_ACCEPTED
;
619 This
->pin
.peer
= pReceivePin
;
620 IPin_AddRef(pReceivePin
);
621 CopyMediaType(&This
->pin
.mt
, pmt
);
623 hr
= IPin_ReceiveConnection(pReceivePin
, &This
->pin
.IPin_iface
, pmt
);
627 IPin_Release(This
->pin
.peer
);
628 This
->pin
.peer
= NULL
;
629 FreeMediaType(&This
->pin
.mt
);
632 TRACE(" -- %x\n", hr
);
636 static HRESULT WINAPI
FileAsyncReaderPin_DecideBufferSize(struct strmbase_source
*iface
,
637 IMemAllocator
*pAlloc
, ALLOCATOR_PROPERTIES
*ppropInputRequest
)
639 AsyncReader
*This
= impl_from_strmbase_source(iface
);
640 ALLOCATOR_PROPERTIES actual
;
642 if (ppropInputRequest
->cbAlign
&& ppropInputRequest
->cbAlign
!= This
->allocProps
.cbAlign
)
643 FIXME("Requested Buffer cbAlign mismatch %i,%i\n",This
->allocProps
.cbAlign
, ppropInputRequest
->cbAlign
);
644 if (ppropInputRequest
->cbPrefix
)
645 FIXME("Requested Buffer cbPrefix mismatch %i,%i\n",This
->allocProps
.cbPrefix
, ppropInputRequest
->cbPrefix
);
646 if (ppropInputRequest
->cbBuffer
)
647 FIXME("Requested Buffer cbBuffer mismatch %i,%i\n",This
->allocProps
.cbBuffer
, ppropInputRequest
->cbBuffer
);
648 if (ppropInputRequest
->cBuffers
)
649 FIXME("Requested Buffer cBuffers mismatch %i,%i\n",This
->allocProps
.cBuffers
, ppropInputRequest
->cBuffers
);
651 return IMemAllocator_SetProperties(pAlloc
, &This
->allocProps
, &actual
);
654 static const struct strmbase_source_ops source_ops
=
656 .base
.pin_query_accept
= source_query_accept
,
657 .base
.pin_get_media_type
= source_get_media_type
,
658 .base
.pin_query_interface
= source_query_interface
,
659 .pfnAttemptConnection
= FileAsyncReaderPin_AttemptConnection
,
660 .pfnDecideBufferSize
= FileAsyncReaderPin_DecideBufferSize
,
661 .pfnDecideAllocator
= BaseOutputPinImpl_DecideAllocator
,
664 static HRESULT WINAPI
FileAsyncReader_QueryInterface(IAsyncReader
*iface
, REFIID iid
, void **out
)
666 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
667 return IPin_QueryInterface(&filter
->source
.pin
.IPin_iface
, iid
, out
);
670 static ULONG WINAPI
FileAsyncReader_AddRef(IAsyncReader
* iface
)
672 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
673 return IPin_AddRef(&filter
->source
.pin
.IPin_iface
);
676 static ULONG WINAPI
FileAsyncReader_Release(IAsyncReader
* iface
)
678 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
679 return IPin_Release(&filter
->source
.pin
.IPin_iface
);
682 static HRESULT WINAPI
FileAsyncReader_RequestAllocator(IAsyncReader
*iface
,
683 IMemAllocator
*preferred
, ALLOCATOR_PROPERTIES
*props
, IMemAllocator
**ret_allocator
)
685 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
686 IMemAllocator
*allocator
;
690 TRACE("filter %p, preferred %p, props %p, ret_allocator %p.\n", filter
, preferred
, props
, ret_allocator
);
695 *ret_allocator
= NULL
;
698 IMemAllocator_AddRef(allocator
= preferred
);
699 else if (FAILED(hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
,
700 CLSCTX_INPROC
, &IID_IMemAllocator
, (void **)&allocator
)))
703 if (FAILED(hr
= IMemAllocator_SetProperties(allocator
, props
, props
)))
705 IMemAllocator_Release(allocator
);
709 if (filter
->requests
)
711 for (i
= 0; i
< filter
->max_requests
; ++i
)
712 CloseHandle(filter
->requests
[i
].ovl
.hEvent
);
713 free(filter
->requests
);
716 filter
->max_requests
= props
->cBuffers
;
717 TRACE("Maximum request count: %u.\n", filter
->max_requests
);
718 if (!(filter
->requests
= calloc(filter
->max_requests
, sizeof(filter
->requests
[0]))))
720 IMemAllocator_Release(allocator
);
721 return E_OUTOFMEMORY
;
724 for (i
= 0; i
< filter
->max_requests
; ++i
)
725 filter
->requests
[i
].ovl
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
726 filter
->allocProps
= *props
;
728 *ret_allocator
= allocator
;
732 static HRESULT WINAPI
FileAsyncReader_Request(IAsyncReader
*iface
, IMediaSample
*sample
, DWORD_PTR cookie
)
734 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
735 REFERENCE_TIME start
, end
;
741 TRACE("filter %p, sample %p, cookie %#lx.\n", filter
, sample
, cookie
);
746 if (FAILED(hr
= IMediaSample_GetTime(sample
, &start
, &end
)))
749 if (FAILED(hr
= IMediaSample_GetPointer(sample
, &data
)))
752 EnterCriticalSection(&filter
->sample_cs
);
753 if (filter
->flushing
)
755 LeaveCriticalSection(&filter
->sample_cs
);
756 return VFW_E_WRONG_STATE
;
759 for (i
= 0; i
< filter
->max_requests
; ++i
)
761 if (!filter
->requests
[i
].sample
)
764 assert(i
< filter
->max_requests
);
765 req
= &filter
->requests
[i
];
767 req
->ovl
.u
.s
.Offset
= BYTES_FROM_MEDIATIME(start
);
768 req
->ovl
.u
.s
.OffsetHigh
= BYTES_FROM_MEDIATIME(start
) >> 32;
769 /* No reference is taken. */
771 if (ReadFile(filter
->file
, data
, BYTES_FROM_MEDIATIME(end
- start
), NULL
, &req
->ovl
)
772 || GetLastError() == ERROR_IO_PENDING
)
775 req
->sample
= sample
;
776 req
->cookie
= cookie
;
779 hr
= HRESULT_FROM_WIN32(GetLastError());
781 LeaveCriticalSection(&filter
->sample_cs
);
785 static HRESULT WINAPI
FileAsyncReader_WaitForNext(IAsyncReader
*iface
,
786 DWORD timeout
, IMediaSample
**sample
, DWORD_PTR
*cookie
)
788 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
791 TRACE("filter %p, timeout %u, sample %p, cookie %p.\n", filter
, timeout
, sample
, cookie
);
796 EnterCriticalSection(&filter
->sample_cs
);
800 if (filter
->flushing
)
802 LeaveCriticalSection(&filter
->sample_cs
);
803 return VFW_E_WRONG_STATE
;
806 for (i
= 0; i
< filter
->max_requests
; ++i
)
808 struct request
*req
= &filter
->requests
[i
];
811 if (req
->sample
&& GetOverlappedResult(filter
->file
, &req
->ovl
, &size
, FALSE
))
813 REFERENCE_TIME start
, end
;
815 IMediaSample_SetActualDataLength(req
->sample
, size
);
816 start
= MEDIATIME_FROM_BYTES(((ULONGLONG
)req
->ovl
.u
.s
.OffsetHigh
<< 32) + req
->ovl
.u
.s
.Offset
);
817 end
= start
+ MEDIATIME_FROM_BYTES(size
);
818 IMediaSample_SetTime(req
->sample
, &start
, &end
);
820 *sample
= req
->sample
;
821 *cookie
= req
->cookie
;
824 LeaveCriticalSection(&filter
->sample_cs
);
825 TRACE("Returning sample %u.\n", i
);
829 } while (SleepConditionVariableCS(&filter
->sample_cv
, &filter
->sample_cs
, timeout
));
831 LeaveCriticalSection(&filter
->sample_cs
);
832 return VFW_E_TIMEOUT
;
835 static BOOL
sync_read(HANDLE file
, LONGLONG offset
, LONG length
, BYTE
*buffer
, DWORD
*read_len
)
837 OVERLAPPED ovl
= {0};
840 ovl
.hEvent
= (HANDLE
)((ULONG_PTR
)CreateEventW(NULL
, TRUE
, FALSE
, NULL
) | 1);
841 ovl
.u
.s
.Offset
= (DWORD
)offset
;
842 ovl
.u
.s
.OffsetHigh
= offset
>> 32;
846 ret
= ReadFile(file
, buffer
, length
, NULL
, &ovl
);
847 if (ret
|| GetLastError() == ERROR_IO_PENDING
)
848 ret
= GetOverlappedResult(file
, &ovl
, read_len
, TRUE
);
850 TRACE("Returning %u bytes.\n", *read_len
);
852 CloseHandle(ovl
.hEvent
);
856 static HRESULT WINAPI
FileAsyncReader_SyncReadAligned(IAsyncReader
*iface
, IMediaSample
*sample
)
858 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
859 REFERENCE_TIME start_time
, end_time
;
866 TRACE("filter %p, sample %p.\n", filter
, sample
);
868 hr
= IMediaSample_GetTime(sample
, &start_time
, &end_time
);
871 hr
= IMediaSample_GetPointer(sample
, &buffer
);
875 length
= BYTES_FROM_MEDIATIME(end_time
- start_time
);
876 ret
= sync_read(filter
->file
, BYTES_FROM_MEDIATIME(start_time
), length
, buffer
, &read_len
);
878 hr
= (read_len
== length
) ? S_OK
: S_FALSE
;
879 else if (GetLastError() == ERROR_HANDLE_EOF
)
882 hr
= HRESULT_FROM_WIN32(GetLastError());
886 IMediaSample_SetActualDataLength(sample
, read_len
);
891 static HRESULT WINAPI
FileAsyncReader_SyncRead(IAsyncReader
*iface
,
892 LONGLONG offset
, LONG length
, BYTE
*buffer
)
894 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
899 TRACE("filter %p, offset %s, length %d, buffer %p.\n",
900 filter
, wine_dbgstr_longlong(offset
), length
, buffer
);
902 ret
= sync_read(filter
->file
, offset
, length
, buffer
, &read_len
);
904 hr
= (read_len
== length
) ? S_OK
: S_FALSE
;
905 else if (GetLastError() == ERROR_HANDLE_EOF
)
908 hr
= HRESULT_FROM_WIN32(GetLastError());
913 static HRESULT WINAPI
FileAsyncReader_Length(IAsyncReader
*iface
, LONGLONG
*total
, LONGLONG
*available
)
915 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
918 TRACE("iface %p, total %p, available %p.\n", iface
, total
, available
);
920 if ((low
= GetFileSize(filter
->file
, &high
)) == -1 && GetLastError() != NO_ERROR
)
921 return HRESULT_FROM_WIN32(GetLastError());
923 *available
= *total
= (LONGLONG
)low
| (LONGLONG
)high
<< (sizeof(DWORD
) * 8);
928 static HRESULT WINAPI
FileAsyncReader_BeginFlush(IAsyncReader
* iface
)
930 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
933 TRACE("iface %p.\n", iface
);
935 EnterCriticalSection(&filter
->sample_cs
);
937 filter
->flushing
= TRUE
;
938 for (i
= 0; i
< filter
->max_requests
; ++i
)
939 filter
->requests
[i
].sample
= NULL
;
940 CancelIoEx(filter
->file
, NULL
);
941 WakeAllConditionVariable(&filter
->sample_cv
);
943 LeaveCriticalSection(&filter
->sample_cs
);
948 static HRESULT WINAPI
FileAsyncReader_EndFlush(IAsyncReader
* iface
)
950 AsyncReader
*filter
= impl_from_IAsyncReader(iface
);
952 TRACE("iface %p.\n", iface
);
954 EnterCriticalSection(&filter
->sample_cs
);
956 filter
->flushing
= FALSE
;
958 LeaveCriticalSection(&filter
->sample_cs
);
963 static const IAsyncReaderVtbl FileAsyncReader_Vtbl
=
965 FileAsyncReader_QueryInterface
,
966 FileAsyncReader_AddRef
,
967 FileAsyncReader_Release
,
968 FileAsyncReader_RequestAllocator
,
969 FileAsyncReader_Request
,
970 FileAsyncReader_WaitForNext
,
971 FileAsyncReader_SyncReadAligned
,
972 FileAsyncReader_SyncRead
,
973 FileAsyncReader_Length
,
974 FileAsyncReader_BeginFlush
,
975 FileAsyncReader_EndFlush
,