Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst / isomp4 / gstqtmux.c
index ad2baf0..531df78 100644 (file)
@@ -97,7 +97,7 @@
  * <refsect2>
  * <title>Example pipelines</title>
  * |[
- * gst-launch v4l2src num-buffers=500 ! video/x-raw-yuv,width=320,height=240 ! ffmpegcolorspace ! qtmux ! filesink location=video.mov
+ * gst-launch v4l2src num-buffers=500 ! video/x-raw,width=320,height=240 ! ffmpegcolorspace ! qtmux ! filesink location=video.mov
  * ]|
  * Records a video stream captured from a v4l2 device and muxes it into a qt file.
  * </refsect2>
 #include <glib/gstdio.h>
 
 #include <gst/gst.h>
-#include <gst/base/gstcollectpads.h>
+#include <gst/base/gstcollectpads2.h>
+#include <gst/audio/audio.h>
+#include <gst/video/video.h>
 #include <gst/tag/xmpwriter.h>
 
 #include <sys/types.h>
@@ -220,7 +222,7 @@ static void gst_qt_mux_get_property (GObject * object,
 
 /* pad functions */
 static GstPad *gst_qt_mux_request_new_pad (GstElement * element,
-    GstPadTemplate * templ, const gchar * name);
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
 static void gst_qt_mux_release_pad (GstElement * element, GstPad * pad);
 
 /* event */
@@ -263,20 +265,17 @@ gst_qt_mux_base_init (gpointer g_class)
   srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
       GST_PAD_ALWAYS, params->src_caps);
   gst_element_class_add_pad_template (element_class, srctempl);
