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)
This commit is contained in:
Tim-Philipp Müller 2005-10-28 15:32:48 +00:00
parent a6562db286
commit 0166570e09
5 changed files with 147 additions and 31 deletions

View file

@ -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),

View 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 */

View file

@ -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 */

View 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;

View 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;