winegstreamer: Implement IMFMediaStream::GetStreamDescriptor.
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
7d4395a00e
commit
4228016b0c
|
@ -36,6 +36,7 @@
|
||||||
#include "winuser.h"
|
#include "winuser.h"
|
||||||
#include "dshow.h"
|
#include "dshow.h"
|
||||||
#include "strmif.h"
|
#include "strmif.h"
|
||||||
|
#include "mfobjects.h"
|
||||||
#include "wine/heap.h"
|
#include "wine/heap.h"
|
||||||
#include "wine/strmbase.h"
|
#include "wine/strmbase.h"
|
||||||
|
|
||||||
|
@ -54,6 +55,9 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
|
extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
|
||||||
|
IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
|
HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
#endif /* __GST_PRIVATE_INCLUDED__ */
|
#endif /* __GST_PRIVATE_INCLUDED__ */
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct media_stream
|
||||||
LONG ref;
|
LONG ref;
|
||||||
struct media_source *parent_source;
|
struct media_source *parent_source;
|
||||||
IMFMediaEventQueue *event_queue;
|
IMFMediaEventQueue *event_queue;
|
||||||
|
IMFStreamDescriptor *descriptor;
|
||||||
GstElement *appsink;
|
GstElement *appsink;
|
||||||
GstPad *their_src, *my_sink;
|
GstPad *their_src, *my_sink;
|
||||||
enum
|
enum
|
||||||
|
@ -55,6 +56,7 @@ struct media_stream
|
||||||
STREAM_INACTIVE,
|
STREAM_INACTIVE,
|
||||||
STREAM_SHUTDOWN,
|
STREAM_SHUTDOWN,
|
||||||
} state;
|
} state;
|
||||||
|
DWORD stream_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct media_source
|
struct media_source
|
||||||
|
@ -350,7 +352,10 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM
|
||||||
if (stream->state == STREAM_SHUTDOWN)
|
if (stream->state == STREAM_SHUTDOWN)
|
||||||
return MF_E_SHUTDOWN;
|
return MF_E_SHUTDOWN;
|
||||||
|
|
||||||
return E_NOTIMPL;
|
IMFStreamDescriptor_AddRef(stream->descriptor);
|
||||||
|
*descriptor = stream->descriptor;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
|
static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
|
||||||
|
@ -379,7 +384,7 @@ static const IMFMediaStreamVtbl media_stream_vtbl =
|
||||||
media_stream_RequestSample
|
media_stream_RequestSample
|
||||||
};
|
};
|
||||||
|
|
||||||
static HRESULT new_media_stream(struct media_source *source, GstPad *pad, struct media_stream **out_stream)
|
static HRESULT new_media_stream(struct media_source *source, GstPad *pad, DWORD stream_id, struct media_stream **out_stream)
|
||||||
{
|
{
|
||||||
struct media_stream *object = heap_alloc_zero(sizeof(*object));
|
struct media_stream *object = heap_alloc_zero(sizeof(*object));
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -392,6 +397,7 @@ static HRESULT new_media_stream(struct media_source *source, GstPad *pad, struct
|
||||||
IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
|
IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
|
||||||
object->parent_source = source;
|
object->parent_source = source;
|
||||||
object->their_src = pad;
|
object->their_src = pad;
|
||||||
|
object->stream_id = stream_id;
|
||||||
|
|
||||||
object->state = STREAM_INACTIVE;
|
object->state = STREAM_INACTIVE;
|
||||||
|
|
||||||
|
@ -409,8 +415,6 @@ static HRESULT new_media_stream(struct media_source *source, GstPad *pad, struct
|
||||||
g_object_set(object->appsink, "max-buffers", 5, NULL);
|
g_object_set(object->appsink, "max-buffers", 5, NULL);
|
||||||
|
|
||||||
object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
|
object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
|
||||||
gst_pad_set_element_private(object->my_sink, object);
|
|
||||||
|
|
||||||
gst_pad_link(object->their_src, object->my_sink);
|
gst_pad_link(object->their_src, object->my_sink);
|
||||||
|
|
||||||
gst_element_sync_state_with_parent(object->appsink);
|
gst_element_sync_state_with_parent(object->appsink);
|
||||||
|
@ -427,6 +431,35 @@ fail:
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT media_stream_init_desc(struct media_stream *stream)
|
||||||
|
{
|
||||||
|
GstCaps *current_caps = gst_pad_get_current_caps(stream->their_src);
|
||||||
|
IMFMediaTypeHandler *type_handler;
|
||||||
|
IMFMediaType *stream_type = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
stream_type = mf_media_type_from_caps(current_caps);
|
||||||
|
gst_caps_unref(current_caps);
|
||||||
|
if (!stream_type)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
hr = MFCreateStreamDescriptor(stream->stream_id, 1, &stream_type, &stream->descriptor);
|
||||||
|
|
||||||
|
IMFMediaType_Release(stream_type);
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_type);
|
||||||
|
|
||||||
|
IMFMediaTypeHandler_Release(type_handler);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
|
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
|
||||||
{
|
{
|
||||||
struct media_source *source = impl_from_IMFMediaSource(iface);
|
struct media_source *source = impl_from_IMFMediaSource(iface);
|
||||||
|
@ -613,6 +646,8 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
|
||||||
gst_object_unref(GST_OBJECT(stream->my_sink));
|
gst_object_unref(GST_OBJECT(stream->my_sink));
|
||||||
if (stream->event_queue)
|
if (stream->event_queue)
|
||||||
IMFMediaEventQueue_Shutdown(stream->event_queue);
|
IMFMediaEventQueue_Shutdown(stream->event_queue);
|
||||||
|
if (stream->descriptor)
|
||||||
|
IMFStreamDescriptor_Release(stream->descriptor);
|
||||||
if (stream->parent_source)
|
if (stream->parent_source)
|
||||||
IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
|
IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
|
||||||
|
|
||||||
|
@ -654,7 +689,7 @@ static void stream_added(GstElement *element, GstPad *pad, gpointer user)
|
||||||
if (gst_pad_get_direction(pad) != GST_PAD_SRC)
|
if (gst_pad_get_direction(pad) != GST_PAD_SRC)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (FAILED(new_media_stream(source, pad, &stream)))
|
if (FAILED(new_media_stream(source, pad, source->stream_count, &stream)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(new_stream_array = heap_realloc(source->streams, (source->stream_count + 1) * (sizeof(*new_stream_array)))))
|
if (!(new_stream_array = heap_realloc(source->streams, (source->stream_count + 1) * (sizeof(*new_stream_array)))))
|
||||||
|
@ -679,6 +714,7 @@ static void stream_removed(GstElement *element, GstPad *pad, gpointer user)
|
||||||
if (stream->their_src != pad)
|
if (stream->their_src != pad)
|
||||||
continue;
|
continue;
|
||||||
stream->their_src = NULL;
|
stream->their_src = NULL;
|
||||||
|
stream->state = STREAM_INACTIVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,6 +731,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
|
||||||
GST_STATIC_PAD_TEMPLATE("mf_src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
|
GST_STATIC_PAD_TEMPLATE("mf_src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
|
||||||
|
|
||||||
struct media_source *object = heap_alloc_zero(sizeof(*object));
|
struct media_source *object = heap_alloc_zero(sizeof(*object));
|
||||||
|
unsigned int i;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -768,6 +805,18 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitForSingleObject(object->no_more_pads_event, INFINITE);
|
WaitForSingleObject(object->no_more_pads_event, INFINITE);
|
||||||
|
for (i = 0; i < object->stream_count; i++)
|
||||||
|
{
|
||||||
|
GstSample *preroll;
|
||||||
|
g_signal_emit_by_name(object->streams[i]->appsink, "pull-preroll", &preroll);
|
||||||
|
if (FAILED(hr = media_stream_init_desc(object->streams[i])))
|
||||||
|
{
|
||||||
|
ERR("Failed to finish initialization of media stream %p, hr %x.\n", object->streams[i], hr);
|
||||||
|
IMFMediaStream_Release(&object->streams[i]->IMFMediaStream_iface);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
gst_sample_unref(preroll);
|
||||||
|
}
|
||||||
|
|
||||||
object->state = SOURCE_STOPPED;
|
object->state = SOURCE_STOPPED;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
#include "gst_private.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "gst_private.h"
|
#include "gst_private.h"
|
||||||
|
@ -436,3 +441,163 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
|
||||||
|
|
||||||
return CLASS_E_CLASSNOTAVAILABLE;
|
return CLASS_E_CLASSNOTAVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
const GUID *subtype;
|
||||||
|
GstVideoFormat format;
|
||||||
|
}
|
||||||
|
uncompressed_video_formats[] =
|
||||||
|
{
|
||||||
|
{&MFVideoFormat_ARGB32, GST_VIDEO_FORMAT_BGRA},
|
||||||
|
{&MFVideoFormat_RGB32, GST_VIDEO_FORMAT_BGRx},
|
||||||
|
{&MFVideoFormat_RGB24, GST_VIDEO_FORMAT_BGR},
|
||||||
|
{&MFVideoFormat_RGB565, GST_VIDEO_FORMAT_BGR16},
|
||||||
|
{&MFVideoFormat_RGB555, GST_VIDEO_FORMAT_BGR15},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* returns NULL if doesn't match exactly */
|
||||||
|
IMFMediaType *mf_media_type_from_caps(const GstCaps *caps)
|
||||||
|
{
|
||||||
|
IMFMediaType *media_type;
|
||||||
|
GstStructure *info;
|
||||||
|
const char *mime_type;
|
||||||
|
|
||||||
|
if (TRACE_ON(mfplat))
|
||||||
|
{
|
||||||
|
gchar *human_readable = gst_caps_to_string(caps);
|
||||||
|
TRACE("caps = %s\n", debugstr_a(human_readable));
|
||||||
|
g_free(human_readable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(MFCreateMediaType(&media_type)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
info = gst_caps_get_structure(caps, 0);
|
||||||
|
mime_type = gst_structure_get_name(info);
|
||||||
|
|
||||||
|
if (!strncmp(mime_type, "video", 5))
|
||||||
|
{
|
||||||
|
GstVideoInfo video_info;
|
||||||
|
|
||||||
|
if (!gst_video_info_from_caps(&video_info, caps))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
|
||||||
|
|
||||||
|
IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ((UINT64)video_info.width << 32) | video_info.height);
|
||||||
|
|
||||||
|
IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ((UINT64)video_info.fps_n << 32) | video_info.fps_d);
|
||||||
|
|
||||||
|
if (!strcmp(mime_type, "video/x-raw"))
|
||||||
|
{
|
||||||
|
GUID fourcc_subtype = MFVideoFormat_Base;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, FALSE);
|
||||||
|
|
||||||
|
/* First try FOURCC */
|
||||||
|
if ((fourcc_subtype.Data1 = gst_video_format_to_fourcc(video_info.finfo->format)))
|
||||||
|
{
|
||||||
|
IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &fourcc_subtype);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < ARRAY_SIZE(uncompressed_video_formats); i++)
|
||||||
|
{
|
||||||
|
if (uncompressed_video_formats[i].format == video_info.finfo->format)
|
||||||
|
{
|
||||||
|
IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, uncompressed_video_formats[i].subtype);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == ARRAY_SIZE(uncompressed_video_formats))
|
||||||
|
{
|
||||||
|
FIXME("Unrecognized uncompressed video format %s\n", gst_video_format_to_string(video_info.finfo->format));
|
||||||
|
IMFMediaType_Release(media_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FIXME("Unrecognized video format %s\n", mime_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strncmp(mime_type, "audio", 5))
|
||||||
|
{
|
||||||
|
gint rate, channels, bitrate;
|
||||||
|
guint64 channel_mask;
|
||||||
|
IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
|
||||||
|
|
||||||
|
if (gst_structure_get_int(info, "rate", &rate))
|
||||||
|
IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, rate);
|
||||||
|
|
||||||
|
if (gst_structure_get_int(info, "channels", &channels))
|
||||||
|
IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channels);
|
||||||
|
|
||||||
|
if (gst_structure_get(info, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL))
|
||||||
|
IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_CHANNEL_MASK, channel_mask);
|
||||||
|
|
||||||
|
if (gst_structure_get_int(info, "bitrate", &bitrate))
|
||||||
|
IMFMediaType_SetUINT32(media_type, &MF_MT_AVG_BITRATE, bitrate);
|
||||||
|
|
||||||
|
if (!strcmp(mime_type, "audio/x-raw"))
|
||||||
|
{
|
||||||
|
GstAudioInfo audio_info;
|
||||||
|
DWORD depth;
|
||||||
|
|
||||||
|
if (!gst_audio_info_from_caps(&audio_info, caps))
|
||||||
|
{
|
||||||
|
ERR("Failed to get caps audio info\n");
|
||||||
|
IMFMediaType_Release(media_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
depth = GST_AUDIO_INFO_DEPTH(&audio_info);
|
||||||
|
|
||||||
|
/* validation */
|
||||||
|
if ((audio_info.finfo->flags & GST_AUDIO_FORMAT_FLAG_INTEGER && depth > 8) ||
|
||||||
|
(audio_info.finfo->flags & GST_AUDIO_FORMAT_FLAG_SIGNED && depth <= 8) ||
|
||||||
|
(audio_info.finfo->endianness != G_LITTLE_ENDIAN && depth > 8))
|
||||||
|
{
|
||||||
|
IMFMediaType_Release(media_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* conversion */
|
||||||
|
switch (audio_info.finfo->flags)
|
||||||
|
{
|
||||||
|
case GST_AUDIO_FORMAT_FLAG_FLOAT:
|
||||||
|
IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_Float);
|
||||||
|
break;
|
||||||
|
case GST_AUDIO_FORMAT_FLAG_INTEGER:
|
||||||
|
case GST_AUDIO_FORMAT_FLAG_SIGNED:
|
||||||
|
IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FIXME("Unrecognized audio format %x\n", audio_info.finfo->format);
|
||||||
|
IMFMediaType_Release(media_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, depth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FIXME("Unrecognized audio format %s\n", mime_type);
|
||||||
|
IMFMediaType_Release(media_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IMFMediaType_Release(media_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return media_type;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue