winegstreamer: Convert MPEG-1 audio to a major type.
[wine.git] / dlls / winegstreamer / wm_reader.c
blob03adea8a318439118a2039026486c3d6d0feeb26
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"
21 WINE_DEFAULT_DEBUG_CHANNEL(wmvcore);
23 static struct wm_stream *get_stream_by_output_number(struct wm_reader *reader, DWORD output)
25 if (output < reader->stream_count)
26 return &reader->streams[output];
27 WARN("Invalid output number %lu.\n", output);
28 return NULL;
31 struct output_props
33 IWMOutputMediaProps IWMOutputMediaProps_iface;
34 LONG refcount;
36 AM_MEDIA_TYPE mt;
39 static inline struct output_props *impl_from_IWMOutputMediaProps(IWMOutputMediaProps *iface)
41 return CONTAINING_RECORD(iface, struct output_props, IWMOutputMediaProps_iface);
44 static HRESULT WINAPI output_props_QueryInterface(IWMOutputMediaProps *iface, REFIID iid, void **out)
46 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
48 TRACE("props %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
50 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IWMOutputMediaProps))
51 *out = &props->IWMOutputMediaProps_iface;
52 else
54 *out = NULL;
55 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
56 return E_NOINTERFACE;
59 IUnknown_AddRef((IUnknown *)*out);
60 return S_OK;
63 static ULONG WINAPI output_props_AddRef(IWMOutputMediaProps *iface)
65 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
66 ULONG refcount = InterlockedIncrement(&props->refcount);
68 TRACE("%p increasing refcount to %lu.\n", props, refcount);
70 return refcount;
73 static ULONG WINAPI output_props_Release(IWMOutputMediaProps *iface)
75 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
76 ULONG refcount = InterlockedDecrement(&props->refcount);
78 TRACE("%p decreasing refcount to %lu.\n", props, refcount);
80 if (!refcount)
81 free(props);
83 return refcount;
86 static HRESULT WINAPI output_props_GetType(IWMOutputMediaProps *iface, GUID *major_type)
88 const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
90 TRACE("iface %p, major_type %p.\n", iface, major_type);
92 *major_type = props->mt.majortype;
93 return S_OK;
96 static HRESULT WINAPI output_props_GetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt, DWORD *size)
98 const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
99 const DWORD req_size = *size;
101 TRACE("iface %p, mt %p, size %p.\n", iface, mt, size);
103 *size = sizeof(*mt) + props->mt.cbFormat;
104 if (!mt)
105 return S_OK;
106 if (req_size < *size)
107 return ASF_E_BUFFERTOOSMALL;
109 strmbase_dump_media_type(&props->mt);
111 memcpy(mt, &props->mt, sizeof(*mt));
112 memcpy(mt + 1, props->mt.pbFormat, props->mt.cbFormat);
113 mt->pbFormat = (BYTE *)(mt + 1);
114 return S_OK;
117 static HRESULT WINAPI output_props_SetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt)
119 FIXME("iface %p, mt %p, stub!\n", iface, mt);
120 return E_NOTIMPL;
123 static HRESULT WINAPI output_props_GetStreamGroupName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
125 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
126 return E_NOTIMPL;
129 static HRESULT WINAPI output_props_GetConnectionName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
131 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
132 return E_NOTIMPL;
135 static const struct IWMOutputMediaPropsVtbl output_props_vtbl =
137 output_props_QueryInterface,
138 output_props_AddRef,
139 output_props_Release,
140 output_props_GetType,
141 output_props_GetMediaType,
142 output_props_SetMediaType,
143 output_props_GetStreamGroupName,
144 output_props_GetConnectionName,
147 static struct output_props *unsafe_impl_from_IWMOutputMediaProps(IWMOutputMediaProps *iface)
149 if (!iface)
150 return NULL;
151 assert(iface->lpVtbl == &output_props_vtbl);
152 return impl_from_IWMOutputMediaProps(iface);
155 static IWMOutputMediaProps *output_props_create(const struct wg_format *format)
157 struct output_props *object;
159 if (!(object = calloc(1, sizeof(*object))))
160 return NULL;
161 object->IWMOutputMediaProps_iface.lpVtbl = &output_props_vtbl;
162 object->refcount = 1;
164 if (!amt_from_wg_format(&object->mt, format, true))
166 free(object);
167 return NULL;
170 TRACE("Created output properties %p.\n", object);
171 return &object->IWMOutputMediaProps_iface;
174 struct buffer
176 INSSBuffer INSSBuffer_iface;
177 LONG refcount;
179 DWORD size, capacity;
180 BYTE data[1];
183 static struct buffer *impl_from_INSSBuffer(INSSBuffer *iface)
185 return CONTAINING_RECORD(iface, struct buffer, INSSBuffer_iface);
188 static HRESULT WINAPI buffer_QueryInterface(INSSBuffer *iface, REFIID iid, void **out)
190 struct buffer *buffer = impl_from_INSSBuffer(iface);
192 TRACE("buffer %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
194 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_INSSBuffer))
195 *out = &buffer->INSSBuffer_iface;
196 else
198 *out = NULL;
199 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
200 return E_NOINTERFACE;
203 IUnknown_AddRef((IUnknown *)*out);
204 return S_OK;
207 static ULONG WINAPI buffer_AddRef(INSSBuffer *iface)
209 struct buffer *buffer = impl_from_INSSBuffer(iface);
210 ULONG refcount = InterlockedIncrement(&buffer->refcount);
212 TRACE("%p increasing refcount to %lu.\n", buffer, refcount);
214 return refcount;
217 static ULONG WINAPI buffer_Release(INSSBuffer *iface)
219 struct buffer *buffer = impl_from_INSSBuffer(iface);
220 ULONG refcount = InterlockedDecrement(&buffer->refcount);
222 TRACE("%p decreasing refcount to %lu.\n", buffer, refcount);
224 if (!refcount)
225 free(buffer);
227 return refcount;
230 static HRESULT WINAPI buffer_GetLength(INSSBuffer *iface, DWORD *size)
232 FIXME("iface %p, size %p, stub!\n", iface, size);
233 return E_NOTIMPL;
236 static HRESULT WINAPI buffer_SetLength(INSSBuffer *iface, DWORD size)
238 struct buffer *buffer = impl_from_INSSBuffer(iface);
240 TRACE("iface %p, size %lu.\n", buffer, size);
242 if (size > buffer->capacity)
243 return E_INVALIDARG;
245 buffer->size = size;
246 return S_OK;
249 static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size)
251 struct buffer *buffer = impl_from_INSSBuffer(iface);
253 TRACE("buffer %p, size %p.\n", buffer, size);
255 *size = buffer->capacity;
256 return S_OK;
259 static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data)
261 struct buffer *buffer = impl_from_INSSBuffer(iface);
263 TRACE("buffer %p, data %p.\n", buffer, data);
265 *data = buffer->data;
266 return S_OK;
269 static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size)
271 struct buffer *buffer = impl_from_INSSBuffer(iface);
273 TRACE("buffer %p, data %p, size %p.\n", buffer, data, size);
275 *size = buffer->size;
276 *data = buffer->data;
277 return S_OK;
280 static const INSSBufferVtbl buffer_vtbl =
282 buffer_QueryInterface,
283 buffer_AddRef,
284 buffer_Release,
285 buffer_GetLength,
286 buffer_SetLength,
287 buffer_GetMaxLength,
288 buffer_GetBuffer,
289 buffer_GetBufferAndLength,
292 struct stream_config
294 IWMStreamConfig IWMStreamConfig_iface;
295 IWMMediaProps IWMMediaProps_iface;
296 LONG refcount;
298 const struct wm_stream *stream;
301 static struct stream_config *impl_from_IWMStreamConfig(IWMStreamConfig *iface)
303 return CONTAINING_RECORD(iface, struct stream_config, IWMStreamConfig_iface);
306 static HRESULT WINAPI stream_config_QueryInterface(IWMStreamConfig *iface, REFIID iid, void **out)
308 struct stream_config *config = impl_from_IWMStreamConfig(iface);
310 TRACE("config %p, iid %s, out %p.\n", config, debugstr_guid(iid), out);
312 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IWMStreamConfig))
313 *out = &config->IWMStreamConfig_iface;
314 else if (IsEqualGUID(iid, &IID_IWMMediaProps))
315 *out = &config->IWMMediaProps_iface;
316 else
318 *out = NULL;
319 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
320 return E_NOINTERFACE;
323 IUnknown_AddRef((IUnknown *)*out);
324 return S_OK;
327 static ULONG WINAPI stream_config_AddRef(IWMStreamConfig *iface)
329 struct stream_config *config = impl_from_IWMStreamConfig(iface);
330 ULONG refcount = InterlockedIncrement(&config->refcount);
332 TRACE("%p increasing refcount to %lu.\n", config, refcount);
334 return refcount;
337 static ULONG WINAPI stream_config_Release(IWMStreamConfig *iface)
339 struct stream_config *config = impl_from_IWMStreamConfig(iface);
340 ULONG refcount = InterlockedDecrement(&config->refcount);
342 TRACE("%p decreasing refcount to %lu.\n", config, refcount);
344 if (!refcount)
346 IWMProfile3_Release(&config->stream->reader->IWMProfile3_iface);
347 free(config);
350 return refcount;
353 static HRESULT WINAPI stream_config_GetStreamType(IWMStreamConfig *iface, GUID *type)
355 struct stream_config *config = impl_from_IWMStreamConfig(iface);
356 struct wm_reader *reader = config->stream->reader;
357 AM_MEDIA_TYPE mt;
359 TRACE("config %p, type %p.\n", config, type);
361 EnterCriticalSection(&reader->cs);
363 if (!amt_from_wg_format(&mt, &config->stream->format, true))
365 LeaveCriticalSection(&reader->cs);
366 return E_OUTOFMEMORY;
369 *type = mt.majortype;
370 FreeMediaType(&mt);
372 LeaveCriticalSection(&reader->cs);
374 return S_OK;
377 static HRESULT WINAPI stream_config_GetStreamNumber(IWMStreamConfig *iface, WORD *number)
379 struct stream_config *config = impl_from_IWMStreamConfig(iface);
381 TRACE("config %p, number %p.\n", config, number);
383 *number = config->stream->index + 1;
384 return S_OK;
387 static HRESULT WINAPI stream_config_SetStreamNumber(IWMStreamConfig *iface, WORD number)
389 FIXME("iface %p, number %u, stub!\n", iface, number);
390 return E_NOTIMPL;
393 static HRESULT WINAPI stream_config_GetStreamName(IWMStreamConfig *iface, WCHAR *name, WORD *len)
395 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
396 return E_NOTIMPL;
399 static HRESULT WINAPI stream_config_SetStreamName(IWMStreamConfig *iface, const WCHAR *name)
401 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
402 return E_NOTIMPL;
405 static HRESULT WINAPI stream_config_GetConnectionName(IWMStreamConfig *iface, WCHAR *name, WORD *len)
407 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
408 return E_NOTIMPL;
411 static HRESULT WINAPI stream_config_SetConnectionName(IWMStreamConfig *iface, const WCHAR *name)
413 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
414 return E_NOTIMPL;
417 static HRESULT WINAPI stream_config_GetBitrate(IWMStreamConfig *iface, DWORD *bitrate)
419 FIXME("iface %p, bitrate %p, stub!\n", iface, bitrate);
420 return E_NOTIMPL;
423 static HRESULT WINAPI stream_config_SetBitrate(IWMStreamConfig *iface, DWORD bitrate)
425 FIXME("iface %p, bitrate %lu, stub!\n", iface, bitrate);
426 return E_NOTIMPL;
429 static HRESULT WINAPI stream_config_GetBufferWindow(IWMStreamConfig *iface, DWORD *window)
431 FIXME("iface %p, window %p, stub!\n", iface, window);
432 return E_NOTIMPL;
435 static HRESULT WINAPI stream_config_SetBufferWindow(IWMStreamConfig *iface, DWORD window)
437 FIXME("iface %p, window %lu, stub!\n", iface, window);
438 return E_NOTIMPL;
441 static const IWMStreamConfigVtbl stream_config_vtbl =
443 stream_config_QueryInterface,
444 stream_config_AddRef,
445 stream_config_Release,
446 stream_config_GetStreamType,
447 stream_config_GetStreamNumber,
448 stream_config_SetStreamNumber,
449 stream_config_GetStreamName,
450 stream_config_SetStreamName,
451 stream_config_GetConnectionName,
452 stream_config_SetConnectionName,
453 stream_config_GetBitrate,
454 stream_config_SetBitrate,
455 stream_config_GetBufferWindow,
456 stream_config_SetBufferWindow,
459 static struct stream_config *impl_from_IWMMediaProps(IWMMediaProps *iface)
461 return CONTAINING_RECORD(iface, struct stream_config, IWMMediaProps_iface);
464 static HRESULT WINAPI stream_props_QueryInterface(IWMMediaProps *iface, REFIID iid, void **out)
466 struct stream_config *config = impl_from_IWMMediaProps(iface);
467 return IWMStreamConfig_QueryInterface(&config->IWMStreamConfig_iface, iid, out);
470 static ULONG WINAPI stream_props_AddRef(IWMMediaProps *iface)
472 struct stream_config *config = impl_from_IWMMediaProps(iface);
473 return IWMStreamConfig_AddRef(&config->IWMStreamConfig_iface);
476 static ULONG WINAPI stream_props_Release(IWMMediaProps *iface)
478 struct stream_config *config = impl_from_IWMMediaProps(iface);
479 return IWMStreamConfig_Release(&config->IWMStreamConfig_iface);
482 static HRESULT WINAPI stream_props_GetType(IWMMediaProps *iface, GUID *major_type)
484 FIXME("iface %p, major_type %p, stub!\n", iface, major_type);
485 return E_NOTIMPL;
488 static HRESULT WINAPI stream_props_GetMediaType(IWMMediaProps *iface, WM_MEDIA_TYPE *mt, DWORD *size)
490 struct stream_config *config = impl_from_IWMMediaProps(iface);
491 const DWORD req_size = *size;
492 AM_MEDIA_TYPE stream_mt;
494 TRACE("iface %p, mt %p, size %p.\n", iface, mt, size);
496 if (!amt_from_wg_format(&stream_mt, &config->stream->format, true))
497 return E_OUTOFMEMORY;
499 *size = sizeof(stream_mt) + stream_mt.cbFormat;
500 if (!mt)
501 return S_OK;
502 if (req_size < *size)
503 return ASF_E_BUFFERTOOSMALL;
505 strmbase_dump_media_type(&stream_mt);
507 memcpy(mt, &stream_mt, sizeof(*mt));
508 memcpy(mt + 1, stream_mt.pbFormat, stream_mt.cbFormat);
509 mt->pbFormat = (BYTE *)(mt + 1);
510 return S_OK;
513 static HRESULT WINAPI stream_props_SetMediaType(IWMMediaProps *iface, WM_MEDIA_TYPE *mt)
515 FIXME("iface %p, mt %p, stub!\n", iface, mt);
516 return E_NOTIMPL;
519 static const IWMMediaPropsVtbl stream_props_vtbl =
521 stream_props_QueryInterface,
522 stream_props_AddRef,
523 stream_props_Release,
524 stream_props_GetType,
525 stream_props_GetMediaType,
526 stream_props_SetMediaType,
529 static DWORD CALLBACK read_thread(void *arg)
531 struct wm_reader *reader = arg;
532 IStream *stream = reader->source_stream;
533 HANDLE file = reader->file;
534 size_t buffer_size = 4096;
535 uint64_t file_size;
536 void *data;
538 if (!(data = malloc(buffer_size)))
539 return 0;
541 if (file)
543 LARGE_INTEGER size;
545 GetFileSizeEx(file, &size);
546 file_size = size.QuadPart;
548 else
550 STATSTG stat;
552 IStream_Stat(stream, &stat, STATFLAG_NONAME);
553 file_size = stat.cbSize.QuadPart;
556 TRACE("Starting read thread for reader %p.\n", reader);
558 while (!reader->read_thread_shutdown)
560 LARGE_INTEGER large_offset;
561 uint64_t offset;
562 ULONG ret_size;
563 uint32_t size;
564 HRESULT hr;
566 if (!wg_parser_get_next_read_offset(reader->wg_parser, &offset, &size))
567 continue;
569 if (offset >= file_size)
570 size = 0;
571 else if (offset + size >= file_size)
572 size = file_size - offset;
574 if (!size)
576 wg_parser_push_data(reader->wg_parser, data, 0);
577 continue;
580 if (!array_reserve(&data, &buffer_size, size, 1))
582 free(data);
583 return 0;
586 ret_size = 0;
588 large_offset.QuadPart = offset;
589 if (file)
591 if (!SetFilePointerEx(file, large_offset, NULL, FILE_BEGIN)
592 || !ReadFile(file, data, size, &ret_size, NULL))
594 ERR("Failed to read %u bytes at offset %I64u, error %lu.\n", size, offset, GetLastError());
595 wg_parser_push_data(reader->wg_parser, NULL, 0);
596 continue;
599 else
601 if (SUCCEEDED(hr = IStream_Seek(stream, large_offset, STREAM_SEEK_SET, NULL)))
602 hr = IStream_Read(stream, data, size, &ret_size);
603 if (FAILED(hr))
605 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr);
606 wg_parser_push_data(reader->wg_parser, NULL, 0);
607 continue;
611 if (ret_size != size)
612 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size);
613 wg_parser_push_data(reader->wg_parser, data, ret_size);
616 free(data);
617 TRACE("Reader is shutting down; exiting.\n");
618 return 0;
621 static struct wm_reader *impl_from_IWMProfile3(IWMProfile3 *iface)
623 return CONTAINING_RECORD(iface, struct wm_reader, IWMProfile3_iface);
626 static HRESULT WINAPI profile_QueryInterface(IWMProfile3 *iface, REFIID iid, void **out)
628 struct wm_reader *reader = impl_from_IWMProfile3(iface);
630 TRACE("reader %p, iid %s, out %p.\n", reader, debugstr_guid(iid), out);
632 if (IsEqualIID(iid, &IID_IWMHeaderInfo)
633 || IsEqualIID(iid, &IID_IWMHeaderInfo2)
634 || IsEqualIID(iid, &IID_IWMHeaderInfo3))
636 *out = &reader->IWMHeaderInfo3_iface;
638 else if (IsEqualIID(iid, &IID_IWMLanguageList))
640 *out = &reader->IWMLanguageList_iface;
642 else if (IsEqualIID(iid, &IID_IWMPacketSize)
643 || IsEqualIID(iid, &IID_IWMPacketSize2))
645 *out = &reader->IWMPacketSize2_iface;
647 else if (IsEqualIID(iid, &IID_IUnknown)
648 || IsEqualIID(iid, &IID_IWMProfile)
649 || IsEqualIID(iid, &IID_IWMProfile2)
650 || IsEqualIID(iid, &IID_IWMProfile3))
652 *out = &reader->IWMProfile3_iface;
654 else if (IsEqualIID(iid, &IID_IWMReaderPlaylistBurn))
656 *out = &reader->IWMReaderPlaylistBurn_iface;
658 else if (IsEqualIID(iid, &IID_IWMReaderTimecode))
660 *out = &reader->IWMReaderTimecode_iface;
662 else if (!(*out = reader->ops->query_interface(reader, iid)))
664 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
665 return E_NOINTERFACE;
668 IUnknown_AddRef((IUnknown *)*out);
669 return S_OK;
672 static ULONG WINAPI profile_AddRef(IWMProfile3 *iface)
674 struct wm_reader *reader = impl_from_IWMProfile3(iface);
675 ULONG refcount = InterlockedIncrement(&reader->refcount);
677 TRACE("%p increasing refcount to %lu.\n", reader, refcount);
679 return refcount;
682 static ULONG WINAPI profile_Release(IWMProfile3 *iface)
684 struct wm_reader *reader = impl_from_IWMProfile3(iface);
685 ULONG refcount = InterlockedDecrement(&reader->refcount);
687 TRACE("%p decreasing refcount to %lu.\n", reader, refcount);
689 if (!refcount)
690 reader->ops->destroy(reader);
692 return refcount;
695 static HRESULT WINAPI profile_GetVersion(IWMProfile3 *iface, WMT_VERSION *version)
697 FIXME("iface %p, version %p, stub!\n", iface, version);
698 return E_NOTIMPL;
701 static HRESULT WINAPI profile_GetName(IWMProfile3 *iface, WCHAR *name, DWORD *length)
703 FIXME("iface %p, name %p, length %p, stub!\n", iface, name, length);
704 return E_NOTIMPL;
707 static HRESULT WINAPI profile_SetName(IWMProfile3 *iface, const WCHAR *name)
709 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
710 return E_NOTIMPL;
713 static HRESULT WINAPI profile_GetDescription(IWMProfile3 *iface, WCHAR *description, DWORD *length)
715 FIXME("iface %p, description %p, length %p, stub!\n", iface, description, length);
716 return E_NOTIMPL;
719 static HRESULT WINAPI profile_SetDescription(IWMProfile3 *iface, const WCHAR *description)
721 FIXME("iface %p, description %s, stub!\n", iface, debugstr_w(description));
722 return E_NOTIMPL;
725 static HRESULT WINAPI profile_GetStreamCount(IWMProfile3 *iface, DWORD *count)
727 struct wm_reader *reader = impl_from_IWMProfile3(iface);
729 TRACE("reader %p, count %p.\n", reader, count);
731 if (!count)
732 return E_INVALIDARG;
734 EnterCriticalSection(&reader->cs);
735 *count = reader->stream_count;
736 LeaveCriticalSection(&reader->cs);
737 return S_OK;
740 static HRESULT WINAPI profile_GetStream(IWMProfile3 *iface, DWORD index, IWMStreamConfig **config)
742 struct wm_reader *reader = impl_from_IWMProfile3(iface);
743 struct stream_config *object;
745 TRACE("reader %p, index %lu, config %p.\n", reader, index, config);
747 EnterCriticalSection(&reader->cs);
749 if (index >= reader->stream_count)
751 LeaveCriticalSection(&reader->cs);
752 WARN("Index %lu exceeds stream count %u; returning E_INVALIDARG.\n", index, reader->stream_count);
753 return E_INVALIDARG;
756 if (!(object = calloc(1, sizeof(*object))))
758 LeaveCriticalSection(&reader->cs);
759 return E_OUTOFMEMORY;
762 object->IWMStreamConfig_iface.lpVtbl = &stream_config_vtbl;
763 object->IWMMediaProps_iface.lpVtbl = &stream_props_vtbl;
764 object->refcount = 1;
765 object->stream = &reader->streams[index];
766 IWMProfile3_AddRef(&reader->IWMProfile3_iface);
768 LeaveCriticalSection(&reader->cs);
770 TRACE("Created stream config %p.\n", object);
771 *config = &object->IWMStreamConfig_iface;
772 return S_OK;
775 static HRESULT WINAPI profile_GetStreamByNumber(IWMProfile3 *iface, WORD stream_number, IWMStreamConfig **config)
777 FIXME("iface %p, stream_number %u, config %p, stub!\n", iface, stream_number, config);
778 return E_NOTIMPL;
781 static HRESULT WINAPI profile_RemoveStream(IWMProfile3 *iface, IWMStreamConfig *config)
783 FIXME("iface %p, config %p, stub!\n", iface, config);
784 return E_NOTIMPL;
787 static HRESULT WINAPI profile_RemoveStreamByNumber(IWMProfile3 *iface, WORD stream_number)
789 FIXME("iface %p, stream_number %u, stub!\n", iface, stream_number);
790 return E_NOTIMPL;
793 static HRESULT WINAPI profile_AddStream(IWMProfile3 *iface, IWMStreamConfig *config)
795 FIXME("iface %p, config %p, stub!\n", iface, config);
796 return E_NOTIMPL;
799 static HRESULT WINAPI profile_ReconfigStream(IWMProfile3 *iface, IWMStreamConfig *config)
801 FIXME("iface %p, config %p, stub!\n", iface, config);
802 return E_NOTIMPL;
805 static HRESULT WINAPI profile_CreateNewStream(IWMProfile3 *iface, REFGUID type, IWMStreamConfig **config)
807 FIXME("iface %p, type %s, config %p, stub!\n", iface, debugstr_guid(type), config);
808 return E_NOTIMPL;
811 static HRESULT WINAPI profile_GetMutualExclusionCount(IWMProfile3 *iface, DWORD *count)
813 FIXME("iface %p, count %p, stub!\n", iface, count);
814 return E_NOTIMPL;
817 static HRESULT WINAPI profile_GetMutualExclusion(IWMProfile3 *iface, DWORD index, IWMMutualExclusion **excl)
819 FIXME("iface %p, index %lu, excl %p, stub!\n", iface, index, excl);
820 return E_NOTIMPL;
823 static HRESULT WINAPI profile_RemoveMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
825 FIXME("iface %p, excl %p, stub!\n", iface, excl);
826 return E_NOTIMPL;
829 static HRESULT WINAPI profile_AddMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
831 FIXME("iface %p, excl %p, stub!\n", iface, excl);
832 return E_NOTIMPL;
835 static HRESULT WINAPI profile_CreateNewMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion **excl)
837 FIXME("iface %p, excl %p, stub!\n", iface, excl);
838 return E_NOTIMPL;
841 static HRESULT WINAPI profile_GetProfileID(IWMProfile3 *iface, GUID *id)
843 FIXME("iface %p, id %p, stub!\n", iface, id);
844 return E_NOTIMPL;
847 static HRESULT WINAPI profile_GetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT *format)
849 FIXME("iface %p, format %p, stub!\n", iface, format);
850 return E_NOTIMPL;
853 static HRESULT WINAPI profile_SetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT format)
855 FIXME("iface %p, format %#x, stub!\n", iface, format);
856 return E_NOTIMPL;
859 static HRESULT WINAPI profile_GetBandwidthSharingCount(IWMProfile3 *iface, DWORD *count)
861 FIXME("iface %p, count %p, stub!\n", iface, count);
862 return E_NOTIMPL;
865 static HRESULT WINAPI profile_GetBandwidthSharing(IWMProfile3 *iface, DWORD index, IWMBandwidthSharing **sharing)
867 FIXME("iface %p, index %lu, sharing %p, stub!\n", iface, index, sharing);
868 return E_NOTIMPL;
871 static HRESULT WINAPI profile_RemoveBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing *sharing)
873 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
874 return E_NOTIMPL;
877 static HRESULT WINAPI profile_AddBandwidthSharing(IWMProfile3 *iface, IWMBandwidthSharing *sharing)
879 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
880 return E_NOTIMPL;
883 static HRESULT WINAPI profile_CreateNewBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing **sharing)
885 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
886 return E_NOTIMPL;
889 static HRESULT WINAPI profile_GetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
891 FIXME("iface %p, stream %p, stub!\n", iface, stream);
892 return E_NOTIMPL;
895 static HRESULT WINAPI profile_SetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization *stream)
897 FIXME("iface %p, stream %p, stub!\n", iface, stream);
898 return E_NOTIMPL;
901 static HRESULT WINAPI profile_RemoveStreamPrioritization(IWMProfile3 *iface)
903 FIXME("iface %p, stub!\n", iface);
904 return E_NOTIMPL;
907 static HRESULT WINAPI profile_CreateNewStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
909 FIXME("iface %p, stream %p, stub!\n", iface, stream);
910 return E_NOTIMPL;
913 static HRESULT WINAPI profile_GetExpectedPacketCount(IWMProfile3 *iface, QWORD duration, QWORD *count)
915 FIXME("iface %p, duration %s, count %p, stub!\n", iface, debugstr_time(duration), count);
916 return E_NOTIMPL;
919 static const IWMProfile3Vtbl profile_vtbl =
921 profile_QueryInterface,
922 profile_AddRef,
923 profile_Release,
924 profile_GetVersion,
925 profile_GetName,
926 profile_SetName,
927 profile_GetDescription,
928 profile_SetDescription,
929 profile_GetStreamCount,
930 profile_GetStream,
931 profile_GetStreamByNumber,
932 profile_RemoveStream,
933 profile_RemoveStreamByNumber,
934 profile_AddStream,
935 profile_ReconfigStream,
936 profile_CreateNewStream,
937 profile_GetMutualExclusionCount,
938 profile_GetMutualExclusion,
939 profile_RemoveMutualExclusion,
940 profile_AddMutualExclusion,
941 profile_CreateNewMutualExclusion,
942 profile_GetProfileID,
943 profile_GetStorageFormat,
944 profile_SetStorageFormat,
945 profile_GetBandwidthSharingCount,
946 profile_GetBandwidthSharing,
947 profile_RemoveBandwidthSharing,
948 profile_AddBandwidthSharing,
949 profile_CreateNewBandwidthSharing,
950 profile_GetStreamPrioritization,
951 profile_SetStreamPrioritization,
952 profile_RemoveStreamPrioritization,
953 profile_CreateNewStreamPrioritization,
954 profile_GetExpectedPacketCount,
957 static struct wm_reader *impl_from_IWMHeaderInfo3(IWMHeaderInfo3 *iface)
959 return CONTAINING_RECORD(iface, struct wm_reader, IWMHeaderInfo3_iface);
962 static HRESULT WINAPI header_info_QueryInterface(IWMHeaderInfo3 *iface, REFIID iid, void **out)
964 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
966 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
969 static ULONG WINAPI header_info_AddRef(IWMHeaderInfo3 *iface)
971 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
973 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
976 static ULONG WINAPI header_info_Release(IWMHeaderInfo3 *iface)
978 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
980 return IWMProfile3_Release(&reader->IWMProfile3_iface);
983 static HRESULT WINAPI header_info_GetAttributeCount(IWMHeaderInfo3 *iface, WORD stream_number, WORD *count)
985 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
986 return E_NOTIMPL;
989 static HRESULT WINAPI header_info_GetAttributeByIndex(IWMHeaderInfo3 *iface, WORD index, WORD *stream_number,
990 WCHAR *name, WORD *name_len, WMT_ATTR_DATATYPE *type, BYTE *value, WORD *size)
992 FIXME("iface %p, index %u, stream_number %p, name %p, name_len %p, type %p, value %p, size %p, stub!\n",
993 iface, index, stream_number, name, name_len, type, value, size);
994 return E_NOTIMPL;
997 static HRESULT WINAPI header_info_GetAttributeByName(IWMHeaderInfo3 *iface, WORD *stream_number,
998 const WCHAR *name, WMT_ATTR_DATATYPE *type, BYTE *value, WORD *size)
1000 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
1001 const WORD req_size = *size;
1003 TRACE("reader %p, stream_number %p, name %s, type %p, value %p, size %u.\n",
1004 reader, stream_number, debugstr_w(name), type, value, *size);
1006 if (!stream_number)
1007 return E_INVALIDARG;
1009 if (!wcscmp(name, L"Duration"))
1011 QWORD duration;
1013 if (*stream_number)
1015 WARN("Requesting duration for stream %u, returning ASF_E_NOTFOUND.\n", *stream_number);
1016 return ASF_E_NOTFOUND;
1019 *size = sizeof(QWORD);
1020 if (!value)
1022 *type = WMT_TYPE_QWORD;
1023 return S_OK;
1025 if (req_size < *size)
1026 return ASF_E_BUFFERTOOSMALL;
1028 *type = WMT_TYPE_QWORD;
1029 EnterCriticalSection(&reader->cs);
1030 duration = wg_parser_stream_get_duration(wg_parser_get_stream(reader->wg_parser, 0));
1031 LeaveCriticalSection(&reader->cs);
1032 TRACE("Returning duration %s.\n", debugstr_time(duration));
1033 memcpy(value, &duration, sizeof(QWORD));
1034 return S_OK;
1036 else if (!wcscmp(name, L"Seekable"))
1038 if (*stream_number)
1040 WARN("Requesting duration for stream %u, returning ASF_E_NOTFOUND.\n", *stream_number);
1041 return ASF_E_NOTFOUND;
1044 *size = sizeof(BOOL);
1045 if (!value)
1047 *type = WMT_TYPE_BOOL;
1048 return S_OK;
1050 if (req_size < *size)
1051 return ASF_E_BUFFERTOOSMALL;
1053 *type = WMT_TYPE_BOOL;
1054 *(BOOL *)value = TRUE;
1055 return S_OK;
1057 else
1059 FIXME("Unknown attribute %s.\n", debugstr_w(name));
1060 return ASF_E_NOTFOUND;
1064 static HRESULT WINAPI header_info_SetAttribute(IWMHeaderInfo3 *iface, WORD stream_number,
1065 const WCHAR *name, WMT_ATTR_DATATYPE type, const BYTE *value, WORD size)
1067 FIXME("iface %p, stream_number %u, name %s, type %#x, value %p, size %u, stub!\n",
1068 iface, stream_number, debugstr_w(name), type, value, size);
1069 return E_NOTIMPL;
1072 static HRESULT WINAPI header_info_GetMarkerCount(IWMHeaderInfo3 *iface, WORD *count)
1074 FIXME("iface %p, count %p, stub!\n", iface, count);
1075 return E_NOTIMPL;
1078 static HRESULT WINAPI header_info_GetMarker(IWMHeaderInfo3 *iface,
1079 WORD index, WCHAR *name, WORD *len, QWORD *time)
1081 FIXME("iface %p, index %u, name %p, len %p, time %p, stub!\n", iface, index, name, len, time);
1082 return E_NOTIMPL;
1085 static HRESULT WINAPI header_info_AddMarker(IWMHeaderInfo3 *iface, const WCHAR *name, QWORD time)
1087 FIXME("iface %p, name %s, time %s, stub!\n", iface, debugstr_w(name), debugstr_time(time));
1088 return E_NOTIMPL;
1091 static HRESULT WINAPI header_info_RemoveMarker(IWMHeaderInfo3 *iface, WORD index)
1093 FIXME("iface %p, index %u, stub!\n", iface, index);
1094 return E_NOTIMPL;
1097 static HRESULT WINAPI header_info_GetScriptCount(IWMHeaderInfo3 *iface, WORD *count)
1099 FIXME("iface %p, count %p, stub!\n", iface, count);
1100 return E_NOTIMPL;
1103 static HRESULT WINAPI header_info_GetScript(IWMHeaderInfo3 *iface, WORD index, WCHAR *type,
1104 WORD *type_len, WCHAR *command, WORD *command_len, QWORD *time)
1106 FIXME("iface %p, index %u, type %p, type_len %p, command %p, command_len %p, time %p, stub!\n",
1107 iface, index, type, type_len, command, command_len, time);
1108 return E_NOTIMPL;
1111 static HRESULT WINAPI header_info_AddScript(IWMHeaderInfo3 *iface,
1112 const WCHAR *type, const WCHAR *command, QWORD time)
1114 FIXME("iface %p, type %s, command %s, time %s, stub!\n",
1115 iface, debugstr_w(type), debugstr_w(command), debugstr_time(time));
1116 return E_NOTIMPL;
1119 static HRESULT WINAPI header_info_RemoveScript(IWMHeaderInfo3 *iface, WORD index)
1121 FIXME("iface %p, index %u, stub!\n", iface, index);
1122 return E_NOTIMPL;
1125 static HRESULT WINAPI header_info_GetCodecInfoCount(IWMHeaderInfo3 *iface, DWORD *count)
1127 FIXME("iface %p, count %p, stub!\n", iface, count);
1128 return E_NOTIMPL;
1131 static HRESULT WINAPI header_info_GetCodecInfo(IWMHeaderInfo3 *iface, DWORD index, WORD *name_len,
1132 WCHAR *name, WORD *desc_len, WCHAR *desc, WMT_CODEC_INFO_TYPE *type, WORD *size, BYTE *info)
1134 FIXME("iface %p, index %lu, name_len %p, name %p, desc_len %p, desc %p, type %p, size %p, info %p, stub!\n",
1135 iface, index, name_len, name, desc_len, desc, type, size, info);
1136 return E_NOTIMPL;
1139 static HRESULT WINAPI header_info_GetAttributeCountEx(IWMHeaderInfo3 *iface, WORD stream_number, WORD *count)
1141 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
1142 return E_NOTIMPL;
1145 static HRESULT WINAPI header_info_GetAttributeIndices(IWMHeaderInfo3 *iface, WORD stream_number,
1146 const WCHAR *name, WORD *lang_index, WORD *indices, WORD *count)
1148 FIXME("iface %p, stream_number %u, name %s, lang_index %p, indices %p, count %p, stub!\n",
1149 iface, stream_number, debugstr_w(name), lang_index, indices, count);
1150 return E_NOTIMPL;
1153 static HRESULT WINAPI header_info_GetAttributeByIndexEx(IWMHeaderInfo3 *iface,
1154 WORD stream_number, WORD index, WCHAR *name, WORD *name_len,
1155 WMT_ATTR_DATATYPE *type, WORD *lang_index, BYTE *value, DWORD *size)
1157 FIXME("iface %p, stream_number %u, index %u, name %p, name_len %p,"
1158 " type %p, lang_index %p, value %p, size %p, stub!\n",
1159 iface, stream_number, index, name, name_len, type, lang_index, value, size);
1160 return E_NOTIMPL;
1163 static HRESULT WINAPI header_info_ModifyAttribute(IWMHeaderInfo3 *iface, WORD stream_number,
1164 WORD index, WMT_ATTR_DATATYPE type, WORD lang_index, const BYTE *value, DWORD size)
1166 FIXME("iface %p, stream_number %u, index %u, type %#x, lang_index %u, value %p, size %lu, stub!\n",
1167 iface, stream_number, index, type, lang_index, value, size);
1168 return E_NOTIMPL;
1171 static HRESULT WINAPI header_info_AddAttribute(IWMHeaderInfo3 *iface,
1172 WORD stream_number, const WCHAR *name, WORD *index,
1173 WMT_ATTR_DATATYPE type, WORD lang_index, const BYTE *value, DWORD size)
1175 FIXME("iface %p, stream_number %u, name %s, index %p, type %#x, lang_index %u, value %p, size %lu, stub!\n",
1176 iface, stream_number, debugstr_w(name), index, type, lang_index, value, size);
1177 return E_NOTIMPL;
1180 static HRESULT WINAPI header_info_DeleteAttribute(IWMHeaderInfo3 *iface, WORD stream_number, WORD index)
1182 FIXME("iface %p, stream_number %u, index %u, stub!\n", iface, stream_number, index);
1183 return E_NOTIMPL;
1186 static HRESULT WINAPI header_info_AddCodecInfo(IWMHeaderInfo3 *iface, const WCHAR *name,
1187 const WCHAR *desc, WMT_CODEC_INFO_TYPE type, WORD size, BYTE *info)
1189 FIXME("iface %p, name %s, desc %s, type %#x, size %u, info %p, stub!\n",
1190 info, debugstr_w(name), debugstr_w(desc), type, size, info);
1191 return E_NOTIMPL;
1194 static const IWMHeaderInfo3Vtbl header_info_vtbl =
1196 header_info_QueryInterface,
1197 header_info_AddRef,
1198 header_info_Release,
1199 header_info_GetAttributeCount,
1200 header_info_GetAttributeByIndex,
1201 header_info_GetAttributeByName,
1202 header_info_SetAttribute,
1203 header_info_GetMarkerCount,
1204 header_info_GetMarker,
1205 header_info_AddMarker,
1206 header_info_RemoveMarker,
1207 header_info_GetScriptCount,
1208 header_info_GetScript,
1209 header_info_AddScript,
1210 header_info_RemoveScript,
1211 header_info_GetCodecInfoCount,
1212 header_info_GetCodecInfo,
1213 header_info_GetAttributeCountEx,
1214 header_info_GetAttributeIndices,
1215 header_info_GetAttributeByIndexEx,
1216 header_info_ModifyAttribute,
1217 header_info_AddAttribute,
1218 header_info_DeleteAttribute,
1219 header_info_AddCodecInfo,
1222 static struct wm_reader *impl_from_IWMLanguageList(IWMLanguageList *iface)
1224 return CONTAINING_RECORD(iface, struct wm_reader, IWMLanguageList_iface);
1227 static HRESULT WINAPI language_list_QueryInterface(IWMLanguageList *iface, REFIID iid, void **out)
1229 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1231 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
1234 static ULONG WINAPI language_list_AddRef(IWMLanguageList *iface)
1236 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1238 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
1241 static ULONG WINAPI language_list_Release(IWMLanguageList *iface)
1243 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1245 return IWMProfile3_Release(&reader->IWMProfile3_iface);
1248 static HRESULT WINAPI language_list_GetLanguageCount(IWMLanguageList *iface, WORD *count)
1250 FIXME("iface %p, count %p, stub!\n", iface, count);
1251 return E_NOTIMPL;
1254 static HRESULT WINAPI language_list_GetLanguageDetails(IWMLanguageList *iface,
1255 WORD index, WCHAR *lang, WORD *len)
1257 FIXME("iface %p, index %u, lang %p, len %p, stub!\n", iface, index, lang, len);
1258 return E_NOTIMPL;
1261 static HRESULT WINAPI language_list_AddLanguageByRFC1766String(IWMLanguageList *iface,
1262 const WCHAR *lang, WORD *index)
1264 FIXME("iface %p, lang %s, index %p, stub!\n", iface, debugstr_w(lang), index);
1265 return E_NOTIMPL;
1268 static const IWMLanguageListVtbl language_list_vtbl =
1270 language_list_QueryInterface,
1271 language_list_AddRef,
1272 language_list_Release,
1273 language_list_GetLanguageCount,
1274 language_list_GetLanguageDetails,
1275 language_list_AddLanguageByRFC1766String,
1278 static struct wm_reader *impl_from_IWMPacketSize2(IWMPacketSize2 *iface)
1280 return CONTAINING_RECORD(iface, struct wm_reader, IWMPacketSize2_iface);
1283 static HRESULT WINAPI packet_size_QueryInterface(IWMPacketSize2 *iface, REFIID iid, void **out)
1285 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1287 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
1290 static ULONG WINAPI packet_size_AddRef(IWMPacketSize2 *iface)
1292 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1294 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
1297 static ULONG WINAPI packet_size_Release(IWMPacketSize2 *iface)
1299 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1301 return IWMProfile3_Release(&reader->IWMProfile3_iface);
1304 static HRESULT WINAPI packet_size_GetMaxPacketSize(IWMPacketSize2 *iface, DWORD *size)
1306 FIXME("iface %p, size %p, stub!\n", iface, size);
1307 return E_NOTIMPL;
1310 static HRESULT WINAPI packet_size_SetMaxPacketSize(IWMPacketSize2 *iface, DWORD size)
1312 FIXME("iface %p, size %lu, stub!\n", iface, size);
1313 return E_NOTIMPL;
1316 static HRESULT WINAPI packet_size_GetMinPacketSize(IWMPacketSize2 *iface, DWORD *size)
1318 FIXME("iface %p, size %p, stub!\n", iface, size);
1319 return E_NOTIMPL;
1322 static HRESULT WINAPI packet_size_SetMinPacketSize(IWMPacketSize2 *iface, DWORD size)
1324 FIXME("iface %p, size %lu, stub!\n", iface, size);
1325 return E_NOTIMPL;
1328 static const IWMPacketSize2Vtbl packet_size_vtbl =
1330 packet_size_QueryInterface,
1331 packet_size_AddRef,
1332 packet_size_Release,
1333 packet_size_GetMaxPacketSize,
1334 packet_size_SetMaxPacketSize,
1335 packet_size_GetMinPacketSize,
1336 packet_size_SetMinPacketSize,
1339 static struct wm_reader *impl_from_IWMReaderPlaylistBurn(IWMReaderPlaylistBurn *iface)
1341 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderPlaylistBurn_iface);
1344 static HRESULT WINAPI playlist_QueryInterface(IWMReaderPlaylistBurn *iface, REFIID iid, void **out)
1346 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1348 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
1351 static ULONG WINAPI playlist_AddRef(IWMReaderPlaylistBurn *iface)
1353 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1355 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
1358 static ULONG WINAPI playlist_Release(IWMReaderPlaylistBurn *iface)
1360 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1362 return IWMProfile3_Release(&reader->IWMProfile3_iface);
1365 static HRESULT WINAPI playlist_InitPlaylistBurn(IWMReaderPlaylistBurn *iface, DWORD count,
1366 const WCHAR **filenames, IWMStatusCallback *callback, void *context)
1368 FIXME("iface %p, count %lu, filenames %p, callback %p, context %p, stub!\n",
1369 iface, count, filenames, callback, context);
1370 return E_NOTIMPL;
1373 static HRESULT WINAPI playlist_GetInitResults(IWMReaderPlaylistBurn *iface, DWORD count, HRESULT *hrs)
1375 FIXME("iface %p, count %lu, hrs %p, stub!\n", iface, count, hrs);
1376 return E_NOTIMPL;
1379 static HRESULT WINAPI playlist_Cancel(IWMReaderPlaylistBurn *iface)
1381 FIXME("iface %p, stub!\n", iface);
1382 return E_NOTIMPL;
1385 static HRESULT WINAPI playlist_EndPlaylistBurn(IWMReaderPlaylistBurn *iface, HRESULT hr)
1387 FIXME("iface %p, hr %#lx, stub!\n", iface, hr);
1388 return E_NOTIMPL;
1391 static const IWMReaderPlaylistBurnVtbl playlist_vtbl =
1393 playlist_QueryInterface,
1394 playlist_AddRef,
1395 playlist_Release,
1396 playlist_InitPlaylistBurn,
1397 playlist_GetInitResults,
1398 playlist_Cancel,
1399 playlist_EndPlaylistBurn,
1402 static struct wm_reader *impl_from_IWMReaderTimecode(IWMReaderTimecode *iface)
1404 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderTimecode_iface);
1407 static HRESULT WINAPI timecode_QueryInterface(IWMReaderTimecode *iface, REFIID iid, void **out)
1409 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1411 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
1414 static ULONG WINAPI timecode_AddRef(IWMReaderTimecode *iface)
1416 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1418 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
1421 static ULONG WINAPI timecode_Release(IWMReaderTimecode *iface)
1423 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1425 return IWMProfile3_Release(&reader->IWMProfile3_iface);
1428 static HRESULT WINAPI timecode_GetTimecodeRangeCount(IWMReaderTimecode *iface,
1429 WORD stream_number, WORD *count)
1431 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
1432 return E_NOTIMPL;
1435 static HRESULT WINAPI timecode_GetTimecodeRangeBounds(IWMReaderTimecode *iface,
1436 WORD stream_number, WORD index, DWORD *start, DWORD *end)
1438 FIXME("iface %p, stream_number %u, index %u, start %p, end %p, stub!\n",
1439 iface, stream_number, index, start, end);
1440 return E_NOTIMPL;
1443 static const IWMReaderTimecodeVtbl timecode_vtbl =
1445 timecode_QueryInterface,
1446 timecode_AddRef,
1447 timecode_Release,
1448 timecode_GetTimecodeRangeCount,
1449 timecode_GetTimecodeRangeBounds,
1452 static HRESULT init_stream(struct wm_reader *reader, QWORD file_size)
1454 struct wg_parser *wg_parser;
1455 HRESULT hr;
1456 WORD i;
1458 if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false)))
1459 return E_OUTOFMEMORY;
1461 reader->wg_parser = wg_parser;
1462 reader->read_thread_shutdown = false;
1463 if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL)))
1465 hr = E_OUTOFMEMORY;
1466 goto out_destroy_parser;
1469 if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size)))
1471 ERR("Failed to connect parser, hr %#lx.\n", hr);
1472 goto out_shutdown_thread;
1475 reader->stream_count = wg_parser_get_stream_count(reader->wg_parser);
1477 if (!(reader->streams = calloc(reader->stream_count, sizeof(*reader->streams))))
1479 hr = E_OUTOFMEMORY;
1480 goto out_disconnect_parser;
1483 for (i = 0; i < reader->stream_count; ++i)
1485 struct wm_stream *stream = &reader->streams[i];
1487 stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i);
1488 stream->reader = reader;
1489 stream->index = i;
1490 stream->selection = WMT_ON;
1491 wg_parser_stream_get_preferred_format(stream->wg_stream, &stream->format);
1492 if (stream->format.major_type == WG_MAJOR_TYPE_AUDIO)
1494 /* R.U.S.E enumerates available audio types, picks the first one it
1495 * likes, and then sets the wrong stream to that type. libav might
1496 * give us WG_AUDIO_FORMAT_F32LE by default, which will result in
1497 * the game incorrectly interpreting float data as integer.
1498 * Therefore just match native and always set our default format to
1499 * S16LE. */
1500 stream->format.u.audio.format = WG_AUDIO_FORMAT_S16LE;
1502 else if (stream->format.major_type == WG_MAJOR_TYPE_VIDEO)
1504 /* Call of Juarez: Bound in Blood breaks if I420 is enumerated.
1505 * Some native decoders output I420, but the msmpeg4v3 decoder
1506 * never does.
1508 * Shadowgrounds provides wmv3 video and assumes that the initial
1509 * video type will be BGR. */
1510 stream->format.u.video.format = WG_VIDEO_FORMAT_BGR;
1512 wg_parser_stream_enable(stream->wg_stream, &stream->format);
1515 /* We probably discarded events because streams weren't enabled yet.
1516 * Now that they're all enabled seek back to the start again. */
1517 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0,
1518 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
1520 return S_OK;
1522 out_disconnect_parser:
1523 wg_parser_disconnect(reader->wg_parser);
1525 out_shutdown_thread:
1526 reader->read_thread_shutdown = true;
1527 WaitForSingleObject(reader->read_thread, INFINITE);
1528 CloseHandle(reader->read_thread);
1529 reader->read_thread = NULL;
1531 out_destroy_parser:
1532 wg_parser_destroy(reader->wg_parser);
1533 reader->wg_parser = NULL;
1535 return hr;
1538 HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream)
1540 STATSTG stat;
1541 HRESULT hr;
1543 if (FAILED(hr = IStream_Stat(stream, &stat, STATFLAG_NONAME)))
1545 ERR("Failed to stat stream, hr %#lx.\n", hr);
1546 return hr;
1549 EnterCriticalSection(&reader->cs);
1551 IStream_AddRef(reader->source_stream = stream);
1552 if (FAILED(hr = init_stream(reader, stat.cbSize.QuadPart)))
1554 IStream_Release(stream);
1555 reader->source_stream = NULL;
1558 LeaveCriticalSection(&reader->cs);
1559 return hr;
1562 HRESULT wm_reader_open_file(struct wm_reader *reader, const WCHAR *filename)
1564 LARGE_INTEGER size;
1565 HANDLE file;
1566 HRESULT hr;
1568 if ((file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
1569 OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
1571 ERR("Failed to open %s, error %lu.\n", debugstr_w(filename), GetLastError());
1572 return HRESULT_FROM_WIN32(GetLastError());
1575 if (!GetFileSizeEx(file, &size))
1577 ERR("Failed to get the size of %s, error %lu.\n", debugstr_w(filename), GetLastError());
1578 CloseHandle(file);
1579 return HRESULT_FROM_WIN32(GetLastError());
1582 EnterCriticalSection(&reader->cs);
1584 reader->file = file;
1586 if (FAILED(hr = init_stream(reader, size.QuadPart)))
1587 reader->file = NULL;
1589 LeaveCriticalSection(&reader->cs);
1590 return hr;
1593 HRESULT wm_reader_close(struct wm_reader *reader)
1595 EnterCriticalSection(&reader->cs);
1597 if (!reader->wg_parser)
1599 LeaveCriticalSection(&reader->cs);
1600 return NS_E_INVALID_REQUEST;
1603 wg_parser_disconnect(reader->wg_parser);
1605 reader->read_thread_shutdown = true;
1606 WaitForSingleObject(reader->read_thread, INFINITE);
1607 CloseHandle(reader->read_thread);
1608 reader->read_thread = NULL;
1610 if (reader->callback_advanced)
1611 IWMReaderCallbackAdvanced_Release(reader->callback_advanced);
1612 reader->callback_advanced = NULL;
1614 wg_parser_destroy(reader->wg_parser);
1615 reader->wg_parser = NULL;
1617 if (reader->source_stream)
1618 IStream_Release(reader->source_stream);
1619 reader->source_stream = NULL;
1620 if (reader->file)
1621 CloseHandle(reader->file);
1622 reader->file = NULL;
1624 LeaveCriticalSection(&reader->cs);
1625 return S_OK;
1628 struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number)
1630 if (stream_number && stream_number <= reader->stream_count)
1631 return &reader->streams[stream_number - 1];
1632 WARN("Invalid stream number %u.\n", stream_number);
1633 return NULL;
1636 HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps **props)
1638 struct wm_stream *stream;
1640 EnterCriticalSection(&reader->cs);
1642 if (!(stream = get_stream_by_output_number(reader, output)))
1644 LeaveCriticalSection(&reader->cs);
1645 return E_INVALIDARG;
1648 *props = output_props_create(&stream->format);
1649 LeaveCriticalSection(&reader->cs);
1650 return *props ? S_OK : E_OUTOFMEMORY;
1653 static const enum wg_video_format video_formats[] =
1655 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
1656 * YUV color space, and it's generally much less expensive for
1657 * videoconvert to do YUV -> YUV transformations. */
1658 WG_VIDEO_FORMAT_NV12,
1659 WG_VIDEO_FORMAT_YV12,
1660 WG_VIDEO_FORMAT_YUY2,
1661 WG_VIDEO_FORMAT_UYVY,
1662 WG_VIDEO_FORMAT_YVYU,
1663 WG_VIDEO_FORMAT_BGRx,
1664 WG_VIDEO_FORMAT_BGR,
1665 WG_VIDEO_FORMAT_RGB16,
1666 WG_VIDEO_FORMAT_RGB15,
1669 HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output, DWORD *count)
1671 struct wm_stream *stream;
1672 struct wg_format format;
1674 EnterCriticalSection(&reader->cs);
1676 if (!(stream = get_stream_by_output_number(reader, output)))
1678 LeaveCriticalSection(&reader->cs);
1679 return E_INVALIDARG;
1682 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
1683 switch (format.major_type)
1685 case WG_MAJOR_TYPE_VIDEO:
1686 *count = ARRAY_SIZE(video_formats);
1687 break;
1689 case WG_MAJOR_TYPE_MPEG1_AUDIO:
1690 case WG_MAJOR_TYPE_WMA:
1691 case WG_MAJOR_TYPE_H264:
1692 FIXME("Format %u not implemented!\n", format.major_type);
1693 /* fallthrough */
1694 case WG_MAJOR_TYPE_AUDIO:
1695 case WG_MAJOR_TYPE_UNKNOWN:
1696 *count = 1;
1697 break;
1700 LeaveCriticalSection(&reader->cs);
1701 return S_OK;
1704 HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output,
1705 DWORD index, IWMOutputMediaProps **props)
1707 struct wm_stream *stream;
1708 struct wg_format format;
1710 EnterCriticalSection(&reader->cs);
1712 if (!(stream = get_stream_by_output_number(reader, output)))
1714 LeaveCriticalSection(&reader->cs);
1715 return E_INVALIDARG;
1718 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
1720 switch (format.major_type)
1722 case WG_MAJOR_TYPE_VIDEO:
1723 if (index >= ARRAY_SIZE(video_formats))
1725 LeaveCriticalSection(&reader->cs);
1726 return NS_E_INVALID_OUTPUT_FORMAT;
1728 format.u.video.format = video_formats[index];
1729 break;
1731 case WG_MAJOR_TYPE_AUDIO:
1732 if (index)
1734 LeaveCriticalSection(&reader->cs);
1735 return NS_E_INVALID_OUTPUT_FORMAT;
1737 format.u.audio.format = WG_AUDIO_FORMAT_S16LE;
1738 break;
1740 case WG_MAJOR_TYPE_MPEG1_AUDIO:
1741 case WG_MAJOR_TYPE_WMA:
1742 case WG_MAJOR_TYPE_H264:
1743 FIXME("Format %u not implemented!\n", format.major_type);
1744 break;
1745 case WG_MAJOR_TYPE_UNKNOWN:
1746 break;
1749 LeaveCriticalSection(&reader->cs);
1751 *props = output_props_create(&format);
1752 return *props ? S_OK : E_OUTOFMEMORY;
1755 HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
1756 IWMOutputMediaProps *props_iface)
1758 struct output_props *props = unsafe_impl_from_IWMOutputMediaProps(props_iface);
1759 struct wg_format format, pref_format;
1760 struct wm_stream *stream;
1762 strmbase_dump_media_type(&props->mt);
1764 if (!amt_to_wg_format(&props->mt, &format))
1766 ERR("Failed to convert media type to winegstreamer format.\n");
1767 return E_FAIL;
1770 EnterCriticalSection(&reader->cs);
1772 if (!(stream = get_stream_by_output_number(reader, output)))
1774 LeaveCriticalSection(&reader->cs);
1775 return E_INVALIDARG;
1778 wg_parser_stream_get_preferred_format(stream->wg_stream, &pref_format);
1779 if (pref_format.major_type != format.major_type)
1781 /* R.U.S.E sets the type of the wrong stream, apparently by accident. */
1782 LeaveCriticalSection(&reader->cs);
1783 WARN("Major types don't match; returning NS_E_INCOMPATIBLE_FORMAT.\n");
1784 return NS_E_INCOMPATIBLE_FORMAT;
1787 stream->format = format;
1788 wg_parser_stream_enable(stream->wg_stream, &format);
1790 /* Re-decode any buffers that might have been generated with the old format.
1792 * FIXME: Seeking in-place will cause some buffers to be dropped.
1793 * Unfortunately, we can't really store the last received PTS and seek there
1794 * either: since seeks are inexact and we aren't guaranteed to receive
1795 * samples in order, some buffers might be duplicated or dropped anyway.
1796 * In order to really seamlessly allow for format changes, we need
1797 * cooperation from each individual GStreamer stream, to be able to tell
1798 * upstream exactly which buffers they need resent...
1800 * In all likelihood this function is being called not mid-stream but rather
1801 * while setting the stream up, before consuming any events. Accordingly
1802 * let's just seek back to the beginning. */
1803 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, reader->start_time, 0,
1804 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
1806 LeaveCriticalSection(&reader->cs);
1807 return S_OK;
1810 static const char *get_major_type_string(enum wg_major_type type)
1812 switch (type)
1814 case WG_MAJOR_TYPE_AUDIO:
1815 return "audio";
1816 case WG_MAJOR_TYPE_VIDEO:
1817 return "video";
1818 case WG_MAJOR_TYPE_UNKNOWN:
1819 return "unknown";
1820 case WG_MAJOR_TYPE_MPEG1_AUDIO:
1821 return "mpeg1-audio";
1822 case WG_MAJOR_TYPE_WMA:
1823 return "wma";
1824 case WG_MAJOR_TYPE_H264:
1825 return "h264";
1827 assert(0);
1828 return NULL;
1831 /* Find the earliest buffer by PTS.
1833 * Native seems to behave similarly to this with the async reader, although our
1834 * unit tests show that it's not entirely consistent—some frames are received
1835 * slightly out of order. It's possible that one stream is being manually offset
1836 * to account for decoding latency.
1838 * The behaviour with the synchronous reader, when stream 0 is requested, seems
1839 * consistent with this hypothesis, but with a much larger offset—the video
1840 * stream seems to be "behind" by about 150 ms.
1842 * The main reason for doing this is that the video and audio stream probably
1843 * don't have quite the same "frame rate", and we don't want to force one stream
1844 * to decode faster just to keep up with the other. Delivering samples in PTS
1845 * order should avoid that problem. */
1846 static WORD get_earliest_buffer(struct wm_reader *reader, struct wg_parser_buffer *ret_buffer)
1848 struct wg_parser_buffer buffer;
1849 QWORD earliest_pts = UI64_MAX;
1850 WORD stream_number = 0;
1851 WORD i;
1853 for (i = 0; i < reader->stream_count; ++i)
1855 struct wm_stream *stream = &reader->streams[i];
1857 if (stream->selection == WMT_OFF)
1858 continue;
1860 if (!wg_parser_stream_get_buffer(stream->wg_stream, &buffer))
1861 continue;
1863 if (buffer.has_pts && buffer.pts < earliest_pts)
1865 stream_number = i + 1;
1866 earliest_pts = buffer.pts;
1867 *ret_buffer = buffer;
1871 return stream_number;
1874 HRESULT wm_reader_get_stream_sample(struct wm_reader *reader, WORD stream_number,
1875 INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags, WORD *ret_stream_number)
1877 IWMReaderCallbackAdvanced *callback_advanced = reader->callback_advanced;
1878 struct wg_parser_stream *wg_stream;
1879 struct wg_parser_buffer wg_buffer;
1880 struct wm_stream *stream;
1881 DWORD size, capacity;
1882 INSSBuffer *sample;
1883 HRESULT hr;
1884 BYTE *data;
1886 for (;;)
1888 if (!stream_number)
1890 if (!(stream_number = get_earliest_buffer(reader, &wg_buffer)))
1892 /* All streams are disabled or EOS. */
1893 return NS_E_NO_MORE_SAMPLES;
1896 stream = wm_reader_get_stream_by_stream_number(reader, stream_number);
1897 wg_stream = stream->wg_stream;
1899 else
1901 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
1903 WARN("Invalid stream number %u; returning E_INVALIDARG.\n", stream_number);
1904 return E_INVALIDARG;
1906 wg_stream = stream->wg_stream;
1908 if (stream->selection == WMT_OFF)
1910 WARN("Stream %u is deselected; returning NS_E_INVALID_REQUEST.\n", stream_number);
1911 return NS_E_INVALID_REQUEST;
1914 if (stream->eos)
1915 return NS_E_NO_MORE_SAMPLES;
1917 if (!wg_parser_stream_get_buffer(wg_stream, &wg_buffer))
1919 stream->eos = true;
1920 TRACE("End of stream.\n");
1921 return NS_E_NO_MORE_SAMPLES;
1925 TRACE("Got buffer for '%s' stream %p.\n", get_major_type_string(stream->format.major_type), stream);
1927 if (callback_advanced && stream->read_compressed && stream->allocate_stream)
1929 if (FAILED(hr = IWMReaderCallbackAdvanced_AllocateForStream(callback_advanced,
1930 stream->index + 1, wg_buffer.size, &sample, NULL)))
1932 ERR("Failed to allocate stream sample of %u bytes, hr %#lx.\n", wg_buffer.size, hr);
1933 wg_parser_stream_release_buffer(wg_stream);
1934 return hr;
1937 else if (callback_advanced && !stream->read_compressed && stream->allocate_output)
1939 if (FAILED(hr = IWMReaderCallbackAdvanced_AllocateForOutput(callback_advanced,
1940 stream->index, wg_buffer.size, &sample, NULL)))
1942 ERR("Failed to allocate output sample of %u bytes, hr %#lx.\n", wg_buffer.size, hr);
1943 wg_parser_stream_release_buffer(wg_stream);
1944 return hr;
1947 else
1949 struct buffer *object;
1951 /* FIXME: Should these be pooled? */
1952 if (!(object = calloc(1, offsetof(struct buffer, data[wg_buffer.size]))))
1954 wg_parser_stream_release_buffer(wg_stream);
1955 return E_OUTOFMEMORY;
1958 object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
1959 object->refcount = 1;
1960 object->capacity = wg_buffer.size;
1962 TRACE("Created buffer %p.\n", object);
1963 sample = &object->INSSBuffer_iface;
1966 if (FAILED(hr = INSSBuffer_GetBufferAndLength(sample, &data, &size)))
1967 ERR("Failed to get data pointer, hr %#lx.\n", hr);
1968 if (FAILED(hr = INSSBuffer_GetMaxLength(sample, &capacity)))
1969 ERR("Failed to get capacity, hr %#lx.\n", hr);
1970 if (wg_buffer.size > capacity)
1971 ERR("Returned capacity %lu is less than requested capacity %u.\n", capacity, wg_buffer.size);
1973 if (!wg_parser_stream_copy_buffer(wg_stream, data, 0, wg_buffer.size))
1975 /* The GStreamer pin has been flushed. */
1976 INSSBuffer_Release(sample);
1977 continue;
1980 if (FAILED(hr = INSSBuffer_SetLength(sample, wg_buffer.size)))
1981 ERR("Failed to set size %u, hr %#lx.\n", wg_buffer.size, hr);
1983 wg_parser_stream_release_buffer(wg_stream);
1985 if (!wg_buffer.has_pts)
1986 FIXME("Missing PTS.\n");
1987 if (!wg_buffer.has_duration)
1988 FIXME("Missing duration.\n");
1990 *pts = wg_buffer.pts;
1991 *duration = wg_buffer.duration;
1992 *flags = 0;
1993 if (wg_buffer.discontinuity)
1994 *flags |= WM_SF_DISCONTINUITY;
1995 if (!wg_buffer.delta)
1996 *flags |= WM_SF_CLEANPOINT;
1998 *ret_sample = sample;
1999 *ret_stream_number = stream_number;
2000 return S_OK;
2004 void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration)
2006 WORD i;
2008 EnterCriticalSection(&reader->cs);
2010 reader->start_time = start;
2012 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, start, start + duration,
2013 AM_SEEKING_AbsolutePositioning, duration ? AM_SEEKING_AbsolutePositioning : AM_SEEKING_NoPositioning);
2015 for (i = 0; i < reader->stream_count; ++i)
2016 reader->streams[i].eos = false;
2018 LeaveCriticalSection(&reader->cs);
2021 HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count,
2022 const WORD *stream_numbers, const WMT_STREAM_SELECTION *selections)
2024 struct wm_stream *stream;
2025 WORD i;
2027 if (!count)
2028 return E_INVALIDARG;
2030 EnterCriticalSection(&reader->cs);
2032 for (i = 0; i < count; ++i)
2034 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_numbers[i])))
2036 LeaveCriticalSection(&reader->cs);
2037 WARN("Invalid stream number %u; returning NS_E_INVALID_REQUEST.\n", stream_numbers[i]);
2038 return NS_E_INVALID_REQUEST;
2042 for (i = 0; i < count; ++i)
2044 stream = wm_reader_get_stream_by_stream_number(reader, stream_numbers[i]);
2045 stream->selection = selections[i];
2046 if (selections[i] == WMT_OFF)
2048 TRACE("Disabling stream %u.\n", stream_numbers[i]);
2049 wg_parser_stream_disable(stream->wg_stream);
2051 else if (selections[i] == WMT_ON)
2053 if (selections[i] != WMT_ON)
2054 FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n",
2055 selections[i], stream_numbers[i]);
2056 TRACE("Enabling stream %u.\n", stream_numbers[i]);
2057 wg_parser_stream_enable(stream->wg_stream, &stream->format);
2061 LeaveCriticalSection(&reader->cs);
2062 return S_OK;
2065 HRESULT wm_reader_get_stream_selection(struct wm_reader *reader,
2066 WORD stream_number, WMT_STREAM_SELECTION *selection)
2068 struct wm_stream *stream;
2070 EnterCriticalSection(&reader->cs);
2072 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2074 LeaveCriticalSection(&reader->cs);
2075 return E_INVALIDARG;
2078 *selection = stream->selection;
2080 LeaveCriticalSection(&reader->cs);
2081 return S_OK;
2084 HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output, BOOL allocate)
2086 struct wm_stream *stream;
2088 EnterCriticalSection(&reader->cs);
2090 if (!(stream = get_stream_by_output_number(reader, output)))
2092 LeaveCriticalSection(&reader->cs);
2093 return E_INVALIDARG;
2096 stream->allocate_output = !!allocate;
2098 LeaveCriticalSection(&reader->cs);
2099 return S_OK;
2102 HRESULT wm_reader_set_allocate_for_stream(struct wm_reader *reader, WORD stream_number, BOOL allocate)
2104 struct wm_stream *stream;
2106 EnterCriticalSection(&reader->cs);
2108 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2110 LeaveCriticalSection(&reader->cs);
2111 return E_INVALIDARG;
2114 stream->allocate_stream = !!allocate;
2116 LeaveCriticalSection(&reader->cs);
2117 return S_OK;
2120 HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, WORD stream_number, BOOL compressed)
2122 struct wm_stream *stream;
2124 EnterCriticalSection(&reader->cs);
2126 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2128 LeaveCriticalSection(&reader->cs);
2129 return E_INVALIDARG;
2132 stream->read_compressed = compressed;
2134 LeaveCriticalSection(&reader->cs);
2135 return S_OK;
2138 HRESULT wm_reader_get_max_stream_size(struct wm_reader *reader, WORD stream_number, DWORD *size)
2140 struct wm_stream *stream;
2142 EnterCriticalSection(&reader->cs);
2144 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2146 LeaveCriticalSection(&reader->cs);
2147 return E_INVALIDARG;
2150 *size = wg_format_get_max_size(&stream->format);
2152 LeaveCriticalSection(&reader->cs);
2153 return S_OK;
2156 void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops)
2158 reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
2159 reader->IWMLanguageList_iface.lpVtbl = &language_list_vtbl;
2160 reader->IWMPacketSize2_iface.lpVtbl = &packet_size_vtbl;
2161 reader->IWMProfile3_iface.lpVtbl = &profile_vtbl;
2162 reader->IWMReaderPlaylistBurn_iface.lpVtbl = &playlist_vtbl;
2163 reader->IWMReaderTimecode_iface.lpVtbl = &timecode_vtbl;
2164 reader->refcount = 1;
2165 reader->ops = ops;
2167 InitializeCriticalSection(&reader->cs);
2168 reader->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wm_reader.cs");
2171 void wm_reader_cleanup(struct wm_reader *reader)
2173 reader->cs.DebugInfo->Spare[0] = 0;
2174 DeleteCriticalSection(&reader->cs);