]> git.0d.be Git - empathy.git/blobdiff - src/empathy-video-src.c
add an header bar to the main window
[empathy.git] / src / empathy-video-src.c
index ceb344215c99fb3dd7335056cb6f84a499b809f0..41dea2377c3636a6f3f3952c5f621d0b726f2eef 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include "config.h"
+#include "empathy-video-src.h"
 
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <gst/interfaces/colorbalance.h>
+#include <gst/video/colorbalance.h>
 
 #define DEBUG_FLAG EMPATHY_DEBUG_VOIP
-#include <libempathy/empathy-debug.h>
-
-#include "empathy-video-src.h"
+#include "empathy-debug.h"
 
 G_DEFINE_TYPE(EmpathyGstVideoSrc, empathy_video_src, GST_TYPE_BIN)
 
@@ -54,6 +51,12 @@ struct _EmpathyGstVideoSrcPrivate
   GstElement *src;
   /* Element implementing a ColorBalance interface */
   GstElement *balance;
+  /* Elements for resolution and framerate adjustment */
+  GstElement *capsfilter;
+  GstElement *videorate;
+  guint width;
+  guint height;
+  guint framerate;
 };
 
 #define EMPATHY_GST_VIDEO_SRC_GET_PRIVATE(o) \
@@ -105,6 +108,16 @@ error:
   return NULL;
 }
 
+static GstPadProbeReturn
+empathy_video_src_drop_eos (GstPad *pad,
+  GstPadProbeInfo *info,
+  gpointer user_data)
+{
+  if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_EVENT (info)) == GST_EVENT_EOS)
+    return GST_PAD_PROBE_DROP;
+
+  return GST_PAD_PROBE_OK;
+}
 
 static void
 empathy_video_src_init (EmpathyGstVideoSrc *obj)
@@ -116,7 +129,7 @@ empathy_video_src_init (EmpathyGstVideoSrc *obj)
   gchar *str;
 
   /* allocate caps here, so we can update it by optional elements */
-  caps = gst_caps_new_simple ("video/x-raw-yuv",
+  caps = gst_caps_new_simple ("video/x-raw",
     "width", G_TYPE_INT, 320,
     "height", G_TYPE_INT, 240,
     NULL);
@@ -129,29 +142,49 @@ empathy_video_src_init (EmpathyGstVideoSrc *obj)
   /* we need to save our source to priv->src */
   priv->src = element;
 
-  /* videomaxrate is optional as it's part of gst-plugins-bad. So don't
-   * fail if it doesn't exist. */
+  /* Drop EOS events, so that our sinks don't get confused when we restart the
+   * source (triggering an EOS) */
+  src = gst_element_get_static_pad (element, "src");
+
+  gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+    empathy_video_src_drop_eos, NULL, NULL);
+
+  gst_object_unref (src);
+
+  /* videorate with the required properties optional as it needs a currently
+   * unreleased gst-plugins-base 0.10.36 */
   element_back = element;
-  if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
-      element, "videomaxrate")) == NULL)
+  element = empathy_gst_add_to_bin (GST_BIN (obj), element, "videorate");
+
+  if (element != NULL && g_object_class_find_property (
+      G_OBJECT_GET_CLASS (element), "max-rate") != NULL)
     {
-      g_message ("Couldn't add \"videomaxrate\" (gst-plugins-bad missing?)");
-      element = element_back;
+      priv->videorate = element;
+      g_object_set (G_OBJECT (element),
+        "drop-only", TRUE,
+        "average-period", GST_SECOND/2,
+        NULL);
     }
   else
     {
-      gst_caps_set_simple (caps,
-        "framerate", GST_TYPE_FRACTION, 15, 1,
-        NULL);
+      g_message ("videorate missing or doesn't have max-rate property, not"
+        "doing dynamic framerate changes (Needs gst-plugins-base >= 0.10.36)");
+      /* Refcount owned by the bin */
+      gst_bin_remove (GST_BIN (obj), element);
+      element = element_back;
     }
 
+  gst_caps_set_simple (caps,
+      "framerate", GST_TYPE_FRACTION_RANGE, 1, 1, 30, 1,
+      NULL);
+
   str = gst_caps_to_string (caps);
   DEBUG ("Current video src caps are : %s", str);
   g_free (str);
 
   if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
-      element, "ffmpegcolorspace")) == NULL)
-    g_error ("Failed to add \"ffmpegcolorspace\" (gst-plugins-base missing?)");
+      element, "videoconvert")) == NULL)
+    g_error ("Failed to add \"videoconvert\" (gst-plugins-base missing?)");
 
   if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
       element, "videoscale")) == NULL)
@@ -162,6 +195,7 @@ empathy_video_src_init (EmpathyGstVideoSrc *obj)
     g_error (
       "Failed to add \"capsfilter\" (gstreamer core elements missing?)");
 
+  priv->capsfilter = element;
   g_object_set (G_OBJECT (element), "caps", caps, NULL);
 
 
@@ -245,23 +279,41 @@ empathy_video_src_new (void)
   return gst_element_factory_make ("empathyvideosrc", NULL);
 }
 
