Merge remote-tracking branch 'origin/0.10'
[platform/upstream/gstreamer.git] / ges / ges-timeline-pipeline.c
index 7b17763..7be4d4e 100644 (file)
@@ -45,6 +45,7 @@ typedef struct
   GstPad *playsinkpad;
   GstPad *encodebinpad;
   GstPad *blocked_pad;
+  gulong probe_id;
 } OutputChain;
 
 G_DEFINE_TYPE (GESTimelinePipeline, ges_timeline_pipeline, GST_TYPE_PIPELINE);
@@ -216,9 +217,9 @@ ges_timeline_pipeline_update_caps (GESTimelinePipeline * self)
           GST_DEBUG ("Smart Render mode, setting input caps");
           ocaps = gst_encoding_profile_get_input_caps (prof);
           if (track->type == GES_TRACK_TYPE_AUDIO)
-            rcaps = gst_caps_from_string ("audio/x-raw-int;audio/x-raw-float");
+            rcaps = gst_caps_new_empty_simple ("audio/x-raw");
           else
-            rcaps = gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb");
+            rcaps = gst_caps_new_empty_simple ("video/x-raw");
           gst_caps_append (ocaps, rcaps);
           ges_track_set_caps (track, ocaps);
         } else {
@@ -226,9 +227,9 @@ ges_timeline_pipeline_update_caps (GESTimelinePipeline * self)
 
           /* Raw preview or rendering mode */
           if (track->type == GES_TRACK_TYPE_VIDEO)
-            caps = gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb");
+            caps = gst_caps_new_empty_simple ("video/x-raw");
           else if (track->type == GES_TRACK_TYPE_AUDIO)
-            gst_caps_from_string ("audio/x-raw-int;audio/x-raw-float");
+            caps = gst_caps_new_empty_simple ("audio/x-raw");
 
           if (caps) {
             ges_track_set_caps (track, caps);
@@ -267,8 +268,8 @@ ges_timeline_pipeline_change_state (GstElement * element,
         ret = GST_STATE_CHANGE_FAILURE;
         goto done;
       }
-      if (self->
-          priv->mode & (TIMELINE_MODE_RENDER | TIMELINE_MODE_SMART_RENDER))
+      if (self->priv->
+          mode & (TIMELINE_MODE_RENDER | TIMELINE_MODE_SMART_RENDER))
         GST_DEBUG ("rendering => Updating pipeline caps");
       if (!ges_timeline_pipeline_update_caps (self)) {
         GST_ERROR_OBJECT (element, "Error setting the caps for rendering");
@@ -324,6 +325,7 @@ get_compatible_unlinked_pad (GstElement * element, GstPad * pad)
   GstIterator *pads;
   gboolean done = FALSE;
   GstCaps *srccaps;
+  GValue paditem = { 0, };
 
   if (G_UNLIKELY (pad == NULL))
     goto no_pad;
@@ -335,32 +337,28 @@ get_compatible_unlinked_pad (GstElement * element, GstPad * pad)
     pads = gst_element_iterate_sink_pads (element);
   else
     pads = gst_element_iterate_src_pads (element);
-  srccaps = gst_pad_get_caps_reffed (pad);
+  srccaps = gst_pad_query_caps (pad, NULL);
 
   GST_DEBUG ("srccaps %" GST_PTR_FORMAT, srccaps);
 
   while (!done) {
-    gpointer padptr;
-
-    switch (gst_iterator_next (pads, &padptr)) {
+    switch (gst_iterator_next (pads, &paditem)) {
       case GST_ITERATOR_OK:
       {
-        GstPad *testpad = (GstPad *) padptr;
+        GstPad *testpad = g_value_get_object (&paditem);
 
-        if (gst_pad_is_linked (testpad)) {
-          gst_object_unref (testpad);
-        } else {
-          GstCaps *sinkcaps = gst_pad_get_caps_reffed (testpad);
+        if (!gst_pad_is_linked (testpad)) {
+          GstCaps *sinkcaps = gst_pad_query_caps (testpad, NULL);
 
           GST_DEBUG ("sinkccaps %" GST_PTR_FORMAT, sinkcaps);
 
           if (gst_caps_can_intersect (srccaps, sinkcaps)) {
-            res = testpad;
+            res = gst_object_ref (testpad);
             done = TRUE;
-          } else
-            gst_object_unref (testpad);
+          }
           gst_caps_unref (sinkcaps);
         }
+        g_value_reset (&paditem);
       }
         break;
       case GST_ITERATOR_DONE:
@@ -372,6 +370,7 @@ get_compatible_unlinked_pad (GstElement * element, GstPad * pad)
         break;
     }
   }
+  g_value_reset (&paditem);
   gst_iterator_free (pads);
   gst_caps_unref (srccaps);
 
@@ -384,11 +383,12 @@ no_pad:
   }
 }
 
-static void
-pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
+static GstPadProbeReturn
+pad_blocked (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
 {
   /* no nothing */
-  GST_DEBUG_OBJECT (pad, "blocked callback, blocked: %d", blocked);
+  GST_DEBUG_OBJECT (pad, "blocked callback, blocked");
+  return GST_PAD_PROBE_OK;
 }
 
 static void
@@ -397,13 +397,19 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
   OutputChain *chain;
   GESTrack *track;
   GstPad *sinkpad;
+  GstCaps *caps;
   gboolean reconfigured = FALSE;
 
+  caps = gst_pad_query_caps (pad, NULL);
+
   GST_DEBUG_OBJECT (self, "new pad %s:%s , caps:%" GST_PTR_FORMAT,
-      GST_DEBUG_PAD_NAME (pad), GST_PAD_CAPS (pad));
+      GST_DEBUG_PAD_NAME (pad), caps);
 
-  if (G_UNLIKELY (!(track =
-              ges_timeline_get_track_for_pad (self->priv->timeline, pad)))) {
+  gst_caps_unref (caps);
+
+  track = ges_timeline_get_track_for_pad (self->priv->timeline, pad);
+
+  if (G_UNLIKELY (!track)) {
     GST_WARNING_OBJECT (self, "Couldn't find coresponding track !");
     return;
   }
@@ -476,8 +482,9 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
       goto error;
     }
     chain->blocked_pad = tmppad;
-    GST_DEBUG ("blocking pad %" GST_PTR_FORMAT, tmppad);
-    gst_pad_set_blocked_async (tmppad, TRUE, pad_blocked, NULL);
+    GST_DEBUG_OBJECT (tmppad, "blocking pad");
+    chain->probe_id = gst_pad_add_probe (tmppad, GST_PAD_PROBE_TYPE_BLOCK,
+        pad_blocked, NULL, NULL);
 
     GST_DEBUG ("Reconfiguring playsink");
 
@@ -499,11 +506,13 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
       sinkpad = get_compatible_unlinked_pad (self->priv->encodebin, pad);
 
       if (sinkpad == NULL) {
-        GstCaps *caps = gst_pad_get_caps_reffed (pad);
+        GstCaps *caps = gst_pad_query_caps (pad, NULL);
+
         /* If no compatible static pad is available, request a pad */
         g_signal_emit_by_name (self->priv->encodebin, "request-pad", caps,
             &sinkpad);
         gst_caps_unref (caps);
+
         if (G_UNLIKELY (sinkpad == NULL)) {
           GST_ERROR_OBJECT (self, "Couldn't get a pad from encodebin !");
           goto error;
@@ -580,10 +589,11 @@ pad_removed_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
   }
 
   if (chain->blocked_pad) {
-    GST_DEBUG ("unblocking pad %" GST_PTR_FORMAT, chain->blocked_pad);
-    gst_pad_set_blocked_async (chain->blocked_pad, FALSE, pad_blocked, NULL);
+    GST_DEBUG_OBJECT (chain->blocked_pad, "unblocking pad");
+    gst_pad_remove_probe (chain->blocked_pad, chain->probe_id);
     gst_object_unref (chain->blocked_pad);
     chain->blocked_pad = NULL;
+    chain->probe_id = 0;
   }
 
   /* Unlike/remove tee */
@@ -609,8 +619,10 @@ no_more_pads_cb (GstElement * timeline, GESTimelinePipeline * self)
     OutputChain *chain = (OutputChain *) tmp->data;
 
     if (chain->blocked_pad) {
-      GST_DEBUG ("unblocking pad %" GST_PTR_FORMAT, chain->blocked_pad);
-      gst_pad_set_blocked_async (chain->blocked_pad, FALSE, pad_blocked, NULL);
+      GST_DEBUG_OBJECT (chain->blocked_pad, "unblocking pad");
+      gst_pad_remove_probe (chain->blocked_pad, chain->probe_id);
+      chain->probe_id = 0;
+      /* do we need to unref and NULL the pad here? */
     }
   }
 }
@@ -797,36 +809,33 @@ ges_timeline_pipeline_set_mode (GESTimelinePipeline * pipeline,
 }
 
 /**
- * ges_timeline_pipeline_get_thumbnail_buffer:
+ * ges_timeline_pipeline_get_thumbnail:
  * @self: a #GESTimelinePipeline in %GST_STATE_PLAYING or %GST_STATE_PAUSED
  * @caps: (transfer none): caps specifying current format. Use %GST_CAPS_ANY
  * for native size.
  *
- * Returns a #GstBuffer with the currently playing in the format specified by
- * caps. The caller should unref the #gst_buffer_unref when finished. If ANY
+ * Returns a #GstSample with the currently playing image in the format specified by
+ * caps. The caller should free the sample with #gst_sample_unref when finished. If ANY
  * caps are specified, the information will be returned in the whatever format
  * is currently used by the sink. This information can be retrieve from caps
  * associated with the buffer.
  *
- * Returns: (transfer full): a #GstBuffer or %NULL
+ * Returns: (transfer full): a #GstSample or %NULL
  */
 
-GstBuffer *
-ges_timeline_pipeline_get_thumbnail_buffer (GESTimelinePipeline * self,
-    GstCaps * caps)
+GstSample *
+ges_timeline_pipeline_get_thumbnail (GESTimelinePipeline * self, GstCaps * caps)
 {
   GstElement *sink;
-  GstBuffer *buf;
 
   sink = self->priv->playsink;
+
   if (!sink) {
     GST_WARNING ("thumbnailing can only be done if we have a playsink");
     return NULL;
   }
 
-  buf = ges_play_sink_convert_frame (sink, caps);
-
-  return buf;
+  return ges_play_sink_convert_frame (sink, caps);
 }
 
 /**
@@ -842,13 +851,14 @@ ges_timeline_pipeline_get_thumbnail_buffer (GESTimelinePipeline * self,
  * 
  * Returns: %TRUE if the thumbnail was properly save, else %FALSE.
  */
-
+/* FIXME 0.11: save_thumbnail should have a GError parameter */
 gboolean
 ges_timeline_pipeline_save_thumbnail (GESTimelinePipeline * self, int width, int
     height, const gchar * format, const gchar * location)
 {
+  GstMapInfo map_info;
   GstBuffer *b;
-  FILE *fp;
+  GstSample *sample;
   GstCaps *caps;
   gboolean res = TRUE;
 
@@ -860,20 +870,28 @@ ges_timeline_pipeline_save_thumbnail (GESTimelinePipeline * self, int width, int
   if (height > 1)
     gst_caps_set_simple (caps, "height", G_TYPE_INT, height, NULL);
 
-  if (!(b = ges_timeline_pipeline_get_thumbnail_buffer (self, caps))) {
+  if (!(sample = ges_timeline_pipeline_get_thumbnail (self, caps))) {
     gst_caps_unref (caps);
     return res;
   }
 
-  /* FIXME : Use standard glib methods */
-  fp = fopen (location, "w+");
-  if (!fwrite (GST_BUFFER_DATA (b), GST_BUFFER_SIZE (b), 1, fp) || ferror (fp)) {
-    res = FALSE;
+  b = gst_sample_get_buffer (sample);
+  if (gst_buffer_map (b, &map_info, GST_MAP_READ)) {
+    GError *err = NULL;
+
+    if (!g_file_set_contents (location, (const char *) map_info.data,
+            map_info.size, &err)) {
+      GST_WARNING ("Could not save thumbnail: %s", err->message);
+      g_error_free (err);
+      res = FALSE;
+    }
   }
 
-  fclose (fp);
   gst_caps_unref (caps);
+  gst_buffer_unmap (b, &map_info);
   gst_buffer_unref (b);
+  gst_sample_unref (sample);
+
   return res;
 }
 
@@ -883,26 +901,27 @@ ges_timeline_pipeline_save_thumbnail (GESTimelinePipeline * self, int width, int
  * @width: the requested width or -1 for native size
  * @height: the requested height or -1 for native size
  *
- * A convenience method for ges_timeline_pipeline_get_thumbnail_raw which
+ * A convenience method for @ges_timeline_pipeline_get_thumbnail which
  * returns a buffer in 24-bit RGB, optionally scaled to the specified width
  * and height. If -1 is specified for either dimension, it will be left at
  * native size. You can retreive this information from the caps associated
  * with the buffer.
  * 
- * The caller is responsible for unreffing the returned buffer with
- * #gst_buffer_unref.
+ * The caller is responsible for unreffing the returned sample with
+ * #gst_sample_unref.
  *
- * Returns: (transfer full): a #GstBuffer or %NULL
+ * Returns: (transfer full): a #GstSample or %NULL
  */
 
-GstBuffer *
+GstSample *
 ges_timeline_pipeline_get_thumbnail_rgb24 (GESTimelinePipeline * self,
     gint width, gint height)
 {
-  GstBuffer *ret;
+  GstSample *ret;
   GstCaps *caps;
 
-  caps = gst_caps_from_string ("video/x-raw-rgb,bpp=(int)24," "depth=(int)24");
+  caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING,
+      "RGB", NULL);
 
   if (width != -1)
     gst_caps_set_simple (caps, "width", G_TYPE_INT, (gint) width, NULL);
@@ -910,7 +929,7 @@ ges_timeline_pipeline_get_thumbnail_rgb24 (GESTimelinePipeline * self,
   if (height != -1)
     gst_caps_set_simple (caps, "height", G_TYPE_INT, (gint) height, NULL);
 
-  ret = ges_timeline_pipeline_get_thumbnail_buffer (self, caps);
+  ret = ges_timeline_pipeline_get_thumbnail (self, caps);
   gst_caps_unref (caps);
   return ret;
 }