From 76304164bb457459b7561d508d17d3af2bac4f70 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Wed, 9 Sep 2009 12:41:17 +0200 Subject: [PATCH] dshowvideosrc: use IEnumMediaTypes when IAMStreamConfig is not usable For some device drivers IAMStreamConfig is not supported. But EnumMediatypes does not provide range size and framerate. --- sys/dshowsrcwrapper/gstdshow.cpp | 72 +++++++++++++++++---- sys/dshowsrcwrapper/gstdshow.h | 14 ++++- sys/dshowsrcwrapper/gstdshowvideosrc.cpp | 103 ++++++++++++++++++++++--------- win32/vs9/libgstdshowsrcwrapper.vcproj | 8 +-- 4 files changed, 150 insertions(+), 47 deletions(-) diff --git a/sys/dshowsrcwrapper/gstdshow.cpp b/sys/dshowsrcwrapper/gstdshow.cpp index 86be548..980ff93 100644 --- a/sys/dshowsrcwrapper/gstdshow.cpp +++ b/sys/dshowsrcwrapper/gstdshow.cpp @@ -22,6 +22,11 @@ #include "gstdshow.h" #include "gstdshowfakesink.h" +const GUID MEDIASUBTYPE_I420 + = { 0x30323449, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71} +}; + void gst_dshow_free_mediatype (AM_MEDIA_TYPE * pmt) { @@ -58,10 +63,45 @@ gst_dshow_free_pin_mediatype (gpointer pt) } GstCapturePinMediaType * -gst_dshow_new_pin_mediatype (IPin * pin, gint id, IAMStreamConfig * streamcaps) +gst_dshow_new_pin_mediatype (IPin * pin) { GstCapturePinMediaType *pin_mediatype = g_new0 (GstCapturePinMediaType, 1); + pin->AddRef (); + pin_mediatype->capture_pin = pin; + + return pin_mediatype; +} + +GstCapturePinMediaType * +gst_dshow_new_pin_mediatype_from_enum_mediatypes (IPin * pin, IEnumMediaTypes *enum_mediatypes) +{ + GstCapturePinMediaType *pin_mediatype = gst_dshow_new_pin_mediatype (pin); + VIDEOINFOHEADER *video_info = NULL; + + HRESULT hres = enum_mediatypes->Next (1, &pin_mediatype->mediatype, NULL); + if (hres != S_OK || !pin_mediatype->mediatype) { + gst_dshow_free_pin_mediatype (pin_mediatype); + return NULL; + } + + video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat; + + pin_mediatype->defaultWidth = video_info->bmiHeader.biWidth; + pin_mediatype->defaultHeight = video_info->bmiHeader.biHeight; + pin_mediatype->defaultFPS = (gint) (10000000 / video_info->AvgTimePerFrame); + pin_mediatype->granularityWidth = 1; + pin_mediatype->granularityHeight = 1; + + return pin_mediatype; +} + +GstCapturePinMediaType * +gst_dshow_new_pin_mediatype_from_streamcaps (IPin * pin, gint id, IAMStreamConfig * streamcaps) +{ + GstCapturePinMediaType *pin_mediatype = gst_dshow_new_pin_mediatype (pin); + VIDEOINFOHEADER *video_info = NULL; + HRESULT hres = streamcaps->GetStreamCaps (id, &pin_mediatype->mediatype, (BYTE *) & pin_mediatype->vscc); if (FAILED (hres) || !pin_mediatype->mediatype) { @@ -69,8 +109,13 @@ gst_dshow_new_pin_mediatype (IPin * pin, gint id, IAMStreamConfig * streamcaps) return NULL; } - pin->AddRef (); - pin_mediatype->capture_pin = pin; + video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat; + + pin_mediatype->defaultWidth = video_info->bmiHeader.biWidth; + pin_mediatype->defaultHeight = video_info->bmiHeader.biHeight; + pin_mediatype->defaultFPS = (gint) (10000000 / video_info->AvgTimePerFrame); + pin_mediatype->granularityWidth = pin_mediatype->vscc.OutputGranularityX; + pin_mediatype->granularityHeight = pin_mediatype->vscc.OutputGranularityY; return pin_mediatype; } @@ -98,6 +143,7 @@ gst_dshow_check_mediatype (AM_MEDIA_TYPE * media_type, const GUID sub_type, return UuidCompare (&media_type->subtype, (UUID *) & sub_type, &rpcstatus) == 0 && rpcstatus == RPC_S_OK && + //IsEqualGUID (&media_type->subtype, &sub_type) UuidCompare (&media_type->formattype, (UUID *) & format_type, &rpcstatus) == 0 && rpcstatus == RPC_S_OK; } @@ -350,20 +396,24 @@ gst_dshow_show_propertypage (IBaseFilter * base_filter) return ret; } +GstVideoFormat +gst_dshow_guid_to_gst_video_format (AM_MEDIA_TYPE *mediatype) +{ + if (gst_dshow_check_mediatype (mediatype, MEDIASUBTYPE_I420, FORMAT_VideoInfo)) + return GST_VIDEO_FORMAT_I420; + + if (gst_dshow_check_mediatype (mediatype, MEDIASUBTYPE_RGB24, FORMAT_VideoInfo)) + return GST_VIDEO_FORMAT_BGR; + + return GST_VIDEO_FORMAT_UNKNOWN; +} + GstCaps * gst_dshow_new_video_caps (GstVideoFormat video_format, const gchar * name, GstCapturePinMediaType * pin_mediatype) { GstCaps *video_caps = NULL; GstStructure *video_structure = NULL; - VIDEOINFOHEADER *video_info = - (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat; - - pin_mediatype->defaultWidth = video_info->bmiHeader.biWidth; - pin_mediatype->defaultHeight = video_info->bmiHeader.biHeight; - pin_mediatype->defaultFPS = (gint) (10000000 / video_info->AvgTimePerFrame); - pin_mediatype->granularityWidth = pin_mediatype->vscc.OutputGranularityX; - pin_mediatype->granularityHeight = pin_mediatype->vscc.OutputGranularityY; /* raw video format */ switch (video_format) { diff --git a/sys/dshowsrcwrapper/gstdshow.h b/sys/dshowsrcwrapper/gstdshow.h index 0e98b0a..47c34e9 100644 --- a/sys/dshowsrcwrapper/gstdshow.h +++ b/sys/dshowsrcwrapper/gstdshow.h @@ -55,8 +55,15 @@ void gst_dshow_free_pin_mediatype (gpointer pt); void gst_dshow_free_mediatype (AM_MEDIA_TYPE * pmt); /* create a new capture media type that handles dshow video caps of a capture pin */ -GstCapturePinMediaType *gst_dshow_new_pin_mediatype (IPin * pin, gint id, - IAMStreamConfig * streamcaps); +GstCapturePinMediaType *gst_dshow_new_pin_mediatype (IPin * pin); + +/* create a new capture media type from enum mediatype */ +GstCapturePinMediaType * gst_dshow_new_pin_mediatype_from_enum_mediatypes (IPin * pin, + IEnumMediaTypes *enum_mediatypes); + +/* create a new capture media type from streamcaps */ +GstCapturePinMediaType *gst_dshow_new_pin_mediatype_from_streamcaps (IPin * pin, + gint id, IAMStreamConfig * streamcaps); /* free the memory of all mediatypes of the input list if pin mediatype */ void gst_dshow_free_pins_mediatypes (GList * mediatypes); @@ -82,6 +89,9 @@ gchar *gst_dshow_getdevice_from_devicename (const GUID * device_category, /* show the capture filter property page (generally used to setup the device). the page is modal*/ gboolean gst_dshow_show_propertypage (IBaseFilter * base_filter); +/* translate GUID format to gsteamer video format */ +GstVideoFormat gst_dshow_guid_to_gst_video_format (AM_MEDIA_TYPE *mediatype); + /* transform a dshow video caps to a gstreamer video caps */ GstCaps *gst_dshow_new_video_caps (GstVideoFormat video_format, const gchar * name, GstCapturePinMediaType * pin_mediatype); diff --git a/sys/dshowsrcwrapper/gstdshowvideosrc.cpp b/sys/dshowsrcwrapper/gstdshowvideosrc.cpp index 433e2cb..c2f9efe 100644 --- a/sys/dshowsrcwrapper/gstdshowvideosrc.cpp +++ b/sys/dshowsrcwrapper/gstdshowvideosrc.cpp @@ -37,11 +37,6 @@ GST_ELEMENT_DETAILS ("DirectShow video capture source", GST_DEBUG_CATEGORY_STATIC (dshowvideosrc_debug); #define GST_CAT_DEFAULT dshowvideosrc_debug -const GUID MEDIASUBTYPE_I420 - = { 0x30323449, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71} -}; - static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, @@ -103,7 +98,9 @@ static GstFlowReturn gst_dshowvideosrc_create (GstPushSrc * psrc, /*utils*/ static GstCaps *gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * - src, IPin * pin, IAMStreamConfig * streamcaps); + src, IPin * pin); +static GstCaps *gst_dshowvideosrc_getcaps_from_enum_mediatypes (GstDshowVideoSrc * + src, IPin * pin); static gboolean gst_dshowvideosrc_push_buffer (byte * buffer, long size, gpointer src_object, UINT64 start, UINT64 stop); @@ -540,18 +537,16 @@ gst_dshowvideosrc_get_caps (GstBaseSrc * basesrc) /* we only want capture pins */ if (UuidCompare (&pin_category, (UUID *) & PIN_CATEGORY_CAPTURE, &rpcstatus) == 0) { - IAMStreamConfig *streamcaps = NULL; - - if (SUCCEEDED (capture_pin->QueryInterface (IID_IAMStreamConfig, - (LPVOID *) & streamcaps))) { + { GstCaps *caps = - gst_dshowvideosrc_getcaps_from_streamcaps (src, capture_pin, - streamcaps); - + gst_dshowvideosrc_getcaps_from_streamcaps (src, capture_pin); if (caps) { gst_caps_append (src->caps, caps); + } else { + caps = gst_dshowvideosrc_getcaps_from_enum_mediatypes (src, capture_pin); + if (caps) + gst_caps_append (src->caps, caps); } - streamcaps->Release (); } } @@ -564,6 +559,8 @@ gst_dshowvideosrc_get_caps (GstBaseSrc * basesrc) } } + g_print ("caps: %s\n", gst_caps_to_string (src->caps)); + if (unidevice) { g_free (unidevice); } @@ -874,8 +871,7 @@ gst_dshowvideosrc_create (GstPushSrc * psrc, GstBuffer ** buf) } static GstCaps * -gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin, - IAMStreamConfig * streamcaps) +gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin) { GstCaps *caps = NULL; HRESULT hres = S_OK; @@ -883,36 +879,36 @@ gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin, int isize = 0; VIDEO_STREAM_CONFIG_CAPS vscc; int i = 0; + IAMStreamConfig *streamcaps = NULL; - if (!streamcaps) + hres = pin->QueryInterface (IID_IAMStreamConfig, (LPVOID *) & streamcaps); + if (FAILED (hres)) { + GST_ERROR ("Failed to retrieve IAMStreamConfig (error=0x%x)", hres); return NULL; + } streamcaps->GetNumberOfCapabilities (&icount, &isize); - if (isize != sizeof (vscc)) + if (isize != sizeof (vscc)) { + streamcaps->Release (); return NULL; + } caps = gst_caps_new_empty (); - for (; i < icount; i++) { + for (i = 0; i < icount; i++) { GstCapturePinMediaType *pin_mediatype = - gst_dshow_new_pin_mediatype (pin, i, streamcaps); + gst_dshow_new_pin_mediatype_from_streamcaps (pin, i, streamcaps); if (pin_mediatype) { GstCaps *mediacaps = NULL; + GstVideoFormat video_format = + gst_dshow_guid_to_gst_video_format (pin_mediatype->mediatype); - if (gst_dshow_check_mediatype (pin_mediatype->mediatype, - MEDIASUBTYPE_I420, FORMAT_VideoInfo)) { - mediacaps = - gst_dshow_new_video_caps (GST_VIDEO_FORMAT_I420, NULL, - pin_mediatype); - - } else if (gst_dshow_check_mediatype (pin_mediatype->mediatype, - MEDIASUBTYPE_RGB24, FORMAT_VideoInfo)) { - mediacaps = - gst_dshow_new_video_caps (GST_VIDEO_FORMAT_BGR, NULL, + if (video_format != GST_VIDEO_FORMAT_UNKNOWN) { + mediacaps = gst_dshow_new_video_caps (video_format, NULL, pin_mediatype); } else if (gst_dshow_check_mediatype (pin_mediatype->mediatype, @@ -939,10 +935,57 @@ gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin, /* failed to convert dshow caps */ gst_dshow_free_pin_mediatype (pin_mediatype); } + } + } + + streamcaps->Release (); + if (caps && gst_caps_is_empty (caps)) { + gst_caps_unref (caps); + caps = NULL; + } + + return caps; +} + +static GstCaps * +gst_dshowvideosrc_getcaps_from_enum_mediatypes (GstDshowVideoSrc * src, IPin * pin) +{ + GstCaps *caps = NULL; + IEnumMediaTypes *enum_mediatypes = NULL; + HRESULT hres = S_OK; + GstCapturePinMediaType *pin_mediatype = NULL; + + hres = pin->EnumMediaTypes (&enum_mediatypes); + if (FAILED (hres)) { + GST_ERROR ("Failed to retrieve IEnumMediaTypes (error=0x%x)", hres); + return NULL; + } + + caps = gst_caps_new_empty (); + + while ((pin_mediatype = gst_dshow_new_pin_mediatype_from_enum_mediatypes (pin, enum_mediatypes)) != NULL) { + + GstCaps *mediacaps = NULL; + GstVideoFormat video_format = gst_dshow_guid_to_gst_video_format (pin_mediatype->mediatype); + + if (video_format != GST_VIDEO_FORMAT_UNKNOWN) + mediacaps = gst_video_format_new_caps (video_format, + pin_mediatype->defaultWidth, pin_mediatype->defaultHeight, + pin_mediatype->defaultFPS, 1, 1, 1); + + if (mediacaps) { + src->pins_mediatypes = + g_list_append (src->pins_mediatypes, pin_mediatype); + gst_caps_append (caps, mediacaps); + } else { + /* failed to convert dshow caps */ + gst_dshow_free_pin_mediatype (pin_mediatype); } } + enum_mediatypes->Release (); + if (caps && gst_caps_is_empty (caps)) { gst_caps_unref (caps); caps = NULL; diff --git a/win32/vs9/libgstdshowsrcwrapper.vcproj b/win32/vs9/libgstdshowsrcwrapper.vcproj index 1c8d22b..7e51c65 100755 --- a/win32/vs9/libgstdshowsrcwrapper.vcproj +++ b/win32/vs9/libgstdshowsrcwrapper.vcproj @@ -61,7 +61,7 @@ />