ntdll: Connect syscall frames across user callbacks on x86-64.
[wine.git] / dlls / qasf / asfreader.c
blob4cf077e9dd3d171e551669d990056adc2089e374
1 /*
2 * WM ASF reader
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"
23 #include "mediaobj.h"
24 #include "propsys.h"
25 #include "initguid.h"
26 #include "wmsdkidl.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);
39 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;
46 rev[j] = 0;
48 return wine_dbg_sprintf("%s", rev);
51 struct buffer
53 INSSBuffer INSSBuffer_iface;
54 LONG refcount;
55 IMediaSample *sample;
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;
72 else
74 *out = NULL;
75 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
76 return E_NOINTERFACE;
79 IUnknown_AddRef((IUnknown *)*out);
80 return S_OK;
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);
88 return 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);
98 if (!ref)
100 IMediaSample_Release(impl->sample);
101 free(impl);
104 return ref;
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);
112 return S_OK;
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);
127 return S_OK;
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,
148 buffer_AddRef,
149 buffer_Release,
150 buffer_GetLength,
151 buffer_SetLength,
152 buffer_GetMaxLength,
153 buffer_GetBuffer,
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);
171 return S_OK;
174 static struct buffer *unsafe_impl_from_INSSBuffer(INSSBuffer *iface)
176 if (iface->lpVtbl != &buffer_vtbl) return NULL;
177 return impl_from_INSSBuffer(iface);
180 struct asf_stream
182 struct strmbase_source source;
183 struct SourceSeeking seek;
184 DWORD index;
187 struct asf_reader
189 struct strmbase_filter filter;
190 IFileSourceFilter IFileSourceFilter_iface;
192 WCHAR *file_name;
194 HRESULT result;
195 WMT_STATUS status;
196 CRITICAL_SECTION status_cs;
197 CONDITION_VARIABLE status_cv;
199 IWMReaderCallback *callback;
200 IWMReader *reader;
202 UINT stream_count;
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;
221 WM_MEDIA_TYPE *mt;
222 DWORD size, i = 0;
223 HRESULT hr;
225 TRACE("iface %p, media_type %p.\n", iface, media_type);
227 if (FAILED(hr = IWMReader_GetOutputFormat(filter->reader, stream->index, i, &props)))
228 return hr;
229 if (FAILED(hr = IWMOutputMediaProps_GetMediaType(props, NULL, &size)))
231 IWMOutputMediaProps_Release(props);
232 return hr;
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);
247 break;
250 IWMOutputMediaProps_Release(props);
251 } while (SUCCEEDED(hr = IWMReader_GetOutputFormat(filter->reader, stream->index, ++i, &props)));
253 free(mt);
254 return hr;
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;
262 WM_MEDIA_TYPE *mt;
263 DWORD size;
264 HRESULT hr;
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);
273 return hr;
275 if (!(mt = malloc(size)))
277 IWMOutputMediaProps_Release(props);
278 return E_OUTOFMEMORY;
281 hr = IWMOutputMediaProps_GetMediaType(props, mt, &size);
282 if (SUCCEEDED(hr))
283 hr = CopyMediaType(media_type, (AM_MEDIA_TYPE *)mt);
285 free(mt);
286 IWMOutputMediaProps_Release(props);
287 return hr;
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;
296 else
297 return E_NOINTERFACE;
299 IUnknown_AddRef((IUnknown *)*out);
300 return S_OK;
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);
311 return S_OK;
314 static HRESULT WINAPI media_seeking_ChangeStop(IMediaSeeking *iface)
316 FIXME("iface %p stub!\n", iface);
317 return S_OK;
320 static HRESULT WINAPI media_seeking_ChangeRate(IMediaSeeking *iface)
322 FIXME("iface %p stub!\n", iface);
323 return S_OK;
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);
394 return pin;
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);
419 free(filter);
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);
430 return S_OK;
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;
442 HRESULT hr = S_OK;
443 int i;
445 TRACE("iface %p\n", iface);
447 if (FAILED(hr = IWMReader_QueryInterface(filter->reader, &IID_IWMReaderAdvanced, (void **)&reader_advanced)))
448 return hr;
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)
459 continue;
461 if (FAILED(hr = IMemAllocator_Commit(stream->source.pAllocator)))
463 WARN("Failed to commit stream %u allocator, hr %#lx\n", i, hr);
464 break;
467 if (FAILED(hr = IWMReaderAdvanced_SetAllocateForOutput(reader_advanced, i, TRUE)))
469 WARN("Failed to enable allocation for stream %u, hr %#lx\n", i, hr);
470 break;
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);
476 break;
479 hr = IWMOutputMediaProps_SetMediaType(props, (WM_MEDIA_TYPE *)&stream->source.pin.mt);
480 if (SUCCEEDED(hr))
481 hr = IWMReader_SetOutputProps(filter->reader, stream->index, props);
482 IWMOutputMediaProps_Release(props);
483 if (FAILED(hr))
485 WARN("Failed to set stream %u output format, hr %#lx\n", i, hr);
486 break;
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);
492 break;
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);
504 if (FAILED(hr))
505 return hr;
507 EnterCriticalSection(&filter->status_cs);
508 if (SUCCEEDED(hr = IWMReader_Start(filter->reader, 0, 0, 1, NULL)))
510 filter->status = -1;
511 while (filter->status != WMT_STARTED)
512 SleepConditionVariableCS(&filter->status_cv, &filter->status_cs, INFINITE);
513 hr = filter->result;
515 LeaveCriticalSection(&filter->status_cs);
517 if (FAILED(hr))
518 WARN("Failed to start WMReader %p, hr %#lx\n", filter->reader, hr);
520 return hr;
523 static HRESULT asf_reader_cleanup_stream(struct strmbase_filter *iface)
525 struct asf_reader *filter = impl_from_strmbase_filter(iface);
526 HRESULT hr = S_OK;
527 int i;
529 TRACE("iface %p\n", iface);
531 EnterCriticalSection(&filter->status_cs);
532 if (SUCCEEDED(hr = IWMReader_Stop(filter->reader)))
534 filter->status = -1;
535 while (filter->status != WMT_STOPPED)
536 SleepConditionVariableCS(&filter->status_cv, &filter->status_cs, INFINITE);
537 hr = filter->result;
539 LeaveCriticalSection(&filter->status_cs);
541 if (FAILED(hr))
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)
549 continue;
551 if (FAILED(hr = IMemAllocator_Decommit(stream->source.pAllocator)))
553 WARN("Failed to decommit stream %u allocator, hr %#lx\n", i, hr);
554 break;
558 return 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);
637 HRESULT hr;
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);
642 if (!file_name)
643 return E_POINTER;
645 EnterCriticalSection(&filter->filter.filter_cs);
647 if (filter->file_name || !(filter->file_name = wcsdup(file_name)))
649 LeaveCriticalSection(&filter->filter.filter_cs);
650 return E_FAIL;
653 EnterCriticalSection(&filter->status_cs);
654 if (SUCCEEDED(hr = IWMReader_Open(filter->reader, filter->file_name, filter->callback, NULL)))
656 filter->status = -1;
657 while (filter->status != WMT_OPENED)
658 SleepConditionVariableCS(&filter->status_cv, &filter->status_cs, INFINITE);
659 hr = filter->result;
661 LeaveCriticalSection(&filter->status_cs);
663 if (FAILED(hr))
664 WARN("Failed to open WM reader, hr %#lx.\n", hr);
666 LeaveCriticalSection(&filter->filter.filter_cs);
668 return S_OK;
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);
677 if (!file_name)
678 return E_POINTER;
679 *file_name = NULL;
681 if (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);
696 return S_OK;
699 static const IFileSourceFilterVtbl file_source_vtbl =
701 file_source_QueryInterface,
702 file_source_AddRef,
703 file_source_Release,
704 file_source_Load,
705 file_source_GetCurFile,
708 struct asf_callback
710 IWMReaderCallback IWMReaderCallback_iface;
711 IWMReaderCallbackAdvanced IWMReaderCallbackAdvanced_iface;
712 LONG ref;
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;
734 else
736 *out = NULL;
737 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
738 return E_NOINTERFACE;
741 IUnknown_AddRef((IUnknown *)*out);
742 return S_OK;
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);
752 return 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);
762 if (!ref)
763 free(callback);
765 return 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];
776 QWORD duration;
777 HRESULT hr;
779 TRACE("iface %p, status %d, result %#lx, type %d, value %p, context %p.\n",
780 iface, status, result, type, value, context);
782 switch (status)
784 case WMT_OPENED:
785 if (FAILED(hr = IWMReader_GetOutputCount(filter->reader, &stream_count)))
787 ERR("Failed to get WMReader output count, hr %#lx.\n", hr);
788 stream_count = 0;
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)))
798 duration = 0;
799 else
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 )))
806 duration = 0;
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);
818 else
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);
837 break;
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)
845 continue;
847 IPin_EndOfStream(stream->source.pin.peer);
849 break;
851 case WMT_STARTED:
852 EnterCriticalSection(&filter->status_cs);
853 filter->result = result;
854 filter->status = WMT_STARTED;
855 LeaveCriticalSection(&filter->status_cs);
856 WakeConditionVariable(&filter->status_cv);
857 break;
859 case WMT_STOPPED:
860 EnterCriticalSection(&filter->status_cs);
861 filter->result = result;
862 filter->status = WMT_STOPPED;
863 LeaveCriticalSection(&filter->status_cs);
864 WakeConditionVariable(&filter->status_cv);
865 break;
867 default:
868 WARN("Ignoring status %#x.\n", status);
869 break;
872 return S_OK;
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;
882 HRESULT hr = S_OK;
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);
890 return S_OK;
893 if (!(buffer = unsafe_impl_from_INSSBuffer(sample)))
894 WARN("Unexpected buffer iface %p, discarding.\n", sample);
895 else
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);
906 return 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);
946 return E_NOTIMPL;
949 static HRESULT WINAPI reader_callback_advanced_OnTime(IWMReaderCallbackAdvanced *iface,
950 QWORD time, void *context)
952 FIXME("iface %p stub!\n", iface);
953 return E_NOTIMPL;
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);
960 return E_NOTIMPL;
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);
967 return E_NOTIMPL;
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);
974 return E_NOTIMPL;
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;
983 HRESULT hr;
985 TRACE("iface %p, output %lu, size %lu, out %p, context %p.\n", iface, output, size, out, context);
987 *out = NULL;
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);
995 return 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;
1031 callback->ref = 1;
1033 *out = &callback->IWMReaderCallback_iface;
1034 return S_OK;
1037 HRESULT asf_reader_create(IUnknown *outer, IUnknown **out)
1039 struct asf_reader *object;
1040 HRESULT hr;
1041 int i;
1043 if (!(object = calloc(1, sizeof(*object))))
1044 return E_OUTOFMEMORY;
1046 if (FAILED(hr = WMCreateReader(NULL, 0, &object->reader)))
1048 free(object);
1049 return hr;
1051 if (FAILED(hr = asf_callback_create(object, &object->callback)))
1053 IWMReader_Release(object->reader);
1054 free(object);
1055 return hr;
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;
1068 return S_OK;