winegstreamer: Introduce a new wg_init_gstreamer unixlib entry.
[wine.git] / dlls / winegstreamer / wm_reader.c
blob764774d505b3b814b61ec5107826a4aa6de0e153
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 struct wg_parser_stream *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 struct wg_parser *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 DWORD req_size = *size;
548 AM_MEDIA_TYPE stream_mt;
550 TRACE("iface %p, mt %p, size %p.\n", iface, mt, size);
552 if (!amt_from_wg_format(&stream_mt, &config->stream->format, true))
553 return E_OUTOFMEMORY;
555 *size = sizeof(stream_mt) + stream_mt.cbFormat;
556 if (!mt)
557 return S_OK;
558 if (req_size < *size)
559 return ASF_E_BUFFERTOOSMALL;
561 strmbase_dump_media_type(&stream_mt);
563 memcpy(mt, &stream_mt, sizeof(*mt));
564 memcpy(mt + 1, stream_mt.pbFormat, stream_mt.cbFormat);
565 mt->pbFormat = (BYTE *)(mt + 1);
566 return S_OK;
569 static HRESULT WINAPI stream_props_SetMediaType(IWMMediaProps *iface, WM_MEDIA_TYPE *mt)
571 FIXME("iface %p, mt %p, stub!\n", iface, mt);
572 return E_NOTIMPL;
575 static const IWMMediaPropsVtbl stream_props_vtbl =
577 stream_props_QueryInterface,
578 stream_props_AddRef,
579 stream_props_Release,
580 stream_props_GetType,
581 stream_props_GetMediaType,
582 stream_props_SetMediaType,
585 static DWORD CALLBACK read_thread(void *arg)
587 struct wm_reader *reader = arg;
588 IStream *stream = reader->source_stream;
589 HANDLE file = reader->file;
590 size_t buffer_size = 4096;
591 uint64_t file_size;
592 void *data;
594 if (!(data = malloc(buffer_size)))
595 return 0;
597 if (file)
599 LARGE_INTEGER size;
601 GetFileSizeEx(file, &size);
602 file_size = size.QuadPart;
604 else
606 STATSTG stat;
608 IStream_Stat(stream, &stat, STATFLAG_NONAME);
609 file_size = stat.cbSize.QuadPart;
612 TRACE("Starting read thread for reader %p.\n", reader);
614 while (!reader->read_thread_shutdown)
616 LARGE_INTEGER large_offset;
617 uint64_t offset;
618 ULONG ret_size;
619 uint32_t size;
620 HRESULT hr;
622 if (!wg_parser_get_next_read_offset(reader->wg_parser, &offset, &size))
623 continue;
625 if (offset >= file_size)
626 size = 0;
627 else if (offset + size >= file_size)
628 size = file_size - offset;
630 if (!size)
632 wg_parser_push_data(reader->wg_parser, data, 0);
633 continue;
636 if (!array_reserve(&data, &buffer_size, size, 1))
638 free(data);
639 return 0;
642 ret_size = 0;
644 large_offset.QuadPart = offset;
645 if (file)
647 if (!SetFilePointerEx(file, large_offset, NULL, FILE_BEGIN)
648 || !ReadFile(file, data, size, &ret_size, NULL))
650 ERR("Failed to read %u bytes at offset %I64u, error %lu.\n", size, offset, GetLastError());
651 wg_parser_push_data(reader->wg_parser, NULL, 0);
652 continue;
655 else
657 if (SUCCEEDED(hr = IStream_Seek(stream, large_offset, STREAM_SEEK_SET, NULL)))
658 hr = IStream_Read(stream, data, size, &ret_size);
659 if (FAILED(hr))
661 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr);
662 wg_parser_push_data(reader->wg_parser, NULL, 0);
663 continue;
667 if (ret_size != size)
668 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size);
669 wg_parser_push_data(reader->wg_parser, data, ret_size);
672 free(data);
673 TRACE("Reader is shutting down; exiting.\n");
674 return 0;
677 static struct wm_reader *impl_from_IWMProfile3(IWMProfile3 *iface)
679 return CONTAINING_RECORD(iface, struct wm_reader, IWMProfile3_iface);
682 static HRESULT WINAPI profile_QueryInterface(IWMProfile3 *iface, REFIID iid, void **out)
684 struct wm_reader *reader = impl_from_IWMProfile3(iface);
685 return IUnknown_QueryInterface(reader->outer, iid, out);
688 static ULONG WINAPI profile_AddRef(IWMProfile3 *iface)
690 struct wm_reader *reader = impl_from_IWMProfile3(iface);
691 return IUnknown_AddRef(reader->outer);
694 static ULONG WINAPI profile_Release(IWMProfile3 *iface)
696 struct wm_reader *reader = impl_from_IWMProfile3(iface);
697 return IUnknown_Release(reader->outer);
700 static HRESULT WINAPI profile_GetVersion(IWMProfile3 *iface, WMT_VERSION *version)
702 FIXME("iface %p, version %p, stub!\n", iface, version);
703 return E_NOTIMPL;
706 static HRESULT WINAPI profile_GetName(IWMProfile3 *iface, WCHAR *name, DWORD *length)
708 FIXME("iface %p, name %p, length %p, stub!\n", iface, name, length);
709 return E_NOTIMPL;
712 static HRESULT WINAPI profile_SetName(IWMProfile3 *iface, const WCHAR *name)
714 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
715 return E_NOTIMPL;
718 static HRESULT WINAPI profile_GetDescription(IWMProfile3 *iface, WCHAR *description, DWORD *length)
720 FIXME("iface %p, description %p, length %p, stub!\n", iface, description, length);
721 return E_NOTIMPL;
724 static HRESULT WINAPI profile_SetDescription(IWMProfile3 *iface, const WCHAR *description)
726 FIXME("iface %p, description %s, stub!\n", iface, debugstr_w(description));
727 return E_NOTIMPL;
730 static HRESULT WINAPI profile_GetStreamCount(IWMProfile3 *iface, DWORD *count)
732 struct wm_reader *reader = impl_from_IWMProfile3(iface);
734 TRACE("reader %p, count %p.\n", reader, count);
736 if (!count)
737 return E_INVALIDARG;
739 EnterCriticalSection(&reader->cs);
740 *count = reader->stream_count;
741 LeaveCriticalSection(&reader->cs);
742 return S_OK;
745 static HRESULT WINAPI profile_GetStream(IWMProfile3 *iface, DWORD index, IWMStreamConfig **config)
747 struct wm_reader *reader = impl_from_IWMProfile3(iface);
748 struct stream_config *object;
750 TRACE("reader %p, index %lu, config %p.\n", reader, index, config);
752 EnterCriticalSection(&reader->cs);
754 if (index >= reader->stream_count)
756 LeaveCriticalSection(&reader->cs);
757 WARN("Index %lu exceeds stream count %u; returning E_INVALIDARG.\n", index, reader->stream_count);
758 return E_INVALIDARG;
761 if (!(object = calloc(1, sizeof(*object))))
763 LeaveCriticalSection(&reader->cs);
764 return E_OUTOFMEMORY;
767 object->IWMStreamConfig_iface.lpVtbl = &stream_config_vtbl;
768 object->IWMMediaProps_iface.lpVtbl = &stream_props_vtbl;
769 object->refcount = 1;
770 object->stream = &reader->streams[index];
771 IWMProfile3_AddRef(&reader->IWMProfile3_iface);
773 LeaveCriticalSection(&reader->cs);
775 TRACE("Created stream config %p.\n", object);
776 *config = &object->IWMStreamConfig_iface;
777 return S_OK;
780 static HRESULT WINAPI profile_GetStreamByNumber(IWMProfile3 *iface, WORD stream_number, IWMStreamConfig **config)
782 HRESULT hr;
784 TRACE("iface %p, stream_number %u, config %p.\n", iface, stream_number, config);
786 if (!stream_number)
787 return NS_E_NO_STREAM;
789 hr = profile_GetStream(iface, stream_number - 1, config);
790 if (hr == E_INVALIDARG)
791 hr = NS_E_NO_STREAM;
793 return hr;
796 static HRESULT WINAPI profile_RemoveStream(IWMProfile3 *iface, IWMStreamConfig *config)
798 FIXME("iface %p, config %p, stub!\n", iface, config);
799 return E_NOTIMPL;
802 static HRESULT WINAPI profile_RemoveStreamByNumber(IWMProfile3 *iface, WORD stream_number)
804 FIXME("iface %p, stream_number %u, stub!\n", iface, stream_number);
805 return E_NOTIMPL;
808 static HRESULT WINAPI profile_AddStream(IWMProfile3 *iface, IWMStreamConfig *config)
810 FIXME("iface %p, config %p, stub!\n", iface, config);
811 return E_NOTIMPL;
814 static HRESULT WINAPI profile_ReconfigStream(IWMProfile3 *iface, IWMStreamConfig *config)
816 FIXME("iface %p, config %p, stub!\n", iface, config);
817 return E_NOTIMPL;
820 static HRESULT WINAPI profile_CreateNewStream(IWMProfile3 *iface, REFGUID type, IWMStreamConfig **config)
822 FIXME("iface %p, type %s, config %p, stub!\n", iface, debugstr_guid(type), config);
823 return E_NOTIMPL;
826 static HRESULT WINAPI profile_GetMutualExclusionCount(IWMProfile3 *iface, DWORD *count)
828 FIXME("iface %p, count %p, stub!\n", iface, count);
829 return E_NOTIMPL;
832 static HRESULT WINAPI profile_GetMutualExclusion(IWMProfile3 *iface, DWORD index, IWMMutualExclusion **excl)
834 FIXME("iface %p, index %lu, excl %p, stub!\n", iface, index, excl);
835 return E_NOTIMPL;
838 static HRESULT WINAPI profile_RemoveMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
840 FIXME("iface %p, excl %p, stub!\n", iface, excl);
841 return E_NOTIMPL;
844 static HRESULT WINAPI profile_AddMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
846 FIXME("iface %p, excl %p, stub!\n", iface, excl);
847 return E_NOTIMPL;
850 static HRESULT WINAPI profile_CreateNewMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion **excl)
852 FIXME("iface %p, excl %p, stub!\n", iface, excl);
853 return E_NOTIMPL;
856 static HRESULT WINAPI profile_GetProfileID(IWMProfile3 *iface, GUID *id)
858 FIXME("iface %p, id %p, stub!\n", iface, id);
859 return E_NOTIMPL;
862 static HRESULT WINAPI profile_GetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT *format)
864 FIXME("iface %p, format %p, stub!\n", iface, format);
865 return E_NOTIMPL;
868 static HRESULT WINAPI profile_SetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT format)
870 FIXME("iface %p, format %#x, stub!\n", iface, format);
871 return E_NOTIMPL;
874 static HRESULT WINAPI profile_GetBandwidthSharingCount(IWMProfile3 *iface, DWORD *count)
876 FIXME("iface %p, count %p, stub!\n", iface, count);
877 return E_NOTIMPL;
880 static HRESULT WINAPI profile_GetBandwidthSharing(IWMProfile3 *iface, DWORD index, IWMBandwidthSharing **sharing)
882 FIXME("iface %p, index %lu, sharing %p, stub!\n", iface, index, sharing);
883 return E_NOTIMPL;
886 static HRESULT WINAPI profile_RemoveBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing *sharing)
888 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
889 return E_NOTIMPL;
892 static HRESULT WINAPI profile_AddBandwidthSharing(IWMProfile3 *iface, IWMBandwidthSharing *sharing)
894 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
895 return E_NOTIMPL;
898 static HRESULT WINAPI profile_CreateNewBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing **sharing)
900 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
901 return E_NOTIMPL;
904 static HRESULT WINAPI profile_GetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
906 FIXME("iface %p, stream %p, stub!\n", iface, stream);
907 return E_NOTIMPL;
910 static HRESULT WINAPI profile_SetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization *stream)
912 FIXME("iface %p, stream %p, stub!\n", iface, stream);
913 return E_NOTIMPL;
916 static HRESULT WINAPI profile_RemoveStreamPrioritization(IWMProfile3 *iface)
918 FIXME("iface %p, stub!\n", iface);
919 return E_NOTIMPL;
922 static HRESULT WINAPI profile_CreateNewStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
924 FIXME("iface %p, stream %p, stub!\n", iface, stream);
925 return E_NOTIMPL;
928 static HRESULT WINAPI profile_GetExpectedPacketCount(IWMProfile3 *iface, QWORD duration, QWORD *count)
930 FIXME("iface %p, duration %s, count %p, stub!\n", iface, debugstr_time(duration), count);
931 return E_NOTIMPL;
934 static const IWMProfile3Vtbl profile_vtbl =
936 profile_QueryInterface,
937 profile_AddRef,
938 profile_Release,
939 profile_GetVersion,
940 profile_GetName,
941 profile_SetName,
942 profile_GetDescription,
943 profile_SetDescription,
944 profile_GetStreamCount,
945 profile_GetStream,
946 profile_GetStreamByNumber,
947 profile_RemoveStream,
948 profile_RemoveStreamByNumber,
949 profile_AddStream,
950 profile_ReconfigStream,
951 profile_CreateNewStream,
952 profile_GetMutualExclusionCount,
953 profile_GetMutualExclusion,
954 profile_RemoveMutualExclusion,
955 profile_AddMutualExclusion,
956 profile_CreateNewMutualExclusion,
957 profile_GetProfileID,
958 profile_GetStorageFormat,
959 profile_SetStorageFormat,
960 profile_GetBandwidthSharingCount,
961 profile_GetBandwidthSharing,
962 profile_RemoveBandwidthSharing,
963 profile_AddBandwidthSharing,
964 profile_CreateNewBandwidthSharing,
965 profile_GetStreamPrioritization,
966 profile_SetStreamPrioritization,
967 profile_RemoveStreamPrioritization,
968 profile_CreateNewStreamPrioritization,
969 profile_GetExpectedPacketCount,
972 static struct wm_reader *impl_from_IWMHeaderInfo3(IWMHeaderInfo3 *iface)
974 return CONTAINING_RECORD(iface, struct wm_reader, IWMHeaderInfo3_iface);
977 static HRESULT WINAPI header_info_QueryInterface(IWMHeaderInfo3 *iface, REFIID iid, void **out)
979 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
980 return IUnknown_QueryInterface(reader->outer, iid, out);
983 static ULONG WINAPI header_info_AddRef(IWMHeaderInfo3 *iface)
985 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
986 return IUnknown_AddRef(reader->outer);
989 static ULONG WINAPI header_info_Release(IWMHeaderInfo3 *iface)
991 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
992 return IUnknown_Release(reader->outer);
995 static HRESULT WINAPI header_info_GetAttributeCount(IWMHeaderInfo3 *iface, WORD stream_number, WORD *count)
997 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
998 return E_NOTIMPL;
1001 static HRESULT WINAPI header_info_GetAttributeByIndex(IWMHeaderInfo3 *iface, WORD index, WORD *stream_number,
1002 WCHAR *name, WORD *name_len, WMT_ATTR_DATATYPE *type, BYTE *value, WORD *size)
1004 FIXME("iface %p, index %u, stream_number %p, name %p, name_len %p, type %p, value %p, size %p, stub!\n",
1005 iface, index, stream_number, name, name_len, type, value, size);
1006 return E_NOTIMPL;
1009 static HRESULT WINAPI header_info_GetAttributeByName(IWMHeaderInfo3 *iface, WORD *stream_number,
1010 const WCHAR *name, WMT_ATTR_DATATYPE *type, BYTE *value, WORD *size)
1012 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
1013 const WORD req_size = *size;
1015 TRACE("reader %p, stream_number %p, name %s, type %p, value %p, size %u.\n",
1016 reader, stream_number, debugstr_w(name), type, value, *size);
1018 if (!stream_number)
1019 return E_INVALIDARG;
1021 if (!wcscmp(name, L"Duration"))
1023 QWORD duration;
1025 if (*stream_number)
1027 WARN("Requesting duration for stream %u, returning ASF_E_NOTFOUND.\n", *stream_number);
1028 return ASF_E_NOTFOUND;
1031 *size = sizeof(QWORD);
1032 if (!value)
1034 *type = WMT_TYPE_QWORD;
1035 return S_OK;
1037 if (req_size < *size)
1038 return ASF_E_BUFFERTOOSMALL;
1040 *type = WMT_TYPE_QWORD;
1041 EnterCriticalSection(&reader->cs);
1042 duration = wg_parser_stream_get_duration(wg_parser_get_stream(reader->wg_parser, 0));
1043 LeaveCriticalSection(&reader->cs);
1044 TRACE("Returning duration %s.\n", debugstr_time(duration));
1045 memcpy(value, &duration, sizeof(QWORD));
1046 return S_OK;
1048 else if (!wcscmp(name, L"Seekable"))
1050 if (*stream_number)
1052 WARN("Requesting duration for stream %u, returning ASF_E_NOTFOUND.\n", *stream_number);
1053 return ASF_E_NOTFOUND;
1056 *size = sizeof(BOOL);
1057 if (!value)
1059 *type = WMT_TYPE_BOOL;
1060 return S_OK;
1062 if (req_size < *size)
1063 return ASF_E_BUFFERTOOSMALL;
1065 *type = WMT_TYPE_BOOL;
1066 *(BOOL *)value = TRUE;
1067 return S_OK;
1069 else
1071 FIXME("Unknown attribute %s.\n", debugstr_w(name));
1072 return ASF_E_NOTFOUND;
1076 static HRESULT WINAPI header_info_SetAttribute(IWMHeaderInfo3 *iface, WORD stream_number,
1077 const WCHAR *name, WMT_ATTR_DATATYPE type, const BYTE *value, WORD size)
1079 FIXME("iface %p, stream_number %u, name %s, type %#x, value %p, size %u, stub!\n",
1080 iface, stream_number, debugstr_w(name), type, value, size);
1081 return E_NOTIMPL;
1084 static HRESULT WINAPI header_info_GetMarkerCount(IWMHeaderInfo3 *iface, WORD *count)
1086 FIXME("iface %p, count %p, stub!\n", iface, count);
1087 return E_NOTIMPL;
1090 static HRESULT WINAPI header_info_GetMarker(IWMHeaderInfo3 *iface,
1091 WORD index, WCHAR *name, WORD *len, QWORD *time)
1093 FIXME("iface %p, index %u, name %p, len %p, time %p, stub!\n", iface, index, name, len, time);
1094 return E_NOTIMPL;
1097 static HRESULT WINAPI header_info_AddMarker(IWMHeaderInfo3 *iface, const WCHAR *name, QWORD time)
1099 FIXME("iface %p, name %s, time %s, stub!\n", iface, debugstr_w(name), debugstr_time(time));
1100 return E_NOTIMPL;
1103 static HRESULT WINAPI header_info_RemoveMarker(IWMHeaderInfo3 *iface, WORD index)
1105 FIXME("iface %p, index %u, stub!\n", iface, index);
1106 return E_NOTIMPL;
1109 static HRESULT WINAPI header_info_GetScriptCount(IWMHeaderInfo3 *iface, WORD *count)
1111 FIXME("iface %p, count %p, stub!\n", iface, count);
1112 return E_NOTIMPL;
1115 static HRESULT WINAPI header_info_GetScript(IWMHeaderInfo3 *iface, WORD index, WCHAR *type,
1116 WORD *type_len, WCHAR *command, WORD *command_len, QWORD *time)
1118 FIXME("iface %p, index %u, type %p, type_len %p, command %p, command_len %p, time %p, stub!\n",
1119 iface, index, type, type_len, command, command_len, time);
1120 return E_NOTIMPL;
1123 static HRESULT WINAPI header_info_AddScript(IWMHeaderInfo3 *iface,
1124 const WCHAR *type, const WCHAR *command, QWORD time)
1126 FIXME("iface %p, type %s, command %s, time %s, stub!\n",
1127 iface, debugstr_w(type), debugstr_w(command), debugstr_time(time));
1128 return E_NOTIMPL;
1131 static HRESULT WINAPI header_info_RemoveScript(IWMHeaderInfo3 *iface, WORD index)
1133 FIXME("iface %p, index %u, stub!\n", iface, index);
1134 return E_NOTIMPL;
1137 static HRESULT WINAPI header_info_GetCodecInfoCount(IWMHeaderInfo3 *iface, DWORD *count)
1139 FIXME("iface %p, count %p, stub!\n", iface, count);
1140 return E_NOTIMPL;
1143 static HRESULT WINAPI header_info_GetCodecInfo(IWMHeaderInfo3 *iface, DWORD index, WORD *name_len,
1144 WCHAR *name, WORD *desc_len, WCHAR *desc, WMT_CODEC_INFO_TYPE *type, WORD *size, BYTE *info)
1146 FIXME("iface %p, index %lu, name_len %p, name %p, desc_len %p, desc %p, type %p, size %p, info %p, stub!\n",
1147 iface, index, name_len, name, desc_len, desc, type, size, info);
1148 return E_NOTIMPL;
1151 static HRESULT WINAPI header_info_GetAttributeCountEx(IWMHeaderInfo3 *iface, WORD stream_number, WORD *count)
1153 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
1154 return E_NOTIMPL;
1157 static HRESULT WINAPI header_info_GetAttributeIndices(IWMHeaderInfo3 *iface, WORD stream_number,
1158 const WCHAR *name, WORD *lang_index, WORD *indices, WORD *count)
1160 FIXME("iface %p, stream_number %u, name %s, lang_index %p, indices %p, count %p, stub!\n",
1161 iface, stream_number, debugstr_w(name), lang_index, indices, count);
1162 return E_NOTIMPL;
1165 static HRESULT WINAPI header_info_GetAttributeByIndexEx(IWMHeaderInfo3 *iface,
1166 WORD stream_number, WORD index, WCHAR *name, WORD *name_len,
1167 WMT_ATTR_DATATYPE *type, WORD *lang_index, BYTE *value, DWORD *size)
1169 FIXME("iface %p, stream_number %u, index %u, name %p, name_len %p,"
1170 " type %p, lang_index %p, value %p, size %p, stub!\n",
1171 iface, stream_number, index, name, name_len, type, lang_index, value, size);
1172 return E_NOTIMPL;
1175 static HRESULT WINAPI header_info_ModifyAttribute(IWMHeaderInfo3 *iface, WORD stream_number,
1176 WORD index, WMT_ATTR_DATATYPE type, WORD lang_index, const BYTE *value, DWORD size)
1178 FIXME("iface %p, stream_number %u, index %u, type %#x, lang_index %u, value %p, size %lu, stub!\n",
1179 iface, stream_number, index, type, lang_index, value, size);
1180 return E_NOTIMPL;
1183 static HRESULT WINAPI header_info_AddAttribute(IWMHeaderInfo3 *iface,
1184 WORD stream_number, const WCHAR *name, WORD *index,
1185 WMT_ATTR_DATATYPE type, WORD lang_index, const BYTE *value, DWORD size)
1187 FIXME("iface %p, stream_number %u, name %s, index %p, type %#x, lang_index %u, value %p, size %lu, stub!\n",
1188 iface, stream_number, debugstr_w(name), index, type, lang_index, value, size);
1189 return E_NOTIMPL;
1192 static HRESULT WINAPI header_info_DeleteAttribute(IWMHeaderInfo3 *iface, WORD stream_number, WORD index)
1194 FIXME("iface %p, stream_number %u, index %u, stub!\n", iface, stream_number, index);
1195 return E_NOTIMPL;
1198 static HRESULT WINAPI header_info_AddCodecInfo(IWMHeaderInfo3 *iface, const WCHAR *name,
1199 const WCHAR *desc, WMT_CODEC_INFO_TYPE type, WORD size, BYTE *info)
1201 FIXME("iface %p, name %s, desc %s, type %#x, size %u, info %p, stub!\n",
1202 info, debugstr_w(name), debugstr_w(desc), type, size, info);
1203 return E_NOTIMPL;
1206 static const IWMHeaderInfo3Vtbl header_info_vtbl =
1208 header_info_QueryInterface,
1209 header_info_AddRef,
1210 header_info_Release,
1211 header_info_GetAttributeCount,
1212 header_info_GetAttributeByIndex,
1213 header_info_GetAttributeByName,
1214 header_info_SetAttribute,
1215 header_info_GetMarkerCount,
1216 header_info_GetMarker,
1217 header_info_AddMarker,
1218 header_info_RemoveMarker,
1219 header_info_GetScriptCount,
1220 header_info_GetScript,
1221 header_info_AddScript,
1222 header_info_RemoveScript,
1223 header_info_GetCodecInfoCount,
1224 header_info_GetCodecInfo,
1225 header_info_GetAttributeCountEx,
1226 header_info_GetAttributeIndices,
1227 header_info_GetAttributeByIndexEx,
1228 header_info_ModifyAttribute,
1229 header_info_AddAttribute,
1230 header_info_DeleteAttribute,
1231 header_info_AddCodecInfo,
1234 static struct wm_reader *impl_from_IWMLanguageList(IWMLanguageList *iface)
1236 return CONTAINING_RECORD(iface, struct wm_reader, IWMLanguageList_iface);
1239 static HRESULT WINAPI language_list_QueryInterface(IWMLanguageList *iface, REFIID iid, void **out)
1241 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1242 return IUnknown_QueryInterface(reader->outer, iid, out);
1245 static ULONG WINAPI language_list_AddRef(IWMLanguageList *iface)
1247 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1248 return IUnknown_AddRef(reader->outer);
1251 static ULONG WINAPI language_list_Release(IWMLanguageList *iface)
1253 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1254 return IUnknown_Release(reader->outer);
1257 static HRESULT WINAPI language_list_GetLanguageCount(IWMLanguageList *iface, WORD *count)
1259 FIXME("iface %p, count %p, stub!\n", iface, count);
1260 return E_NOTIMPL;
1263 static HRESULT WINAPI language_list_GetLanguageDetails(IWMLanguageList *iface,
1264 WORD index, WCHAR *lang, WORD *len)
1266 FIXME("iface %p, index %u, lang %p, len %p, stub!\n", iface, index, lang, len);
1267 return E_NOTIMPL;
1270 static HRESULT WINAPI language_list_AddLanguageByRFC1766String(IWMLanguageList *iface,
1271 const WCHAR *lang, WORD *index)
1273 FIXME("iface %p, lang %s, index %p, stub!\n", iface, debugstr_w(lang), index);
1274 return E_NOTIMPL;
1277 static const IWMLanguageListVtbl language_list_vtbl =
1279 language_list_QueryInterface,
1280 language_list_AddRef,
1281 language_list_Release,
1282 language_list_GetLanguageCount,
1283 language_list_GetLanguageDetails,
1284 language_list_AddLanguageByRFC1766String,
1287 static struct wm_reader *impl_from_IWMPacketSize2(IWMPacketSize2 *iface)
1289 return CONTAINING_RECORD(iface, struct wm_reader, IWMPacketSize2_iface);
1292 static HRESULT WINAPI packet_size_QueryInterface(IWMPacketSize2 *iface, REFIID iid, void **out)
1294 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1295 return IUnknown_QueryInterface(reader->outer, iid, out);
1298 static ULONG WINAPI packet_size_AddRef(IWMPacketSize2 *iface)
1300 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1301 return IUnknown_AddRef(reader->outer);
1304 static ULONG WINAPI packet_size_Release(IWMPacketSize2 *iface)
1306 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1307 return IUnknown_Release(reader->outer);
1310 static HRESULT WINAPI packet_size_GetMaxPacketSize(IWMPacketSize2 *iface, DWORD *size)
1312 FIXME("iface %p, size %p, stub!\n", iface, size);
1313 return E_NOTIMPL;
1316 static HRESULT WINAPI packet_size_SetMaxPacketSize(IWMPacketSize2 *iface, DWORD size)
1318 FIXME("iface %p, size %lu, stub!\n", iface, size);
1319 return E_NOTIMPL;
1322 static HRESULT WINAPI packet_size_GetMinPacketSize(IWMPacketSize2 *iface, DWORD *size)
1324 FIXME("iface %p, size %p, stub!\n", iface, size);
1325 return E_NOTIMPL;
1328 static HRESULT WINAPI packet_size_SetMinPacketSize(IWMPacketSize2 *iface, DWORD size)
1330 FIXME("iface %p, size %lu, stub!\n", iface, size);
1331 return E_NOTIMPL;
1334 static const IWMPacketSize2Vtbl packet_size_vtbl =
1336 packet_size_QueryInterface,
1337 packet_size_AddRef,
1338 packet_size_Release,
1339 packet_size_GetMaxPacketSize,
1340 packet_size_SetMaxPacketSize,
1341 packet_size_GetMinPacketSize,
1342 packet_size_SetMinPacketSize,
1345 static struct wm_reader *impl_from_IWMReaderPlaylistBurn(IWMReaderPlaylistBurn *iface)
1347 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderPlaylistBurn_iface);
1350 static HRESULT WINAPI playlist_QueryInterface(IWMReaderPlaylistBurn *iface, REFIID iid, void **out)
1352 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1353 return IUnknown_QueryInterface(reader->outer, iid, out);
1356 static ULONG WINAPI playlist_AddRef(IWMReaderPlaylistBurn *iface)
1358 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1359 return IUnknown_AddRef(reader->outer);
1362 static ULONG WINAPI playlist_Release(IWMReaderPlaylistBurn *iface)
1364 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1365 return IUnknown_Release(reader->outer);
1368 static HRESULT WINAPI playlist_InitPlaylistBurn(IWMReaderPlaylistBurn *iface, DWORD count,
1369 const WCHAR **filenames, IWMStatusCallback *callback, void *context)
1371 FIXME("iface %p, count %lu, filenames %p, callback %p, context %p, stub!\n",
1372 iface, count, filenames, callback, context);
1373 return E_NOTIMPL;
1376 static HRESULT WINAPI playlist_GetInitResults(IWMReaderPlaylistBurn *iface, DWORD count, HRESULT *hrs)
1378 FIXME("iface %p, count %lu, hrs %p, stub!\n", iface, count, hrs);
1379 return E_NOTIMPL;
1382 static HRESULT WINAPI playlist_Cancel(IWMReaderPlaylistBurn *iface)
1384 FIXME("iface %p, stub!\n", iface);
1385 return E_NOTIMPL;
1388 static HRESULT WINAPI playlist_EndPlaylistBurn(IWMReaderPlaylistBurn *iface, HRESULT hr)
1390 FIXME("iface %p, hr %#lx, stub!\n", iface, hr);
1391 return E_NOTIMPL;
1394 static const IWMReaderPlaylistBurnVtbl playlist_vtbl =
1396 playlist_QueryInterface,
1397 playlist_AddRef,
1398 playlist_Release,
1399 playlist_InitPlaylistBurn,
1400 playlist_GetInitResults,
1401 playlist_Cancel,
1402 playlist_EndPlaylistBurn,
1405 static struct wm_reader *impl_from_IWMReaderTimecode(IWMReaderTimecode *iface)
1407 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderTimecode_iface);
1410 static HRESULT WINAPI timecode_QueryInterface(IWMReaderTimecode *iface, REFIID iid, void **out)
1412 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1413 return IUnknown_QueryInterface(reader->outer, iid, out);
1416 static ULONG WINAPI timecode_AddRef(IWMReaderTimecode *iface)
1418 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1419 return IUnknown_AddRef(reader->outer);
1422 static ULONG WINAPI timecode_Release(IWMReaderTimecode *iface)
1424 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1425 return IUnknown_Release(reader->outer);
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 /* API consumers expect RGB video to be bottom-up. */
1513 if (stream->format.u.video.height > 0)
1514 stream->format.u.video.height = -stream->format.u.video.height;
1516 wg_parser_stream_enable(stream->wg_stream, &stream->format);
1519 /* We probably discarded events because streams weren't enabled yet.
1520 * Now that they're all enabled seek back to the start again. */
1521 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0,
1522 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
1524 return S_OK;
1526 out_disconnect_parser:
1527 wg_parser_disconnect(reader->wg_parser);
1529 out_shutdown_thread:
1530 reader->read_thread_shutdown = true;
1531 WaitForSingleObject(reader->read_thread, INFINITE);
1532 CloseHandle(reader->read_thread);
1533 reader->read_thread = NULL;
1535 out_destroy_parser:
1536 wg_parser_destroy(reader->wg_parser);
1537 reader->wg_parser = NULL;
1539 return hr;
1542 static struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number)
1544 if (stream_number && stream_number <= reader->stream_count)
1545 return &reader->streams[stream_number - 1];
1546 WARN("Invalid stream number %u.\n", stream_number);
1547 return NULL;
1550 static const enum wg_video_format video_formats[] =
1552 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
1553 * YUV color space, and it's generally much less expensive for
1554 * videoconvert to do YUV -> YUV transformations. */
1555 WG_VIDEO_FORMAT_NV12,
1556 WG_VIDEO_FORMAT_YV12,
1557 WG_VIDEO_FORMAT_YUY2,
1558 WG_VIDEO_FORMAT_UYVY,
1559 WG_VIDEO_FORMAT_YVYU,
1560 WG_VIDEO_FORMAT_BGRx,
1561 WG_VIDEO_FORMAT_BGR,
1562 WG_VIDEO_FORMAT_RGB16,
1563 WG_VIDEO_FORMAT_RGB15,
1566 static const char *get_major_type_string(enum wg_major_type type)
1568 switch (type)
1570 case WG_MAJOR_TYPE_AUDIO:
1571 return "audio";
1572 case WG_MAJOR_TYPE_AUDIO_MPEG1:
1573 return "mpeg1-audio";
1574 case WG_MAJOR_TYPE_AUDIO_MPEG4:
1575 return "mpeg4-audio";
1576 case WG_MAJOR_TYPE_AUDIO_WMA:
1577 return "wma";
1578 case WG_MAJOR_TYPE_VIDEO:
1579 return "video";
1580 case WG_MAJOR_TYPE_VIDEO_CINEPAK:
1581 return "cinepak";
1582 case WG_MAJOR_TYPE_VIDEO_H264:
1583 return "h264";
1584 case WG_MAJOR_TYPE_VIDEO_WMV:
1585 return "wmv";
1586 case WG_MAJOR_TYPE_VIDEO_INDEO:
1587 return "indeo";
1588 case WG_MAJOR_TYPE_UNKNOWN:
1589 return "unknown";
1591 assert(0);
1592 return NULL;
1595 static HRESULT wm_stream_allocate_sample(struct wm_stream *stream, DWORD size, INSSBuffer **sample)
1597 struct buffer *buffer;
1599 if (!stream->read_compressed && stream->output_allocator)
1600 return IWMReaderAllocatorEx_AllocateForOutputEx(stream->output_allocator, stream->index,
1601 size, sample, 0, 0, 0, NULL);
1603 if (stream->read_compressed && stream->stream_allocator)
1604 return IWMReaderAllocatorEx_AllocateForStreamEx(stream->stream_allocator, stream->index + 1,
1605 size, sample, 0, 0, 0, NULL);
1607 /* FIXME: Should these be pooled? */
1608 if (!(buffer = calloc(1, offsetof(struct buffer, data[size]))))
1609 return E_OUTOFMEMORY;
1610 buffer->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
1611 buffer->refcount = 1;
1612 buffer->capacity = size;
1614 TRACE("Created buffer %p.\n", buffer);
1615 *sample = &buffer->INSSBuffer_iface;
1616 return S_OK;
1619 static HRESULT wm_reader_read_stream_sample(struct wm_reader *reader, struct wg_parser_buffer *buffer,
1620 INSSBuffer **sample, QWORD *pts, QWORD *duration, DWORD *flags)
1622 struct wm_stream *stream;
1623 DWORD size, capacity;
1624 HRESULT hr;
1625 BYTE *data;
1627 if (!(stream = wm_reader_get_stream_by_stream_number(reader, buffer->stream + 1)))
1628 return E_INVALIDARG;
1630 TRACE("Got buffer for '%s' stream %p.\n", get_major_type_string(stream->format.major_type), stream);
1632 if (FAILED(hr = wm_stream_allocate_sample(stream, buffer->size, sample)))
1634 ERR("Failed to allocate sample of %u bytes, hr %#lx.\n", buffer->size, hr);
1635 wg_parser_stream_release_buffer(stream->wg_stream);
1636 return hr;
1639 if (FAILED(hr = INSSBuffer_GetBufferAndLength(*sample, &data, &size)))
1640 ERR("Failed to get data pointer, hr %#lx.\n", hr);
1641 if (FAILED(hr = INSSBuffer_GetMaxLength(*sample, &capacity)))
1642 ERR("Failed to get capacity, hr %#lx.\n", hr);
1643 if (buffer->size > capacity)
1644 ERR("Returned capacity %lu is less than requested capacity %u.\n", capacity, buffer->size);
1646 if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, buffer->size))
1648 /* The GStreamer pin has been flushed. */
1649 INSSBuffer_Release(*sample);
1650 *sample = NULL;
1651 return S_FALSE;
1654 if (FAILED(hr = INSSBuffer_SetLength(*sample, buffer->size)))
1655 ERR("Failed to set size %u, hr %#lx.\n", buffer->size, hr);
1657 wg_parser_stream_release_buffer(stream->wg_stream);
1659 if (!buffer->has_pts)
1660 FIXME("Missing PTS.\n");
1661 if (!buffer->has_duration)
1662 FIXME("Missing duration.\n");
1664 *pts = buffer->pts;
1665 *duration = buffer->duration;
1666 *flags = 0;
1667 if (buffer->discontinuity)
1668 *flags |= WM_SF_DISCONTINUITY;
1669 if (!buffer->delta)
1670 *flags |= WM_SF_CLEANPOINT;
1672 return S_OK;
1675 static struct wm_reader *impl_from_IUnknown(IUnknown *iface)
1677 return CONTAINING_RECORD(iface, struct wm_reader, IUnknown_inner);
1680 static HRESULT WINAPI unknown_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out)
1682 struct wm_reader *reader = impl_from_IUnknown(iface);
1684 TRACE("reader %p, iid %s, out %p.\n", reader, debugstr_guid(iid), out);
1686 if (IsEqualIID(iid, &IID_IUnknown)
1687 || IsEqualIID(iid, &IID_IWMSyncReader)
1688 || IsEqualIID(iid, &IID_IWMSyncReader2))
1689 *out = &reader->IWMSyncReader2_iface;
1690 else if (IsEqualIID(iid, &IID_IWMHeaderInfo)
1691 || IsEqualIID(iid, &IID_IWMHeaderInfo2)
1692 || IsEqualIID(iid, &IID_IWMHeaderInfo3))
1693 *out = &reader->IWMHeaderInfo3_iface;
1694 else if (IsEqualIID(iid, &IID_IWMLanguageList))
1695 *out = &reader->IWMLanguageList_iface;
1696 else if (IsEqualIID(iid, &IID_IWMPacketSize)
1697 || IsEqualIID(iid, &IID_IWMPacketSize2))
1698 *out = &reader->IWMPacketSize2_iface;
1699 else if (IsEqualIID(iid, &IID_IWMProfile)
1700 || IsEqualIID(iid, &IID_IWMProfile2)
1701 || IsEqualIID(iid, &IID_IWMProfile3))
1702 *out = &reader->IWMProfile3_iface;
1703 else if (IsEqualIID(iid, &IID_IWMReaderPlaylistBurn))
1704 *out = &reader->IWMReaderPlaylistBurn_iface;
1705 else if (IsEqualIID(iid, &IID_IWMReaderTimecode))
1706 *out = &reader->IWMReaderTimecode_iface;
1707 else
1709 FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1710 *out = NULL;
1711 return E_NOINTERFACE;
1714 IUnknown_AddRef((IUnknown *)*out);
1715 return S_OK;
1718 static ULONG WINAPI unknown_inner_AddRef(IUnknown *iface)
1720 struct wm_reader *reader = impl_from_IUnknown(iface);
1721 ULONG refcount = InterlockedIncrement(&reader->refcount);
1722 TRACE("%p increasing refcount to %lu.\n", reader, refcount);
1723 return refcount;
1726 static ULONG WINAPI unknown_inner_Release(IUnknown *iface)
1728 struct wm_reader *reader = impl_from_IUnknown(iface);
1729 ULONG refcount = InterlockedDecrement(&reader->refcount);
1731 TRACE("%p decreasing refcount to %lu.\n", reader, refcount);
1733 if (!refcount)
1735 IWMSyncReader2_Close(&reader->IWMSyncReader2_iface);
1737 reader->cs.DebugInfo->Spare[0] = 0;
1738 DeleteCriticalSection(&reader->cs);
1740 free(reader);
1743 return refcount;
1746 static const IUnknownVtbl unknown_inner_vtbl =
1748 unknown_inner_QueryInterface,
1749 unknown_inner_AddRef,
1750 unknown_inner_Release,
1753 static struct wm_reader *impl_from_IWMSyncReader2(IWMSyncReader2 *iface)
1755 return CONTAINING_RECORD(iface, struct wm_reader, IWMSyncReader2_iface);
1758 static HRESULT WINAPI reader_QueryInterface(IWMSyncReader2 *iface, REFIID iid, void **out)
1760 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1761 return IUnknown_QueryInterface(reader->outer, iid, out);
1764 static ULONG WINAPI reader_AddRef(IWMSyncReader2 *iface)
1766 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1767 return IUnknown_AddRef(reader->outer);
1770 static ULONG WINAPI reader_Release(IWMSyncReader2 *iface)
1772 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1773 return IUnknown_Release(reader->outer);
1776 static HRESULT WINAPI reader_Close(IWMSyncReader2 *iface)
1778 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1780 TRACE("reader %p.\n", reader);
1782 EnterCriticalSection(&reader->cs);
1784 if (!reader->wg_parser)
1786 LeaveCriticalSection(&reader->cs);
1787 return NS_E_INVALID_REQUEST;
1790 wg_parser_disconnect(reader->wg_parser);
1792 reader->read_thread_shutdown = true;
1793 WaitForSingleObject(reader->read_thread, INFINITE);
1794 CloseHandle(reader->read_thread);
1795 reader->read_thread = NULL;
1797 wg_parser_destroy(reader->wg_parser);
1798 reader->wg_parser = NULL;
1800 if (reader->source_stream)
1801 IStream_Release(reader->source_stream);
1802 reader->source_stream = NULL;
1803 if (reader->file)
1804 CloseHandle(reader->file);
1805 reader->file = NULL;
1807 LeaveCriticalSection(&reader->cs);
1808 return S_OK;
1811 static HRESULT WINAPI reader_GetMaxOutputSampleSize(IWMSyncReader2 *iface, DWORD output, DWORD *max)
1813 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
1814 FIXME("(%p)->(%lu %p): stub!\n", This, output, max);
1815 return E_NOTIMPL;
1818 static HRESULT WINAPI reader_GetMaxStreamSampleSize(IWMSyncReader2 *iface, WORD stream_number, DWORD *size)
1820 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1821 struct wm_stream *stream;
1823 TRACE("reader %p, stream_number %u, size %p.\n", reader, stream_number, size);
1825 EnterCriticalSection(&reader->cs);
1827 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
1829 LeaveCriticalSection(&reader->cs);
1830 return E_INVALIDARG;
1833 *size = wg_format_get_max_size(&stream->format);
1835 LeaveCriticalSection(&reader->cs);
1836 return S_OK;
1839 static HRESULT WINAPI reader_GetNextSample(IWMSyncReader2 *iface,
1840 WORD stream_number, INSSBuffer **sample, QWORD *pts, QWORD *duration,
1841 DWORD *flags, DWORD *output_number, WORD *ret_stream_number)
1843 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1844 struct wm_stream *stream;
1845 HRESULT hr = S_FALSE;
1847 TRACE("reader %p, stream_number %u, sample %p, pts %p, duration %p,"
1848 " flags %p, output_number %p, ret_stream_number %p.\n",
1849 reader, stream_number, sample, pts, duration, flags, output_number, ret_stream_number);
1851 if (!stream_number && !output_number && !ret_stream_number)
1852 return E_INVALIDARG;
1854 EnterCriticalSection(&reader->cs);
1856 if (!stream_number)
1857 stream = NULL;
1858 else if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
1859 hr = E_INVALIDARG;
1860 else if (stream->selection == WMT_OFF)
1861 hr = NS_E_INVALID_REQUEST;
1862 else if (stream->eos)
1863 hr = NS_E_NO_MORE_SAMPLES;
1865 while (hr == S_FALSE)
1867 struct wg_parser_buffer wg_buffer;
1868 if (!wg_parser_stream_get_buffer(reader->wg_parser, stream ? stream->wg_stream : NULL, &wg_buffer))
1869 hr = NS_E_NO_MORE_SAMPLES;
1870 else if (SUCCEEDED(hr = wm_reader_read_stream_sample(reader, &wg_buffer, sample, pts, duration, flags)))
1871 stream_number = wg_buffer.stream + 1;
1874 if (stream && hr == NS_E_NO_MORE_SAMPLES)
1875 stream->eos = true;
1877 if (output_number && hr == S_OK)
1878 *output_number = stream_number - 1;
1879 if (ret_stream_number && (hr == S_OK || stream_number))
1880 *ret_stream_number = stream_number;
1882 LeaveCriticalSection(&reader->cs);
1883 return hr;
1886 static HRESULT WINAPI reader_GetOutputCount(IWMSyncReader2 *iface, DWORD *count)
1888 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1890 TRACE("reader %p, count %p.\n", reader, count);
1892 EnterCriticalSection(&reader->cs);
1893 *count = reader->stream_count;
1894 LeaveCriticalSection(&reader->cs);
1895 return S_OK;
1898 static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface,
1899 DWORD output, DWORD index, IWMOutputMediaProps **props)
1901 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1902 struct wm_stream *stream;
1903 struct wg_format format;
1905 TRACE("reader %p, output %lu, index %lu, props %p.\n", reader, output, index, props);
1907 EnterCriticalSection(&reader->cs);
1909 if (!(stream = get_stream_by_output_number(reader, output)))
1911 LeaveCriticalSection(&reader->cs);
1912 return E_INVALIDARG;
1915 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
1917 switch (format.major_type)
1919 case WG_MAJOR_TYPE_VIDEO:
1920 if (index >= ARRAY_SIZE(video_formats))
1922 LeaveCriticalSection(&reader->cs);
1923 return NS_E_INVALID_OUTPUT_FORMAT;
1925 format.u.video.format = video_formats[index];
1926 /* API consumers expect RGB video to be bottom-up. */
1927 if (format.u.video.height > 0 && wg_video_format_is_rgb(format.u.video.format))
1928 format.u.video.height = -format.u.video.height;
1929 break;
1931 case WG_MAJOR_TYPE_AUDIO:
1932 if (index)
1934 LeaveCriticalSection(&reader->cs);
1935 return NS_E_INVALID_OUTPUT_FORMAT;
1937 format.u.audio.format = WG_AUDIO_FORMAT_S16LE;
1938 break;
1940 case WG_MAJOR_TYPE_AUDIO_MPEG1:
1941 case WG_MAJOR_TYPE_AUDIO_MPEG4:
1942 case WG_MAJOR_TYPE_AUDIO_WMA:
1943 case WG_MAJOR_TYPE_VIDEO_CINEPAK:
1944 case WG_MAJOR_TYPE_VIDEO_H264:
1945 case WG_MAJOR_TYPE_VIDEO_WMV:
1946 case WG_MAJOR_TYPE_VIDEO_INDEO:
1947 FIXME("Format %u not implemented!\n", format.major_type);
1948 break;
1949 case WG_MAJOR_TYPE_UNKNOWN:
1950 break;
1953 LeaveCriticalSection(&reader->cs);
1955 *props = output_props_create(&format);
1956 return *props ? S_OK : E_OUTOFMEMORY;
1959 static HRESULT WINAPI reader_GetOutputFormatCount(IWMSyncReader2 *iface, DWORD output, DWORD *count)
1961 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1962 struct wm_stream *stream;
1963 struct wg_format format;
1965 TRACE("reader %p, output %lu, count %p.\n", reader, output, count);
1967 EnterCriticalSection(&reader->cs);
1969 if (!(stream = get_stream_by_output_number(reader, output)))
1971 LeaveCriticalSection(&reader->cs);
1972 return E_INVALIDARG;
1975 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
1976 switch (format.major_type)
1978 case WG_MAJOR_TYPE_VIDEO:
1979 *count = ARRAY_SIZE(video_formats);
1980 break;
1982 case WG_MAJOR_TYPE_AUDIO_MPEG1:
1983 case WG_MAJOR_TYPE_AUDIO_MPEG4:
1984 case WG_MAJOR_TYPE_AUDIO_WMA:
1985 case WG_MAJOR_TYPE_VIDEO_CINEPAK:
1986 case WG_MAJOR_TYPE_VIDEO_H264:
1987 case WG_MAJOR_TYPE_VIDEO_WMV:
1988 case WG_MAJOR_TYPE_VIDEO_INDEO:
1989 FIXME("Format %u not implemented!\n", format.major_type);
1990 /* fallthrough */
1991 case WG_MAJOR_TYPE_AUDIO:
1992 case WG_MAJOR_TYPE_UNKNOWN:
1993 *count = 1;
1994 break;
1997 LeaveCriticalSection(&reader->cs);
1998 return S_OK;
2001 static HRESULT WINAPI reader_GetOutputNumberForStream(IWMSyncReader2 *iface,
2002 WORD stream_number, DWORD *output)
2004 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2006 TRACE("reader %p, stream_number %u, output %p.\n", reader, stream_number, output);
2008 *output = stream_number - 1;
2009 return S_OK;
2012 static HRESULT WINAPI reader_GetOutputProps(IWMSyncReader2 *iface,
2013 DWORD output, IWMOutputMediaProps **props)
2015 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2016 struct wm_stream *stream;
2018 TRACE("reader %p, output %lu, props %p.\n", reader, output, props);
2020 EnterCriticalSection(&reader->cs);
2022 if (!(stream = get_stream_by_output_number(reader, output)))
2024 LeaveCriticalSection(&reader->cs);
2025 return E_INVALIDARG;
2028 *props = output_props_create(&stream->format);
2029 LeaveCriticalSection(&reader->cs);
2030 return *props ? S_OK : E_OUTOFMEMORY;
2033 static HRESULT WINAPI reader_GetOutputSetting(IWMSyncReader2 *iface, DWORD output_num, const WCHAR *name,
2034 WMT_ATTR_DATATYPE *type, BYTE *value, WORD *length)
2036 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2037 FIXME("(%p)->(%lu %s %p %p %p): stub!\n", This, output_num, debugstr_w(name), type, value, length);
2038 return E_NOTIMPL;
2041 static HRESULT WINAPI reader_GetReadStreamSamples(IWMSyncReader2 *iface, WORD stream_number, BOOL *compressed)
2043 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2044 struct wm_stream *stream;
2046 TRACE("reader %p, stream_number %u, compressed %p.\n", reader, stream_number, compressed);
2048 EnterCriticalSection(&reader->cs);
2050 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2052 LeaveCriticalSection(&reader->cs);
2053 return E_INVALIDARG;
2056 *compressed = stream->read_compressed;
2058 LeaveCriticalSection(&reader->cs);
2059 return S_OK;
2062 static HRESULT WINAPI reader_GetStreamNumberForOutput(IWMSyncReader2 *iface,
2063 DWORD output, WORD *stream_number)
2065 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2067 TRACE("reader %p, output %lu, stream_number %p.\n", reader, output, stream_number);
2069 *stream_number = output + 1;
2070 return S_OK;
2073 static HRESULT WINAPI reader_GetStreamSelected(IWMSyncReader2 *iface,
2074 WORD stream_number, WMT_STREAM_SELECTION *selection)
2076 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2077 struct wm_stream *stream;
2079 TRACE("reader %p, stream_number %u, selection %p.\n", reader, stream_number, selection);
2081 EnterCriticalSection(&reader->cs);
2083 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2085 LeaveCriticalSection(&reader->cs);
2086 return E_INVALIDARG;
2089 *selection = stream->selection;
2091 LeaveCriticalSection(&reader->cs);
2092 return S_OK;
2095 static HRESULT WINAPI reader_Open(IWMSyncReader2 *iface, const WCHAR *filename)
2097 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2098 LARGE_INTEGER size;
2099 HANDLE file;
2100 HRESULT hr;
2102 TRACE("reader %p, filename %s.\n", reader, debugstr_w(filename));
2104 if ((file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2105 OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
2107 ERR("Failed to open %s, error %lu.\n", debugstr_w(filename), GetLastError());
2108 return HRESULT_FROM_WIN32(GetLastError());
2111 if (!GetFileSizeEx(file, &size))
2113 ERR("Failed to get the size of %s, error %lu.\n", debugstr_w(filename), GetLastError());
2114 CloseHandle(file);
2115 return HRESULT_FROM_WIN32(GetLastError());
2118 EnterCriticalSection(&reader->cs);
2120 if (reader->wg_parser)
2122 LeaveCriticalSection(&reader->cs);
2123 WARN("Stream is already open; returning E_UNEXPECTED.\n");
2124 CloseHandle(file);
2125 return E_UNEXPECTED;
2128 reader->file = file;
2130 if (FAILED(hr = init_stream(reader, size.QuadPart)))
2131 reader->file = NULL;
2133 LeaveCriticalSection(&reader->cs);
2134 return hr;
2137 static HRESULT WINAPI reader_OpenStream(IWMSyncReader2 *iface, IStream *stream)
2139 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2140 STATSTG stat;
2141 HRESULT hr;
2143 TRACE("reader %p, stream %p.\n", reader, stream);
2145 if (FAILED(hr = IStream_Stat(stream, &stat, STATFLAG_NONAME)))
2147 ERR("Failed to stat stream, hr %#lx.\n", hr);
2148 return hr;
2151 EnterCriticalSection(&reader->cs);
2153 if (reader->wg_parser)
2155 LeaveCriticalSection(&reader->cs);
2156 WARN("Stream is already open; returning E_UNEXPECTED.\n");
2157 return E_UNEXPECTED;
2160 IStream_AddRef(reader->source_stream = stream);
2161 if (FAILED(hr = init_stream(reader, stat.cbSize.QuadPart)))
2163 IStream_Release(stream);
2164 reader->source_stream = NULL;
2167 LeaveCriticalSection(&reader->cs);
2168 return hr;
2171 static HRESULT WINAPI reader_SetOutputProps(IWMSyncReader2 *iface, DWORD output, IWMOutputMediaProps *props_iface)
2173 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2174 struct output_props *props = unsafe_impl_from_IWMOutputMediaProps(props_iface);
2175 struct wg_format format, pref_format;
2176 struct wm_stream *stream;
2177 HRESULT hr = S_OK;
2178 int i;
2180 TRACE("reader %p, output %lu, props_iface %p.\n", reader, output, props_iface);
2182 strmbase_dump_media_type(&props->mt);
2184 if (!amt_to_wg_format(&props->mt, &format))
2186 ERR("Failed to convert media type to winegstreamer format.\n");
2187 return E_FAIL;
2190 EnterCriticalSection(&reader->cs);
2192 if (!(stream = get_stream_by_output_number(reader, output)))
2194 LeaveCriticalSection(&reader->cs);
2195 return E_INVALIDARG;
2198 wg_parser_stream_get_preferred_format(stream->wg_stream, &pref_format);
2199 if (pref_format.major_type != format.major_type)
2201 /* R.U.S.E sets the type of the wrong stream, apparently by accident. */
2202 hr = NS_E_INCOMPATIBLE_FORMAT;
2204 else switch (pref_format.major_type)
2206 case WG_MAJOR_TYPE_AUDIO:
2207 if (format.u.audio.format == WG_AUDIO_FORMAT_UNKNOWN)
2208 hr = NS_E_AUDIO_CODEC_NOT_INSTALLED;
2209 else if (format.u.audio.channels > pref_format.u.audio.channels)
2210 hr = NS_E_AUDIO_CODEC_NOT_INSTALLED;
2211 break;
2213 case WG_MAJOR_TYPE_VIDEO:
2214 for (i = 0; i < ARRAY_SIZE(video_formats); ++i)
2215 if (format.u.video.format == video_formats[i])
2216 break;
2217 if (i == ARRAY_SIZE(video_formats))
2218 hr = NS_E_INVALID_OUTPUT_FORMAT;
2219 else if (pref_format.u.video.width != format.u.video.width)
2220 hr = NS_E_INVALID_OUTPUT_FORMAT;
2221 else if (abs(pref_format.u.video.height) != abs(format.u.video.height))
2222 hr = NS_E_INVALID_OUTPUT_FORMAT;
2223 break;
2225 default:
2226 hr = NS_E_INCOMPATIBLE_FORMAT;
2227 break;
2230 if (FAILED(hr))
2232 WARN("Unsupported media type, returning %#lx.\n", hr);
2233 LeaveCriticalSection(&reader->cs);
2234 return hr;
2237 stream->format = format;
2238 wg_parser_stream_enable(stream->wg_stream, &format);
2240 /* Re-decode any buffers that might have been generated with the old format.
2242 * FIXME: Seeking in-place will cause some buffers to be dropped.
2243 * Unfortunately, we can't really store the last received PTS and seek there
2244 * either: since seeks are inexact and we aren't guaranteed to receive
2245 * samples in order, some buffers might be duplicated or dropped anyway.
2246 * In order to really seamlessly allow for format changes, we need
2247 * cooperation from each individual GStreamer stream, to be able to tell
2248 * upstream exactly which buffers they need resent...
2250 * In all likelihood this function is being called not mid-stream but rather
2251 * while setting the stream up, before consuming any events. Accordingly
2252 * let's just seek back to the beginning. */
2253 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, reader->start_time, 0,
2254 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
2256 LeaveCriticalSection(&reader->cs);
2257 return S_OK;
2260 static HRESULT WINAPI reader_SetOutputSetting(IWMSyncReader2 *iface, DWORD output,
2261 const WCHAR *name, WMT_ATTR_DATATYPE type, const BYTE *value, WORD size)
2263 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2265 TRACE("reader %p, output %lu, name %s, type %#x, value %p, size %u.\n",
2266 reader, output, debugstr_w(name), type, value, size);
2268 if (!wcscmp(name, L"VideoSampleDurations"))
2270 FIXME("Ignoring VideoSampleDurations setting.\n");
2271 return S_OK;
2273 if (!wcscmp(name, L"EnableDiscreteOutput"))
2275 FIXME("Ignoring EnableDiscreteOutput setting.\n");
2276 return S_OK;
2278 if (!wcscmp(name, L"SpeakerConfig"))
2280 FIXME("Ignoring SpeakerConfig setting.\n");
2281 return S_OK;
2283 else
2285 FIXME("Unknown setting %s; returning E_NOTIMPL.\n", debugstr_w(name));
2286 return E_NOTIMPL;
2290 static HRESULT WINAPI reader_SetRange(IWMSyncReader2 *iface, QWORD start, LONGLONG duration)
2292 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2293 WORD i;
2295 TRACE("reader %p, start %I64u, duration %I64d.\n", reader, start, duration);
2297 EnterCriticalSection(&reader->cs);
2299 reader->start_time = start;
2301 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, start, start + duration,
2302 AM_SEEKING_AbsolutePositioning, duration ? AM_SEEKING_AbsolutePositioning : AM_SEEKING_NoPositioning);
2304 for (i = 0; i < reader->stream_count; ++i)
2305 reader->streams[i].eos = false;
2307 LeaveCriticalSection(&reader->cs);
2308 return S_OK;
2311 static HRESULT WINAPI reader_SetRangeByFrame(IWMSyncReader2 *iface, WORD stream_num, QWORD frame_num,
2312 LONGLONG frames)
2314 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2315 FIXME("(%p)->(%d %s %s): stub!\n", This, stream_num, wine_dbgstr_longlong(frame_num), wine_dbgstr_longlong(frames));
2316 return E_NOTIMPL;
2319 static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD stream_number, BOOL compressed)
2321 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2322 struct wm_stream *stream;
2324 TRACE("reader %p, stream_index %u, compressed %d.\n", reader, stream_number, compressed);
2326 EnterCriticalSection(&reader->cs);
2328 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2330 LeaveCriticalSection(&reader->cs);
2331 return E_INVALIDARG;
2334 stream->read_compressed = compressed;
2336 LeaveCriticalSection(&reader->cs);
2337 return S_OK;
2340 static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface,
2341 WORD count, WORD *stream_numbers, WMT_STREAM_SELECTION *selections)
2343 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2344 struct wm_stream *stream;
2345 WORD i;
2347 TRACE("reader %p, count %u, stream_numbers %p, selections %p.\n",
2348 reader, count, stream_numbers, selections);
2350 if (!count)
2351 return E_INVALIDARG;
2353 EnterCriticalSection(&reader->cs);
2355 for (i = 0; i < count; ++i)
2357 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_numbers[i])))
2359 LeaveCriticalSection(&reader->cs);
2360 WARN("Invalid stream number %u; returning NS_E_INVALID_REQUEST.\n", stream_numbers[i]);
2361 return NS_E_INVALID_REQUEST;
2365 for (i = 0; i < count; ++i)
2367 stream = wm_reader_get_stream_by_stream_number(reader, stream_numbers[i]);
2368 stream->selection = selections[i];
2369 if (selections[i] == WMT_OFF)
2371 TRACE("Disabling stream %u.\n", stream_numbers[i]);
2372 wg_parser_stream_disable(stream->wg_stream);
2374 else if (selections[i] == WMT_ON)
2376 if (selections[i] != WMT_ON)
2377 FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n",
2378 selections[i], stream_numbers[i]);
2379 TRACE("Enabling stream %u.\n", stream_numbers[i]);
2380 wg_parser_stream_enable(stream->wg_stream, &stream->format);
2384 LeaveCriticalSection(&reader->cs);
2385 return S_OK;
2388 static HRESULT WINAPI reader_SetRangeByTimecode(IWMSyncReader2 *iface, WORD stream_num,
2389 WMT_TIMECODE_EXTENSION_DATA *start, WMT_TIMECODE_EXTENSION_DATA *end)
2391 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2392 FIXME("(%p)->(%u %p %p): stub!\n", This, stream_num, start, end);
2393 return E_NOTIMPL;
2396 static HRESULT WINAPI reader_SetRangeByFrameEx(IWMSyncReader2 *iface, WORD stream_num, QWORD frame_num,
2397 LONGLONG frames_to_read, QWORD *starttime)
2399 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2400 FIXME("(%p)->(%u %s %s %p): stub!\n", This, stream_num, wine_dbgstr_longlong(frame_num),
2401 wine_dbgstr_longlong(frames_to_read), starttime);
2402 return E_NOTIMPL;
2405 static HRESULT WINAPI reader_SetAllocateForOutput(IWMSyncReader2 *iface, DWORD output, IWMReaderAllocatorEx *allocator)
2407 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2408 struct wm_stream *stream;
2410 TRACE("reader %p, output %lu, allocator %p.\n", reader, output, allocator);
2412 EnterCriticalSection(&reader->cs);
2414 if (!(stream = get_stream_by_output_number(reader, output)))
2416 LeaveCriticalSection(&reader->cs);
2417 return E_INVALIDARG;
2420 if (stream->output_allocator)
2421 IWMReaderAllocatorEx_Release(stream->output_allocator);
2422 if ((stream->output_allocator = allocator))
2423 IWMReaderAllocatorEx_AddRef(stream->output_allocator);
2425 LeaveCriticalSection(&reader->cs);
2426 return S_OK;
2429 static HRESULT WINAPI reader_GetAllocateForOutput(IWMSyncReader2 *iface, DWORD output, IWMReaderAllocatorEx **allocator)
2431 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2432 struct wm_stream *stream;
2434 TRACE("reader %p, output %lu, allocator %p.\n", reader, output, allocator);
2436 if (!allocator)
2437 return E_INVALIDARG;
2439 EnterCriticalSection(&reader->cs);
2441 if (!(stream = get_stream_by_output_number(reader, output)))
2443 LeaveCriticalSection(&reader->cs);
2444 return E_INVALIDARG;
2447 stream = reader->streams + output;
2448 if ((*allocator = stream->output_allocator))
2449 IWMReaderAllocatorEx_AddRef(*allocator);
2451 LeaveCriticalSection(&reader->cs);
2452 return S_OK;
2455 static HRESULT WINAPI reader_SetAllocateForStream(IWMSyncReader2 *iface, DWORD stream_number, IWMReaderAllocatorEx *allocator)
2457 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2458 struct wm_stream *stream;
2460 TRACE("reader %p, stream_number %lu, allocator %p.\n", reader, stream_number, allocator);
2462 EnterCriticalSection(&reader->cs);
2464 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2466 LeaveCriticalSection(&reader->cs);
2467 return E_INVALIDARG;
2470 if (stream->stream_allocator)
2471 IWMReaderAllocatorEx_Release(stream->stream_allocator);
2472 if ((stream->stream_allocator = allocator))
2473 IWMReaderAllocatorEx_AddRef(stream->stream_allocator);
2475 LeaveCriticalSection(&reader->cs);
2476 return S_OK;
2479 static HRESULT WINAPI reader_GetAllocateForStream(IWMSyncReader2 *iface, DWORD stream_number, IWMReaderAllocatorEx **allocator)
2481 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2482 struct wm_stream *stream;
2484 TRACE("reader %p, stream_number %lu, allocator %p.\n", reader, stream_number, allocator);
2486 if (!allocator)
2487 return E_INVALIDARG;
2489 EnterCriticalSection(&reader->cs);
2491 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2493 LeaveCriticalSection(&reader->cs);
2494 return E_INVALIDARG;
2497 if ((*allocator = stream->stream_allocator))
2498 IWMReaderAllocatorEx_AddRef(*allocator);
2500 LeaveCriticalSection(&reader->cs);
2501 return S_OK;
2504 static const IWMSyncReader2Vtbl reader_vtbl =
2506 reader_QueryInterface,
2507 reader_AddRef,
2508 reader_Release,
2509 reader_Open,
2510 reader_Close,
2511 reader_SetRange,
2512 reader_SetRangeByFrame,
2513 reader_GetNextSample,
2514 reader_SetStreamsSelected,
2515 reader_GetStreamSelected,
2516 reader_SetReadStreamSamples,
2517 reader_GetReadStreamSamples,
2518 reader_GetOutputSetting,
2519 reader_SetOutputSetting,
2520 reader_GetOutputCount,
2521 reader_GetOutputProps,
2522 reader_SetOutputProps,
2523 reader_GetOutputFormatCount,
2524 reader_GetOutputFormat,
2525 reader_GetOutputNumberForStream,
2526 reader_GetStreamNumberForOutput,
2527 reader_GetMaxOutputSampleSize,
2528 reader_GetMaxStreamSampleSize,
2529 reader_OpenStream,
2530 reader_SetRangeByTimecode,
2531 reader_SetRangeByFrameEx,
2532 reader_SetAllocateForOutput,
2533 reader_GetAllocateForOutput,
2534 reader_SetAllocateForStream,
2535 reader_GetAllocateForStream
2538 HRESULT WINAPI winegstreamer_create_wm_sync_reader(IUnknown *outer, void **out)
2540 struct wm_reader *object;
2542 TRACE("out %p.\n", out);
2544 if (!init_gstreamer())
2545 return E_FAIL;
2547 if (!(object = calloc(1, sizeof(*object))))
2548 return E_OUTOFMEMORY;
2550 object->IUnknown_inner.lpVtbl = &unknown_inner_vtbl;
2551 object->IWMSyncReader2_iface.lpVtbl = &reader_vtbl;
2552 object->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
2553 object->IWMLanguageList_iface.lpVtbl = &language_list_vtbl;
2554 object->IWMPacketSize2_iface.lpVtbl = &packet_size_vtbl;
2555 object->IWMProfile3_iface.lpVtbl = &profile_vtbl;
2556 object->IWMReaderPlaylistBurn_iface.lpVtbl = &playlist_vtbl;
2557 object->IWMReaderTimecode_iface.lpVtbl = &timecode_vtbl;
2558 object->outer = outer ? outer : &object->IUnknown_inner;
2559 object->refcount = 1;
2561 InitializeCriticalSection(&object->cs);
2562 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": reader.cs");
2564 TRACE("Created reader %p.\n", object);
2565 *out = outer ? (void *)&object->IUnknown_inner : (void *)&object->IWMSyncReader2_iface;
2566 return S_OK;