mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 18:50:48 +00:00
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)
This commit is contained in:
parent
a0fa3b2917
commit
92753a26de
3 changed files with 351 additions and 22 deletions
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
|||
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),
|
||||
|
|
|
@ -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);
|
||||
|
@ -212,6 +217,31 @@ gst_matroska_demux_init (GstMatroskaDemux * demux)
|
|||
gst_matroska_demux_reset (GST_ELEMENT (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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -288,6 +313,181 @@ gst_matroska_demux_stream_from_num (GstMatroskaDemux * demux, guint track_num)
|
|||
return -1;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue