ntdll: Translate signal to trap when trap code is 0 on ARM.
[wine.git] / dlls / mfreadwrite / main.c
blobfd9062f648a3618fcaa4f9a6aa030026316b5cb5
1 /*
3 * Copyright 2014 Austin English
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "ole2.h"
29 #include "rpcproxy.h"
31 #undef INITGUID
32 #include <guiddef.h>
33 #include "mfapi.h"
34 #include "mferror.h"
35 #include "mfidl.h"
36 #include "mfreadwrite.h"
38 #include "wine/debug.h"
39 #include "wine/heap.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
43 static HINSTANCE mfinstance;
45 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
47 switch (reason)
49 case DLL_WINE_PREATTACH:
50 return FALSE; /* prefer native version */
51 case DLL_PROCESS_ATTACH:
52 mfinstance = instance;
53 DisableThreadLibraryCalls(instance);
54 break;
57 return TRUE;
60 HRESULT WINAPI DllCanUnloadNow(void)
62 return S_FALSE;
65 HRESULT WINAPI DllRegisterServer(void)
67 return __wine_register_resources( mfinstance );
70 HRESULT WINAPI DllUnregisterServer(void)
72 return __wine_unregister_resources( mfinstance );
75 struct media_stream
77 IMFMediaStream *stream;
78 IMFMediaType *current;
79 DWORD id;
82 typedef struct source_reader
84 IMFSourceReader IMFSourceReader_iface;
85 IMFAsyncCallback source_events_callback;
86 IMFAsyncCallback stream_events_callback;
87 LONG refcount;
88 IMFMediaSource *source;
89 IMFPresentationDescriptor *descriptor;
90 DWORD first_audio_stream_index;
91 DWORD first_video_stream_index;
92 IMFSourceReaderCallback *async_callback;
93 BOOL shutdown_on_release;
94 struct media_stream *streams;
95 DWORD stream_count;
96 CRITICAL_SECTION cs;
97 } srcreader;
99 struct sink_writer
101 IMFSinkWriter IMFSinkWriter_iface;
102 LONG refcount;
105 static inline srcreader *impl_from_IMFSourceReader(IMFSourceReader *iface)
107 return CONTAINING_RECORD(iface, srcreader, IMFSourceReader_iface);
110 static struct source_reader *impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
112 return CONTAINING_RECORD(iface, struct source_reader, source_events_callback);
115 static struct source_reader *impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
117 return CONTAINING_RECORD(iface, struct source_reader, stream_events_callback);
120 static inline struct sink_writer *impl_from_IMFSinkWriter(IMFSinkWriter *iface)
122 return CONTAINING_RECORD(iface, struct sink_writer, IMFSinkWriter_iface);
125 static HRESULT WINAPI source_reader_source_events_callback_QueryInterface(IMFAsyncCallback *iface,
126 REFIID riid, void **obj)
128 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
130 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
131 IsEqualIID(riid, &IID_IUnknown))
133 *obj = iface;
134 IMFAsyncCallback_AddRef(iface);
135 return S_OK;
138 WARN("Unsupported %s.\n", debugstr_guid(riid));
139 *obj = NULL;
140 return E_NOINTERFACE;
143 static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface)
145 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
146 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
149 static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface)
151 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
152 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
155 static HRESULT WINAPI source_reader_source_events_callback_GetParameters(IMFAsyncCallback *iface,
156 DWORD *flags, DWORD *queue)
158 return E_NOTIMPL;
161 static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IMFMediaEvent *event)
163 IMFStreamDescriptor *sd;
164 IMFMediaStream *stream;
165 PROPVARIANT value;
166 unsigned int i;
167 DWORD id = 0;
168 HRESULT hr;
170 PropVariantInit(&value);
171 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
173 WARN("Failed to get event value, hr %#x.\n", hr);
174 return hr;
177 if (value.vt != VT_UNKNOWN || !value.u.punkVal)
179 WARN("Unexpected value type %d.\n", value.vt);
180 PropVariantClear(&value);
181 return E_UNEXPECTED;
184 hr = IUnknown_QueryInterface(value.u.punkVal, &IID_IMFMediaStream, (void **)&stream);
185 PropVariantClear(&value);
186 if (FAILED(hr))
188 WARN("Unexpected object type.\n");
189 return hr;
192 TRACE("Got new stream %p.\n", stream);
194 if (SUCCEEDED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
196 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &id);
197 IMFStreamDescriptor_Release(sd);
200 if (FAILED(hr))
202 WARN("Unidentified stream %p, hr %#x.\n", stream, hr);
203 IMFMediaStream_Release(stream);
204 return hr;
207 for (i = 0; i < reader->stream_count; ++i)
209 if (id == reader->streams[i].id)
211 if (!InterlockedCompareExchangePointer((void **)&reader->streams[i].stream, stream, NULL))
213 IMFMediaStream_AddRef(reader->streams[i].stream);
214 if (FAILED(hr = IMFMediaStream_BeginGetEvent(stream, &reader->stream_events_callback,
215 (IUnknown *)stream)))
217 WARN("Failed to subscribe to stream events, hr %#x.\n", hr);
220 break;
224 if (i == reader->stream_count)
225 WARN("Stream with id %#x was not present in presentation descriptor.\n", id);
227 IMFMediaStream_Release(stream);
229 return hr;
232 static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
234 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
235 MediaEventType event_type;
236 IMFMediaSource *source;
237 IMFMediaEvent *event;
238 HRESULT hr;
240 TRACE("%p, %p.\n", iface, result);
242 source = (IMFMediaSource *)IMFAsyncResult_GetStateNoAddRef(result);
244 if (FAILED(hr = IMFMediaSource_EndGetEvent(source, result, &event)))
245 return hr;
247 IMFMediaEvent_GetType(event, &event_type);
249 TRACE("Got event %u.\n", event_type);
251 switch (event_type)
253 case MENewStream:
254 hr = source_reader_new_stream_handler(reader, event);
255 break;
256 default:
260 if (FAILED(hr))
261 WARN("Failed while handling %d event, hr %#x.\n", event_type, hr);
263 IMFMediaEvent_Release(event);
265 IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
267 return S_OK;
270 static const IMFAsyncCallbackVtbl source_events_callback_vtbl =
272 source_reader_source_events_callback_QueryInterface,
273 source_reader_source_events_callback_AddRef,
274 source_reader_source_events_callback_Release,
275 source_reader_source_events_callback_GetParameters,
276 source_reader_source_events_callback_Invoke,
279 static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface)
281 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
282 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
285 static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface)
287 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
288 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
291 static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
293 MediaEventType event_type;
294 IMFMediaStream *stream;
295 IMFMediaEvent *event;
296 HRESULT hr;
298 TRACE("%p, %p.\n", iface, result);
300 stream = (IMFMediaStream *)IMFAsyncResult_GetStateNoAddRef(result);
302 if (FAILED(hr = IMFMediaStream_EndGetEvent(stream, result, &event)))
303 return hr;
305 IMFMediaEvent_GetType(event, &event_type);
307 TRACE("Got event %u.\n", event_type);
309 IMFMediaEvent_Release(event);
311 IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
313 return S_OK;
316 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl =
318 source_reader_source_events_callback_QueryInterface,
319 source_reader_stream_events_callback_AddRef,
320 source_reader_stream_events_callback_Release,
321 source_reader_source_events_callback_GetParameters,
322 source_reader_stream_events_callback_Invoke,
325 static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReader *iface, REFIID riid, void **out)
327 srcreader *This = impl_from_IMFSourceReader(iface);
329 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out);
331 if(IsEqualGUID(riid, &IID_IUnknown) ||
332 IsEqualGUID(riid, &IID_IMFSourceReader))
334 *out = &This->IMFSourceReader_iface;
336 else
338 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
339 *out = NULL;
340 return E_NOINTERFACE;
343 IUnknown_AddRef((IUnknown*)*out);
344 return S_OK;
347 static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface)
349 srcreader *This = impl_from_IMFSourceReader(iface);
350 ULONG ref = InterlockedIncrement(&This->refcount);
352 TRACE("(%p) ref=%u\n", This, ref);
354 return ref;
357 static ULONG WINAPI src_reader_Release(IMFSourceReader *iface)
359 struct source_reader *reader = impl_from_IMFSourceReader(iface);
360 ULONG refcount = InterlockedDecrement(&reader->refcount);
361 unsigned int i;
363 TRACE("%p, refcount %d.\n", iface, refcount);
365 if (!refcount)
367 if (reader->async_callback)
368 IMFSourceReaderCallback_Release(reader->async_callback);
369 if (reader->shutdown_on_release)
370 IMFMediaSource_Shutdown(reader->source);
371 if (reader->descriptor)
372 IMFPresentationDescriptor_Release(reader->descriptor);
373 IMFMediaSource_Release(reader->source);
375 for (i = 0; i < reader->stream_count; ++i)
377 if (reader->streams[i].stream)
378 IMFMediaStream_Release(reader->streams[i].stream);
379 if (reader->streams[i].current)
380 IMFMediaType_Release(reader->streams[i].current);
382 heap_free(reader->streams);
383 DeleteCriticalSection(&reader->cs);
384 heap_free(reader);
387 return refcount;
390 static HRESULT WINAPI src_reader_GetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL *selected)
392 struct source_reader *reader = impl_from_IMFSourceReader(iface);
393 IMFStreamDescriptor *sd;
395 TRACE("%p, %#x, %p.\n", iface, index, selected);
397 switch (index)
399 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
400 index = reader->first_video_stream_index;
401 break;
402 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
403 index = reader->first_audio_stream_index;
404 break;
405 default:
409 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, selected, &sd)))
410 return MF_E_INVALIDSTREAMNUMBER;
411 IMFStreamDescriptor_Release(sd);
413 return S_OK;
416 static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL selected)
418 struct source_reader *reader = impl_from_IMFSourceReader(iface);
419 unsigned int count;
420 HRESULT hr;
422 TRACE("%p, %#x, %d.\n", iface, index, selected);
424 switch (index)
426 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
427 index = reader->first_video_stream_index;
428 break;
429 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
430 index = reader->first_audio_stream_index;
431 break;
432 case MF_SOURCE_READER_ALL_STREAMS:
433 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(reader->descriptor, &count)))
434 return hr;
436 for (index = 0; index < count; ++index)
438 if (selected)
439 IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
440 else
441 IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
444 return S_OK;
445 default:
449 if (selected)
450 hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
451 else
452 hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
454 if (FAILED(hr))
455 return MF_E_INVALIDSTREAMNUMBER;
457 return S_OK;
460 static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReader *iface, DWORD index, DWORD type_index,
461 IMFMediaType **type)
463 struct source_reader *reader = impl_from_IMFSourceReader(iface);
464 IMFMediaTypeHandler *handler;
465 IMFStreamDescriptor *sd;
466 BOOL selected;
467 HRESULT hr;
469 TRACE("%p, %#x, %#x, %p.\n", iface, index, type_index, type);
471 switch (index)
473 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
474 index = reader->first_video_stream_index;
475 break;
476 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
477 index = reader->first_audio_stream_index;
478 break;
479 default:
483 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
484 return MF_E_INVALIDSTREAMNUMBER;
486 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
487 IMFStreamDescriptor_Release(sd);
488 if (FAILED(hr))
489 return hr;
491 if (type_index == MF_SOURCE_READER_CURRENT_TYPE_INDEX)
492 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, type);
493 else
494 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, type_index, type);
495 IMFMediaTypeHandler_Release(handler);
497 return hr;
500 static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReader *iface, DWORD index, IMFMediaType **type)
502 struct source_reader *reader = impl_from_IMFSourceReader(iface);
503 HRESULT hr;
505 TRACE("%p, %#x, %p.\n", iface, index, type);
507 switch (index)
509 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
510 index = reader->first_video_stream_index;
511 break;
512 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
513 index = reader->first_audio_stream_index;
514 break;
515 default:
519 if (index >= reader->stream_count)
520 return MF_E_INVALIDSTREAMNUMBER;
522 if (FAILED(hr = MFCreateMediaType(type)))
523 return hr;
525 EnterCriticalSection(&reader->cs);
527 hr = IMFMediaType_CopyAllItems(reader->streams[index].current, (IMFAttributes *)*type);
529 LeaveCriticalSection(&reader->cs);
531 return hr;
534 static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWORD index, DWORD *reserved,
535 IMFMediaType *type)
537 struct source_reader *reader = impl_from_IMFSourceReader(iface);
538 HRESULT hr;
540 TRACE("%p, %#x, %p, %p.\n", iface, index, reserved, type);
542 switch (index)
544 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
545 index = reader->first_video_stream_index;
546 break;
547 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
548 index = reader->first_audio_stream_index;
549 break;
550 default:
554 if (index >= reader->stream_count)
555 return MF_E_INVALIDSTREAMNUMBER;
557 /* FIXME: validate passed type and current presentation state. */
559 EnterCriticalSection(&reader->cs);
561 hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current);
563 LeaveCriticalSection(&reader->cs);
565 return hr;
568 static HRESULT WINAPI src_reader_SetCurrentPosition(IMFSourceReader *iface, REFGUID format, REFPROPVARIANT position)
570 struct source_reader *reader = impl_from_IMFSourceReader(iface);
571 DWORD flags;
572 HRESULT hr;
574 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), position);
576 /* FIXME: fail if we got pending samples. */
578 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
579 return hr;
581 if (!(flags & MFMEDIASOURCE_CAN_SEEK))
582 return MF_E_INVALIDREQUEST;
584 return IMFMediaSource_Start(reader->source, reader->descriptor, format, position);
587 static HRESULT WINAPI src_reader_ReadSample(IMFSourceReader *iface, DWORD index,
588 DWORD flags, DWORD *actualindex, DWORD *sampleflags, LONGLONG *timestamp,
589 IMFSample **sample)
591 srcreader *This = impl_from_IMFSourceReader(iface);
592 FIXME("%p, 0x%08x, 0x%08x, %p, %p, %p, %p\n", This, index, flags, actualindex,
593 sampleflags, timestamp, sample);
594 return E_NOTIMPL;
597 static HRESULT WINAPI src_reader_Flush(IMFSourceReader *iface, DWORD index)
599 srcreader *This = impl_from_IMFSourceReader(iface);
600 FIXME("%p, 0x%08x\n", This, index);
601 return E_NOTIMPL;
604 static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReader *iface, DWORD index, REFGUID service,
605 REFIID riid, void **object)
607 struct source_reader *reader = impl_from_IMFSourceReader(iface);
608 IUnknown *obj = NULL;
609 HRESULT hr;
611 TRACE("%p, %#x, %s, %s, %p\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object);
613 switch (index)
615 case MF_SOURCE_READER_MEDIASOURCE:
616 obj = (IUnknown *)reader->source;
617 break;
618 default:
619 FIXME("Unsupported index %#x.\n", index);
620 return E_NOTIMPL;
623 if (IsEqualGUID(service, &GUID_NULL))
625 hr = IUnknown_QueryInterface(obj, riid, object);
627 else
629 IMFGetService *gs;
631 hr = IUnknown_QueryInterface(obj, &IID_IMFGetService, (void **)&gs);
632 if (SUCCEEDED(hr))
634 hr = IMFGetService_GetService(gs, service, riid, object);
635 IMFGetService_Release(gs);
639 return hr;
642 static HRESULT WINAPI src_reader_GetPresentationAttribute(IMFSourceReader *iface, DWORD index,
643 REFGUID guid, PROPVARIANT *value)
645 struct source_reader *reader = impl_from_IMFSourceReader(iface);
646 IMFStreamDescriptor *sd;
647 BOOL selected;
648 HRESULT hr;
650 TRACE("%p, %#x, %s, %p.\n", iface, index, debugstr_guid(guid), value);
652 switch (index)
654 case MF_SOURCE_READER_MEDIASOURCE:
655 if (IsEqualGUID(guid, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS))
657 DWORD flags;
659 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
660 return hr;
662 value->vt = VT_UI4;
663 value->u.ulVal = flags;
664 return S_OK;
666 else
668 return IMFPresentationDescriptor_GetItem(reader->descriptor, guid, value);
670 break;
671 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
672 index = reader->first_video_stream_index;
673 break;
674 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
675 index = reader->first_audio_stream_index;
676 break;
677 default:
681 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
682 return hr;
684 hr = IMFStreamDescriptor_GetItem(sd, guid, value);
685 IMFStreamDescriptor_Release(sd);
687 return hr;
690 struct IMFSourceReaderVtbl srcreader_vtbl =
692 src_reader_QueryInterface,
693 src_reader_AddRef,
694 src_reader_Release,
695 src_reader_GetStreamSelection,
696 src_reader_SetStreamSelection,
697 src_reader_GetNativeMediaType,
698 src_reader_GetCurrentMediaType,
699 src_reader_SetCurrentMediaType,
700 src_reader_SetCurrentPosition,
701 src_reader_ReadSample,
702 src_reader_Flush,
703 src_reader_GetServiceForStream,
704 src_reader_GetPresentationAttribute
707 static DWORD reader_get_first_stream_index(IMFPresentationDescriptor *descriptor, const GUID *major)
709 unsigned int count, i;
710 BOOL selected;
711 HRESULT hr;
712 GUID guid;
714 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
715 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
717 for (i = 0; i < count; ++i)
719 IMFMediaTypeHandler *handler;
720 IMFStreamDescriptor *sd;
722 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, &selected, &sd)))
724 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
725 IMFStreamDescriptor_Release(sd);
726 if (SUCCEEDED(hr))
728 hr = IMFMediaTypeHandler_GetMajorType(handler, &guid);
729 IMFMediaTypeHandler_Release(handler);
730 if (SUCCEEDED(hr) && IsEqualGUID(&guid, major))
732 return i;
738 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
741 static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttributes *attributes,
742 BOOL shutdown_on_release, REFIID riid, void **out)
744 struct source_reader *object;
745 unsigned int i;
746 HRESULT hr;
748 object = heap_alloc_zero(sizeof(*object));
749 if (!object)
750 return E_OUTOFMEMORY;
752 object->IMFSourceReader_iface.lpVtbl = &srcreader_vtbl;
753 object->source_events_callback.lpVtbl = &source_events_callback_vtbl;
754 object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl;
755 object->refcount = 1;
756 object->source = source;
757 IMFMediaSource_AddRef(object->source);
758 InitializeCriticalSection(&object->cs);
760 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
761 goto failed;
763 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(object->descriptor, &object->stream_count)))
764 goto failed;
766 if (!(object->streams = heap_alloc_zero(object->stream_count * sizeof(*object->streams))))
768 hr = E_OUTOFMEMORY;
769 goto failed;
772 /* Set initial current media types. */
773 for (i = 0; i < object->stream_count; ++i)
775 IMFMediaTypeHandler *handler;
776 IMFStreamDescriptor *sd;
777 IMFMediaType *src_type;
778 BOOL selected;
780 if (FAILED(hr = MFCreateMediaType(&object->streams[i].current)))
781 break;
783 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(object->descriptor, i, &selected, &sd)))
784 break;
786 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &object->streams[i].id)))
787 WARN("Failed to get stream identifier, hr %#x.\n", hr);
789 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
790 IMFStreamDescriptor_Release(sd);
791 if (FAILED(hr))
792 break;
794 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &src_type);
795 IMFMediaTypeHandler_Release(handler);
796 if (FAILED(hr))
797 break;
799 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)object->streams[i].current);
800 IMFMediaType_Release(src_type);
801 if (FAILED(hr))
802 break;
805 if (FAILED(hr))
806 goto failed;
808 /* At least one major type has to be set. */
809 object->first_audio_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Audio);
810 object->first_video_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Video);
812 if (object->first_audio_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX &&
813 object->first_video_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX)
815 hr = MF_E_ATTRIBUTENOTFOUND;
818 if (FAILED(hr = IMFMediaSource_BeginGetEvent(object->source, &object->source_events_callback,
819 (IUnknown *)object->source)))
821 goto failed;
824 if (attributes)
826 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK, &IID_IMFSourceReaderCallback,
827 (void **)&object->async_callback);
828 if (object->async_callback)
829 TRACE("Using async callback %p.\n", object->async_callback);
832 hr = IMFSourceReader_QueryInterface(&object->IMFSourceReader_iface, riid, out);
834 failed:
835 IMFSourceReader_Release(&object->IMFSourceReader_iface);
836 return hr;
839 static HRESULT bytestream_get_url_hint(IMFByteStream *stream, WCHAR const **url)
841 static const UINT8 asfmagic[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
842 static const UINT8 wavmagic[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
843 static const UINT8 wavmask[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
844 static const WCHAR asfW[] = {'.','a','s','f',0};
845 static const WCHAR wavW[] = {'.','w','a','v',0};
846 static const struct stream_content_url_hint
848 const UINT8 *magic;
849 UINT32 magic_len;
850 const WCHAR *url;
851 const UINT8 *mask;
853 url_hints[] =
855 { asfmagic, sizeof(asfmagic), asfW },
856 { wavmagic, sizeof(wavmagic), wavW, wavmask },
858 UINT8 buffer[4 * sizeof(unsigned int)];
859 IMFAttributes *attributes;
860 UINT32 length = 0;
861 unsigned int i, j;
862 DWORD caps = 0;
863 QWORD position;
864 HRESULT hr;
866 *url = NULL;
868 if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
870 IMFAttributes_GetStringLength(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &length);
871 IMFAttributes_Release(attributes);
874 if (length)
875 return S_OK;
877 if (FAILED(hr = IMFByteStream_GetCapabilities(stream, &caps)))
878 return hr;
880 if (!(caps & MFBYTESTREAM_IS_SEEKABLE))
881 return S_OK;
883 if (FAILED(hr = IMFByteStream_GetCurrentPosition(stream, &position)))
884 return hr;
886 hr = IMFByteStream_Read(stream, buffer, sizeof(buffer), &length);
887 IMFByteStream_SetCurrentPosition(stream, position);
888 if (FAILED(hr))
889 return hr;
891 if (length < sizeof(buffer))
892 return S_OK;
894 for (i = 0; i < ARRAY_SIZE(url_hints); ++i)
896 if (url_hints[i].mask)
898 unsigned int *mask = (unsigned int *)url_hints[i].mask;
899 unsigned int *data = (unsigned int *)buffer;
901 for (j = 0; j < sizeof(buffer) / sizeof(unsigned int); ++j)
902 data[j] &= mask[j];
905 if (!memcmp(buffer, url_hints[i].magic, min(url_hints[i].magic_len, length)))
907 *url = url_hints[i].url;
908 break;
912 if (!*url)
913 WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer, length));
915 return S_OK;
918 static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttributes *attributes,
919 REFIID riid, void **out)
921 IPropertyStore *props = NULL;
922 IMFSourceResolver *resolver;
923 MF_OBJECT_TYPE obj_type;
924 IMFMediaSource *source;
925 const WCHAR *url;
926 HRESULT hr;
928 /* If stream does not have content type set, try to guess from starting byte sequence. */
929 if (FAILED(hr = bytestream_get_url_hint(stream, &url)))
930 return hr;
932 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
933 return hr;
935 if (attributes)
936 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
937 (void **)&props);
939 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, url, MF_RESOLUTION_MEDIASOURCE, props,
940 &obj_type, (IUnknown **)&source);
941 IMFSourceResolver_Release(resolver);
942 if (props)
943 IPropertyStore_Release(props);
944 if (FAILED(hr))
945 return hr;
947 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
948 IMFMediaSource_Release(source);
949 return hr;
952 static HRESULT create_source_reader_from_url(const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
954 IPropertyStore *props = NULL;
955 IMFSourceResolver *resolver;
956 IUnknown *object = NULL;
957 MF_OBJECT_TYPE obj_type;
958 IMFMediaSource *source;
959 HRESULT hr;
961 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
962 return hr;
964 if (attributes)
965 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
966 (void **)&props);
968 hr = IMFSourceResolver_CreateObjectFromURL(resolver, url, MF_RESOLUTION_MEDIASOURCE, props, &obj_type,
969 &object);
970 if (SUCCEEDED(hr))
972 switch (obj_type)
974 case MF_OBJECT_BYTESTREAM:
975 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, (IMFByteStream *)object, NULL,
976 MF_RESOLUTION_MEDIASOURCE, props, &obj_type, (IUnknown **)&source);
977 break;
978 case MF_OBJECT_MEDIASOURCE:
979 source = (IMFMediaSource *)object;
980 IMFMediaSource_AddRef(source);
981 break;
982 default:
983 WARN("Unknown object type %d.\n", obj_type);
984 hr = E_UNEXPECTED;
986 IUnknown_Release(object);
989 IMFSourceResolver_Release(resolver);
990 if (props)
991 IPropertyStore_Release(props);
992 if (FAILED(hr))
993 return hr;
995 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
996 IMFMediaSource_Release(source);
997 return hr;
1000 static HRESULT WINAPI sink_writer_QueryInterface(IMFSinkWriter *iface, REFIID riid, void **out)
1002 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1004 if (IsEqualIID(riid, &IID_IMFSinkWriter) ||
1005 IsEqualIID(riid, &IID_IUnknown))
1007 *out = iface;
1008 IMFSinkWriter_AddRef(iface);
1009 return S_OK;
1012 WARN("Unsupported %s.\n", debugstr_guid(riid));
1013 *out = NULL;
1014 return E_NOINTERFACE;
1017 static ULONG WINAPI sink_writer_AddRef(IMFSinkWriter *iface)
1019 struct sink_writer *writer = impl_from_IMFSinkWriter(iface);
1020 ULONG refcount = InterlockedIncrement(&writer->refcount);
1022 TRACE("%p, %u.\n", iface, refcount);
1024 return refcount;
1027 static ULONG WINAPI sink_writer_Release(IMFSinkWriter *iface)
1029 struct sink_writer *writer = impl_from_IMFSinkWriter(iface);
1030 ULONG refcount = InterlockedDecrement(&writer->refcount);
1032 TRACE("%p, %u.\n", iface, refcount);
1034 if (!refcount)
1036 heap_free(writer);
1039 return refcount;
1042 static HRESULT WINAPI sink_writer_AddStream(IMFSinkWriter *iface, IMFMediaType *type, DWORD *index)
1044 FIXME("%p, %p, %p.\n", iface, type, index);
1046 return E_NOTIMPL;
1049 static HRESULT WINAPI sink_writer_SetInputMediaType(IMFSinkWriter *iface, DWORD index, IMFMediaType *type,
1050 IMFAttributes *parameters)
1052 FIXME("%p, %u, %p, %p.\n", iface, index, type, parameters);
1054 return E_NOTIMPL;
1057 static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriter *iface)
1059 FIXME("%p.\n", iface);
1061 return E_NOTIMPL;
1064 static HRESULT WINAPI sink_writer_WriteSample(IMFSinkWriter *iface, DWORD index, IMFSample *sample)
1066 FIXME("%p, %u, %p.\n", iface, index, sample);
1068 return E_NOTIMPL;
1071 static HRESULT WINAPI sink_writer_SendStreamTick(IMFSinkWriter *iface, DWORD index, LONGLONG timestamp)
1073 FIXME("%p, %u, %s.\n", iface, index, wine_dbgstr_longlong(timestamp));
1075 return E_NOTIMPL;
1078 static HRESULT WINAPI sink_writer_PlaceMarker(IMFSinkWriter *iface, DWORD index, void *context)
1080 FIXME("%p, %u, %p.\n", iface, index, context);
1082 return E_NOTIMPL;
1085 static HRESULT WINAPI sink_writer_NotifyEndOfSegment(IMFSinkWriter *iface, DWORD index)
1087 FIXME("%p, %u.\n", iface, index);
1089 return E_NOTIMPL;
1092 static HRESULT WINAPI sink_writer_Flush(IMFSinkWriter *iface, DWORD index)
1094 FIXME("%p, %u.\n", iface, index);
1096 return E_NOTIMPL;
1099 static HRESULT WINAPI sink_writer_Finalize(IMFSinkWriter *iface)
1101 FIXME("%p.\n", iface);
1103 return E_NOTIMPL;
1106 static HRESULT WINAPI sink_writer_GetServiceForStream(IMFSinkWriter *iface, DWORD index, REFGUID service,
1107 REFIID riid, void **object)
1109 FIXME("%p, %u, %s, %s, %p.\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object);
1111 return E_NOTIMPL;
1114 static HRESULT WINAPI sink_writer_GetStatistics(IMFSinkWriter *iface, DWORD index, MF_SINK_WRITER_STATISTICS *stats)
1116 FIXME("%p, %u, %p.\n", iface, index, stats);
1118 return E_NOTIMPL;
1121 static const IMFSinkWriterVtbl sink_writer_vtbl =
1123 sink_writer_QueryInterface,
1124 sink_writer_AddRef,
1125 sink_writer_Release,
1126 sink_writer_AddStream,
1127 sink_writer_SetInputMediaType,
1128 sink_writer_BeginWriting,
1129 sink_writer_WriteSample,
1130 sink_writer_SendStreamTick,
1131 sink_writer_PlaceMarker,
1132 sink_writer_NotifyEndOfSegment,
1133 sink_writer_Flush,
1134 sink_writer_Finalize,
1135 sink_writer_GetServiceForStream,
1136 sink_writer_GetStatistics,
1139 static HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attributes,
1140 REFIID riid, void **out)
1142 struct sink_writer *object;
1143 HRESULT hr;
1145 object = heap_alloc(sizeof(*object));
1146 if (!object)
1147 return E_OUTOFMEMORY;
1149 object->IMFSinkWriter_iface.lpVtbl = &sink_writer_vtbl;
1150 object->refcount = 1;
1152 hr = IMFSinkWriter_QueryInterface(&object->IMFSinkWriter_iface, riid, out);
1153 IMFSinkWriter_Release(&object->IMFSinkWriter_iface);
1154 return hr;
1157 static HRESULT create_sink_writer_from_stream(IMFByteStream *stream, IMFAttributes *attributes,
1158 REFIID riid, void **out)
1160 struct sink_writer *object;
1161 HRESULT hr;
1163 object = heap_alloc(sizeof(*object));
1164 if (!object)
1165 return E_OUTOFMEMORY;
1167 object->IMFSinkWriter_iface.lpVtbl = &sink_writer_vtbl;
1168 object->refcount = 1;
1170 hr = IMFSinkWriter_QueryInterface(&object->IMFSinkWriter_iface, riid, out);
1171 IMFSinkWriter_Release(&object->IMFSinkWriter_iface);
1172 return hr;
1175 /***********************************************************************
1176 * MFCreateSinkWriterFromMediaSink (mfreadwrite.@)
1178 HRESULT WINAPI MFCreateSinkWriterFromMediaSink(IMFMediaSink *sink, IMFAttributes *attributes, IMFSinkWriter **writer)
1180 TRACE("%p, %p, %p.\n", sink, attributes, writer);
1182 return create_sink_writer_from_sink(sink, attributes, &IID_IMFSinkWriter, (void **)writer);
1185 static HRESULT create_source_reader_from_object(IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
1187 IMFMediaSource *source = NULL;
1188 IMFByteStream *stream = NULL;
1189 HRESULT hr;
1191 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSource, (void **)&source);
1192 if (FAILED(hr))
1193 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
1195 if (source)
1197 UINT32 disconnect = 0;
1199 if (attributes)
1200 IMFAttributes_GetUINT32(attributes, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, &disconnect);
1201 hr = create_source_reader_from_source(source, attributes, !disconnect, riid, out);
1203 else if (stream)
1204 hr = create_source_reader_from_stream(stream, attributes, riid, out);
1206 if (source)
1207 IMFMediaSource_Release(source);
1208 if (stream)
1209 IMFByteStream_Release(stream);
1211 return hr;
1214 /***********************************************************************
1215 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
1217 HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes,
1218 IMFSourceReader **reader)
1220 TRACE("%p, %p, %p.\n", stream, attributes, reader);
1222 return create_source_reader_from_object((IUnknown *)stream, attributes, &IID_IMFSourceReader, (void **)reader);
1225 /***********************************************************************
1226 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
1228 HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes,
1229 IMFSourceReader **reader)
1231 TRACE("%p, %p, %p.\n", source, attributes, reader);
1233 return create_source_reader_from_object((IUnknown *)source, attributes, &IID_IMFSourceReader, (void **)reader);
1236 /***********************************************************************
1237 * MFCreateSourceReaderFromURL (mfreadwrite.@)
1239 HRESULT WINAPI MFCreateSourceReaderFromURL(const WCHAR *url, IMFAttributes *attributes, IMFSourceReader **reader)
1241 TRACE("%s, %p, %p.\n", debugstr_w(url), attributes, reader);
1243 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, (void **)reader);
1246 static HRESULT WINAPI readwrite_factory_QueryInterface(IMFReadWriteClassFactory *iface, REFIID riid, void **out)
1248 if (IsEqualIID(riid, &IID_IMFReadWriteClassFactory) ||
1249 IsEqualIID(riid, &IID_IUnknown))
1251 *out = iface;
1252 IMFReadWriteClassFactory_AddRef(iface);
1253 return S_OK;
1256 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1257 *out = NULL;
1258 return E_NOINTERFACE;
1261 static ULONG WINAPI readwrite_factory_AddRef(IMFReadWriteClassFactory *iface)
1263 return 2;
1266 static ULONG WINAPI readwrite_factory_Release(IMFReadWriteClassFactory *iface)
1268 return 1;
1271 static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory *iface, REFCLSID clsid,
1272 const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
1274 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid), debugstr_w(url), attributes, debugstr_guid(riid), out);
1276 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
1278 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, out);
1281 FIXME("Unsupported %s.\n", debugstr_guid(clsid));
1283 return E_NOTIMPL;
1286 static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory *iface, REFCLSID clsid,
1287 IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
1289 HRESULT hr;
1291 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out);
1293 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
1295 return create_source_reader_from_object(unk, attributes, riid, out);
1297 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
1299 IMFByteStream *stream = NULL;
1300 IMFMediaSink *sink = NULL;
1302 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
1303 if (FAILED(hr))
1304 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink);
1306 if (stream)
1307 hr = create_sink_writer_from_stream(stream, attributes, riid, out);
1308 else if (sink)
1309 hr = create_sink_writer_from_sink(sink, attributes, riid, out);
1311 if (sink)
1312 IMFMediaSink_Release(sink);
1313 if (stream)
1314 IMFByteStream_Release(stream);
1316 return hr;
1318 else
1320 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
1321 *out = NULL;
1322 return E_FAIL;
1326 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl =
1328 readwrite_factory_QueryInterface,
1329 readwrite_factory_AddRef,
1330 readwrite_factory_Release,
1331 readwrite_factory_CreateInstanceFromURL,
1332 readwrite_factory_CreateInstanceFromObject,
1335 static IMFReadWriteClassFactory readwrite_factory = { &readwrite_factory_vtbl };
1337 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
1339 TRACE("%s, %p.\n", debugstr_guid(riid), out);
1341 if (IsEqualGUID(riid, &IID_IClassFactory) ||
1342 IsEqualGUID(riid, &IID_IUnknown))
1344 IClassFactory_AddRef(iface);
1345 *out = iface;
1346 return S_OK;
1349 WARN("interface %s not implemented\n", debugstr_guid(riid));
1350 *out = NULL;
1351 return E_NOINTERFACE;
1354 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
1356 return 2;
1359 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
1361 return 1;
1364 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out)
1366 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), out);
1368 *out = NULL;
1370 if (outer)
1371 return CLASS_E_NOAGGREGATION;
1373 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory, riid, out);
1376 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
1378 FIXME("%d.\n", dolock);
1379 return S_OK;
1382 static const struct IClassFactoryVtbl classfactoryvtbl =
1384 classfactory_QueryInterface,
1385 classfactory_AddRef,
1386 classfactory_Release,
1387 classfactory_CreateInstance,
1388 classfactory_LockServer,
1391 static IClassFactory classfactory = { &classfactoryvtbl };
1393 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
1395 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), out);
1397 if (IsEqualGUID(clsid, &CLSID_MFReadWriteClassFactory))
1398 return IClassFactory_QueryInterface(&classfactory, riid, out);
1400 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
1401 *out = NULL;
1402 return CLASS_E_CLASSNOTAVAILABLE;