summaryrefslogtreecommitdiffstats
path: root/gst/matroska
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim@centricular.net>2005-10-28 15:32:48 +0000
committerTim-Philipp Müller <tim@centricular.net>2005-10-28 15:32:48 +0000
commit0166570e093c14e10a5c0e64ada784357dc8aa0f (patch)
treeb7e7b1414331ed2e6a9f349530eb3e273a713553 /gst/matroska
parenta6562db28617c495842d557bc6bc6e3327f7e55a (diff)
gst/matroska/: Add SimpleBlock support to matroska demuxer and muxer (part of
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)
Diffstat (limited to 'gst/matroska')
-rw-r--r--gst/matroska/matroska-demux.c53
-rw-r--r--gst/matroska/matroska-ids.h1
-rw-r--r--gst/matroska/matroska-mux.c103
-rw-r--r--gst/matroska/matroska-mux.h3
4 files changed, 129 insertions, 31 deletions
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index a605a711..96f53f32 100644
--- a/gst/matroska/matroska-demux.c
+++ b/gst/matroska/matroska-demux.c
@@ -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 */
diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h
index a0895a95..ff61efd1 100644
--- a/gst/matroska/matroska-ids.h
+++ b/gst/matroska/matroska-ids.h
@@ -117,6 +117,7 @@
/* 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 */
diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c
index 4dc81356..ee19fa38 100644
--- a/gst/matroska/matroska-mux.c
+++ b/gst/matroska/matroska-mux.c
@@ -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;
diff --git a/gst/matroska/matroska-mux.h b/gst/matroska/matroska-mux.h
index 15f113cc..2f1d2db4 100644
--- a/gst/matroska/matroska-mux.h
+++ b/gst/matroska/matroska-mux.h
@@ -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;