summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog24
-rw-r--r--configure.ac11
-rw-r--r--gst/matroska/Makefile.am7
-rw-r--r--gst/matroska/lzo.c288
-rw-r--r--gst/matroska/lzo.h35
-rw-r--r--gst/matroska/matroska-demux.c453
-rw-r--r--gst/matroska/matroska-ids.h13
7 files changed, 719 insertions, 112 deletions
diff --git a/ChangeLog b/ChangeLog
index 3c955cb3..03a65383 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,29 @@
2008-08-02 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * configure.ac:
+ * gst/matroska/Makefile.am:
+ * gst/matroska/lzo.c: (get_byte), (get_len), (copy),
+ (copy_backptr), (lzo1x_decode), (main):
+ * gst/matroska/lzo.h:
+ * gst/matroska/matroska-demux.c:
+ (gst_matroska_demux_read_track_encoding),
+ (gst_matroska_decompress_data), (gst_matroska_decode_data),
+ (gst_matroska_decode_buffer),
+ (gst_matroska_decode_content_encodings),
+ (gst_matroska_demux_read_track_encodings),
+ (gst_matroska_demux_add_stream),
+ (gst_matroska_demux_parse_blockgroup_or_simpleblock):
+ * gst/matroska/matroska-ids.h:
+ Decode the codec private data and following ContentEncoding if
+ necessary.
+
+ Support bzip2, lzo and header stripped compression. For lzo use the
+ ffmpeg lzo implementation as liblzo is GPL licensed.
+
+ Fix zlib decompression.
+
+2008-08-02 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
* gst/matroska/matroska-mux.c:
(gst_matroska_mux_audio_pad_setcaps):
Fix muxing of MP3/MP2 with different MPEG versions by calculating the
diff --git a/configure.ac b/configure.ac
index 73fb95cd..ccd9770b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -933,9 +933,9 @@ AG_GST_CHECK_FEATURE(WAVPACK, [wavpack plug-in], wavpack, [
AC_SUBST(WAVPACK_LIBS)
])
-dnl *** qtdemux & id3demux prefer to have zlib ***
+dnl *** qtdemux & id3demux & matroska prefer to have zlib ***
translit(dnm, m, l) AM_CONDITIONAL(USE_ZLIB, true)
-AG_GST_CHECK_FEATURE(ZLIB, [zlib support for id3demux/qtdemux],, [
+AG_GST_CHECK_FEATURE(ZLIB, [zlib support for id3demux/qtdemux/matroska],, [
AG_GST_CHECK_LIBHEADER(ZLIB,
z, uncompress,, zlib.h, [
HAVE_ZLIB="yes"
@@ -944,6 +944,13 @@ AG_GST_CHECK_FEATURE(ZLIB, [zlib support for id3demux/qtdemux],, [
])
])
+dnl *** matroska prefers to have bz2 ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_BZ2, true)
+AG_GST_CHECK_FEATURE(BZ2, [bz2 library for matroska ],, [
+ AG_GST_CHECK_LIBHEADER(BZ2, bz2, BZ2_bzCompress, ,bzlib.h, BZ2_LIBS="-lbz2")
+ AC_SUBST(BZ2_LIBS)
+])
+
else
dnl not building plugins with external dependencies,
diff --git a/gst/matroska/Makefile.am b/gst/matroska/Makefile.am
index 6c3f2275..6ce6b10d 100644
--- a/gst/matroska/Makefile.am
+++ b/gst/matroska/Makefile.am
@@ -6,7 +6,8 @@ libgstmatroska_la_SOURCES = \
matroska.c \
matroska-demux.c \
matroska-ids.c \
- matroska-mux.c
+ matroska-mux.c \
+ lzo.c
noinst_HEADERS = \
ebml-ids.h \
@@ -14,7 +15,8 @@ noinst_HEADERS = \
ebml-write.h \
matroska-demux.h \
matroska-ids.h \
- matroska-mux.h
+ matroska-mux.h \
+ lzo.h
libgstmatroska_la_CFLAGS = \
$(GST_BASE_CFLAGS) \
@@ -28,5 +30,6 @@ libgstmatroska_la_LIBADD = \
-lgstriff-@GST_MAJORMINOR@ \
-lgsttag-@GST_MAJORMINOR@ \
$(ZLIB_LIBS) \
+ $(BZ2_LIBS) \
$(LIBM)
libgstmatroska_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/gst/matroska/lzo.c b/gst/matroska/lzo.c
new file mode 100644
index 00000000..57982348
--- /dev/null
+++ b/gst/matroska/lzo.c
@@ -0,0 +1,288 @@
+/*
+ * LZO 1x decompression
+ * Copyright (c) 2006 Reimar Doeffinger
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <gst/gst.h>
+#include <stdlib.h>
+#include <string.h>
+#include "_stdint.h"
+#include "lzo.h"
+
+/*! define if we may write up to 12 bytes beyond the output buffer */
+/* #define OUTBUF_PADDED 1 */
+/*! define if we may read up to 8 bytes beyond the input buffer */
+/* #define INBUF_PADDED 1 */
+typedef struct LZOContext
+{
+ const uint8_t *in, *in_end;
+ uint8_t *out_start, *out, *out_end;
+ int error;
+} LZOContext;
+
+/**
+ * \brief read one byte from input buffer, avoiding overrun
+ * \return byte read
+ */
+static inline int
+get_byte (LZOContext * c)
+{
+ if (c->in < c->in_end)
+ return *c->in++;
+ c->error |= LZO_INPUT_DEPLETED;
+ return 1;
+}
+
+#ifdef INBUF_PADDED
+#define GETB(c) (*(c).in++)
+#else
+#define GETB(c) get_byte(&(c))
+#endif
+
+/**
+ * \brief decode a length value in the coding used by lzo
+ * \param x previous byte value
+ * \param mask bits used from x
+ * \return decoded length value
+ */
+static inline int
+get_len (LZOContext * c, int x, int mask)
+{
+ int cnt = x & mask;
+ if (!cnt) {
+ while (!(x = get_byte (c)))
+ cnt += 255;
+ cnt += mask + x;
+ }
+ return cnt;
+}
+
+/*#define UNALIGNED_LOADSTORE */
+#define BUILTIN_MEMCPY
+#ifdef UNALIGNED_LOADSTORE
+#define COPY2(d, s) *(uint16_t *)(d) = *(uint16_t *)(s);
+#define COPY4(d, s) *(uint32_t *)(d) = *(uint32_t *)(s);
+#elif defined(BUILTIN_MEMCPY)
+#define COPY2(d, s) memcpy(d, s, 2);
+#define COPY4(d, s) memcpy(d, s, 4);
+#else
+#define COPY2(d, s) (d)[0] = (s)[0]; (d)[1] = (s)[1];
+#define COPY4(d, s) (d)[0] = (s)[0]; (d)[1] = (s)[1]; (d)[2] = (s)[2]; (d)[3] = (s)[3];
+#endif
+
+/**
+ * \brief copy bytes from input to output buffer with checking
+ * \param cnt number of bytes to copy, must be >= 0
+ */
+static inline void
+copy (LZOContext * c, int cnt)
+{
+ register const uint8_t *src = c->in;
+ register uint8_t *dst = c->out;
+ if (cnt > c->in_end - src) {
+ cnt = MAX (c->in_end - src, 0);
+ c->error |= LZO_INPUT_DEPLETED;
+ }
+ if (cnt > c->out_end - dst) {
+ cnt = MAX (c->out_end - dst, 0);
+ c->error |= LZO_OUTPUT_FULL;
+ }
+#if defined(INBUF_PADDED) && defined(OUTBUF_PADDED)
+ COPY4 (dst, src);
+ src += 4;
+ dst += 4;
+ cnt -= 4;
+ if (cnt > 0)
+#endif
+ memcpy (dst, src, cnt);
+ c->in = src + cnt;
+ c->out = dst + cnt;
+}
+
+/**
+ * \brief copy previously decoded bytes to current position
+ * \param back how many bytes back we start
+ * \param cnt number of bytes to copy, must be >= 0
+ *
+ * cnt > back is valid, this will copy the bytes we just copied,
+ * thus creating a repeating pattern with a period length of back.
+ */
+static inline void
+copy_backptr (LZOContext * c, int back, int cnt)
+{
+ register const uint8_t *src = &c->out[-back];
+ register uint8_t *dst = c->out;
+ if (src < c->out_start || src > dst) {
+ c->error |= LZO_INVALID_BACKPTR;
+ return;
+ }
+ if (cnt > c->out_end - dst) {
+ cnt = MAX (c->out_end - dst, 0);
+ c->error |= LZO_OUTPUT_FULL;
+ }
+ if (back == 1) {
+ memset (dst, *src, cnt);
+ dst += cnt;
+ } else {
+#ifdef OUTBUF_PADDED
+ COPY2 (dst, src);
+ COPY2 (dst + 2, src + 2);
+ src += 4;
+ dst += 4;
+ cnt -= 4;
+ if (cnt > 0) {
+ COPY2 (dst, src);
+ COPY2 (dst + 2, src + 2);
+ COPY2 (dst + 4, src + 4);
+ COPY2 (dst + 6, src + 6);
+ src += 8;
+ dst += 8;
+ cnt -= 8;
+ }
+#endif
+ if (cnt > 0) {
+ int blocklen = back;
+ while (cnt > blocklen) {
+ memcpy (dst, src, blocklen);
+ dst += blocklen;
+ cnt -= blocklen;
+ blocklen <<= 1;
+ }
+ memcpy (dst, src, cnt);
+ }
+ dst += cnt;
+ }
+ c->out = dst;
+}
+
+/**
+ * \brief decode LZO 1x compressed data
+ * \param out output buffer
+ * \param outlen size of output buffer, number of bytes left are returned here
+ * \param in input buffer
+ * \param inlen size of input buffer, number of bytes left are returned here
+ * \return 0 on success, otherwise error flags, see lzo.h
+ *
+ * make sure all buffers are appropriately padded, in must provide
+ * LZO_INPUT_PADDING, out must provide LZO_OUTPUT_PADDING additional bytes
+ */
+int
+lzo1x_decode (void *out, int *outlen, const void *in, int *inlen)
+{
+ int state = 0;
+ int x;
+ LZOContext c;
+ c.in = in;
+ c.in_end = (const uint8_t *) in + *inlen;
+ c.out = c.out_start = out;
+ c.out_end = (uint8_t *) out + *outlen;
+ c.error = 0;
+ x = GETB (c);
+ if (x > 17) {
+ copy (&c, x - 17);
+ x = GETB (c);
+ if (x < 16)
+ c.error |= LZO_ERROR;
+ }
+ if (c.in > c.in_end)
+ c.error |= LZO_INPUT_DEPLETED;
+ while (!c.error) {
+ int cnt, back;
+ if (x > 15) {
+ if (x > 63) {
+ cnt = (x >> 5) - 1;
+ back = (GETB (c) << 3) + ((x >> 2) & 7) + 1;
+ } else if (x > 31) {
+ cnt = get_len (&c, x, 31);
+ x = GETB (c);
+ back = (GETB (c) << 6) + (x >> 2) + 1;
+ } else {
+ cnt = get_len (&c, x, 7);
+ back = (1 << 14) + ((x & 8) << 11);
+ x = GETB (c);
+ back += (GETB (c) << 6) + (x >> 2);
+ if (back == (1 << 14)) {
+ if (cnt != 1)
+ c.error |= LZO_ERROR;
+ break;
+ }
+ }
+ } else if (!state) {
+ cnt = get_len (&c, x, 15);
+ copy (&c, cnt + 3);
+ x = GETB (c);
+ if (x > 15)
+ continue;
+ cnt = 1;
+ back = (1 << 11) + (GETB (c) << 2) + (x >> 2) + 1;
+ } else {
+ cnt = 0;
+ back = (GETB (c) << 2) + (x >> 2) + 1;
+ }
+ copy_backptr (&c, back, cnt + 2);
+ state = cnt = x & 3;
+ copy (&c, cnt);
+ x = GETB (c);
+ }
+ *inlen = c.in_end - c.in;
+ if (c.in > c.in_end)
+ *inlen = 0;
+ *outlen = c.out_end - c.out;
+ return c.error;
+}
+
+#ifdef TEST
+#include <stdio.h>
+#include <lzo/lzo1x.h>
+#include "log.h"
+#define MAXSZ (10*1024*1024)
+int
+main (int argc, char *argv[])
+{
+ FILE *in = fopen (argv[1], "rb");
+ uint8_t *orig = av_malloc (MAXSZ + 16);
+ uint8_t *comp = av_malloc (2 * MAXSZ + 16);
+ uint8_t *decomp = av_malloc (MAXSZ + 16);
+ size_t s = fread (orig, 1, MAXSZ, in);
+ lzo_uint clen = 0;
+ long tmp[LZO1X_MEM_COMPRESS];
+ int inlen, outlen;
+ int i;
+ av_log_level = AV_LOG_DEBUG;
+ lzo1x_999_compress (orig, s, comp, &clen, tmp);
+ for (i = 0; i < 300; i++) {
+ START_TIMER inlen = clen;
+ outlen = MAXSZ;
+#ifdef LIBLZO
+ if (lzo1x_decompress_safe (comp, inlen, decomp, &outlen, NULL))
+#elif defined(LIBLZO_UNSAFE)
+ if (lzo1x_decompress (comp, inlen, decomp, &outlen, NULL))
+#else
+ if (lzo1x_decode (decomp, &outlen, comp, &inlen))
+#endif
+ av_log (NULL, AV_LOG_ERROR, "decompression error\n");
+ STOP_TIMER ("lzod")
+ }
+ if (memcmp (orig, decomp, s))
+ av_log (NULL, AV_LOG_ERROR, "decompression incorrect\n");
+ else
+ av_log (NULL, AV_LOG_ERROR, "decompression ok\n");
+ return 0;
+}
+#endif
diff --git a/gst/matroska/lzo.h b/gst/matroska/lzo.h
new file mode 100644
index 00000000..e7795f77
--- /dev/null
+++ b/gst/matroska/lzo.h
@@ -0,0 +1,35 @@
+/*
+ * LZO 1x decompression
+ * copyright (c) 2006 Reimar Doeffinger
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFMPEG_LZO_H
+#define FFMPEG_LZO_H
+
+#define LZO_INPUT_DEPLETED 1
+#define LZO_OUTPUT_FULL 2
+#define LZO_INVALID_BACKPTR 4
+#define LZO_ERROR 8
+
+#define LZO_INPUT_PADDING 8
+#define LZO_OUTPUT_PADDING 12
+
+int lzo1x_decode(void *out, int *outlen, const void *in, int *inlen);
+
+#endif /* FFMPEG_LZO_H */
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index ee74aeb0..ba67759c 100644
--- a/gst/matroska/matroska-demux.c
+++ b/gst/matroska/matroska-demux.c
@@ -54,6 +54,12 @@
#include <zlib.h>
#endif
+#ifdef HAVE_BZ2
+#include <bzlib.h>
+#endif
+
+#include "lzo.h"
+
#include "matroska-demux.h"
#include "matroska-ids.h"
@@ -462,10 +468,6 @@ gst_matroska_demux_read_track_encoding (GstMatroskaDemux * demux,
G_GUINT64_FORMAT, num);
ret = GST_FLOW_ERROR;
break;
- } else if (num & 0x4) {
- GST_ERROR_OBJECT (demux, "Unsupported ContentEncodingScope %"
- G_GUINT64_FORMAT, num);
- ret = GST_FLOW_ERROR;
}
GST_DEBUG_OBJECT (demux, "ContentEncodingScope: %" G_GUINT64_FORMAT,
@@ -524,11 +526,6 @@ gst_matroska_demux_read_track_encoding (GstMatroskaDemux * demux,
G_GUINT64_FORMAT, num);
ret = GST_FLOW_ERROR;
break;
- } else if (num != 0) {
- GST_ERROR_OBJECT (demux, "Unsupported ContentCompAlgo %"
- G_GUINT64_FORMAT, num);
- ret = GST_FLOW_ERROR;
- break;
}
GST_DEBUG_OBJECT (demux, "ContentCompAlgo: %" G_GUINT64_FORMAT,
num);
@@ -596,6 +593,317 @@ gst_matroska_demux_read_track_encoding (GstMatroskaDemux * demux,
return ret;
}
+static gboolean
+gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
+ guint8 ** data_out, guint * size_out,
+ GstMatroskaTrackCompressionAlgorithm algo)
+{
+ guint8 *new_data = NULL;
+ guint new_size = 0;
+
+ guint8 *data = *data_out;
+ guint size = *size_out;
+
+ gboolean ret = TRUE;
+
+ if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB) {
+#ifdef HAVE_ZLIB
+ /* zlib encoded data */
+ z_stream zstream;
+ guint orig_size;
+ int result;
+
+ orig_size = size;
+ zstream.zalloc = (alloc_func) 0;
+ zstream.zfree = (free_func) 0;
+ zstream.opaque = (voidpf) 0;
+ if (inflateInit (&zstream) != Z_OK) {
+ GST_WARNING ("zlib initialization failed.");
+ ret = FALSE;
+ goto out;
+ }
+ zstream.next_in = (Bytef *) data;
+ zstream.avail_in = orig_size;
+ new_size = orig_size;
+ new_data = g_malloc (new_size);
+ zstream.avail_out = new_size;
+ zstream.next_out = (Bytef *) new_data;
+
+ do {
+ result = inflate (&zstream, Z_NO_FLUSH);
+ if (result != Z_OK && result != Z_STREAM_END) {
+ GST_WARNING ("zlib decompression failed.");
+ g_free (new_data);
+ inflateEnd (&zstream);
+ break;
+ }
+ new_size += 4000;
+ new_data = g_realloc (new_data, new_size);
+ zstream.next_out = (Bytef *) (new_data + zstream.total_out);
+ zstream.avail_out += 4000;
+ } while (zstream.avail_in != 0 && result != Z_STREAM_END);
+
+ if (result != Z_STREAM_END) {
+ ret = FALSE;
+ goto out;
+ } else {
+ new_size = zstream.total_out;
+ inflateEnd (&zstream);
+ }
+#else
+ GST_WARNING ("zlib encoded tracks not supported.");
+ ret = FALSE;
+ goto out;
+#endif
+ } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB) {
+#ifdef HAVE_BZ2
+ /* bzip2 encoded data */
+ bz_stream bzstream;
+ guint orig_size;
+ int result;
+
+ bzstream.bzalloc = NULL;
+ bzstream.bzfree = NULL;
+ bzstream.opaque = NULL;
+ orig_size = size;
+
+ if ((result = BZ2_bzDecompressInit (&bzstream, 0, 0)) != BZ_OK) {
+ GST_WARNING ("bzip2 initialization failed.");
+ ret = FALSE;
+ goto out;
+ }
+
+ bzstream.next_in = (char *) data;
+ bzstream.avail_in = orig_size;
+ new_size = orig_size;
+ new_data = g_malloc (new_size);
+ bzstream.avail_out = new_size;
+ bzstream.next_out = (char *) new_data;
+
+ do {
+ result = BZ2_bzDecompress (&bzstream);
+ if (result != BZ_OK && result != BZ_STREAM_END) {
+ GST_WARNING ("bzip2 decompression failed.");
+ g_free (new_data);
+ BZ2_bzDecompressEnd (&bzstream);
+ break;
+ }
+ new_size += 4000;
+ new_data = g_realloc (new_data, new_size);
+ bzstream.next_out = (char *) (new_data + bzstream.total_out_lo32);
+ bzstream.avail_out += 4000;
+ } while (bzstream.avail_in != 0 && result != BZ_STREAM_END);
+
+ if (result != BZ_STREAM_END) {
+ ret = FALSE;
+ goto out;
+ } else {
+ new_size = bzstream.total_out_lo32;
+ BZ2_bzDecompressEnd (&bzstream);
+ }
+#else
+ GST_WARNING ("bzip2 encoded tracks not supported.");
+ ret = FALSE;
+ goto out;
+#endif
+ } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X) {
+ /* lzo encoded data */
+ int result;
+ int orig_size, out_size;
+
+ orig_size = size;
+ out_size = size;
+ new_size = size;
+ new_data = g_malloc (new_size);
+
+ do {
+ orig_size = size;
+ out_size = new_size;
+
+ result = lzo1x_decode (new_data, &out_size, data, &orig_size);
+
+ if (orig_size > 0) {
+ new_size += 4000;
+ new_data = g_realloc (new_data, new_size);
+ }
+ } while (orig_size > 0 && result == LZO_OUTPUT_FULL);
+
+ new_size -= out_size;
+
+ if (result != LZO_OUTPUT_FULL) {
+ GST_WARNING ("lzo decompression failed");
+ g_free (new_data);
+
+ ret = FALSE;
+ goto out;
+ }
+
+ } else if (algo == GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP) {
+ /* header stripped encoded data */
+ if (enc->comp_settings_length > 0) {
+ new_data = g_malloc (size + enc->comp_settings_length);
+ new_size = size + enc->comp_settings_length;
+
+ memcpy (new_data, enc->comp_settings, enc->comp_settings_length);
+ memcpy (new_data + enc->comp_settings_length, data, size);
+ }
+ } else {
+ g_assert_not_reached ();
+ }
+
+out:
+
+ if (!ret) {
+ *data_out = NULL;
+ *size_out = 0;
+ } else {
+ *data_out = new_data;
+ *size_out = new_size;
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_matroska_decode_data (GArray * encodings, guint8 ** data_out,
+ guint * size_out, GstMatroskaTrackEncodingScope scope, gboolean free)
+{
+ guint8 *data;
+ guint size;
+ gboolean ret = TRUE;
+ gint i;
+
+ g_return_val_if_fail (encodings != NULL, FALSE);
+ g_return_val_if_fail (data_out != NULL && *data_out != NULL, FALSE);
+ g_return_val_if_fail (size_out != NULL, FALSE);
+
+ data = *data_out;
+ size = *size_out;
+
+ for (i = 0; i < encodings->len; i++) {
+ GstMatroskaTrackEncoding *enc =
+ &g_array_index (encodings, GstMatroskaTrackEncoding, i);
+ guint8 *new_data = NULL;
+ guint new_size = 0;
+
+ if ((enc->scope & scope) == 0)
+ continue;
+
+ /* Encryption not supported yet */
+ if (enc->type != 0) {
+ ret = FALSE;
+ break;
+ }
+
+ new_data = data;
+ new_size = size;
+
+ ret =
+ gst_matroska_decompress_data (enc, &new_data, &new_size,
+ enc->comp_algo);
+
+ if (!ret)
+ break;
+
+ if ((data == *data_out && free) || (data != *data_out))
+ g_free (data);
+
+ data = new_data;
+ size = new_size;
+ }
+
+ if (!ret) {
+ if ((data == *data_out && free) || (data != *data_out))
+ g_free (data);
+
+ *data_out = NULL;
+ *size_out = 0;
+ } else {
+ *data_out = data;
+ *size_out = size;
+ }
+
+ return ret;
+}
+
+static GstBuffer *
+gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf)
+{
+ guint8 *data;
+ guint size;
+ GstBuffer *new_buf;
+
+ g_return_val_if_fail (GST_IS_BUFFER (buf), NULL);
+
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ g_return_val_if_fail (data != NULL && size > 0, buf);
+
+ if (gst_matroska_decode_data (context->encodings, &data, &size,
+ GST_MATROSKA_TRACK_ENCODING_SCOPE_FRAME, FALSE)) {
+ new_buf = gst_buffer_new ();
+ GST_BUFFER_MALLOCDATA (new_buf) = (guint8 *) data;
+ GST_BUFFER_DATA (new_buf) = (guint8 *) data;
+ GST_BUFFER_SIZE (new_buf) = size;
+
+ gst_buffer_unref (buf);
+ buf = new_buf;
+
+ return buf;
+ } else {
+ gst_buffer_unref (buf);
+ return NULL;
+ }
+}
+
+static GstFlowReturn
+gst_matroska_decode_content_encodings (GArray * encodings)
+{
+ gint i;
+
+ if (encodings == NULL)
+ return GST_FLOW_OK;
+
+ for (i = 0; i < encodings->len; i++) {
+ GstMatroskaTrackEncoding *enc =
+ &g_array_index (encodings, GstMatroskaTrackEncoding, i);
+ GstMatroskaTrackEncoding *enc2;
+ guint8 *data = NULL;
+ guint size;
+
+ if ((enc->
+ scope & GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING) ==
+ 0)
+ continue;
+
+ /* Encryption not supported yet */
+ if (enc->type != 0)
+ return GST_FLOW_ERROR;
+
+ if (i + 1 >= encodings->len)
+ return GST_FLOW_ERROR;
+
+ enc2 = &g_array_index (encodings, GstMatroskaTrackEncoding, i + 1);
+
+ if (enc->comp_settings_length == 0)
+ continue;
+
+ data = enc->comp_settings;
+ size = enc->comp_settings_length;
+
+ if (!gst_matroska_decompress_data (enc, &data, &size, enc->comp_algo))
+ return GST_FLOW_ERROR;
+
+ g_free (enc->comp_settings);
+
+ enc->comp_settings = data;
+ enc->comp_settings_length = size;
+ }
+
+ return GST_FLOW_OK;
+}
+
static GstFlowReturn
gst_matroska_demux_read_track_encodings (GstMatroskaDemux * demux,
GstMatroskaTrackContext * context)
@@ -648,9 +956,7 @@ gst_matroska_demux_read_track_encodings (GstMatroskaDemux * demux,
g_array_sort (context->encodings,
(GCompareFunc) gst_matroska_demux_encoding_cmp);
- /* TODO: Decompress & decrypt ContentEncodings if necessary */
-
- return ret;
+ return gst_matroska_decode_content_encodings (context->encodings);
}
static gboolean
@@ -1355,7 +1661,16 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux)
DEBUG_ELEMENT_STOP (demux, ebml, "TrackEntry", ret);
- /* TODO: decompress/decrypt codec private if necessary */
+ /* Decode codec private data if necessary */
+ if (context->encodings && context->encodings->len > 0 && context->codec_priv
+ && context->codec_priv_size > 0) {
+ if (!gst_matroska_decode_data (context->encodings,
+ (guint8 **) & context->codec_priv, &context->codec_priv_size,
+ GST_MATROSKA_TRACK_ENCODING_SCOPE_CODEC_DATA, TRUE)) {
+ GST_WARNING_OBJECT (demux, "Decoding codec private data failed");
+ ret = GST_FLOW_ERROR;
+ }
+ }
if (context->type == 0 || context->codec_id == NULL || (ret != GST_FLOW_OK
&& ret != GST_FLOW_UNEXPECTED)) {
@@ -3496,100 +3811,6 @@ gst_matroska_demux_check_subtitle_buffer (GstElement * element,
return GST_FLOW_OK;
}
-static GstBuffer *
-gst_matroska_decode_buffer (GstMatroskaTrackContext * context, GstBuffer * buf)
-{
- gint i;
-
- g_assert (context->encodings != NULL);
-
- for (i = 0; i < context->encodings->len; i++) {
- GstMatroskaTrackEncoding *enc;
- guint8 *new_data = NULL;
- guint new_size = 0;
- GstBuffer *new_buf;
-
- enc = &g_array_index (context->encodings, GstMatroskaTrackEncoding, i);
-
- /* Currently only compression is supported */
- if (enc->type != 0)
- break;
-
- /* FIXME: use enc->scope ! only necessary to decode buffer if scope & 0x1 */
-
- 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.");
- break;
- }
- 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;
- /* FIXME: not exactly fast, right? */
- 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.");
- g_free (new_data);
- inflateEnd (&zstream);
- break;
- }
- 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 ("zlib encoded tracks not supported.");
- break;
-#endif
-/* FIXME: add bzip/lzo support, what is header stripped?
- * it's insane and requires deeper knowledge of the used codec
- */
- } else if (enc->comp_algo == 1) {
- GST_WARNING ("BZIP encoded tracks not supported.");
- break;
- } else if (enc->comp_algo == 2) {
- GST_WARNING ("LZO encoded tracks not supported.");
- break;
- } else if (enc->comp_algo == 3) {
- GST_WARNING ("Header-stripped tracks not supported.");
- break;
- } else {
- g_assert_not_reached ();
- }
-
- g_assert (new_data != NULL);
-
- new_buf = gst_buffer_new ();
- GST_BUFFER_MALLOCDATA (new_buf) = (guint8 *) new_data;
- GST_BUFFER_DATA (new_buf) = (guint8 *) new_data;
- GST_BUFFER_SIZE (new_buf) = new_size;
- gst_buffer_copy_metadata (new_buf, buf, GST_BUFFER_COPY_TIMESTAMPS);
-
- gst_buffer_unref (buf);
- buf = new_buf;
- }
-
- return buf;
-}
-
static GstFlowReturn
gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
guint64 cluster_time, gboolean is_simpleblock)
@@ -3804,7 +4025,17 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
g_free (stream->codec_state);
stream->codec_state = data;
stream->codec_state_size = data_len;
- /* TODO: decompress/decrypt if necessary */
+
+ /* Decode if necessary */
+ if (stream->encodings && stream->encodings->len > 0
+ && stream->codec_state && stream->codec_state_size > 0) {
+ if (!gst_matroska_decode_data (stream->encodings,
+ (guint8 **) & stream->codec_state, &stream->codec_state_size,
+ GST_MATROSKA_TRACK_ENCODING_SCOPE_CODEC_DATA, TRUE)) {
+ GST_WARNING_OBJECT (demux, "Decoding codec state failed");
+ }
+ }
+
GST_DEBUG_OBJECT (demux, "CodecState of %u bytes",
stream->codec_state_size);
break;
@@ -3880,6 +4111,11 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
if (stream->encodings != NULL && stream->encodings->len > 0)
sub = gst_matroska_decode_buffer (stream, sub);
+ if (sub == NULL) {
+ GST_WARNING_OBJECT (demux, "Decoding buffer failed");
+ goto next_lace;
+ }
+
GST_BUFFER_TIMESTAMP (sub) = lace_time;
if (lace_time != GST_CLOCK_TIME_NONE) {
@@ -3950,6 +4186,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
/* combine flows */
ret = gst_matroska_demux_combine_flows (demux, stream, ret);
+ next_lace:
size -= lace_size[n];
if (lace_time != GST_CLOCK_TIME_NONE)
lace_time += duration / laces;
diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h
index c6c1852a..8a73d37a 100644
--- a/gst/matroska/matroska-ids.h
+++ b/gst/matroska/matroska-ids.h
@@ -554,6 +554,19 @@ typedef struct _Wavpack4Header {
guint32 crc; /* crc for actual decoded data */
} Wavpack4Header;
+typedef enum {
+ GST_MATROSKA_TRACK_ENCODING_SCOPE_FRAME = (1<<0),
+ GST_MATROSKA_TRACK_ENCODING_SCOPE_CODEC_DATA = (1<<1),
+ GST_MATROSKA_TRACK_ENCODING_SCOPE_NEXT_CONTENT_ENCODING = (1<<2)
+} GstMatroskaTrackEncodingScope;
+
+typedef enum {
+ GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_ZLIB = 0,
+ GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_BZLIB = 1,
+ GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_LZO1X = 2,
+ GST_MATROSKA_TRACK_COMPRESSION_ALGORITHM_HEADERSTRIP = 3
+} GstMatroskaTrackCompressionAlgorithm;
+
typedef struct _GstMatroskaTrackEncoding {
guint order;
guint scope : 3;