summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrédéric Riss <frederic.riss@gmail.com>2006-09-04 16:21:17 +0000
committerTim-Philipp Müller <tim@centricular.net>2006-09-04 16:21:17 +0000
commit92753a26de57b14af07441122237ac82ac1684ba (patch)
treea3f328e1d3e8223195581836f40827c5a837ef22
parenta0fa3b2917891bc36e3c186bc2d5389233571331 (diff)
gst/matroska/: Add support for VOBSUB subtitle tracks and zlib-compressed tracks. Make sure we start on a keyframe af...
Original commit message from CVS: Patch by: Frédéric Riss <frederic.riss at gmail dot com> * gst/matroska/matroska-demux.c: (gst_matroska_track_free), (gst_matroska_demux_reset), (gst_matroska_demux_read_track_encodings), (gst_matroska_demux_add_stream), (gst_matroska_decode_buffer), (gst_matroska_demux_parse_blockgroup_or_simpleblock), (gst_matroska_demux_subtitle_caps): * gst/matroska/matroska-ids.h: Add support for VOBSUB subtitle tracks and zlib-compressed tracks. Make sure we start on a keyframe after a seek. (#343348)
-rw-r--r--ChangeLog14
-rw-r--r--gst/matroska/matroska-demux.c329
-rw-r--r--gst/matroska/matroska-ids.h30
3 files changed, 351 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index 4780d757..2511bc20 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
2006-09-04 Tim-Philipp Müller <tim at centricular dot net>
+ Patch by: Frédéric Riss <frederic.riss at gmail dot com>
+
+ * gst/matroska/matroska-demux.c: (gst_matroska_track_free),
+ (gst_matroska_demux_reset),
+ (gst_matroska_demux_read_track_encodings),
+ (gst_matroska_demux_add_stream), (gst_matroska_decode_buffer),
+ (gst_matroska_demux_parse_blockgroup_or_simpleblock),
+ (gst_matroska_demux_subtitle_caps):
+ * gst/matroska/matroska-ids.h:
+ Add support for VOBSUB subtitle tracks and zlib-compressed
+ tracks. Make sure we start on a keyframe after a seek. (#343348)
+
+2006-09-04 Tim-Philipp Müller <tim at centricular dot net>
+
* gst/matroska/matroska-demux.c: (gst_matroska_demux_push_hdr_buf),
(gst_matroska_demux_push_flac_codec_priv_data),
(gst_matroska_demux_push_xiph_codec_priv_data),
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index 3d6208de..17120a0e 100644
--- a/gst/matroska/matroska-demux.c
+++ b/gst/matroska/matroska-demux.c
@@ -33,6 +33,10 @@
#include <gst/riff/riff-ids.h>
#include <gst/riff/riff-media.h>
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
#include "matroska-demux.h"
#include "matroska-ids.h"
@@ -71,7 +75,8 @@ static GstStaticPadTemplate subtitle_src_templ =
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("text/plain; application/x-ssa; application/x-ass; "
- "application/x-usf; application/x-subtitle-unknown")
+ "application/x-usf; video/x-dvd-subpicture; "
+ "application/x-subtitle-unknown")
);
static void gst_matroska_demux_base_init (GstMatroskaDemuxClass * klass);
@@ -213,6 +218,31 @@ gst_matroska_demux_init (GstMatroskaDemux * demux)
}
static void
+gst_matroska_track_free (GstMatroskaTrackContext * track)
+{
+ g_free (track->codec_id);
+ g_free (track->codec_name);
+ g_free (track->name);
+ g_free (track->language);
+ g_free (track->codec_priv);
+
+ if (track->encodings != NULL) {
+ int i;
+
+ for (i = 0; i < track->encodings->len; ++i) {
+ GstMatroskaTrackEncoding *enc = &g_array_index (track->encodings,
+ GstMatroskaTrackEncoding,
+ i);
+
+ g_free (enc->comp_settings);
+ }
+ g_array_free (track->encodings, TRUE);
+ }
+
+ g_free (track);
+}
+
+static void
gst_matroska_demux_reset (GstElement * element)
{
GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (element);
@@ -228,12 +258,7 @@ gst_matroska_demux_reset (GstElement * element)
gst_element_remove_pad (GST_ELEMENT (demux), demux->src[i]->pad);
}
gst_caps_replace (&demux->src[i]->caps, NULL);
- g_free (demux->src[i]->codec_id);
- g_free (demux->src[i]->codec_name);
- g_free (demux->src[i]->name);
- g_free (demux->src[i]->language);
- g_free (demux->src[i]->codec_priv);
- g_free (demux->src[i]);
+ gst_matroska_track_free (demux->src[i]);
demux->src[i] = NULL;
}
}
@@ -289,6 +314,181 @@ gst_matroska_demux_stream_from_num (GstMatroskaDemux * demux, guint track_num)
}
static gboolean
+gst_matroska_demux_read_track_encodings (GstEbmlRead * ebml,
+ GstMatroskaDemux * demux, GstMatroskaTrackContext * context)
+{
+ gboolean res = TRUE;
+ guint32 id;
+
+ if (!gst_ebml_read_master (ebml, &id))
+ return FALSE;
+
+ context->encodings =
+ g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaTrackEncoding), 1);
+
+ while (res) {
+ if (!gst_ebml_peek_id (ebml, &demux->level_up, &id)) {
+ res = FALSE;
+ break;
+ } else if (demux->level_up > 0) {
+ demux->level_up--;
+ break;
+ }
+
+ switch (id) {
+ case GST_MATROSKA_ID_CONTENTENCODING:{
+ GstMatroskaTrackEncoding enc = { 0, };
+
+ if (!gst_ebml_read_master (ebml, &id)) {
+ res = FALSE;
+ break;
+ }
+
+ while (res) {
+ if (!gst_ebml_peek_id (ebml, &demux->level_up, &id)) {
+ res = FALSE;
+ break;
+ } else if (demux->level_up > 0) {
+ demux->level_up--;
+ break;
+ }
+
+ switch (id) {
+ case GST_MATROSKA_ID_CONTENTENCODINGORDER:{
+ guint64 num;
+
+ if (!gst_ebml_read_uint (ebml, &id, &num)) {
+ res = FALSE;
+ break;
+ }
+ enc.order = num;
+ break;
+ }
+ case GST_MATROSKA_ID_CONTENTENCODINGSCOPE:{
+ guint64 num;
+
+ if (!gst_ebml_read_uint (ebml, &id, &num)) {
+ res = FALSE;
+ break;
+ }
+ if (num > 7)
+ GST_WARNING ("Unknown scope value in contents encoding.");
+ else
+ enc.scope = num;
+ break;
+ }
+ case GST_MATROSKA_ID_CONTENTENCODINGTYPE:{
+ guint64 num;
+
+ if (!gst_ebml_read_uint (ebml, &id, &num)) {
+ res = FALSE;
+ break;
+ }
+ if (num > 1)
+ GST_WARNING ("Unknown type value in contents encoding.");
+ else
+ enc.type = num;
+ break;
+ }
+ case GST_MATROSKA_ID_CONTENTCOMPRESSION:{
+
+ if (!gst_ebml_read_master (ebml, &id)) {
+ res = FALSE;
+ break;
+ }
+
+ while (res) {
+
+ if (!gst_ebml_peek_id (ebml, &demux->level_up, &id)) {
+ res = FALSE;
+ break;
+ } else if (demux->level_up > 0) {
+ demux->level_up--;
+ break;
+ }
+
+ switch (id) {
+ case GST_MATROSKA_ID_CONTENTCOMPALGO:{
+ guint64 num;
+
+ if (!gst_ebml_read_uint (ebml, &id, &num)) {
+ res = FALSE;
+ break;
+ }
+ if (num > 3)
+ GST_WARNING ("Unknown scope value in encoding compalgo.");
+ else
+ enc.comp_algo = num;
+ break;
+ }
+ case GST_MATROSKA_ID_CONTENTCOMPSETTINGS:{
+ guint8 *data;
+ guint64 size;
+
+
+ if (!gst_ebml_read_binary (ebml, &id, &data, &size)) {
+ res = FALSE;
+ break;
+ }
+ enc.comp_settings = data;
+ enc.comp_settings_length = size;
+ break;
+ }
+ default:
+ GST_WARNING ("Unknown track compression header entry 0x%x"
+ " - ignoring", id);
+ if (!gst_ebml_read_skip (ebml))
+ res = FALSE;
+ break;
+ }
+
+ if (demux->level_up) {
+ demux->level_up--;
+ break;
+ }
+ }
+ break;
+ }
+
+ case GST_MATROSKA_ID_CONTENTENCRYPTION:
+ GST_WARNING ("Encrypted tracks not yet supported");
+ /* pass-through */
+ default:
+ GST_WARNING
+ ("Unknown track encoding header entry 0x%x - ignoring", id);
+ if (!gst_ebml_read_skip (ebml))
+ res = FALSE;
+ break;
+ }
+
+ if (demux->level_up) {
+ demux->level_up--;
+ break;
+ }
+ }
+
+ g_array_append_val (context->encodings, enc);
+ break;
+ }
+
+ default:
+ GST_WARNING ("Unknown track encodings header entry 0x%x - ignoring",
+ id);
+ if (!gst_ebml_read_skip (ebml))
+ res = FALSE;
+ break;
+ }
+
+ if (demux->level_up) {
+ demux->level_up--;
+ break;
+ }
+ }
+
+ return res;
+}
+
+static gboolean
gst_matroska_demux_add_stream (GstMatroskaDemux * demux)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (demux);
@@ -795,6 +995,13 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux)
break;
}
+ case GST_MATROSKA_ID_CONTENTENCODINGS:{
+ if (!gst_matroska_demux_read_track_encodings (ebml, demux, context)) {
+ res = FALSE;
+ }
+ break;
+ }
+
default:
GST_WARNING ("Unknown track header entry 0x%x - ignoring", id);
/* pass-through */
@@ -823,12 +1030,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux)
demux->num_streams--;
demux->src[demux->num_streams] = NULL;
if (context) {
- g_free (context->codec_id);
- g_free (context->codec_name);
- g_free (context->name);
- g_free (context->language);
- g_free (context->codec_priv);
- g_free (context);
+ gst_matroska_track_free (context);
}
return res;
@@ -2269,6 +2471,83 @@ gst_matroska_demux_check_subtitle_buffer (GstMatroskaDemux * demux,
return newbuf;
}
+static GstBuffer *
+gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf)
+{
+ gint i;
+ guint8 *new_data = NULL;
+ guint new_size = 0;
+ GstBuffer *res;
+
+ g_assert (context->encodings != NULL);
+
+ for (i = 0; i < context->encodings->len; i++) {
+ GstMatroskaTrackEncoding *enc;
+
+ enc = &g_array_index (context->encodings, GstMatroskaTrackEncoding, i);
+
+ /* FIXME: use enc->scope ? */
+
+ if (enc->comp_algo == 0) {
+#ifdef HAVE_ZLIB
+ /* zlib encoded track */
+ z_stream zstream;
+ guint orig_size;
+ int result;
+
+ orig_size = GST_BUFFER_SIZE (buf);
+ zstream.zalloc = (alloc_func) 0;
+ zstream.zfree = (free_func) 0;
+ zstream.opaque = (voidpf) 0;
+ if (inflateInit (&zstream) != Z_OK) {
+ GST_WARNING ("zlib initialization failed.\n");
+ return buf;
+ }
+ zstream.next_in = (Bytef *) GST_BUFFER_DATA (buf);
+ zstream.avail_in = orig_size;
+ new_size = orig_size;
+ new_data = g_malloc (new_size);
+ zstream.avail_out = new_size;
+ do {
+ new_size += 4000;
+ new_data = g_realloc (new_data, new_size);
+ zstream.next_out = (Bytef *) (new_data + zstream.total_out);
+ result = inflate (&zstream, Z_NO_FLUSH);
+ if (result != Z_OK && result != Z_STREAM_END) {
+ GST_WARNING ("zlib decompression failed.\n");
+ g_free (new_data);
+ inflateEnd (&zstream);
+ return buf;
+ }
+ zstream.avail_out += 4000;
+ } while (zstream.avail_out == 4000 &&
+ zstream.avail_in != 0 && result != Z_STREAM_END);
+
+ new_size = zstream.total_out;
+ inflateEnd (&zstream);
+#else
+ GST_WARNING ("GZIP encoded tracks not supported.");
+ return buf;
+#endif
+ } else if (enc->comp_algo == 1) {
+ GST_WARNING ("BZIP encoded tracks not supported.");
+ return buf;
+ } else if (enc->comp_algo == 2) {
+ GST_WARNING ("LZO encoded tracks not supported.");
+ return buf;
+ }
+ }
+
+ res = gst_buffer_new ();
+ GST_BUFFER_MALLOCDATA (res) = (guint8 *) new_data;
+ GST_BUFFER_DATA (res) = (guint8 *) new_data;
+ GST_BUFFER_SIZE (res) = new_size;
+ gst_buffer_stamp (res, buf);
+
+ gst_buffer_unref (buf);
+ return res;
+}
+
static gboolean
gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
guint64 cluster_time, gboolean is_simpleblock)
@@ -2286,6 +2565,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
gint64 time = 0;
gint64 lace_time = 0;
gint flags = 0;
+ gint64 referenceblock = 0;
while (!got_error) {
if (!is_simpleblock) {
@@ -2456,15 +2736,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
}
case GST_MATROSKA_ID_REFERENCEBLOCK:{
- /* FIXME: implement support for ReferenceBlock
- gint64 num;
- if (!gst_ebml_read_sint (ebml, &id, &num)) {
- res = FALSE;
- break;
- }
- GST_WARNING ("FIXME: implement support for ReferenceBlock");
- */
- if (!gst_ebml_read_skip (ebml))
+ if (!gst_ebml_read_sint (ebml, &id, &referenceblock))
got_error = TRUE;
break;
}
@@ -2497,6 +2769,13 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
lace_time = GST_CLOCK_TIME_NONE;
}
+ if (referenceblock && readblock && demux->src[stream_num]->set_discont) {
+ /* When doing seeks or such, we need to restart on key frames or
+ decoders might choke. */
+ readblock = FALSE;
+ gst_buffer_unref (buf);
+ }
+
if (!got_error && readblock) {
guint64 duration = 0;
@@ -2518,6 +2797,9 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
sub = gst_buffer_create_sub (buf,
GST_BUFFER_SIZE (buf) - size, lace_size[n]);
+ if (stream->encodings != NULL && stream->encodings->len > 0)
+ sub = gst_matroska_decode_buffer (stream, sub);
+
GST_BUFFER_TIMESTAMP (sub) = lace_time;
if (lace_time != GST_CLOCK_TIME_NONE)
demux->pos = lace_time;
@@ -3609,6 +3891,9 @@ gst_matroska_demux_subtitle_caps (GstMatroskaTrackSubtitleContext *
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_USF)) {
caps = gst_caps_new_simple ("application/x-usf", NULL);
subtitlecontext->check_utf8 = TRUE;
+ } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB)) {
+ caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
+ subtitlecontext->check_utf8 = FALSE;
} else {
GST_DEBUG ("Unknown subtitle stream: codec_id='%s'", codec_id);
caps = gst_caps_new_simple ("application/x-subtitle-unknown", NULL);
diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h
index 0c05974b..5a5e5722 100644
--- a/gst/matroska/matroska-ids.h
+++ b/gst/matroska/matroska-ids.h
@@ -71,6 +71,7 @@
#define GST_MATROSKA_ID_TRACKMINCACHE 0x6DE7
#define GST_MATROSKA_ID_TRACKMAXCACHE 0x6DF8
#define GST_MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383
+#define GST_MATROSKA_ID_CONTENTENCODINGS 0x6D80
/* IDs in the trackvideo master */
#define GST_MATROSKA_ID_VIDEOFRAMERATE 0x2383E3
@@ -126,6 +127,21 @@
#define GST_MATROSKA_ID_BLOCK 0xA1
#define GST_MATROSKA_ID_BLOCKDURATION 0x9B
+/* IDs in the contentencodings master */
+#define GST_MATROSKA_ID_CONTENTENCODING 0x6240
+
+/* IDS IN THE CONTENTENCODING MASTER */
+#define GST_MATROSKA_ID_CONTENTENCODINGORDER 0X5031
+#define GST_MATROSKA_ID_CONTENTENCODINGSCOPE 0X5032
+#define GST_MATROSKA_ID_CONTENTENCODINGTYPE 0X5033
+#define GST_MATROSKA_ID_CONTENTCOMPRESSION 0X5034
+#define GST_MATROSKA_ID_CONTENTENCRYPTION 0X5035
+
+/* IDS IN THE CONTENTCOMPRESSION MASTER */
+#define GST_MATROSKA_ID_CONTENTCOMPALGO 0X4254
+#define GST_MATROSKA_ID_CONTENTCOMPSETTINGS 0X4255
+
+
/*
* Matroska Codec IDs. Strings.
*/
@@ -175,6 +191,7 @@
#define GST_MATROSKA_CODEC_ID_SUBTITLE_SSA "S_TEXT/SSA"
#define GST_MATROSKA_CODEC_ID_SUBTITLE_ASS "S_TEXT/ASS"
#define GST_MATROSKA_CODEC_ID_SUBTITLE_USF "S_TEXT/USF"
+#define GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB "S_VOBSUB"
/*
* Matrodka tags. Strings.
@@ -266,6 +283,10 @@ typedef struct _GstMatroskaTrackContext {
/* Tags to send after newsegment event */
GstTagList *pending_tags;
+
+ /* A GArray of GstMatroskaTrackEncoding structures which contain the
+ * encoding (compression/encryption) settings for this track, if any */
+ GArray *encodings;
} GstMatroskaTrackContext;
typedef struct _GstMatroskaTrackVideoContext {
@@ -316,6 +337,15 @@ typedef struct _Wavpack4Header {
guint32 crc; /* crc for actual decoded data */
} Wavpack4Header;
+typedef struct _GstMatroskaTrackEncoding {
+ guint order;
+ guint scope : 3;
+ guint type : 1;
+ guint comp_algo : 2;
+ guint8 *comp_settings;
+ guint comp_settings_length;
+} GstMatroskaTrackEncoding;
+
gboolean gst_matroska_track_init_video_context (GstMatroskaTrackContext ** p_context);
gboolean gst_matroska_track_init_audio_context (GstMatroskaTrackContext ** p_context);
gboolean gst_matroska_track_init_subtitle_context (GstMatroskaTrackContext ** p_context);