From 0166570e093c14e10a5c0e64ada784357dc8aa0f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 28 Oct 2005 15:32:48 +0000 Subject: [PATCH] gst/matroska/: Add SimpleBlock support to matroska demuxer and muxer (part of MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Original commit message from CVS: Reviewed by: Tim-Philipp Müller * 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 | 18 ++++++++ gst/matroska/matroska-demux.c | 53 +++++++++++++++++----- gst/matroska/matroska-ids.h | 1 + gst/matroska/matroska-mux.c | 103 ++++++++++++++++++++++++++++++++++-------- gst/matroska/matroska-mux.h | 3 ++ 5 files changed, 147 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4422223..c2ad96d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2005-10-28 Michal Benes + + Reviewed by: Tim-Philipp Müller + + * 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 * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init), (gst_jpeg_dec_chain), diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index a605a71..96f53f3 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 a0895a9..ff61efd 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 4dc8135..ee19fa3 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 15f113c..2f1d2db 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; -- 2.7.4