d3dx9: Unify calling parse_mesh helper functions.
[wine.git] / dlls / winegstreamer / wm_reader.c
blob882b6df1bbb3434430c60b091e598f828635c00c
1 /*
2 * Copyright 2012 Austin English
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "gst_private.h"
20 #include "initguid.h"
21 #include "wmsdk.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(wmvcore);
25 struct wm_stream
27 struct wm_reader *reader;
28 wg_parser_stream_t wg_stream;
29 struct wg_format format;
30 WMT_STREAM_SELECTION selection;
31 WORD index;
32 bool eos;
33 /* Note that we only pretend to read compressed samples, and instead output
34 * uncompressed samples regardless of whether we are configured to read
35 * compressed samples. Rather, the behaviour of the reader objects differs
36 * in nontrivial ways depending on this field. */
37 bool read_compressed;
39 IWMReaderAllocatorEx *output_allocator;
40 IWMReaderAllocatorEx *stream_allocator;
43 struct wm_reader
45 IUnknown IUnknown_inner;
46 IWMSyncReader2 IWMSyncReader2_iface;
47 IWMHeaderInfo3 IWMHeaderInfo3_iface;
48 IWMLanguageList IWMLanguageList_iface;
49 IWMPacketSize2 IWMPacketSize2_iface;
50 IWMProfile3 IWMProfile3_iface;
51 IWMReaderPlaylistBurn IWMReaderPlaylistBurn_iface;
52 IWMReaderTimecode IWMReaderTimecode_iface;
53 IUnknown *outer;
54 LONG refcount;
56 CRITICAL_SECTION cs;
57 QWORD start_time;
59 IStream *source_stream;
60 HANDLE file;
61 HANDLE read_thread;
62 bool read_thread_shutdown;
63 wg_parser_t wg_parser;
65 struct wm_stream *streams;
66 WORD stream_count;
69 static struct wm_stream *get_stream_by_output_number(struct wm_reader *reader, DWORD output)
71 if (output < reader->stream_count)
72 return &reader->streams[output];
73 WARN("Invalid output number %lu.\n", output);
74 return NULL;
77 struct output_props
79 IWMOutputMediaProps IWMOutputMediaProps_iface;
80 LONG refcount;
82 AM_MEDIA_TYPE mt;
85 static inline struct output_props *impl_from_IWMOutputMediaProps(IWMOutputMediaProps *iface)
87 return CONTAINING_RECORD(iface, struct output_props, IWMOutputMediaProps_iface);
90 static HRESULT WINAPI output_props_QueryInterface(IWMOutputMediaProps *iface, REFIID iid, void **out)
92 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
94 TRACE("props %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
96 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IWMOutputMediaProps))
97 *out = &props->IWMOutputMediaProps_iface;
98 else
100 *out = NULL;
101 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
102 return E_NOINTERFACE;
105 IUnknown_AddRef((IUnknown *)*out);
106 return S_OK;
109 static ULONG WINAPI output_props_AddRef(IWMOutputMediaProps *iface)
111 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
112 ULONG refcount = InterlockedIncrement(&props->refcount);
114 TRACE("%p increasing refcount to %lu.\n", props, refcount);
116 return refcount;
119 static ULONG WINAPI output_props_Release(IWMOutputMediaProps *iface)
121 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
122 ULONG refcount = InterlockedDecrement(&props->refcount);
124 TRACE("%p decreasing refcount to %lu.\n", props, refcount);
126 if (!refcount)
127 free(props);
129 return refcount;
132 static HRESULT WINAPI output_props_GetType(IWMOutputMediaProps *iface, GUID *major_type)
134 const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
136 TRACE("iface %p, major_type %p.\n", iface, major_type);
138 *major_type = props->mt.majortype;
139 return S_OK;
142 static HRESULT WINAPI output_props_GetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt, DWORD *size)
144 const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
145 const DWORD req_size = *size;
147 TRACE("iface %p, mt %p, size %p.\n", iface, mt, size);
149 *size = sizeof(*mt) + props->mt.cbFormat;
150 if (!mt)
151 return S_OK;
152 if (req_size < *size)
153 return ASF_E_BUFFERTOOSMALL;
155 strmbase_dump_media_type(&props->mt);
157 memcpy(mt, &props->mt, sizeof(*mt));
158 memcpy(mt + 1, props->mt.pbFormat, props->mt.cbFormat);
159 mt->pbFormat = (BYTE *)(mt + 1);
160 return S_OK;
163 static HRESULT WINAPI output_props_SetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt)
165 const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
167 TRACE("iface %p, mt %p.\n", iface, mt);
169 if (!mt)
170 return E_POINTER;
172 if (!IsEqualGUID(&props->mt.majortype, &mt->majortype))
173 return E_FAIL;
175 FreeMediaType((AM_MEDIA_TYPE *)&props->mt);
176 return CopyMediaType((AM_MEDIA_TYPE *)&props->mt, (AM_MEDIA_TYPE *)mt);
179 static HRESULT WINAPI output_props_GetStreamGroupName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
181 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
182 return E_NOTIMPL;
185 static HRESULT WINAPI output_props_GetConnectionName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
187 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
188 return E_NOTIMPL;
191 static const struct IWMOutputMediaPropsVtbl output_props_vtbl =
193 output_props_QueryInterface,
194 output_props_AddRef,
195 output_props_Release,
196 output_props_GetType,
197 output_props_GetMediaType,
198 output_props_SetMediaType,
199 output_props_GetStreamGroupName,
200 output_props_GetConnectionName,
203 static struct output_props *unsafe_impl_from_IWMOutputMediaProps(IWMOutputMediaProps *iface)
205 if (!iface)
206 return NULL;
207 assert(iface->lpVtbl == &output_props_vtbl);
208 return impl_from_IWMOutputMediaProps(iface);
211 static IWMOutputMediaProps *output_props_create(const struct wg_format *format)
213 struct output_props *object;
215 if (!(object = calloc(1, sizeof(*object))))
216 return NULL;
217 object->IWMOutputMediaProps_iface.lpVtbl = &output_props_vtbl;
218 object->refcount = 1;
220 if (!amt_from_wg_format(&object->mt, format, true))
222 free(object);
223 return NULL;
226 TRACE("Created output properties %p.\n", object);
227 return &object->IWMOutputMediaProps_iface;
230 struct buffer
232 INSSBuffer INSSBuffer_iface;
233 LONG refcount;
235 DWORD size, capacity;
236 BYTE data[1];
239 static struct buffer *impl_from_INSSBuffer(INSSBuffer *iface)
241 return CONTAINING_RECORD(iface, struct buffer, INSSBuffer_iface);
244 static HRESULT WINAPI buffer_QueryInterface(INSSBuffer *iface, REFIID iid, void **out)
246 struct buffer *buffer = impl_from_INSSBuffer(iface);
248 TRACE("buffer %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
250 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_INSSBuffer))
251 *out = &buffer->INSSBuffer_iface;
252 else
254 *out = NULL;
255 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
256 return E_NOINTERFACE;
259 IUnknown_AddRef((IUnknown *)*out);
260 return S_OK;
263 static ULONG WINAPI buffer_AddRef(INSSBuffer *iface)
265 struct buffer *buffer = impl_from_INSSBuffer(iface);
266 ULONG refcount = InterlockedIncrement(&buffer->refcount);
268 TRACE("%p increasing refcount to %lu.\n", buffer, refcount);
270 return refcount;
273 static ULONG WINAPI buffer_Release(INSSBuffer *iface)
275 struct buffer *buffer = impl_from_INSSBuffer(iface);
276 ULONG refcount = InterlockedDecrement(&buffer->refcount);
278 TRACE("%p decreasing refcount to %lu.\n", buffer, refcount);
280 if (!refcount)
281 free(buffer);
283 return refcount;
286 static HRESULT WINAPI buffer_GetLength(INSSBuffer *iface, DWORD *size)
288 FIXME("iface %p, size %p, stub!\n", iface, size);
289 return E_NOTIMPL;
292 static HRESULT WINAPI buffer_SetLength(INSSBuffer *iface, DWORD size)
294 struct buffer *buffer = impl_from_INSSBuffer(iface);
296 TRACE("iface %p, size %lu.\n", buffer, size);
298 if (size > buffer->capacity)
299 return E_INVALIDARG;
301 buffer->size = size;
302 return S_OK;
305 static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size)
307 struct buffer *buffer = impl_from_INSSBuffer(iface);
309 TRACE("buffer %p, size %p.\n", buffer, size);
311 *size = buffer->capacity;
312 return S_OK;
315 static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data)
317 struct buffer *buffer = impl_from_INSSBuffer(iface);
319 TRACE("buffer %p, data %p.\n", buffer, data);
321 *data = buffer->data;
322 return S_OK;
325 static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size)
327 struct buffer *buffer = impl_from_INSSBuffer(iface);
329 TRACE("buffer %p, data %p, size %p.\n", buffer, data, size);
331 *size = buffer->size;
332 *data = buffer->data;
333 return S_OK;
336 static const INSSBufferVtbl buffer_vtbl =
338 buffer_QueryInterface,
339 buffer_AddRef,
340 buffer_Release,
341 buffer_GetLength,
342 buffer_SetLength,
343 buffer_GetMaxLength,
344 buffer_GetBuffer,
345 buffer_GetBufferAndLength,
348 struct stream_config
350 IWMStreamConfig IWMStreamConfig_iface;
351 IWMMediaProps IWMMediaProps_iface;
352 LONG refcount;
354 const struct wm_stream *stream;
357 static struct stream_config *impl_from_IWMStreamConfig(IWMStreamConfig *iface)
359 return CONTAINING_RECORD(iface, struct stream_config, IWMStreamConfig_iface);
362 static HRESULT WINAPI stream_config_QueryInterface(IWMStreamConfig *iface, REFIID iid, void **out)
364 struct stream_config *config = impl_from_IWMStreamConfig(iface);
366 TRACE("config %p, iid %s, out %p.\n", config, debugstr_guid(iid), out);
368 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IWMStreamConfig))
369 *out = &config->IWMStreamConfig_iface;
370 else if (IsEqualGUID(iid, &IID_IWMMediaProps))
371 *out = &config->IWMMediaProps_iface;
372 else
374 *out = NULL;
375 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
376 return E_NOINTERFACE;
379 IUnknown_AddRef((IUnknown *)*out);
380 return S_OK;
383 static ULONG WINAPI stream_config_AddRef(IWMStreamConfig *iface)
385 struct stream_config *config = impl_from_IWMStreamConfig(iface);
386 ULONG refcount = InterlockedIncrement(&config->refcount);
388 TRACE("%p increasing refcount to %lu.\n", config, refcount);
390 return refcount;
393 static ULONG WINAPI stream_config_Release(IWMStreamConfig *iface)
395 struct stream_config *config = impl_from_IWMStreamConfig(iface);
396 ULONG refcount = InterlockedDecrement(&config->refcount);
398 TRACE("%p decreasing refcount to %lu.\n", config, refcount);
400 if (!refcount)
402 IWMProfile3_Release(&config->stream->reader->IWMProfile3_iface);
403 free(config);
406 return refcount;
409 static HRESULT WINAPI stream_config_GetStreamType(IWMStreamConfig *iface, GUID *type)
411 struct stream_config *config = impl_from_IWMStreamConfig(iface);
412 struct wm_reader *reader = config->stream->reader;
413 AM_MEDIA_TYPE mt;
415 TRACE("config %p, type %p.\n", config, type);
417 EnterCriticalSection(&reader->cs);
419 if (!amt_from_wg_format(&mt, &config->stream->format, true))
421 LeaveCriticalSection(&reader->cs);
422 return E_OUTOFMEMORY;
425 *type = mt.majortype;
426 FreeMediaType(&mt);
428 LeaveCriticalSection(&reader->cs);
430 return S_OK;
433 static HRESULT WINAPI stream_config_GetStreamNumber(IWMStreamConfig *iface, WORD *number)
435 struct stream_config *config = impl_from_IWMStreamConfig(iface);
437 TRACE("config %p, number %p.\n", config, number);
439 *number = config->stream->index + 1;
440 return S_OK;
443 static HRESULT WINAPI stream_config_SetStreamNumber(IWMStreamConfig *iface, WORD number)
445 FIXME("iface %p, number %u, stub!\n", iface, number);
446 return E_NOTIMPL;
449 static HRESULT WINAPI stream_config_GetStreamName(IWMStreamConfig *iface, WCHAR *name, WORD *len)
451 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
452 return E_NOTIMPL;
455 static HRESULT WINAPI stream_config_SetStreamName(IWMStreamConfig *iface, const WCHAR *name)
457 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
458 return E_NOTIMPL;
461 static HRESULT WINAPI stream_config_GetConnectionName(IWMStreamConfig *iface, WCHAR *name, WORD *len)
463 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
464 return E_NOTIMPL;
467 static HRESULT WINAPI stream_config_SetConnectionName(IWMStreamConfig *iface, const WCHAR *name)
469 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
470 return E_NOTIMPL;
473 static HRESULT WINAPI stream_config_GetBitrate(IWMStreamConfig *iface, DWORD *bitrate)
475 FIXME("iface %p, bitrate %p, stub!\n", iface, bitrate);
476 return E_NOTIMPL;
479 static HRESULT WINAPI stream_config_SetBitrate(IWMStreamConfig *iface, DWORD bitrate)
481 FIXME("iface %p, bitrate %lu, stub!\n", iface, bitrate);
482 return E_NOTIMPL;
485 static HRESULT WINAPI stream_config_GetBufferWindow(IWMStreamConfig *iface, DWORD *window)
487 FIXME("iface %p, window %p, stub!\n", iface, window);
488 return E_NOTIMPL;
491 static HRESULT WINAPI stream_config_SetBufferWindow(IWMStreamConfig *iface, DWORD window)
493 FIXME("iface %p, window %lu, stub!\n", iface, window);
494 return E_NOTIMPL;
497 static const IWMStreamConfigVtbl stream_config_vtbl =
499 stream_config_QueryInterface,
500 stream_config_AddRef,
501 stream_config_Release,
502 stream_config_GetStreamType,
503 stream_config_GetStreamNumber,
504 stream_config_SetStreamNumber,
505 stream_config_GetStreamName,
506 stream_config_SetStreamName,
507 stream_config_GetConnectionName,
508 stream_config_SetConnectionName,
509 stream_config_GetBitrate,
510 stream_config_SetBitrate,
511 stream_config_GetBufferWindow,
512 stream_config_SetBufferWindow,
515 static struct stream_config *impl_from_IWMMediaProps(IWMMediaProps *iface)
517 return CONTAINING_RECORD(iface, struct stream_config, IWMMediaProps_iface);
520 static HRESULT WINAPI stream_props_QueryInterface(IWMMediaProps *iface, REFIID iid, void **out)
522 struct stream_config *config = impl_from_IWMMediaProps(iface);
523 return IWMStreamConfig_QueryInterface(&config->IWMStreamConfig_iface, iid, out);
526 static ULONG WINAPI stream_props_AddRef(IWMMediaProps *iface)
528 struct stream_config *config = impl_from_IWMMediaProps(iface);
529 return IWMStreamConfig_AddRef(&config->IWMStreamConfig_iface);
532 static ULONG WINAPI stream_props_Release(IWMMediaProps *iface)
534 struct stream_config *config = impl_from_IWMMediaProps(iface);
535 return IWMStreamConfig_Release(&config->IWMStreamConfig_iface);
538 static HRESULT WINAPI stream_props_GetType(IWMMediaProps *iface, GUID *major_type)
540 FIXME("iface %p, major_type %p, stub!\n", iface, major_type);
541 return E_NOTIMPL;
544 static HRESULT WINAPI stream_props_GetMediaType(IWMMediaProps *iface, WM_MEDIA_TYPE *mt, DWORD *size)
546 struct stream_config *config = impl_from_IWMMediaProps(iface);
547 const struct wg_format *format;
548 struct wg_format codec_format;
549 const DWORD req_size = *size;
550 AM_MEDIA_TYPE stream_mt;
552 TRACE("iface %p, mt %p, size %p.\n", iface, mt, size);
554 wg_parser_stream_get_codec_format(config->stream->wg_stream, &codec_format);
555 format = (codec_format.major_type != WG_MAJOR_TYPE_UNKNOWN) ? &codec_format : &config->stream->format;
556 if (!amt_from_wg_format(&stream_mt, format, true))
557 return E_OUTOFMEMORY;
559 *size = sizeof(stream_mt) + stream_mt.cbFormat;
560 if (!mt)
561 return S_OK;
562 if (req_size < *size)
563 return ASF_E_BUFFERTOOSMALL;
565 strmbase_dump_media_type(&stream_mt);
567 memcpy(mt, &stream_mt, sizeof(*mt));
568 memcpy(mt + 1, stream_mt.pbFormat, stream_mt.cbFormat);
569 mt->pbFormat = (BYTE *)(mt + 1);
570 return S_OK;
573 static HRESULT WINAPI stream_props_SetMediaType(IWMMediaProps *iface, WM_MEDIA_TYPE *mt)
575 FIXME("iface %p, mt %p, stub!\n", iface, mt);
576 return E_NOTIMPL;
579 static const IWMMediaPropsVtbl stream_props_vtbl =
581 stream_props_QueryInterface,
582 stream_props_AddRef,
583 stream_props_Release,
584 stream_props_GetType,
585 stream_props_GetMediaType,
586 stream_props_SetMediaType,
589 static DWORD CALLBACK read_thread(void *arg)
591 struct wm_reader *reader = arg;
592 IStream *stream = reader->source_stream;
593 HANDLE file = reader->file;
594 size_t buffer_size = 4096;
595 uint64_t file_size;
596 void *data;
598 if (!(data = malloc(buffer_size)))
599 return 0;
601 if (file)
603 LARGE_INTEGER size;
605 GetFileSizeEx(file, &size);
606 file_size = size.QuadPart;
608 else
610 STATSTG stat;
612 IStream_Stat(stream, &stat, STATFLAG_NONAME);
613 file_size = stat.cbSize.QuadPart;
616 TRACE("Starting read thread for reader %p.\n", reader);
618 while (!reader->read_thread_shutdown)
620 LARGE_INTEGER large_offset;
621 uint64_t offset;
622 ULONG ret_size;
623 uint32_t size;
624 HRESULT hr;
626 if (!wg_parser_get_next_read_offset(reader->wg_parser, &offset, &size))
627 continue;
629 if (offset >= file_size)
630 size = 0;
631 else if (offset + size >= file_size)
632 size = file_size - offset;
634 if (!size)
636 wg_parser_push_data(reader->wg_parser, data, 0);
637 continue;
640 if (!array_reserve(&data, &buffer_size, size, 1))
642 free(data);
643 return 0;
646 ret_size = 0;
648 large_offset.QuadPart = offset;
649 if (file)
651 if (!SetFilePointerEx(file, large_offset, NULL, FILE_BEGIN)
652 || !ReadFile(file, data, size, &ret_size, NULL))
654 ERR("Failed to read %u bytes at offset %I64u, error %lu.\n", size, offset, GetLastError());
655 wg_parser_push_data(reader->wg_parser, NULL, 0);
656 continue;
659 else
661 if (SUCCEEDED(hr = IStream_Seek(stream, large_offset, STREAM_SEEK_SET, NULL)))
662 hr = IStream_Read(stream, data, size, &ret_size);
663 if (FAILED(hr))
665 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr);
666 wg_parser_push_data(reader->wg_parser, NULL, 0);
667 continue;
671 if (ret_size != size)
672 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size);
673 wg_parser_push_data(reader->wg_parser, data, ret_size);
676 free(data);
677 TRACE("Reader is shutting down; exiting.\n");
678 return 0;
681 static struct wm_reader *impl_from_IWMProfile3(IWMProfile3 *iface)
683 return CONTAINING_RECORD(iface, struct wm_reader, IWMProfile3_iface);
686 static HRESULT WINAPI profile_QueryInterface(IWMProfile3 *iface, REFIID iid, void **out)
688 struct wm_reader *reader = impl_from_IWMProfile3(iface);
689 return IUnknown_QueryInterface(reader->outer, iid, out);
692 static ULONG WINAPI profile_AddRef(IWMProfile3 *iface)
694 struct wm_reader *reader = impl_from_IWMProfile3(iface);
695 return IUnknown_AddRef(reader->outer);
698 static ULONG WINAPI profile_Release(IWMProfile3 *iface)
700 struct wm_reader *reader = impl_from_IWMProfile3(iface);
701 return IUnknown_Release(reader->outer);
704 static HRESULT WINAPI profile_GetVersion(IWMProfile3 *iface, WMT_VERSION *version)
706 FIXME("iface %p, version %p, stub!\n", iface, version);
707 return E_NOTIMPL;
710 static HRESULT WINAPI profile_GetName(IWMProfile3 *iface, WCHAR *name, DWORD *length)
712 FIXME("iface %p, name %p, length %p, stub!\n", iface, name, length);
713 return E_NOTIMPL;
716 static HRESULT WINAPI profile_SetName(IWMProfile3 *iface, const WCHAR *name)
718 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
719 return E_NOTIMPL;
722 static HRESULT WINAPI profile_GetDescription(IWMProfile3 *iface, WCHAR *description, DWORD *length)
724 FIXME("iface %p, description %p, length %p, stub!\n", iface, description, length);
725 return E_NOTIMPL;
728 static HRESULT WINAPI profile_SetDescription(IWMProfile3 *iface, const WCHAR *description)
730 FIXME("iface %p, description %s, stub!\n", iface, debugstr_w(description));
731 return E_NOTIMPL;
734 static HRESULT WINAPI profile_GetStreamCount(IWMProfile3 *iface, DWORD *count)
736 struct wm_reader *reader = impl_from_IWMProfile3(iface);
738 TRACE("reader %p, count %p.\n", reader, count);
740 if (!count)
741 return E_INVALIDARG;
743 EnterCriticalSection(&reader->cs);
744 *count = reader->stream_count;
745 LeaveCriticalSection(&reader->cs);
746 return S_OK;
749 static HRESULT WINAPI profile_GetStream(IWMProfile3 *iface, DWORD index, IWMStreamConfig **config)
751 struct wm_reader *reader = impl_from_IWMProfile3(iface);
752 struct stream_config *object;
754 TRACE("reader %p, index %lu, config %p.\n", reader, index, config);
756 EnterCriticalSection(&reader->cs);
758 if (index >= reader->stream_count)
760 LeaveCriticalSection(&reader->cs);
761 WARN("Index %lu exceeds stream count %u; returning E_INVALIDARG.\n", index, reader->stream_count);
762 return E_INVALIDARG;
765 if (!(object = calloc(1, sizeof(*object))))
767 LeaveCriticalSection(&reader->cs);
768 return E_OUTOFMEMORY;
771 object->IWMStreamConfig_iface.lpVtbl = &stream_config_vtbl;
772 object->IWMMediaProps_iface.lpVtbl = &stream_props_vtbl;
773 object->refcount = 1;
774 object->stream = &reader->streams[index];
775 IWMProfile3_AddRef(&reader->IWMProfile3_iface);
777 LeaveCriticalSection(&reader->cs);
779 TRACE("Created stream config %p.\n", object);
780 *config = &object->IWMStreamConfig_iface;
781 return S_OK;
784 static HRESULT WINAPI profile_GetStreamByNumber(IWMProfile3 *iface, WORD stream_number, IWMStreamConfig **config)
786 HRESULT hr;
788 TRACE("iface %p, stream_number %u, config %p.\n", iface, stream_number, config);
790 if (!stream_number)
791 return NS_E_NO_STREAM;
793 hr = profile_GetStream(iface, stream_number - 1, config);
794 if (hr == E_INVALIDARG)
795 hr = NS_E_NO_STREAM;
797 return hr;
800 static HRESULT WINAPI profile_RemoveStream(IWMProfile3 *iface, IWMStreamConfig *config)
802 FIXME("iface %p, config %p, stub!\n", iface, config);
803 return E_NOTIMPL;
806 static HRESULT WINAPI profile_RemoveStreamByNumber(IWMProfile3 *iface, WORD stream_number)
808 FIXME("iface %p, stream_number %u, stub!\n", iface, stream_number);
809 return E_NOTIMPL;
812 static HRESULT WINAPI profile_AddStream(IWMProfile3 *iface, IWMStreamConfig *config)
814 FIXME("iface %p, config %p, stub!\n", iface, config);
815 return E_NOTIMPL;
818 static HRESULT WINAPI profile_ReconfigStream(IWMProfile3 *iface, IWMStreamConfig *config)
820 FIXME("iface %p, config %p, stub!\n", iface, config);
821 return E_NOTIMPL;
824 static HRESULT WINAPI profile_CreateNewStream(IWMProfile3 *iface, REFGUID type, IWMStreamConfig **config)
826 FIXME("iface %p, type %s, config %p, stub!\n", iface, debugstr_guid(type), config);
827 return E_NOTIMPL;
830 static HRESULT WINAPI profile_GetMutualExclusionCount(IWMProfile3 *iface, DWORD *count)
832 FIXME("iface %p, count %p, stub!\n", iface, count);
833 return E_NOTIMPL;
836 static HRESULT WINAPI profile_GetMutualExclusion(IWMProfile3 *iface, DWORD index, IWMMutualExclusion **excl)
838 FIXME("iface %p, index %lu, excl %p, stub!\n", iface, index, excl);
839 return E_NOTIMPL;
842 static HRESULT WINAPI profile_RemoveMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
844 FIXME("iface %p, excl %p, stub!\n", iface, excl);
845 return E_NOTIMPL;
848 static HRESULT WINAPI profile_AddMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
850 FIXME("iface %p, excl %p, stub!\n", iface, excl);
851 return E_NOTIMPL;
854 static HRESULT WINAPI profile_CreateNewMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion **excl)
856 FIXME("iface %p, excl %p, stub!\n", iface, excl);
857 return E_NOTIMPL;
860 static HRESULT WINAPI profile_GetProfileID(IWMProfile3 *iface, GUID *id)
862 FIXME("iface %p, id %p, stub!\n", iface, id);
863 return E_NOTIMPL;
866 static HRESULT WINAPI profile_GetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT *format)
868 FIXME("iface %p, format %p, stub!\n", iface, format);
869 return E_NOTIMPL;
872 static HRESULT WINAPI profile_SetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT format)
874 FIXME("iface %p, format %#x, stub!\n", iface, format);
875 return E_NOTIMPL;
878 static HRESULT WINAPI profile_GetBandwidthSharingCount(IWMProfile3 *iface, DWORD *count)
880 FIXME("iface %p, count %p, stub!\n", iface, count);
881 return E_NOTIMPL;
884 static HRESULT WINAPI profile_GetBandwidthSharing(IWMProfile3 *iface, DWORD index, IWMBandwidthSharing **sharing)
886 FIXME("iface %p, index %lu, sharing %p, stub!\n", iface, index, sharing);
887 return E_NOTIMPL;
890 static HRESULT WINAPI profile_RemoveBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing *sharing)
892 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
893 return E_NOTIMPL;
896 static HRESULT WINAPI profile_AddBandwidthSharing(IWMProfile3 *iface, IWMBandwidthSharing *sharing)
898 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
899 return E_NOTIMPL;
902 static HRESULT WINAPI profile_CreateNewBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing **sharing)
904 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
905 return E_NOTIMPL;
908 static HRESULT WINAPI profile_GetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
910 FIXME("iface %p, stream %p, stub!\n", iface, stream);
911 return E_NOTIMPL;
914 static HRESULT WINAPI profile_SetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization *stream)
916 FIXME("iface %p, stream %p, stub!\n", iface, stream);
917 return E_NOTIMPL;
920 static HRESULT WINAPI profile_RemoveStreamPrioritization(IWMProfile3 *iface)
922 FIXME("iface %p, stub!\n", iface);
923 return E_NOTIMPL;
926 static HRESULT WINAPI profile_CreateNewStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
928 FIXME("iface %p, stream %p, stub!\n", iface, stream);
929 return E_NOTIMPL;
932 static HRESULT WINAPI profile_GetExpectedPacketCount(IWMProfile3 *iface, QWORD duration, QWORD *count)
934 FIXME("iface %p, duration %s, count %p, stub!\n", iface, debugstr_time(duration), count);
935 return E_NOTIMPL;
938 static const IWMProfile3Vtbl profile_vtbl =
940 profile_QueryInterface,
941 profile_AddRef,
942 profile_Release,
943 profile_GetVersion,
944 profile_GetName,
945 profile_SetName,
946 profile_GetDescription,
947 profile_SetDescription,
948 profile_GetStreamCount,
949 profile_GetStream,
950 profile_GetStreamByNumber,
951 profile_RemoveStream,
952 profile_RemoveStreamByNumber,
953 profile_AddStream,
954 profile_ReconfigStream,
955 profile_CreateNewStream,
956 profile_GetMutualExclusionCount,
957 profile_GetMutualExclusion,
958 profile_RemoveMutualExclusion,
959 profile_AddMutualExclusion,
960 profile_CreateNewMutualExclusion,
961 profile_GetProfileID,
962 profile_GetStorageFormat,
963 profile_SetStorageFormat,
964 profile_GetBandwidthSharingCount,
965 profile_GetBandwidthSharing,
966 profile_RemoveBandwidthSharing,
967 profile_AddBandwidthSharing,
968 profile_CreateNewBandwidthSharing,
969 profile_GetStreamPrioritization,
970 profile_SetStreamPrioritization,
971 profile_RemoveStreamPrioritization,
972 profile_CreateNewStreamPrioritization,
973 profile_GetExpectedPacketCount,
976 static struct wm_reader *impl_from_IWMHeaderInfo3(IWMHeaderInfo3 *iface)
978 return CONTAINING_RECORD(iface, struct wm_reader, IWMHeaderInfo3_iface);
981 static HRESULT WINAPI header_info_QueryInterface(IWMHeaderInfo3 *iface, REFIID iid, void **out)
983 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
984 return IUnknown_QueryInterface(reader->outer, iid, out);
987 static ULONG WINAPI header_info_AddRef(IWMHeaderInfo3 *iface)
989 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
990 return IUnknown_AddRef(reader->outer);
993 static ULONG WINAPI header_info_Release(IWMHeaderInfo3 *iface)
995 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
996 return IUnknown_Release(reader->outer);
999 static HRESULT WINAPI header_info_GetAttributeCount(IWMHeaderInfo3 *iface, WORD stream_number, WORD *count)
1001 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
1002 return E_NOTIMPL;
1005 static HRESULT WINAPI header_info_GetAttributeByIndex(IWMHeaderInfo3 *iface, WORD index, WORD *stream_number,
1006 WCHAR *name, WORD *name_len, WMT_ATTR_DATATYPE *type, BYTE *value, WORD *size)
1008 FIXME("iface %p, index %u, stream_number %p, name %p, name_len %p, type %p, value %p, size %p, stub!\n",
1009 iface, index, stream_number, name, name_len, type, value, size);
1010 return E_NOTIMPL;
1013 static HRESULT WINAPI header_info_GetAttributeByName(IWMHeaderInfo3 *iface, WORD *stream_number,
1014 const WCHAR *name, WMT_ATTR_DATATYPE *type, BYTE *value, WORD *size)
1016 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
1017 const WORD req_size = *size;
1019 TRACE("reader %p, stream_number %p, name %s, type %p, value %p, size %u.\n",
1020 reader, stream_number, debugstr_w(name), type, value, *size);
1022 if (!stream_number)
1023 return E_INVALIDARG;
1025 if (!wcscmp(name, L"Duration"))
1027 QWORD duration;
1029 if (*stream_number)
1031 WARN("Requesting duration for stream %u, returning ASF_E_NOTFOUND.\n", *stream_number);
1032 return ASF_E_NOTFOUND;
1035 *size = sizeof(QWORD);
1036 if (!value)
1038 *type = WMT_TYPE_QWORD;
1039 return S_OK;
1041 if (req_size < *size)
1042 return ASF_E_BUFFERTOOSMALL;
1044 *type = WMT_TYPE_QWORD;
1045 EnterCriticalSection(&reader->cs);
1046 duration = wg_parser_stream_get_duration(wg_parser_get_stream(reader->wg_parser, 0));
1047 LeaveCriticalSection(&reader->cs);
1048 TRACE("Returning duration %s.\n", debugstr_time(duration));
1049 memcpy(value, &duration, sizeof(QWORD));
1050 return S_OK;
1052 else if (!wcscmp(name, L"Seekable"))
1054 if (*stream_number)
1056 WARN("Requesting duration for stream %u, returning ASF_E_NOTFOUND.\n", *stream_number);
1057 return ASF_E_NOTFOUND;
1060 *size = sizeof(BOOL);
1061 if (!value)
1063 *type = WMT_TYPE_BOOL;
1064 return S_OK;
1066 if (req_size < *size)
1067 return ASF_E_BUFFERTOOSMALL;
1069 *type = WMT_TYPE_BOOL;
1070 *(BOOL *)value = TRUE;
1071 return S_OK;
1073 else
1075 FIXME("Unknown attribute %s.\n", debugstr_w(name));
1076 return ASF_E_NOTFOUND;
1080 static HRESULT WINAPI header_info_SetAttribute(IWMHeaderInfo3 *iface, WORD stream_number,
1081 const WCHAR *name, WMT_ATTR_DATATYPE type, const BYTE *value, WORD size)
1083 FIXME("iface %p, stream_number %u, name %s, type %#x, value %p, size %u, stub!\n",
1084 iface, stream_number, debugstr_w(name), type, value, size);
1085 return E_NOTIMPL;
1088 static HRESULT WINAPI header_info_GetMarkerCount(IWMHeaderInfo3 *iface, WORD *count)
1090 FIXME("iface %p, count %p, stub!\n", iface, count);
1091 return E_NOTIMPL;
1094 static HRESULT WINAPI header_info_GetMarker(IWMHeaderInfo3 *iface,
1095 WORD index, WCHAR *name, WORD *len, QWORD *time)
1097 FIXME("iface %p, index %u, name %p, len %p, time %p, stub!\n", iface, index, name, len, time);
1098 return E_NOTIMPL;
1101 static HRESULT WINAPI header_info_AddMarker(IWMHeaderInfo3 *iface, const WCHAR *name, QWORD time)
1103 FIXME("iface %p, name %s, time %s, stub!\n", iface, debugstr_w(name), debugstr_time(time));
1104 return E_NOTIMPL;
1107 static HRESULT WINAPI header_info_RemoveMarker(IWMHeaderInfo3 *iface, WORD index)
1109 FIXME("iface %p, index %u, stub!\n", iface, index);
1110 return E_NOTIMPL;
1113 static HRESULT WINAPI header_info_GetScriptCount(IWMHeaderInfo3 *iface, WORD *count)
1115 FIXME("iface %p, count %p, stub!\n", iface, count);
1116 return E_NOTIMPL;
1119 static HRESULT WINAPI header_info_GetScript(IWMHeaderInfo3 *iface, WORD index, WCHAR *type,
1120 WORD *type_len, WCHAR *command, WORD *command_len, QWORD *time)
1122 FIXME("iface %p, index %u, type %p, type_len %p, command %p, command_len %p, time %p, stub!\n",
1123 iface, index, type, type_len, command, command_len, time);
1124 return E_NOTIMPL;
1127 static HRESULT WINAPI header_info_AddScript(IWMHeaderInfo3 *iface,
1128 const WCHAR *type, const WCHAR *command, QWORD time)
1130 FIXME("iface %p, type %s, command %s, time %s, stub!\n",
1131 iface, debugstr_w(type), debugstr_w(command), debugstr_time(time));
1132 return E_NOTIMPL;
1135 static HRESULT WINAPI header_info_RemoveScript(IWMHeaderInfo3 *iface, WORD index)
1137 FIXME("iface %p, index %u, stub!\n", iface, index);
1138 return E_NOTIMPL;
1141 static HRESULT WINAPI header_info_GetCodecInfoCount(IWMHeaderInfo3 *iface, DWORD *count)
1143 FIXME("iface %p, count %p, stub!\n", iface, count);
1144 return E_NOTIMPL;
1147 static HRESULT WINAPI header_info_GetCodecInfo(IWMHeaderInfo3 *iface, DWORD index, WORD *name_len,
1148 WCHAR *name, WORD *desc_len, WCHAR *desc, WMT_CODEC_INFO_TYPE *type, WORD *size, BYTE *info)
1150 FIXME("iface %p, index %lu, name_len %p, name %p, desc_len %p, desc %p, type %p, size %p, info %p, stub!\n",
1151 iface, index, name_len, name, desc_len, desc, type, size, info);
1152 return E_NOTIMPL;
1155 static HRESULT WINAPI header_info_GetAttributeCountEx(IWMHeaderInfo3 *iface, WORD stream_number, WORD *count)
1157 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
1158 return E_NOTIMPL;
1161 static HRESULT WINAPI header_info_GetAttributeIndices(IWMHeaderInfo3 *iface, WORD stream_number,
1162 const WCHAR *name, WORD *lang_index, WORD *indices, WORD *count)
1164 FIXME("iface %p, stream_number %u, name %s, lang_index %p, indices %p, count %p, stub!\n",
1165 iface, stream_number, debugstr_w(name), lang_index, indices, count);
1166 return E_NOTIMPL;
1169 static HRESULT WINAPI header_info_GetAttributeByIndexEx(IWMHeaderInfo3 *iface,
1170 WORD stream_number, WORD index, WCHAR *name, WORD *name_len,
1171 WMT_ATTR_DATATYPE *type, WORD *lang_index, BYTE *value, DWORD *size)
1173 FIXME("iface %p, stream_number %u, index %u, name %p, name_len %p,"
1174 " type %p, lang_index %p, value %p, size %p, stub!\n",
1175 iface, stream_number, index, name, name_len, type, lang_index, value, size);
1176 return E_NOTIMPL;
1179 static HRESULT WINAPI header_info_ModifyAttribute(IWMHeaderInfo3 *iface, WORD stream_number,
1180 WORD index, WMT_ATTR_DATATYPE type, WORD lang_index, const BYTE *value, DWORD size)
1182 FIXME("iface %p, stream_number %u, index %u, type %#x, lang_index %u, value %p, size %lu, stub!\n",
1183 iface, stream_number, index, type, lang_index, value, size);
1184 return E_NOTIMPL;
1187 static HRESULT WINAPI header_info_AddAttribute(IWMHeaderInfo3 *iface,
1188 WORD stream_number, const WCHAR *name, WORD *index,
1189 WMT_ATTR_DATATYPE type, WORD lang_index, const BYTE *value, DWORD size)
1191 FIXME("iface %p, stream_number %u, name %s, index %p, type %#x, lang_index %u, value %p, size %lu, stub!\n",
1192 iface, stream_number, debugstr_w(name), index, type, lang_index, value, size);
1193 return E_NOTIMPL;
1196 static HRESULT WINAPI header_info_DeleteAttribute(IWMHeaderInfo3 *iface, WORD stream_number, WORD index)
1198 FIXME("iface %p, stream_number %u, index %u, stub!\n", iface, stream_number, index);
1199 return E_NOTIMPL;
1202 static HRESULT WINAPI header_info_AddCodecInfo(IWMHeaderInfo3 *iface, const WCHAR *name,
1203 const WCHAR *desc, WMT_CODEC_INFO_TYPE type, WORD size, BYTE *info)
1205 FIXME("iface %p, name %s, desc %s, type %#x, size %u, info %p, stub!\n",
1206 info, debugstr_w(name), debugstr_w(desc), type, size, info);
1207 return E_NOTIMPL;
1210 static const IWMHeaderInfo3Vtbl header_info_vtbl =
1212 header_info_QueryInterface,
1213 header_info_AddRef,
1214 header_info_Release,
1215 header_info_GetAttributeCount,
1216 header_info_GetAttributeByIndex,
1217 header_info_GetAttributeByName,
1218 header_info_SetAttribute,
1219 header_info_GetMarkerCount,
1220 header_info_GetMarker,
1221 header_info_AddMarker,
1222 header_info_RemoveMarker,
1223 header_info_GetScriptCount,
1224 header_info_GetScript,
1225 header_info_AddScript,
1226 header_info_RemoveScript,
1227 header_info_GetCodecInfoCount,
1228 header_info_GetCodecInfo,
1229 header_info_GetAttributeCountEx,
1230 header_info_GetAttributeIndices,
1231 header_info_GetAttributeByIndexEx,
1232 header_info_ModifyAttribute,
1233 header_info_AddAttribute,
1234 header_info_DeleteAttribute,
1235 header_info_AddCodecInfo,
1238 static struct wm_reader *impl_from_IWMLanguageList(IWMLanguageList *iface)
1240 return CONTAINING_RECORD(iface, struct wm_reader, IWMLanguageList_iface);
1243 static HRESULT WINAPI language_list_QueryInterface(IWMLanguageList *iface, REFIID iid, void **out)
1245 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1246 return IUnknown_QueryInterface(reader->outer, iid, out);
1249 static ULONG WINAPI language_list_AddRef(IWMLanguageList *iface)
1251 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1252 return IUnknown_AddRef(reader->outer);
1255 static ULONG WINAPI language_list_Release(IWMLanguageList *iface)
1257 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1258 return IUnknown_Release(reader->outer);
1261 static HRESULT WINAPI language_list_GetLanguageCount(IWMLanguageList *iface, WORD *count)
1263 FIXME("iface %p, count %p, stub!\n", iface, count);
1264 return E_NOTIMPL;
1267 static HRESULT WINAPI language_list_GetLanguageDetails(IWMLanguageList *iface,
1268 WORD index, WCHAR *lang, WORD *len)
1270 FIXME("iface %p, index %u, lang %p, len %p, stub!\n", iface, index, lang, len);
1271 return E_NOTIMPL;
1274 static HRESULT WINAPI language_list_AddLanguageByRFC1766String(IWMLanguageList *iface,
1275 const WCHAR *lang, WORD *index)
1277 FIXME("iface %p, lang %s, index %p, stub!\n", iface, debugstr_w(lang), index);
1278 return E_NOTIMPL;
1281 static const IWMLanguageListVtbl language_list_vtbl =
1283 language_list_QueryInterface,
1284 language_list_AddRef,
1285 language_list_Release,
1286 language_list_GetLanguageCount,
1287 language_list_GetLanguageDetails,
1288 language_list_AddLanguageByRFC1766String,
1291 static struct wm_reader *impl_from_IWMPacketSize2(IWMPacketSize2 *iface)
1293 return CONTAINING_RECORD(iface, struct wm_reader, IWMPacketSize2_iface);
1296 static HRESULT WINAPI packet_size_QueryInterface(IWMPacketSize2 *iface, REFIID iid, void **out)
1298 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1299 return IUnknown_QueryInterface(reader->outer, iid, out);
1302 static ULONG WINAPI packet_size_AddRef(IWMPacketSize2 *iface)
1304 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1305 return IUnknown_AddRef(reader->outer);
1308 static ULONG WINAPI packet_size_Release(IWMPacketSize2 *iface)
1310 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1311 return IUnknown_Release(reader->outer);
1314 static HRESULT WINAPI packet_size_GetMaxPacketSize(IWMPacketSize2 *iface, DWORD *size)
1316 FIXME("iface %p, size %p, stub!\n", iface, size);
1317 return E_NOTIMPL;
1320 static HRESULT WINAPI packet_size_SetMaxPacketSize(IWMPacketSize2 *iface, DWORD size)
1322 FIXME("iface %p, size %lu, stub!\n", iface, size);
1323 return E_NOTIMPL;
1326 static HRESULT WINAPI packet_size_GetMinPacketSize(IWMPacketSize2 *iface, DWORD *size)
1328 FIXME("iface %p, size %p, stub!\n", iface, size);
1329 return E_NOTIMPL;
1332 static HRESULT WINAPI packet_size_SetMinPacketSize(IWMPacketSize2 *iface, DWORD size)
1334 FIXME("iface %p, size %lu, stub!\n", iface, size);
1335 return E_NOTIMPL;
1338 static const IWMPacketSize2Vtbl packet_size_vtbl =
1340 packet_size_QueryInterface,
1341 packet_size_AddRef,
1342 packet_size_Release,
1343 packet_size_GetMaxPacketSize,
1344 packet_size_SetMaxPacketSize,
1345 packet_size_GetMinPacketSize,
1346 packet_size_SetMinPacketSize,
1349 static struct wm_reader *impl_from_IWMReaderPlaylistBurn(IWMReaderPlaylistBurn *iface)
1351 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderPlaylistBurn_iface);
1354 static HRESULT WINAPI playlist_QueryInterface(IWMReaderPlaylistBurn *iface, REFIID iid, void **out)
1356 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1357 return IUnknown_QueryInterface(reader->outer, iid, out);
1360 static ULONG WINAPI playlist_AddRef(IWMReaderPlaylistBurn *iface)
1362 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1363 return IUnknown_AddRef(reader->outer);
1366 static ULONG WINAPI playlist_Release(IWMReaderPlaylistBurn *iface)
1368 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1369 return IUnknown_Release(reader->outer);
1372 static HRESULT WINAPI playlist_InitPlaylistBurn(IWMReaderPlaylistBurn *iface, DWORD count,
1373 const WCHAR **filenames, IWMStatusCallback *callback, void *context)
1375 FIXME("iface %p, count %lu, filenames %p, callback %p, context %p, stub!\n",
1376 iface, count, filenames, callback, context);
1377 return E_NOTIMPL;
1380 static HRESULT WINAPI playlist_GetInitResults(IWMReaderPlaylistBurn *iface, DWORD count, HRESULT *hrs)
1382 FIXME("iface %p, count %lu, hrs %p, stub!\n", iface, count, hrs);
1383 return E_NOTIMPL;
1386 static HRESULT WINAPI playlist_Cancel(IWMReaderPlaylistBurn *iface)
1388 FIXME("iface %p, stub!\n", iface);
1389 return E_NOTIMPL;
1392 static HRESULT WINAPI playlist_EndPlaylistBurn(IWMReaderPlaylistBurn *iface, HRESULT hr)
1394 FIXME("iface %p, hr %#lx, stub!\n", iface, hr);
1395 return E_NOTIMPL;
1398 static const IWMReaderPlaylistBurnVtbl playlist_vtbl =
1400 playlist_QueryInterface,
1401 playlist_AddRef,
1402 playlist_Release,
1403 playlist_InitPlaylistBurn,
1404 playlist_GetInitResults,
1405 playlist_Cancel,
1406 playlist_EndPlaylistBurn,
1409 static struct wm_reader *impl_from_IWMReaderTimecode(IWMReaderTimecode *iface)
1411 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderTimecode_iface);
1414 static HRESULT WINAPI timecode_QueryInterface(IWMReaderTimecode *iface, REFIID iid, void **out)
1416 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1417 return IUnknown_QueryInterface(reader->outer, iid, out);
1420 static ULONG WINAPI timecode_AddRef(IWMReaderTimecode *iface)
1422 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1423 return IUnknown_AddRef(reader->outer);
1426 static ULONG WINAPI timecode_Release(IWMReaderTimecode *iface)
1428 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1429 return IUnknown_Release(reader->outer);
1432 static HRESULT WINAPI timecode_GetTimecodeRangeCount(IWMReaderTimecode *iface,
1433 WORD stream_number, WORD *count)
1435 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
1436 return E_NOTIMPL;
1439 static HRESULT WINAPI timecode_GetTimecodeRangeBounds(IWMReaderTimecode *iface,
1440 WORD stream_number, WORD index, DWORD *start, DWORD *end)
1442 FIXME("iface %p, stream_number %u, index %u, start %p, end %p, stub!\n",
1443 iface, stream_number, index, start, end);
1444 return E_NOTIMPL;
1447 static const IWMReaderTimecodeVtbl timecode_vtbl =
1449 timecode_QueryInterface,
1450 timecode_AddRef,
1451 timecode_Release,
1452 timecode_GetTimecodeRangeCount,
1453 timecode_GetTimecodeRangeBounds,
1456 static HRESULT init_stream(struct wm_reader *reader, QWORD file_size)
1458 wg_parser_t wg_parser;
1459 HRESULT hr;
1460 WORD i;
1462 if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, FALSE)))
1463 return E_OUTOFMEMORY;
1465 reader->wg_parser = wg_parser;
1466 reader->read_thread_shutdown = false;
1467 if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL)))
1469 hr = E_OUTOFMEMORY;
1470 goto out_destroy_parser;
1473 if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size)))
1475 ERR("Failed to connect parser, hr %#lx.\n", hr);
1476 goto out_shutdown_thread;
1479 reader->stream_count = wg_parser_get_stream_count(reader->wg_parser);
1481 if (!(reader->streams = calloc(reader->stream_count, sizeof(*reader->streams))))
1483 hr = E_OUTOFMEMORY;
1484 goto out_disconnect_parser;
1487 for (i = 0; i < reader->stream_count; ++i)
1489 struct wm_stream *stream = &reader->streams[i];
1491 stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i);
1492 stream->reader = reader;
1493 stream->index = i;
1494 stream->selection = WMT_ON;
1495 wg_parser_stream_get_preferred_format(stream->wg_stream, &stream->format);
1496 if (stream->format.major_type == WG_MAJOR_TYPE_AUDIO)
1498 /* R.U.S.E enumerates available audio types, picks the first one it
1499 * likes, and then sets the wrong stream to that type. libav might
1500 * give us WG_AUDIO_FORMAT_F32LE by default, which will result in
1501 * the game incorrectly interpreting float data as integer.
1502 * Therefore just match native and always set our default format to
1503 * S16LE. */
1504 stream->format.u.audio.format = WG_AUDIO_FORMAT_S16LE;
1506 else if (stream->format.major_type == WG_MAJOR_TYPE_VIDEO)
1508 /* Call of Juarez: Bound in Blood breaks if I420 is enumerated.
1509 * Some native decoders output I420, but the msmpeg4v3 decoder
1510 * never does.
1512 * Shadowgrounds provides wmv3 video and assumes that the initial
1513 * video type will be BGR. */
1514 stream->format.u.video.format = WG_VIDEO_FORMAT_BGR;
1516 /* API consumers expect RGB video to be bottom-up. */
1517 if (stream->format.u.video.height > 0)
1518 stream->format.u.video.height = -stream->format.u.video.height;
1520 wg_parser_stream_enable(stream->wg_stream, &stream->format);
1523 /* We probably discarded events because streams weren't enabled yet.
1524 * Now that they're all enabled seek back to the start again. */
1525 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0,
1526 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
1528 return S_OK;
1530 out_disconnect_parser:
1531 wg_parser_disconnect(reader->wg_parser);
1533 out_shutdown_thread:
1534 reader->read_thread_shutdown = true;
1535 WaitForSingleObject(reader->read_thread, INFINITE);
1536 CloseHandle(reader->read_thread);
1537 reader->read_thread = NULL;
1539 out_destroy_parser:
1540 wg_parser_destroy(reader->wg_parser);
1541 reader->wg_parser = 0;
1543 return hr;
1546 static struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number)
1548 if (stream_number && stream_number <= reader->stream_count)
1549 return &reader->streams[stream_number - 1];
1550 WARN("Invalid stream number %u.\n", stream_number);
1551 return NULL;
1554 static const enum wg_video_format video_formats[] =
1556 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
1557 * YUV color space, and it's generally much less expensive for
1558 * videoconvert to do YUV -> YUV transformations. */
1559 WG_VIDEO_FORMAT_NV12,
1560 WG_VIDEO_FORMAT_YV12,
1561 WG_VIDEO_FORMAT_YUY2,
1562 WG_VIDEO_FORMAT_UYVY,
1563 WG_VIDEO_FORMAT_YVYU,
1564 WG_VIDEO_FORMAT_BGRx,
1565 WG_VIDEO_FORMAT_BGR,
1566 WG_VIDEO_FORMAT_RGB16,
1567 WG_VIDEO_FORMAT_RGB15,
1570 static const char *get_major_type_string(enum wg_major_type type)
1572 switch (type)
1574 case WG_MAJOR_TYPE_AUDIO:
1575 return "audio";
1576 case WG_MAJOR_TYPE_AUDIO_MPEG1:
1577 return "mpeg1-audio";
1578 case WG_MAJOR_TYPE_AUDIO_MPEG4:
1579 return "mpeg4-audio";
1580 case WG_MAJOR_TYPE_AUDIO_WMA:
1581 return "wma";
1582 case WG_MAJOR_TYPE_VIDEO:
1583 return "video";
1584 case WG_MAJOR_TYPE_VIDEO_CINEPAK:
1585 return "cinepak";
1586 case WG_MAJOR_TYPE_VIDEO_H264:
1587 return "h264";
1588 case WG_MAJOR_TYPE_VIDEO_WMV:
1589 return "wmv";
1590 case WG_MAJOR_TYPE_VIDEO_INDEO:
1591 return "indeo";
1592 case WG_MAJOR_TYPE_VIDEO_MPEG1:
1593 return "mpeg1-video";
1594 case WG_MAJOR_TYPE_UNKNOWN:
1595 return "unknown";
1597 assert(0);
1598 return NULL;
1601 static HRESULT wm_stream_allocate_sample(struct wm_stream *stream, DWORD size, INSSBuffer **sample)
1603 struct buffer *buffer;
1605 if (!stream->read_compressed && stream->output_allocator)
1606 return IWMReaderAllocatorEx_AllocateForOutputEx(stream->output_allocator, stream->index,
1607 size, sample, 0, 0, 0, NULL);
1609 if (stream->read_compressed && stream->stream_allocator)
1610 return IWMReaderAllocatorEx_AllocateForStreamEx(stream->stream_allocator, stream->index + 1,
1611 size, sample, 0, 0, 0, NULL);
1613 /* FIXME: Should these be pooled? */
1614 if (!(buffer = calloc(1, offsetof(struct buffer, data[size]))))
1615 return E_OUTOFMEMORY;
1616 buffer->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
1617 buffer->refcount = 1;
1618 buffer->capacity = size;
1620 TRACE("Created buffer %p.\n", buffer);
1621 *sample = &buffer->INSSBuffer_iface;
1622 return S_OK;
1625 static HRESULT wm_reader_read_stream_sample(struct wm_reader *reader, struct wg_parser_buffer *buffer,
1626 INSSBuffer **sample, QWORD *pts, QWORD *duration, DWORD *flags)
1628 struct wm_stream *stream;
1629 DWORD size, capacity;
1630 HRESULT hr;
1631 BYTE *data;
1633 if (!(stream = wm_reader_get_stream_by_stream_number(reader, buffer->stream + 1)))
1634 return E_INVALIDARG;
1636 TRACE("Got buffer for '%s' stream %p.\n", get_major_type_string(stream->format.major_type), stream);
1638 if (FAILED(hr = wm_stream_allocate_sample(stream, buffer->size, sample)))
1640 ERR("Failed to allocate sample of %u bytes, hr %#lx.\n", buffer->size, hr);
1641 wg_parser_stream_release_buffer(stream->wg_stream);
1642 return hr;
1645 if (FAILED(hr = INSSBuffer_GetBufferAndLength(*sample, &data, &size)))
1646 ERR("Failed to get data pointer, hr %#lx.\n", hr);
1647 if (FAILED(hr = INSSBuffer_GetMaxLength(*sample, &capacity)))
1648 ERR("Failed to get capacity, hr %#lx.\n", hr);
1649 if (buffer->size > capacity)
1650 ERR("Returned capacity %lu is less than requested capacity %u.\n", capacity, buffer->size);
1652 if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, buffer->size))
1654 /* The GStreamer pin has been flushed. */
1655 INSSBuffer_Release(*sample);
1656 *sample = NULL;
1657 return S_FALSE;
1660 if (FAILED(hr = INSSBuffer_SetLength(*sample, buffer->size)))
1661 ERR("Failed to set size %u, hr %#lx.\n", buffer->size, hr);
1663 wg_parser_stream_release_buffer(stream->wg_stream);
1665 if (!buffer->has_pts)
1666 FIXME("Missing PTS.\n");
1667 if (!buffer->has_duration)
1668 FIXME("Missing duration.\n");
1670 *pts = buffer->pts;
1671 *duration = buffer->duration;
1672 *flags = 0;
1673 if (buffer->discontinuity)
1674 *flags |= WM_SF_DISCONTINUITY;
1675 if (!buffer->delta)
1676 *flags |= WM_SF_CLEANPOINT;
1678 return S_OK;
1681 static struct wm_reader *impl_from_IUnknown(IUnknown *iface)
1683 return CONTAINING_RECORD(iface, struct wm_reader, IUnknown_inner);
1686 static HRESULT WINAPI unknown_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out)
1688 struct wm_reader *reader = impl_from_IUnknown(iface);
1690 TRACE("reader %p, iid %s, out %p.\n", reader, debugstr_guid(iid), out);
1692 if (IsEqualIID(iid, &IID_IUnknown)
1693 || IsEqualIID(iid, &IID_IWMSyncReader)
1694 || IsEqualIID(iid, &IID_IWMSyncReader2))
1695 *out = &reader->IWMSyncReader2_iface;
1696 else if (IsEqualIID(iid, &IID_IWMHeaderInfo)
1697 || IsEqualIID(iid, &IID_IWMHeaderInfo2)
1698 || IsEqualIID(iid, &IID_IWMHeaderInfo3))
1699 *out = &reader->IWMHeaderInfo3_iface;
1700 else if (IsEqualIID(iid, &IID_IWMLanguageList))
1701 *out = &reader->IWMLanguageList_iface;
1702 else if (IsEqualIID(iid, &IID_IWMPacketSize)
1703 || IsEqualIID(iid, &IID_IWMPacketSize2))
1704 *out = &reader->IWMPacketSize2_iface;
1705 else if (IsEqualIID(iid, &IID_IWMProfile)
1706 || IsEqualIID(iid, &IID_IWMProfile2)
1707 || IsEqualIID(iid, &IID_IWMProfile3))
1708 *out = &reader->IWMProfile3_iface;
1709 else if (IsEqualIID(iid, &IID_IWMReaderPlaylistBurn))
1710 *out = &reader->IWMReaderPlaylistBurn_iface;
1711 else if (IsEqualIID(iid, &IID_IWMReaderTimecode))
1712 *out = &reader->IWMReaderTimecode_iface;
1713 else
1715 FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1716 *out = NULL;
1717 return E_NOINTERFACE;
1720 IUnknown_AddRef((IUnknown *)*out);
1721 return S_OK;
1724 static ULONG WINAPI unknown_inner_AddRef(IUnknown *iface)
1726 struct wm_reader *reader = impl_from_IUnknown(iface);
1727 ULONG refcount = InterlockedIncrement(&reader->refcount);
1728 TRACE("%p increasing refcount to %lu.\n", reader, refcount);
1729 return refcount;
1732 static ULONG WINAPI unknown_inner_Release(IUnknown *iface)
1734 struct wm_reader *reader = impl_from_IUnknown(iface);
1735 ULONG refcount = InterlockedDecrement(&reader->refcount);
1737 TRACE("%p decreasing refcount to %lu.\n", reader, refcount);
1739 if (!refcount)
1741 IWMSyncReader2_Close(&reader->IWMSyncReader2_iface);
1743 reader->cs.DebugInfo->Spare[0] = 0;
1744 DeleteCriticalSection(&reader->cs);
1746 free(reader);
1749 return refcount;
1752 static const IUnknownVtbl unknown_inner_vtbl =
1754 unknown_inner_QueryInterface,
1755 unknown_inner_AddRef,
1756 unknown_inner_Release,
1759 static struct wm_reader *impl_from_IWMSyncReader2(IWMSyncReader2 *iface)
1761 return CONTAINING_RECORD(iface, struct wm_reader, IWMSyncReader2_iface);
1764 static HRESULT WINAPI reader_QueryInterface(IWMSyncReader2 *iface, REFIID iid, void **out)
1766 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1767 return IUnknown_QueryInterface(reader->outer, iid, out);
1770 static ULONG WINAPI reader_AddRef(IWMSyncReader2 *iface)
1772 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1773 return IUnknown_AddRef(reader->outer);
1776 static ULONG WINAPI reader_Release(IWMSyncReader2 *iface)
1778 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1779 return IUnknown_Release(reader->outer);
1782 static HRESULT WINAPI reader_Close(IWMSyncReader2 *iface)
1784 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1786 TRACE("reader %p.\n", reader);
1788 EnterCriticalSection(&reader->cs);
1790 if (!reader->wg_parser)
1792 LeaveCriticalSection(&reader->cs);
1793 return NS_E_INVALID_REQUEST;
1796 wg_parser_disconnect(reader->wg_parser);
1798 reader->read_thread_shutdown = true;
1799 WaitForSingleObject(reader->read_thread, INFINITE);
1800 CloseHandle(reader->read_thread);
1801 reader->read_thread = NULL;
1803 wg_parser_destroy(reader->wg_parser);
1804 reader->wg_parser = 0;
1806 if (reader->source_stream)
1807 IStream_Release(reader->source_stream);
1808 reader->source_stream = NULL;
1809 if (reader->file)
1810 CloseHandle(reader->file);
1811 reader->file = NULL;
1813 LeaveCriticalSection(&reader->cs);
1814 return S_OK;
1817 static HRESULT WINAPI reader_GetMaxOutputSampleSize(IWMSyncReader2 *iface, DWORD output, DWORD *max)
1819 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
1820 FIXME("(%p)->(%lu %p): stub!\n", This, output, max);
1821 return E_NOTIMPL;
1824 static HRESULT WINAPI reader_GetMaxStreamSampleSize(IWMSyncReader2 *iface, WORD stream_number, DWORD *size)
1826 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1827 struct wm_stream *stream;
1829 TRACE("reader %p, stream_number %u, size %p.\n", reader, stream_number, size);
1831 EnterCriticalSection(&reader->cs);
1833 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
1835 LeaveCriticalSection(&reader->cs);
1836 return E_INVALIDARG;
1839 *size = wg_format_get_max_size(&stream->format);
1841 LeaveCriticalSection(&reader->cs);
1842 return S_OK;
1845 static HRESULT WINAPI reader_GetNextSample(IWMSyncReader2 *iface,
1846 WORD stream_number, INSSBuffer **sample, QWORD *pts, QWORD *duration,
1847 DWORD *flags, DWORD *output_number, WORD *ret_stream_number)
1849 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1850 struct wm_stream *stream;
1851 HRESULT hr = S_FALSE;
1853 TRACE("reader %p, stream_number %u, sample %p, pts %p, duration %p,"
1854 " flags %p, output_number %p, ret_stream_number %p.\n",
1855 reader, stream_number, sample, pts, duration, flags, output_number, ret_stream_number);
1857 if (!stream_number && !output_number && !ret_stream_number)
1858 return E_INVALIDARG;
1860 EnterCriticalSection(&reader->cs);
1862 if (!stream_number)
1863 stream = NULL;
1864 else if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
1865 hr = E_INVALIDARG;
1866 else if (stream->selection == WMT_OFF)
1867 hr = NS_E_INVALID_REQUEST;
1868 else if (stream->eos)
1869 hr = NS_E_NO_MORE_SAMPLES;
1871 while (hr == S_FALSE)
1873 struct wg_parser_buffer wg_buffer;
1874 if (!wg_parser_stream_get_buffer(reader->wg_parser, stream ? stream->wg_stream : 0, &wg_buffer))
1875 hr = NS_E_NO_MORE_SAMPLES;
1876 else if (SUCCEEDED(hr = wm_reader_read_stream_sample(reader, &wg_buffer, sample, pts, duration, flags)))
1877 stream_number = wg_buffer.stream + 1;
1880 if (stream && hr == NS_E_NO_MORE_SAMPLES)
1881 stream->eos = true;
1883 if (output_number && hr == S_OK)
1884 *output_number = stream_number - 1;
1885 if (ret_stream_number && (hr == S_OK || stream_number))
1886 *ret_stream_number = stream_number;
1888 LeaveCriticalSection(&reader->cs);
1889 return hr;
1892 static HRESULT WINAPI reader_GetOutputCount(IWMSyncReader2 *iface, DWORD *count)
1894 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1896 TRACE("reader %p, count %p.\n", reader, count);
1898 EnterCriticalSection(&reader->cs);
1899 *count = reader->stream_count;
1900 LeaveCriticalSection(&reader->cs);
1901 return S_OK;
1904 static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface,
1905 DWORD output, DWORD index, IWMOutputMediaProps **props)
1907 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1908 struct wm_stream *stream;
1909 struct wg_format format;
1911 TRACE("reader %p, output %lu, index %lu, props %p.\n", reader, output, index, props);
1913 EnterCriticalSection(&reader->cs);
1915 if (!(stream = get_stream_by_output_number(reader, output)))
1917 LeaveCriticalSection(&reader->cs);
1918 return E_INVALIDARG;
1921 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
1923 switch (format.major_type)
1925 case WG_MAJOR_TYPE_VIDEO:
1926 if (index >= ARRAY_SIZE(video_formats))
1928 LeaveCriticalSection(&reader->cs);
1929 return NS_E_INVALID_OUTPUT_FORMAT;
1931 format.u.video.format = video_formats[index];
1932 /* API consumers expect RGB video to be bottom-up. */
1933 if (format.u.video.height > 0 && wg_video_format_is_rgb(format.u.video.format))
1934 format.u.video.height = -format.u.video.height;
1935 break;
1937 case WG_MAJOR_TYPE_AUDIO:
1938 if (index)
1940 LeaveCriticalSection(&reader->cs);
1941 return NS_E_INVALID_OUTPUT_FORMAT;
1943 format.u.audio.format = WG_AUDIO_FORMAT_S16LE;
1944 break;
1946 case WG_MAJOR_TYPE_AUDIO_MPEG1:
1947 case WG_MAJOR_TYPE_AUDIO_MPEG4:
1948 case WG_MAJOR_TYPE_AUDIO_WMA:
1949 case WG_MAJOR_TYPE_VIDEO_CINEPAK:
1950 case WG_MAJOR_TYPE_VIDEO_H264:
1951 case WG_MAJOR_TYPE_VIDEO_WMV:
1952 case WG_MAJOR_TYPE_VIDEO_INDEO:
1953 case WG_MAJOR_TYPE_VIDEO_MPEG1:
1954 FIXME("Format %u not implemented!\n", format.major_type);
1955 break;
1956 case WG_MAJOR_TYPE_UNKNOWN:
1957 break;
1960 LeaveCriticalSection(&reader->cs);
1962 *props = output_props_create(&format);
1963 return *props ? S_OK : E_OUTOFMEMORY;
1966 static HRESULT WINAPI reader_GetOutputFormatCount(IWMSyncReader2 *iface, DWORD output, DWORD *count)
1968 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1969 struct wm_stream *stream;
1970 struct wg_format format;
1972 TRACE("reader %p, output %lu, count %p.\n", reader, output, count);
1974 EnterCriticalSection(&reader->cs);
1976 if (!(stream = get_stream_by_output_number(reader, output)))
1978 LeaveCriticalSection(&reader->cs);
1979 return E_INVALIDARG;
1982 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
1983 switch (format.major_type)
1985 case WG_MAJOR_TYPE_VIDEO:
1986 *count = ARRAY_SIZE(video_formats);
1987 break;
1989 case WG_MAJOR_TYPE_AUDIO_MPEG1:
1990 case WG_MAJOR_TYPE_AUDIO_MPEG4:
1991 case WG_MAJOR_TYPE_AUDIO_WMA:
1992 case WG_MAJOR_TYPE_VIDEO_CINEPAK:
1993 case WG_MAJOR_TYPE_VIDEO_H264:
1994 case WG_MAJOR_TYPE_VIDEO_WMV:
1995 case WG_MAJOR_TYPE_VIDEO_INDEO:
1996 case WG_MAJOR_TYPE_VIDEO_MPEG1:
1997 FIXME("Format %u not implemented!\n", format.major_type);
1998 /* fallthrough */
1999 case WG_MAJOR_TYPE_AUDIO:
2000 case WG_MAJOR_TYPE_UNKNOWN:
2001 *count = 1;
2002 break;
2005 LeaveCriticalSection(&reader->cs);
2006 return S_OK;
2009 static HRESULT WINAPI reader_GetOutputNumberForStream(IWMSyncReader2 *iface,
2010 WORD stream_number, DWORD *output)
2012 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2014 TRACE("reader %p, stream_number %u, output %p.\n", reader, stream_number, output);
2016 *output = stream_number - 1;
2017 return S_OK;
2020 static HRESULT WINAPI reader_GetOutputProps(IWMSyncReader2 *iface,
2021 DWORD output, IWMOutputMediaProps **props)
2023 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2024 struct wm_stream *stream;
2026 TRACE("reader %p, output %lu, props %p.\n", reader, output, props);
2028 EnterCriticalSection(&reader->cs);
2030 if (!(stream = get_stream_by_output_number(reader, output)))
2032 LeaveCriticalSection(&reader->cs);
2033 return E_INVALIDARG;
2036 *props = output_props_create(&stream->format);
2037 LeaveCriticalSection(&reader->cs);
2038 return *props ? S_OK : E_OUTOFMEMORY;
2041 static HRESULT WINAPI reader_GetOutputSetting(IWMSyncReader2 *iface, DWORD output_num, const WCHAR *name,
2042 WMT_ATTR_DATATYPE *type, BYTE *value, WORD *length)
2044 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2045 FIXME("(%p)->(%lu %s %p %p %p): stub!\n", This, output_num, debugstr_w(name), type, value, length);
2046 return E_NOTIMPL;
2049 static HRESULT WINAPI reader_GetReadStreamSamples(IWMSyncReader2 *iface, WORD stream_number, BOOL *compressed)
2051 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2052 struct wm_stream *stream;
2054 TRACE("reader %p, stream_number %u, compressed %p.\n", reader, stream_number, compressed);
2056 EnterCriticalSection(&reader->cs);
2058 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2060 LeaveCriticalSection(&reader->cs);
2061 return E_INVALIDARG;
2064 *compressed = stream->read_compressed;
2066 LeaveCriticalSection(&reader->cs);
2067 return S_OK;
2070 static HRESULT WINAPI reader_GetStreamNumberForOutput(IWMSyncReader2 *iface,
2071 DWORD output, WORD *stream_number)
2073 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2075 TRACE("reader %p, output %lu, stream_number %p.\n", reader, output, stream_number);
2077 *stream_number = output + 1;
2078 return S_OK;
2081 static HRESULT WINAPI reader_GetStreamSelected(IWMSyncReader2 *iface,
2082 WORD stream_number, WMT_STREAM_SELECTION *selection)
2084 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2085 struct wm_stream *stream;
2087 TRACE("reader %p, stream_number %u, selection %p.\n", reader, stream_number, selection);
2089 EnterCriticalSection(&reader->cs);
2091 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2093 LeaveCriticalSection(&reader->cs);
2094 return E_INVALIDARG;
2097 *selection = stream->selection;
2099 LeaveCriticalSection(&reader->cs);
2100 return S_OK;
2103 static HRESULT WINAPI reader_Open(IWMSyncReader2 *iface, const WCHAR *filename)
2105 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2106 LARGE_INTEGER size;
2107 HANDLE file;
2108 HRESULT hr;
2110 TRACE("reader %p, filename %s.\n", reader, debugstr_w(filename));
2112 if ((file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2113 OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
2115 ERR("Failed to open %s, error %lu.\n", debugstr_w(filename), GetLastError());
2116 return HRESULT_FROM_WIN32(GetLastError());
2119 if (!GetFileSizeEx(file, &size))
2121 ERR("Failed to get the size of %s, error %lu.\n", debugstr_w(filename), GetLastError());
2122 CloseHandle(file);
2123 return HRESULT_FROM_WIN32(GetLastError());
2126 EnterCriticalSection(&reader->cs);
2128 if (reader->wg_parser)
2130 LeaveCriticalSection(&reader->cs);
2131 WARN("Stream is already open; returning E_UNEXPECTED.\n");
2132 CloseHandle(file);
2133 return E_UNEXPECTED;
2136 reader->file = file;
2138 if (FAILED(hr = init_stream(reader, size.QuadPart)))
2139 reader->file = NULL;
2141 LeaveCriticalSection(&reader->cs);
2142 return hr;
2145 static HRESULT WINAPI reader_OpenStream(IWMSyncReader2 *iface, IStream *stream)
2147 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2148 STATSTG stat;
2149 HRESULT hr;
2151 TRACE("reader %p, stream %p.\n", reader, stream);
2153 if (FAILED(hr = IStream_Stat(stream, &stat, STATFLAG_NONAME)))
2155 ERR("Failed to stat stream, hr %#lx.\n", hr);
2156 return hr;
2159 EnterCriticalSection(&reader->cs);
2161 if (reader->wg_parser)
2163 LeaveCriticalSection(&reader->cs);
2164 WARN("Stream is already open; returning E_UNEXPECTED.\n");
2165 return E_UNEXPECTED;
2168 IStream_AddRef(reader->source_stream = stream);
2169 if (FAILED(hr = init_stream(reader, stat.cbSize.QuadPart)))
2171 IStream_Release(stream);
2172 reader->source_stream = NULL;
2175 LeaveCriticalSection(&reader->cs);
2176 return hr;
2179 static HRESULT WINAPI reader_SetOutputProps(IWMSyncReader2 *iface, DWORD output, IWMOutputMediaProps *props_iface)
2181 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2182 struct output_props *props = unsafe_impl_from_IWMOutputMediaProps(props_iface);
2183 struct wg_format format, pref_format;
2184 struct wm_stream *stream;
2185 HRESULT hr = S_OK;
2186 int i;
2188 TRACE("reader %p, output %lu, props_iface %p.\n", reader, output, props_iface);
2190 strmbase_dump_media_type(&props->mt);
2192 if (!amt_to_wg_format(&props->mt, &format))
2194 ERR("Failed to convert media type to winegstreamer format.\n");
2195 return E_FAIL;
2198 EnterCriticalSection(&reader->cs);
2200 if (!(stream = get_stream_by_output_number(reader, output)))
2202 LeaveCriticalSection(&reader->cs);
2203 return E_INVALIDARG;
2206 wg_parser_stream_get_preferred_format(stream->wg_stream, &pref_format);
2207 if (pref_format.major_type != format.major_type)
2209 /* R.U.S.E sets the type of the wrong stream, apparently by accident. */
2210 hr = NS_E_INCOMPATIBLE_FORMAT;
2212 else switch (pref_format.major_type)
2214 case WG_MAJOR_TYPE_AUDIO:
2215 if (format.u.audio.format == WG_AUDIO_FORMAT_UNKNOWN)
2216 hr = NS_E_AUDIO_CODEC_NOT_INSTALLED;
2217 else if (format.u.audio.channels > pref_format.u.audio.channels)
2218 hr = NS_E_AUDIO_CODEC_NOT_INSTALLED;
2219 break;
2221 case WG_MAJOR_TYPE_VIDEO:
2222 for (i = 0; i < ARRAY_SIZE(video_formats); ++i)
2223 if (format.u.video.format == video_formats[i])
2224 break;
2225 if (i == ARRAY_SIZE(video_formats))
2226 hr = NS_E_INVALID_OUTPUT_FORMAT;
2227 else if (pref_format.u.video.width != format.u.video.width)
2228 hr = NS_E_INVALID_OUTPUT_FORMAT;
2229 else if (abs(pref_format.u.video.height) != abs(format.u.video.height))
2230 hr = NS_E_INVALID_OUTPUT_FORMAT;
2231 break;
2233 default:
2234 hr = NS_E_INCOMPATIBLE_FORMAT;
2235 break;
2238 if (FAILED(hr))
2240 WARN("Unsupported media type, returning %#lx.\n", hr);
2241 LeaveCriticalSection(&reader->cs);
2242 return hr;
2245 stream->format = format;
2246 wg_parser_stream_enable(stream->wg_stream, &format);
2248 /* Re-decode any buffers that might have been generated with the old format.
2250 * FIXME: Seeking in-place will cause some buffers to be dropped.
2251 * Unfortunately, we can't really store the last received PTS and seek there
2252 * either: since seeks are inexact and we aren't guaranteed to receive
2253 * samples in order, some buffers might be duplicated or dropped anyway.
2254 * In order to really seamlessly allow for format changes, we need
2255 * cooperation from each individual GStreamer stream, to be able to tell
2256 * upstream exactly which buffers they need resent...
2258 * In all likelihood this function is being called not mid-stream but rather
2259 * while setting the stream up, before consuming any events. Accordingly
2260 * let's just seek back to the beginning. */
2261 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, reader->start_time, 0,
2262 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
2264 LeaveCriticalSection(&reader->cs);
2265 return S_OK;
2268 static HRESULT WINAPI reader_SetOutputSetting(IWMSyncReader2 *iface, DWORD output,
2269 const WCHAR *name, WMT_ATTR_DATATYPE type, const BYTE *value, WORD size)
2271 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2273 TRACE("reader %p, output %lu, name %s, type %#x, value %p, size %u.\n",
2274 reader, output, debugstr_w(name), type, value, size);
2276 if (!wcscmp(name, L"VideoSampleDurations"))
2278 FIXME("Ignoring VideoSampleDurations setting.\n");
2279 return S_OK;
2281 if (!wcscmp(name, L"EnableDiscreteOutput"))
2283 FIXME("Ignoring EnableDiscreteOutput setting.\n");
2284 return S_OK;
2286 if (!wcscmp(name, L"SpeakerConfig"))
2288 FIXME("Ignoring SpeakerConfig setting.\n");
2289 return S_OK;
2291 else
2293 FIXME("Unknown setting %s; returning E_NOTIMPL.\n", debugstr_w(name));
2294 return E_NOTIMPL;
2298 static HRESULT WINAPI reader_SetRange(IWMSyncReader2 *iface, QWORD start, LONGLONG duration)
2300 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2301 WORD i;
2303 TRACE("reader %p, start %I64u, duration %I64d.\n", reader, start, duration);
2305 EnterCriticalSection(&reader->cs);
2307 reader->start_time = start;
2309 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, start, start + duration,
2310 AM_SEEKING_AbsolutePositioning, duration ? AM_SEEKING_AbsolutePositioning : AM_SEEKING_NoPositioning);
2312 for (i = 0; i < reader->stream_count; ++i)
2313 reader->streams[i].eos = false;
2315 LeaveCriticalSection(&reader->cs);
2316 return S_OK;
2319 static HRESULT WINAPI reader_SetRangeByFrame(IWMSyncReader2 *iface, WORD stream_num, QWORD frame_num,
2320 LONGLONG frames)
2322 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2323 FIXME("(%p)->(%d %s %s): stub!\n", This, stream_num, wine_dbgstr_longlong(frame_num), wine_dbgstr_longlong(frames));
2324 return E_NOTIMPL;
2327 static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD stream_number, BOOL compressed)
2329 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2330 struct wm_stream *stream;
2332 TRACE("reader %p, stream_index %u, compressed %d.\n", reader, stream_number, compressed);
2334 EnterCriticalSection(&reader->cs);
2336 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2338 LeaveCriticalSection(&reader->cs);
2339 return E_INVALIDARG;
2342 stream->read_compressed = compressed;
2344 LeaveCriticalSection(&reader->cs);
2345 return S_OK;
2348 static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface,
2349 WORD count, WORD *stream_numbers, WMT_STREAM_SELECTION *selections)
2351 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2352 struct wm_stream *stream;
2353 WORD i;
2355 TRACE("reader %p, count %u, stream_numbers %p, selections %p.\n",
2356 reader, count, stream_numbers, selections);
2358 if (!count)
2359 return E_INVALIDARG;
2361 EnterCriticalSection(&reader->cs);
2363 for (i = 0; i < count; ++i)
2365 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_numbers[i])))
2367 LeaveCriticalSection(&reader->cs);
2368 WARN("Invalid stream number %u; returning NS_E_INVALID_REQUEST.\n", stream_numbers[i]);
2369 return NS_E_INVALID_REQUEST;
2373 for (i = 0; i < count; ++i)
2375 stream = wm_reader_get_stream_by_stream_number(reader, stream_numbers[i]);
2376 stream->selection = selections[i];
2377 if (selections[i] == WMT_OFF)
2379 TRACE("Disabling stream %u.\n", stream_numbers[i]);
2380 wg_parser_stream_disable(stream->wg_stream);
2382 else if (selections[i] == WMT_ON)
2384 if (selections[i] != WMT_ON)
2385 FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n",
2386 selections[i], stream_numbers[i]);
2387 TRACE("Enabling stream %u.\n", stream_numbers[i]);
2388 wg_parser_stream_enable(stream->wg_stream, &stream->format);
2392 LeaveCriticalSection(&reader->cs);
2393 return S_OK;
2396 static HRESULT WINAPI reader_SetRangeByTimecode(IWMSyncReader2 *iface, WORD stream_num,
2397 WMT_TIMECODE_EXTENSION_DATA *start, WMT_TIMECODE_EXTENSION_DATA *end)
2399 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2400 FIXME("(%p)->(%u %p %p): stub!\n", This, stream_num, start, end);
2401 return E_NOTIMPL;
2404 static HRESULT WINAPI reader_SetRangeByFrameEx(IWMSyncReader2 *iface, WORD stream_num, QWORD frame_num,
2405 LONGLONG frames_to_read, QWORD *starttime)
2407 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2408 FIXME("(%p)->(%u %s %s %p): stub!\n", This, stream_num, wine_dbgstr_longlong(frame_num),
2409 wine_dbgstr_longlong(frames_to_read), starttime);
2410 return E_NOTIMPL;
2413 static HRESULT WINAPI reader_SetAllocateForOutput(IWMSyncReader2 *iface, DWORD output, IWMReaderAllocatorEx *allocator)
2415 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2416 struct wm_stream *stream;
2418 TRACE("reader %p, output %lu, allocator %p.\n", reader, output, allocator);
2420 EnterCriticalSection(&reader->cs);
2422 if (!(stream = get_stream_by_output_number(reader, output)))
2424 LeaveCriticalSection(&reader->cs);
2425 return E_INVALIDARG;
2428 if (stream->output_allocator)
2429 IWMReaderAllocatorEx_Release(stream->output_allocator);
2430 if ((stream->output_allocator = allocator))
2431 IWMReaderAllocatorEx_AddRef(stream->output_allocator);
2433 LeaveCriticalSection(&reader->cs);
2434 return S_OK;
2437 static HRESULT WINAPI reader_GetAllocateForOutput(IWMSyncReader2 *iface, DWORD output, IWMReaderAllocatorEx **allocator)
2439 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2440 struct wm_stream *stream;
2442 TRACE("reader %p, output %lu, allocator %p.\n", reader, output, allocator);
2444 if (!allocator)
2445 return E_INVALIDARG;
2447 EnterCriticalSection(&reader->cs);
2449 if (!(stream = get_stream_by_output_number(reader, output)))
2451 LeaveCriticalSection(&reader->cs);
2452 return E_INVALIDARG;
2455 stream = reader->streams + output;
2456 if ((*allocator = stream->output_allocator))
2457 IWMReaderAllocatorEx_AddRef(*allocator);
2459 LeaveCriticalSection(&reader->cs);
2460 return S_OK;
2463 static HRESULT WINAPI reader_SetAllocateForStream(IWMSyncReader2 *iface, DWORD stream_number, IWMReaderAllocatorEx *allocator)
2465 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2466 struct wm_stream *stream;
2468 TRACE("reader %p, stream_number %lu, allocator %p.\n", reader, stream_number, allocator);
2470 EnterCriticalSection(&reader->cs);
2472 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2474 LeaveCriticalSection(&reader->cs);
2475 return E_INVALIDARG;
2478 if (stream->stream_allocator)
2479 IWMReaderAllocatorEx_Release(stream->stream_allocator);
2480 if ((stream->stream_allocator = allocator))
2481 IWMReaderAllocatorEx_AddRef(stream->stream_allocator);
2483 LeaveCriticalSection(&reader->cs);
2484 return S_OK;
2487 static HRESULT WINAPI reader_GetAllocateForStream(IWMSyncReader2 *iface, DWORD stream_number, IWMReaderAllocatorEx **allocator)
2489 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2490 struct wm_stream *stream;
2492 TRACE("reader %p, stream_number %lu, allocator %p.\n", reader, stream_number, allocator);
2494 if (!allocator)
2495 return E_INVALIDARG;
2497 EnterCriticalSection(&reader->cs);
2499 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2501 LeaveCriticalSection(&reader->cs);
2502 return E_INVALIDARG;
2505 if ((*allocator = stream->stream_allocator))
2506 IWMReaderAllocatorEx_AddRef(*allocator);
2508 LeaveCriticalSection(&reader->cs);
2509 return S_OK;
2512 static const IWMSyncReader2Vtbl reader_vtbl =
2514 reader_QueryInterface,
2515 reader_AddRef,
2516 reader_Release,
2517 reader_Open,
2518 reader_Close,
2519 reader_SetRange,
2520 reader_SetRangeByFrame,
2521 reader_GetNextSample,
2522 reader_SetStreamsSelected,
2523 reader_GetStreamSelected,
2524 reader_SetReadStreamSamples,
2525 reader_GetReadStreamSamples,
2526 reader_GetOutputSetting,
2527 reader_SetOutputSetting,
2528 reader_GetOutputCount,
2529 reader_GetOutputProps,
2530 reader_SetOutputProps,
2531 reader_GetOutputFormatCount,
2532 reader_GetOutputFormat,
2533 reader_GetOutputNumberForStream,
2534 reader_GetStreamNumberForOutput,
2535 reader_GetMaxOutputSampleSize,
2536 reader_GetMaxStreamSampleSize,
2537 reader_OpenStream,
2538 reader_SetRangeByTimecode,
2539 reader_SetRangeByFrameEx,
2540 reader_SetAllocateForOutput,
2541 reader_GetAllocateForOutput,
2542 reader_SetAllocateForStream,
2543 reader_GetAllocateForStream
2546 HRESULT WINAPI winegstreamer_create_wm_sync_reader(IUnknown *outer, void **out)
2548 struct wm_reader *object;
2550 TRACE("out %p.\n", out);
2552 if (!init_gstreamer())
2553 return E_FAIL;
2555 if (!(object = calloc(1, sizeof(*object))))
2556 return E_OUTOFMEMORY;
2558 object->IUnknown_inner.lpVtbl = &unknown_inner_vtbl;
2559 object->IWMSyncReader2_iface.lpVtbl = &reader_vtbl;
2560 object->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
2561 object->IWMLanguageList_iface.lpVtbl = &language_list_vtbl;
2562 object->IWMPacketSize2_iface.lpVtbl = &packet_size_vtbl;
2563 object->IWMProfile3_iface.lpVtbl = &profile_vtbl;
2564 object->IWMReaderPlaylistBurn_iface.lpVtbl = &playlist_vtbl;
2565 object->IWMReaderTimecode_iface.lpVtbl = &timecode_vtbl;
2566 object->outer = outer ? outer : &object->IUnknown_inner;
2567 object->refcount = 1;
2569 InitializeCriticalSection(&object->cs);
2570 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": reader.cs");
2572 TRACE("Created reader %p.\n", object);
2573 *out = outer ? (void *)&object->IUnknown_inner : (void *)&object->IWMSyncReader2_iface;
2574 return S_OK;