-  gst_object_unref (srctempl);
 
   if (params->audio_sink_caps) {
-    audiosinktempl = gst_pad_template_new ("audio_%d",
+    audiosinktempl = gst_pad_template_new ("audio_%u",
         GST_PAD_SINK, GST_PAD_REQUEST, params->audio_sink_caps);
     gst_element_class_add_pad_template (element_class, audiosinktempl);
-    gst_object_unref (audiosinktempl);
   }
 
   if (params->video_sink_caps) {
-    videosinktempl = gst_pad_template_new ("video_%d",
+    videosinktempl = gst_pad_template_new ("video_%u",
         GST_PAD_SINK, GST_PAD_REQUEST, params->video_sink_caps);
     gst_element_class_add_pad_template (element_class, videosinktempl);
-    gst_object_unref (videosinktempl);
   }
 
   klass->format = params->prop->format;
@@ -525,20 +524,23 @@ gst_qt_mux_prepare_jpc_buffer (GstQTPad * qtpad, GstBuffer * buf,
     GstQTMux * qtmux)
 {
   GstBuffer *newbuf;
+  GstMapInfo map;
+  gsize size;
 
   GST_LOG_OBJECT (qtmux, "Preparing jpc buffer");
 
   if (buf == NULL)
     return NULL;
 
-  newbuf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) + 8);
-  gst_buffer_copy_metadata (newbuf, buf, GST_BUFFER_COPY_ALL);
+  size = gst_buffer_get_size (buf);
+  newbuf = gst_buffer_new_and_alloc (size + 8);
+  gst_buffer_copy_into (newbuf, buf, GST_BUFFER_COPY_ALL, 8, size);
 
-  GST_WRITE_UINT32_BE (GST_BUFFER_DATA (newbuf), GST_BUFFER_SIZE (newbuf));
-  GST_WRITE_UINT32_LE (GST_BUFFER_DATA (newbuf) + 4, FOURCC_jp2c);
+  gst_buffer_map (newbuf, &map, GST_MAP_WRITE);
+  GST_WRITE_UINT32_BE (map.data, map.size);
+  GST_WRITE_UINT32_LE (map.data + 4, FOURCC_jp2c);
 
-  memcpy (GST_BUFFER_DATA (newbuf) + 8, GST_BUFFER_DATA (buf),
-      GST_BUFFER_SIZE (buf));
+  gst_buffer_unmap (buf, &map);
   gst_buffer_unref (buf);
 
   return newbuf;
@@ -616,7 +618,7 @@ gst_qt_mux_add_mp4_date (GstQTMux * qtmux, const GstTagList * list,
   GDateDay day;
   gchar *str;
 
-  g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_DATE);
+  g_return_if_fail (gst_tag_get_type (tag) == G_TYPE_DATE);
 
   if (!gst_tag_list_get_date (list, tag, &date) || !date)
     return;
@@ -646,20 +648,27 @@ gst_qt_mux_add_mp4_cover (GstQTMux * qtmux, const GstTagList * list,
 {
   GValue value = { 0, };
   GstBuffer *buf;
+  GstSample *sample;
   GstCaps *caps;
   GstStructure *structure;
   gint flags = 0;
+  GstMapInfo map;
 
-  g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_BUFFER);
+  g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_SAMPLE);
 
   if (!gst_tag_list_copy_value (&value, list, tag))
     return;
 
-  buf = gst_value_get_buffer (&value);
+  sample = gst_value_get_sample (&value);
+
+  if (!sample)
+    goto done;
+
+  buf = gst_sample_get_buffer (sample);
   if (!buf)
     goto done;
 
-  caps = gst_buffer_get_caps (buf);
+  caps = gst_sample_get_caps (sample);
   if (!caps) {
     GST_WARNING_OBJECT (qtmux, "preview image without caps");
     goto done;
@@ -672,17 +681,17 @@ gst_qt_mux_add_mp4_cover (GstQTMux * qtmux, const GstTagList * list,
     flags = 13;
   else if (gst_structure_has_name (structure, "image/png"))
     flags = 14;
-  gst_caps_unref (caps);
 
   if (!flags) {
     GST_WARNING_OBJECT (qtmux, "preview image format not supported");
     goto done;
   }
 
+  gst_buffer_map (buf, &map, GST_MAP_READ);
   GST_DEBUG_OBJECT (qtmux, "Adding tag %" GST_FOURCC_FORMAT
-      " -> image size %d", GST_FOURCC_ARGS (fourcc), GST_BUFFER_SIZE (buf));
-  atom_moov_add_tag (qtmux->moov, fourcc, flags, GST_BUFFER_DATA (buf),
-      GST_BUFFER_SIZE (buf));
+      " -> image size %" G_GSIZE_FORMAT "", GST_FOURCC_ARGS (fourcc), map.size);
+  atom_moov_add_tag (qtmux->moov, fourcc, flags, map.data, map.size);
+  gst_buffer_unmap (buf, &map);
 done:
   g_value_unset (&value);
 }
@@ -724,7 +733,7 @@ gst_qt_mux_add_3gp_date (GstQTMux * qtmux, const GstTagList * list,
   GDate *date = NULL;
   GDateYear year;
 
-  g_return_if_fail (gst_tag_get_type (tag) == GST_TYPE_DATE);
+  g_return_if_fail (gst_tag_get_type (tag) == G_TYPE_DATE);
 
   if (!gst_tag_list_get_date (list, tag, &date) || !date)
     return;
@@ -1109,14 +1118,18 @@ gst_qt_mux_add_metadata_tags (GstQTMux * qtmux, const GstTagList * list)
       GstCaps *caps = NULL;
 
       val = gst_tag_list_get_value_index (list, GST_QT_DEMUX_PRIVATE_TAG, i);
-      buf = (GstBuffer *) gst_value_get_mini_object (val);
+      buf = (GstBuffer *) gst_value_get_buffer (val);
 
-      if (buf && (caps = gst_buffer_get_caps (buf))) {
+      /* FIXME-0.11 */
+      if (buf && (caps = NULL /*gst_buffer_get_caps (buf) */ )) {
         GstStructure *s;
         const gchar *style = NULL;
+        GstMapInfo map;
 
-        GST_DEBUG_OBJECT (qtmux, "Found private tag %d/%d; size %d, caps %"
-            GST_PTR_FORMAT, i, num_tags, GST_BUFFER_SIZE (buf), caps);
+        gst_buffer_map (buf, &map, GST_MAP_READ);
+        GST_DEBUG_OBJECT (qtmux,
+            "Found private tag %d/%d; size %" G_GSIZE_FORMAT ", caps %"
+            GST_PTR_FORMAT, i, num_tags, map.size, caps);
         s = gst_caps_get_structure (caps, 0);
         if (s && (style = gst_structure_get_string (s, "style"))) {
           /* try to prevent some style tag ending up into another variant
@@ -1126,10 +1139,10 @@ gst_qt_mux_add_metadata_tags (GstQTMux * qtmux, const GstTagList * list)
               (strcmp (style, "iso") == 0 &&
                   qtmux_klass->format == GST_QT_MUX_FORMAT_3GP)) {
             GST_DEBUG_OBJECT (qtmux, "Adding private tag");
-            atom_moov_add_blob_tag (qtmux->moov, GST_BUFFER_DATA (buf),
-                GST_BUFFER_SIZE (buf));
+            atom_moov_add_blob_tag (qtmux->moov, map.data, map.size);
           }
         }
+        gst_buffer_unmap (buf, &map);
         gst_caps_unref (caps);
       }
     }
@@ -1176,8 +1189,8 @@ _gst_buffer_new_take_data (guint8 * data, guint size)
   GstBuffer *buf;
 
   buf = gst_buffer_new ();
-  GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
-  GST_BUFFER_SIZE (buf) = size;
+  gst_buffer_take_memory (buf, -1,
+      gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
 
   return buf;
 }
@@ -1187,21 +1200,21 @@ gst_qt_mux_send_buffer (GstQTMux * qtmux, GstBuffer * buf, guint64 * offset,
     gboolean mind_fast)
 {
   GstFlowReturn res;
-  guint8 *data;
-  guint size;
+  gsize size;
 
   g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
 
-  data = GST_BUFFER_DATA (buf);
-  size = GST_BUFFER_SIZE (buf);
-
-  GST_LOG_OBJECT (qtmux, "sending buffer size %d", size);
+  size = gst_buffer_get_size (buf);
+  GST_LOG_OBJECT (qtmux, "sending buffer size %" G_GSIZE_FORMAT, size);
 
   if (mind_fast && qtmux->fast_start_file) {
+    GstMapInfo map;
     gint ret;
 
     GST_LOG_OBJECT (qtmux, "to temporary file");
-    ret = fwrite (data, sizeof (guint8), size, qtmux->fast_start_file);
+    gst_buffer_map (buf, &map, GST_MAP_READ);
+    ret = fwrite (map.data, sizeof (guint8), map.size, qtmux->fast_start_file);
+    gst_buffer_unmap (buf, &map);
     gst_buffer_unref (buf);
     if (ret != size)
       goto write_error;
@@ -1209,9 +1222,6 @@ gst_qt_mux_send_buffer (GstQTMux * qtmux, GstBuffer * buf, guint64 * offset,
       res = GST_FLOW_OK;
   } else {
     GST_LOG_OBJECT (qtmux, "downstream");
-
-    buf = gst_buffer_make_metadata_writable (buf);
-    gst_buffer_set_caps (buf, GST_PAD_CAPS (qtmux->srcpad));
     res = gst_pad_push (qtmux->srcpad, buf);
   }
 
@@ -1262,16 +1272,20 @@ gst_qt_mux_send_buffered_data (GstQTMux * qtmux, guint64 * offset)
    * (somehow optimize copy?) */
   GST_DEBUG_OBJECT (qtmux, "Sending buffered data");
   while (ret == GST_FLOW_OK) {
-    gint r;
     const int bufsize = 4096;
+    GstMapInfo map;
+    gsize size;
 
     buf = gst_buffer_new_and_alloc (bufsize);
-    r = fread (GST_BUFFER_DATA (buf), sizeof (guint8), bufsize,
-        qtmux->fast_start_file);
-    if (r == 0)
+    gst_buffer_map (buf, &map, GST_MAP_WRITE);
+    size = fread (map.data, sizeof (guint8), bufsize, qtmux->fast_start_file);
+    if (size == 0) {
+      gst_buffer_unmap (buf, &map);
       break;
-    GST_BUFFER_SIZE (buf) = r;
-    GST_LOG_OBJECT (qtmux, "Pushing buffered buffer of size %d", r);
+    }
+    GST_LOG_OBJECT (qtmux, "Pushing buffered buffer of size %d",
+        (gint) map.size);
+    gst_buffer_unmap (buf, &map);
     ret = gst_qt_mux_send_buffer (qtmux, buf, offset, FALSE);
     buf = NULL;
   }
@@ -1368,9 +1382,10 @@ static GstFlowReturn
 gst_qt_mux_update_mdat_size (GstQTMux * qtmux, guint64 mdat_pos,
     guint64 mdat_size, guint64 * offset)
 {
-  GstEvent *event;
   GstBuffer *buf;
   gboolean large_file;
+  GstSegment segment;
+  GstMapInfo map;
 
   large_file = (mdat_size > MDAT_LARGE_FILE_LIMIT);
 
@@ -1378,23 +1393,23 @@ gst_qt_mux_update_mdat_size (GstQTMux * qtmux, guint64 mdat_pos,
     mdat_pos += 8;
 
   /* seek and rewrite the header */
-  event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
-      mdat_pos, GST_CLOCK_TIME_NONE, 0);
-  gst_pad_push_event (qtmux->srcpad, event);
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  segment.start = mdat_pos;
+  gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
 
   if (large_file) {
     buf = gst_buffer_new_and_alloc (sizeof (guint64));
-    GST_WRITE_UINT64_BE (GST_BUFFER_DATA (buf), mdat_size + 16);
+    gst_buffer_map (buf, &map, GST_MAP_WRITE);
+    GST_WRITE_UINT64_BE (map.data, mdat_size + 16);
   } else {
-    guint8 *data;
-
     buf = gst_buffer_new_and_alloc (16);
-    data = GST_BUFFER_DATA (buf);
-    GST_WRITE_UINT32_BE (data, 8);
-    GST_WRITE_UINT32_LE (data + 4, FOURCC_free);
-    GST_WRITE_UINT32_BE (data + 8, mdat_size + 8);
-    GST_WRITE_UINT32_LE (data + 12, FOURCC_mdat);
+    gst_buffer_map (buf, &map, GST_MAP_WRITE);
+    GST_WRITE_UINT32_BE (map.data, 8);
+    GST_WRITE_UINT32_LE (map.data + 4, FOURCC_free);
+    GST_WRITE_UINT32_BE (map.data + 8, mdat_size + 8);
+    GST_WRITE_UINT32_LE (map.data + 12, FOURCC_mdat);
   }
+  gst_buffer_unmap (buf, &map);
 
   return gst_qt_mux_send_buffer (qtmux, buf, offset, FALSE);
 }
@@ -1481,14 +1496,17 @@ gst_qt_mux_set_header_on_caps (GstQTMux * mux, GstBuffer * buf)
   GstStructure *structure;
   GValue array = { 0 };
   GValue value = { 0 };
-  GstCaps *caps;
+  GstCaps *caps, *tcaps;
+
+  tcaps = gst_pad_get_current_caps (mux->srcpad);
+  caps = gst_caps_copy (tcaps);
+  gst_caps_unref (tcaps);
 
-  caps = gst_caps_copy (GST_PAD_CAPS (mux->srcpad));
   structure = gst_caps_get_structure (caps, 0);
 
   g_value_init (&array, GST_TYPE_ARRAY);
 
-  GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+  GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
   g_value_init (&value, GST_TYPE_BUFFER);
   gst_value_take_buffer (&value, gst_buffer_ref (buf));
   gst_value_array_append_value (&array, &value);
@@ -1603,6 +1621,7 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
 {
   GstFlowReturn ret = GST_FLOW_OK;
   GstCaps *caps;
+  GstSegment segment;
 
   GST_DEBUG_OBJECT (qtmux, "starting file");
 
@@ -1623,24 +1642,24 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
       gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
       GST_INFO_OBJECT (qtmux, "downstream is %sseekable",
           seekable ? "" : "not ");
-      if (!seekable) {
-        qtmux->streamable = TRUE;
-        g_object_notify (G_OBJECT (qtmux), "streamable");
-        GST_WARNING_OBJECT (qtmux, "downstream is not seekable, but "
-            "streamable=false. Will ignore that and create streamable output "
-            "instead");
-      }
     } else {
       /* have to assume seeking is supported if query not handled downstream */
-      /* FIXME 0.11: change to query not handled => seeking not supported */
       GST_WARNING_OBJECT (qtmux, "downstream did not handle seeking query");
+      seekable = FALSE;
+    }
+    if (!seekable) {
+      qtmux->streamable = TRUE;
+      g_object_notify (G_OBJECT (qtmux), "streamable");
+      GST_WARNING_OBJECT (qtmux, "downstream is not seekable, but "
+          "streamable=false. Will ignore that and create streamable output "
+          "instead");
     }
     gst_query_unref (query);
   }
 
   /* let downstream know we think in BYTES and expect to do seeking later on */
-  gst_pad_push_event (qtmux->srcpad,
-      gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0));
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
 
   /* initialize our moov recovery file */
   GST_OBJECT_LOCK (qtmux);
@@ -1823,7 +1842,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
   }
 
   if (qtmux->fragment_sequence) {
-    GstEvent *event;
+    GstSegment segment;
 
     if (qtmux->mfra) {
       guint8 *data = NULL;
@@ -1843,7 +1862,6 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
       return GST_FLOW_OK;
     }
 
-
     timescale = qtmux->timescale;
     /* only mvex duration is updated,
      * mvhd should be consistent with empty moov
@@ -1853,9 +1871,9 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
     GST_DEBUG_OBJECT (qtmux, "rewriting moov with mvex duration %"
         GST_TIME_FORMAT, GST_TIME_ARGS (first_ts));
     /* seek and rewrite the header */
-    event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
-        qtmux->mdat_pos, GST_CLOCK_TIME_NONE, 0);
-    gst_pad_push_event (qtmux->srcpad, event);
+    gst_segment_init (&segment, GST_FORMAT_BYTES);
+    segment.start = qtmux->mdat_pos;
+    gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
     /* no need to seek back */
     return gst_qt_mux_send_moov (qtmux, NULL, FALSE);
   }
@@ -2011,14 +2029,15 @@ flush:
     pad->traf = NULL;
     atom_moof_copy_data (moof, &data, &size, &offset);
     buffer = _gst_buffer_new_take_data (data, offset);
-    GST_LOG_OBJECT (qtmux, "writing moof size %d", GST_BUFFER_SIZE (buffer));
+    GST_LOG_OBJECT (qtmux, "writing moof size %" G_GSIZE_FORMAT,
+        gst_buffer_get_size (buffer));
     ret = gst_qt_mux_send_buffer (qtmux, buffer, &qtmux->header_size, FALSE);
 
     /* and actual data */
     total_size = 0;
     for (i = 0; i < atom_array_get_len (&pad->fragment_buffers); i++) {
       total_size +=
-          GST_BUFFER_SIZE (atom_array_index (&pad->fragment_buffers, i));
+          gst_buffer_get_size (atom_array_index (&pad->fragment_buffers, i));
     }
 
     GST_LOG_OBJECT (qtmux, "writing %d buffers, total_size %d",
@@ -2142,7 +2161,7 @@ gst_qt_mux_get_asc_buffer_ts (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf)
     buf = pad->buf_entries[pad->buf_head];
     pad->buf_entries[pad->buf_head++] = NULL;
     pad->buf_head %= wrap;
-    buf = gst_buffer_make_metadata_writable (buf);
+    buf = gst_buffer_make_writable (buf);
     /* track original ts (= pts ?) for later */
     GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_TIMESTAMP (buf);
     GST_BUFFER_TIMESTAMP (buf) = ts;
@@ -2181,7 +2200,7 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf)
 
   if (G_LIKELY (buf != NULL && GST_CLOCK_TIME_IS_VALID (pad->first_ts) &&
           pad->first_ts != 0)) {
-    buf = gst_buffer_make_metadata_writable (buf);
+    buf = gst_buffer_make_writable (buf);
     check_and_subtract_ts (qtmux, &GST_BUFFER_TIMESTAMP (buf), pad->first_ts);
   }
   /* when we obtain the first_ts we subtract from all stored buffers we have,
@@ -2344,7 +2363,7 @@ again:
 
   /* for computing the avg bitrate */
   if (G_LIKELY (last_buf)) {
-    pad->total_bytes += GST_BUFFER_SIZE (last_buf);
+    pad->total_bytes += gst_buffer_get_size (last_buf);
     pad->total_duration += duration;
   }
 
@@ -2359,7 +2378,7 @@ again:
        buffer (= chunk)), but can also be fixed-packet-size codecs like ADPCM
      */
     sample_size = pad->sample_size;
