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
);
33 IWMOutputMediaProps IWMOutputMediaProps_iface
;
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
;
55 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
59 IUnknown_AddRef((IUnknown
*)*out
);
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
);
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
);
86 static HRESULT WINAPI
output_props_GetType(IWMOutputMediaProps
*iface
, GUID
*major_type
)
88 FIXME("iface %p, major_type %p, stub!\n", iface
, major_type
);
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
;
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);
113 static HRESULT WINAPI
output_props_SetMediaType(IWMOutputMediaProps
*iface
, WM_MEDIA_TYPE
*mt
)
115 FIXME("iface %p, mt %p, stub!\n", iface
, mt
);
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
);
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
);
131 static const struct IWMOutputMediaPropsVtbl output_props_vtbl
=
133 output_props_QueryInterface
,
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
)
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
))))
157 object
->IWMOutputMediaProps_iface
.lpVtbl
= &output_props_vtbl
;
158 object
->refcount
= 1;
160 if (!amt_from_wg_format(&object
->mt
, format
, true))
166 TRACE("Created output properties %p.\n", object
);
167 return &object
->IWMOutputMediaProps_iface
;
172 INSSBuffer INSSBuffer_iface
;
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
;
195 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
196 return E_NOINTERFACE
;
199 IUnknown_AddRef((IUnknown
*)*out
);
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
);
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
);
226 static HRESULT WINAPI
buffer_GetLength(INSSBuffer
*iface
, DWORD
*size
)
228 FIXME("iface %p, size %p, stub!\n", iface
, size
);
232 static HRESULT WINAPI
buffer_SetLength(INSSBuffer
*iface
, DWORD size
)
234 FIXME("iface %p, size %u, stub!\n", iface
, size
);
238 static HRESULT WINAPI
buffer_GetMaxLength(INSSBuffer
*iface
, DWORD
*size
)
240 FIXME("iface %p, size %p, stub!\n", iface
, size
);
244 static HRESULT WINAPI
buffer_GetBuffer(INSSBuffer
*iface
, BYTE
**data
)
246 FIXME("iface %p, data %p, stub!\n", iface
, data
);
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
;
261 static const INSSBufferVtbl buffer_vtbl
=
263 buffer_QueryInterface
,
270 buffer_GetBufferAndLength
,
275 IWMStreamConfig IWMStreamConfig_iface
;
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
;
297 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
298 return E_NOINTERFACE
;
301 IUnknown_AddRef((IUnknown
*)*out
);
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
);
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
);
324 IWMProfile3_Release(&config
->stream
->reader
->IWMProfile3_iface
);
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
;
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
;
350 LeaveCriticalSection(&reader
->cs
);
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;
365 static HRESULT WINAPI
stream_config_SetStreamNumber(IWMStreamConfig
*iface
, WORD number
)
367 FIXME("iface %p, number %u, stub!\n", iface
, number
);
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
);
377 static HRESULT WINAPI
stream_config_SetStreamName(IWMStreamConfig
*iface
, const WCHAR
*name
)
379 FIXME("iface %p, name %s, stub!\n", iface
, debugstr_w(name
));
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
);
389 static HRESULT WINAPI
stream_config_SetConnectionName(IWMStreamConfig
*iface
, const WCHAR
*name
)
391 FIXME("iface %p, name %s, stub!\n", iface
, debugstr_w(name
));
395 static HRESULT WINAPI
stream_config_GetBitrate(IWMStreamConfig
*iface
, DWORD
*bitrate
)
397 FIXME("iface %p, bitrate %p, stub!\n", iface
, bitrate
);
401 static HRESULT WINAPI
stream_config_SetBitrate(IWMStreamConfig
*iface
, DWORD bitrate
)
403 FIXME("iface %p, bitrate %u, stub!\n", iface
, bitrate
);
407 static HRESULT WINAPI
stream_config_GetBufferWindow(IWMStreamConfig
*iface
, DWORD
*window
)
409 FIXME("iface %p, window %p, stub!\n", iface
, window
);
413 static HRESULT WINAPI
stream_config_SetBufferWindow(IWMStreamConfig
*iface
, DWORD window
)
415 FIXME("iface %p, window %u, stub!\n", iface
, window
);
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;
446 if (!(data
= malloc(buffer_size
)))
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
;
462 if (!wg_parser_get_next_read_offset(reader
->wg_parser
, &offset
, &size
))
465 if (offset
>= file_size
)
467 else if (offset
+ size
>= file_size
)
468 size
= file_size
- offset
;
472 wg_parser_push_data(reader
->wg_parser
, data
, 0);
476 if (!array_reserve(&data
, &buffer_size
, size
, 1))
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
);
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
);
495 TRACE("Reader is shutting down; exiting.\n");
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
);
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
);
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
);
568 reader
->ops
->destroy(reader
);
573 static HRESULT WINAPI
profile_GetVersion(IWMProfile3
*iface
, WMT_VERSION
*version
)
575 FIXME("iface %p, version %p, stub!\n", iface
, version
);
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
);
585 static HRESULT WINAPI
profile_SetName(IWMProfile3
*iface
, const WCHAR
*name
)
587 FIXME("iface %p, name %s, stub!\n", iface
, debugstr_w(name
));
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
);
597 static HRESULT WINAPI
profile_SetDescription(IWMProfile3
*iface
, const WCHAR
*description
)
599 FIXME("iface %p, description %s, stub!\n", iface
, debugstr_w(description
));
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
);
612 EnterCriticalSection(&reader
->cs
);
613 *count
= reader
->stream_count
;
614 LeaveCriticalSection(&reader
->cs
);
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
);
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
;
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
);
658 static HRESULT WINAPI
profile_RemoveStream(IWMProfile3
*iface
, IWMStreamConfig
*config
)
660 FIXME("iface %p, config %p, stub!\n", iface
, config
);
664 static HRESULT WINAPI
profile_RemoveStreamByNumber(IWMProfile3
*iface
, WORD stream_number
)
666 FIXME("iface %p, stream_number %u, stub!\n", iface
, stream_number
);
670 static HRESULT WINAPI
profile_AddStream(IWMProfile3
*iface
, IWMStreamConfig
*config
)
672 FIXME("iface %p, config %p, stub!\n", iface
, config
);
676 static HRESULT WINAPI
profile_ReconfigStream(IWMProfile3
*iface
, IWMStreamConfig
*config
)
678 FIXME("iface %p, config %p, stub!\n", iface
, config
);
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
);
688 static HRESULT WINAPI
profile_GetMutualExclusionCount(IWMProfile3
*iface
, DWORD
*count
)
690 FIXME("iface %p, count %p, stub!\n", iface
, count
);
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
);
700 static HRESULT WINAPI
profile_RemoveMutualExclusion(IWMProfile3
*iface
, IWMMutualExclusion
*excl
)
702 FIXME("iface %p, excl %p, stub!\n", iface
, excl
);
706 static HRESULT WINAPI
profile_AddMutualExclusion(IWMProfile3
*iface
, IWMMutualExclusion
*excl
)
708 FIXME("iface %p, excl %p, stub!\n", iface
, excl
);
712 static HRESULT WINAPI
profile_CreateNewMutualExclusion(IWMProfile3
*iface
, IWMMutualExclusion
**excl
)
714 FIXME("iface %p, excl %p, stub!\n", iface
, excl
);
718 static HRESULT WINAPI
profile_GetProfileID(IWMProfile3
*iface
, GUID
*id
)
720 FIXME("iface %p, id %p, stub!\n", iface
, id
);
724 static HRESULT WINAPI
profile_GetStorageFormat(IWMProfile3
*iface
, WMT_STORAGE_FORMAT
*format
)
726 FIXME("iface %p, format %p, stub!\n", iface
, format
);
730 static HRESULT WINAPI
profile_SetStorageFormat(IWMProfile3
*iface
, WMT_STORAGE_FORMAT format
)
732 FIXME("iface %p, format %#x, stub!\n", iface
, format
);
736 static HRESULT WINAPI
profile_GetBandwidthSharingCount(IWMProfile3
*iface
, DWORD
*count
)
738 FIXME("iface %p, count %p, stub!\n", iface
, count
);
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
);
748 static HRESULT WINAPI
profile_RemoveBandwidthSharing( IWMProfile3
*iface
, IWMBandwidthSharing
*sharing
)
750 FIXME("iface %p, sharing %p, stub!\n", iface
, sharing
);
754 static HRESULT WINAPI
profile_AddBandwidthSharing(IWMProfile3
*iface
, IWMBandwidthSharing
*sharing
)
756 FIXME("iface %p, sharing %p, stub!\n", iface
, sharing
);
760 static HRESULT WINAPI
profile_CreateNewBandwidthSharing( IWMProfile3
*iface
, IWMBandwidthSharing
**sharing
)
762 FIXME("iface %p, sharing %p, stub!\n", iface
, sharing
);
766 static HRESULT WINAPI
profile_GetStreamPrioritization(IWMProfile3
*iface
, IWMStreamPrioritization
**stream
)
768 FIXME("iface %p, stream %p, stub!\n", iface
, stream
);
772 static HRESULT WINAPI
profile_SetStreamPrioritization(IWMProfile3
*iface
, IWMStreamPrioritization
*stream
)
774 FIXME("iface %p, stream %p, stub!\n", iface
, stream
);
778 static HRESULT WINAPI
profile_RemoveStreamPrioritization(IWMProfile3
*iface
)
780 FIXME("iface %p, stub!\n", iface
);
784 static HRESULT WINAPI
profile_CreateNewStreamPrioritization(IWMProfile3
*iface
, IWMStreamPrioritization
**stream
)
786 FIXME("iface %p, stream %p, stub!\n", iface
, stream
);
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
);
796 static const IWMProfile3Vtbl profile_vtbl
=
798 profile_QueryInterface
,
804 profile_GetDescription
,
805 profile_SetDescription
,
806 profile_GetStreamCount
,
808 profile_GetStreamByNumber
,
809 profile_RemoveStream
,
810 profile_RemoveStreamByNumber
,
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
);
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
);
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
);
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
);
890 static HRESULT WINAPI
header_info_GetMarkerCount(IWMHeaderInfo3
*iface
, WORD
*count
)
892 FIXME("iface %p, count %p, stub!\n", iface
, count
);
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
);
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
));
909 static HRESULT WINAPI
header_info_RemoveMarker(IWMHeaderInfo3
*iface
, WORD index
)
911 FIXME("iface %p, index %u, stub!\n", iface
, index
);
915 static HRESULT WINAPI
header_info_GetScriptCount(IWMHeaderInfo3
*iface
, WORD
*count
)
917 FIXME("iface %p, count %p, stub!\n", iface
, count
);
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
);
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
));
937 static HRESULT WINAPI
header_info_RemoveScript(IWMHeaderInfo3
*iface
, WORD index
)
939 FIXME("iface %p, index %u, stub!\n", iface
, index
);
943 static HRESULT WINAPI
header_info_GetCodecInfoCount(IWMHeaderInfo3
*iface
, DWORD
*count
)
945 FIXME("iface %p, count %p, stub!\n", iface
, count
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
1012 static const IWMHeaderInfo3Vtbl header_info_vtbl
=
1014 header_info_QueryInterface
,
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
);
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
);
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
);
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
);
1128 static HRESULT WINAPI
packet_size_SetMaxPacketSize(IWMPacketSize2
*iface
, DWORD size
)
1130 FIXME("iface %p, size %u, stub!\n", iface
, size
);
1134 static HRESULT WINAPI
packet_size_GetMinPacketSize(IWMPacketSize2
*iface
, DWORD
*size
)
1136 FIXME("iface %p, size %p, stub!\n", iface
, size
);
1140 static HRESULT WINAPI
packet_size_SetMinPacketSize(IWMPacketSize2
*iface
, DWORD size
)
1142 FIXME("iface %p, size %u, stub!\n", iface
, size
);
1146 static const IWMPacketSize2Vtbl packet_size_vtbl
=
1148 packet_size_QueryInterface
,
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
);
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
);
1197 static HRESULT WINAPI
playlist_Cancel(IWMReaderPlaylistBurn
*iface
)
1199 FIXME("iface %p, stub!\n", iface
);
1203 static HRESULT WINAPI
playlist_EndPlaylistBurn(IWMReaderPlaylistBurn
*iface
, HRESULT hr
)
1205 FIXME("iface %p, hr %#x, stub!\n", iface
, hr
);
1209 static const IWMReaderPlaylistBurnVtbl playlist_vtbl
=
1211 playlist_QueryInterface
,
1214 playlist_InitPlaylistBurn
,
1215 playlist_GetInitResults
,
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
);
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
);
1261 static const IWMReaderTimecodeVtbl timecode_vtbl
=
1263 timecode_QueryInterface
,
1266 timecode_GetTimecodeRangeCount
,
1267 timecode_GetTimecodeRangeBounds
,
1270 HRESULT
wm_reader_open_stream(struct wm_reader
*reader
, IStream
*stream
)
1272 struct wg_parser
*wg_parser
;
1277 if (FAILED(hr
= IStream_Stat(stream
, &stat
, STATFLAG_NONAME
)))
1279 ERR("Failed to stat stream, hr %#x.\n", 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
)))
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
))))
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
;
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
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
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
);
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
;
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
);
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
);
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
);
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
);
1455 case WG_MAJOR_TYPE_AUDIO
:
1456 case WG_MAJOR_TYPE_UNKNOWN
:
1461 LeaveCriticalSection(&reader
->cs
);
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
];
1492 case WG_MAJOR_TYPE_AUDIO
:
1495 LeaveCriticalSection(&reader
->cs
);
1496 return NS_E_INVALID_OUTPUT_FORMAT
;
1498 format
.u
.audio
.format
= WG_AUDIO_FORMAT_S16LE
;
1501 case WG_MAJOR_TYPE_UNKNOWN
:
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");
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
);
1566 static const char *get_major_type_string(enum wg_major_type type
)
1570 case WG_MAJOR_TYPE_AUDIO
:
1572 case WG_MAJOR_TYPE_VIDEO
:
1574 case WG_MAJOR_TYPE_UNKNOWN
:
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
;
1589 return NS_E_NO_MORE_SAMPLES
;
1593 if (!wg_parser_stream_get_event(wg_stream
, &event
))
1595 FIXME("Stream is flushing.\n");
1599 TRACE("Got event of type %#x for %s stream %p.\n", event
.type
,
1600 get_major_type_string(stream
->format
.major_type
), stream
);
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. */
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
;
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
;
1642 case WG_PARSER_EVENT_EOS
:
1644 TRACE("End of stream.\n");
1645 return NS_E_NO_MORE_SAMPLES
;
1647 case WG_PARSER_EVENT_SEGMENT
:
1650 case WG_PARSER_EVENT_NONE
:
1656 void wm_reader_seek(struct wm_reader
*reader
, QWORD start
, LONGLONG duration
)
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;
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
);