winegstreamer: Set rcSource and rcTarget for WMF video formats.
[wine.git] / dlls / winegstreamer / wm_reader.c
blob1d46db3fb0d73f8cb58d6ba9abfe90bdc63e3d4d
1 /*
2 * Copyright 2012 Austin English
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "gst_private.h"
21 WINE_DEFAULT_DEBUG_CHANNEL(wmvcore);
23 static struct wm_stream *get_stream_by_output_number(struct wm_reader *reader, DWORD output)
25 if (output < reader->stream_count)
26 return &reader->streams[output];
27 WARN("Invalid output number %u.\n", output);
28 return NULL;
31 struct output_props
33 IWMOutputMediaProps IWMOutputMediaProps_iface;
34 LONG refcount;
36 AM_MEDIA_TYPE mt;
39 static inline struct output_props *impl_from_IWMOutputMediaProps(IWMOutputMediaProps *iface)
41 return CONTAINING_RECORD(iface, struct output_props, IWMOutputMediaProps_iface);
44 static HRESULT WINAPI output_props_QueryInterface(IWMOutputMediaProps *iface, REFIID iid, void **out)
46 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
48 TRACE("props %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
50 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IWMOutputMediaProps))
51 *out = &props->IWMOutputMediaProps_iface;
52 else
54 *out = NULL;
55 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
56 return E_NOINTERFACE;
59 IUnknown_AddRef((IUnknown *)*out);
60 return S_OK;
63 static ULONG WINAPI output_props_AddRef(IWMOutputMediaProps *iface)
65 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
66 ULONG refcount = InterlockedIncrement(&props->refcount);
68 TRACE("%p increasing refcount to %u.\n", props, refcount);
70 return refcount;
73 static ULONG WINAPI output_props_Release(IWMOutputMediaProps *iface)
75 struct output_props *props = impl_from_IWMOutputMediaProps(iface);
76 ULONG refcount = InterlockedDecrement(&props->refcount);
78 TRACE("%p decreasing refcount to %u.\n", props, refcount);
80 if (!refcount)
81 free(props);
83 return refcount;
86 static HRESULT WINAPI output_props_GetType(IWMOutputMediaProps *iface, GUID *major_type)
88 FIXME("iface %p, major_type %p, stub!\n", iface, major_type);
89 return E_NOTIMPL;
92 static HRESULT WINAPI output_props_GetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt, DWORD *size)
94 const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
95 const DWORD req_size = *size;
97 TRACE("iface %p, mt %p, size %p.\n", iface, mt, size);
99 *size = sizeof(*mt) + props->mt.cbFormat;
100 if (!mt)
101 return S_OK;
102 if (req_size < *size)
103 return ASF_E_BUFFERTOOSMALL;
105 strmbase_dump_media_type(&props->mt);
107 memcpy(mt, &props->mt, sizeof(*mt));
108 memcpy(mt + 1, props->mt.pbFormat, props->mt.cbFormat);
109 mt->pbFormat = (BYTE *)(mt + 1);
110 return S_OK;
113 static HRESULT WINAPI output_props_SetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt)
115 FIXME("iface %p, mt %p, stub!\n", iface, mt);
116 return E_NOTIMPL;
119 static HRESULT WINAPI output_props_GetStreamGroupName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
121 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
122 return E_NOTIMPL;
125 static HRESULT WINAPI output_props_GetConnectionName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
127 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
128 return E_NOTIMPL;
131 static const struct IWMOutputMediaPropsVtbl output_props_vtbl =
133 output_props_QueryInterface,
134 output_props_AddRef,
135 output_props_Release,
136 output_props_GetType,
137 output_props_GetMediaType,
138 output_props_SetMediaType,
139 output_props_GetStreamGroupName,
140 output_props_GetConnectionName,
143 static struct output_props *unsafe_impl_from_IWMOutputMediaProps(IWMOutputMediaProps *iface)
145 if (!iface)
146 return NULL;
147 assert(iface->lpVtbl == &output_props_vtbl);
148 return impl_from_IWMOutputMediaProps(iface);
151 static IWMOutputMediaProps *output_props_create(const struct wg_format *format)
153 struct output_props *object;
155 if (!(object = calloc(1, sizeof(*object))))
156 return NULL;
157 object->IWMOutputMediaProps_iface.lpVtbl = &output_props_vtbl;
158 object->refcount = 1;
160 if (!amt_from_wg_format(&object->mt, format, true))
162 free(object);
163 return NULL;
166 TRACE("Created output properties %p.\n", object);
167 return &object->IWMOutputMediaProps_iface;
170 struct buffer
172 INSSBuffer INSSBuffer_iface;
173 LONG refcount;
175 DWORD size;
176 BYTE data[1];
179 static struct buffer *impl_from_INSSBuffer(INSSBuffer *iface)
181 return CONTAINING_RECORD(iface, struct buffer, INSSBuffer_iface);
184 static HRESULT WINAPI buffer_QueryInterface(INSSBuffer *iface, REFIID iid, void **out)
186 struct buffer *buffer = impl_from_INSSBuffer(iface);
188 TRACE("buffer %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
190 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_INSSBuffer))
191 *out = &buffer->INSSBuffer_iface;
192 else
194 *out = NULL;
195 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
196 return E_NOINTERFACE;
199 IUnknown_AddRef((IUnknown *)*out);
200 return S_OK;
203 static ULONG WINAPI buffer_AddRef(INSSBuffer *iface)
205 struct buffer *buffer = impl_from_INSSBuffer(iface);
206 ULONG refcount = InterlockedIncrement(&buffer->refcount);
208 TRACE("%p increasing refcount to %u.\n", buffer, refcount);
210 return refcount;
213 static ULONG WINAPI buffer_Release(INSSBuffer *iface)
215 struct buffer *buffer = impl_from_INSSBuffer(iface);
216 ULONG refcount = InterlockedDecrement(&buffer->refcount);
218 TRACE("%p decreasing refcount to %u.\n", buffer, refcount);
220 if (!refcount)
221 free(buffer);
223 return refcount;
226 static HRESULT WINAPI buffer_GetLength(INSSBuffer *iface, DWORD *size)
228 FIXME("iface %p, size %p, stub!\n", iface, size);
229 return E_NOTIMPL;
232 static HRESULT WINAPI buffer_SetLength(INSSBuffer *iface, DWORD size)
234 FIXME("iface %p, size %u, stub!\n", iface, size);
235 return E_NOTIMPL;
238 static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size)
240 FIXME("iface %p, size %p, stub!\n", iface, size);
241 return E_NOTIMPL;
244 static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data)
246 FIXME("iface %p, data %p, stub!\n", iface, data);
247 return E_NOTIMPL;
250 static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size)
252 struct buffer *buffer = impl_from_INSSBuffer(iface);
254 TRACE("buffer %p, data %p, size %p.\n", buffer, data, size);
256 *size = buffer->size;
257 *data = buffer->data;
258 return S_OK;
261 static const INSSBufferVtbl buffer_vtbl =
263 buffer_QueryInterface,
264 buffer_AddRef,
265 buffer_Release,
266 buffer_GetLength,
267 buffer_SetLength,
268 buffer_GetMaxLength,
269 buffer_GetBuffer,
270 buffer_GetBufferAndLength,
273 struct stream_config
275 IWMStreamConfig IWMStreamConfig_iface;
276 LONG refcount;
278 const struct wm_stream *stream;
281 static struct stream_config *impl_from_IWMStreamConfig(IWMStreamConfig *iface)
283 return CONTAINING_RECORD(iface, struct stream_config, IWMStreamConfig_iface);
286 static HRESULT WINAPI stream_config_QueryInterface(IWMStreamConfig *iface, REFIID iid, void **out)
288 struct stream_config *config = impl_from_IWMStreamConfig(iface);
290 TRACE("config %p, iid %s, out %p.\n", config, debugstr_guid(iid), out);
292 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IWMStreamConfig))
293 *out = &config->IWMStreamConfig_iface;
294 else
296 *out = NULL;
297 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
298 return E_NOINTERFACE;
301 IUnknown_AddRef((IUnknown *)*out);
302 return S_OK;
305 static ULONG WINAPI stream_config_AddRef(IWMStreamConfig *iface)
307 struct stream_config *config = impl_from_IWMStreamConfig(iface);
308 ULONG refcount = InterlockedIncrement(&config->refcount);
310 TRACE("%p increasing refcount to %u.\n", config, refcount);
312 return refcount;
315 static ULONG WINAPI stream_config_Release(IWMStreamConfig *iface)
317 struct stream_config *config = impl_from_IWMStreamConfig(iface);
318 ULONG refcount = InterlockedDecrement(&config->refcount);
320 TRACE("%p decreasing refcount to %u.\n", config, refcount);
322 if (!refcount)
324 IWMProfile3_Release(&config->stream->reader->IWMProfile3_iface);
325 free(config);
328 return refcount;
331 static HRESULT WINAPI stream_config_GetStreamType(IWMStreamConfig *iface, GUID *type)
333 struct stream_config *config = impl_from_IWMStreamConfig(iface);
334 struct wm_reader *reader = config->stream->reader;
335 AM_MEDIA_TYPE mt;
337 TRACE("config %p, type %p.\n", config, type);
339 EnterCriticalSection(&reader->cs);
341 if (!amt_from_wg_format(&mt, &config->stream->format, true))
343 LeaveCriticalSection(&reader->cs);
344 return E_OUTOFMEMORY;
347 *type = mt.majortype;
348 FreeMediaType(&mt);
350 LeaveCriticalSection(&reader->cs);
352 return S_OK;
355 static HRESULT WINAPI stream_config_GetStreamNumber(IWMStreamConfig *iface, WORD *number)
357 struct stream_config *config = impl_from_IWMStreamConfig(iface);
359 TRACE("config %p, number %p.\n", config, number);
361 *number = config->stream->index + 1;
362 return S_OK;
365 static HRESULT WINAPI stream_config_SetStreamNumber(IWMStreamConfig *iface, WORD number)
367 FIXME("iface %p, number %u, stub!\n", iface, number);
368 return E_NOTIMPL;
371 static HRESULT WINAPI stream_config_GetStreamName(IWMStreamConfig *iface, WCHAR *name, WORD *len)
373 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
374 return E_NOTIMPL;
377 static HRESULT WINAPI stream_config_SetStreamName(IWMStreamConfig *iface, const WCHAR *name)
379 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
380 return E_NOTIMPL;
383 static HRESULT WINAPI stream_config_GetConnectionName(IWMStreamConfig *iface, WCHAR *name, WORD *len)
385 FIXME("iface %p, name %p, len %p, stub!\n", iface, name, len);
386 return E_NOTIMPL;
389 static HRESULT WINAPI stream_config_SetConnectionName(IWMStreamConfig *iface, const WCHAR *name)
391 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
392 return E_NOTIMPL;
395 static HRESULT WINAPI stream_config_GetBitrate(IWMStreamConfig *iface, DWORD *bitrate)
397 FIXME("iface %p, bitrate %p, stub!\n", iface, bitrate);
398 return E_NOTIMPL;
401 static HRESULT WINAPI stream_config_SetBitrate(IWMStreamConfig *iface, DWORD bitrate)
403 FIXME("iface %p, bitrate %u, stub!\n", iface, bitrate);
404 return E_NOTIMPL;
407 static HRESULT WINAPI stream_config_GetBufferWindow(IWMStreamConfig *iface, DWORD *window)
409 FIXME("iface %p, window %p, stub!\n", iface, window);
410 return E_NOTIMPL;
413 static HRESULT WINAPI stream_config_SetBufferWindow(IWMStreamConfig *iface, DWORD window)
415 FIXME("iface %p, window %u, stub!\n", iface, window);
416 return E_NOTIMPL;
419 static const IWMStreamConfigVtbl stream_config_vtbl =
421 stream_config_QueryInterface,
422 stream_config_AddRef,
423 stream_config_Release,
424 stream_config_GetStreamType,
425 stream_config_GetStreamNumber,
426 stream_config_SetStreamNumber,
427 stream_config_GetStreamName,
428 stream_config_SetStreamName,
429 stream_config_GetConnectionName,
430 stream_config_SetConnectionName,
431 stream_config_GetBitrate,
432 stream_config_SetBitrate,
433 stream_config_GetBufferWindow,
434 stream_config_SetBufferWindow,
437 static DWORD CALLBACK read_thread(void *arg)
439 struct wm_reader *reader = arg;
440 IStream *stream = reader->source_stream;
441 size_t buffer_size = 4096;
442 uint64_t file_size;
443 STATSTG stat;
444 void *data;
446 if (!(data = malloc(buffer_size)))
447 return 0;
449 IStream_Stat(stream, &stat, STATFLAG_NONAME);
450 file_size = stat.cbSize.QuadPart;
452 TRACE("Starting read thread for reader %p.\n", reader);
454 while (!reader->read_thread_shutdown)
456 LARGE_INTEGER stream_offset;
457 uint64_t offset;
458 ULONG ret_size;
459 uint32_t size;
460 HRESULT hr;
462 if (!wg_parser_get_next_read_offset(reader->wg_parser, &offset, &size))
463 continue;
465 if (offset >= file_size)
466 size = 0;
467 else if (offset + size >= file_size)
468 size = file_size - offset;
470 if (!size)
472 wg_parser_push_data(reader->wg_parser, data, 0);
473 continue;
476 if (!array_reserve(&data, &buffer_size, size, 1))
478 free(data);
479 return 0;
482 ret_size = 0;
484 stream_offset.QuadPart = offset;
485 if (SUCCEEDED(hr = IStream_Seek(stream, stream_offset, STREAM_SEEK_SET, NULL)))
486 hr = IStream_Read(stream, data, size, &ret_size);
487 if (FAILED(hr))
488 ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr);
489 else if (ret_size != size)
490 ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size);
491 wg_parser_push_data(reader->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size);
494 free(data);
495 TRACE("Reader is shutting down; exiting.\n");
496 return 0;
499 static struct wm_reader *impl_from_IWMProfile3(IWMProfile3 *iface)
501 return CONTAINING_RECORD(iface, struct wm_reader, IWMProfile3_iface);
504 static HRESULT WINAPI profile_QueryInterface(IWMProfile3 *iface, REFIID iid, void **out)
506 struct wm_reader *reader = impl_from_IWMProfile3(iface);
508 TRACE("reader %p, iid %s, out %p.\n", reader, debugstr_guid(iid), out);
510 if (IsEqualIID(iid, &IID_IWMHeaderInfo)
511 || IsEqualIID(iid, &IID_IWMHeaderInfo2)
512 || IsEqualIID(iid, &IID_IWMHeaderInfo3))
514 *out = &reader->IWMHeaderInfo3_iface;
516 else if (IsEqualIID(iid, &IID_IWMLanguageList))
518 *out = &reader->IWMLanguageList_iface;
520 else if (IsEqualIID(iid, &IID_IWMPacketSize)
521 || IsEqualIID(iid, &IID_IWMPacketSize2))
523 *out = &reader->IWMPacketSize2_iface;
525 else if (IsEqualIID(iid, &IID_IUnknown)
526 || IsEqualIID(iid, &IID_IWMProfile)
527 || IsEqualIID(iid, &IID_IWMProfile2)
528 || IsEqualIID(iid, &IID_IWMProfile3))
530 *out = &reader->IWMProfile3_iface;
532 else if (IsEqualIID(iid, &IID_IWMReaderPlaylistBurn))
534 *out = &reader->IWMReaderPlaylistBurn_iface;
536 else if (IsEqualIID(iid, &IID_IWMReaderTimecode))
538 *out = &reader->IWMReaderTimecode_iface;
540 else if (!(*out = reader->ops->query_interface(reader, iid)))
542 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
543 return E_NOINTERFACE;
546 IUnknown_AddRef((IUnknown *)*out);
547 return S_OK;
550 static ULONG WINAPI profile_AddRef(IWMProfile3 *iface)
552 struct wm_reader *reader = impl_from_IWMProfile3(iface);
553 ULONG refcount = InterlockedIncrement(&reader->refcount);
555 TRACE("%p increasing refcount to %u.\n", reader, refcount);
557 return refcount;
560 static ULONG WINAPI profile_Release(IWMProfile3 *iface)
562 struct wm_reader *reader = impl_from_IWMProfile3(iface);
563 ULONG refcount = InterlockedDecrement(&reader->refcount);
565 TRACE("%p decreasing refcount to %u.\n", reader, refcount);
567 if (!refcount)
568 reader->ops->destroy(reader);
570 return refcount;
573 static HRESULT WINAPI profile_GetVersion(IWMProfile3 *iface, WMT_VERSION *version)
575 FIXME("iface %p, version %p, stub!\n", iface, version);
576 return E_NOTIMPL;
579 static HRESULT WINAPI profile_GetName(IWMProfile3 *iface, WCHAR *name, DWORD *length)
581 FIXME("iface %p, name %p, length %p, stub!\n", iface, name, length);
582 return E_NOTIMPL;
585 static HRESULT WINAPI profile_SetName(IWMProfile3 *iface, const WCHAR *name)
587 FIXME("iface %p, name %s, stub!\n", iface, debugstr_w(name));
588 return E_NOTIMPL;
591 static HRESULT WINAPI profile_GetDescription(IWMProfile3 *iface, WCHAR *description, DWORD *length)
593 FIXME("iface %p, description %p, length %p, stub!\n", iface, description, length);
594 return E_NOTIMPL;
597 static HRESULT WINAPI profile_SetDescription(IWMProfile3 *iface, const WCHAR *description)
599 FIXME("iface %p, description %s, stub!\n", iface, debugstr_w(description));
600 return E_NOTIMPL;
603 static HRESULT WINAPI profile_GetStreamCount(IWMProfile3 *iface, DWORD *count)
605 struct wm_reader *reader = impl_from_IWMProfile3(iface);
607 TRACE("reader %p, count %p.\n", reader, count);
609 if (!count)
610 return E_INVALIDARG;
612 EnterCriticalSection(&reader->cs);
613 *count = reader->stream_count;
614 LeaveCriticalSection(&reader->cs);
615 return S_OK;
618 static HRESULT WINAPI profile_GetStream(IWMProfile3 *iface, DWORD index, IWMStreamConfig **config)
620 struct wm_reader *reader = impl_from_IWMProfile3(iface);
621 struct stream_config *object;
623 TRACE("reader %p, index %u, config %p.\n", reader, index, config);
625 EnterCriticalSection(&reader->cs);
627 if (index >= reader->stream_count)
629 LeaveCriticalSection(&reader->cs);
630 WARN("Index %u exceeds stream count %u; returning E_INVALIDARG.\n", index, reader->stream_count);
631 return E_INVALIDARG;
634 if (!(object = calloc(1, sizeof(*object))))
636 LeaveCriticalSection(&reader->cs);
637 return E_OUTOFMEMORY;
640 object->IWMStreamConfig_iface.lpVtbl = &stream_config_vtbl;
641 object->refcount = 1;
642 object->stream = &reader->streams[index];
643 IWMProfile3_AddRef(&reader->IWMProfile3_iface);
645 LeaveCriticalSection(&reader->cs);
647 TRACE("Created stream config %p.\n", object);
648 *config = &object->IWMStreamConfig_iface;
649 return S_OK;
652 static HRESULT WINAPI profile_GetStreamByNumber(IWMProfile3 *iface, WORD stream_number, IWMStreamConfig **config)
654 FIXME("iface %p, stream_number %u, config %p, stub!\n", iface, stream_number, config);
655 return E_NOTIMPL;
658 static HRESULT WINAPI profile_RemoveStream(IWMProfile3 *iface, IWMStreamConfig *config)
660 FIXME("iface %p, config %p, stub!\n", iface, config);
661 return E_NOTIMPL;
664 static HRESULT WINAPI profile_RemoveStreamByNumber(IWMProfile3 *iface, WORD stream_number)
666 FIXME("iface %p, stream_number %u, stub!\n", iface, stream_number);
667 return E_NOTIMPL;
670 static HRESULT WINAPI profile_AddStream(IWMProfile3 *iface, IWMStreamConfig *config)
672 FIXME("iface %p, config %p, stub!\n", iface, config);
673 return E_NOTIMPL;
676 static HRESULT WINAPI profile_ReconfigStream(IWMProfile3 *iface, IWMStreamConfig *config)
678 FIXME("iface %p, config %p, stub!\n", iface, config);
679 return E_NOTIMPL;
682 static HRESULT WINAPI profile_CreateNewStream(IWMProfile3 *iface, REFGUID type, IWMStreamConfig **config)
684 FIXME("iface %p, type %s, config %p, stub!\n", iface, debugstr_guid(type), config);
685 return E_NOTIMPL;
688 static HRESULT WINAPI profile_GetMutualExclusionCount(IWMProfile3 *iface, DWORD *count)
690 FIXME("iface %p, count %p, stub!\n", iface, count);
691 return E_NOTIMPL;
694 static HRESULT WINAPI profile_GetMutualExclusion(IWMProfile3 *iface, DWORD index, IWMMutualExclusion **excl)
696 FIXME("iface %p, index %u, excl %p, stub!\n", iface, index, excl);
697 return E_NOTIMPL;
700 static HRESULT WINAPI profile_RemoveMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
702 FIXME("iface %p, excl %p, stub!\n", iface, excl);
703 return E_NOTIMPL;
706 static HRESULT WINAPI profile_AddMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion *excl)
708 FIXME("iface %p, excl %p, stub!\n", iface, excl);
709 return E_NOTIMPL;
712 static HRESULT WINAPI profile_CreateNewMutualExclusion(IWMProfile3 *iface, IWMMutualExclusion **excl)
714 FIXME("iface %p, excl %p, stub!\n", iface, excl);
715 return E_NOTIMPL;
718 static HRESULT WINAPI profile_GetProfileID(IWMProfile3 *iface, GUID *id)
720 FIXME("iface %p, id %p, stub!\n", iface, id);
721 return E_NOTIMPL;
724 static HRESULT WINAPI profile_GetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT *format)
726 FIXME("iface %p, format %p, stub!\n", iface, format);
727 return E_NOTIMPL;
730 static HRESULT WINAPI profile_SetStorageFormat(IWMProfile3 *iface, WMT_STORAGE_FORMAT format)
732 FIXME("iface %p, format %#x, stub!\n", iface, format);
733 return E_NOTIMPL;
736 static HRESULT WINAPI profile_GetBandwidthSharingCount(IWMProfile3 *iface, DWORD *count)
738 FIXME("iface %p, count %p, stub!\n", iface, count);
739 return E_NOTIMPL;
742 static HRESULT WINAPI profile_GetBandwidthSharing(IWMProfile3 *iface, DWORD index, IWMBandwidthSharing **sharing)
744 FIXME("iface %p, index %d, sharing %p, stub!\n", iface, index, sharing);
745 return E_NOTIMPL;
748 static HRESULT WINAPI profile_RemoveBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing *sharing)
750 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
751 return E_NOTIMPL;
754 static HRESULT WINAPI profile_AddBandwidthSharing(IWMProfile3 *iface, IWMBandwidthSharing *sharing)
756 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
757 return E_NOTIMPL;
760 static HRESULT WINAPI profile_CreateNewBandwidthSharing( IWMProfile3 *iface, IWMBandwidthSharing **sharing)
762 FIXME("iface %p, sharing %p, stub!\n", iface, sharing);
763 return E_NOTIMPL;
766 static HRESULT WINAPI profile_GetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
768 FIXME("iface %p, stream %p, stub!\n", iface, stream);
769 return E_NOTIMPL;
772 static HRESULT WINAPI profile_SetStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization *stream)
774 FIXME("iface %p, stream %p, stub!\n", iface, stream);
775 return E_NOTIMPL;
778 static HRESULT WINAPI profile_RemoveStreamPrioritization(IWMProfile3 *iface)
780 FIXME("iface %p, stub!\n", iface);
781 return E_NOTIMPL;
784 static HRESULT WINAPI profile_CreateNewStreamPrioritization(IWMProfile3 *iface, IWMStreamPrioritization **stream)
786 FIXME("iface %p, stream %p, stub!\n", iface, stream);
787 return E_NOTIMPL;
790 static HRESULT WINAPI profile_GetExpectedPacketCount(IWMProfile3 *iface, QWORD duration, QWORD *count)
792 FIXME("iface %p, duration %s, count %p, stub!\n", iface, debugstr_time(duration), count);
793 return E_NOTIMPL;
796 static const IWMProfile3Vtbl profile_vtbl =
798 profile_QueryInterface,
799 profile_AddRef,
800 profile_Release,
801 profile_GetVersion,
802 profile_GetName,
803 profile_SetName,
804 profile_GetDescription,
805 profile_SetDescription,
806 profile_GetStreamCount,
807 profile_GetStream,
808 profile_GetStreamByNumber,
809 profile_RemoveStream,
810 profile_RemoveStreamByNumber,
811 profile_AddStream,
812 profile_ReconfigStream,
813 profile_CreateNewStream,
814 profile_GetMutualExclusionCount,
815 profile_GetMutualExclusion,
816 profile_RemoveMutualExclusion,
817 profile_AddMutualExclusion,
818 profile_CreateNewMutualExclusion,
819 profile_GetProfileID,
820 profile_GetStorageFormat,
821 profile_SetStorageFormat,
822 profile_GetBandwidthSharingCount,
823 profile_GetBandwidthSharing,
824 profile_RemoveBandwidthSharing,
825 profile_AddBandwidthSharing,
826 profile_CreateNewBandwidthSharing,
827 profile_GetStreamPrioritization,
828 profile_SetStreamPrioritization,
829 profile_RemoveStreamPrioritization,
830 profile_CreateNewStreamPrioritization,
831 profile_GetExpectedPacketCount,
834 static struct wm_reader *impl_from_IWMHeaderInfo3(IWMHeaderInfo3 *iface)
836 return CONTAINING_RECORD(iface, struct wm_reader, IWMHeaderInfo3_iface);
839 static HRESULT WINAPI header_info_QueryInterface(IWMHeaderInfo3 *iface, REFIID iid, void **out)
841 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
843 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
846 static ULONG WINAPI header_info_AddRef(IWMHeaderInfo3 *iface)
848 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
850 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
853 static ULONG WINAPI header_info_Release(IWMHeaderInfo3 *iface)
855 struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface);
857 return IWMProfile3_Release(&reader->IWMProfile3_iface);
860 static HRESULT WINAPI header_info_GetAttributeCount(IWMHeaderInfo3 *iface, WORD stream_number, WORD *count)
862 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
863 return E_NOTIMPL;
866 static HRESULT WINAPI header_info_GetAttributeByIndex(IWMHeaderInfo3 *iface, WORD index, WORD *stream_number,
867 WCHAR *name, WORD *name_len, WMT_ATTR_DATATYPE *type, BYTE *value, WORD *size)
869 FIXME("iface %p, index %u, stream_number %p, name %p, name_len %p, type %p, value %p, size %p, stub!\n",
870 iface, index, stream_number, name, name_len, type, value, size);
871 return E_NOTIMPL;
874 static HRESULT WINAPI header_info_GetAttributeByName(IWMHeaderInfo3 *iface, WORD *stream_number,
875 const WCHAR *name, WMT_ATTR_DATATYPE *type, BYTE *value, WORD *size)
877 FIXME("iface %p, stream_number %p, name %s, type %p, value %p, size %p, stub!\n",
878 iface, stream_number, debugstr_w(name), type, value, size);
879 return E_NOTIMPL;
882 static HRESULT WINAPI header_info_SetAttribute(IWMHeaderInfo3 *iface, WORD stream_number,
883 const WCHAR *name, WMT_ATTR_DATATYPE type, const BYTE *value, WORD size)
885 FIXME("iface %p, stream_number %u, name %s, type %#x, value %p, size %u, stub!\n",
886 iface, stream_number, debugstr_w(name), type, value, size);
887 return E_NOTIMPL;
890 static HRESULT WINAPI header_info_GetMarkerCount(IWMHeaderInfo3 *iface, WORD *count)
892 FIXME("iface %p, count %p, stub!\n", iface, count);
893 return E_NOTIMPL;
896 static HRESULT WINAPI header_info_GetMarker(IWMHeaderInfo3 *iface,
897 WORD index, WCHAR *name, WORD *len, QWORD *time)
899 FIXME("iface %p, index %u, name %p, len %p, time %p, stub!\n", iface, index, name, len, time);
900 return E_NOTIMPL;
903 static HRESULT WINAPI header_info_AddMarker(IWMHeaderInfo3 *iface, const WCHAR *name, QWORD time)
905 FIXME("iface %p, name %s, time %s, stub!\n", iface, debugstr_w(name), debugstr_time(time));
906 return E_NOTIMPL;
909 static HRESULT WINAPI header_info_RemoveMarker(IWMHeaderInfo3 *iface, WORD index)
911 FIXME("iface %p, index %u, stub!\n", iface, index);
912 return E_NOTIMPL;
915 static HRESULT WINAPI header_info_GetScriptCount(IWMHeaderInfo3 *iface, WORD *count)
917 FIXME("iface %p, count %p, stub!\n", iface, count);
918 return E_NOTIMPL;
921 static HRESULT WINAPI header_info_GetScript(IWMHeaderInfo3 *iface, WORD index, WCHAR *type,
922 WORD *type_len, WCHAR *command, WORD *command_len, QWORD *time)
924 FIXME("iface %p, index %u, type %p, type_len %p, command %p, command_len %p, time %p, stub!\n",
925 iface, index, type, type_len, command, command_len, time);
926 return E_NOTIMPL;
929 static HRESULT WINAPI header_info_AddScript(IWMHeaderInfo3 *iface,
930 const WCHAR *type, const WCHAR *command, QWORD time)
932 FIXME("iface %p, type %s, command %s, time %s, stub!\n",
933 iface, debugstr_w(type), debugstr_w(command), debugstr_time(time));
934 return E_NOTIMPL;
937 static HRESULT WINAPI header_info_RemoveScript(IWMHeaderInfo3 *iface, WORD index)
939 FIXME("iface %p, index %u, stub!\n", iface, index);
940 return E_NOTIMPL;
943 static HRESULT WINAPI header_info_GetCodecInfoCount(IWMHeaderInfo3 *iface, DWORD *count)
945 FIXME("iface %p, count %p, stub!\n", iface, count);
946 return E_NOTIMPL;
949 static HRESULT WINAPI header_info_GetCodecInfo(IWMHeaderInfo3 *iface, DWORD index, WORD *name_len,
950 WCHAR *name, WORD *desc_len, WCHAR *desc, WMT_CODEC_INFO_TYPE *type, WORD *size, BYTE *info)
952 FIXME("iface %p, index %u, name_len %p, name %p, desc_len %p, desc %p, type %p, size %p, info %p, stub!\n",
953 iface, index, name_len, name, desc_len, desc, type, size, info);
954 return E_NOTIMPL;
957 static HRESULT WINAPI header_info_GetAttributeCountEx(IWMHeaderInfo3 *iface, WORD stream_number, WORD *count)
959 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
960 return E_NOTIMPL;
963 static HRESULT WINAPI header_info_GetAttributeIndices(IWMHeaderInfo3 *iface, WORD stream_number,
964 const WCHAR *name, WORD *lang_index, WORD *indices, WORD *count)
966 FIXME("iface %p, stream_number %u, name %s, lang_index %p, indices %p, count %p, stub!\n",
967 iface, stream_number, debugstr_w(name), lang_index, indices, count);
968 return E_NOTIMPL;
971 static HRESULT WINAPI header_info_GetAttributeByIndexEx(IWMHeaderInfo3 *iface,
972 WORD stream_number, WORD index, WCHAR *name, WORD *name_len,
973 WMT_ATTR_DATATYPE *type, WORD *lang_index, BYTE *value, DWORD *size)
975 FIXME("iface %p, stream_number %u, index %u, name %p, name_len %p,"
976 " type %p, lang_index %p, value %p, size %p, stub!\n",
977 iface, stream_number, index, debugstr_w(name), name_len, type, lang_index, value, size);
978 return E_NOTIMPL;
981 static HRESULT WINAPI header_info_ModifyAttribute(IWMHeaderInfo3 *iface, WORD stream_number,
982 WORD index, WMT_ATTR_DATATYPE type, WORD lang_index, const BYTE *value, DWORD size)
984 FIXME("iface %p, stream_number %u, index %u, type %#x, lang_index %u, value %p, size %u, stub!\n",
985 iface, stream_number, index, type, lang_index, value, size);
986 return E_NOTIMPL;
989 static HRESULT WINAPI header_info_AddAttribute(IWMHeaderInfo3 *iface,
990 WORD stream_number, const WCHAR *name, WORD *index,
991 WMT_ATTR_DATATYPE type, WORD lang_index, const BYTE *value, DWORD size)
993 FIXME("iface %p, stream_number %u, name %s, index %p, type %#x, lang_index %u, value %p, size %u, stub!\n",
994 iface, stream_number, debugstr_w(name), index, type, lang_index, value, size);
995 return E_NOTIMPL;
998 static HRESULT WINAPI header_info_DeleteAttribute(IWMHeaderInfo3 *iface, WORD stream_number, WORD index)
1000 FIXME("iface %p, stream_number %u, index %u, stub!\n", iface, stream_number, index);
1001 return E_NOTIMPL;
1004 static HRESULT WINAPI header_info_AddCodecInfo(IWMHeaderInfo3 *iface, const WCHAR *name,
1005 const WCHAR *desc, WMT_CODEC_INFO_TYPE type, WORD size, BYTE *info)
1007 FIXME("iface %p, name %s, desc %s, type %#x, size %u, info %p, stub!\n",
1008 info, debugstr_w(name), debugstr_w(desc), type, size, info);
1009 return E_NOTIMPL;
1012 static const IWMHeaderInfo3Vtbl header_info_vtbl =
1014 header_info_QueryInterface,
1015 header_info_AddRef,
1016 header_info_Release,
1017 header_info_GetAttributeCount,
1018 header_info_GetAttributeByIndex,
1019 header_info_GetAttributeByName,
1020 header_info_SetAttribute,
1021 header_info_GetMarkerCount,
1022 header_info_GetMarker,
1023 header_info_AddMarker,
1024 header_info_RemoveMarker,
1025 header_info_GetScriptCount,
1026 header_info_GetScript,
1027 header_info_AddScript,
1028 header_info_RemoveScript,
1029 header_info_GetCodecInfoCount,
1030 header_info_GetCodecInfo,
1031 header_info_GetAttributeCountEx,
1032 header_info_GetAttributeIndices,
1033 header_info_GetAttributeByIndexEx,
1034 header_info_ModifyAttribute,
1035 header_info_AddAttribute,
1036 header_info_DeleteAttribute,
1037 header_info_AddCodecInfo,
1040 static struct wm_reader *impl_from_IWMLanguageList(IWMLanguageList *iface)
1042 return CONTAINING_RECORD(iface, struct wm_reader, IWMLanguageList_iface);
1045 static HRESULT WINAPI language_list_QueryInterface(IWMLanguageList *iface, REFIID iid, void **out)
1047 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1049 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
1052 static ULONG WINAPI language_list_AddRef(IWMLanguageList *iface)
1054 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1056 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
1059 static ULONG WINAPI language_list_Release(IWMLanguageList *iface)
1061 struct wm_reader *reader = impl_from_IWMLanguageList(iface);
1063 return IWMProfile3_Release(&reader->IWMProfile3_iface);
1066 static HRESULT WINAPI language_list_GetLanguageCount(IWMLanguageList *iface, WORD *count)
1068 FIXME("iface %p, count %p, stub!\n", iface, count);
1069 return E_NOTIMPL;
1072 static HRESULT WINAPI language_list_GetLanguageDetails(IWMLanguageList *iface,
1073 WORD index, WCHAR *lang, WORD *len)
1075 FIXME("iface %p, index %u, lang %p, len %p, stub!\n", iface, index, lang, len);
1076 return E_NOTIMPL;
1079 static HRESULT WINAPI language_list_AddLanguageByRFC1766String(IWMLanguageList *iface,
1080 const WCHAR *lang, WORD *index)
1082 FIXME("iface %p, lang %s, index %p, stub!\n", iface, debugstr_w(lang), index);
1083 return E_NOTIMPL;
1086 static const IWMLanguageListVtbl language_list_vtbl =
1088 language_list_QueryInterface,
1089 language_list_AddRef,
1090 language_list_Release,
1091 language_list_GetLanguageCount,
1092 language_list_GetLanguageDetails,
1093 language_list_AddLanguageByRFC1766String,
1096 static struct wm_reader *impl_from_IWMPacketSize2(IWMPacketSize2 *iface)
1098 return CONTAINING_RECORD(iface, struct wm_reader, IWMPacketSize2_iface);
1101 static HRESULT WINAPI packet_size_QueryInterface(IWMPacketSize2 *iface, REFIID iid, void **out)
1103 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1105 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
1108 static ULONG WINAPI packet_size_AddRef(IWMPacketSize2 *iface)
1110 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1112 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
1115 static ULONG WINAPI packet_size_Release(IWMPacketSize2 *iface)
1117 struct wm_reader *reader = impl_from_IWMPacketSize2(iface);
1119 return IWMProfile3_Release(&reader->IWMProfile3_iface);
1122 static HRESULT WINAPI packet_size_GetMaxPacketSize(IWMPacketSize2 *iface, DWORD *size)
1124 FIXME("iface %p, size %p, stub!\n", iface, size);
1125 return E_NOTIMPL;
1128 static HRESULT WINAPI packet_size_SetMaxPacketSize(IWMPacketSize2 *iface, DWORD size)
1130 FIXME("iface %p, size %u, stub!\n", iface, size);
1131 return E_NOTIMPL;
1134 static HRESULT WINAPI packet_size_GetMinPacketSize(IWMPacketSize2 *iface, DWORD *size)
1136 FIXME("iface %p, size %p, stub!\n", iface, size);
1137 return E_NOTIMPL;
1140 static HRESULT WINAPI packet_size_SetMinPacketSize(IWMPacketSize2 *iface, DWORD size)
1142 FIXME("iface %p, size %u, stub!\n", iface, size);
1143 return E_NOTIMPL;
1146 static const IWMPacketSize2Vtbl packet_size_vtbl =
1148 packet_size_QueryInterface,
1149 packet_size_AddRef,
1150 packet_size_Release,
1151 packet_size_GetMaxPacketSize,
1152 packet_size_SetMaxPacketSize,
1153 packet_size_GetMinPacketSize,
1154 packet_size_SetMinPacketSize,
1157 static struct wm_reader *impl_from_IWMReaderPlaylistBurn(IWMReaderPlaylistBurn *iface)
1159 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderPlaylistBurn_iface);
1162 static HRESULT WINAPI playlist_QueryInterface(IWMReaderPlaylistBurn *iface, REFIID iid, void **out)
1164 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1166 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
1169 static ULONG WINAPI playlist_AddRef(IWMReaderPlaylistBurn *iface)
1171 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1173 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
1176 static ULONG WINAPI playlist_Release(IWMReaderPlaylistBurn *iface)
1178 struct wm_reader *reader = impl_from_IWMReaderPlaylistBurn(iface);
1180 return IWMProfile3_Release(&reader->IWMProfile3_iface);
1183 static HRESULT WINAPI playlist_InitPlaylistBurn(IWMReaderPlaylistBurn *iface, DWORD count,
1184 const WCHAR **filenames, IWMStatusCallback *callback, void *context)
1186 FIXME("iface %p, count %u, filenames %p, callback %p, context %p, stub!\n",
1187 iface, count, filenames, callback, context);
1188 return E_NOTIMPL;
1191 static HRESULT WINAPI playlist_GetInitResults(IWMReaderPlaylistBurn *iface, DWORD count, HRESULT *hrs)
1193 FIXME("iface %p, count %u, hrs %p, stub!\n", iface, count, hrs);
1194 return E_NOTIMPL;
1197 static HRESULT WINAPI playlist_Cancel(IWMReaderPlaylistBurn *iface)
1199 FIXME("iface %p, stub!\n", iface);
1200 return E_NOTIMPL;
1203 static HRESULT WINAPI playlist_EndPlaylistBurn(IWMReaderPlaylistBurn *iface, HRESULT hr)
1205 FIXME("iface %p, hr %#x, stub!\n", iface, hr);
1206 return E_NOTIMPL;
1209 static const IWMReaderPlaylistBurnVtbl playlist_vtbl =
1211 playlist_QueryInterface,
1212 playlist_AddRef,
1213 playlist_Release,
1214 playlist_InitPlaylistBurn,
1215 playlist_GetInitResults,
1216 playlist_Cancel,
1217 playlist_EndPlaylistBurn,
1220 static struct wm_reader *impl_from_IWMReaderTimecode(IWMReaderTimecode *iface)
1222 return CONTAINING_RECORD(iface, struct wm_reader, IWMReaderTimecode_iface);
1225 static HRESULT WINAPI timecode_QueryInterface(IWMReaderTimecode *iface, REFIID iid, void **out)
1227 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1229 return IWMProfile3_QueryInterface(&reader->IWMProfile3_iface, iid, out);
1232 static ULONG WINAPI timecode_AddRef(IWMReaderTimecode *iface)
1234 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1236 return IWMProfile3_AddRef(&reader->IWMProfile3_iface);
1239 static ULONG WINAPI timecode_Release(IWMReaderTimecode *iface)
1241 struct wm_reader *reader = impl_from_IWMReaderTimecode(iface);
1243 return IWMProfile3_Release(&reader->IWMProfile3_iface);
1246 static HRESULT WINAPI timecode_GetTimecodeRangeCount(IWMReaderTimecode *iface,
1247 WORD stream_number, WORD *count)
1249 FIXME("iface %p, stream_number %u, count %p, stub!\n", iface, stream_number, count);
1250 return E_NOTIMPL;
1253 static HRESULT WINAPI timecode_GetTimecodeRangeBounds(IWMReaderTimecode *iface,
1254 WORD stream_number, WORD index, DWORD *start, DWORD *end)
1256 FIXME("iface %p, stream_number %u, index %u, start %p, end %p, stub!\n",
1257 iface, stream_number, index, start, end);
1258 return E_NOTIMPL;
1261 static const IWMReaderTimecodeVtbl timecode_vtbl =
1263 timecode_QueryInterface,
1264 timecode_AddRef,
1265 timecode_Release,
1266 timecode_GetTimecodeRangeCount,
1267 timecode_GetTimecodeRangeBounds,
1270 HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream)
1272 struct wg_parser *wg_parser;
1273 STATSTG stat;
1274 HRESULT hr;
1275 WORD i;
1277 if (FAILED(hr = IStream_Stat(stream, &stat, STATFLAG_NONAME)))
1279 ERR("Failed to stat stream, hr %#x.\n", hr);
1280 return hr;
1283 if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false)))
1284 return E_OUTOFMEMORY;
1286 EnterCriticalSection(&reader->cs);
1288 reader->wg_parser = wg_parser;
1289 IStream_AddRef(reader->source_stream = stream);
1290 reader->read_thread_shutdown = false;
1291 if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL)))
1293 hr = E_OUTOFMEMORY;
1294 goto out_destroy_parser;
1297 if (FAILED(hr = wg_parser_connect(reader->wg_parser, stat.cbSize.QuadPart)))
1299 ERR("Failed to connect parser, hr %#x.\n", hr);
1300 goto out_shutdown_thread;
1303 reader->stream_count = wg_parser_get_stream_count(reader->wg_parser);
1305 if (!(reader->streams = calloc(reader->stream_count, sizeof(*reader->streams))))
1307 hr = E_OUTOFMEMORY;
1308 goto out_disconnect_parser;
1311 for (i = 0; i < reader->stream_count; ++i)
1313 struct wm_stream *stream = &reader->streams[i];
1315 stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i);
1316 stream->reader = reader;
1317 stream->index = i;
1318 wg_parser_stream_get_preferred_format(stream->wg_stream, &stream->format);
1319 if (stream->format.major_type == WG_MAJOR_TYPE_AUDIO)
1321 /* R.U.S.E enumerates available audio types, picks the first one it
1322 * likes, and then sets the wrong stream to that type. libav might
1323 * give us WG_AUDIO_FORMAT_F32LE by default, which will result in
1324 * the game incorrectly interpreting float data as integer.
1325 * Therefore just match native and always set our default format to
1326 * S16LE. */
1327 stream->format.u.audio.format = WG_AUDIO_FORMAT_S16LE;
1329 else if (stream->format.major_type == WG_MAJOR_TYPE_VIDEO)
1331 /* Call of Juarez: Bound in Blood breaks if I420 is enumerated.
1332 * Some native decoders output I420, but the msmpeg4v3 decoder
1333 * never does. */
1334 if (stream->format.u.video.format == WG_VIDEO_FORMAT_I420)
1335 stream->format.u.video.format = WG_VIDEO_FORMAT_YV12;
1337 wg_parser_stream_enable(stream->wg_stream, &stream->format);
1340 wg_parser_end_flush(reader->wg_parser);
1341 /* We probably discarded events because streams weren't enabled yet.
1342 * Now that they're all enabled seek back to the start again. */
1343 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0,
1344 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
1346 LeaveCriticalSection(&reader->cs);
1347 return S_OK;
1349 out_disconnect_parser:
1350 wg_parser_disconnect(reader->wg_parser);
1352 out_shutdown_thread:
1353 reader->read_thread_shutdown = true;
1354 WaitForSingleObject(reader->read_thread, INFINITE);
1355 CloseHandle(reader->read_thread);
1356 reader->read_thread = NULL;
1358 out_destroy_parser:
1359 wg_parser_destroy(reader->wg_parser);
1360 reader->wg_parser = NULL;
1361 IStream_Release(reader->source_stream);
1362 reader->source_stream = NULL;
1364 LeaveCriticalSection(&reader->cs);
1365 return hr;
1368 HRESULT wm_reader_close(struct wm_reader *reader)
1370 EnterCriticalSection(&reader->cs);
1372 if (!reader->source_stream)
1374 LeaveCriticalSection(&reader->cs);
1375 return NS_E_INVALID_REQUEST;
1378 wg_parser_disconnect(reader->wg_parser);
1380 reader->read_thread_shutdown = true;
1381 WaitForSingleObject(reader->read_thread, INFINITE);
1382 CloseHandle(reader->read_thread);
1383 reader->read_thread = NULL;
1385 wg_parser_destroy(reader->wg_parser);
1386 reader->wg_parser = NULL;
1387 IStream_Release(reader->source_stream);
1388 reader->source_stream = NULL;
1390 LeaveCriticalSection(&reader->cs);
1391 return S_OK;
1394 struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number)
1396 if (stream_number && stream_number <= reader->stream_count)
1397 return &reader->streams[stream_number - 1];
1398 WARN("Invalid stream number %u.\n", stream_number);
1399 return NULL;
1402 HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps **props)
1404 struct wm_stream *stream;
1406 EnterCriticalSection(&reader->cs);
1408 if (!(stream = get_stream_by_output_number(reader, output)))
1410 LeaveCriticalSection(&reader->cs);
1411 return E_INVALIDARG;
1414 *props = output_props_create(&stream->format);
1415 LeaveCriticalSection(&reader->cs);
1416 return *props ? S_OK : E_OUTOFMEMORY;
1419 static const enum wg_video_format video_formats[] =
1421 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
1422 * YUV color space, and it's generally much less expensive for
1423 * videoconvert to do YUV -> YUV transformations. */
1424 WG_VIDEO_FORMAT_NV12,
1425 WG_VIDEO_FORMAT_YV12,
1426 WG_VIDEO_FORMAT_YUY2,
1427 WG_VIDEO_FORMAT_UYVY,
1428 WG_VIDEO_FORMAT_YVYU,
1429 WG_VIDEO_FORMAT_BGRx,
1430 WG_VIDEO_FORMAT_BGR,
1431 WG_VIDEO_FORMAT_RGB16,
1432 WG_VIDEO_FORMAT_RGB15,
1435 HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output, DWORD *count)
1437 struct wm_stream *stream;
1438 struct wg_format format;
1440 EnterCriticalSection(&reader->cs);
1442 if (!(stream = get_stream_by_output_number(reader, output)))
1444 LeaveCriticalSection(&reader->cs);
1445 return E_INVALIDARG;
1448 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
1449 switch (format.major_type)
1451 case WG_MAJOR_TYPE_VIDEO:
1452 *count = ARRAY_SIZE(video_formats);
1453 break;
1455 case WG_MAJOR_TYPE_AUDIO:
1456 case WG_MAJOR_TYPE_UNKNOWN:
1457 *count = 1;
1458 break;
1461 LeaveCriticalSection(&reader->cs);
1462 return S_OK;
1465 HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output,
1466 DWORD index, IWMOutputMediaProps **props)
1468 struct wm_stream *stream;
1469 struct wg_format format;
1471 EnterCriticalSection(&reader->cs);
1473 if (!(stream = get_stream_by_output_number(reader, output)))
1475 LeaveCriticalSection(&reader->cs);
1476 return E_INVALIDARG;
1479 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
1481 switch (format.major_type)
1483 case WG_MAJOR_TYPE_VIDEO:
1484 if (index >= ARRAY_SIZE(video_formats))
1486 LeaveCriticalSection(&reader->cs);
1487 return NS_E_INVALID_OUTPUT_FORMAT;
1489 format.u.video.format = video_formats[index];
1490 break;
1492 case WG_MAJOR_TYPE_AUDIO:
1493 if (index)
1495 LeaveCriticalSection(&reader->cs);
1496 return NS_E_INVALID_OUTPUT_FORMAT;
1498 format.u.audio.format = WG_AUDIO_FORMAT_S16LE;
1499 break;
1501 case WG_MAJOR_TYPE_UNKNOWN:
1502 break;
1505 LeaveCriticalSection(&reader->cs);
1507 *props = output_props_create(&format);
1508 return *props ? S_OK : E_OUTOFMEMORY;
1511 HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
1512 IWMOutputMediaProps *props_iface)
1514 struct output_props *props = unsafe_impl_from_IWMOutputMediaProps(props_iface);
1515 struct wg_format format, pref_format;
1516 struct wm_stream *stream;
1518 strmbase_dump_media_type(&props->mt);
1520 if (!amt_to_wg_format(&props->mt, &format))
1522 ERR("Failed to convert media type to winegstreamer format.\n");
1523 return E_FAIL;
1526 EnterCriticalSection(&reader->cs);
1528 if (!(stream = get_stream_by_output_number(reader, output)))
1530 LeaveCriticalSection(&reader->cs);
1531 return E_INVALIDARG;
1534 wg_parser_stream_get_preferred_format(stream->wg_stream, &pref_format);
1535 if (pref_format.major_type != format.major_type)
1537 /* R.U.S.E sets the type of the wrong stream, apparently by accident. */
1538 LeaveCriticalSection(&reader->cs);
1539 WARN("Major types don't match; returning NS_E_INCOMPATIBLE_FORMAT.\n");
1540 return NS_E_INCOMPATIBLE_FORMAT;
1543 stream->format = format;
1544 wg_parser_stream_enable(stream->wg_stream, &format);
1546 /* Re-decode any buffers that might have been generated with the old format.
1548 * FIXME: Seeking in-place will cause some buffers to be dropped.
1549 * Unfortunately, we can't really store the last received PTS and seek there
1550 * either: since seeks are inexact and we aren't guaranteed to receive
1551 * samples in order, some buffers might be duplicated or dropped anyway.
1552 * In order to really seamlessly allow for format changes, we need
1553 * cooperation from each individual GStreamer stream, to be able to tell
1554 * upstream exactly which buffers they need resent...
1556 * In all likelihood this function is being called not mid-stream but rather
1557 * while setting the stream up, before consuming any events. Accordingly
1558 * let's just seek back to the beginning. */
1559 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, reader->start_time, 0,
1560 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
1562 LeaveCriticalSection(&reader->cs);
1563 return S_OK;
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_VIDEO:
1573 return "video";
1574 case WG_MAJOR_TYPE_UNKNOWN:
1575 return "unknown";
1577 assert(0);
1578 return NULL;
1581 HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
1582 INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags)
1584 struct wg_parser_stream *wg_stream = stream->wg_stream;
1585 struct wg_parser_event event;
1586 struct buffer *object;
1588 if (stream->eos)
1589 return NS_E_NO_MORE_SAMPLES;
1591 for (;;)
1593 if (!wg_parser_stream_get_event(wg_stream, &event))
1595 FIXME("Stream is flushing.\n");
1596 return E_NOTIMPL;
1599 TRACE("Got event of type %#x for %s stream %p.\n", event.type,
1600 get_major_type_string(stream->format.major_type), stream);
1602 switch (event.type)
1604 case WG_PARSER_EVENT_BUFFER:
1605 /* FIXME: Should these be pooled? */
1606 if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size]))))
1608 wg_parser_stream_release_buffer(wg_stream);
1609 return E_OUTOFMEMORY;
1612 object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
1613 object->refcount = 1;
1614 object->size = event.u.buffer.size;
1616 if (!wg_parser_stream_copy_buffer(wg_stream, object->data, 0, object->size))
1618 /* The GStreamer pin has been flushed. */
1619 free(object);
1620 break;
1623 wg_parser_stream_release_buffer(wg_stream);
1625 if (!event.u.buffer.has_pts)
1626 FIXME("Missing PTS.\n");
1627 if (!event.u.buffer.has_duration)
1628 FIXME("Missing duration.\n");
1630 *pts = event.u.buffer.pts;
1631 *duration = event.u.buffer.duration;
1632 *flags = 0;
1633 if (event.u.buffer.discontinuity)
1634 *flags |= WM_SF_DISCONTINUITY;
1635 if (!event.u.buffer.delta)
1636 *flags |= WM_SF_CLEANPOINT;
1638 TRACE("Created buffer %p.\n", object);
1639 *ret_sample = &object->INSSBuffer_iface;
1640 return S_OK;
1642 case WG_PARSER_EVENT_EOS:
1643 stream->eos = true;
1644 TRACE("End of stream.\n");
1645 return NS_E_NO_MORE_SAMPLES;
1647 case WG_PARSER_EVENT_SEGMENT:
1648 break;
1650 case WG_PARSER_EVENT_NONE:
1651 assert(0);
1656 void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration)
1658 WORD i;
1660 EnterCriticalSection(&reader->cs);
1662 reader->start_time = start;
1664 wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, start, start + duration,
1665 AM_SEEKING_AbsolutePositioning, duration ? AM_SEEKING_AbsolutePositioning : AM_SEEKING_NoPositioning);
1667 for (i = 0; i < reader->stream_count; ++i)
1668 reader->streams[i].eos = false;
1670 LeaveCriticalSection(&reader->cs);
1673 void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops)
1675 reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
1676 reader->IWMLanguageList_iface.lpVtbl = &language_list_vtbl;
1677 reader->IWMPacketSize2_iface.lpVtbl = &packet_size_vtbl;
1678 reader->IWMProfile3_iface.lpVtbl = &profile_vtbl;
1679 reader->IWMReaderPlaylistBurn_iface.lpVtbl = &playlist_vtbl;
1680 reader->IWMReaderTimecode_iface.lpVtbl = &timecode_vtbl;
1681 reader->refcount = 1;
1682 reader->ops = ops;
1684 InitializeCriticalSection(&reader->cs);
1685 reader->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wm_reader.cs");
1688 void wm_reader_cleanup(struct wm_reader *reader)
1690 reader->cs.DebugInfo->Spare[0] = 0;
1691 DeleteCriticalSection(&reader->cs);