po: Update Lithuanian translation.
[wine.git] / dlls / quartz / filesource.c
blobcf5fe45771584373f13eec925e609917a25ce781
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 %u.\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);
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);
366 return S_OK;
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;
382 struct request *req;
383 OVERLAPPED *ovl;
384 ULONG_PTR key;
385 DWORD size;
386 BOOL ret;
388 for (;;)
390 ret = GetQueuedCompletionStatus(filter->port, &size, &key, &ovl, INFINITE);
392 if (ret && key)
393 break;
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);
401 if (ret)
402 WakeConditionVariable(&filter->sample_cv);
403 else
405 ERR("GetQueuedCompletionStatus() returned failure, error %u.\n", GetLastError());
406 req->sample = NULL;
409 LeaveCriticalSection(&filter->sample_cs);
412 return 0;
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;
435 return S_OK;
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);
459 HANDLE hFile;
461 TRACE("%p->(%s, %p)\n", This, debugstr_w(pszFileName), pmt);
462 strmbase_dump_media_type(pmt);
464 if (!pszFileName)
465 return E_POINTER;
467 /* open file */
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");
479 CloseHandle(hFile);
480 return HRESULT_FROM_WIN32(GetLastError());
483 if (This->pszFileName)
485 free(This->pszFileName);
486 FreeMediaType(&This->mt);
489 if (!(This->pszFileName = wcsdup(pszFileName)))
491 CloseHandle(hFile);
492 return E_OUTOFMEMORY;
495 strmbase_source_init(&This->source, &This->filter, L"Output", &source_ops);
496 BaseFilterImpl_IncrementPinVersion(&This->filter);
498 This->file = hFile;
499 This->flushing = FALSE;
500 This->requests = NULL;
502 if (!pmt)
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));
511 else
512 CopyMediaType(&This->mt, pmt);
514 return S_OK;
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);
523 if (!ppszFileName)
524 return E_POINTER;
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);
531 if (mt)
532 CopyMediaType(mt, &This->mt);
534 else
536 *ppszFileName = NULL;
537 if (mt)
538 memset(mt, 0, sizeof(AM_MEDIA_TYPE));
541 return S_OK;
544 static const IFileSourceFilterVtbl FileSource_Vtbl =
546 FileSource_QueryInterface,
547 FileSource_AddRef,
548 FileSource_Release,
549 FileSource_Load,
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)))
570 return S_OK;
572 return S_FALSE;
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);
579 if (index > 1)
580 return VFW_S_NO_MORE_ITEMS;
582 if (index == 0)
583 CopyMediaType(mt, &filter->mt);
584 else if (index == 1)
585 CopyMediaType(mt, &default_mt);
586 return S_OK;
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;
595 else
596 return E_NOINTERFACE;
598 IUnknown_AddRef((IUnknown *)*out);
599 return S_OK;
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)
609 HRESULT hr;
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);
622 if (FAILED(hr))
624 IPin_Release(This->pin.peer);
625 This->pin.peer = NULL;
626 FreeMediaType(&This->pin.mt);
629 TRACE(" -- %x\n", hr);
630 return 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;
664 unsigned int i;
665 HRESULT hr;
667 TRACE("filter %p, preferred %p, props %p, ret_allocator %p.\n", filter, preferred, props, ret_allocator);
669 if (!props->cbAlign)
670 props->cbAlign = 1;
672 *ret_allocator = NULL;
674 if (preferred)
675 IMemAllocator_AddRef(allocator = preferred);
676 else if (FAILED(hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,
677 CLSCTX_INPROC, &IID_IMemAllocator, (void **)&allocator)))
678 return hr;
680 if (FAILED(hr = IMemAllocator_SetProperties(allocator, props, props)))
682 IMemAllocator_Release(allocator);
683 return hr;
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;
705 return S_OK;
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;
712 struct request *req;
713 unsigned int i;
714 HRESULT hr;
715 BYTE *data;
717 TRACE("filter %p, sample %p, cookie %#lx.\n", filter, sample, cookie);
719 if (!sample)
720 return E_POINTER;
722 if (FAILED(hr = IMediaSample_GetTime(sample, &start, &end)))
723 return hr;
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)))
729 return hr;
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)
741 break;
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)
753 hr = S_OK;
754 req->sample = sample;
755 req->cookie = cookie;
757 else
758 hr = HRESULT_FROM_WIN32(GetLastError());
760 LeaveCriticalSection(&filter->sample_cs);
761 return hr;
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);
768 unsigned int i;
770 TRACE("filter %p, timeout %u, sample %p, cookie %p.\n", filter, timeout, sample, cookie);
772 *sample = NULL;
773 *cookie = 0;
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];
788 DWORD size;
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;
801 req->sample = NULL;
803 LeaveCriticalSection(&filter->sample_cs);
804 TRACE("Returning sample %u.\n", i);
805 return S_OK;
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};
817 BOOL ret;
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;
823 *read_len = 0;
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);
832 return ret;
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;
839 DWORD read_len;
840 BYTE *buffer;
841 LONG length;
842 HRESULT hr;
843 BOOL ret;
845 TRACE("filter %p, sample %p.\n", filter, sample);
847 hr = IMediaSample_GetTime(sample, &start_time, &end_time);
849 if (SUCCEEDED(hr))
850 hr = IMediaSample_GetPointer(sample, &buffer);
852 if (SUCCEEDED(hr))
854 length = BYTES_FROM_MEDIATIME(end_time - start_time);
855 ret = sync_read(filter->file, BYTES_FROM_MEDIATIME(start_time), length, buffer, &read_len);
856 if (ret)
857 hr = (read_len == length) ? S_OK : S_FALSE;
858 else if (GetLastError() == ERROR_HANDLE_EOF)
859 hr = S_OK;
860 else
861 hr = HRESULT_FROM_WIN32(GetLastError());
864 if (SUCCEEDED(hr))
865 IMediaSample_SetActualDataLength(sample, read_len);
867 return hr;
870 static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader *iface,
871 LONGLONG offset, LONG length, BYTE *buffer)
873 struct async_reader *filter = impl_from_IAsyncReader(iface);
874 DWORD read_len;
875 HRESULT hr;
876 BOOL ret;
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);
882 if (ret)
883 hr = (read_len == length) ? S_OK : S_FALSE;
884 else if (GetLastError() == ERROR_HANDLE_EOF)
885 hr = S_FALSE;
886 else
887 hr = HRESULT_FROM_WIN32(GetLastError());
889 return hr;
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;
900 return S_OK;
903 static HRESULT WINAPI FileAsyncReader_BeginFlush(IAsyncReader * iface)
905 struct async_reader *filter = impl_from_IAsyncReader(iface);
906 unsigned int i;
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);
920 return S_OK;
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);
935 return S_OK;
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,