-    if (GST_BUFFER_SIZE (last_buf) % sample_size != 0)
+    if (gst_buffer_get_size (last_buf) % sample_size != 0)
       goto fragmented_sample;
     /* note: qt raw audio storage warps it implicitly into a timewise
      * perfect stream, discarding buffer times */
@@ -2367,7 +2386,7 @@ again:
       nsamples = gst_util_uint64_scale_round (GST_BUFFER_DURATION (last_buf),
           atom_trak_get_timescale (pad->trak), GST_SECOND);
     } else {
-      nsamples = GST_BUFFER_SIZE (last_buf) / sample_size;
+      nsamples = gst_buffer_get_size (last_buf) / sample_size;
     }
     duration = GST_BUFFER_DURATION (last_buf) / nsamples;
 
@@ -2376,7 +2395,7 @@ again:
     pad->last_dts += duration * nsamples;
   } else {
     nsamples = 1;
-    sample_size = GST_BUFFER_SIZE (last_buf);
+    sample_size = gst_buffer_get_size (last_buf);
     if (pad->have_dts) {
       gint64 scaled_dts;
       pad->last_dts = GST_BUFFER_OFFSET_END (last_buf);
@@ -2547,7 +2566,7 @@ gst_qt_mux_handle_buffer (GstCollectPads2 * pads, GstCollectData2 * cdata,
   }
 
   if (G_UNLIKELY (qtmux->state == GST_QT_MUX_STATE_EOS))
-    return GST_FLOW_UNEXPECTED;
+    return GST_FLOW_EOS;
 
   best_pad = (GstQTPad *) cdata;
 
@@ -2563,7 +2582,7 @@ gst_qt_mux_handle_buffer (GstCollectPads2 * pads, GstCollectData2 * cdata,
     if (ret == GST_FLOW_OK) {
       GST_DEBUG_OBJECT (qtmux, "Pushing eos");
       gst_pad_push_event (qtmux->srcpad, gst_event_new_eos ());
-      ret = GST_FLOW_UNEXPECTED;
+      ret = GST_FLOW_EOS;
     } else {
       GST_WARNING_OBJECT (qtmux, "Failed to stop file: %s",
           gst_flow_get_name (ret));
@@ -2621,19 +2640,19 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
    * the old caps are a subset of the new one (this means upstream
    * added more info to the caps, as both should be 'fixed' caps) */
   if (qtpad->fourcc) {
-    GstCaps *current_caps = NULL;
-    gboolean is_subset;
-    g_object_get (pad, "caps", &current_caps, NULL);
+    GstCaps *current_caps;
+
+    current_caps = gst_pad_get_current_caps (pad);
     g_assert (caps != NULL);
 
-    is_subset = gst_qtmux_caps_is_subset_full (qtmux, current_caps, caps);
-    gst_caps_unref (current_caps);
-    if (!is_subset) {
+    if (!gst_qtmux_caps_is_subset_full (qtmux, current_caps, caps)) {
+      gst_caps_unref (current_caps);
       goto refuse_renegotiation;
     }
     GST_DEBUG_OBJECT (qtmux,
         "pad %s accepted renegotiation to %" GST_PTR_FORMAT " from %"
-        GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, GST_PAD_CAPS (pad));
+        GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, current_caps);
+    gst_caps_unref (current_caps);
   }
 
   GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT,
@@ -2710,11 +2729,12 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
               "assuming 'raw'");
         }
 
-        if (!codec_data || GST_BUFFER_SIZE (codec_data) < 2)
+        if (!codec_data || gst_buffer_get_size ((GstBuffer *) codec_data) < 2)
           GST_WARNING_OBJECT (qtmux, "no (valid) codec_data for AAC audio");
         else {
-          guint8 profile = GST_READ_UINT8 (GST_BUFFER_DATA (codec_data));
+          guint8 profile;
 
+          gst_buffer_extract ((GstBuffer *) codec_data, 0, &profile, 1);
           /* warn if not Low Complexity profile */
           profile >>= 3;
           if (profile != 2)
@@ -2749,51 +2769,38 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
     entry.samples_per_packet = 320;
     entry.bytes_per_sample = 2;
     ext_atom = build_amr_extension ();
-  } else if (strcmp (mimetype, "audio/x-raw-int") == 0) {
-    gint width;
-    gint depth;
-    gint endianness;
-    gboolean sign;
-
-    if (!gst_structure_get_int (structure, "width", &width) ||
-        !gst_structure_get_int (structure, "depth", &depth) ||
-        !gst_structure_get_boolean (structure, "signed", &sign)) {
-      GST_DEBUG_OBJECT (qtmux, "broken caps, width/depth/signed field missing");
-      goto refuse_caps;
-    }
+  } else if (strcmp (mimetype, "audio/x-raw") == 0) {
+    GstAudioInfo info;
 
-    if (depth <= 8) {
-      endianness = G_BYTE_ORDER;
-    } else if (!gst_structure_get_int (structure, "endianness", &endianness)) {
-      GST_DEBUG_OBJECT (qtmux, "broken caps, endianness field missing");
+    gst_audio_info_init (&info);
+    if (!gst_audio_info_from_caps (&info, caps))
       goto refuse_caps;
-    }
 
     /* spec has no place for a distinction in these */
-    if (width != depth) {
+    if (info.finfo->width != info.finfo->depth) {
       GST_DEBUG_OBJECT (qtmux, "width must be same as depth!");
       goto refuse_caps;
     }
 
-    if (sign) {
-      if (endianness == G_LITTLE_ENDIAN)
+    if ((info.finfo->flags & GST_AUDIO_FORMAT_FLAG_SIGNED)) {
+      if (info.finfo->endianness == G_LITTLE_ENDIAN)
         entry.fourcc = FOURCC_sowt;
-      else if (endianness == G_BIG_ENDIAN)
+      else if (info.finfo->endianness == G_BIG_ENDIAN)
         entry.fourcc = FOURCC_twos;
       /* maximum backward compatibility; only new version for > 16 bit */
-      if (depth <= 16)
+      if (info.finfo->depth <= 16)
         entry.version = 0;
       /* not compressed in any case */
       entry.compression_id = 0;
       /* QT spec says: max at 16 bit even if sample size were actually larger,
        * however, most players (e.g. QuickTime!) seem to disagree, so ... */
-      entry.sample_size = depth;
-      entry.bytes_per_sample = depth / 8;
+      entry.sample_size = info.finfo->depth;
+      entry.bytes_per_sample = info.finfo->depth / 8;
       entry.samples_per_packet = 1;
-      entry.bytes_per_packet = depth / 8;
-      entry.bytes_per_frame = entry.bytes_per_packet * channels;
+      entry.bytes_per_packet = info.finfo->depth / 8;
+      entry.bytes_per_frame = entry.bytes_per_packet * info.channels;
     } else {
-      if (width == 8 && depth == 8) {
+      if (info.finfo->width == 8 && info.finfo->depth == 8) {
         /* fall back to old 8-bit version */
         entry.fourcc = FOURCC_raw_;
         entry.version = 0;
@@ -2804,7 +2811,7 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
         goto refuse_caps;
       }
     }
-    constant_size = (depth / 8) * channels;
+    constant_size = (info.finfo->depth / 8) * info.channels;
   } else if (strcmp (mimetype, "audio/x-alaw") == 0) {
     entry.fourcc = FOURCC_alaw;
     entry.samples_per_packet = 1023;
@@ -2841,19 +2848,24 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
   } else if (strcmp (mimetype, "audio/x-alac") == 0) {
     GstBuffer *codec_config;
     gint len;
+    GstMapInfo map;
 
     entry.fourcc = FOURCC_alac;
+    gst_buffer_map ((GstBuffer *) codec_data, &map, GST_MAP_READ);
     /* let's check if codec data already comes with 'alac' atom prefix */
-    if (!codec_data || (len = GST_BUFFER_SIZE (codec_data)) < 28) {
+    if (!codec_data || (len = map.size) < 28) {
       GST_DEBUG_OBJECT (qtmux, "broken caps, codec data missing");
+      gst_buffer_unmap ((GstBuffer *) codec_data, &map);
       goto refuse_caps;
     }
-    if (GST_READ_UINT32_LE (GST_BUFFER_DATA (codec_data) + 4) == FOURCC_alac) {
+    if (GST_READ_UINT32_LE (map.data + 4) == FOURCC_alac) {
       len -= 8;
-      codec_config = gst_buffer_create_sub ((GstBuffer *) codec_data, 8, len);
+      codec_config =
+          gst_buffer_copy_region ((GstBuffer *) codec_data, 0, 8, len);
     } else {
       codec_config = gst_buffer_ref ((GstBuffer *) codec_data);
     }
+    gst_buffer_unmap ((GstBuffer *) codec_data, &map);
     if (len != 28) {
       /* does not look good, but perhaps some trailing unneeded stuff */
       GST_WARNING_OBJECT (qtmux, "unexpected codec-data size, possibly broken");
@@ -2863,9 +2875,10 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
     else
       ext_atom = build_codec_data_extension (FOURCC_alac, codec_config);
     /* set some more info */
+    gst_buffer_map (codec_config, &map, GST_MAP_READ);
     entry.bytes_per_sample = 2;
-    entry.samples_per_packet =
-        GST_READ_UINT32_BE (GST_BUFFER_DATA (codec_config) + 4);
+    entry.samples_per_packet = GST_READ_UINT32_BE (map.data + 4);
+    gst_buffer_unmap (codec_config, &map);
     gst_buffer_unref (codec_config);
   }
 
@@ -2946,19 +2959,19 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
    * the old caps are a subset of the new one (this means upstream
    * added more info to the caps, as both should be 'fixed' caps) */
   if (qtpad->fourcc) {
-    GstCaps *current_caps = NULL;
-    gboolean is_subset;
-    g_object_get (pad, "caps", &current_caps, NULL);
+    GstCaps *current_caps;
+
+    current_caps = gst_pad_get_current_caps (pad);
     g_assert (caps != NULL);
 
-    is_subset = gst_qtmux_caps_is_subset_full (qtmux, current_caps, caps);
-    gst_caps_unref (current_caps);
-    if (!is_subset) {
+    if (!gst_qtmux_caps_is_subset_full (qtmux, current_caps, caps)) {
+      gst_caps_unref (current_caps);
       goto refuse_renegotiation;
     }
     GST_DEBUG_OBJECT (qtmux,
         "pad %s accepted renegotiation to %" GST_PTR_FORMAT " from %"
-        GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, GST_PAD_CAPS (pad));
+        GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, current_caps);
+    gst_caps_unref (current_caps);
   }
 
   GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT,
@@ -3013,24 +3026,29 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
   sync = TRUE;
 
   /* now map onto a fourcc, and some extra properties */
-  if (strcmp (mimetype, "video/x-raw-rgb") == 0) {
-    gint bpp;
+  if (strcmp (mimetype, "video/x-raw") == 0) {
+    const gchar *format;
+    GstVideoFormat fmt;
+    const GstVideoFormatInfo *vinfo;
 
-    entry.fourcc = FOURCC_raw_;
-    gst_structure_get_int (structure, "bpp", &bpp);
-    entry.depth = bpp;
-    sync = FALSE;
-  } else if (strcmp (mimetype, "video/x-raw-yuv") == 0) {
-    guint32 format = 0;
+    format = gst_structure_get_string (structure, "format");
+    fmt = gst_video_format_from_string (format);
+    vinfo = gst_video_format_get_info (fmt);
 
-    sync = FALSE;
-    gst_structure_get_fourcc (structure, "format", &format);
-    switch (format) {
-      case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
+    switch (fmt) {
+      case GST_VIDEO_FORMAT_UYVY:
         if (depth == -1)
           depth = 24;
         entry.fourcc = FOURCC_2vuy;
         entry.depth = depth;
+        sync = FALSE;
+        break;
+      default:
+        if (GST_VIDEO_FORMAT_INFO_FLAGS (vinfo) & GST_VIDEO_FORMAT_FLAG_RGB) {
+          entry.fourcc = FOURCC_raw_;
+          entry.depth = GST_VIDEO_FORMAT_INFO_PSTRIDE (vinfo, 0) * 8;
+          sync = FALSE;
+        }
         break;
     }
   } else if (strcmp (mimetype, "video/x-h263") == 0) {
@@ -3168,7 +3186,7 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
     sync = FALSE;
   } else if (strcmp (mimetype, "image/x-j2c") == 0 ||
       strcmp (mimetype, "image/x-jpc") == 0) {
-    guint32 fourcc;
+    const gchar *colorspace;
     const GValue *cmap_array;
     const GValue *cdef_array;
     gint ncomp = 0;
@@ -3186,9 +3204,11 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
     ext_atom = NULL;
     entry.fourcc = FOURCC_mjp2;
     sync = FALSE;
-    if (gst_structure_get_fourcc (structure, "fourcc", &fourcc) &&
+
+    colorspace = gst_structure_get_string (structure, "colorspace");
+    if (colorspace &&
         (ext_atom =
-            build_jp2h_extension (qtpad->trak, width, height, fourcc, ncomp,
+            build_jp2h_extension (qtpad->trak, width, height, colorspace, ncomp,
                 cmap_array, cdef_array)) != NULL) {
       ext_atom_list = g_list_append (ext_atom_list, ext_atom);
 
@@ -3212,13 +3232,13 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
   } else if (strcmp (mimetype, "video/x-qt-part") == 0) {
     guint32 fourcc;
 
-    gst_structure_get_fourcc (structure, "format", &fourcc);
+    gst_structure_get_uint (structure, "format", &fourcc);
     entry.fourcc = fourcc;
     qtpad->have_dts = TRUE;
   } else if (strcmp (mimetype, "video/x-mp4-part") == 0) {
     guint32 fourcc;
 
-    gst_structure_get_fourcc (structure, "format", &fourcc);
+    gst_structure_get_uint (structure, "format", &fourcc);
     entry.fourcc = fourcc;
     qtpad->have_dts = TRUE;
   }
@@ -3246,8 +3266,8 @@ refuse_caps:
 refuse_renegotiation:
   {
     GST_WARNING_OBJECT (qtmux,
-        "pad %s refused renegotiation to %" GST_PTR_FORMAT " from %"
-        GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, GST_PAD_CAPS (pad));
+        "pad %s refused renegotiation to %" GST_PTR_FORMAT, GST_PAD_NAME (pad),
+        caps);
     gst_object_unref (qtmux);
     return FALSE;
   }
@@ -3260,9 +3280,26 @@ gst_qt_mux_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
   GstQTMux *qtmux;
   guint32 avg_bitrate = 0, max_bitrate = 0;
   GstPad *pad = data->pad;
+  gboolean ret = FALSE;
 
   qtmux = GST_QT_MUX_CAST (user_data);
   switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+      GstQTPad *collect_pad;
+
+      gst_event_parse_caps (event, &caps);
+
+      /* find stream data */
+      collect_pad = (GstQTPad *) gst_pad_get_element_private (pad);
+      g_assert (collect_pad);
+      g_assert (collect_pad->set_caps);
+
+      ret = collect_pad->set_caps (pad, caps);
+      gst_event_unref (event);
+      break;
+    }
     case GST_EVENT_TAG:{
       GstTagList *list;
       GstTagSetter *setter = GST_TAG_SETTER (qtmux);
@@ -3289,14 +3326,21 @@ gst_qt_mux_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
           qtpad->max_bitrate = max_bitrate;
       }
 
+      gst_event_unref (event);
+      ret = TRUE;
       break;
     }
     default:
+      ret = gst_pad_event_default (data->pad, GST_OBJECT (qtmux), event);
+      break;
+    case GST_EVENT_EOS:
+    case GST_EVENT_SEGMENT:
+      gst_event_unref (event);
+      ret = TRUE;
       break;
   }
 
-  /* now GstCollectPads2 can take care of the rest, e.g. EOS */
-  return FALSE;
+  return ret;
 }
 
 static void
@@ -3323,7 +3367,7 @@ gst_qt_mux_release_pad (GstElement * element, GstPad * pad)
 
 static GstPad *
 gst_qt_mux_request_new_pad (GstElement * element,
-    GstPadTemplate * templ, const gchar * req_name)
+    GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
 {
   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
   GstQTMux *qtmux = GST_QT_MUX_CAST (element);
@@ -3331,6 +3375,7 @@ gst_qt_mux_request_new_pad (GstElement * element,
   GstPad *newpad;
   gboolean audio;
   gchar *name;
+  gint pad_id;
 
   if (templ->direction != GST_PAD_SINK)
     goto wrong_direction;
@@ -3338,12 +3383,20 @@ gst_qt_mux_request_new_pad (GstElement * element,
   if (qtmux->state > GST_QT_MUX_STATE_STARTED)
     goto too_late;
 
-  if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
+  if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
     audio = TRUE;
-    name = g_strdup_printf ("audio_%02d", qtmux->audio_pads++);
-  } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
+    if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
+      name = g_strdup (req_name);
+    } else {
+      name = g_strdup_printf ("audio_%u", qtmux->audio_pads++);
+    }
+  } else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
     audio = FALSE;
-    name = g_strdup_printf ("video_%02d", qtmux->video_pads++);
+    if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
+      name = g_strdup (req_name);
+    } else {
+      name = g_strdup_printf ("video_%u", qtmux->video_pads++);
+    }
   } else
     goto wrong_template;
 
@@ -3364,11 +3417,9 @@ gst_qt_mux_request_new_pad (GstElement * element,
 
   /* set up pad functions */
   if (audio)
-    gst_pad_set_setcaps_function (newpad,
-        GST_DEBUG_FUNCPTR (gst_qt_mux_audio_sink_set_caps));
+    collect_pad->set_caps = GST_DEBUG_FUNCPTR (gst_qt_mux_audio_sink_set_caps);
   else
-    gst_pad_set_setcaps_function (newpad,
-        GST_DEBUG_FUNCPTR (gst_qt_mux_video_sink_set_caps));
+    collect_pad->set_caps = GST_DEBUG_FUNCPTR (gst_qt_mux_video_sink_set_caps);
 
   gst_pad_set_active (newpad, TRUE);
   gst_element_add_pad (element, newpad);