winegstreamer: Use IWMSyncReader2_GetNextSample in the async reader.
[wine.git] / dlls / winegstreamer / wm_reader.c
blobe68e0a7d0cabc186a5104d741c2512c687b4f5df
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 struct wm_stream
25 struct wm_reader *reader;
26 struct wg_parser_stream *wg_stream;
27 struct wg_format format;
28 WMT_STREAM_SELECTION selection;
29 WORD index;
30 bool eos;
31 /* Note that we only pretend to read compressed samples, and instead output
32 * uncompressed samples regardless of whether we are configured to read
33 * compressed samples. Rather, the behaviour of the reader objects differs
34 * in nontrivial ways depending on this field. */
35 bool read_compressed;
37 IWMReaderAllocatorEx *output_allocator;
38 IWMReaderAllocatorEx *stream_allocator;
41 struct wm_reader
43 IUnknown IUnknown_inner;
44 IWMSyncReader2 IWMSyncReader2_iface;
45 IWMHeaderInfo3 IWMHeaderInfo3_iface;
46 IWMLanguageList IWMLanguageList_iface;
47 IWMPacketSize2 IWMPacketSize2_iface;
48 IWMProfile3 IWMProfile3_iface;
49 IWMReaderPlaylistBurn IWMReaderPlaylistBurn_iface;
50 IWMReaderTimecode IWMReaderTimecode_iface;
51 IUnknown *outer;
52 LONG refcount;
54 CRITICAL_SECTION cs;
55 QWORD start_time;
57 IStream *source_stream;
58 HANDLE file;
59 HANDLE read_thread;
60 bool read_thread_shutdown;
61 struct wg_parser *wg_parser;
63 struct wm_stream *streams;
64 WORD stream_count;
67 static struct wm_stream *get_stream_by_output_number(struct wm_reader *reader, DWORD output)
69 if (output < reader->stream_count)
70 return &reader->streams[output];
71 WARN("Invalid output number %lu.\n", output);
72 return NULL;
75 struct output_props
77 IWMOutputMediaProps IWMOutputMediaProps_iface;
78 LONG refcount;
80 AM_MEDIA_TYPE mt;
83 static inline struct output_props *impl_from_IWMOutputMediaProps(IWMOutputMediaProps *iface)
85 return CONTAINING_RECORD(iface, struct output_props, IWMOutputMediaProps_iface);
88 static HRESULT WINAPI output_props_QueryInterface(IWMOutputMediaProps *iface, REFIID iid, void **out)
90 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
92 TRACE("props %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
94 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IWMOutputMediaProps))
95 *out = &props->IWMOutputMediaProps_iface;
96 else
98 *out = NULL;
99 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
100 return E_NOINTERFACE;
103 IUnknown_AddRef((IUnknown *)*out);
104 return S_OK;
107 static ULONG WINAPI output_props_AddRef(IWMOutputMediaProps *iface)
109 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
110 ULONG refcount = InterlockedIncrement(&props->refcount);
112 TRACE("%p increasing refcount to %lu.\n", props, refcount);
114 return refcount;
117 static ULONG WINAPI output_props_Release(IWMOutputMediaProps *iface)
119 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
120 ULONG refcount = InterlockedDecrement(&props->refcount);
122 TRACE("%p decreasing refcount to %lu.\n", props, refcount);
124 if (!refcount)
125 free(props);
127 return refcount;
130 static HRESULT WINAPI output_props_GetType(IWMOutputMediaProps *iface, GUID *major_type)
132 const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
134 TRACE("iface %p, major_type %p.\n", iface, major_type);
136 *major_type = props->mt.majortype;
137 return S_OK;
140 static HRESULT WINAPI output_props_GetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt, DWORD *size)
142 const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
143 const DWORD req_size = *size;
145 TRACE("iface %p, mt %p, size %p.\n", iface, mt, size);
147 *size = sizeof(*mt) + props->mt.cbFormat;
148 if (!mt)
149 return S_OK;
150 if (req_size < *size)
151 return ASF_E_BUFFERTOOSMALL;
153 strmbase_dump_media_type(&props->mt);
155 memcpy(mt, &props->mt, sizeof(*mt));
156 memcpy(mt + 1, props->mt.pbFormat, props->mt.cbFormat);
157 mt->pbFormat = (BYTE *)(mt + 1);
158 return S_OK;
161 static HRESULT WINAPI output_props_SetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt)
163 const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
165 TRACE("iface %p, mt %p.\n", iface, mt);
167 if (!mt)
168 return E_POINTER;
170 if (!IsEqualGUID(&props->mt.majortype, &mt->majortype))
171 return E_FAIL;
173 FreeMediaType((AM_MEDIA_TYPE *)&props->mt);
174 return CopyMediaType((AM_MEDIA_TYPE *)&props->mt, (AM_MEDIA_TYPE *)mt);
177 static HRESULT WINAPI output_props_GetStreamGroupName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
179 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
180 return E_NOTIMPL;
183 static HRESULT WINAPI output_props_GetConnectionName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
185 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
186 return E_NOTIMPL;
189 static const struct IWMOutputMediaPropsVtbl output_props_vtbl =
191 output_props_QueryInterface,
192 output_props_AddRef,
193 output_props_Release,
194 output_props_GetType,
195 output_props_GetMediaType,
196 output_props_SetMediaType,
197 output_props_GetStreamGroupName,
198 output_props_GetConnectionName,
201 static struct output_props *unsafe_impl_from_IWMOutputMediaProps(IWMOutputMediaProps *iface)
203 if (!iface)
204 return NULL;
205 assert(iface->lpVtbl == &output_props_vtbl);
206 return impl_from_IWMOutputMediaProps(iface);
209 static IWMOutputMediaProps *output_props_create(const struct wg_format *format)
211 struct output_props *object;
213 if (!(object = calloc(1, sizeof(*object))))
214 return NULL;
215 object->IWMOutputMediaProps_iface.lpVtbl = &output_props_vtbl;
216 object->refcount = 1;
218 if (!amt_from_wg_format(&object->mt, format, true))
220 free(object);
221 return NULL;
224 TRACE("Created output properties %p.\n", object);
225 return &object->IWMOutputMediaProps_iface;
228 struct buffer
230 INSSBuffer INSSBuffer_iface;
231 LONG refcount;
233 DWORD size, capacity;
234 BYTE data[1];
237 static struct buffer *impl_from_INSSBuffer(INSSBuffer *iface)
239 return CONTAINING_RECORD(iface, struct buffer, INSSBuffer_iface);
242 static HRESULT WINAPI buffer_QueryInterface(INSSBuffer *iface, REFIID iid, void **out)
244 struct buffer *buffer = impl_from_INSSBuffer(iface);
246 TRACE("buffer %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
248 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_INSSBuffer))
249 *out = &buffer->INSSBuffer_iface;
250 else
252 *out = NULL;
253 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
254 return E_NOINTERFACE;
257 IUnknown_AddRef((IUnknown *)*out);
258 return S_OK;
261 static ULONG WINAPI buffer_AddRef(INSSBuffer *iface)
263 struct buffer *buffer = impl_from_INSSBuffer(iface);
264 ULONG refcount = InterlockedIncrement(&buffer->refcount);
266 TRACE("%p increasing refcount to %lu.\n", buffer, refcount);
268 return refcount;
271 static ULONG WINAPI buffer_Release(INSSBuffer *iface)
273 struct buffer *buffer = impl_from_INSSBuffer(iface);
274 ULONG refcount = InterlockedDecrement(&buffer->refcount);
276 TRACE("%p decreasing refcount to %lu.\n", buffer, refcount);
278 if (!refcount)
279 free(buffer);
281 return refcount;
284 static HRESULT WINAPI buffer_GetLength(INSSBuffer *iface, DWORD *size)
286 FIXME("iface %p, size %p, stub!\n", iface, size);
287 return E_NOTIMPL;
290 static HRESULT WINAPI buffer_SetLength(INSSBuffer *iface, DWORD size)
292 struct buffer *buffer = impl_from_INSSBuffer(iface);
294 TRACE("iface %p, size %lu.\n", buffer, size);
296 if (size > buffer->capacity)
297 return E_INVALIDARG;
299 buffer->size = size;
300 return S_OK;
303 static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size)
305 struct buffer *buffer = impl_from_INSSBuffer(iface);
307 TRACE("buffer %p, size %p.\n", buffer, size);
309 *size = buffer->capacity;
310 return S_OK;
313 static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data)
315 struct buffer *buffer = impl_from_INSSBuffer(iface);
317 TRACE("buffer %p, data %p.\n", buffer, data);
319 *data = buffer->data;
320 return S_OK;
323 static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size)
325 struct buffer *buffer = impl_from_INSSBuffer(iface);
327 TRACE("buffer %p, data %p, size %p.\n", buffer, data, size);
329 *size = buffer->size;
330 *data = buffer->data;
331 return S_OK;
334 static const INSSBufferVtbl buffer_vtbl =
336 buffer_QueryInterface,
337 buffer_AddRef,
338 buffer_Release,
339 buffer_GetLength,
340 buffer_SetLength,
341 buffer_GetMaxLength,
342 buffer_GetBuffer,
343 buffer_GetBufferAndLength,
346 struct stream_config
348 IWMStreamConfig IWMStreamConfig_iface;
349 IWMMediaProps IWMMediaProps_iface;
350 LONG refcount;
352 const struct wm_stream *stream;
355 static struct stream_config *impl_from_IWMStreamConfig(IWMStreamConfig *iface)
357 return CONTAINING_RECORD(iface, struct stream_config, IWMStreamConfig_iface);
360 static HRESULT WINAPI stream_config_QueryInterface(IWMStreamConfig *iface, REFIID iid, void **out)
362 struct stream_config *config = impl_from_IWMStreamConfig(iface);
364 TRACE("config %p, iid %s, out %p.\n", config, debugstr_guid(iid), out);
366 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IWMStreamConfig))
367 *out = &config->IWMStreamConfig_iface;
368 else if (IsEqualGUID(iid, &IID_IWMMediaProps))
369 *out = &config->IWMMediaProps_iface;
370 else
372 *out = NULL;
373 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
374 return E_NOINTERFACE;
377 IUnknown_AddRef((IUnknown *)*out);
378 return S_OK;
381 static ULONG WINAPI stream_config_AddRef(IWMStreamConfig *iface)
383 struct stream_config *config = impl_from_IWMStreamConfig(iface);
384 ULONG refcount = InterlockedIncrement(&config->refcount);
386 TRACE("%p increasing refcount to %lu.\n", config, refcount);
388 return refcount;
391 static ULONG WINAPI stream_config_Release(IWMStreamConfig *iface)
393 struct stream_config *config = impl_from_IWMStreamConfig(iface);
394 ULONG refcount = InterlockedDecrement(&config->refcount);
396 TRACE("%p decreasing refcount to %lu.\n", config, refcount);
398 if (!refcount)
400 IWMProfile3_Release(&config->stream->reader->IWMProfile3_iface);
401 free(config);
404 return refcount;
407 static HRESULT WINAPI stream_config_GetStreamType(IWMStreamConfig *iface, GUID *type)
409 struct stream_config *config = impl_from_IWMStreamConfig(iface);
410 struct wm_reader *reader = config->stream->reader;
411 AM_MEDIA_TYPE mt;
413 TRACE("config %p, type %p.\n", config, type);
415 EnterCriticalSection(&reader->cs);
417 if (!amt_from_wg_format(&mt, &config->stream->format, true))
419 LeaveCriticalSection(&reader->cs);
420 return E_OUTOFMEMORY;
423 *type = mt.majortype;
424 FreeMediaType(&mt);
426 LeaveCriticalSection(&reader->cs);
428 return S_OK;
431 static HRESULT WINAPI stream_config_GetStreamNumber(IWMStreamConfig *iface, WORD *number)
433 struct stream_config *config = impl_from_IWMStreamConfig(iface);
435 TRACE("config %p, number %p.\n", config, number);
437 *number = config->stream->index + 1;
438 return S_OK;
441 static HRESULT WINAPI stream_config_SetStreamNumber(IWMStreamConfig *iface, WORD number)
443 FIXME("iface %p, number %u, stub!\n", iface, number);
444 return E_NOTIMPL;
447 static HRESULT WINAPI stream_config_GetStreamName(IWMStreamConfig *iface, WCHAR *name, WORD *len)
449 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
450 return E_NOTIMPL;
453 static HRESULT WINAPI stream_config_SetStreamName(IWMStreamConfig *iface, const WCHAR *name)
455 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
456 return E_NOTIMPL;
459 static HRESULT WINAPI stream_config_GetConnectionName(IWMStreamConfig *iface, WCHAR *name, WORD *len)
461 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
462 return E_NOTIMPL;
465 static HRESULT WINAPI stream_config_SetConnectionName(IWMStreamConfig *iface, const WCHAR *name)
467 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
468 return E_NOTIMPL;
471 static HRESULT WINAPI stream_config_GetBitrate(IWMStreamConfig *iface, DWORD *bitrate)
473 FIXME("iface %p, bitrate %p, stub!\n", iface, bitrate);
474 return E_NOTIMPL;
477 static HRESULT WINAPI stream_config_SetBitrate(IWMStreamConfig *iface, DWORD bitrate)
479 FIXME("iface %p, bitrate %lu, stub!\n", iface, bitrate);
480 return E_NOTIMPL;
483 static HRESULT WINAPI stream_config_GetBufferWindow(IWMStreamConfig *iface, DWORD *window)
485 FIXME("iface %p, window %p, stub!\n", iface, window);
486 return E_NOTIMPL;
489 static HRESULT WINAPI stream_config_SetBufferWindow(IWMStreamConfig *iface, DWORD window)
491 FIXME("iface %p, window %lu, stub!\n", iface, window);
492 return E_NOTIMPL;
495 static const IWMStreamConfigVtbl stream_config_vtbl =
497 stream_config_QueryInterface,
498 stream_config_AddRef,
499 stream_config_Release,
500 stream_config_GetStreamType,
501 stream_config_GetStreamNumber,
502 stream_config_SetStreamNumber,
503 stream_config_GetStreamName,
504 stream_config_SetStreamName,
505 stream_config_GetConnectionName,
506 stream_config_SetConnectionName,
507 stream_config_GetBitrate,
508 stream_config_SetBitrate,
509 stream_config_GetBufferWindow,
510 stream_config_SetBufferWindow,
513 static struct stream_config *impl_from_IWMMediaProps(IWMMediaProps *iface)
515 return CONTAINING_RECORD(iface, struct stream_config, IWMMediaProps_iface);
518 static HRESULT WINAPI stream_props_QueryInterface(IWMMediaProps *iface, REFIID iid, void **out)
520 struct stream_config *config = impl_from_IWMMediaProps(iface);
521 return IWMStreamConfig_QueryInterface(&config->IWMStreamConfig_iface, iid, out);
524 static ULONG WINAPI stream_props_AddRef(IWMMediaProps *iface)
526 struct stream_config *config = impl_from_IWMMediaProps(iface);
527 return IWMStreamConfig_AddRef(&config->IWMStreamConfig_iface);
530 static ULONG WINAPI stream_props_Release(IWMMediaProps *iface)
532 struct stream_config *config = impl_from_IWMMediaProps(iface);
533 return IWMStreamConfig_Release(&config->IWMStreamConfig_iface);
536 static HRESULT WINAPI stream_props_GetType(IWMMediaProps *iface, GUID *major_type)
538 FIXME("iface %p, major_type %p, stub!\n", iface, major_type);
539 return E_NOTIMPL;
542 static HRESULT WINAPI stream_props_GetMediaType(IWMMediaProps *iface, WM_MEDIA_TYPE *mt, DWORD *size)
544 struct stream_config *config = impl_from_IWMMediaProps(iface);
545 const DWORD req_size = *size;
546 AM_MEDIA_TYPE stream_mt;
548 TRACE("iface %p, mt %p, size %p.\n", iface, mt, size);
550 if (!amt_from_wg_format(&stream_mt, &config->stream->format, true))
551 return E_OUTOFMEMORY;
553 *size = sizeof(stream_mt) + stream_mt.cbFormat;
554 if (!mt)
555 return S_OK;
556 if (req_size < *size)
557 return ASF_E_BUFFERTOOSMALL;
559 strmbase_dump_media_type(&stream_mt);
561 memcpy(mt, &stream_mt, sizeof(*mt));
562 memcpy(mt + 1, stream_mt.pbFormat, stream_mt.cbFormat);
563 mt->pbFormat = (BYTE *)(mt + 1);
564 return S_OK;
567 static HRESULT WINAPI stream_props_SetMediaType(IWMMediaProps *iface, WM_MEDIA_TYPE *mt)
569 FIXME("iface %p, mt %p, stub!\n", iface, mt);
570 return E_NOTIMPL;
573 static const IWMMediaPropsVtbl stream_props_vtbl =
575 stream_props_QueryInterface,
576 stream_props_AddRef,
577 stream_props_Release,
578 stream_props_GetType,
579 stream_props_GetMediaType,
580 stream_props_SetMediaType,
583 static DWORD CALLBACK read_thread(void *arg)
585 struct wm_reader *reader = arg;
586 IStream *stream = reader->source_stream;
587 HANDLE file = reader->file;
588 size_t buffer_size = 4096;
589 uint64_t file_size;
590 void *data;
592 if (!(data = malloc(buffer_size)))
593 return 0;
595 if (file)
597 LARGE_INTEGER size;
599 GetFileSizeEx(file, &size);
600 file_size = size.QuadPart;
602 else
604 STATSTG stat;
606 IStream_Stat(stream, &stat, STATFLAG_NONAME);
607 file_size = stat.cbSize.QuadPart;
610 TRACE("Starting read thread for reader %p.\n", reader);
612 while (!reader->read_thread_shutdown)
614 LARGE_INTEGER large_offset;
615 uint64_t offset;
616 ULONG ret_size;
617 uint32_t size;
618 HRESULT hr;
620 if (!wg_parser_get_next_read_offset(reader->wg_parser, &offset, &size))
621 continue;
623 if (offset >= file_size)
624 size = 0;
625 else if (offset + size >= file_size)
626 size = file_size - offset;
628 if (!size)
630 wg_parser_push_data(reader->wg_parser, data, 0);
631 continue;
634 if (!array_reserve(&data, &buffer_size, size, 1))
636 free(data);
637 return 0;
640 ret_size = 0;
642 large_offset.QuadPart = offset;
643 if (file)
645 if (!SetFilePointerEx(file, large_offset, NULL, FILE_BEGIN)
646 || !ReadFile(file, data, size, &ret_size, NULL))
648 ERR("Failed to read %u bytes at offset %I64u, error %lu.\n", size, offset, GetLastError());
649 wg_parser_push_data(reader->wg_parser, NULL, 0);
650 continue;
653 else
655 if (SUCCEEDED(hr = IStream_Seek(stream, large_offset, STREAM_SEEK_SET, NULL)))
656 hr = IStream_Read(stream, data, size, &ret_size);
657 if (FAILED(hr))
659 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr);
660 wg_parser_push_data(reader->wg_parser, NULL, 0);
661 continue;
665 if (ret_size != size)
666 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size);
667 wg_parser_push_data(reader->wg_parser, data, ret_size);
670 free(data);
671 TRACE("Reader is shutting down; exiting.\n");
672 return 0;
675 static struct wm_reader *impl_from_IWMProfile3(IWMProfile3 *iface)
677 return CONTAINING_RECORD(iface, struct wm_reader, IWMProfile3_iface);
680 static HRESULT WINAPI profile_QueryInterface(IWMProfile3 *iface, REFIID iid, void **out)
682 struct wm_reader *reader = impl_from_IWMProfile3(iface);
683 return IUnknown_QueryInterface(reader->outer, iid, out);
686 static ULONG WINAPI profile_AddRef(IWMProfile3 *iface)
688 struct wm_reader *reader = impl_from_IWMProfile3(iface);
689 return IUnknown_AddRef(reader->outer);
692 static ULONG WINAPI profile_Release(IWMProfile3 *iface)
694 struct wm_reader *reader = impl_from_IWMProfile3(iface);
695 return IUnknown_Release(reader->outer);
698 static HRESULT WINAPI profile_GetVersion(IWMProfile3 *iface, WMT_VERSION *version)
700 FIXME("iface %p, version %p, stub!\n", iface, version);
701 return E_NOTIMPL;
704 static HRESULT WINAPI profile_GetName(IWMProfile3 *iface, WCHAR *name, DWORD *length)
706 FIXME("iface %p, name %p, length %p, stub!\n", iface, name, length);
707 return E_NOTIMPL;
710 static HRESULT WINAPI profile_SetName(IWMProfile3 *iface, const WCHAR *name)
712 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
713 return E_NOTIMPL;
716 static HRESULT WINAPI profile_GetDescription(IWMProfile3 *iface, WCHAR *description, DWORD *length)
718 FIXME("iface %p, description %p, length %p, stub!\n", iface, description, length);
719 return E_NOTIMPL;
722 static HRESULT WINAPI profile_SetDescription(IWMProfile3 *iface, const WCHAR *description)
724 FIXME("iface %p, description %s, stub!\n", iface, debugstr_w(description));
725 return E_NOTIMPL;
728 static HRESULT WINAPI profile_GetStreamCount(IWMProfile3 *iface, DWORD *count)
730 struct wm_reader *reader = impl_from_IWMProfile3(iface);
732 TRACE("reader %p, count %p.\n", reader, count);
734 if (!count)
735 return E_INVALIDARG;
737 EnterCriticalSection(&reader->cs);
738 *count = reader->stream_count;
739 LeaveCriticalSection(&reader->cs);
740 return S_OK;
743 static HRESULT WINAPI profile_GetStream(IWMProfile3 *iface, DWORD index, IWMStreamConfig **config)
745 struct wm_reader *reader = impl_from_IWMProfile3(iface);
746 struct stream_config *object;
748 TRACE("reader %p, index %lu, config %p.\n", reader, index, config);
750 EnterCriticalSection(&reader->cs);
752 if (index >= reader->stream_count)
754 LeaveCriticalSection(&reader->cs);
755 WARN("Index %lu exceeds stream count %u; returning E_INVALIDARG.\n", index, reader->stream_count);
756 return E_INVALIDARG;
759 if (!(object = calloc(1, sizeof(*object))))
761 LeaveCriticalSection(&reader->cs);
762 return E_OUTOFMEMORY;
765 object->IWMStreamConfig_iface.lpVtbl = &stream_config_vtbl;
766 object->IWMMediaProps_iface.lpVtbl = &stream_props_vtbl;
767 object->refcount = 1;
768 object->stream = &reader->streams[index];
769 IWMProfile3_AddRef(&reader->IWMProfile3_iface);
771 LeaveCriticalSection(&reader->cs);
773 TRACE("Created stream config %p.\n", object);
774 *config = &object->IWMStreamConfig_iface;
775 return S_OK;
778 static HRESULT WINAPI profile_GetStreamByNumber(IWMProfile3 *iface, WORD stream_number, IWMStreamConfig **config)
780 FIXME("iface %p, stream_number %u, config %p, stub!\n", iface, stream_number, config);
781 return E_NOTIMPL;
784 static HRESULT WINAPI profile_RemoveStream(IWMProfile3 *iface, IWMStreamConfig *config)
786 FIXME("iface %p, config %p, stub!\n", iface, config);
787 return E_NOTIMPL;
790 static HRESULT WINAPI profile_RemoveStreamByNumber(IWMProfile3 *iface, WORD stream_number)
792 FIXME("iface %p, stream_number %u, stub!\n", iface, stream_number);
793 return E_NOTIMPL;
796 static HRESULT WINAPI profile_AddStream(IWMProfile3 *iface, IWMStreamConfig *config)
798 FIXME("iface %p, config %p, stub!\n", iface, config);
799 return E_NOTIMPL;
802 static HRESULT WINAPI profile_ReconfigStream(IWMProfile3 *iface, IWMStreamConfig *config)
804 FIXME("iface %p, config %p, stub!\n", iface, config);
805 return E_NOTIMPL;
808 static HRESULT WINAPI profile_CreateNewStream(IWMProfile3 *iface, REFGUID type, IWMStreamConfig **config)
810 FIXME("iface %p, type %s, config %p, stub!\n", iface, debugstr_guid(type), config);
811 return E_NOTIMPL;
814 static HRESULT WINAPI profile_GetMutualExclusionCount(IWMProfile3 *iface, DWORD *count)
816 FIXME("iface %p, count %p, stub!\n", iface, count);
817 return E_NOTIMPL;
820 static HRESULT WINAPI profile_GetMutualExclusion(IWMProfile3 *iface, DWORD index, IWMMutualExclusion **excl)
822 FIXME("iface %p, index %lu, excl %p, stub!\n", iface, index, excl);
823 return E_NOTIMPL;
826 static HRESULT WINAPI profile_RemoveMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
828 FIXME("iface %p, excl %p, stub!\n", iface, excl);
829 return E_NOTIMPL;
832 static HRESULT WINAPI profile_AddMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
834 FIXME("iface %p, excl %p, stub!\n", iface, excl);
835 return E_NOTIMPL;
838 static HRESULT WINAPI profile_CreateNewMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion **excl)
840 FIXME("iface %p, excl %p, stub!\n", iface, excl);
841 return E_NOTIMPL;
844 static HRESULT WINAPI profile_GetProfileID(IWMProfile3 *iface, GUID *id)
846 FIXME("iface %p, id %p, stub!\n", iface, id);
847 return E_NOTIMPL;
850 static HRESULT WINAPI profile_GetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT *format)
852 FIXME("iface %p, format %p, stub!\n", iface, format);
853 return E_NOTIMPL;
856 static HRESULT WINAPI profile_SetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT format)
858 FIXME("iface %p, format %#x, stub!\n", iface, format);
859 return E_NOTIMPL;
862 static HRESULT WINAPI profile_GetBandwidthSharingCount(IWMProfile3 *iface, DWORD *count)
864 FIXME("iface %p, count %p, stub!\n", iface, count);
865 return E_NOTIMPL;
868 static HRESULT WINAPI profile_GetBandwidthSharing(IWMProfile3 *iface, DWORD index, IWMBandwidthSharing **sharing)
870 FIXME("iface %p, index %lu, sharing %p, stub!\n", iface, index, sharing);
871 return E_NOTIMPL;
874 static HRESULT WINAPI profile_RemoveBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing *sharing)
876 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
877 return E_NOTIMPL;
880 static HRESULT WINAPI profile_AddBandwidthSharing(IWMProfile3 *iface, IWMBandwidthSharing *sharing)
882 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
883 return E_NOTIMPL;
886 static HRESULT WINAPI profile_CreateNewBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing **sharing)
888 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
889 return E_NOTIMPL;
892 static HRESULT WINAPI profile_GetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
894 FIXME("iface %p, stream %p, stub!\n", iface, stream);
895 return E_NOTIMPL;
898 static HRESULT WINAPI profile_SetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization *stream)
900 FIXME("iface %p, stream %p, stub!\n", iface, stream);
901 return E_NOTIMPL;
904 static HRESULT WINAPI profile_RemoveStreamPrioritization(IWMProfile3 *iface)
906 FIXME("iface %p, stub!\n", iface);
907 return E_NOTIMPL;
910 static HRESULT WINAPI profile_CreateNewStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
912 FIXME("iface %p, stream %p, stub!\n", iface, stream);
913 return E_NOTIMPL;
916 static HRESULT WINAPI profile_GetExpectedPacketCount(IWMProfile3 *iface, QWORD duration, QWORD *count)
918 FIXME("iface %p, duration %s, count %p, stub!\n", iface, debugstr_time(duration), count);
919 return E_NOTIMPL;
922 static const IWMProfile3Vtbl profile_vtbl =
924 profile_QueryInterface,
925 profile_AddRef,
926 profile_Release,
927 profile_GetVersion,
928 profile_GetName,
929 profile_SetName,
930 profile_GetDescription,
931 profile_SetDescription,
932 profile_GetStreamCount,
933 profile_GetStream,
934 profile_GetStreamByNumber,
935 profile_RemoveStream,
936 profile_RemoveStreamByNumber,
937 profile_AddStream,
938 profile_ReconfigStream,
939 profile_CreateNewStream,
940 profile_GetMutualExclusionCount,
941 profile_GetMutualExclusion,
942 profile_RemoveMutualExclusion,
943 profile_AddMutualExclusion,
944 profile_CreateNewMutualExclusion,
945 profile_GetProfileID,
946 profile_GetStorageFormat,
947 profile_SetStorageFormat,
948 profile_GetBandwidthSharingCount,
949 profile_GetBandwidthSharing,
950 profile_RemoveBandwidthSharing,
951 profile_AddBandwidthSharing,
952 profile_CreateNewBandwidthSharing,
953 profile_GetStreamPrioritization,
954 profile_SetStreamPrioritization,
955 profile_RemoveStreamPrioritization,
956 profile_CreateNewStreamPrioritization,
957 profile_GetExpectedPacketCount,
960 static struct wm_reader *impl_from_IWMHeaderInfo3(IWMHeaderInfo3 *iface)
962 return CONTAINING_RECORD(iface, struct wm_reader, IWMHeaderInfo3_iface);
965 static HRESULT WINAPI header_info_QueryInterface(IWMHeaderInfo3 *iface, REFIID iid, void **out)
967 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
968 return IUnknown_QueryInterface(reader->outer, iid, out);
971 static ULONG WINAPI header_info_AddRef(IWMHeaderInfo3 *iface)
973 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
974 return IUnknown_AddRef(reader->outer);
977 static ULONG WINAPI header_info_Release(IWMHeaderInfo3 *iface)
979 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
980 return IUnknown_Release(reader->outer);
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);
1230 return IUnknown_QueryInterface(reader->outer, iid, out);
1233 static ULONG WINAPI language_list_AddRef(IWMLanguageList *iface)
1235 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1236 return IUnknown_AddRef(reader->outer);
1239 static ULONG WINAPI language_list_Release(IWMLanguageList *iface)
1241 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1242 return IUnknown_Release(reader->outer);
1245 static HRESULT WINAPI language_list_GetLanguageCount(IWMLanguageList *iface, WORD *count)
1247 FIXME("iface %p, count %p, stub!\n", iface, count);
1248 return E_NOTIMPL;
1251 static HRESULT WINAPI language_list_GetLanguageDetails(IWMLanguageList *iface,
1252 WORD index, WCHAR *lang, WORD *len)
1254 FIXME("iface %p, index %u, lang %p, len %p, stub!\n", iface, index, lang, len);
1255 return E_NOTIMPL;
1258 static HRESULT WINAPI language_list_AddLanguageByRFC1766String(IWMLanguageList *iface,
1259 const WCHAR *lang, WORD *index)
1261 FIXME("iface %p, lang %s, index %p, stub!\n", iface, debugstr_w(lang), index);
1262 return E_NOTIMPL;
1265 static const IWMLanguageListVtbl language_list_vtbl =
1267 language_list_QueryInterface,
1268 language_list_AddRef,
1269 language_list_Release,
1270 language_list_GetLanguageCount,
1271 language_list_GetLanguageDetails,
1272 language_list_AddLanguageByRFC1766String,
1275 static struct wm_reader *impl_from_IWMPacketSize2(IWMPacketSize2 *iface)
1277 return CONTAINING_RECORD(iface, struct wm_reader, IWMPacketSize2_iface);
1280 static HRESULT WINAPI packet_size_QueryInterface(IWMPacketSize2 *iface, REFIID iid, void **out)
1282 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1283 return IUnknown_QueryInterface(reader->outer, iid, out);
1286 static ULONG WINAPI packet_size_AddRef(IWMPacketSize2 *iface)
1288 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1289 return IUnknown_AddRef(reader->outer);
1292 static ULONG WINAPI packet_size_Release(IWMPacketSize2 *iface)
1294 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1295 return IUnknown_Release(reader->outer);
1298 static HRESULT WINAPI packet_size_GetMaxPacketSize(IWMPacketSize2 *iface, DWORD *size)
1300 FIXME("iface %p, size %p, stub!\n", iface, size);
1301 return E_NOTIMPL;
1304 static HRESULT WINAPI packet_size_SetMaxPacketSize(IWMPacketSize2 *iface, DWORD size)
1306 FIXME("iface %p, size %lu, stub!\n", iface, size);
1307 return E_NOTIMPL;
1310 static HRESULT WINAPI packet_size_GetMinPacketSize(IWMPacketSize2 *iface, DWORD *size)
1312 FIXME("iface %p, size %p, stub!\n", iface, size);
1313 return E_NOTIMPL;
1316 static HRESULT WINAPI packet_size_SetMinPacketSize(IWMPacketSize2 *iface, DWORD size)
1318 FIXME("iface %p, size %lu, stub!\n", iface, size);
1319 return E_NOTIMPL;
1322 static const IWMPacketSize2Vtbl packet_size_vtbl =
1324 packet_size_QueryInterface,
1325 packet_size_AddRef,
1326 packet_size_Release,
1327 packet_size_GetMaxPacketSize,
1328 packet_size_SetMaxPacketSize,
1329 packet_size_GetMinPacketSize,
1330 packet_size_SetMinPacketSize,
1333 static struct wm_reader *impl_from_IWMReaderPlaylistBurn(IWMReaderPlaylistBurn *iface)
1335 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderPlaylistBurn_iface);
1338 static HRESULT WINAPI playlist_QueryInterface(IWMReaderPlaylistBurn *iface, REFIID iid, void **out)
1340 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1341 return IUnknown_QueryInterface(reader->outer, iid, out);
1344 static ULONG WINAPI playlist_AddRef(IWMReaderPlaylistBurn *iface)
1346 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1347 return IUnknown_AddRef(reader->outer);
1350 static ULONG WINAPI playlist_Release(IWMReaderPlaylistBurn *iface)
1352 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1353 return IUnknown_Release(reader->outer);
1356 static HRESULT WINAPI playlist_InitPlaylistBurn(IWMReaderPlaylistBurn *iface, DWORD count,
1357 const WCHAR **filenames, IWMStatusCallback *callback, void *context)
1359 FIXME("iface %p, count %lu, filenames %p, callback %p, context %p, stub!\n",
1360 iface, count, filenames, callback, context);
1361 return E_NOTIMPL;
1364 static HRESULT WINAPI playlist_GetInitResults(IWMReaderPlaylistBurn *iface, DWORD count, HRESULT *hrs)
1366 FIXME("iface %p, count %lu, hrs %p, stub!\n", iface, count, hrs);
1367 return E_NOTIMPL;
1370 static HRESULT WINAPI playlist_Cancel(IWMReaderPlaylistBurn *iface)
1372 FIXME("iface %p, stub!\n", iface);
1373 return E_NOTIMPL;
1376 static HRESULT WINAPI playlist_EndPlaylistBurn(IWMReaderPlaylistBurn *iface, HRESULT hr)
1378 FIXME("iface %p, hr %#lx, stub!\n", iface, hr);
1379 return E_NOTIMPL;
1382 static const IWMReaderPlaylistBurnVtbl playlist_vtbl =
1384 playlist_QueryInterface,
1385 playlist_AddRef,
1386 playlist_Release,
1387 playlist_InitPlaylistBurn,
1388 playlist_GetInitResults,
1389 playlist_Cancel,
1390 playlist_EndPlaylistBurn,
1393 static struct wm_reader *impl_from_IWMReaderTimecode(IWMReaderTimecode *iface)
1395 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderTimecode_iface);
1398 static HRESULT WINAPI timecode_QueryInterface(IWMReaderTimecode *iface, REFIID iid, void **out)
1400 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1401 return IUnknown_QueryInterface(reader->outer, iid, out);
1404 static ULONG WINAPI timecode_AddRef(IWMReaderTimecode *iface)
1406 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1407 return IUnknown_AddRef(reader->outer);
1410 static ULONG WINAPI timecode_Release(IWMReaderTimecode *iface)
1412 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1413 return IUnknown_Release(reader->outer);
1416 static HRESULT WINAPI timecode_GetTimecodeRangeCount(IWMReaderTimecode *iface,
1417 WORD stream_number, WORD *count)
1419 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
1420 return E_NOTIMPL;
1423 static HRESULT WINAPI timecode_GetTimecodeRangeBounds(IWMReaderTimecode *iface,
1424 WORD stream_number, WORD index, DWORD *start, DWORD *end)
1426 FIXME("iface %p, stream_number %u, index %u, start %p, end %p, stub!\n",
1427 iface, stream_number, index, start, end);
1428 return E_NOTIMPL;
1431 static const IWMReaderTimecodeVtbl timecode_vtbl =
1433 timecode_QueryInterface,
1434 timecode_AddRef,
1435 timecode_Release,
1436 timecode_GetTimecodeRangeCount,
1437 timecode_GetTimecodeRangeBounds,
1440 static HRESULT init_stream(struct wm_reader *reader, QWORD file_size)
1442 struct wg_parser *wg_parser;
1443 HRESULT hr;
1444 WORD i;
1446 if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false)))
1447 return E_OUTOFMEMORY;
1449 reader->wg_parser = wg_parser;
1450 reader->read_thread_shutdown = false;
1451 if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL)))
1453 hr = E_OUTOFMEMORY;
1454 goto out_destroy_parser;
1457 if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size)))
1459 ERR("Failed to connect parser, hr %#lx.\n", hr);
1460 goto out_shutdown_thread;
1463 reader->stream_count = wg_parser_get_stream_count(reader->wg_parser);
1465 if (!(reader->streams = calloc(reader->stream_count, sizeof(*reader->streams))))
1467 hr = E_OUTOFMEMORY;
1468 goto out_disconnect_parser;
1471 for (i = 0; i < reader->stream_count; ++i)
1473 struct wm_stream *stream = &reader->streams[i];
1475 stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i);
1476 stream->reader = reader;
1477 stream->index = i;
1478 stream->selection = WMT_ON;
1479 wg_parser_stream_get_preferred_format(stream->wg_stream, &stream->format);
1480 if (stream->format.major_type == WG_MAJOR_TYPE_AUDIO)
1482 /* R.U.S.E enumerates available audio types, picks the first one it
1483 * likes, and then sets the wrong stream to that type. libav might
1484 * give us WG_AUDIO_FORMAT_F32LE by default, which will result in
1485 * the game incorrectly interpreting float data as integer.
1486 * Therefore just match native and always set our default format to
1487 * S16LE. */
1488 stream->format.u.audio.format = WG_AUDIO_FORMAT_S16LE;
1490 else if (stream->format.major_type == WG_MAJOR_TYPE_VIDEO)
1492 /* Call of Juarez: Bound in Blood breaks if I420 is enumerated.
1493 * Some native decoders output I420, but the msmpeg4v3 decoder
1494 * never does.
1496 * Shadowgrounds provides wmv3 video and assumes that the initial
1497 * video type will be BGR. */
1498 stream->format.u.video.format = WG_VIDEO_FORMAT_BGR;
1500 wg_parser_stream_enable(stream->wg_stream, &stream->format);
1503 /* We probably discarded events because streams weren't enabled yet.
1504 * Now that they're all enabled seek back to the start again. */
1505 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0,
1506 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
1508 return S_OK;
1510 out_disconnect_parser:
1511 wg_parser_disconnect(reader->wg_parser);
1513 out_shutdown_thread:
1514 reader->read_thread_shutdown = true;
1515 WaitForSingleObject(reader->read_thread, INFINITE);
1516 CloseHandle(reader->read_thread);
1517 reader->read_thread = NULL;
1519 out_destroy_parser:
1520 wg_parser_destroy(reader->wg_parser);
1521 reader->wg_parser = NULL;
1523 return hr;
1526 static struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number)
1528 if (stream_number && stream_number <= reader->stream_count)
1529 return &reader->streams[stream_number - 1];
1530 WARN("Invalid stream number %u.\n", stream_number);
1531 return NULL;
1534 static const enum wg_video_format video_formats[] =
1536 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
1537 * YUV color space, and it's generally much less expensive for
1538 * videoconvert to do YUV -> YUV transformations. */
1539 WG_VIDEO_FORMAT_NV12,
1540 WG_VIDEO_FORMAT_YV12,
1541 WG_VIDEO_FORMAT_YUY2,
1542 WG_VIDEO_FORMAT_UYVY,
1543 WG_VIDEO_FORMAT_YVYU,
1544 WG_VIDEO_FORMAT_BGRx,
1545 WG_VIDEO_FORMAT_BGR,
1546 WG_VIDEO_FORMAT_RGB16,
1547 WG_VIDEO_FORMAT_RGB15,
1550 static const char *get_major_type_string(enum wg_major_type type)
1552 switch (type)
1554 case WG_MAJOR_TYPE_AUDIO:
1555 return "audio";
1556 case WG_MAJOR_TYPE_AUDIO_MPEG1:
1557 return "mpeg1-audio";
1558 case WG_MAJOR_TYPE_AUDIO_WMA:
1559 return "wma";
1560 case WG_MAJOR_TYPE_VIDEO:
1561 return "video";
1562 case WG_MAJOR_TYPE_VIDEO_CINEPAK:
1563 return "cinepak";
1564 case WG_MAJOR_TYPE_VIDEO_H264:
1565 return "h264";
1566 case WG_MAJOR_TYPE_UNKNOWN:
1567 return "unknown";
1569 assert(0);
1570 return NULL;
1573 /* Find the earliest buffer by PTS.
1575 * Native seems to behave similarly to this with the async reader, although our
1576 * unit tests show that it's not entirely consistent—some frames are received
1577 * slightly out of order. It's possible that one stream is being manually offset
1578 * to account for decoding latency.
1580 * The behaviour with the synchronous reader, when stream 0 is requested, seems
1581 * consistent with this hypothesis, but with a much larger offset—the video
1582 * stream seems to be "behind" by about 150 ms.
1584 * The main reason for doing this is that the video and audio stream probably
1585 * don't have quite the same "frame rate", and we don't want to force one stream
1586 * to decode faster just to keep up with the other. Delivering samples in PTS
1587 * order should avoid that problem. */
1588 static WORD get_earliest_buffer(struct wm_reader *reader, struct wg_parser_buffer *ret_buffer)
1590 struct wg_parser_buffer buffer;
1591 QWORD earliest_pts = UI64_MAX;
1592 WORD stream_number = 0;
1593 WORD i;
1595 for (i = 0; i < reader->stream_count; ++i)
1597 struct wm_stream *stream = &reader->streams[i];
1599 if (stream->selection == WMT_OFF)
1600 continue;
1602 if (!wg_parser_stream_get_buffer(stream->wg_stream, &buffer))
1603 continue;
1605 if (buffer.has_pts && buffer.pts < earliest_pts)
1607 stream_number = i + 1;
1608 earliest_pts = buffer.pts;
1609 *ret_buffer = buffer;
1613 return stream_number;
1616 static HRESULT wm_reader_get_stream_sample(struct wm_reader *reader, WORD stream_number,
1617 INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags, WORD *ret_stream_number)
1619 struct wg_parser_stream *wg_stream;
1620 struct wg_parser_buffer wg_buffer;
1621 struct wm_stream *stream;
1622 struct buffer *object;
1623 DWORD size, capacity;
1624 INSSBuffer *sample;
1625 HRESULT hr = S_OK;
1626 BYTE *data;
1628 for (;;)
1630 if (!stream_number)
1632 if (!(stream_number = get_earliest_buffer(reader, &wg_buffer)))
1634 /* All streams are disabled or EOS. */
1635 return NS_E_NO_MORE_SAMPLES;
1638 stream = wm_reader_get_stream_by_stream_number(reader, stream_number);
1639 wg_stream = stream->wg_stream;
1641 else
1643 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
1645 WARN("Invalid stream number %u; returning E_INVALIDARG.\n", stream_number);
1646 return E_INVALIDARG;
1648 wg_stream = stream->wg_stream;
1650 if (stream->selection == WMT_OFF)
1652 WARN("Stream %u is deselected; returning NS_E_INVALID_REQUEST.\n", stream_number);
1653 return NS_E_INVALID_REQUEST;
1656 if (stream->eos)
1657 return NS_E_NO_MORE_SAMPLES;
1659 if (!wg_parser_stream_get_buffer(wg_stream, &wg_buffer))
1661 stream->eos = true;
1662 TRACE("End of stream.\n");
1663 return NS_E_NO_MORE_SAMPLES;
1667 TRACE("Got buffer for '%s' stream %p.\n", get_major_type_string(stream->format.major_type), stream);
1669 if (!stream->read_compressed && stream->output_allocator)
1670 hr = IWMReaderAllocatorEx_AllocateForOutputEx(stream->output_allocator, stream->index,
1671 wg_buffer.size, &sample, 0, 0, 0, NULL);
1672 else if (stream->read_compressed && stream->stream_allocator)
1673 hr = IWMReaderAllocatorEx_AllocateForStreamEx(stream->stream_allocator, stream->index + 1,
1674 wg_buffer.size, &sample, 0, 0, 0, NULL);
1675 /* FIXME: Should these be pooled? */
1676 else if (!(object = calloc(1, offsetof(struct buffer, data[wg_buffer.size]))))
1677 hr = E_OUTOFMEMORY;
1678 else
1680 object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
1681 object->refcount = 1;
1682 object->capacity = wg_buffer.size;
1684 TRACE("Created buffer %p.\n", object);
1685 sample = &object->INSSBuffer_iface;
1688 if (FAILED(hr))
1690 ERR("Failed to allocate sample of %u bytes, hr %#lx.\n", wg_buffer.size, hr);
1691 wg_parser_stream_release_buffer(wg_stream);
1692 return hr;
1695 if (FAILED(hr = INSSBuffer_GetBufferAndLength(sample, &data, &size)))
1696 ERR("Failed to get data pointer, hr %#lx.\n", hr);
1697 if (FAILED(hr = INSSBuffer_GetMaxLength(sample, &capacity)))
1698 ERR("Failed to get capacity, hr %#lx.\n", hr);
1699 if (wg_buffer.size > capacity)
1700 ERR("Returned capacity %lu is less than requested capacity %u.\n", capacity, wg_buffer.size);
1702 if (!wg_parser_stream_copy_buffer(wg_stream, data, 0, wg_buffer.size))
1704 /* The GStreamer pin has been flushed. */
1705 INSSBuffer_Release(sample);
1706 continue;
1709 if (FAILED(hr = INSSBuffer_SetLength(sample, wg_buffer.size)))
1710 ERR("Failed to set size %u, hr %#lx.\n", wg_buffer.size, hr);
1712 wg_parser_stream_release_buffer(wg_stream);
1714 if (!wg_buffer.has_pts)
1715 FIXME("Missing PTS.\n");
1716 if (!wg_buffer.has_duration)
1717 FIXME("Missing duration.\n");
1719 *pts = wg_buffer.pts;
1720 *duration = wg_buffer.duration;
1721 *flags = 0;
1722 if (wg_buffer.discontinuity)
1723 *flags |= WM_SF_DISCONTINUITY;
1724 if (!wg_buffer.delta)
1725 *flags |= WM_SF_CLEANPOINT;
1727 *ret_sample = sample;
1728 *ret_stream_number = stream_number;
1729 return S_OK;
1733 static struct wm_reader *impl_from_IUnknown(IUnknown *iface)
1735 return CONTAINING_RECORD(iface, struct wm_reader, IUnknown_inner);
1738 static HRESULT WINAPI unknown_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out)
1740 struct wm_reader *reader = impl_from_IUnknown(iface);
1742 TRACE("reader %p, iid %s, out %p.\n", reader, debugstr_guid(iid), out);
1744 if (IsEqualIID(iid, &IID_IUnknown)
1745 || IsEqualIID(iid, &IID_IWMSyncReader)
1746 || IsEqualIID(iid, &IID_IWMSyncReader2))
1747 *out = &reader->IWMSyncReader2_iface;
1748 else if (IsEqualIID(iid, &IID_IWMHeaderInfo)
1749 || IsEqualIID(iid, &IID_IWMHeaderInfo2)
1750 || IsEqualIID(iid, &IID_IWMHeaderInfo3))
1751 *out = &reader->IWMHeaderInfo3_iface;
1752 else if (IsEqualIID(iid, &IID_IWMLanguageList))
1753 *out = &reader->IWMLanguageList_iface;
1754 else if (IsEqualIID(iid, &IID_IWMPacketSize)
1755 || IsEqualIID(iid, &IID_IWMPacketSize2))
1756 *out = &reader->IWMPacketSize2_iface;
1757 else if (IsEqualIID(iid, &IID_IWMProfile)
1758 || IsEqualIID(iid, &IID_IWMProfile2)
1759 || IsEqualIID(iid, &IID_IWMProfile3))
1760 *out = &reader->IWMProfile3_iface;
1761 else if (IsEqualIID(iid, &IID_IWMReaderPlaylistBurn))
1762 *out = &reader->IWMReaderPlaylistBurn_iface;
1763 else if (IsEqualIID(iid, &IID_IWMReaderTimecode))
1764 *out = &reader->IWMReaderTimecode_iface;
1765 else
1767 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1768 return E_NOINTERFACE;
1771 IUnknown_AddRef((IUnknown *)*out);
1772 return S_OK;
1775 static ULONG WINAPI unknown_inner_AddRef(IUnknown *iface)
1777 struct wm_reader *reader = impl_from_IUnknown(iface);
1778 ULONG refcount = InterlockedIncrement(&reader->refcount);
1779 TRACE("%p increasing refcount to %lu.\n", reader, refcount);
1780 return refcount;
1783 static ULONG WINAPI unknown_inner_Release(IUnknown *iface)
1785 struct wm_reader *reader = impl_from_IUnknown(iface);
1786 ULONG refcount = InterlockedDecrement(&reader->refcount);
1788 TRACE("%p decreasing refcount to %lu.\n", reader, refcount);
1790 if (!refcount)
1792 IWMSyncReader2_Close(&reader->IWMSyncReader2_iface);
1794 reader->cs.DebugInfo->Spare[0] = 0;
1795 DeleteCriticalSection(&reader->cs);
1797 free(reader);
1800 return refcount;
1803 static const IUnknownVtbl unknown_inner_vtbl =
1805 unknown_inner_QueryInterface,
1806 unknown_inner_AddRef,
1807 unknown_inner_Release,
1810 static struct wm_reader *impl_from_IWMSyncReader2(IWMSyncReader2 *iface)
1812 return CONTAINING_RECORD(iface, struct wm_reader, IWMSyncReader2_iface);
1815 static HRESULT WINAPI reader_QueryInterface(IWMSyncReader2 *iface, REFIID iid, void **out)
1817 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1818 return IUnknown_QueryInterface(reader->outer, iid, out);
1821 static ULONG WINAPI reader_AddRef(IWMSyncReader2 *iface)
1823 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1824 return IUnknown_AddRef(reader->outer);
1827 static ULONG WINAPI reader_Release(IWMSyncReader2 *iface)
1829 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1830 return IUnknown_Release(reader->outer);
1833 static HRESULT WINAPI reader_Close(IWMSyncReader2 *iface)
1835 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1837 TRACE("reader %p.\n", reader);
1839 EnterCriticalSection(&reader->cs);
1841 if (!reader->wg_parser)
1843 LeaveCriticalSection(&reader->cs);
1844 return NS_E_INVALID_REQUEST;
1847 wg_parser_disconnect(reader->wg_parser);
1849 reader->read_thread_shutdown = true;
1850 WaitForSingleObject(reader->read_thread, INFINITE);
1851 CloseHandle(reader->read_thread);
1852 reader->read_thread = NULL;
1854 wg_parser_destroy(reader->wg_parser);
1855 reader->wg_parser = NULL;
1857 if (reader->source_stream)
1858 IStream_Release(reader->source_stream);
1859 reader->source_stream = NULL;
1860 if (reader->file)
1861 CloseHandle(reader->file);
1862 reader->file = NULL;
1864 LeaveCriticalSection(&reader->cs);
1865 return S_OK;
1868 static HRESULT WINAPI reader_GetMaxOutputSampleSize(IWMSyncReader2 *iface, DWORD output, DWORD *max)
1870 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
1871 FIXME("(%p)->(%lu %p): stub!\n", This, output, max);
1872 return E_NOTIMPL;
1875 static HRESULT WINAPI reader_GetMaxStreamSampleSize(IWMSyncReader2 *iface, WORD stream_number, DWORD *size)
1877 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1878 struct wm_stream *stream;
1880 TRACE("reader %p, stream_number %u, size %p.\n", reader, stream_number, size);
1882 EnterCriticalSection(&reader->cs);
1884 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
1886 LeaveCriticalSection(&reader->cs);
1887 return E_INVALIDARG;
1890 *size = wg_format_get_max_size(&stream->format);
1892 LeaveCriticalSection(&reader->cs);
1893 return S_OK;
1896 static HRESULT WINAPI reader_GetNextSample(IWMSyncReader2 *iface,
1897 WORD stream_number, INSSBuffer **sample, QWORD *pts, QWORD *duration,
1898 DWORD *flags, DWORD *output_number, WORD *ret_stream_number)
1900 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1901 HRESULT hr = NS_E_NO_MORE_SAMPLES;
1903 TRACE("reader %p, stream_number %u, sample %p, pts %p, duration %p,"
1904 " flags %p, output_number %p, ret_stream_number %p.\n",
1905 reader, stream_number, sample, pts, duration, flags, output_number, ret_stream_number);
1907 if (!stream_number && !output_number && !ret_stream_number)
1908 return E_INVALIDARG;
1910 EnterCriticalSection(&reader->cs);
1912 hr = wm_reader_get_stream_sample(reader, stream_number, sample, pts, duration, flags, &stream_number);
1913 if (output_number && hr == S_OK)
1914 *output_number = stream_number - 1;
1915 if (ret_stream_number && (hr == S_OK || stream_number))
1916 *ret_stream_number = stream_number;
1918 LeaveCriticalSection(&reader->cs);
1919 return hr;
1922 static HRESULT WINAPI reader_GetOutputCount(IWMSyncReader2 *iface, DWORD *count)
1924 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1926 TRACE("reader %p, count %p.\n", reader, count);
1928 EnterCriticalSection(&reader->cs);
1929 *count = reader->stream_count;
1930 LeaveCriticalSection(&reader->cs);
1931 return S_OK;
1934 static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface,
1935 DWORD output, DWORD index, IWMOutputMediaProps **props)
1937 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1938 struct wm_stream *stream;
1939 struct wg_format format;
1941 TRACE("reader %p, output %lu, index %lu, props %p.\n", reader, output, index, props);
1943 EnterCriticalSection(&reader->cs);
1945 if (!(stream = get_stream_by_output_number(reader, output)))
1947 LeaveCriticalSection(&reader->cs);
1948 return E_INVALIDARG;
1951 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
1953 switch (format.major_type)
1955 case WG_MAJOR_TYPE_VIDEO:
1956 if (index >= ARRAY_SIZE(video_formats))
1958 LeaveCriticalSection(&reader->cs);
1959 return NS_E_INVALID_OUTPUT_FORMAT;
1961 format.u.video.format = video_formats[index];
1962 break;
1964 case WG_MAJOR_TYPE_AUDIO:
1965 if (index)
1967 LeaveCriticalSection(&reader->cs);
1968 return NS_E_INVALID_OUTPUT_FORMAT;
1970 format.u.audio.format = WG_AUDIO_FORMAT_S16LE;
1971 break;
1973 case WG_MAJOR_TYPE_AUDIO_MPEG1:
1974 case WG_MAJOR_TYPE_AUDIO_WMA:
1975 case WG_MAJOR_TYPE_VIDEO_CINEPAK:
1976 case WG_MAJOR_TYPE_VIDEO_H264:
1977 FIXME("Format %u not implemented!\n", format.major_type);
1978 break;
1979 case WG_MAJOR_TYPE_UNKNOWN:
1980 break;
1983 LeaveCriticalSection(&reader->cs);
1985 *props = output_props_create(&format);
1986 return *props ? S_OK : E_OUTOFMEMORY;
1989 static HRESULT WINAPI reader_GetOutputFormatCount(IWMSyncReader2 *iface, DWORD output, DWORD *count)
1991 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
1992 struct wm_stream *stream;
1993 struct wg_format format;
1995 TRACE("reader %p, output %lu, count %p.\n", reader, output, count);
1997 EnterCriticalSection(&reader->cs);
1999 if (!(stream = get_stream_by_output_number(reader, output)))
2001 LeaveCriticalSection(&reader->cs);
2002 return E_INVALIDARG;
2005 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
2006 switch (format.major_type)
2008 case WG_MAJOR_TYPE_VIDEO:
2009 *count = ARRAY_SIZE(video_formats);
2010 break;
2012 case WG_MAJOR_TYPE_AUDIO_MPEG1:
2013 case WG_MAJOR_TYPE_AUDIO_WMA:
2014 case WG_MAJOR_TYPE_VIDEO_CINEPAK:
2015 case WG_MAJOR_TYPE_VIDEO_H264:
2016 FIXME("Format %u not implemented!\n", format.major_type);
2017 /* fallthrough */
2018 case WG_MAJOR_TYPE_AUDIO:
2019 case WG_MAJOR_TYPE_UNKNOWN:
2020 *count = 1;
2021 break;
2024 LeaveCriticalSection(&reader->cs);
2025 return S_OK;
2028 static HRESULT WINAPI reader_GetOutputNumberForStream(IWMSyncReader2 *iface,
2029 WORD stream_number, DWORD *output)
2031 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2033 TRACE("reader %p, stream_number %u, output %p.\n", reader, stream_number, output);
2035 *output = stream_number - 1;
2036 return S_OK;
2039 static HRESULT WINAPI reader_GetOutputProps(IWMSyncReader2 *iface,
2040 DWORD output, IWMOutputMediaProps **props)
2042 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2043 struct wm_stream *stream;
2045 TRACE("reader %p, output %lu, props %p.\n", reader, output, props);
2047 EnterCriticalSection(&reader->cs);
2049 if (!(stream = get_stream_by_output_number(reader, output)))
2051 LeaveCriticalSection(&reader->cs);
2052 return E_INVALIDARG;
2055 *props = output_props_create(&stream->format);
2056 LeaveCriticalSection(&reader->cs);
2057 return *props ? S_OK : E_OUTOFMEMORY;
2060 static HRESULT WINAPI reader_GetOutputSetting(IWMSyncReader2 *iface, DWORD output_num, const WCHAR *name,
2061 WMT_ATTR_DATATYPE *type, BYTE *value, WORD *length)
2063 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2064 FIXME("(%p)->(%lu %s %p %p %p): stub!\n", This, output_num, debugstr_w(name), type, value, length);
2065 return E_NOTIMPL;
2068 static HRESULT WINAPI reader_GetReadStreamSamples(IWMSyncReader2 *iface, WORD stream_number, BOOL *compressed)
2070 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2071 struct wm_stream *stream;
2073 TRACE("reader %p, stream_number %u, compressed %p.\n", reader, stream_number, compressed);
2075 EnterCriticalSection(&reader->cs);
2077 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2079 LeaveCriticalSection(&reader->cs);
2080 return E_INVALIDARG;
2083 *compressed = stream->read_compressed;
2085 LeaveCriticalSection(&reader->cs);
2086 return S_OK;
2089 static HRESULT WINAPI reader_GetStreamNumberForOutput(IWMSyncReader2 *iface,
2090 DWORD output, WORD *stream_number)
2092 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2094 TRACE("reader %p, output %lu, stream_number %p.\n", reader, output, stream_number);
2096 *stream_number = output + 1;
2097 return S_OK;
2100 static HRESULT WINAPI reader_GetStreamSelected(IWMSyncReader2 *iface,
2101 WORD stream_number, WMT_STREAM_SELECTION *selection)
2103 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2104 struct wm_stream *stream;
2106 TRACE("reader %p, stream_number %u, selection %p.\n", reader, stream_number, selection);
2108 EnterCriticalSection(&reader->cs);
2110 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2112 LeaveCriticalSection(&reader->cs);
2113 return E_INVALIDARG;
2116 *selection = stream->selection;
2118 LeaveCriticalSection(&reader->cs);
2119 return S_OK;
2122 static HRESULT WINAPI reader_Open(IWMSyncReader2 *iface, const WCHAR *filename)
2124 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2125 LARGE_INTEGER size;
2126 HANDLE file;
2127 HRESULT hr;
2129 TRACE("reader %p, filename %s.\n", reader, debugstr_w(filename));
2131 if ((file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2132 OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
2134 ERR("Failed to open %s, error %lu.\n", debugstr_w(filename), GetLastError());
2135 return HRESULT_FROM_WIN32(GetLastError());
2138 if (!GetFileSizeEx(file, &size))
2140 ERR("Failed to get the size of %s, error %lu.\n", debugstr_w(filename), GetLastError());
2141 CloseHandle(file);
2142 return HRESULT_FROM_WIN32(GetLastError());
2145 EnterCriticalSection(&reader->cs);
2147 if (reader->wg_parser)
2149 LeaveCriticalSection(&reader->cs);
2150 WARN("Stream is already open; returning E_UNEXPECTED.\n");
2151 CloseHandle(file);
2152 return E_UNEXPECTED;
2155 reader->file = file;
2157 if (FAILED(hr = init_stream(reader, size.QuadPart)))
2158 reader->file = NULL;
2160 LeaveCriticalSection(&reader->cs);
2161 return hr;
2164 static HRESULT WINAPI reader_OpenStream(IWMSyncReader2 *iface, IStream *stream)
2166 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2167 STATSTG stat;
2168 HRESULT hr;
2170 TRACE("reader %p, stream %p.\n", reader, stream);
2172 if (FAILED(hr = IStream_Stat(stream, &stat, STATFLAG_NONAME)))
2174 ERR("Failed to stat stream, hr %#lx.\n", hr);
2175 return hr;
2178 EnterCriticalSection(&reader->cs);
2180 if (reader->wg_parser)
2182 LeaveCriticalSection(&reader->cs);
2183 WARN("Stream is already open; returning E_UNEXPECTED.\n");
2184 return E_UNEXPECTED;
2187 IStream_AddRef(reader->source_stream = stream);
2188 if (FAILED(hr = init_stream(reader, stat.cbSize.QuadPart)))
2190 IStream_Release(stream);
2191 reader->source_stream = NULL;
2194 LeaveCriticalSection(&reader->cs);
2195 return hr;
2198 static HRESULT WINAPI reader_SetOutputProps(IWMSyncReader2 *iface, DWORD output, IWMOutputMediaProps *props_iface)
2200 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2201 struct output_props *props = unsafe_impl_from_IWMOutputMediaProps(props_iface);
2202 struct wg_format format, pref_format;
2203 struct wm_stream *stream;
2204 HRESULT hr = S_OK;
2205 int i;
2207 TRACE("reader %p, output %lu, props_iface %p.\n", reader, output, props_iface);
2209 strmbase_dump_media_type(&props->mt);
2211 if (!amt_to_wg_format(&props->mt, &format))
2213 ERR("Failed to convert media type to winegstreamer format.\n");
2214 return E_FAIL;
2217 EnterCriticalSection(&reader->cs);
2219 if (!(stream = get_stream_by_output_number(reader, output)))
2221 LeaveCriticalSection(&reader->cs);
2222 return E_INVALIDARG;
2225 wg_parser_stream_get_preferred_format(stream->wg_stream, &pref_format);
2226 if (pref_format.major_type != format.major_type)
2228 /* R.U.S.E sets the type of the wrong stream, apparently by accident. */
2229 hr = NS_E_INCOMPATIBLE_FORMAT;
2231 else switch (pref_format.major_type)
2233 case WG_MAJOR_TYPE_AUDIO:
2234 if (format.u.audio.format == WG_AUDIO_FORMAT_UNKNOWN)
2235 hr = NS_E_AUDIO_CODEC_NOT_INSTALLED;
2236 else if (format.u.audio.channels > pref_format.u.audio.channels)
2237 hr = NS_E_AUDIO_CODEC_NOT_INSTALLED;
2238 break;
2240 case WG_MAJOR_TYPE_VIDEO:
2241 for (i = 0; i < ARRAY_SIZE(video_formats); ++i)
2242 if (format.u.video.format == video_formats[i])
2243 break;
2244 if (i == ARRAY_SIZE(video_formats))
2245 hr = NS_E_INVALID_OUTPUT_FORMAT;
2246 else if (pref_format.u.video.width != format.u.video.width)
2247 hr = NS_E_INVALID_OUTPUT_FORMAT;
2248 else if (pref_format.u.video.height != format.u.video.height)
2249 hr = NS_E_INVALID_OUTPUT_FORMAT;
2250 break;
2252 default:
2253 hr = NS_E_INCOMPATIBLE_FORMAT;
2254 break;
2257 if (FAILED(hr))
2259 WARN("Unsupported media type, returning %#lx.\n", hr);
2260 LeaveCriticalSection(&reader->cs);
2261 return hr;
2264 stream->format = format;
2265 wg_parser_stream_enable(stream->wg_stream, &format);
2267 /* Re-decode any buffers that might have been generated with the old format.
2269 * FIXME: Seeking in-place will cause some buffers to be dropped.
2270 * Unfortunately, we can't really store the last received PTS and seek there
2271 * either: since seeks are inexact and we aren't guaranteed to receive
2272 * samples in order, some buffers might be duplicated or dropped anyway.
2273 * In order to really seamlessly allow for format changes, we need
2274 * cooperation from each individual GStreamer stream, to be able to tell
2275 * upstream exactly which buffers they need resent...
2277 * In all likelihood this function is being called not mid-stream but rather
2278 * while setting the stream up, before consuming any events. Accordingly
2279 * let's just seek back to the beginning. */
2280 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, reader->start_time, 0,
2281 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
2283 LeaveCriticalSection(&reader->cs);
2284 return S_OK;
2287 static HRESULT WINAPI reader_SetOutputSetting(IWMSyncReader2 *iface, DWORD output,
2288 const WCHAR *name, WMT_ATTR_DATATYPE type, const BYTE *value, WORD size)
2290 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2292 TRACE("reader %p, output %lu, name %s, type %#x, value %p, size %u.\n",
2293 reader, output, debugstr_w(name), type, value, size);
2295 if (!wcscmp(name, L"VideoSampleDurations"))
2297 FIXME("Ignoring VideoSampleDurations setting.\n");
2298 return S_OK;
2300 if (!wcscmp(name, L"EnableDiscreteOutput"))
2302 FIXME("Ignoring EnableDiscreteOutput setting.\n");
2303 return S_OK;
2305 if (!wcscmp(name, L"SpeakerConfig"))
2307 FIXME("Ignoring SpeakerConfig setting.\n");
2308 return S_OK;
2310 else
2312 FIXME("Unknown setting %s; returning E_NOTIMPL.\n", debugstr_w(name));
2313 return E_NOTIMPL;
2317 static HRESULT WINAPI reader_SetRange(IWMSyncReader2 *iface, QWORD start, LONGLONG duration)
2319 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2320 WORD i;
2322 TRACE("reader %p, start %I64u, duration %I64d.\n", reader, start, duration);
2324 EnterCriticalSection(&reader->cs);
2326 reader->start_time = start;
2328 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, start, start + duration,
2329 AM_SEEKING_AbsolutePositioning, duration ? AM_SEEKING_AbsolutePositioning : AM_SEEKING_NoPositioning);
2331 for (i = 0; i < reader->stream_count; ++i)
2332 reader->streams[i].eos = false;
2334 LeaveCriticalSection(&reader->cs);
2335 return S_OK;
2338 static HRESULT WINAPI reader_SetRangeByFrame(IWMSyncReader2 *iface, WORD stream_num, QWORD frame_num,
2339 LONGLONG frames)
2341 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2342 FIXME("(%p)->(%d %s %s): stub!\n", This, stream_num, wine_dbgstr_longlong(frame_num), wine_dbgstr_longlong(frames));
2343 return E_NOTIMPL;
2346 static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD stream_number, BOOL compressed)
2348 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2349 struct wm_stream *stream;
2351 TRACE("reader %p, stream_index %u, compressed %d.\n", reader, stream_number, compressed);
2353 EnterCriticalSection(&reader->cs);
2355 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2357 LeaveCriticalSection(&reader->cs);
2358 return E_INVALIDARG;
2361 stream->read_compressed = compressed;
2363 LeaveCriticalSection(&reader->cs);
2364 return S_OK;
2367 static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface,
2368 WORD count, WORD *stream_numbers, WMT_STREAM_SELECTION *selections)
2370 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2371 struct wm_stream *stream;
2372 WORD i;
2374 TRACE("reader %p, count %u, stream_numbers %p, selections %p.\n",
2375 reader, count, stream_numbers, selections);
2377 if (!count)
2378 return E_INVALIDARG;
2380 EnterCriticalSection(&reader->cs);
2382 for (i = 0; i < count; ++i)
2384 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_numbers[i])))
2386 LeaveCriticalSection(&reader->cs);
2387 WARN("Invalid stream number %u; returning NS_E_INVALID_REQUEST.\n", stream_numbers[i]);
2388 return NS_E_INVALID_REQUEST;
2392 for (i = 0; i < count; ++i)
2394 stream = wm_reader_get_stream_by_stream_number(reader, stream_numbers[i]);
2395 stream->selection = selections[i];
2396 if (selections[i] == WMT_OFF)
2398 TRACE("Disabling stream %u.\n", stream_numbers[i]);
2399 wg_parser_stream_disable(stream->wg_stream);
2401 else if (selections[i] == WMT_ON)
2403 if (selections[i] != WMT_ON)
2404 FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n",
2405 selections[i], stream_numbers[i]);
2406 TRACE("Enabling stream %u.\n", stream_numbers[i]);
2407 wg_parser_stream_enable(stream->wg_stream, &stream->format);
2411 LeaveCriticalSection(&reader->cs);
2412 return S_OK;
2415 static HRESULT WINAPI reader_SetRangeByTimecode(IWMSyncReader2 *iface, WORD stream_num,
2416 WMT_TIMECODE_EXTENSION_DATA *start, WMT_TIMECODE_EXTENSION_DATA *end)
2418 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2419 FIXME("(%p)->(%u %p %p): stub!\n", This, stream_num, start, end);
2420 return E_NOTIMPL;
2423 static HRESULT WINAPI reader_SetRangeByFrameEx(IWMSyncReader2 *iface, WORD stream_num, QWORD frame_num,
2424 LONGLONG frames_to_read, QWORD *starttime)
2426 struct wm_reader *This = impl_from_IWMSyncReader2(iface);
2427 FIXME("(%p)->(%u %s %s %p): stub!\n", This, stream_num, wine_dbgstr_longlong(frame_num),
2428 wine_dbgstr_longlong(frames_to_read), starttime);
2429 return E_NOTIMPL;
2432 static HRESULT WINAPI reader_SetAllocateForOutput(IWMSyncReader2 *iface, DWORD output, IWMReaderAllocatorEx *allocator)
2434 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2435 struct wm_stream *stream;
2437 TRACE("reader %p, output %lu, allocator %p.\n", reader, output, allocator);
2439 EnterCriticalSection(&reader->cs);
2441 if (!(stream = get_stream_by_output_number(reader, output)))
2443 LeaveCriticalSection(&reader->cs);
2444 return E_INVALIDARG;
2447 if (stream->output_allocator)
2448 IWMReaderAllocatorEx_Release(stream->output_allocator);
2449 if ((stream->output_allocator = allocator))
2450 IWMReaderAllocatorEx_AddRef(stream->output_allocator);
2452 LeaveCriticalSection(&reader->cs);
2453 return S_OK;
2456 static HRESULT WINAPI reader_GetAllocateForOutput(IWMSyncReader2 *iface, DWORD output, IWMReaderAllocatorEx **allocator)
2458 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2459 struct wm_stream *stream;
2461 TRACE("reader %p, output %lu, allocator %p.\n", reader, output, allocator);
2463 if (!allocator)
2464 return E_INVALIDARG;
2466 EnterCriticalSection(&reader->cs);
2468 if (!(stream = get_stream_by_output_number(reader, output)))
2470 LeaveCriticalSection(&reader->cs);
2471 return E_INVALIDARG;
2474 stream = reader->streams + output;
2475 if ((*allocator = stream->output_allocator))
2476 IWMReaderAllocatorEx_AddRef(*allocator);
2478 LeaveCriticalSection(&reader->cs);
2479 return S_OK;
2482 static HRESULT WINAPI reader_SetAllocateForStream(IWMSyncReader2 *iface, DWORD stream_number, IWMReaderAllocatorEx *allocator)
2484 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2485 struct wm_stream *stream;
2487 TRACE("reader %p, stream_number %lu, allocator %p.\n", reader, stream_number, allocator);
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 (stream->stream_allocator)
2498 IWMReaderAllocatorEx_Release(stream->stream_allocator);
2499 if ((stream->stream_allocator = allocator))
2500 IWMReaderAllocatorEx_AddRef(stream->stream_allocator);
2502 LeaveCriticalSection(&reader->cs);
2503 return S_OK;
2506 static HRESULT WINAPI reader_GetAllocateForStream(IWMSyncReader2 *iface, DWORD stream_number, IWMReaderAllocatorEx **allocator)
2508 struct wm_reader *reader = impl_from_IWMSyncReader2(iface);
2509 struct wm_stream *stream;
2511 TRACE("reader %p, stream_number %lu, allocator %p.\n", reader, stream_number, allocator);
2513 if (!allocator)
2514 return E_INVALIDARG;
2516 EnterCriticalSection(&reader->cs);
2518 if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
2520 LeaveCriticalSection(&reader->cs);
2521 return E_INVALIDARG;
2524 if ((*allocator = stream->stream_allocator))
2525 IWMReaderAllocatorEx_AddRef(*allocator);
2527 LeaveCriticalSection(&reader->cs);
2528 return S_OK;
2531 static const IWMSyncReader2Vtbl reader_vtbl =
2533 reader_QueryInterface,
2534 reader_AddRef,
2535 reader_Release,
2536 reader_Open,
2537 reader_Close,
2538 reader_SetRange,
2539 reader_SetRangeByFrame,
2540 reader_GetNextSample,
2541 reader_SetStreamsSelected,
2542 reader_GetStreamSelected,
2543 reader_SetReadStreamSamples,
2544 reader_GetReadStreamSamples,
2545 reader_GetOutputSetting,
2546 reader_SetOutputSetting,
2547 reader_GetOutputCount,
2548 reader_GetOutputProps,
2549 reader_SetOutputProps,
2550 reader_GetOutputFormatCount,
2551 reader_GetOutputFormat,
2552 reader_GetOutputNumberForStream,
2553 reader_GetStreamNumberForOutput,
2554 reader_GetMaxOutputSampleSize,
2555 reader_GetMaxStreamSampleSize,
2556 reader_OpenStream,
2557 reader_SetRangeByTimecode,
2558 reader_SetRangeByFrameEx,
2559 reader_SetAllocateForOutput,
2560 reader_GetAllocateForOutput,
2561 reader_SetAllocateForStream,
2562 reader_GetAllocateForStream
2565 HRESULT WINAPI winegstreamer_create_wm_sync_reader(IUnknown *outer, void **out)
2567 struct wm_reader *object;
2569 TRACE("out %p.\n", out);
2571 if (!(object = calloc(1, sizeof(*object))))
2572 return E_OUTOFMEMORY;
2574 object->IUnknown_inner.lpVtbl = &unknown_inner_vtbl;
2575 object->IWMSyncReader2_iface.lpVtbl = &reader_vtbl;
2576 object->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
2577 object->IWMLanguageList_iface.lpVtbl = &language_list_vtbl;
2578 object->IWMPacketSize2_iface.lpVtbl = &packet_size_vtbl;
2579 object->IWMProfile3_iface.lpVtbl = &profile_vtbl;
2580 object->IWMReaderPlaylistBurn_iface.lpVtbl = &playlist_vtbl;
2581 object->IWMReaderTimecode_iface.lpVtbl = &timecode_vtbl;
2582 object->outer = outer ? outer : &object->IUnknown_inner;
2583 object->refcount = 1;
2585 InitializeCriticalSection(&object->cs);
2586 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": reader.cs");
2588 TRACE("Created reader %p.\n", object);
2589 *out = outer ? (void *)&object->IUnknown_inner : (void *)&object->IWMSyncReader2_iface;
2590 return S_OK;