gst/matroska/: Add SimpleBlock support to matroska demuxer and muxer (part of
authorTim-Philipp Müller <tim@centricular.net>
Fri, 28 Oct 2005 15:32:48 +0000 (15:32 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Fri, 28 Oct 2005 15:32:48 +0000 (15:32 +0000)
Original commit message from CVS:
Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
* gst/matroska/matroska-demux.c: (gst_matroska_demux_init_stream),
(gst_matroska_demux_parse_info),
(gst_matroska_demux_parse_blockgroup_or_simpleblock),
(gst_matroska_demux_parse_cluster):
* gst/matroska/matroska-ids.h:
* gst/matroska/matroska-mux.c: (gst_matroska_mux_class_init),
(gst_matroska_mux_init), (gst_matroska_mux_start),
(gst_matroska_mux_create_buffer_header),
(gst_matroska_mux_write_data), (gst_matroska_mux_set_property),
(gst_matroska_mux_get_property):
* gst/matroska/matroska-mux.h:
Add SimpleBlock support to matroska demuxer and muxer (part of
Matroska v2). (#319731)

ChangeLog
gst/matroska/matroska-demux.c
gst/matroska/matroska-ids.h
gst/matroska/matroska-mux.c
gst/matroska/matroska-mux.h

index 4422223..c2ad96d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2005-10-28  Michal Benes  <michal dot benes at xeris dot cz>
+
+       Reviewed by: Tim-Philipp Müller  <tim at centricular dot net>
+
+       * gst/matroska/matroska-demux.c: (gst_matroska_demux_init_stream),
+       (gst_matroska_demux_parse_info),
+       (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+       (gst_matroska_demux_parse_cluster):
+       * gst/matroska/matroska-ids.h:
+       * gst/matroska/matroska-mux.c: (gst_matroska_mux_class_init),
+       (gst_matroska_mux_init), (gst_matroska_mux_start),
+       (gst_matroska_mux_create_buffer_header),
+       (gst_matroska_mux_write_data), (gst_matroska_mux_set_property),
+       (gst_matroska_mux_get_property):
+       * gst/matroska/matroska-mux.h:
+         Add SimpleBlock support to matroska demuxer and muxer (part of
+         Matroska v2). (#319731)
+
 2005-10-28  Wim Taymans  <wim@fluendo.com>
 
        * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init), (gst_jpeg_dec_chain),
index a605a71..96f53f3 100644 (file)
@@ -1254,9 +1254,9 @@ gst_matroska_demux_init_stream (GstMatroskaDemux * demux)
     return FALSE;
   }
   g_free (doctype);
-  if (version > 1) {
+  if (version > 2) {
     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
-        ("Demuxer version (1) is too old to read stream version %d", version));
+        ("Demuxer version (2) is too old to read stream version %d", version));
     return FALSE;
   }
 
@@ -1625,6 +1625,13 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux)
         break;
       }
 
+      case GST_MATROSKA_ID_SEGMENTUID:{
+        /* TODO not yet implemented. */
+        if (!gst_ebml_read_skip (ebml))
+          res = FALSE;
+        break;
+      }
+
       default:
         GST_WARNING ("Unknown entry 0x%x in info header", id);
         /* fall-through */
@@ -2087,8 +2094,8 @@ gst_matroska_demux_add_wvpk_header (GstMatroskaTrackContext * stream,
 }
 
 static gboolean
