dshowvideosrc: use IEnumMediaTypes when IAMStreamConfig is not usable
authorJulien Isorce <julien.isorce@gmail.com>
Wed, 9 Sep 2009 10:41:17 +0000 (12:41 +0200)
committerJulien Isorce <julien.isorce@gmail.com>
Wed, 9 Sep 2009 10:41:17 +0000 (12:41 +0200)
For some device drivers IAMStreamConfig is not supported.
But EnumMediatypes does not provide range size and framerate.

sys/dshowsrcwrapper/gstdshow.cpp
sys/dshowsrcwrapper/gstdshow.h
sys/dshowsrcwrapper/gstdshowvideosrc.cpp
win32/vs9/libgstdshowsrcwrapper.vcproj

index 86be548..980ff93 100644 (file)
 #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) {
index 0e98b0a..47c34e9 100644 (file)
@@ -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);
index 433e2cb..c2f9efe 100644 (file)
@@ -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;
index 1c8d22b..7e51c65 100755 (executable)
@@ -61,7 +61,7 @@
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib libgstaudio-0.10.lib glib-2.0.lib gmodule-2.0.lib gobject-2.0.lib gthread-2.0.lib winmm.lib rpcrt4.lib strmbasd.lib strmiids.lib"\r
+                               AdditionalDependencies="libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib libgstaudio-0.10.lib libgstvideo-0.10.lib glib-2.0.lib gmodule-2.0.lib gobject-2.0.lib gthread-2.0.lib winmm.lib rpcrt4.lib strmbasd.lib strmiids.lib"\r
                                LinkIncremental="2"\r
                                AdditionalLibraryDirectories="C:\msys\1.0\local\lib;&quot;C:\Program Files\Microsoft SDKs\Windows\v6.1\Lib&quot;;&quot;C:\Program Files\Microsoft SDKs\Windows\v6.1\Samples\Multimedia\DirectShow\BaseClasses\Debug&quot;"\r
                                GenerateDebugInformation="true"\r
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib libgstaudio-0.10.lib glib-2.0.lib gmodule-2.0.lib gobject-2.0.lib gthread-2.0.lib winmm.lib rpcrt4.lib strmbase.lib strmiids.lib"\r
+                               AdditionalDependencies="libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib libgstaudio-0.10.lib libgstvideo-0.10.lib glib-2.0.lib gmodule-2.0.lib gobject-2.0.lib gthread-2.0.lib winmm.lib rpcrt4.lib strmbase.lib strmiids.lib"\r
                                LinkIncremental="1"\r
                                AdditionalLibraryDirectories="C:\msys\1.0\local\lib;&quot;C:\Program Files\Microsoft SDKs\Windows\v6.1\Lib&quot;;&quot;C:\Program Files\Microsoft SDKs\Windows\v6.1\Samples\Multimedia\DirectShow\BaseClasses\Release&quot;"\r
                                GenerateDebugInformation="true"\r
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib libgstaudio-0.10.lib glib-2.0.lib gmodule-2.0.lib gobject-2.0.lib gthread-2.0.lib winmm.lib rpcrt4.lib strmbasd.lib strmiids.lib"\r
+                               AdditionalDependencies="libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib libgstaudio-0.10.lib libgstvideo-0.10.lib glib-2.0.lib gmodule-2.0.lib gobject-2.0.lib gthread-2.0.lib winmm.lib rpcrt4.lib strmbasd.lib strmiids.lib"\r
                                LinkIncremental="2"\r
                                AdditionalLibraryDirectories="C:\msys\1.0\local\lib;&quot;C:\Program Files\Microsoft SDKs\Windows\v6.1\Lib&quot;;&quot;C:\Program Files\Microsoft SDKs\Windows\v6.1\Samples\Multimedia\DirectShow\BaseClasses\Debug_MBCS&quot;"\r
                                GenerateDebugInformation="true"\r
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib libgstaudio-0.10.lib glib-2.0.lib gmodule-2.0.lib gobject-2.0.lib gthread-2.0.lib winmm.lib rpcrt4.lib strmbase.lib strmiids.lib"\r
+                               AdditionalDependencies="libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib libgstaudio-0.10.lib libgstvideo-0.10.lib glib-2.0.lib gmodule-2.0.lib gobject-2.0.lib gthread-2.0.lib winmm.lib rpcrt4.lib strmbase.lib strmiids.lib"\r
                                LinkIncremental="1"\r
                                AdditionalLibraryDirectories="C:\msys\1.0\local\lib;&quot;C:\Program Files\Microsoft SDKs\Windows\v6.1\Lib&quot;;&quot;C:\Program Files\Microsoft SDKs\Windows\v6.1\Samples\Multimedia\DirectShow\BaseClasses\Release_MBCS&quot;"\r
                                GenerateDebugInformation="true"\r