mshtml: Implement MediaQueryList's matches prop.
[wine.git] / dlls / quartz / filesource.c
blob6ffae606df401ce8860c3f0aabdeb38fd7277d42
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 "uuids.h"
28 #include "vfwmsgs.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "shlwapi.h"
32 #include <assert.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}},
40 TRUE,
41 FALSE,
43 {0,0,0,{0,0,0,0,0,0,0,0}},
44 NULL,
46 NULL
49 struct request
51 IMediaSample *sample;
52 DWORD_PTR cookie;
53 OVERLAPPED ovl;
56 struct async_reader
58 struct strmbase_filter filter;
59 IFileSourceFilter IFileSourceFilter_iface;
61 struct strmbase_source source;
62 IAsyncReader IAsyncReader_iface;
64 LPOLESTR pszFileName;
65 AM_MEDIA_TYPE mt;
66 HANDLE file, port, io_thread;
67 LARGE_INTEGER file_size;
68 CRITICAL_SECTION sample_cs;
69 BOOL flushing;
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;
95 return -1;
98 static BOOL process_pattern_string(const WCHAR *pattern, HANDLE file)
100 ULONG size, offset, i, ret_size;
101 BYTE *mask, *expect, *actual;
102 int d;
103 BOOL ret = TRUE;
105 /* format: "offset, size, mask, value" */
107 offset = wcstol(pattern, NULL, 10);
109 if (!(pattern = wcschr(pattern, ',')))
110 return FALSE;
111 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, ',')))
120 heap_free(mask);
121 heap_free(expect);
122 return FALSE;
124 pattern++;
125 while (byte_from_hex_char(*pattern) == -1 && (*pattern != ','))
126 pattern++;
128 for (i = 0; (d = byte_from_hex_char(*pattern)) != -1 && (i/2 < size); pattern++, i++)
130 if (i % 2)
131 mask[i / 2] |= d;
132 else
133 mask[i / 2] = d << 4;
136 if (!(pattern = wcschr(pattern, ',')))
138 heap_free(mask);
139 heap_free(expect);
140 return FALSE;
142 pattern++;
143 while (byte_from_hex_char(*pattern) == -1 && (*pattern != ','))
144 pattern++;
146 for (i = 0; (d = byte_from_hex_char(*pattern)) != -1 && (i/2 < size); pattern++, i++)
148 if (i % 2)
149 expect[i / 2] |= d;
150 else
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)
158 heap_free(actual);
159 heap_free(expect);
160 heap_free(mask);
161 return FALSE;
164 for (i = 0; i < size; ++i)
166 if ((actual[i] & mask[i]) != expect[i])
168 ret = FALSE;
169 break;
173 heap_free(actual);
174 heap_free(expect);
175 heap_free(mask);
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);
181 return ret;
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;
188 const WCHAR *ext;
189 HKEY parent_key;
190 HANDLE file;
192 if ((ext = wcsrchr(filename, '.')))
194 WCHAR guidstr[39];
195 HKEY key;
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);
212 RegCloseKey(key);
213 return FALSE;
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 %lu.\n", debugstr_w(filename), GetLastError());
221 return FALSE;
224 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Media Type", 0, KEY_READ, &parent_key))
226 CloseHandle(file);
227 return FALSE;
230 for (majortype_idx = 0; ; ++majortype_idx)
232 WCHAR majortype_str[39];
233 HKEY majortype_key;
234 DWORD subtype_idx;
236 size = ARRAY_SIZE(majortype_str);
237 if (RegEnumKeyExW(parent_key, majortype_idx, majortype_str, &size, NULL, NULL, NULL, NULL))
238 break;
240 if (!wcscmp(majortype_str, L"Extensions"))
241 continue;
243 if (RegOpenKeyExW(parent_key, majortype_str, 0, KEY_READ, &majortype_key))
244 continue;
246 for (subtype_idx = 0; ; ++subtype_idx)
248 WCHAR subtype_str[39], *pattern;
249 DWORD value_idx, max_size;
250 HKEY subtype_key;
252 size = ARRAY_SIZE(subtype_str);
253 if (RegEnumKeyExW(majortype_key, subtype_idx, subtype_str, &size, NULL, NULL, NULL, NULL))
254 break;
256 if (RegOpenKeyExW(majortype_key, subtype_str, 0, KEY_READ, &subtype_key))
257 continue;
259 if (RegQueryInfoKeyW(subtype_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_size, NULL, NULL))
260 continue;
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);
270 size = max_size;
271 if (RegEnumValueW(subtype_key, value_idx, value_name, &value_len,
272 NULL, NULL, (BYTE *)pattern, &max_size))
273 break;
275 if (!wcscmp(value_name, L"Source Filter"))
276 continue;
278 if (!process_pattern_string(pattern, file))
279 continue;
281 if (majortype)
282 CLSIDFromString(majortype_str, majortype);
283 if (subtype)
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);
290 heap_free(pattern);
291 RegCloseKey(subtype_key);
292 RegCloseKey(majortype_key);
293 RegCloseKey(parent_key);
294 CloseHandle(file);
295 return TRUE;
298 heap_free(pattern);
299 RegCloseKey(subtype_key);
302 RegCloseKey(majortype_key);
305 RegCloseKey(parent_key);
306 CloseHandle(file);
307 return FALSE;
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;
316 return NULL;
319 static void async_reader_destroy(struct strmbase_filter *iface)
321 struct async_reader *filter = impl_from_strmbase_filter(iface);
323 if (filter->pszFileName)
325 unsigned int i;
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);
353 free(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);
364 return S_OK;
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;
380 struct request *req;
381 OVERLAPPED *ovl;
382 ULONG_PTR key;
383 DWORD size;
384 BOOL ret;
386 for (;;)
388 ret = GetQueuedCompletionStatus(filter->port, &size, &key, &ovl, INFINITE);
390 if (ret && key)
391 break;
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);
399 if (ret)
400 WakeConditionVariable(&filter->sample_cv);
401 else
403 ERR("GetQueuedCompletionStatus() returned failure, error %lu.\n", GetLastError());
404 req->sample = NULL;
407 LeaveCriticalSection(&filter->sample_cs);
410 return 0;
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;
433 return S_OK;
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);
457 HANDLE hFile;
459 TRACE("%p->(%s, %p)\n", This, debugstr_w(pszFileName), pmt);
460 strmbase_dump_media_type(pmt);
462 if (!pszFileName)
463 return E_POINTER;
465 /* open file */
466 /* FIXME: check the sharing values that native uses */
467 hFile = CreateFileW(pszFileName, GENERIC_READ, FILE_SHARE_READ, 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");
477 CloseHandle(hFile);
478 return HRESULT_FROM_WIN32(GetLastError());
481 if (This->pszFileName)
483 free(This->pszFileName);
484 FreeMediaType(&This->mt);
487 if (!(This->pszFileName = wcsdup(pszFileName)))
489 CloseHandle(hFile);
490 return E_OUTOFMEMORY;
493 strmbase_source_init(&This->source, &This->filter, L"Output", &source_ops);
494 BaseFilterImpl_IncrementPinVersion(&This->filter);
496 This->file = hFile;
497 This->flushing = FALSE;
498 This->requests = NULL;
500 if (!pmt)
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));
509 else
510 CopyMediaType(&This->mt, pmt);
512 return S_OK;
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);
521 if (!ppszFileName)
522 return E_POINTER;
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);
529 if (mt)
530 CopyMediaType(mt, &This->mt);
532 else
534 *ppszFileName = NULL;
535 if (mt)
536 memset(mt, 0, sizeof(AM_MEDIA_TYPE));
539 return S_OK;
542 static const IFileSourceFilterVtbl FileSource_Vtbl =
544 FileSource_QueryInterface,
545 FileSource_AddRef,
546 FileSource_Release,
547 FileSource_Load,
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)))
568 return S_OK;
570 return S_FALSE;
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);
577 if (index > 1)
578 return VFW_S_NO_MORE_ITEMS;
580 if (index == 0)
581 CopyMediaType(mt, &filter->mt);
582 else if (index == 1)
583 CopyMediaType(mt, &default_mt);
584 return S_OK;
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;
593 else
594 return E_NOINTERFACE;
596 IUnknown_AddRef((IUnknown *)*out);
597 return S_OK;
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)
607 HRESULT hr;
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);
620 if (FAILED(hr))
622 IPin_Release(This->pin.peer);
623 This->pin.peer = NULL;
624 FreeMediaType(&This->pin.mt);
627 return hr;
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;
661 unsigned int i;
662 HRESULT hr;
664 TRACE("filter %p, preferred %p, props %p, ret_allocator %p.\n", filter, preferred, props, ret_allocator);
666 if (!props->cbAlign)
667 props->cbAlign = 1;
669 *ret_allocator = NULL;
671 if (preferred)
672 IMemAllocator_AddRef(allocator = preferred);
673 else if (FAILED(hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,
674 CLSCTX_INPROC, &IID_IMemAllocator, (void **)&allocator)))
675 return hr;
677 if (FAILED(hr = IMemAllocator_SetProperties(allocator, props, props)))
679 IMemAllocator_Release(allocator);
680 return hr;
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;
702 return S_OK;
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;
709 struct request *req;
710 unsigned int i;
711 HRESULT hr;
712 BYTE *data;
714 TRACE("filter %p, sample %p, cookie %#Ix.\n", filter, sample, cookie);
716 if (!sample)
717 return E_POINTER;
719 if (FAILED(hr = IMediaSample_GetTime(sample, &start, &end)))
720 return hr;
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)))
726 return hr;
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)
738 break;
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)
750 hr = S_OK;
751 req->sample = sample;
752 req->cookie = cookie;
754 else
755 hr = HRESULT_FROM_WIN32(GetLastError());
757 LeaveCriticalSection(&filter->sample_cs);
758 return hr;
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);
765 unsigned int i;
767 TRACE("filter %p, timeout %lu, sample %p, cookie %p.\n", filter, timeout, sample, cookie);
769 *sample = NULL;
770 *cookie = 0;
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];
785 DWORD size;
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;
798 req->sample = NULL;
800 LeaveCriticalSection(&filter->sample_cs);
801 TRACE("Returning sample %u.\n", i);
802 return S_OK;
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};
814 BOOL ret;
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;
820 *read_len = 0;
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);
829 return ret;
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;
836 DWORD read_len;
837 BYTE *buffer;
838 LONG length;
839 HRESULT hr;
840 BOOL ret;
842 TRACE("filter %p, sample %p.\n", filter, sample);
844 hr = IMediaSample_GetTime(sample, &start_time, &end_time);
846 if (SUCCEEDED(hr))
847 hr = IMediaSample_GetPointer(sample, &buffer);
849 if (SUCCEEDED(hr))
851 length = BYTES_FROM_MEDIATIME(end_time - start_time);
852 ret = sync_read(filter->file, BYTES_FROM_MEDIATIME(start_time), length, buffer, &read_len);
853 if (ret)
854 hr = (read_len == length) ? S_OK : S_FALSE;
855 else if (GetLastError() == ERROR_HANDLE_EOF)
856 hr = S_OK;
857 else
858 hr = HRESULT_FROM_WIN32(GetLastError());
861 if (SUCCEEDED(hr))
862 IMediaSample_SetActualDataLength(sample, read_len);
864 return hr;
867 static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader *iface,
868 LONGLONG offset, LONG length, BYTE *buffer)
870 struct async_reader *filter = impl_from_IAsyncReader(iface);
871 DWORD read_len;
872 HRESULT hr;
873 BOOL ret;
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);
879 if (ret)
880 hr = (read_len == length) ? S_OK : S_FALSE;
881 else if (GetLastError() == ERROR_HANDLE_EOF)
882 hr = S_FALSE;
883 else
884 hr = HRESULT_FROM_WIN32(GetLastError());
886 return hr;
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;
897 return S_OK;
900 static HRESULT WINAPI FileAsyncReader_BeginFlush(IAsyncReader * iface)
902 struct async_reader *filter = impl_from_IAsyncReader(iface);
903 unsigned int i;
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);
917 return S_OK;
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);
932 return S_OK;
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,