Index: gst/matroska/matroska-ids.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/matroska/matroska-ids.h,v
retrieving revision 1.21
diff -u -p -r1.21 matroska-ids.h
--- gst/matroska/matroska-ids.h	29 Jun 2006 11:41:55 -0000	1.21
+++ gst/matroska/matroska-ids.h	4 Aug 2006 17:12:09 -0000
@@ -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.
  */
@@ -174,6 +190,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.
@@ -260,6 +277,10 @@ typedef struct _GstMatroskaTrackContext 
 
   /* Tags to send after newsegment event */
   GstTagList   *pending_tags;
+
+  /* A GArray of GstMatroskaTrackEncoding.
+     Encoding (Compression/Encryption) settings for this track. */
+  GArray       *encodings;
 } GstMatroskaTrackContext;
 
 typedef struct _GstMatroskaTrackVideoContext {
@@ -310,6 +331,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);
Index: gst/matroska/matroska-demux.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/matroska/matroska-demux.c,v
retrieving revision 1.84
diff -u -p -r1.84 matroska-demux.c
--- gst/matroska/matroska-demux.c	29 Jun 2006 11:41:55 -0000	1.84
+++ gst/matroska/matroska-demux.c	4 Aug 2006 17:12:09 -0000
@@ -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
     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);
@@ -289,6 +294,182 @@ gst_matroska_demux_stream_from_num (GstM
 }
 
 static gboolean
+gst_read_track_encodings (GstEbmlRead * ebml, 
+			  GstMatroskaDemux * demux, 
+			  GstMatroskaTrackContext * context)
+{
+  gboolean res = TRUE;
+  guint32 id;
+
+  if (!gst_ebml_read_master (ebml, &id))
+    res = FALSE;
+  else
+    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;
+      memset(&enc, 0, sizeof(enc));
+      
+      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);
@@ -794,8 +975,15 @@ gst_matroska_demux_add_stream (GstMatros
         context->default_duration = num;
         break;
       }
-
-      default:
+	
+      case GST_MATROSKA_ID_CONTENTENCODINGS:{
+	if (!gst_read_track_encodings (ebml, demux, context)) {
+          res = FALSE;
+        }
+	break;
+      }
+      
+    default:
         GST_WARNING ("Unknown track header entry 0x%x - ignoring", id);
         /* pass-through */
 
@@ -2207,6 +2395,90 @@ gst_matroska_demux_check_subtitle_buffer
   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 = &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)
@@ -2224,6 +2496,7 @@ gst_matroska_demux_parse_blockgroup_or_s
   gint64 time = 0;
   gint64 lace_time = 0;
   gint flags = 0;
+  gint64 referenceblock = 0;
 
   while (!got_error) {
     if (!is_simpleblock) {
@@ -2387,19 +2660,11 @@ gst_matroska_demux_parse_blockgroup_or_s
       }
 
       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))
-          got_error = TRUE;
+	if (!gst_ebml_read_sint (ebml, &id, &referenceblock))
+	  got_error = TRUE;
         break;
       }
-
+	
       default:
         GST_WARNING ("Unknown entry 0x%x in blockgroup data", id);
         /* fall-through */
@@ -2428,6 +2693,13 @@ gst_matroska_demux_parse_blockgroup_or_s
     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;
 
@@ -2449,6 +2721,10 @@ gst_matroska_demux_parse_blockgroup_or_s
       sub = gst_buffer_create_sub (buf,
           GST_BUFFER_SIZE (buf) - size, lace_size[n]);
 
+      if (stream->encodings != NULL
+	  && stream->encodings->len)
+	sub = gst_matroska_decode_buffer(stream, sub);
+
       GST_BUFFER_TIMESTAMP (sub) = lace_time;
       if (lace_time != GST_CLOCK_TIME_NONE)
         demux->pos = lace_time;
@@ -3535,6 +3811,9 @@ gst_matroska_demux_subtitle_caps (GstMat
   } 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);
