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