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
);
32 struct strmbase_source source
;
38 struct strmbase_filter filter
;
39 IFileSourceFilter IFileSourceFilter_iface
;
41 AM_MEDIA_TYPE media_type
;
46 CRITICAL_SECTION status_cs
;
47 CONDITION_VARIABLE status_cv
;
49 IWMReaderCallback
*callback
;
53 struct asf_stream streams
[16];
56 static inline struct asf_stream
*impl_from_strmbase_pin(struct strmbase_pin
*iface
)
58 return CONTAINING_RECORD(iface
, struct asf_stream
, source
.pin
);
61 static inline struct asf_reader
*asf_reader_from_asf_stream(struct asf_stream
*stream
)
63 return CONTAINING_RECORD(stream
, struct asf_reader
, streams
[stream
->index
]);
66 static HRESULT
asf_stream_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*media_type
)
68 struct asf_stream
*stream
= impl_from_strmbase_pin(iface
);
69 struct asf_reader
*filter
= asf_reader_from_asf_stream(stream
);
70 IWMOutputMediaProps
*props
;
75 TRACE("iface %p, media_type %p.\n", iface
, media_type
);
77 if (FAILED(hr
= IWMReader_GetOutputFormat(filter
->reader
, stream
->index
, i
, &props
)))
79 if (FAILED(hr
= IWMOutputMediaProps_GetMediaType(props
, NULL
, &size
)))
81 IWMOutputMediaProps_Release(props
);
84 if (!(mt
= malloc(size
)))
86 IWMOutputMediaProps_Release(props
);
92 if (SUCCEEDED(hr
= IWMOutputMediaProps_GetMediaType(props
, mt
, &size
))
93 && IsEqualGUID(&mt
->majortype
, &media_type
->majortype
)
94 && IsEqualGUID(&mt
->subtype
, &media_type
->subtype
))
96 IWMOutputMediaProps_Release(props
);
100 IWMOutputMediaProps_Release(props
);
101 } while (SUCCEEDED(hr
= IWMReader_GetOutputFormat(filter
->reader
, stream
->index
, ++i
, &props
)));
107 static HRESULT
asf_stream_get_media_type(struct strmbase_pin
*iface
, unsigned int index
, AM_MEDIA_TYPE
*media_type
)
109 struct asf_stream
*stream
= impl_from_strmbase_pin(iface
);
110 struct asf_reader
*filter
= asf_reader_from_asf_stream(stream
);
111 IWMOutputMediaProps
*props
;
116 TRACE("iface %p, index %u, media_type %p.\n", iface
, index
, media_type
);
118 if (FAILED(IWMReader_GetOutputFormat(filter
->reader
, stream
->index
, index
, &props
)))
119 return VFW_S_NO_MORE_ITEMS
;
120 if (FAILED(hr
= IWMOutputMediaProps_GetMediaType(props
, NULL
, &size
)))
122 IWMOutputMediaProps_Release(props
);
125 if (!(mt
= malloc(size
)))
127 IWMOutputMediaProps_Release(props
);
128 return E_OUTOFMEMORY
;
131 hr
= IWMOutputMediaProps_GetMediaType(props
, mt
, &size
);
133 hr
= CopyMediaType(media_type
, (AM_MEDIA_TYPE
*)mt
);
136 IWMOutputMediaProps_Release(props
);
140 static inline struct asf_reader
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
142 return CONTAINING_RECORD(iface
, struct asf_reader
, filter
);
145 static struct strmbase_pin
*asf_reader_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
147 struct asf_reader
*filter
= impl_from_strmbase_filter(iface
);
148 struct strmbase_pin
*pin
= NULL
;
150 TRACE("iface %p, index %u.\n", iface
, index
);
152 EnterCriticalSection(&filter
->filter
.filter_cs
);
153 if (index
< filter
->stream_count
)
154 pin
= &filter
->streams
[index
].source
.pin
;
155 LeaveCriticalSection(&filter
->filter
.filter_cs
);
160 static void asf_reader_destroy(struct strmbase_filter
*iface
)
162 struct asf_reader
*filter
= impl_from_strmbase_filter(iface
);
163 struct strmbase_source
*source
;
165 while (filter
->stream_count
--)
167 source
= &filter
->streams
[filter
->stream_count
].source
;
168 if (source
->pin
.peer
) IPin_Disconnect(source
->pin
.peer
);
169 IPin_Disconnect(&source
->pin
.IPin_iface
);
170 strmbase_source_cleanup(source
);
173 free(filter
->file_name
);
174 FreeMediaType(&filter
->media_type
);
175 IWMReaderCallback_Release(filter
->callback
);
176 IWMReader_Release(filter
->reader
);
178 strmbase_filter_cleanup(&filter
->filter
);
180 filter
->status_cs
.DebugInfo
->Spare
[0] = 0;
181 DeleteCriticalSection(&filter
->status_cs
);
186 static HRESULT
asf_reader_query_interface(struct strmbase_filter
*iface
, REFIID iid
, void **out
)
188 struct asf_reader
*filter
= impl_from_strmbase_filter(iface
);
190 if (IsEqualGUID(iid
, &IID_IFileSourceFilter
))
192 *out
= &filter
->IFileSourceFilter_iface
;
193 IUnknown_AddRef((IUnknown
*)*out
);
197 return E_NOINTERFACE
;
200 static const struct strmbase_filter_ops filter_ops
=
202 .filter_get_pin
= asf_reader_get_pin
,
203 .filter_destroy
= asf_reader_destroy
,
204 .filter_query_interface
= asf_reader_query_interface
,
207 static HRESULT WINAPI
asf_reader_DecideBufferSize(struct strmbase_source
*iface
,
208 IMemAllocator
*allocator
, ALLOCATOR_PROPERTIES
*req_props
)
210 struct asf_stream
*stream
= impl_from_strmbase_pin(&iface
->pin
);
211 unsigned int buffer_size
= 16384;
212 ALLOCATOR_PROPERTIES ret_props
;
214 TRACE("iface %p, allocator %p, req_props %p.\n", iface
, allocator
, req_props
);
216 if (IsEqualGUID(&stream
->source
.pin
.mt
.formattype
, &FORMAT_VideoInfo
))
218 VIDEOINFOHEADER
*format
= (VIDEOINFOHEADER
*)stream
->source
.pin
.mt
.pbFormat
;
219 buffer_size
= format
->bmiHeader
.biSizeImage
;
221 else if (IsEqualGUID(&stream
->source
.pin
.mt
.formattype
, &FORMAT_WaveFormatEx
)
222 && (IsEqualGUID(&stream
->source
.pin
.mt
.subtype
, &MEDIASUBTYPE_PCM
)
223 || IsEqualGUID(&stream
->source
.pin
.mt
.subtype
, &MEDIASUBTYPE_IEEE_FLOAT
)))
225 WAVEFORMATEX
*format
= (WAVEFORMATEX
*)stream
->source
.pin
.mt
.pbFormat
;
226 buffer_size
= format
->nAvgBytesPerSec
;
229 req_props
->cBuffers
= max(req_props
->cBuffers
, 1);
230 req_props
->cbBuffer
= max(req_props
->cbBuffer
, buffer_size
);
231 req_props
->cbAlign
= max(req_props
->cbAlign
, 1);
232 return IMemAllocator_SetProperties(allocator
, req_props
, &ret_props
);
235 static const struct strmbase_source_ops source_ops
=
237 .base
.pin_query_accept
= asf_stream_query_accept
,
238 .base
.pin_get_media_type
= asf_stream_get_media_type
,
239 .pfnDecideAllocator
= BaseOutputPinImpl_DecideAllocator
,
240 .pfnAttemptConnection
= BaseOutputPinImpl_AttemptConnection
,
241 .pfnDecideBufferSize
= asf_reader_DecideBufferSize
,
244 static inline struct asf_reader
*impl_from_IFileSourceFilter(IFileSourceFilter
*iface
)
246 return CONTAINING_RECORD(iface
, struct asf_reader
, IFileSourceFilter_iface
);
249 static HRESULT WINAPI
file_source_QueryInterface(IFileSourceFilter
*iface
, REFIID iid
, void **out
)
251 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
253 return IBaseFilter_QueryInterface(&filter
->filter
.IBaseFilter_iface
, iid
, out
);
256 static ULONG WINAPI
file_source_AddRef(IFileSourceFilter
*iface
)
258 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
260 return IBaseFilter_AddRef(&filter
->filter
.IBaseFilter_iface
);
263 static ULONG WINAPI
file_source_Release(IFileSourceFilter
*iface
)
265 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
267 return IBaseFilter_Release(&filter
->filter
.IBaseFilter_iface
);
270 static HRESULT WINAPI
file_source_Load(IFileSourceFilter
*iface
, LPCOLESTR file_name
, const AM_MEDIA_TYPE
*media_type
)
272 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
275 TRACE("filter %p, file_name %s, media_type %p.\n", filter
, debugstr_w(file_name
), media_type
);
276 strmbase_dump_media_type(media_type
);
281 EnterCriticalSection(&filter
->filter
.filter_cs
);
283 if (filter
->file_name
|| !(filter
->file_name
= wcsdup(file_name
)))
285 LeaveCriticalSection(&filter
->filter
.filter_cs
);
289 if (media_type
&& FAILED(hr
= CopyMediaType(&filter
->media_type
, media_type
)))
291 LeaveCriticalSection(&filter
->filter
.filter_cs
);
295 EnterCriticalSection(&filter
->status_cs
);
296 if (SUCCEEDED(hr
= IWMReader_Open(filter
->reader
, filter
->file_name
, filter
->callback
, NULL
)))
299 while (filter
->status
!= WMT_OPENED
)
300 SleepConditionVariableCS(&filter
->status_cv
, &filter
->status_cs
, INFINITE
);
303 LeaveCriticalSection(&filter
->status_cs
);
306 WARN("Failed to open WM reader, hr %#lx.\n", hr
);
308 LeaveCriticalSection(&filter
->filter
.filter_cs
);
313 static HRESULT WINAPI
file_source_GetCurFile(IFileSourceFilter
*iface
, LPOLESTR
*file_name
, AM_MEDIA_TYPE
*media_type
)
315 struct asf_reader
*filter
= impl_from_IFileSourceFilter(iface
);
317 TRACE("filter %p, file_name %p, media_type %p.\n", filter
, file_name
, media_type
);
325 media_type
->majortype
= filter
->media_type
.majortype
;
326 media_type
->subtype
= filter
->media_type
.subtype
;
327 media_type
->lSampleSize
= filter
->media_type
.lSampleSize
;
328 media_type
->pUnk
= filter
->media_type
.pUnk
;
329 media_type
->cbFormat
= filter
->media_type
.cbFormat
;
332 if (filter
->file_name
)
334 *file_name
= CoTaskMemAlloc((wcslen(filter
->file_name
) + 1) * sizeof(WCHAR
));
335 wcscpy(*file_name
, filter
->file_name
);
341 static const IFileSourceFilterVtbl file_source_vtbl
=
343 file_source_QueryInterface
,
347 file_source_GetCurFile
,
352 IWMReaderCallback IWMReaderCallback_iface
;
355 struct asf_reader
*filter
;
358 static inline struct asf_callback
*impl_from_IWMReaderCallback(IWMReaderCallback
*iface
)
360 return CONTAINING_RECORD(iface
, struct asf_callback
, IWMReaderCallback_iface
);
363 static HRESULT WINAPI
reader_callback_QueryInterface(IWMReaderCallback
*iface
, const IID
*iid
, void **out
)
365 struct asf_callback
*callback
= impl_from_IWMReaderCallback(iface
);
367 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
369 if (IsEqualGUID(iid
, &IID_IUnknown
)
370 || IsEqualGUID(iid
, &IID_IWMStatusCallback
)
371 || IsEqualGUID(iid
, &IID_IWMReaderCallback
))
372 *out
= &callback
->IWMReaderCallback_iface
;
376 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
377 return E_NOINTERFACE
;
380 IUnknown_AddRef((IUnknown
*)*out
);
384 static ULONG WINAPI
reader_callback_AddRef(IWMReaderCallback
*iface
)
386 struct asf_callback
*callback
= impl_from_IWMReaderCallback(iface
);
387 ULONG ref
= InterlockedIncrement(&callback
->ref
);
389 TRACE("%p increasing ref to %lu.\n", callback
, ref
);
394 static ULONG WINAPI
reader_callback_Release(IWMReaderCallback
*iface
)
396 struct asf_callback
*callback
= impl_from_IWMReaderCallback(iface
);
397 ULONG ref
= InterlockedDecrement(&callback
->ref
);
399 TRACE("%p decreasing ref to %lu.\n", callback
, ref
);
407 static HRESULT WINAPI
reader_callback_OnStatus(IWMReaderCallback
*iface
, WMT_STATUS status
, HRESULT result
,
408 WMT_ATTR_DATATYPE type
, BYTE
*value
, void *context
)
410 struct asf_reader
*filter
= impl_from_IWMReaderCallback(iface
)->filter
;
411 AM_MEDIA_TYPE stream_media_type
= {{0}};
412 DWORD i
, stream_count
;
413 WCHAR name
[MAX_PATH
];
416 TRACE("iface %p, status %d, result %#lx, type %d, value %p, context %p.\n",
417 iface
, status
, result
, type
, value
, context
);
422 if (FAILED(hr
= IWMReader_GetOutputCount(filter
->reader
, &stream_count
)))
424 ERR("Failed to get WMReader output count, hr %#lx.\n", hr
);
427 if (stream_count
> ARRAY_SIZE(filter
->streams
))
429 FIXME("Found %lu streams, not supported!\n", stream_count
);
430 stream_count
= ARRAY_SIZE(filter
->streams
);
433 for (i
= 0; i
< stream_count
; ++i
)
435 struct asf_stream
*stream
= filter
->streams
+ i
;
437 if (FAILED(hr
= asf_stream_get_media_type(&stream
->source
.pin
, 0, &stream_media_type
)))
438 WARN("Failed to get stream media type, hr %#lx.\n", hr
);
439 if (IsEqualGUID(&stream_media_type
.majortype
, &MEDIATYPE_Video
))
440 swprintf(name
, ARRAY_SIZE(name
), L
"Raw Video %u", stream
->index
);
442 swprintf(name
, ARRAY_SIZE(name
), L
"Raw Audio %u", stream
->index
);
443 FreeMediaType(&stream_media_type
);
445 strmbase_source_init(&stream
->source
, &filter
->filter
, name
, &source_ops
);
447 filter
->stream_count
= stream_count
;
448 BaseFilterImpl_IncrementPinVersion(&filter
->filter
);
450 EnterCriticalSection(&filter
->status_cs
);
451 filter
->result
= result
;
452 filter
->status
= WMT_OPENED
;
453 LeaveCriticalSection(&filter
->status_cs
);
454 WakeConditionVariable(&filter
->status_cv
);
458 WARN("Ignoring status %#x.\n", status
);
465 static HRESULT WINAPI
reader_callback_OnSample(IWMReaderCallback
*iface
, DWORD output
, QWORD time
,
466 QWORD duration
, DWORD flags
, INSSBuffer
*sample
, void *context
)
468 FIXME("iface %p, output %lu, time %I64u, duration %I64u, flags %#lx, sample %p, context %p stub!\n",
469 iface
, output
, time
, duration
, flags
, sample
, context
);
473 static const IWMReaderCallbackVtbl reader_callback_vtbl
=
475 reader_callback_QueryInterface
,
476 reader_callback_AddRef
,
477 reader_callback_Release
,
478 reader_callback_OnStatus
,
479 reader_callback_OnSample
,
482 static HRESULT
asf_callback_create(struct asf_reader
*filter
, IWMReaderCallback
**out
)
484 struct asf_callback
*callback
;
486 if (!(callback
= calloc(1, sizeof(*callback
))))
487 return E_OUTOFMEMORY
;
489 callback
->IWMReaderCallback_iface
.lpVtbl
= &reader_callback_vtbl
;
490 callback
->filter
= filter
;
493 *out
= &callback
->IWMReaderCallback_iface
;
497 HRESULT
asf_reader_create(IUnknown
*outer
, IUnknown
**out
)
499 struct asf_reader
*object
;
503 if (!(object
= calloc(1, sizeof(*object
))))
504 return E_OUTOFMEMORY
;
506 if (FAILED(hr
= WMCreateReader(NULL
, 0, &object
->reader
)))
511 if (FAILED(hr
= asf_callback_create(object
, &object
->callback
)))
513 IWMReader_Release(object
->reader
);
518 for (i
= 0; i
< ARRAY_SIZE(object
->streams
); ++i
) object
->streams
[i
].index
= i
;
519 strmbase_filter_init(&object
->filter
, outer
, &CLSID_WMAsfReader
, &filter_ops
);
520 object
->IFileSourceFilter_iface
.lpVtbl
= &file_source_vtbl
;
522 InitializeCriticalSection(&object
->status_cs
);
523 object
->status_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": status_cs");
525 TRACE("Created WM ASF reader %p.\n", object
);
526 *out
= &object
->filter
.IUnknown_inner
;