winegstreamer: Implement IMFMediaSource::Start.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
9d7f98ee7f
commit
12f1afbffe
|
@ -603,10 +603,7 @@ todo_wine
|
|||
|
||||
var.vt = VT_EMPTY;
|
||||
hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var);
|
||||
todo_wine
|
||||
ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr);
|
||||
if (FAILED(hr))
|
||||
goto skip_source_tests;
|
||||
|
||||
get_event((IMFMediaEventGenerator *)mediasource, MENewStream, &var);
|
||||
ok(var.vt == VT_UNKNOWN, "Unexpected value type %u from MENewStream event.\n", var.vt);
|
||||
|
@ -624,10 +621,13 @@ todo_wine
|
|||
hr = IMFMediaStream_RequestSample(video_stream, NULL);
|
||||
if (i == sample_count)
|
||||
break;
|
||||
todo_wine
|
||||
ok(hr == S_OK, "Failed to request sample %u, hr %#x.\n", i + 1, hr);
|
||||
if (hr != S_OK)
|
||||
break;
|
||||
}
|
||||
if (FAILED(hr))
|
||||
goto skip_source_tests;
|
||||
|
||||
for (i = 0; i < sample_count; ++i)
|
||||
{
|
||||
|
@ -665,11 +665,11 @@ todo_wine
|
|||
|
||||
hr = IMFMediaStream_RequestSample(video_stream, NULL);
|
||||
ok(hr == MF_E_END_OF_STREAM, "Unexpected hr %#x.\n", hr);
|
||||
IMFMediaStream_Release(video_stream);
|
||||
|
||||
get_event((IMFMediaEventGenerator *)mediasource, MEEndOfPresentation, NULL);
|
||||
|
||||
skip_source_tests:
|
||||
IMFMediaStream_Release(video_stream);
|
||||
IMFMediaTypeHandler_Release(handler);
|
||||
IMFPresentationDescriptor_Release(descriptor);
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
|
|||
|
||||
HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
|
||||
IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) DECLSPEC_HIDDEN;
|
||||
GstCaps *caps_from_mf_media_type(IMFMediaType *type) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
|
||||
|
||||
|
|
|
@ -55,14 +55,38 @@ struct media_stream
|
|||
{
|
||||
STREAM_INACTIVE,
|
||||
STREAM_SHUTDOWN,
|
||||
STREAM_RUNNING,
|
||||
} state;
|
||||
DWORD stream_id;
|
||||
};
|
||||
|
||||
enum source_async_op
|
||||
{
|
||||
SOURCE_ASYNC_START,
|
||||
};
|
||||
|
||||
struct source_async_command
|
||||
{
|
||||
IUnknown IUnknown_iface;
|
||||
LONG refcount;
|
||||
enum source_async_op op;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
IMFPresentationDescriptor *descriptor;
|
||||
GUID format;
|
||||
PROPVARIANT position;
|
||||
} start;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct media_source
|
||||
{
|
||||
IMFMediaSource IMFMediaSource_iface;
|
||||
IMFAsyncCallback async_commands_callback;
|
||||
LONG ref;
|
||||
DWORD async_commands_queue;
|
||||
IMFMediaEventQueue *event_queue;
|
||||
IMFByteStream *byte_stream;
|
||||
struct media_stream **streams;
|
||||
|
@ -76,6 +100,7 @@ struct media_source
|
|||
{
|
||||
SOURCE_OPENING,
|
||||
SOURCE_STOPPED,
|
||||
SOURCE_RUNNING,
|
||||
SOURCE_SHUTDOWN,
|
||||
} state;
|
||||
HANDLE no_more_pads_event;
|
||||
|
@ -91,7 +116,260 @@ static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *ifac
|
|||
return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
|
||||
}
|
||||
|
||||
static GstFlowReturn bytestream_wrapper_pull(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
|
||||
static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, struct media_source, async_commands_callback);
|
||||
}
|
||||
|
||||
static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
|
||||
{
|
||||
if (IsEqualIID(riid, &IID_IUnknown))
|
||||
{
|
||||
*obj = iface;
|
||||
IUnknown_AddRef(iface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
WARN("Unsupported interface %s.\n", debugstr_guid(riid));
|
||||
*obj = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG WINAPI source_async_command_AddRef(IUnknown *iface)
|
||||
{
|
||||
struct source_async_command *command = impl_from_async_command_IUnknown(iface);
|
||||
return InterlockedIncrement(&command->refcount);
|
||||
}
|
||||
|
||||
static ULONG WINAPI source_async_command_Release(IUnknown *iface)
|
||||
{
|
||||
struct source_async_command *command = impl_from_async_command_IUnknown(iface);
|
||||
ULONG refcount = InterlockedDecrement(&command->refcount);
|
||||
|
||||
if (!refcount)
|
||||
{
|
||||
if (command->op == SOURCE_ASYNC_START)
|
||||
PropVariantClear(&command->u.start.position);
|
||||
heap_free(command);
|
||||
}
|
||||
|
||||
return refcount;
|
||||
}
|
||||
|
||||
static const IUnknownVtbl source_async_command_vtbl =
|
||||
{
|
||||
source_async_command_QueryInterface,
|
||||
source_async_command_AddRef,
|
||||
source_async_command_Release,
|
||||
};
|
||||
|
||||
static HRESULT source_create_async_op(enum source_async_op op, struct source_async_command **ret)
|
||||
{
|
||||
struct source_async_command *command;
|
||||
|
||||
if (!(command = heap_alloc_zero(sizeof(*command))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
|
||||
command->op = op;
|
||||
|
||||
*ret = command;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
|
||||
{
|
||||
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
|
||||
|
||||
if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
|
||||
IsEqualIID(riid, &IID_IUnknown))
|
||||
{
|
||||
*obj = iface;
|
||||
IMFAsyncCallback_AddRef(iface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
WARN("Unsupported %s.\n", debugstr_guid(riid));
|
||||
*obj = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
|
||||
DWORD *flags, DWORD *queue)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
|
||||
{
|
||||
struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
|
||||
return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
|
||||
}
|
||||
|
||||
static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
|
||||
{
|
||||
struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
|
||||
return IMFMediaSource_Release(&source->IMFMediaSource_iface);
|
||||
}
|
||||
|
||||
static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected)
|
||||
{
|
||||
ULONG sd_count;
|
||||
IMFStreamDescriptor *ret;
|
||||
unsigned int i;
|
||||
|
||||
if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count)))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < sd_count; i++)
|
||||
{
|
||||
DWORD stream_id;
|
||||
|
||||
if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret)))
|
||||
return NULL;
|
||||
|
||||
if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id)
|
||||
return ret;
|
||||
|
||||
IMFStreamDescriptor_Release(ret);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void start_pipeline(struct media_source *source, struct source_async_command *command)
|
||||
{
|
||||
PROPVARIANT *position = &command->u.start.position;
|
||||
BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY;
|
||||
GstStateChangeReturn ret;
|
||||
unsigned int i;
|
||||
|
||||
gst_element_set_state(source->container, GST_STATE_PAUSED);
|
||||
ret = gst_element_get_state(source->container, NULL, NULL, -1);
|
||||
assert(ret == GST_STATE_CHANGE_SUCCESS);
|
||||
|
||||
/* seek to beginning on stop->play */
|
||||
if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY)
|
||||
{
|
||||
position->vt = VT_I8;
|
||||
position->u.hVal.QuadPart = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < source->stream_count; i++)
|
||||
{
|
||||
struct media_stream *stream;
|
||||
IMFStreamDescriptor *sd;
|
||||
IMFMediaTypeHandler *mth;
|
||||
IMFMediaType *current_mt;
|
||||
GstCaps *current_caps;
|
||||
GstCaps *prev_caps;
|
||||
DWORD stream_id;
|
||||
BOOL was_active;
|
||||
BOOL selected;
|
||||
|
||||
stream = source->streams[i];
|
||||
|
||||
IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id);
|
||||
|
||||
sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected);
|
||||
IMFStreamDescriptor_Release(sd);
|
||||
|
||||
was_active = stream->state != STREAM_INACTIVE;
|
||||
|
||||
stream->state = selected ? STREAM_RUNNING : STREAM_INACTIVE;
|
||||
|
||||
if (selected)
|
||||
{
|
||||
IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &mth);
|
||||
IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt);
|
||||
current_caps = caps_from_mf_media_type(current_mt);
|
||||
g_object_get(stream->appsink, "caps", &prev_caps, NULL);
|
||||
if (!prev_caps || !gst_caps_is_equal(prev_caps, current_caps))
|
||||
{
|
||||
GstEvent *reconfigure_event = gst_event_new_reconfigure();
|
||||
g_object_set(stream->appsink, "caps", current_caps, NULL);
|
||||
gst_pad_push_event(gst_element_get_static_pad(stream->appsink, "sink"), reconfigure_event);
|
||||
}
|
||||
|
||||
gst_caps_unref(current_caps);
|
||||
if (prev_caps)
|
||||
gst_caps_unref(prev_caps);
|
||||
IMFMediaType_Release(current_mt);
|
||||
IMFMediaTypeHandler_Release(mth);
|
||||
}
|
||||
|
||||
g_object_set(stream->appsink, "drop", !selected, NULL);
|
||||
|
||||
if (position->vt != VT_EMPTY)
|
||||
{
|
||||
GstEvent *seek_event = gst_event_new_seek(1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
|
||||
GST_SEEK_TYPE_SET, position->u.hVal.QuadPart / 100, GST_SEEK_TYPE_NONE, 0);
|
||||
|
||||
gst_pad_push_event(stream->my_sink, seek_event);
|
||||
}
|
||||
|
||||
if (selected)
|
||||
{
|
||||
TRACE("Stream %u (%p) selected\n", i, stream);
|
||||
IMFMediaEventQueue_QueueEventParamUnk(source->event_queue,
|
||||
was_active ? MEUpdatedStream : MENewStream, &GUID_NULL,
|
||||
S_OK, (IUnknown*) &stream->IMFMediaStream_iface);
|
||||
|
||||
IMFMediaEventQueue_QueueEventParamVar(stream->event_queue,
|
||||
seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position);
|
||||
}
|
||||
}
|
||||
|
||||
IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
|
||||
seek_message ? MESourceSeeked : MESourceStarted,
|
||||
&GUID_NULL, S_OK, position);
|
||||
|
||||
source->state = SOURCE_RUNNING;
|
||||
|
||||
gst_element_set_state(source->container, GST_STATE_PLAYING);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
||||
{
|
||||
struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
|
||||
struct source_async_command *command;
|
||||
IUnknown *state;
|
||||
HRESULT hr;
|
||||
|
||||
if (source->state == SOURCE_SHUTDOWN)
|
||||
return S_OK;
|
||||
|
||||
if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
|
||||
return hr;
|
||||
|
||||
command = impl_from_async_command_IUnknown(state);
|
||||
switch (command->op)
|
||||
{
|
||||
case SOURCE_ASYNC_START:
|
||||
start_pipeline(source, command);
|
||||
break;
|
||||
}
|
||||
|
||||
IUnknown_Release(state);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
|
||||
{
|
||||
callback_QueryInterface,
|
||||
source_async_commands_callback_AddRef,
|
||||
source_async_commands_callback_Release,
|
||||
callback_GetParameters,
|
||||
source_async_commands_Invoke,
|
||||
};
|
||||
|
||||
GstFlowReturn bytestream_wrapper_pull(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
|
||||
GstBuffer **buf)
|
||||
{
|
||||
struct media_source *source = gst_pad_get_element_private(pad);
|
||||
|
@ -683,16 +961,30 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *
|
|||
}
|
||||
|
||||
static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
|
||||
const GUID *time_format, const PROPVARIANT *start_position)
|
||||
const GUID *time_format, const PROPVARIANT *position)
|
||||
{
|
||||
struct media_source *source = impl_from_IMFMediaSource(iface);
|
||||
struct source_async_command *command;
|
||||
HRESULT hr;
|
||||
|
||||
FIXME("(%p)->(%p, %p, %p): stub\n", source, descriptor, time_format, start_position);
|
||||
TRACE("(%p)->(%p, %p, %p)\n", source, descriptor, time_format, position);
|
||||
|
||||
if (source->state == SOURCE_SHUTDOWN)
|
||||
return MF_E_SHUTDOWN;
|
||||
|
||||
return E_NOTIMPL;
|
||||
if (!(IsEqualIID(time_format, &GUID_NULL)))
|
||||
return MF_E_UNSUPPORTED_TIME_FORMAT;
|
||||
|
||||
if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command)))
|
||||
{
|
||||
command->u.start.descriptor = descriptor;
|
||||
command->u.start.format = *time_format;
|
||||
PropVariantCopy(&command->u.start.position, position);
|
||||
|
||||
hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
|
||||
|
@ -773,6 +1065,9 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
|
|||
if (source->no_more_pads_event)
|
||||
CloseHandle(source->no_more_pads_event);
|
||||
|
||||
if (source->async_commands_queue)
|
||||
MFUnlockWorkQueue(source->async_commands_queue);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -853,6 +1148,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
|
|||
return E_OUTOFMEMORY;
|
||||
|
||||
object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
|
||||
object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
|
||||
object->ref = 1;
|
||||
object->byte_stream = bytestream;
|
||||
IMFByteStream_AddRef(bytestream);
|
||||
|
@ -861,6 +1157,9 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
|
|||
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
|
||||
goto fail;
|
||||
|
||||
if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
|
||||
goto fail;
|
||||
|
||||
object->container = gst_bin_new(NULL);
|
||||
object->bus = gst_bus_new();
|
||||
gst_bus_set_sync_handler(object->bus, mf_src_bus_watch_wrapper, object, NULL);
|
||||
|
|
|
@ -601,3 +601,133 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps)
|
|||
|
||||
return media_type;
|
||||
}
|
||||
|
||||
GstCaps *caps_from_mf_media_type(IMFMediaType *type)
|
||||
{
|
||||
GUID major_type;
|
||||
GUID subtype;
|
||||
GstCaps *output = NULL;
|
||||
|
||||
if (FAILED(IMFMediaType_GetMajorType(type, &major_type)))
|
||||
return NULL;
|
||||
if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
|
||||
return NULL;
|
||||
|
||||
if (IsEqualGUID(&major_type, &MFMediaType_Video))
|
||||
{
|
||||
UINT64 frame_rate = 0, frame_size = 0;
|
||||
DWORD width, height;
|
||||
GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
|
||||
GUID subtype_base;
|
||||
GstVideoInfo info;
|
||||
unsigned int i;
|
||||
|
||||
if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
|
||||
return NULL;
|
||||
width = frame_size >> 32;
|
||||
height = frame_size;
|
||||
|
||||
output = gst_caps_new_empty_simple("video/x-raw");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uncompressed_video_formats); i++)
|
||||
{
|
||||
if (IsEqualGUID(uncompressed_video_formats[i].subtype, &subtype))
|
||||
{
|
||||
format = uncompressed_video_formats[i].format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
subtype_base = subtype;
|
||||
subtype_base.Data1 = 0;
|
||||
if (format == GST_VIDEO_FORMAT_UNKNOWN && IsEqualGUID(&MFVideoFormat_Base, &subtype_base))
|
||||
format = gst_video_format_from_fourcc(subtype.Data1);
|
||||
|
||||
if (format == GST_VIDEO_FORMAT_UNKNOWN)
|
||||
{
|
||||
FIXME("Unrecognized format %s\n", debugstr_guid(&subtype));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gst_video_info_set_format(&info, format, width, height);
|
||||
output = gst_video_info_to_caps(&info);
|
||||
|
||||
if (frame_size)
|
||||
{
|
||||
gst_caps_set_simple(output, "width", G_TYPE_INT, width, NULL);
|
||||
gst_caps_set_simple(output, "height", G_TYPE_INT, height, NULL);
|
||||
}
|
||||
if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)))
|
||||
{
|
||||
/* Darksiders: Warmastered Edition uses a MF_MT_FRAME_RATE of 0,
|
||||
and gstreamer won't accept an undefined number as the framerate. */
|
||||
if (!(DWORD32)frame_rate)
|
||||
frame_rate = 1;
|
||||
gst_caps_set_simple(output, "framerate", GST_TYPE_FRACTION, (DWORD32)(frame_rate >> 32), (DWORD32) frame_rate, NULL);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
else if (IsEqualGUID(&major_type, &MFMediaType_Audio))
|
||||
{
|
||||
DWORD rate, channels, channel_mask, bitrate;
|
||||
|
||||
if (IsEqualGUID(&subtype, &MFAudioFormat_Float))
|
||||
{
|
||||
output = gst_caps_new_empty_simple("audio/x-raw");
|
||||
|
||||
gst_caps_set_simple(output, "format", G_TYPE_STRING, "F32LE", NULL);
|
||||
gst_caps_set_simple(output, "layout", G_TYPE_STRING, "interleaved", NULL);
|
||||
}
|
||||
else if (IsEqualGUID(&subtype, &MFAudioFormat_PCM))
|
||||
{
|
||||
DWORD bits_per_sample;
|
||||
|
||||
if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample)))
|
||||
{
|
||||
char format[6];
|
||||
char type;
|
||||
|
||||
type = bits_per_sample > 8 ? 'S' : 'U';
|
||||
|
||||
output = gst_caps_new_empty_simple("audio/x-raw");
|
||||
|
||||
sprintf(format, "%c%u%s", type, bits_per_sample, bits_per_sample > 8 ? "LE" : "");
|
||||
|
||||
gst_caps_set_simple(output, "format", G_TYPE_STRING, format, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Bits per sample not set.\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate)))
|
||||
{
|
||||
gst_caps_set_simple(output, "rate", G_TYPE_INT, rate, NULL);
|
||||
}
|
||||
if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels)))
|
||||
{
|
||||
gst_caps_set_simple(output, "channels", G_TYPE_INT, channels, NULL);
|
||||
}
|
||||
if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, &channel_mask)))
|
||||
{
|
||||
gst_caps_set_simple(output, "channel-mask", GST_TYPE_BITMASK, (guint64) channel_mask, NULL);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AVG_BITRATE, &bitrate)))
|
||||
{
|
||||
gst_caps_set_simple(output, "bitrate", G_TYPE_INT, bitrate, NULL);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
FIXME("Unrecognized major type %s\n", debugstr_guid(&major_type));
|
||||
return NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue