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}},
58 struct strmbase_filter filter
;
59 IFileSourceFilter IFileSourceFilter_iface
;
61 struct strmbase_source source
;
62 IAsyncReader IAsyncReader_iface
;
66 HANDLE file
, port
, io_thread
;
67 LARGE_INTEGER file_size
;
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 struct async_reader
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
79 return CONTAINING_RECORD(iface
, struct async_reader
, filter
);
82 static inline struct async_reader
*impl_from_IFileSourceFilter(IFileSourceFilter
*iface
)
84 return CONTAINING_RECORD(iface
, struct async_reader
, 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] = L
"Media Type\\Extensions\\";
187 DWORD majortype_idx
, size
;
192 if ((ext
= wcsrchr(filename
, '.')))
197 wcscat(extensions_path
, ext
);
198 if (!RegOpenKeyExW(HKEY_CLASSES_ROOT
, extensions_path
, 0, KEY_READ
, &key
))
200 size
= sizeof(guidstr
);
201 if (majortype
&& !RegQueryValueExW(key
, L
"Media Type", NULL
, NULL
, (BYTE
*)guidstr
, &size
))
202 CLSIDFromString(guidstr
, majortype
);
204 size
= sizeof(guidstr
);
205 if (subtype
&& !RegQueryValueExW(key
, L
"Subtype", NULL
, NULL
, (BYTE
*)guidstr
, &size
))
206 CLSIDFromString(guidstr
, subtype
);
208 size
= sizeof(guidstr
);
209 if (source_clsid
&& !RegQueryValueExW(key
, L
"Source Filter", NULL
, NULL
, (BYTE
*)guidstr
, &size
))
210 CLSIDFromString(guidstr
, source_clsid
);
217 if ((file
= CreateFileW(filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
218 OPEN_EXISTING
, 0, NULL
)) == INVALID_HANDLE_VALUE
)
220 WARN("Failed to open file %s, error %u.\n", debugstr_w(filename
), GetLastError());
224 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Media Type", 0, KEY_READ
, &parent_key
))
230 for (majortype_idx
= 0; ; ++majortype_idx
)
232 WCHAR majortype_str
[39];
236 size
= ARRAY_SIZE(majortype_str
);
237 if (RegEnumKeyExW(parent_key
, majortype_idx
, majortype_str
, &size
, NULL
, NULL
, NULL
, NULL
))
240 if (!wcscmp(majortype_str
, L
"Extensions"))
243 if (RegOpenKeyExW(parent_key
, majortype_str
, 0, KEY_READ
, &majortype_key
))
246 for (subtype_idx
= 0; ; ++subtype_idx
)
248 WCHAR subtype_str
[39], *pattern
;
249 DWORD value_idx
, max_size
;
252 size
= ARRAY_SIZE(subtype_str
);
253 if (RegEnumKeyExW(majortype_key
, subtype_idx
, subtype_str
, &size
, NULL
, NULL
, NULL
, NULL
))
256 if (RegOpenKeyExW(majortype_key
, subtype_str
, 0, KEY_READ
, &subtype_key
))
259 if (RegQueryInfoKeyW(subtype_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_size
, NULL
, NULL
))
262 pattern
= heap_alloc(max_size
);
264 for (value_idx
= 0; ; ++value_idx
)
266 /* The longest name we should encounter is "Source Filter". */
267 WCHAR value_name
[14], source_clsid_str
[39];
268 DWORD value_len
= ARRAY_SIZE(value_name
);
271 if (RegEnumValueW(subtype_key
, value_idx
, value_name
, &value_len
,
272 NULL
, NULL
, (BYTE
*)pattern
, &max_size
))
275 if (!wcscmp(value_name
, L
"Source Filter"))
278 if (!process_pattern_string(pattern
, file
))
282 CLSIDFromString(majortype_str
, majortype
);
284 CLSIDFromString(subtype_str
, subtype
);
285 size
= sizeof(source_clsid_str
);
286 if (source_clsid
&& !RegQueryValueExW(subtype_key
, L
"Source Filter",
287 NULL
, NULL
, (BYTE
*)source_clsid_str
, &size
))
288 CLSIDFromString(source_clsid_str
, source_clsid
);
291 RegCloseKey(subtype_key
);
292 RegCloseKey(majortype_key
);
293 RegCloseKey(parent_key
);
299 RegCloseKey(subtype_key
);
302 RegCloseKey(majortype_key
);
305 RegCloseKey(parent_key
);
310 static struct strmbase_pin
*async_reader_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
312 struct async_reader
*filter
= impl_from_strmbase_filter(iface
);
314 if (!index
&& filter
->pszFileName
)
315 return &filter
->source
.pin
;
319 static void async_reader_destroy(struct strmbase_filter
*iface
)
321 struct async_reader
*filter
= impl_from_strmbase_filter(iface
);
323 if (filter
->pszFileName
)
327 if (filter
->source
.pin
.peer
)
328 IPin_Disconnect(filter
->source
.pin
.peer
);
330 IPin_Disconnect(&filter
->source
.pin
.IPin_iface
);
332 if (filter
->requests
)
334 for (i
= 0; i
< filter
->max_requests
; ++i
)
335 CloseHandle(filter
->requests
[i
].ovl
.hEvent
);
336 free(filter
->requests
);
338 CloseHandle(filter
->file
);
339 filter
->sample_cs
.DebugInfo
->Spare
[0] = 0;
340 DeleteCriticalSection(&filter
->sample_cs
);
341 strmbase_source_cleanup(&filter
->source
);
343 free(filter
->pszFileName
);
344 FreeMediaType(&filter
->mt
);
347 PostQueuedCompletionStatus(filter
->port
, 0, 1, NULL
);
348 WaitForSingleObject(filter
->io_thread
, INFINITE
);
349 CloseHandle(filter
->io_thread
);
350 CloseHandle(filter
->port
);
352 strmbase_filter_cleanup(&filter
->filter
);
355 InterlockedDecrement(&object_locks
);
358 static HRESULT
async_reader_query_interface(struct strmbase_filter
*iface
, REFIID iid
, void **out
)
360 struct async_reader
*filter
= impl_from_strmbase_filter(iface
);
362 if (IsEqualGUID(iid
, &IID_IFileSourceFilter
))
364 *out
= &filter
->IFileSourceFilter_iface
;
365 IUnknown_AddRef((IUnknown
*)*out
);
369 return E_NOINTERFACE
;
372 static const struct strmbase_filter_ops filter_ops
=
374 .filter_get_pin
= async_reader_get_pin
,
375 .filter_destroy
= async_reader_destroy
,
376 .filter_query_interface
= async_reader_query_interface
,
379 static DWORD CALLBACK
io_thread(void *arg
)
381 struct async_reader
*filter
= arg
;
390 ret
= GetQueuedCompletionStatus(filter
->port
, &size
, &key
, &ovl
, INFINITE
);
395 EnterCriticalSection(&filter
->sample_cs
);
397 req
= CONTAINING_RECORD(ovl
, struct request
, ovl
);
398 TRACE("Got sample %u.\n", req
- filter
->requests
);
399 assert(req
>= filter
->requests
&& req
< filter
->requests
+ filter
->max_requests
);
402 WakeConditionVariable(&filter
->sample_cv
);
405 ERR("GetQueuedCompletionStatus() returned failure, error %u.\n", GetLastError());
409 LeaveCriticalSection(&filter
->sample_cs
);
415 HRESULT
async_reader_create(IUnknown
*outer
, IUnknown
**out
)
417 struct async_reader
*object
;
419 if (!(object
= calloc(1, sizeof(*object
))))
420 return E_OUTOFMEMORY
;
422 strmbase_filter_init(&object
->filter
, outer
, &CLSID_AsyncReader
, &filter_ops
);
424 object
->IFileSourceFilter_iface
.lpVtbl
= &FileSource_Vtbl
;
425 object
->IAsyncReader_iface
.lpVtbl
= &FileAsyncReader_Vtbl
;
427 InitializeCriticalSection(&object
->sample_cs
);
428 object
->sample_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": FileAsyncReader.sample_cs");
429 InitializeConditionVariable(&object
->sample_cv
);
430 object
->port
= CreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 0);
431 object
->io_thread
= CreateThread(NULL
, 0, io_thread
, object
, 0, NULL
);
433 TRACE("Created file source %p.\n", object
);
434 *out
= &object
->filter
.IUnknown_inner
;
438 static HRESULT WINAPI
FileSource_QueryInterface(IFileSourceFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
440 struct async_reader
*filter
= impl_from_IFileSourceFilter(iface
);
441 return IBaseFilter_QueryInterface(&filter
->filter
.IBaseFilter_iface
, riid
, ppv
);
444 static ULONG WINAPI
FileSource_AddRef(IFileSourceFilter
* iface
)
446 struct async_reader
*filter
= impl_from_IFileSourceFilter(iface
);
447 return IBaseFilter_AddRef(&filter
->filter
.IBaseFilter_iface
);
450 static ULONG WINAPI
FileSource_Release(IFileSourceFilter
* iface
)
452 struct async_reader
*filter
= impl_from_IFileSourceFilter(iface
);
453 return IBaseFilter_Release(&filter
->filter
.IBaseFilter_iface
);
456 static HRESULT WINAPI
FileSource_Load(IFileSourceFilter
* iface
, LPCOLESTR pszFileName
, const AM_MEDIA_TYPE
* pmt
)
458 struct async_reader
*This
= impl_from_IFileSourceFilter(iface
);
461 TRACE("%p->(%s, %p)\n", This
, debugstr_w(pszFileName
), pmt
);
462 strmbase_dump_media_type(pmt
);
468 /* FIXME: check the sharing values that native uses */
469 hFile
= CreateFileW(pszFileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, NULL
);
471 if (hFile
== INVALID_HANDLE_VALUE
)
473 return HRESULT_FROM_WIN32(GetLastError());
476 if (!GetFileSizeEx(hFile
, &This
->file_size
))
478 WARN("Could not get file size.\n");
480 return HRESULT_FROM_WIN32(GetLastError());
483 if (This
->pszFileName
)
485 free(This
->pszFileName
);
486 FreeMediaType(&This
->mt
);
489 if (!(This
->pszFileName
= wcsdup(pszFileName
)))
492 return E_OUTOFMEMORY
;
495 strmbase_source_init(&This
->source
, &This
->filter
, L
"Output", &source_ops
);
496 BaseFilterImpl_IncrementPinVersion(&This
->filter
);
499 This
->flushing
= FALSE
;
500 This
->requests
= NULL
;
504 CopyMediaType(&This
->mt
, &default_mt
);
505 if (get_media_type(pszFileName
, &This
->mt
.majortype
, &This
->mt
.subtype
, NULL
))
507 TRACE("Found major type %s, subtype %s.\n",
508 debugstr_guid(&This
->mt
.majortype
), debugstr_guid(&This
->mt
.subtype
));
512 CopyMediaType(&This
->mt
, pmt
);
517 static HRESULT WINAPI
FileSource_GetCurFile(IFileSourceFilter
*iface
, LPOLESTR
*ppszFileName
, AM_MEDIA_TYPE
*mt
)
519 struct async_reader
*This
= impl_from_IFileSourceFilter(iface
);
521 TRACE("filter %p, filename %p, mt %p.\n", This
, ppszFileName
, mt
);
526 /* copy file name & media type if available, otherwise clear the outputs */
527 if (This
->pszFileName
)
529 *ppszFileName
= CoTaskMemAlloc((wcslen(This
->pszFileName
) + 1) * sizeof(WCHAR
));
530 wcscpy(*ppszFileName
, This
->pszFileName
);
532 CopyMediaType(mt
, &This
->mt
);
536 *ppszFileName
= NULL
;
538 memset(mt
, 0, sizeof(AM_MEDIA_TYPE
));
544 static const IFileSourceFilterVtbl FileSource_Vtbl
=
546 FileSource_QueryInterface
,
550 FileSource_GetCurFile
553 static inline struct async_reader
*impl_from_strmbase_pin(struct strmbase_pin
*iface
)
555 return CONTAINING_RECORD(iface
, struct async_reader
, source
.pin
);
558 static inline struct async_reader
*impl_from_IAsyncReader(IAsyncReader
*iface
)
560 return CONTAINING_RECORD(iface
, struct async_reader
, IAsyncReader_iface
);
563 static HRESULT
source_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
565 struct async_reader
*filter
= impl_from_strmbase_pin(iface
);
567 if (IsEqualGUID(&mt
->majortype
, &filter
->mt
.majortype
)
568 && (!IsEqualGUID(&mt
->subtype
, &GUID_NULL
)
569 || IsEqualGUID(&filter
->mt
.subtype
, &GUID_NULL
)))
575 static HRESULT
source_get_media_type(struct strmbase_pin
*iface
, unsigned int index
, AM_MEDIA_TYPE
*mt
)
577 struct async_reader
*filter
= impl_from_strmbase_pin(iface
);
580 return VFW_S_NO_MORE_ITEMS
;
583 CopyMediaType(mt
, &filter
->mt
);
585 CopyMediaType(mt
, &default_mt
);
589 static HRESULT
source_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
591 struct async_reader
*filter
= impl_from_strmbase_pin(iface
);
593 if (IsEqualGUID(iid
, &IID_IAsyncReader
))
594 *out
= &filter
->IAsyncReader_iface
;
596 return E_NOINTERFACE
;
598 IUnknown_AddRef((IUnknown
*)*out
);
602 /* Function called as a helper to IPin_Connect */
603 /* specific AM_MEDIA_TYPE - it cannot be NULL */
604 /* this differs from standard OutputPin_AttemptConnection only in that it
605 * doesn't need the IMemInputPin interface on the receiving pin */
606 static HRESULT WINAPI
FileAsyncReaderPin_AttemptConnection(struct strmbase_source
*This
,
607 IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
611 TRACE("%p->(%p, %p)\n", This
, pReceivePin
, pmt
);
613 if (This
->pin
.ops
->pin_query_accept(&This
->pin
, pmt
) != S_OK
)
614 return VFW_E_TYPE_NOT_ACCEPTED
;
616 This
->pin
.peer
= pReceivePin
;
617 IPin_AddRef(pReceivePin
);
618 CopyMediaType(&This
->pin
.mt
, pmt
);
620 hr
= IPin_ReceiveConnection(pReceivePin
, &This
->pin
.IPin_iface
, pmt
);
624 IPin_Release(This
->pin
.peer
);
625 This
->pin
.peer
= NULL
;
626 FreeMediaType(&This
->pin
.mt
);
629 TRACE(" -- %x\n", hr
);
633 static const struct strmbase_source_ops source_ops
=
635 .base
.pin_query_accept
= source_query_accept
,
636 .base
.pin_get_media_type
= source_get_media_type
,
637 .base
.pin_query_interface
= source_query_interface
,
638 .pfnAttemptConnection
= FileAsyncReaderPin_AttemptConnection
,
641 static HRESULT WINAPI
FileAsyncReader_QueryInterface(IAsyncReader
*iface
, REFIID iid
, void **out
)
643 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
644 return IPin_QueryInterface(&filter
->source
.pin
.IPin_iface
, iid
, out
);
647 static ULONG WINAPI
FileAsyncReader_AddRef(IAsyncReader
* iface
)
649 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
650 return IPin_AddRef(&filter
->source
.pin
.IPin_iface
);
653 static ULONG WINAPI
FileAsyncReader_Release(IAsyncReader
* iface
)
655 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
656 return IPin_Release(&filter
->source
.pin
.IPin_iface
);
659 static HRESULT WINAPI
FileAsyncReader_RequestAllocator(IAsyncReader
*iface
,
660 IMemAllocator
*preferred
, ALLOCATOR_PROPERTIES
*props
, IMemAllocator
**ret_allocator
)
662 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
663 IMemAllocator
*allocator
;
667 TRACE("filter %p, preferred %p, props %p, ret_allocator %p.\n", filter
, preferred
, props
, ret_allocator
);
672 *ret_allocator
= NULL
;
675 IMemAllocator_AddRef(allocator
= preferred
);
676 else if (FAILED(hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
,
677 CLSCTX_INPROC
, &IID_IMemAllocator
, (void **)&allocator
)))
680 if (FAILED(hr
= IMemAllocator_SetProperties(allocator
, props
, props
)))
682 IMemAllocator_Release(allocator
);
686 if (filter
->requests
)
688 for (i
= 0; i
< filter
->max_requests
; ++i
)
689 CloseHandle(filter
->requests
[i
].ovl
.hEvent
);
690 free(filter
->requests
);
693 filter
->max_requests
= props
->cBuffers
;
694 TRACE("Maximum request count: %u.\n", filter
->max_requests
);
695 if (!(filter
->requests
= calloc(filter
->max_requests
, sizeof(filter
->requests
[0]))))
697 IMemAllocator_Release(allocator
);
698 return E_OUTOFMEMORY
;
701 for (i
= 0; i
< filter
->max_requests
; ++i
)
702 filter
->requests
[i
].ovl
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
704 *ret_allocator
= allocator
;
708 static HRESULT WINAPI
FileAsyncReader_Request(IAsyncReader
*iface
, IMediaSample
*sample
, DWORD_PTR cookie
)
710 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
711 REFERENCE_TIME start
, end
;
717 TRACE("filter %p, sample %p, cookie %#lx.\n", filter
, sample
, cookie
);
722 if (FAILED(hr
= IMediaSample_GetTime(sample
, &start
, &end
)))
725 if (BYTES_FROM_MEDIATIME(start
) >= filter
->file_size
.QuadPart
)
726 return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF
);
728 if (FAILED(hr
= IMediaSample_GetPointer(sample
, &data
)))
731 EnterCriticalSection(&filter
->sample_cs
);
732 if (filter
->flushing
)
734 LeaveCriticalSection(&filter
->sample_cs
);
735 return VFW_E_WRONG_STATE
;
738 for (i
= 0; i
< filter
->max_requests
; ++i
)
740 if (!filter
->requests
[i
].sample
)
743 assert(i
< filter
->max_requests
);
744 req
= &filter
->requests
[i
];
746 req
->ovl
.u
.s
.Offset
= BYTES_FROM_MEDIATIME(start
);
747 req
->ovl
.u
.s
.OffsetHigh
= BYTES_FROM_MEDIATIME(start
) >> 32;
748 /* No reference is taken. */
750 if (ReadFile(filter
->file
, data
, BYTES_FROM_MEDIATIME(end
- start
), NULL
, &req
->ovl
)
751 || GetLastError() == ERROR_IO_PENDING
)
754 req
->sample
= sample
;
755 req
->cookie
= cookie
;
758 hr
= HRESULT_FROM_WIN32(GetLastError());
760 LeaveCriticalSection(&filter
->sample_cs
);
764 static HRESULT WINAPI
FileAsyncReader_WaitForNext(IAsyncReader
*iface
,
765 DWORD timeout
, IMediaSample
**sample
, DWORD_PTR
*cookie
)
767 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
770 TRACE("filter %p, timeout %u, sample %p, cookie %p.\n", filter
, timeout
, sample
, cookie
);
775 EnterCriticalSection(&filter
->sample_cs
);
779 if (filter
->flushing
)
781 LeaveCriticalSection(&filter
->sample_cs
);
782 return VFW_E_WRONG_STATE
;
785 for (i
= 0; i
< filter
->max_requests
; ++i
)
787 struct request
*req
= &filter
->requests
[i
];
790 if (req
->sample
&& GetOverlappedResult(filter
->file
, &req
->ovl
, &size
, FALSE
))
792 REFERENCE_TIME start
, end
;
794 IMediaSample_SetActualDataLength(req
->sample
, size
);
795 start
= MEDIATIME_FROM_BYTES(((ULONGLONG
)req
->ovl
.u
.s
.OffsetHigh
<< 32) + req
->ovl
.u
.s
.Offset
);
796 end
= start
+ MEDIATIME_FROM_BYTES(size
);
797 IMediaSample_SetTime(req
->sample
, &start
, &end
);
799 *sample
= req
->sample
;
800 *cookie
= req
->cookie
;
803 LeaveCriticalSection(&filter
->sample_cs
);
804 TRACE("Returning sample %u.\n", i
);
808 } while (SleepConditionVariableCS(&filter
->sample_cv
, &filter
->sample_cs
, timeout
));
810 LeaveCriticalSection(&filter
->sample_cs
);
811 return VFW_E_TIMEOUT
;
814 static BOOL
sync_read(HANDLE file
, LONGLONG offset
, LONG length
, BYTE
*buffer
, DWORD
*read_len
)
816 OVERLAPPED ovl
= {0};
819 ovl
.hEvent
= (HANDLE
)((ULONG_PTR
)CreateEventW(NULL
, TRUE
, FALSE
, NULL
) | 1);
820 ovl
.u
.s
.Offset
= (DWORD
)offset
;
821 ovl
.u
.s
.OffsetHigh
= offset
>> 32;
825 ret
= ReadFile(file
, buffer
, length
, NULL
, &ovl
);
826 if (ret
|| GetLastError() == ERROR_IO_PENDING
)
827 ret
= GetOverlappedResult(file
, &ovl
, read_len
, TRUE
);
829 TRACE("Returning %u bytes.\n", *read_len
);
831 CloseHandle(ovl
.hEvent
);
835 static HRESULT WINAPI
FileAsyncReader_SyncReadAligned(IAsyncReader
*iface
, IMediaSample
*sample
)
837 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
838 REFERENCE_TIME start_time
, end_time
;
845 TRACE("filter %p, sample %p.\n", filter
, sample
);
847 hr
= IMediaSample_GetTime(sample
, &start_time
, &end_time
);
850 hr
= IMediaSample_GetPointer(sample
, &buffer
);
854 length
= BYTES_FROM_MEDIATIME(end_time
- start_time
);
855 ret
= sync_read(filter
->file
, BYTES_FROM_MEDIATIME(start_time
), length
, buffer
, &read_len
);
857 hr
= (read_len
== length
) ? S_OK
: S_FALSE
;
858 else if (GetLastError() == ERROR_HANDLE_EOF
)
861 hr
= HRESULT_FROM_WIN32(GetLastError());
865 IMediaSample_SetActualDataLength(sample
, read_len
);
870 static HRESULT WINAPI
FileAsyncReader_SyncRead(IAsyncReader
*iface
,
871 LONGLONG offset
, LONG length
, BYTE
*buffer
)
873 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
878 TRACE("filter %p, offset %s, length %d, buffer %p.\n",
879 filter
, wine_dbgstr_longlong(offset
), length
, buffer
);
881 ret
= sync_read(filter
->file
, offset
, length
, buffer
, &read_len
);
883 hr
= (read_len
== length
) ? S_OK
: S_FALSE
;
884 else if (GetLastError() == ERROR_HANDLE_EOF
)
887 hr
= HRESULT_FROM_WIN32(GetLastError());
892 static HRESULT WINAPI
FileAsyncReader_Length(IAsyncReader
*iface
, LONGLONG
*total
, LONGLONG
*available
)
894 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
896 TRACE("iface %p, total %p, available %p.\n", iface
, total
, available
);
898 *available
= *total
= filter
->file_size
.QuadPart
;
903 static HRESULT WINAPI
FileAsyncReader_BeginFlush(IAsyncReader
* iface
)
905 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
908 TRACE("iface %p.\n", iface
);
910 EnterCriticalSection(&filter
->sample_cs
);
912 filter
->flushing
= TRUE
;
913 for (i
= 0; i
< filter
->max_requests
; ++i
)
914 filter
->requests
[i
].sample
= NULL
;
915 CancelIoEx(filter
->file
, NULL
);
916 WakeAllConditionVariable(&filter
->sample_cv
);
918 LeaveCriticalSection(&filter
->sample_cs
);
923 static HRESULT WINAPI
FileAsyncReader_EndFlush(IAsyncReader
* iface
)
925 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
927 TRACE("iface %p.\n", iface
);
929 EnterCriticalSection(&filter
->sample_cs
);
931 filter
->flushing
= FALSE
;
933 LeaveCriticalSection(&filter
->sample_cs
);
938 static const IAsyncReaderVtbl FileAsyncReader_Vtbl
=
940 FileAsyncReader_QueryInterface
,
941 FileAsyncReader_AddRef
,
942 FileAsyncReader_Release
,
943 FileAsyncReader_RequestAllocator
,
944 FileAsyncReader_Request
,
945 FileAsyncReader_WaitForNext
,
946 FileAsyncReader_SyncReadAligned
,
947 FileAsyncReader_SyncRead
,
948 FileAsyncReader_Length
,
949 FileAsyncReader_BeginFlush
,
950 FileAsyncReader_EndFlush
,