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:
parent
a6562db286
commit
0166570e09
18
ChangeLog
18
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>
|
2005-10-28 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init), (gst_jpeg_dec_chain),
|
* ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init), (gst_jpeg_dec_chain),
|
||||||
|
@ -1254,9 +1254,9 @@ gst_matroska_demux_init_stream (GstMatroskaDemux * demux)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
g_free (doctype);
|
g_free (doctype);
|
||||||
if (version > 1) {
|
if (version > 2) {
|
||||||
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1625,6 +1625,13 @@ gst_matroska_demux_parse_info (GstMatroskaDemux * demux)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_SEGMENTUID:{
|
||||||
|
/* TODO not yet implemented. */
|
||||||
|
if (!gst_ebml_read_skip (ebml))
|
||||||
|
res = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GST_WARNING ("Unknown entry 0x%x in info header", id);
|
GST_WARNING ("Unknown entry 0x%x in info header", id);
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
@ -2087,8 +2094,8 @@ gst_matroska_demux_add_wvpk_header (GstMatroskaTrackContext * stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_matroska_demux_parse_blockgroup (GstMatroskaDemux * demux,
|
gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
guint64 cluster_time)
|
guint64 cluster_time, gboolean is_simpleblock)
|
||||||
{
|
{
|
||||||
GstMatroskaTrackContext *stream = NULL;
|
GstMatroskaTrackContext *stream = NULL;
|
||||||
GstEbmlRead *ebml = GST_EBML_READ (demux);
|
GstEbmlRead *ebml = GST_EBML_READ (demux);
|
||||||
@ -2101,8 +2108,10 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux * demux,
|
|||||||
guint size = 0;
|
guint size = 0;
|
||||||
gint *lace_size = NULL;
|
gint *lace_size = NULL;
|
||||||
gint64 time = 0;
|
gint64 time = 0;
|
||||||
|
gint flags = 0;
|
||||||
|
|
||||||
while (!got_error) {
|
while (!got_error) {
|
||||||
|
if (!is_simpleblock) {
|
||||||
if (!gst_ebml_peek_id (ebml, &demux->level_up, &id))
|
if (!gst_ebml_peek_id (ebml, &demux->level_up, &id))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -2110,16 +2119,19 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux * demux,
|
|||||||
demux->level_up--;
|
demux->level_up--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
id = GST_MATROSKA_ID_SIMPLEBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
/* one block inside the group. Note, block parsing is one
|
/* one block inside the group. Note, block parsing is one
|
||||||
* of the harder things, so this code is a bit complicated.
|
* of the harder things, so this code is a bit complicated.
|
||||||
* See http://www.matroska.org/ for documentation. */
|
* See http://www.matroska.org/ for documentation. */
|
||||||
|
case GST_MATROSKA_ID_SIMPLEBLOCK:
|
||||||
case GST_MATROSKA_ID_BLOCK:
|
case GST_MATROSKA_ID_BLOCK:
|
||||||
{
|
{
|
||||||
guint64 num;
|
guint64 num;
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
gint flags = 0;
|
|
||||||
|
|
||||||
if (!gst_ebml_read_buffer (ebml, &id, &buf)) {
|
if (!gst_ebml_read_buffer (ebml, &id, &buf)) {
|
||||||
got_error = TRUE;
|
got_error = TRUE;
|
||||||
@ -2281,6 +2293,9 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux * demux,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_simpleblock)
|
||||||
|
break;
|
||||||
|
|
||||||
if (demux->level_up) {
|
if (demux->level_up) {
|
||||||
demux->level_up--;
|
demux->level_up--;
|
||||||
break;
|
break;
|
||||||
@ -2331,6 +2346,13 @@ gst_matroska_demux_parse_blockgroup (GstMatroskaDemux * demux,
|
|||||||
stream->pos += GST_BUFFER_DURATION (sub);
|
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_DEBUG ("Pushing data of size %d for stream %d, time=%"
|
||||||
GST_TIME_FORMAT " and duration=%" GST_TIME_FORMAT,
|
GST_TIME_FORMAT " and duration=%" GST_TIME_FORMAT,
|
||||||
GST_BUFFER_SIZE (sub), stream_num,
|
GST_BUFFER_SIZE (sub), stream_num,
|
||||||
@ -2394,11 +2416,20 @@ gst_matroska_demux_parse_cluster (GstMatroskaDemux * demux)
|
|||||||
if (!gst_ebml_read_master (ebml, &id)) {
|
if (!gst_ebml_read_master (ebml, &id)) {
|
||||||
got_error = TRUE;
|
got_error = TRUE;
|
||||||
} else {
|
} 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;
|
got_error = TRUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_SIMPLEBLOCK:
|
||||||
|
{
|
||||||
|
if (!gst_matroska_demux_parse_blockgroup_or_simpleblock (demux,
|
||||||
|
cluster_time, TRUE))
|
||||||
|
got_error = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GST_WARNING ("Unknown entry 0x%x in cluster data", id);
|
GST_WARNING ("Unknown entry 0x%x in cluster data", id);
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
|
@ -117,6 +117,7 @@
|
|||||||
/* IDs in the cluster master */
|
/* IDs in the cluster master */
|
||||||
#define GST_MATROSKA_ID_CLUSTERTIMECODE 0xE7
|
#define GST_MATROSKA_ID_CLUSTERTIMECODE 0xE7
|
||||||
#define GST_MATROSKA_ID_BLOCKGROUP 0xA0
|
#define GST_MATROSKA_ID_BLOCKGROUP 0xA0
|
||||||
|
#define GST_MATROSKA_ID_SIMPLEBLOCK 0xA3
|
||||||
#define GST_MATROSKA_ID_REFERENCEBLOCK 0xFB
|
#define GST_MATROSKA_ID_REFERENCEBLOCK 0xFB
|
||||||
|
|
||||||
/* IDs in the blockgroup master */
|
/* IDs in the blockgroup master */
|
||||||
|
@ -42,7 +42,8 @@ enum
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ARG_0,
|
ARG_0,
|
||||||
ARG_WRITING_APP
|
ARG_WRITING_APP,
|
||||||
|
ARG_MATROSKA_VERSION
|
||||||
/* FILL ME */
|
/* FILL ME */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -201,6 +202,10 @@ gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
|
|||||||
g_param_spec_string ("writing-app", "Writing application.",
|
g_param_spec_string ("writing-app", "Writing application.",
|
||||||
"The name the application that creates the matroska file.",
|
"The name the application that creates the matroska file.",
|
||||||
NULL, G_PARAM_READWRITE));
|
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->change_state = gst_matroska_mux_change_state;
|
||||||
gstelement_class->request_new_pad = gst_matroska_mux_request_new_pad;
|
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 */
|
/* initialize internal variables */
|
||||||
mux->index = NULL;
|
mux->index = NULL;
|
||||||
|
mux->matroska_version = 1;
|
||||||
|
|
||||||
/* Initialize all variables */
|
/* Initialize all variables */
|
||||||
gst_matroska_mux_reset (GST_ELEMENT (mux));
|
gst_matroska_mux_reset (GST_ELEMENT (mux));
|
||||||
@ -1000,7 +1006,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
|
|||||||
GTimeVal time = { 0, 0 };
|
GTimeVal time = { 0, 0 };
|
||||||
|
|
||||||
/* we start with a EBML header */
|
/* 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 */
|
/* start a segment */
|
||||||
mux->segment_pos =
|
mux->segment_pos =
|
||||||
@ -1269,6 +1275,35 @@ gst_matroska_mux_best_pad (GstMatroskaMux * mux)
|
|||||||
return best;
|
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:
|
* gst_matroska_mux_write_data:
|
||||||
* @mux: #GstMatroskaMux
|
* @mux: #GstMatroskaMux
|
||||||
@ -1284,6 +1319,8 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
|
|||||||
GstEbmlWrite *ebml = mux->ebml_write;
|
GstEbmlWrite *ebml = mux->ebml_write;
|
||||||
GstBuffer *buf, *hdr;
|
GstBuffer *buf, *hdr;
|
||||||
guint64 cluster, blockgroup;
|
guint64 cluster, blockgroup;
|
||||||
|
gboolean write_duration;
|
||||||
|
guint16 relative_timestamp;
|
||||||
|
|
||||||
/* which stream to write from? */
|
/* which stream to write from? */
|
||||||
best = gst_matroska_mux_best_pad (mux);
|
best = gst_matroska_mux_best_pad (mux);
|
||||||
@ -1379,32 +1416,52 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux)
|
|||||||
idx->track = best->track->num;
|
idx->track = best->track->num;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write one blockgroup with one block with
|
/* Check if the duration differs from the default duration. */
|
||||||
* one slice (*breath*).
|
write_duration = FALSE;
|
||||||
* 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);
|
|
||||||
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
|
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
|
||||||
guint64 block_duration = GST_BUFFER_DURATION (buf);
|
guint64 block_duration = GST_BUFFER_DURATION (buf);
|
||||||
|
|
||||||
if (block_duration != best->track->default_duration) {
|
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,
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_BLOCKDURATION,
|
||||||
block_duration / mux->time_scale);
|
block_duration / mux->time_scale);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
gst_ebml_write_master_finish (ebml, blockgroup);
|
gst_ebml_write_master_finish (ebml, blockgroup);
|
||||||
return gst_ebml_last_write_result (ebml);
|
return gst_ebml_last_write_result (ebml);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1504,6 +1561,9 @@ gst_matroska_mux_set_property (GObject * object,
|
|||||||
g_free (mux->writing_app);
|
g_free (mux->writing_app);
|
||||||
mux->writing_app = g_strdup (g_value_get_string (value));
|
mux->writing_app = g_strdup (g_value_get_string (value));
|
||||||
break;
|
break;
|
||||||
|
case ARG_MATROSKA_VERSION:
|
||||||
|
mux->matroska_version = g_value_get_int (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -1523,6 +1583,9 @@ gst_matroska_mux_get_property (GObject * object,
|
|||||||
case ARG_WRITING_APP:
|
case ARG_WRITING_APP:
|
||||||
g_value_set_string (value, mux->writing_app);
|
g_value_set_string (value, mux->writing_app);
|
||||||
break;
|
break;
|
||||||
|
case ARG_MATROSKA_VERSION:
|
||||||
|
g_value_set_int (value, mux->matroska_version);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -94,6 +94,9 @@ typedef struct _GstMatroskaMux {
|
|||||||
/* Application name (for the writing application header element) */
|
/* Application name (for the writing application header element) */
|
||||||
gchar *writing_app;
|
gchar *writing_app;
|
||||||
|
|
||||||
|
/* Matroska version. */
|
||||||
|
guint matroska_version;
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
GstMatroskaMuxState state;
|
GstMatroskaMuxState state;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user