+static GstColorBalance *
+dup_color_balance (GstElement *src)
+{
+  GstElement *color;
+
+  /* Find something supporting GstColorBalance */
+  color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
+
+  if (color == NULL)
+    return NULL;
+
+  /* colorbalance is wrapped by GstImplementsInterface, we
+   * need to check if it is actually supported for this instance
+   * in its current state before trying to use it */
+  if (!GST_IS_COLOR_BALANCE (color))
+    {
+      g_object_unref (color);
+      return NULL;
+    }
+
+  return GST_COLOR_BALANCE (color);
+}
+
 void
 empathy_video_src_set_channel (GstElement *src,
   EmpathyGstVideoSrcChannel channel, guint percent)
 {
-  GstElement *color;
   GstColorBalance *balance;
   const GList *channels;
   GList *l;
 
-  /* Find something supporting GstColorBalance */
-  color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
-
-  if (color == NULL)
+  balance = dup_color_balance (src);
+  if (balance == NULL)
     return;
 
-  balance = GST_COLOR_BALANCE (color);
-
   channels = gst_color_balance_list_channels (balance);
 
   for (l = (GList *) channels; l != NULL; l = g_list_next (l))
@@ -277,27 +329,22 @@ empathy_video_src_set_channel (GstElement *src,
         }
     }
 
-  g_object_unref (color);
+  g_object_unref (balance);
 }
 
 guint
 empathy_video_src_get_channel (GstElement *src,
   EmpathyGstVideoSrcChannel channel)
 {
-  GstElement *color;
   GstColorBalance *balance;
   const GList *channels;
   GList *l;
   guint percent = 0;
 
-  /* Find something supporting GstColorBalance */
-  color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
-
-  if (color == NULL)
+  balance = dup_color_balance (src);
+  if (balance == NULL)
     return percent;
 
-  balance = GST_COLOR_BALANCE (color);
-
   channels = gst_color_balance_list_channels (balance);
 
   for (l = (GList *) channels; l != NULL; l = g_list_next (l))
@@ -315,7 +362,7 @@ empathy_video_src_get_channel (GstElement *src,
         }
     }
 
-  g_object_unref (color);
+  g_object_unref (balance);
 
   return percent;
 }
@@ -324,20 +371,15 @@ empathy_video_src_get_channel (GstElement *src,
 guint
 empathy_video_src_get_supported_channels (GstElement *src)
 {
-  GstElement *color;
   GstColorBalance *balance;
   const GList *channels;
   GList *l;
   guint result = 0;
 
-  /* Find something supporting GstColorBalance */
-  color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
-
-  if (color == NULL)
+  balance = dup_color_balance (src);
+  if (balance == NULL)
     goto out;
 
-  balance = GST_COLOR_BALANCE (color);
-
   channels = gst_color_balance_list_channels (balance);
 
   for (l = (GList *) channels; l != NULL; l = g_list_next (l))
@@ -355,7 +397,7 @@ empathy_video_src_get_supported_channels (GstElement *src)
         }
     }
 
-  g_object_unref (color);
+  g_object_unref (balance);
 
 out:
   return result;
@@ -370,9 +412,9 @@ empathy_video_src_change_device (EmpathyGstVideoSrc *self,
 
   gst_element_get_state (priv->src, &state, NULL, 0);
 
-  gst_element_set_state (priv->src, GST_STATE_NULL);
+  g_return_if_fail (state == GST_STATE_NULL);
+
   g_object_set (priv->src, "device", device, NULL);
-  gst_element_set_state (priv->src, state);
 }
 
 gchar *
@@ -385,3 +427,60 @@ empathy_video_src_dup_device (EmpathyGstVideoSrc *self)
 
   return device;
 }
+
+void
+empathy_video_src_set_framerate (GstElement *src,
+    guint framerate)
+{
+  EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
+
+  if (priv->videorate)
+    {
+      g_object_set (G_OBJECT (priv->videorate), "max-rate", framerate, NULL);
+    }
+}
+
+void
+empathy_video_src_set_resolution (GstElement *src,
+    guint width,
+    guint height)
+{
+  EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
+  GstCaps *caps;
+  GstPad *srcpad, *peer;
+
+  g_return_if_fail (priv->capsfilter != NULL);
+
+  gst_element_set_locked_state (priv->src, TRUE);
+  gst_element_set_state (priv->src, GST_STATE_NULL);
+
+  srcpad = gst_element_get_static_pad (priv->src, "src");
+  peer = gst_pad_get_peer (srcpad);
+
+  /* Keep a ref as removing it from the bin will loose our reference */
+  gst_object_ref (priv->src);
+  gst_bin_remove (GST_BIN (src), priv->src);
+
+  g_object_get (priv->capsfilter, "caps", &caps, NULL);
+  caps = gst_caps_make_writable (caps);
+
+  gst_caps_set_simple (caps,
+      "width", G_TYPE_INT, width,
+      "height", G_TYPE_INT, height,
+      NULL);
+
+  g_object_set (priv->capsfilter, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  gst_bin_add (GST_BIN (src), priv->src);
+  /* We as the bin own the source again, so drop the temporary ref */
+  gst_object_unref (priv->src);
+
+  gst_pad_link (srcpad, peer);
+
+  gst_element_set_locked_state (priv->src, FALSE);
+  gst_element_sync_state_with_parent (priv->src);
+
+  gst_object_unref (srcpad);
+  gst_object_unref (peer);
+}