-gst_matroska_demux_parse_blockgroup (GstMatroskaDemux * demux,
-    guint64 cluster_time)
+gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
+    guint64 cluster_time, gboolean is_simpleblock)
 {
   GstMatroskaTrackContext *stream = NULL;
   GstEbmlRead *ebml = GST_EBML_READ (demux);
@@ -2101,25 +2108,30 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux * demux,
   guint size = 0;
   gint *lace_size = NULL;
   gint64 time = 0;
+  gint flags = 0;
 
   while (!got_error) {
-    if (!gst_ebml_peek_id (ebml, &demux->level_up, &id))
-      goto error;
+    if (!is_simpleblock) {
+      if (!gst_ebml_peek_id (ebml, &demux->level_up, &id))
+        goto error;
 
-    if (demux->level_up) {
-      demux->level_up--;
-      break;
+      if (demux->level_up) {
+        demux->level_up--;
+        break;
+      }
+    } else {
+      id = GST_MATROSKA_ID_SIMPLEBLOCK;
     }
 
     switch (id) {
         /* one block inside the group. Note, block parsing is one
          * of the harder things, so this code is a bit complicated.
          * See http://www.matroska.org/ for documentation. */
+      case GST_MATROSKA_ID_SIMPLEBLOCK:
       case GST_MATROSKA_ID_BLOCK:
       {
         guint64 num;
         guint8 *data;
-        gint flags = 0;
 
         if (!gst_ebml_read_buffer (ebml, &id, &buf)) {
           got_error = TRUE;
@@ -2281,6 +2293,9 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux * demux,
         break;
     }
 
+    if (is_simpleblock)
+      break;
+
     if (demux->level_up) {
       demux->level_up--;
       break;
@@ -2331,6 +2346,13 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux * demux,
         stream->pos += GST_BUFFER_DURATION (sub);
       }
 
+      if (is_simpleblock) {
+        if (flags & 0x80)
+          GST_BUFFER_FLAG_UNSET (sub, GST_BUFFER_FLAG_DELTA_UNIT);
+        else
+          GST_BUFFER_FLAG_SET (sub, GST_BUFFER_FLAG_DELTA_UNIT);
+      }
+
       GST_DEBUG ("Pushing data of size %d for stream %d, time=%"
           GST_TIME_FORMAT " and duration=%" GST_TIME_FORMAT,
           GST_BUFFER_SIZE (sub), stream_num,
@@ -2394,11 +2416,20 @@ gst_matroska_demux_parse_cluster (GstMatroskaDemux * demux)
         if (!gst_ebml_read_master (ebml, &id)) {
           got_error = TRUE;
         } else {
-          if (!gst_matroska_demux_parse_blockgroup (demux, cluster_time))
+          if (!gst_matroska_demux_parse_blockgroup_or_simpleblock (demux,
+                  cluster_time, FALSE))
             got_error = TRUE;
         }
         break;
 
+      case GST_MATROSKA_ID_SIMPLEBLOCK:
+      {
+        if (!gst_matroska_demux_parse_blockgroup_or_simpleblock (demux,
+                cluster_time, TRUE))
+          got_error = TRUE;
+        break;
+      }
+
       default:
         GST_WARNING ("Unknown entry 0x%x in cluster data", id);
         /* fall-through */
index a0895a9..ff61efd 100644 (file)
 /* IDs in the cluster master */
 #define GST_MATROSKA_ID_CLUSTERTIMECODE 0xE7
 #define GST_MATROSKA_ID_BLOCKGROUP 0xA0
+#define GST_MATROSKA_ID_SIMPLEBLOCK 0xA3
 #define GST_MATROSKA_ID_REFERENCEBLOCK 0xFB
 
 /* IDs in the blockgroup master */
index 4dc8135..ee19fa3 100644 (file)
@@ -42,7 +42,8 @@ enum
 enum
 {
   ARG_0,
-  ARG_WRITING_APP
+  ARG_WRITING_APP,
+  ARG_MATROSKA_VERSION
       /* FILL ME */
 };
 
@@ -201,6 +202,10 @@ gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
       g_param_spec_string ("writing-app", "Writing application.",
           "The name the application that creates the matroska file.",
           NULL, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, ARG_MATROSKA_VERSION,
+      g_param_spec_int ("version", "Matroska version",
+          "This parameter determines what matroska features can be used.",
+          1, 2, 1, G_PARAM_READWRITE));
 
   gstelement_class->change_state = gst_matroska_mux_change_state;
   gstelement_class->request_new_pad = gst_matroska_mux_request_new_pad;
@@ -233,6 +238,7 @@ gst_matroska_mux_init (GstMatroskaMux * mux, GstMatroskaMuxClass * g_class)
 
   /* initialize internal variables */
   mux->index = NULL;
+  mux->matroska_version = 1;
 
   /* Initialize all variables */
   gst_matroska_mux_reset (GST_ELEMENT (mux));
@@ -1000,7 +1006,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
   GTimeVal time = { 0, 0 };
 
   /* we start with a EBML header */
-  gst_ebml_write_header (ebml, "matroska", 1);
+  gst_ebml_write_header (ebml, "matroska", mux->matroska_version);
 
   /* start a segment */
   mux->segment_pos =
@@ -1269,6 +1275,35 @@ gst_matroska_mux_best_pad (GstMatroskaMux * mux)
   return best;
 }
 
+
+/**
+ * gst_matroska_mux_buffer_header:
+ * @track: Track context.
+ * @relative_timestamp: relative timestamp of the buffer
+ * @flags: Buffer flags.
+ *
+ * Create a buffer containing buffer header.
+ * 
+ * Returns: New buffer.
+ */
+GstBuffer *
+gst_matroska_mux_create_buffer_header (GstMatroskaTrackContext * track,
+    guint16 relative_timestamp, int flags)
+{
+  GstBuffer *hdr;
+
+  hdr = gst_buffer_new_and_alloc (4);
+  /* track num - FIXME: what if num >= 0x80 (unlikely)? */
+  GST_BUFFER_DATA (hdr)[0] = track->num | 0x80;
+  /* time relative to clustertime */
+  GST_WRITE_UINT16_BE (GST_BUFFER_DATA (hdr) + 1, relative_timestamp);
+
+  /* flags */
+  GST_BUFFER_DATA (hdr)[3] = flags;
+
+  return hdr;
+}
+
 /**
  * gst_matroska_mux_write_data:
  * @mux: #GstMatroskaMux
@@ -1284,6 +1319,8 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
   GstEbmlWrite *ebml = mux->ebml_write;
   GstBuffer *buf, *hdr;
   guint64 cluster, blockgroup;
+  gboolean write_duration;
+  guint16 relative_timestamp;
 
   /* which stream to write from? */
   best = gst_matroska_mux_best_pad (mux);
@@ -1379,32 +1416,52 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
     idx->track = best->track->num;
   }
 
-  /* write one blockgroup with one block with
-   * one slice (*breath*).
-   * FIXME: lacing, etc. */
-  blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
-  gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
-      GST_BUFFER_SIZE (buf) + 4);
-  hdr = gst_buffer_new_and_alloc (4);
-  /* track num - FIXME: what if num >= 0x80 (unlikely)? */
-  GST_BUFFER_DATA (hdr)[0] = best->track->num | 0x80;
-  /* time relative to clustertime */
-  *(guint16 *) & GST_BUFFER_DATA (hdr)[1] = GUINT16_TO_BE (
-      (GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time) / mux->time_scale);
-  /* flags - no lacing (yet) */
-  GST_BUFFER_DATA (hdr)[3] = 0;
-  gst_ebml_write_buffer (ebml, hdr);
-  gst_ebml_write_buffer (ebml, buf);
+  /* Check if the duration differs from the default duration. */
+  write_duration = FALSE;
   if (GST_BUFFER_DURATION_IS_VALID (buf)) {
     guint64 block_duration = GST_BUFFER_DURATION (buf);
 
     if (block_duration != best->track->default_duration) {
+      write_duration = TRUE;
+    }
+  }
+
+  /* write the block, for matroska v2 use SimpleBlock if possible
+   * one slice (*breath*).
+   * FIXME: lacing, etc. */
+  relative_timestamp =
+      (GST_BUFFER_TIMESTAMP (buf) - mux->cluster_time) / mux->time_scale;
+  if (mux->matroska_version > 1 && !write_duration) {
+    int flags =
+        GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ? 0 : 0x80;
+
+    hdr =
+        gst_matroska_mux_create_buffer_header (best->track, relative_timestamp,
+        flags);
+    gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_SIMPLEBLOCK,
+        GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
+    gst_ebml_write_buffer (ebml, hdr);
+    gst_ebml_write_buffer (ebml, buf);
+
+    return gst_ebml_last_write_result (ebml);
+  } else {
+    blockgroup = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_BLOCKGROUP);
+    hdr =
+        gst_matroska_mux_create_buffer_header (best->track, relative_timestamp,
+        0);
+    gst_ebml_write_buffer_header (ebml, GST_MATROSKA_ID_BLOCK,
+        GST_BUFFER_SIZE (buf) + GST_BUFFER_SIZE (hdr));
+    gst_ebml_write_buffer (ebml, hdr);
+    gst_ebml_write_buffer (ebml, buf);
+    if (write_duration) {
+      guint64 block_duration = GST_BUFFER_DURATION (buf);
+
       gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION,
           block_duration / mux->time_scale);
     }
+    gst_ebml_write_master_finish (ebml, blockgroup);
+    return gst_ebml_last_write_result (ebml);
   }
-  gst_ebml_write_master_finish (ebml, blockgroup);
-  return gst_ebml_last_write_result (ebml);
 }
 
 
@@ -1504,6 +1561,9 @@ gst_matroska_mux_set_property (GObject * object,
       g_free (mux->writing_app);
       mux->writing_app = g_strdup (g_value_get_string (value));
       break;
+    case ARG_MATROSKA_VERSION:
+      mux->matroska_version = g_value_get_int (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1523,6 +1583,9 @@ gst_matroska_mux_get_property (GObject * object,
     case ARG_WRITING_APP:
       g_value_set_string (value, mux->writing_app);
       break;
+    case ARG_MATROSKA_VERSION:
+      g_value_set_int (value, mux->matroska_version);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index 15f113c..2f1d2db 100644 (file)
@@ -94,6 +94,9 @@ typedef struct _GstMatroskaMux {
   /* Application name (for the writing application header element) */
   gchar          *writing_app;
 
+  /* Matroska version. */
+  guint          matroska_version;
+
   /* state */
   GstMatroskaMuxState state;