4 * Copyright 2020 Jactry Zeng for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "qasf_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
30 static inline const char *debugstr_time(REFERENCE_TIME time
)
32 ULONGLONG abstime
= time
>= 0 ? time
: -time
;
33 unsigned int i
= 0, j
= 0;
34 char buffer
[23], rev
[23];
36 while (abstime
|| i
<= 8)
38 buffer
[i
++] = '0' + (abstime
% 10);
40 if (i
== 7) buffer
[i
++] = '.';
42 if (time
< 0) buffer
[i
++] = '-';
44 while (i
--) rev
[j
++] = buffer
[i
];
45 while (rev
[j
-1] == '0' && rev
[j
-2] != '.') --j
;
48 return wine_dbg_sprintf("%s", rev
);
53 INSSBuffer INSSBuffer_iface
;
58 static struct buffer
*impl_from_INSSBuffer(INSSBuffer
*iface
)
60 return CONTAINING_RECORD(iface
, struct buffer
, INSSBuffer_iface
);
63 static HRESULT WINAPI
buffer_QueryInterface(INSSBuffer
*iface
, REFIID iid
, void **out
)
65 struct buffer
*impl
= impl_from_INSSBuffer(iface
);
67 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
69 if (IsEqualGUID(iid
, &IID_IUnknown
)
70 || IsEqualGUID(iid
, &IID_INSSBuffer
))
71 *out
= &impl
->INSSBuffer_iface
;
75 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
79 IUnknown_AddRef((IUnknown
*)*out
);
83 static ULONG WINAPI
buffer_AddRef(INSSBuffer
*iface
)
85 struct buffer
*impl
= impl_from_INSSBuffer(iface
);
86 ULONG ref
= InterlockedIncrement(&impl
->refcount
);
87 TRACE("iface %p increasing refcount to %lu.\n", iface
, ref
);
91 static ULONG WINAPI
buffer_Release(INSSBuffer
*iface
)
93 struct buffer
*impl
= impl_from_INSSBuffer(iface
);
94 ULONG ref
= InterlockedDecrement(&impl
->refcount
);
96 TRACE("iface %p decreasing refcount to %lu.\n", iface
, ref
);
100 IMediaSample_Release(impl
->sample
);
107 static HRESULT WINAPI
buffer_GetLength(INSSBuffer
*iface
, DWORD
*size
)
109 struct buffer
*impl
= impl_from_INSSBuffer(iface
);
110 TRACE("iface %p, size %p.\n", iface
, size
);
111 *size
= IMediaSample_GetActualDataLength(impl
->sample
);
115 static HRESULT WINAPI
buffer_SetLength(INSSBuffer
*iface
, DWORD size
)
117 struct buffer
*impl
= impl_from_INSSBuffer(iface
);
118 TRACE("iface %p, size %lu.\n", iface
, size
);
119 return IMediaSample_SetActualDataLength(impl
->sample
, size
);
122 static HRESULT WINAPI
buffer_GetMaxLength(INSSBuffer
*iface
, DWORD
*size
)
124 struct buffer
*impl
= impl_from_INSSBuffer(iface
);
125 TRACE("iface %p, size %p.\n", iface
, size
);
126 *size
= IMediaSample_GetSize(impl
->sample
);
130 static HRESULT WINAPI
buffer_GetBuffer(INSSBuffer
*iface
, BYTE
**data
)
132 struct buffer
*impl
= impl_from_INSSBuffer(iface
);
133 TRACE("iface %p, data %p.\n", iface
, data
);
134 return IMediaSample_GetPointer(impl
->sample
, data
);
137 static HRESULT WINAPI
buffer_GetBufferAndLength(INSSBuffer
*iface
, BYTE
**data
, DWORD
*size
)
139 struct buffer
*impl
= impl_from_INSSBuffer(iface
);
140 TRACE("iface %p, data %p, size %p.\n", iface
, data
, size
);
141 *size
= IMediaSample_GetSize(impl
->sample
);
142 return IMediaSample_GetPointer(impl
->sample
, data
);
145 static const INSSBufferVtbl buffer_vtbl
=
147 buffer_QueryInterface
,
154 buffer_GetBufferAndLength
,
157 static HRESULT
buffer_create(IMediaSample
*sample
, INSSBuffer
**out
)
159 struct buffer
*buffer
;
161 if (!(buffer
= calloc(1, sizeof(struct buffer
))))
162 return E_OUTOFMEMORY
;
164 buffer
->INSSBuffer_iface
.lpVtbl
= &buffer_vtbl
;
165 buffer
->refcount
= 1;
166 buffer
->sample
= sample
;
168 *out
= &buffer
->INSSBuffer_iface
;
169 TRACE("Created buffer %p for sample %p\n", *out
, sample
);
174 static struct buffer
*unsafe_impl_from_INSSBuffer(INSSBuffer
*iface
)
176 if (iface
->lpVtbl
!= &buffer_vtbl
) return NULL
;
177 return impl_from_INSSBuffer(iface
);
182 struct strmbase_source source
;
183 struct SourceSeeking seek
;
189 struct strmbase_filter filter
;
190 IFileSourceFilter IFileSourceFilter_iface
;
196 CRITICAL_SECTION status_cs
;
197 CONDITION_VARIABLE status_cv
;
199 IWMReaderCallback
*callback
;
203 struct asf_stream streams
[16];
206 static inline struct asf_stream
*impl_from_strmbase_pin(struct strmbase_pin
*iface
)
208 return CONTAINING_RECORD(iface
, struct asf_stream
, source
.pin
);
211 static inline struct asf_reader
*asf_reader_from_asf_stream(struct asf_stream
*stream
)
213 return CONTAINING_RECORD(stream
, struct asf_reader
, streams
[stream
->index
]);
216 static HRESULT
asf_stream_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*media_type
)
218 struct asf_stream
*stream
= impl_from_strmbase_pin(iface
);
219 struct asf_reader
*filter
= asf_reader_from_asf_stream(stream
);
220 IWMOutputMediaProps
*props
;
225 TRACE("iface %p, media_type %p.\n", iface
, media_type
);
227 if (FAILED(hr
= IWMReader_GetOutputFormat(filter
->reader
, stream
->index
, i
, &props
)))
229 if (FAILED(hr
= IWMOutputMediaProps_GetMediaType(props
, NULL
, &size
)))
231 IWMOutputMediaProps_Release(props
);
234 if (!(mt
= malloc(size
)))
236 IWMOutputMediaProps_Release(props
);
237 return E_OUTOFMEMORY
;
242 if (SUCCEEDED(hr
= IWMOutputMediaProps_GetMediaType(props
, mt
, &size
))
243 && IsEqualGUID(&mt
->majortype
, &media_type
->majortype
)
244 && IsEqualGUID(&mt
->subtype
, &media_type
->subtype
))
246 IWMOutputMediaProps_Release(props
);
250 IWMOutputMediaProps_Release(props
);
251 } while (SUCCEEDED(hr
= IWMReader_GetOutputFormat(filter
->reader
, stream
->index
, ++i
, &props
)));
257 static HRESULT
asf_stream_get_media_type(struct strmbase_pin
*iface
, unsigned int index
, AM_MEDIA_TYPE
*media_type
)
259 struct asf_stream
*stream
= impl_from_strmbase_pin(iface
);
260 struct asf_reader
*filter
= asf_reader_from_asf_stream(stream
);
261 IWMOutputMediaProps
*props
;
266 TRACE("iface %p, index %u, media_type %p.\n", iface
, index
, media_type
);
268 if (FAILED(IWMReader_GetOutputFormat(filter
->reader
, stream
->index
, index
, &props
)))
269 return VFW_S_NO_MORE_ITEMS
;
270 if (FAILED(hr
= IWMOutputMediaProps_GetMediaType(props
, NULL
, &size
)))
272 IWMOutputMediaProps_Release(props
);
275 if (!(mt
= malloc(size
)))
277 IWMOutputMediaProps_Release(props
);
278 return E_OUTOFMEMORY
;
281 hr
= IWMOutputMediaProps_GetMediaType(props
, mt
, &size
);
283 hr
= CopyMediaType(media_type
, (AM_MEDIA_TYPE
*)mt
);
286 IWMOutputMediaProps_Release(props
);
290 static HRESULT
asf_stream_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
292 struct asf_stream
*stream
= impl_from_strmbase_pin(iface
);
294 if (IsEqualGUID(iid
, &IID_IMediaSeeking
))
295 *out
= &stream
->seek
.IMediaSeeking_iface
;
297 return E_NOINTERFACE
;
299 IUnknown_AddRef((IUnknown
*)*out
);
303 static inline struct asf_stream
*impl_from_IMediaSeeking(IMediaSeeking
*iface
)
305 return CONTAINING_RECORD(iface
, struct asf_stream
, seek
.IMediaSeeking_iface
);
308 static HRESULT WINAPI
media_seeking_ChangeCurrent(IMediaSeeking
*iface
)
310 FIXME("iface %p stub!\n", iface
);
314 static HRESULT WINAPI
media_seeking_ChangeStop(IMediaSeeking
*iface
)
316 FIXME("iface %p stub!\n", iface
);
320 static HRESULT WINAPI
media_seeking_ChangeRate(IMediaSeeking
*iface
)
322 FIXME("iface %p stub!\n", iface
);
326 static HRESULT WINAPI
media_seeking_QueryInterface(IMediaSeeking
*iface
, REFIID riid
, void **ppv
)
328 struct asf_stream
*impl
= impl_from_IMediaSeeking(iface
);
329 return IUnknown_QueryInterface(&impl
->source
.pin
.IPin_iface
, riid
, ppv
);
332 static ULONG WINAPI
media_seeking_AddRef(IMediaSeeking
*iface
)
334 struct asf_stream
*impl
= impl_from_IMediaSeeking(iface
);
335 return IUnknown_AddRef(&impl
->source
.pin
.IPin_iface
);
338 static ULONG WINAPI
media_seeking_Release(IMediaSeeking
*iface
)
340 struct asf_stream
*impl
= impl_from_IMediaSeeking(iface
);
341 return IUnknown_Release(&impl
->source
.pin
.IPin_iface
);
344 static HRESULT WINAPI
media_seeking_SetPositions(IMediaSeeking
*iface
,
345 LONGLONG
*current
, DWORD current_flags
, LONGLONG
*stop
, DWORD stop_flags
)
347 FIXME("iface %p, current %s, current_flags %#lx, stop %s, stop_flags %#lx stub!\n",
348 iface
, current
? debugstr_time(*current
) : "<null>", current_flags
,
349 stop
? debugstr_time(*stop
) : "<null>", stop_flags
);
350 return SourceSeekingImpl_SetPositions(iface
, current
, current_flags
, stop
, stop_flags
);
353 static const IMediaSeekingVtbl media_seeking_vtbl
=
355 media_seeking_QueryInterface
,
356 media_seeking_AddRef
,
357 media_seeking_Release
,
358 SourceSeekingImpl_GetCapabilities
,
359 SourceSeekingImpl_CheckCapabilities
,
360 SourceSeekingImpl_IsFormatSupported
,
361 SourceSeekingImpl_QueryPreferredFormat
,
362 SourceSeekingImpl_GetTimeFormat
,
363 SourceSeekingImpl_IsUsingTimeFormat
,
364 SourceSeekingImpl_SetTimeFormat
,
365 SourceSeekingImpl_GetDuration
,
366 SourceSeekingImpl_GetStopPosition
,
367 SourceSeekingImpl_GetCurrentPosition
,
368 SourceSeekingImpl_ConvertTimeFormat
,
369 media_seeking_SetPositions
,
370 SourceSeekingImpl_GetPositions
,
371 SourceSeekingImpl_GetAvailable
,
372 SourceSeekingImpl_SetRate
,
373 SourceSeekingImpl_GetRate
,
374 SourceSeekingImpl_GetPreroll
,
377 static inline struct asf_reader
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
379 return CONTAINING_RECORD(iface
, struct asf_reader
, filter
);
382 static struct strmbase_pin
*asf_reader_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
384 struct asf_reader
*filter
= impl_from_strmbase_filter(iface
);
385 struct strmbase_pin
*pin
= NULL
;
387 TRACE("iface %p, index %u.\n", iface
, index
);
389 EnterCriticalSection(&filter
->filter
.filter_cs
);
390 if (index
< filter
->stream_count
)
391 pin
= &filter
->streams
[index
].source
.pin
;
392 LeaveCriticalSection(&filter
->filter
.filter_cs
);
397 static void asf_reader_destroy(struct strmbase_filter
*iface
)
399 struct asf_reader
*filter
= impl_from_strmbase_filter(iface
);
400 struct strmbase_source
*source
;
402 while (filter
->stream_count
--)
404 source
= &filter
->streams
[filter
->stream_count
].source
;
405 if (source
->pin
.peer
) IPin_Disconnect(source
->pin
.peer
);
406 IPin_Disconnect(&source
->pin
.IPin_iface
);
407 strmbase_source_cleanup(source
);
410 free(filter
->file_name
);
411 IWMReaderCallback_Release(filter
->callback
);
412 IWMReader_Release(filter
->reader
);
414 strmbase_filter_cleanup(&filter
->filter
);
416 filter
->status_cs
.DebugInfo
->Spare
[0] = 0;
417 DeleteCriticalSection(&filter
->status_cs
);
422 static HRESULT
asf_reader_query_interface(struct strmbase_filter
*iface
, REFIID iid
, void **out
)
424 struct asf_reader
*filter
= impl_from_strmbase_filter(iface
);
426 if (IsEqualGUID(iid
, &IID_IFileSourceFilter
))
428 *out
= &filter
->IFileSourceFilter_iface
;
429 IUnknown_AddRef((IUnknown
*)*out
);
433 return E_NOINTERFACE
;
436 static HRESULT
asf_reader_init_stream(struct strmbase_filter
*iface
)
438 struct asf_reader
*filter
= impl_from_strmbase_filter(iface
);
439 WMT_STREAM_SELECTION selections
[ARRAY_SIZE(filter
->streams
)];
440 WORD stream_numbers
[ARRAY_SIZE(filter
->streams
)];
441 IWMReaderAdvanced
*reader_advanced
;
445 TRACE("iface %p\n", iface
);
447 if (FAILED(hr
= IWMReader_QueryInterface(filter
->reader
, &IID_IWMReaderAdvanced
, (void **)&reader_advanced
)))
450 for (i
= 0; i
< filter
->stream_count
; ++i
)
452 struct asf_stream
*stream
= filter
->streams
+ i
;
453 IWMOutputMediaProps
*props
;
455 stream_numbers
[i
] = i
+ 1;
456 selections
[i
] = WMT_OFF
;
458 if (!stream
->source
.pin
.peer
)
461 if (FAILED(hr
= IMemAllocator_Commit(stream
->source
.pAllocator
)))
463 WARN("Failed to commit stream %u allocator, hr %#lx\n", i
, hr
);
467 if (FAILED(hr
= IWMReaderAdvanced_SetAllocateForOutput(reader_advanced
, i
, TRUE
)))
469 WARN("Failed to enable allocation for stream %u, hr %#lx\n", i
, hr
);
473 if (FAILED(hr
= IWMReader_GetOutputFormat(filter
->reader
, stream
->index
, 0, &props
)))
475 WARN("Failed to get stream %u output format, hr %#lx\n", i
, hr
);
479 hr
= IWMOutputMediaProps_SetMediaType(props
, (WM_MEDIA_TYPE
*)&stream
->source
.pin
.mt
);
481 hr
= IWMReader_SetOutputProps(filter
->reader
, stream
->index
, props
);
482 IWMOutputMediaProps_Release(props
);
485 WARN("Failed to set stream %u output format, hr %#lx\n", i
, hr
);
489 if (FAILED(hr
= IPin_NewSegment(stream
->source
.pin
.peer
, 0, 0, 1)))
491 WARN("Failed to start stream %u new segment, hr %#lx\n", i
, hr
);
495 selections
[i
] = WMT_ON
;
498 if (SUCCEEDED(hr
) && FAILED(hr
= IWMReaderAdvanced_SetStreamsSelected(reader_advanced
,
499 filter
->stream_count
, stream_numbers
, selections
)))
500 WARN("Failed to set reader %p stream selection, hr %#lx\n", filter
->reader
, hr
);
502 IWMReaderAdvanced_Release(reader_advanced
);
507 EnterCriticalSection(&filter
->status_cs
);
508 if (SUCCEEDED(hr
= IWMReader_Start(filter
->reader
, 0, 0, 1, NULL
)))
511 while (filter
->status
!= WMT_STARTED
)
512 SleepConditionVariableCS(&filter
->status_cv
, &filter
->status_cs
, INFINITE
);
515 LeaveCriticalSection(&filter
->status_cs
);
518 WARN("Failed to start WMReader %p, hr %#lx\n", filter
->reader
, hr
);
523 static HRESULT
asf_reader_cleanup_stream(struct strmbase_filter
*iface
)
525 struct asf_reader
*filter
= impl_from_strmbase_filter(iface
);
529 TRACE("iface %p\n", iface
);
531 EnterCriticalSection(&filter
->status_cs
);
532 if (SUCCEEDED(hr
= IWMReader_Stop(filter
->reader
)))
535 while (filter
->status
!= WMT_STOPPED
)
536 SleepConditionVariableCS(&filter
->status_cv
, &filter
->status_cs
, INFINITE
);
539 LeaveCriticalSection(&filter
->status_cs
);
542 WARN("Failed to stop WMReader %p, hr %#lx\n", filter
->reader
, hr
);
544 for (i
= 0; i
< filter
->stream_count
; ++i
)
546 struct asf_stream
*stream
= filter
->streams
+ i
;
548 if (!stream
->source
.pin
.peer
)
551 if (FAILED(hr
= IMemAllocator_Decommit(stream
->source
.pAllocator
)))
553 WARN("Failed to decommit stream %u allocator, hr %#lx\n", i
, hr
);
561 static const struct strmbase_filter_ops filter_ops
=
563 .filter_get_pin
= asf_reader_get_pin
,
564 .filter_destroy
= asf_reader_destroy
,
565 .filter_query_interface
= asf_reader_query_interface
,
566 .filter_init_stream
= asf_reader_init_stream
,
567 .filter_cleanup_stream
= asf_reader_cleanup_stream
,
570 static HRESULT WINAPI
asf_reader_DecideBufferSize(struct strmbase_source
*iface
,
571 IMemAllocator
*allocator
, ALLOCATOR_PROPERTIES
*req_props
)
573 struct asf_stream
*stream
= impl_from_strmbase_pin(&iface
->pin
);
574 unsigned int buffer_size
= 16384;
575 ALLOCATOR_PROPERTIES ret_props
;
577 TRACE("iface %p, allocator %p, req_props %p.\n", iface
, allocator
, req_props
);
579 if (IsEqualGUID(&stream
->source
.pin
.mt
.formattype
, &FORMAT_VideoInfo
))
581 VIDEOINFOHEADER
*format
= (VIDEOINFOHEADER
*)stream
->source
.pin
.mt
.pbFormat
;
582 buffer_size
= format
->bmiHeader
.biSizeImage
;
584 else if (IsEqualGUID(&stream
->source
.pin
.mt
.formattype
, &FORMAT_WaveFormatEx
)
585 && (IsEqualGUID(&stream
->source
.pin
.mt
.subtype
, &MEDIASUBTYPE_PCM
)
586 || IsEqualGUID(&stream
->source
.pin
.mt
.subtype
, &MEDIASUBTYPE_IEEE_FLOAT
)))
588 WAVEFORMATEX
*format
= (WAVEFORMATEX
*)stream
->source
.pin
.mt
.pbFormat
;
589 buffer_size
= format
->nAvgBytesPerSec
;
592 req_props
->cBuffers
= max(req_props
->cBuffers
, 1);
593 req_props
->cbBuffer
= max(req_props
->cbBuffer
, buffer_size
);
594 req_props
->cbAlign
= max(req_props
->cbAlign
, 1);
595 return IMemAllocator_SetProperties(allocator
, req_props
, &ret_props
);
598 static const struct strmbase_source_ops source_ops
=
600 .base
.pin_query_accept
= asf_stream_query_accept
,
601 .base
.pin_get_media_type
= asf_stream_get_media_type
,
602 .base
.pin_query_interface
= asf_stream_query_interface
,
603 .pfnDecideAllocator
= BaseOutputPinImpl_DecideAllocator
,
604 .pfnAttemptConnection
= BaseOutputPinImpl_AttemptConnection
,
605 .pfnDecideBufferSize
= asf_reader_DecideBufferSize
,
608 static inline struct asf_reader
*impl_from_IFileSourceFilter(IFileSourceFilter
*iface
)
610 return CONTAINING_RECORD(iface
, struct asf_reader
, IFileSourceFilter_iface
);
613 static HRESULT WINAPI
file_source_QueryInterface(IFileSourceFilter
*iface
, REFIID iid
, void **out
)
615 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
617 return IBaseFilter_QueryInterface(&filter
->filter
.IBaseFilter_iface
, iid
, out
);
620 static ULONG WINAPI
file_source_AddRef(IFileSourceFilter
*iface
)
622 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
624 return IBaseFilter_AddRef(&filter
->filter
.IBaseFilter_iface
);
627 static ULONG WINAPI
file_source_Release(IFileSourceFilter
*iface
)
629 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
631 return IBaseFilter_Release(&filter
->filter
.IBaseFilter_iface
);
634 static HRESULT WINAPI
file_source_Load(IFileSourceFilter
*iface
, LPCOLESTR file_name
, const AM_MEDIA_TYPE
*media_type
)
636 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
639 TRACE("filter %p, file_name %s, media_type %p.\n", filter
, debugstr_w(file_name
), media_type
);
640 strmbase_dump_media_type(media_type
);
645 EnterCriticalSection(&filter
->filter
.filter_cs
);
647 if (filter
->file_name
|| !(filter
->file_name
= wcsdup(file_name
)))
649 LeaveCriticalSection(&filter
->filter
.filter_cs
);
653 EnterCriticalSection(&filter
->status_cs
);
654 if (SUCCEEDED(hr
= IWMReader_Open(filter
->reader
, filter
->file_name
, filter
->callback
, NULL
)))
657 while (filter
->status
!= WMT_OPENED
)
658 SleepConditionVariableCS(&filter
->status_cv
, &filter
->status_cs
, INFINITE
);
661 LeaveCriticalSection(&filter
->status_cs
);
664 WARN("Failed to open WM reader, hr %#lx.\n", hr
);
666 LeaveCriticalSection(&filter
->filter
.filter_cs
);
671 static HRESULT WINAPI
file_source_GetCurFile(IFileSourceFilter
*iface
, LPOLESTR
*file_name
, AM_MEDIA_TYPE
*media_type
)
673 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
675 TRACE("filter %p, file_name %p, media_type %p.\n", filter
, file_name
, media_type
);
683 media_type
->majortype
= GUID_NULL
;
684 media_type
->subtype
= GUID_NULL
;
685 media_type
->lSampleSize
= 0;
686 media_type
->pUnk
= NULL
;
687 media_type
->cbFormat
= 0;
690 if (filter
->file_name
)
692 *file_name
= CoTaskMemAlloc((wcslen(filter
->file_name
) + 1) * sizeof(WCHAR
));
693 wcscpy(*file_name
, filter
->file_name
);
699 static const IFileSourceFilterVtbl file_source_vtbl
=
701 file_source_QueryInterface
,
705 file_source_GetCurFile
,
710 IWMReaderCallback IWMReaderCallback_iface
;
711 IWMReaderCallbackAdvanced IWMReaderCallbackAdvanced_iface
;
714 struct asf_reader
*filter
;
717 static inline struct asf_callback
*impl_from_IWMReaderCallback(IWMReaderCallback
*iface
)
719 return CONTAINING_RECORD(iface
, struct asf_callback
, IWMReaderCallback_iface
);
722 static HRESULT WINAPI
reader_callback_QueryInterface(IWMReaderCallback
*iface
, const IID
*iid
, void **out
)
724 struct asf_callback
*callback
= impl_from_IWMReaderCallback(iface
);
726 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
728 if (IsEqualGUID(iid
, &IID_IUnknown
)
729 || IsEqualGUID(iid
, &IID_IWMStatusCallback
)
730 || IsEqualGUID(iid
, &IID_IWMReaderCallback
))
731 *out
= &callback
->IWMReaderCallback_iface
;
732 else if (IsEqualGUID(iid
, &IID_IWMReaderCallbackAdvanced
))
733 *out
= &callback
->IWMReaderCallbackAdvanced_iface
;
737 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
738 return E_NOINTERFACE
;
741 IUnknown_AddRef((IUnknown
*)*out
);
745 static ULONG WINAPI
reader_callback_AddRef(IWMReaderCallback
*iface
)
747 struct asf_callback
*callback
= impl_from_IWMReaderCallback(iface
);
748 ULONG ref
= InterlockedIncrement(&callback
->ref
);
750 TRACE("%p increasing ref to %lu.\n", callback
, ref
);
755 static ULONG WINAPI
reader_callback_Release(IWMReaderCallback
*iface
)
757 struct asf_callback
*callback
= impl_from_IWMReaderCallback(iface
);
758 ULONG ref
= InterlockedDecrement(&callback
->ref
);
760 TRACE("%p decreasing ref to %lu.\n", callback
, ref
);
768 static HRESULT WINAPI
reader_callback_OnStatus(IWMReaderCallback
*iface
, WMT_STATUS status
, HRESULT result
,
769 WMT_ATTR_DATATYPE type
, BYTE
*value
, void *context
)
771 struct asf_reader
*filter
= impl_from_IWMReaderCallback(iface
)->filter
;
772 AM_MEDIA_TYPE stream_media_type
= {{0}};
773 IWMHeaderInfo
*header_info
;
774 DWORD i
, stream_count
;
775 WCHAR name
[MAX_PATH
];
779 TRACE("iface %p, status %d, result %#lx, type %d, value %p, context %p.\n",
780 iface
, status
, result
, type
, value
, context
);
785 if (FAILED(hr
= IWMReader_GetOutputCount(filter
->reader
, &stream_count
)))
787 ERR("Failed to get WMReader output count, hr %#lx.\n", hr
);
790 if (stream_count
> ARRAY_SIZE(filter
->streams
))
792 FIXME("Found %lu streams, not supported!\n", stream_count
);
793 stream_count
= ARRAY_SIZE(filter
->streams
);
796 if (FAILED(hr
= IWMReader_QueryInterface(filter
->reader
, &IID_IWMHeaderInfo
,
797 (void **)&header_info
)))
801 WMT_ATTR_DATATYPE type
= WMT_TYPE_QWORD
;
802 WORD index
= 0, size
= sizeof(duration
);
804 if (FAILED(IWMHeaderInfo_GetAttributeByName(header_info
, &index
, L
"Duration",
805 &type
, (BYTE
*)&duration
, &size
)))
807 IWMHeaderInfo_Release(header_info
);
810 for (i
= 0; i
< stream_count
; ++i
)
812 struct asf_stream
*stream
= filter
->streams
+ i
;
814 if (FAILED(hr
= asf_stream_get_media_type(&stream
->source
.pin
, 0, &stream_media_type
)))
815 WARN("Failed to get stream media type, hr %#lx.\n", hr
);
816 if (IsEqualGUID(&stream_media_type
.majortype
, &MEDIATYPE_Video
))
817 swprintf(name
, ARRAY_SIZE(name
), L
"Raw Video %u", stream
->index
);
819 swprintf(name
, ARRAY_SIZE(name
), L
"Raw Audio %u", stream
->index
);
820 FreeMediaType(&stream_media_type
);
822 strmbase_source_init(&stream
->source
, &filter
->filter
, name
, &source_ops
);
823 strmbase_seeking_init(&stream
->seek
, &media_seeking_vtbl
, media_seeking_ChangeStop
,
824 media_seeking_ChangeCurrent
, media_seeking_ChangeRate
);
825 stream
->seek
.llCurrent
= 0;
826 stream
->seek
.llDuration
= duration
;
827 stream
->seek
.llStop
= duration
;
829 filter
->stream_count
= stream_count
;
830 BaseFilterImpl_IncrementPinVersion(&filter
->filter
);
832 EnterCriticalSection(&filter
->status_cs
);
833 filter
->result
= result
;
834 filter
->status
= WMT_OPENED
;
835 LeaveCriticalSection(&filter
->status_cs
);
836 WakeConditionVariable(&filter
->status_cv
);
839 case WMT_END_OF_STREAMING
:
840 for (i
= 0; i
< filter
->stream_count
; ++i
)
842 struct asf_stream
*stream
= filter
->streams
+ i
;
844 if (!stream
->source
.pin
.peer
)
847 IPin_EndOfStream(stream
->source
.pin
.peer
);
852 EnterCriticalSection(&filter
->status_cs
);
853 filter
->result
= result
;
854 filter
->status
= WMT_STARTED
;
855 LeaveCriticalSection(&filter
->status_cs
);
856 WakeConditionVariable(&filter
->status_cv
);
860 EnterCriticalSection(&filter
->status_cs
);
861 filter
->result
= result
;
862 filter
->status
= WMT_STOPPED
;
863 LeaveCriticalSection(&filter
->status_cs
);
864 WakeConditionVariable(&filter
->status_cv
);
868 WARN("Ignoring status %#x.\n", status
);
875 static HRESULT WINAPI
reader_callback_OnSample(IWMReaderCallback
*iface
, DWORD output
, QWORD time
,
876 QWORD duration
, DWORD flags
, INSSBuffer
*sample
, void *context
)
878 struct asf_reader
*filter
= impl_from_IWMReaderCallback(iface
)->filter
;
879 REFERENCE_TIME start_time
= time
, end_time
= time
+ duration
;
880 struct asf_stream
*stream
= filter
->streams
+ output
;
881 struct buffer
*buffer
;
884 TRACE("iface %p, output %lu, time %I64u, duration %I64u, flags %#lx, sample %p, context %p.\n",
885 iface
, output
, time
, duration
, flags
, sample
, context
);
887 if (!stream
->source
.pin
.peer
)
889 WARN("Output %lu pin is not connected, discarding %p.\n", output
, sample
);
893 if (!(buffer
= unsafe_impl_from_INSSBuffer(sample
)))
894 WARN("Unexpected buffer iface %p, discarding.\n", sample
);
897 IMediaSample_SetTime(buffer
->sample
, &start_time
, &end_time
);
898 IMediaSample_SetDiscontinuity(buffer
->sample
, !!(flags
& WM_SF_DISCONTINUITY
));
899 IMediaSample_SetSyncPoint(buffer
->sample
, !!(flags
& WM_SF_CLEANPOINT
));
901 hr
= IMemInputPin_Receive(stream
->source
.pMemInputPin
, buffer
->sample
);
903 TRACE("Receive returned hr %#lx.\n", hr
);
909 static const IWMReaderCallbackVtbl reader_callback_vtbl
=
911 reader_callback_QueryInterface
,
912 reader_callback_AddRef
,
913 reader_callback_Release
,
914 reader_callback_OnStatus
,
915 reader_callback_OnSample
,
918 static inline struct asf_callback
*impl_from_IWMReaderCallbackAdvanced(IWMReaderCallbackAdvanced
*iface
)
920 return CONTAINING_RECORD(iface
, struct asf_callback
, IWMReaderCallbackAdvanced_iface
);
923 static HRESULT WINAPI
reader_callback_advanced_QueryInterface(IWMReaderCallbackAdvanced
*iface
, REFIID riid
, LPVOID
* ppv
)
925 struct asf_callback
*impl
= impl_from_IWMReaderCallbackAdvanced(iface
);
926 return IUnknown_QueryInterface(&impl
->IWMReaderCallback_iface
, riid
, ppv
);
929 static ULONG WINAPI
reader_callback_advanced_AddRef(IWMReaderCallbackAdvanced
*iface
)
931 struct asf_callback
*impl
= impl_from_IWMReaderCallbackAdvanced(iface
);
932 return IUnknown_AddRef(&impl
->IWMReaderCallback_iface
);
935 static ULONG WINAPI
reader_callback_advanced_Release(IWMReaderCallbackAdvanced
*iface
)
937 struct asf_callback
*impl
= impl_from_IWMReaderCallbackAdvanced(iface
);
938 return IUnknown_Release(&impl
->IWMReaderCallback_iface
);
941 static HRESULT WINAPI
reader_callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced
*iface
,
942 WORD stream
, QWORD time
, QWORD duration
, DWORD flags
, INSSBuffer
*sample
, void *context
)
944 FIXME("iface %p, stream %u, time %I64u, duration %I64u, flags %#lx, sample %p, context %p stub!\n",
945 iface
, stream
, time
, duration
, flags
, sample
, context
);
949 static HRESULT WINAPI
reader_callback_advanced_OnTime(IWMReaderCallbackAdvanced
*iface
,
950 QWORD time
, void *context
)
952 FIXME("iface %p stub!\n", iface
);
956 static HRESULT WINAPI
reader_callback_advanced_OnStreamSelection(IWMReaderCallbackAdvanced
*iface
,
957 WORD count
, WORD
*stream_numbers
, WMT_STREAM_SELECTION
*selections
, void *context
)
959 FIXME("iface %p stub!\n", iface
);
963 static HRESULT WINAPI
reader_callback_advanced_OnOutputPropsChanged(IWMReaderCallbackAdvanced
*iface
,
964 DWORD output
, WM_MEDIA_TYPE
*mt
, void *context
)
966 FIXME("iface %p stub!\n", iface
);
970 static HRESULT WINAPI
reader_callback_advanced_AllocateForStream(IWMReaderCallbackAdvanced
*iface
,
971 WORD stream
, DWORD size
, INSSBuffer
**out
, void *context
)
973 FIXME("iface %p stub!\n", iface
);
977 static HRESULT WINAPI
reader_callback_advanced_AllocateForOutput(IWMReaderCallbackAdvanced
*iface
,
978 DWORD output
, DWORD size
, INSSBuffer
**out
, void *context
)
980 struct asf_reader
*filter
= impl_from_IWMReaderCallbackAdvanced(iface
)->filter
;
981 struct asf_stream
*stream
= filter
->streams
+ output
;
982 IMediaSample
*sample
;
985 TRACE("iface %p, output %lu, size %lu, out %p, context %p.\n", iface
, output
, size
, out
, context
);
989 if (!stream
->source
.pin
.peer
)
990 return VFW_E_NOT_CONNECTED
;
992 if (FAILED(hr
= IMemAllocator_GetBuffer(stream
->source
.pAllocator
, &sample
, NULL
, NULL
, 0)))
994 WARN("Failed to get a sample, hr %#lx.\n", hr
);
998 if (size
> IMediaSample_GetSize(sample
))
1000 WARN("Allocated media sample is too small, size %lu.\n", size
);
1001 IMediaSample_Release(sample
);
1002 return VFW_E_BUFFER_OVERFLOW
;
1005 return buffer_create(sample
, out
);
1008 static const IWMReaderCallbackAdvancedVtbl reader_callback_advanced_vtbl
=
1010 reader_callback_advanced_QueryInterface
,
1011 reader_callback_advanced_AddRef
,
1012 reader_callback_advanced_Release
,
1013 reader_callback_advanced_OnStreamSample
,
1014 reader_callback_advanced_OnTime
,
1015 reader_callback_advanced_OnStreamSelection
,
1016 reader_callback_advanced_OnOutputPropsChanged
,
1017 reader_callback_advanced_AllocateForStream
,
1018 reader_callback_advanced_AllocateForOutput
,
1021 static HRESULT
asf_callback_create(struct asf_reader
*filter
, IWMReaderCallback
**out
)
1023 struct asf_callback
*callback
;
1025 if (!(callback
= calloc(1, sizeof(*callback
))))
1026 return E_OUTOFMEMORY
;
1028 callback
->IWMReaderCallback_iface
.lpVtbl
= &reader_callback_vtbl
;
1029 callback
->IWMReaderCallbackAdvanced_iface
.lpVtbl
= &reader_callback_advanced_vtbl
;
1030 callback
->filter
= filter
;
1033 *out
= &callback
->IWMReaderCallback_iface
;
1037 HRESULT
asf_reader_create(IUnknown
*outer
, IUnknown
**out
)
1039 struct asf_reader
*object
;
1043 if (!(object
= calloc(1, sizeof(*object
))))
1044 return E_OUTOFMEMORY
;
1046 if (FAILED(hr
= WMCreateReader(NULL
, 0, &object
->reader
)))
1051 if (FAILED(hr
= asf_callback_create(object
, &object
->callback
)))
1053 IWMReader_Release(object
->reader
);
1058 for (i
= 0; i
< ARRAY_SIZE(object
->streams
); ++i
) object
->streams
[i
].index
= i
;
1059 strmbase_filter_init(&object
->filter
, outer
, &CLSID_WMAsfReader
, &filter_ops
);
1060 object
->IFileSourceFilter_iface
.lpVtbl
= &file_source_vtbl
;
1062 InitializeCriticalSection(&object
->status_cs
);
1063 object
->status_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": status_cs");
1065 TRACE("Created WM ASF reader %p.\n", object
);
1066 *out
= &object
->filter
.IUnknown_inner
;