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
| FILE_SHARE_DELETE
, NULL
,
218 OPEN_EXISTING
, 0, NULL
)) == INVALID_HANDLE_VALUE
)
220 WARN("Failed to open file %s, error %lu.\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
);
356 static HRESULT
async_reader_query_interface(struct strmbase_filter
*iface
, REFIID iid
, void **out
)
358 struct async_reader
*filter
= impl_from_strmbase_filter(iface
);
360 if (IsEqualGUID(iid
, &IID_IFileSourceFilter
))
362 *out
= &filter
->IFileSourceFilter_iface
;
363 IUnknown_AddRef((IUnknown
*)*out
);
367 return E_NOINTERFACE
;
370 static const struct strmbase_filter_ops filter_ops
=
372 .filter_get_pin
= async_reader_get_pin
,
373 .filter_destroy
= async_reader_destroy
,
374 .filter_query_interface
= async_reader_query_interface
,
377 static DWORD CALLBACK
io_thread(void *arg
)
379 struct async_reader
*filter
= arg
;
388 ret
= GetQueuedCompletionStatus(filter
->port
, &size
, &key
, &ovl
, INFINITE
);
393 EnterCriticalSection(&filter
->sample_cs
);
395 req
= CONTAINING_RECORD(ovl
, struct request
, ovl
);
396 TRACE("Got sample %Iu.\n", req
- filter
->requests
);
397 assert(req
>= filter
->requests
&& req
< filter
->requests
+ filter
->max_requests
);
400 WakeConditionVariable(&filter
->sample_cv
);
403 ERR("GetQueuedCompletionStatus() returned failure, error %lu.\n", GetLastError());
407 LeaveCriticalSection(&filter
->sample_cs
);
413 HRESULT
async_reader_create(IUnknown
*outer
, IUnknown
**out
)
415 struct async_reader
*object
;
417 if (!(object
= calloc(1, sizeof(*object
))))
418 return E_OUTOFMEMORY
;
420 strmbase_filter_init(&object
->filter
, outer
, &CLSID_AsyncReader
, &filter_ops
);
422 object
->IFileSourceFilter_iface
.lpVtbl
= &FileSource_Vtbl
;
423 object
->IAsyncReader_iface
.lpVtbl
= &FileAsyncReader_Vtbl
;
425 InitializeCriticalSection(&object
->sample_cs
);
426 object
->sample_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": FileAsyncReader.sample_cs");
427 InitializeConditionVariable(&object
->sample_cv
);
428 object
->port
= CreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 0);
429 object
->io_thread
= CreateThread(NULL
, 0, io_thread
, object
, 0, NULL
);
431 TRACE("Created file source %p.\n", object
);
432 *out
= &object
->filter
.IUnknown_inner
;
436 static HRESULT WINAPI
FileSource_QueryInterface(IFileSourceFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
438 struct async_reader
*filter
= impl_from_IFileSourceFilter(iface
);
439 return IBaseFilter_QueryInterface(&filter
->filter
.IBaseFilter_iface
, riid
, ppv
);
442 static ULONG WINAPI
FileSource_AddRef(IFileSourceFilter
* iface
)
444 struct async_reader
*filter
= impl_from_IFileSourceFilter(iface
);
445 return IBaseFilter_AddRef(&filter
->filter
.IBaseFilter_iface
);
448 static ULONG WINAPI
FileSource_Release(IFileSourceFilter
* iface
)
450 struct async_reader
*filter
= impl_from_IFileSourceFilter(iface
);
451 return IBaseFilter_Release(&filter
->filter
.IBaseFilter_iface
);
454 static HRESULT WINAPI
FileSource_Load(IFileSourceFilter
* iface
, LPCOLESTR pszFileName
, const AM_MEDIA_TYPE
* pmt
)
456 struct async_reader
*This
= impl_from_IFileSourceFilter(iface
);
459 TRACE("%p->(%s, %p)\n", This
, debugstr_w(pszFileName
), pmt
);
460 strmbase_dump_media_type(pmt
);
466 /* FIXME: check the sharing values that native uses */
467 hFile
= CreateFileW(pszFileName
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_DELETE
, NULL
, OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, NULL
);
469 if (hFile
== INVALID_HANDLE_VALUE
)
471 return HRESULT_FROM_WIN32(GetLastError());
474 if (!GetFileSizeEx(hFile
, &This
->file_size
))
476 WARN("Could not get file size.\n");
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 struct async_reader
*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 struct async_reader
*impl_from_strmbase_pin(struct strmbase_pin
*iface
)
553 return CONTAINING_RECORD(iface
, struct async_reader
, source
.pin
);
556 static inline struct async_reader
*impl_from_IAsyncReader(IAsyncReader
*iface
)
558 return CONTAINING_RECORD(iface
, struct async_reader
, IAsyncReader_iface
);
561 static HRESULT
source_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
563 struct async_reader
*filter
= impl_from_strmbase_pin(iface
);
565 if (IsEqualGUID(&mt
->majortype
, &filter
->mt
.majortype
)
566 && (!IsEqualGUID(&mt
->subtype
, &GUID_NULL
)
567 || IsEqualGUID(&filter
->mt
.subtype
, &GUID_NULL
)))
573 static HRESULT
source_get_media_type(struct strmbase_pin
*iface
, unsigned int index
, AM_MEDIA_TYPE
*mt
)
575 struct async_reader
*filter
= impl_from_strmbase_pin(iface
);
578 return VFW_S_NO_MORE_ITEMS
;
581 CopyMediaType(mt
, &filter
->mt
);
583 CopyMediaType(mt
, &default_mt
);
587 static HRESULT
source_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
589 struct async_reader
*filter
= impl_from_strmbase_pin(iface
);
591 if (IsEqualGUID(iid
, &IID_IAsyncReader
))
592 *out
= &filter
->IAsyncReader_iface
;
594 return E_NOINTERFACE
;
596 IUnknown_AddRef((IUnknown
*)*out
);
600 /* Function called as a helper to IPin_Connect */
601 /* specific AM_MEDIA_TYPE - it cannot be NULL */
602 /* this differs from standard OutputPin_AttemptConnection only in that it
603 * doesn't need the IMemInputPin interface on the receiving pin */
604 static HRESULT WINAPI
FileAsyncReaderPin_AttemptConnection(struct strmbase_source
*This
,
605 IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
609 TRACE("%p->(%p, %p)\n", This
, pReceivePin
, pmt
);
611 if (This
->pin
.ops
->pin_query_accept(&This
->pin
, pmt
) != S_OK
)
612 return VFW_E_TYPE_NOT_ACCEPTED
;
614 This
->pin
.peer
= pReceivePin
;
615 IPin_AddRef(pReceivePin
);
616 CopyMediaType(&This
->pin
.mt
, pmt
);
618 hr
= IPin_ReceiveConnection(pReceivePin
, &This
->pin
.IPin_iface
, pmt
);
622 IPin_Release(This
->pin
.peer
);
623 This
->pin
.peer
= NULL
;
624 FreeMediaType(&This
->pin
.mt
);
630 static const struct strmbase_source_ops source_ops
=
632 .base
.pin_query_accept
= source_query_accept
,
633 .base
.pin_get_media_type
= source_get_media_type
,
634 .base
.pin_query_interface
= source_query_interface
,
635 .pfnAttemptConnection
= FileAsyncReaderPin_AttemptConnection
,
638 static HRESULT WINAPI
FileAsyncReader_QueryInterface(IAsyncReader
*iface
, REFIID iid
, void **out
)
640 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
641 return IPin_QueryInterface(&filter
->source
.pin
.IPin_iface
, iid
, out
);
644 static ULONG WINAPI
FileAsyncReader_AddRef(IAsyncReader
* iface
)
646 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
647 return IPin_AddRef(&filter
->source
.pin
.IPin_iface
);
650 static ULONG WINAPI
FileAsyncReader_Release(IAsyncReader
* iface
)
652 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
653 return IPin_Release(&filter
->source
.pin
.IPin_iface
);
656 static HRESULT WINAPI
FileAsyncReader_RequestAllocator(IAsyncReader
*iface
,
657 IMemAllocator
*preferred
, ALLOCATOR_PROPERTIES
*props
, IMemAllocator
**ret_allocator
)
659 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
660 IMemAllocator
*allocator
;
664 TRACE("filter %p, preferred %p, props %p, ret_allocator %p.\n", filter
, preferred
, props
, ret_allocator
);
669 *ret_allocator
= NULL
;
672 IMemAllocator_AddRef(allocator
= preferred
);
673 else if (FAILED(hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
,
674 CLSCTX_INPROC
, &IID_IMemAllocator
, (void **)&allocator
)))
677 if (FAILED(hr
= IMemAllocator_SetProperties(allocator
, props
, props
)))
679 IMemAllocator_Release(allocator
);
683 if (filter
->requests
)
685 for (i
= 0; i
< filter
->max_requests
; ++i
)
686 CloseHandle(filter
->requests
[i
].ovl
.hEvent
);
687 free(filter
->requests
);
690 filter
->max_requests
= props
->cBuffers
;
691 TRACE("Maximum request count: %u.\n", filter
->max_requests
);
692 if (!(filter
->requests
= calloc(filter
->max_requests
, sizeof(filter
->requests
[0]))))
694 IMemAllocator_Release(allocator
);
695 return E_OUTOFMEMORY
;
698 for (i
= 0; i
< filter
->max_requests
; ++i
)
699 filter
->requests
[i
].ovl
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
701 *ret_allocator
= allocator
;
705 static HRESULT WINAPI
FileAsyncReader_Request(IAsyncReader
*iface
, IMediaSample
*sample
, DWORD_PTR cookie
)
707 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
708 REFERENCE_TIME start
, end
;
714 TRACE("filter %p, sample %p, cookie %#Ix.\n", filter
, sample
, cookie
);
719 if (FAILED(hr
= IMediaSample_GetTime(sample
, &start
, &end
)))
722 if (BYTES_FROM_MEDIATIME(start
) >= filter
->file_size
.QuadPart
)
723 return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF
);
725 if (FAILED(hr
= IMediaSample_GetPointer(sample
, &data
)))
728 EnterCriticalSection(&filter
->sample_cs
);
729 if (filter
->flushing
)
731 LeaveCriticalSection(&filter
->sample_cs
);
732 return VFW_E_WRONG_STATE
;
735 for (i
= 0; i
< filter
->max_requests
; ++i
)
737 if (!filter
->requests
[i
].sample
)
740 assert(i
< filter
->max_requests
);
741 req
= &filter
->requests
[i
];
743 req
->ovl
.u
.s
.Offset
= BYTES_FROM_MEDIATIME(start
);
744 req
->ovl
.u
.s
.OffsetHigh
= BYTES_FROM_MEDIATIME(start
) >> 32;
745 /* No reference is taken. */
747 if (ReadFile(filter
->file
, data
, BYTES_FROM_MEDIATIME(end
- start
), NULL
, &req
->ovl
)
748 || GetLastError() == ERROR_IO_PENDING
)
751 req
->sample
= sample
;
752 req
->cookie
= cookie
;
755 hr
= HRESULT_FROM_WIN32(GetLastError());
757 LeaveCriticalSection(&filter
->sample_cs
);
761 static HRESULT WINAPI
FileAsyncReader_WaitForNext(IAsyncReader
*iface
,
762 DWORD timeout
, IMediaSample
**sample
, DWORD_PTR
*cookie
)
764 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
767 TRACE("filter %p, timeout %lu, sample %p, cookie %p.\n", filter
, timeout
, sample
, cookie
);
772 EnterCriticalSection(&filter
->sample_cs
);
776 if (filter
->flushing
)
778 LeaveCriticalSection(&filter
->sample_cs
);
779 return VFW_E_WRONG_STATE
;
782 for (i
= 0; i
< filter
->max_requests
; ++i
)
784 struct request
*req
= &filter
->requests
[i
];
787 if (req
->sample
&& GetOverlappedResult(filter
->file
, &req
->ovl
, &size
, FALSE
))
789 REFERENCE_TIME start
, end
;
791 IMediaSample_SetActualDataLength(req
->sample
, size
);
792 start
= MEDIATIME_FROM_BYTES(((ULONGLONG
)req
->ovl
.u
.s
.OffsetHigh
<< 32) + req
->ovl
.u
.s
.Offset
);
793 end
= start
+ MEDIATIME_FROM_BYTES(size
);
794 IMediaSample_SetTime(req
->sample
, &start
, &end
);
796 *sample
= req
->sample
;
797 *cookie
= req
->cookie
;
800 LeaveCriticalSection(&filter
->sample_cs
);
801 TRACE("Returning sample %u.\n", i
);
805 } while (SleepConditionVariableCS(&filter
->sample_cv
, &filter
->sample_cs
, timeout
));
807 LeaveCriticalSection(&filter
->sample_cs
);
808 return VFW_E_TIMEOUT
;
811 static BOOL
sync_read(HANDLE file
, LONGLONG offset
, LONG length
, BYTE
*buffer
, DWORD
*read_len
)
813 OVERLAPPED ovl
= {0};
816 ovl
.hEvent
= (HANDLE
)((ULONG_PTR
)CreateEventW(NULL
, TRUE
, FALSE
, NULL
) | 1);
817 ovl
.u
.s
.Offset
= (DWORD
)offset
;
818 ovl
.u
.s
.OffsetHigh
= offset
>> 32;
822 ret
= ReadFile(file
, buffer
, length
, NULL
, &ovl
);
823 if (ret
|| GetLastError() == ERROR_IO_PENDING
)
824 ret
= GetOverlappedResult(file
, &ovl
, read_len
, TRUE
);
826 TRACE("Returning %lu bytes.\n", *read_len
);
828 CloseHandle(ovl
.hEvent
);
832 static HRESULT WINAPI
FileAsyncReader_SyncReadAligned(IAsyncReader
*iface
, IMediaSample
*sample
)
834 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
835 REFERENCE_TIME start_time
, end_time
;
842 TRACE("filter %p, sample %p.\n", filter
, sample
);
844 hr
= IMediaSample_GetTime(sample
, &start_time
, &end_time
);
847 hr
= IMediaSample_GetPointer(sample
, &buffer
);
851 length
= BYTES_FROM_MEDIATIME(end_time
- start_time
);
852 ret
= sync_read(filter
->file
, BYTES_FROM_MEDIATIME(start_time
), length
, buffer
, &read_len
);
854 hr
= (read_len
== length
) ? S_OK
: S_FALSE
;
855 else if (GetLastError() == ERROR_HANDLE_EOF
)
858 hr
= HRESULT_FROM_WIN32(GetLastError());
862 IMediaSample_SetActualDataLength(sample
, read_len
);
867 static HRESULT WINAPI
FileAsyncReader_SyncRead(IAsyncReader
*iface
,
868 LONGLONG offset
, LONG length
, BYTE
*buffer
)
870 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
875 TRACE("filter %p, offset %s, length %ld, buffer %p.\n",
876 filter
, wine_dbgstr_longlong(offset
), length
, buffer
);
878 ret
= sync_read(filter
->file
, offset
, length
, buffer
, &read_len
);
880 hr
= (read_len
== length
) ? S_OK
: S_FALSE
;
881 else if (GetLastError() == ERROR_HANDLE_EOF
)
884 hr
= HRESULT_FROM_WIN32(GetLastError());
889 static HRESULT WINAPI
FileAsyncReader_Length(IAsyncReader
*iface
, LONGLONG
*total
, LONGLONG
*available
)
891 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
893 TRACE("iface %p, total %p, available %p.\n", iface
, total
, available
);
895 *available
= *total
= filter
->file_size
.QuadPart
;
900 static HRESULT WINAPI
FileAsyncReader_BeginFlush(IAsyncReader
* iface
)
902 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
905 TRACE("iface %p.\n", iface
);
907 EnterCriticalSection(&filter
->sample_cs
);
909 filter
->flushing
= TRUE
;
910 for (i
= 0; i
< filter
->max_requests
; ++i
)
911 filter
->requests
[i
].sample
= NULL
;
912 CancelIoEx(filter
->file
, NULL
);
913 WakeAllConditionVariable(&filter
->sample_cv
);
915 LeaveCriticalSection(&filter
->sample_cs
);
920 static HRESULT WINAPI
FileAsyncReader_EndFlush(IAsyncReader
* iface
)
922 struct async_reader
*filter
= impl_from_IAsyncReader(iface
);
924 TRACE("iface %p.\n", iface
);
926 EnterCriticalSection(&filter
->sample_cs
);
928 filter
->flushing
= FALSE
;
930 LeaveCriticalSection(&filter
->sample_cs
);
935 static const IAsyncReaderVtbl FileAsyncReader_Vtbl
=
937 FileAsyncReader_QueryInterface
,
938 FileAsyncReader_AddRef
,
939 FileAsyncReader_Release
,
940 FileAsyncReader_RequestAllocator
,
941 FileAsyncReader_Request
,
942 FileAsyncReader_WaitForNext
,
943 FileAsyncReader_SyncReadAligned
,
944 FileAsyncReader_SyncRead
,
945 FileAsyncReader_Length
,
946 FileAsyncReader_BeginFlush
,
947 FileAsyncReader_EndFlush
,