]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/matroskadec.c
only print debug info when sample is actually added
[ffmpeg] / libavformat / matroskadec.c
index 0daf8f19eecb55bb4aa7d98cde55a9f0f34d98cd..9c65a5b9ccc2c7903a2cd4beaddf3fc2a3a99264 100644 (file)
 #include "avformat.h"
 /* For codec_get_id(). */
 #include "riff.h"
-#include "intfloat_readwrite.h"
 #include "matroska.h"
+#include "libavcodec/mpeg4audio.h"
+#include "libavutil/intfloat_readwrite.h"
+#include "libavutil/lzo.h"
+#ifdef CONFIG_ZLIB
+#include <zlib.h>
+#endif
+#ifdef CONFIG_BZLIB
+#include <bzlib.h>
+#endif
 
 typedef struct Track {
     MatroskaTrackType type;
@@ -54,6 +62,11 @@ typedef struct Track {
 
     uint64_t default_duration;
     MatroskaTrackFlags flags;
+
+    int encoding_scope;
+    MatroskaTrackEncodingCompAlgo encoding_algo;
+    uint8_t *encoding_settings;
+    int encoding_settings_len;
 } MatroskaTrack;
 
 typedef struct MatroskaVideoTrack {
@@ -94,13 +107,11 @@ typedef struct MatroskaAudioTrack {
 
 typedef struct MatroskaSubtitleTrack {
     MatroskaTrack track;
-
-    int ass;
     //..
 } MatroskaSubtitleTrack;
 
-#define MAX_TRACK_SIZE (FFMAX(FFMAX(sizeof(MatroskaVideoTrack), \
-                                    sizeof(MatroskaAudioTrack)), \
+#define MAX_TRACK_SIZE (FFMAX3(sizeof(MatroskaVideoTrack), \
+                                    sizeof(MatroskaAudioTrack), \
                                     sizeof(MatroskaSubtitleTrack)))
 
 typedef struct MatroskaLevel {
@@ -176,7 +187,7 @@ typedef struct MatroskaDemuxContext {
 static int
 ebml_read_element_level_up (MatroskaDemuxContext *matroska)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
     offset_t pos = url_ftell(pb);
     int num = 0;
 
@@ -208,7 +219,7 @@ ebml_read_num (MatroskaDemuxContext *matroska,
                int                   max_size,
                uint64_t             *number)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
     int len_mask = 0x80, read = 1, n = 1;
     int64_t total = 0;
 
@@ -325,7 +336,7 @@ static int
 ebml_read_seek (MatroskaDemuxContext *matroska,
                 offset_t              offset)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
 
     /* clear ID cache, if any */
     matroska->peek_id = 0;
@@ -341,7 +352,7 @@ ebml_read_seek (MatroskaDemuxContext *matroska,
 static int
 ebml_read_skip (MatroskaDemuxContext *matroska)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
     uint32_t id;
     uint64_t length;
     int res;
@@ -365,7 +376,7 @@ ebml_read_uint (MatroskaDemuxContext *matroska,
                 uint32_t             *id,
                 uint64_t             *num)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
     int n = 0, size, res;
     uint64_t rlength;
 
@@ -399,7 +410,7 @@ ebml_read_sint (MatroskaDemuxContext *matroska,
                 uint32_t             *id,
                 int64_t              *num)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
     int size, n = 1, negative = 0, res;
     uint64_t rlength;
 
@@ -438,7 +449,7 @@ ebml_read_float (MatroskaDemuxContext *matroska,
                  uint32_t             *id,
                  double               *num)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
     int size, res;
     uint64_t rlength;
 
@@ -472,7 +483,7 @@ ebml_read_ascii (MatroskaDemuxContext *matroska,
                  uint32_t             *id,
                  char                **str)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
     int size, res;
     uint64_t rlength;
 
@@ -534,7 +545,7 @@ static int
 ebml_read_master (MatroskaDemuxContext *matroska,
                   uint32_t             *id)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
     uint64_t length;
     MatroskaLevel *level;
     int res;
@@ -569,7 +580,7 @@ ebml_read_binary (MatroskaDemuxContext *matroska,
                   uint8_t             **binary,
                   int                  *size)
 {
-    ByteIOContext *pb = &matroska->ctx->pb;
+    ByteIOContext *pb = matroska->ctx->pb;
     uint64_t rlength;
     int res;
 
@@ -846,6 +857,24 @@ matroska_queue_packet (MatroskaDemuxContext *matroska,
     matroska->num_packets++;
 }
 
+/*
+ * Free all packets in our internal queue.
+ */
+static void
+matroska_clear_queue (MatroskaDemuxContext *matroska)
+{
+    if (matroska->packets) {
+        int n;
+        for (n = 0; n < matroska->num_packets; n++) {
+            av_free_packet(matroska->packets[n]);
+            av_free(matroska->packets[n]);
+        }
+        av_free(matroska->packets);
+        matroska->packets = NULL;
+        matroska->num_packets = 0;
+    }
+}
+
 
 /*
  * Autodetecting...
@@ -1052,7 +1081,7 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
                         av_log(matroska->ctx, AV_LOG_INFO,
                                "Unknown or unsupported track type 0x%x\n",
                                track->type);
-                        track->type = 0;
+                        track->type = MATROSKA_TRACK_TYPE_NONE;
                         break;
                 }
                 matroska->tracks[matroska->num_tracks - 1] = track;
@@ -1199,9 +1228,9 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
                             break;
                         }
 
-                        /* colourspace (only matters for raw video)
+                        /* colorspace (only matters for raw video)
                          * fourcc */
-                        case MATROSKA_ID_VIDEOCOLOURSPACE: {
+                        case MATROSKA_ID_VIDEOCOLORSPACE: {
                             uint64_t num;
                             if ((res = ebml_read_uint(matroska, &id,
                                                       &num)) < 0)
@@ -1411,6 +1440,154 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
                 break;
             }
 
+            case MATROSKA_ID_TRACKCONTENTENCODINGS: {
+                if ((res = ebml_read_master(matroska, &id)) < 0)
+                    break;
+
+                while (res == 0) {
+                    if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+                        res = AVERROR(EIO);
+                        break;
+                    } else if (matroska->level_up > 0) {
+                        matroska->level_up--;
+                        break;
+                    }
+
+                    switch (id) {
+                        case MATROSKA_ID_TRACKCONTENTENCODING: {
+                            int encoding_scope = 1;
+                            if ((res = ebml_read_master(matroska, &id)) < 0)
+                                break;
+
+                            while (res == 0) {
+                                if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+                                    res = AVERROR(EIO);
+                                    break;
+                                } else if (matroska->level_up > 0) {
+                                    matroska->level_up--;
+                                    break;
+                                }
+
+                                switch (id) {
+                                    case MATROSKA_ID_ENCODINGSCOPE: {
+                                        uint64_t num;
+                                        if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
+                                            break;
+                                        encoding_scope = num;
+                                        break;
+                                    }
+
+                                    case MATROSKA_ID_ENCODINGTYPE: {
+                                        uint64_t num;
+                                        if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
+                                            break;
+                                        if (num)
+                                            av_log(matroska->ctx, AV_LOG_ERROR,
+                                                   "Unsupported encoding type");
+                                        break;
+                                    }
+
+                                    case MATROSKA_ID_ENCODINGCOMPRESSION: {
+                                        if ((res = ebml_read_master(matroska, &id)) < 0)
+                                            break;
+
+                                        while (res == 0) {
+                                            if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+                                                res = AVERROR(EIO);
+                                                break;
+                                            } else if (matroska->level_up > 0) {
+                                                matroska->level_up--;
+                                                break;
+                                            }
+
+                                            switch (id) {
+                                                case MATROSKA_ID_ENCODINGCOMPALGO: {
+                                                    uint64_t num;
+                                                    if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
+                                                        break;
+                                                    if (num != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP &&
+#ifdef CONFIG_ZLIB
+                                                        num != MATROSKA_TRACK_ENCODING_COMP_ZLIB &&
+#endif
+#ifdef CONFIG_BZLIB
+                                                        num != MATROSKA_TRACK_ENCODING_COMP_BZLIB &&
+#endif
+                                                        num != MATROSKA_TRACK_ENCODING_COMP_LZO)
+                                                        av_log(matroska->ctx, AV_LOG_ERROR,
+                                                               "Unsupported compression algo\n");
+                                                    track->encoding_algo = num;
+                                                    break;
+                                                }
+
+                                                case MATROSKA_ID_ENCODINGCOMPSETTINGS: {
+                                                    uint8_t *data;
+                                                    int size;
+                                                    if ((res = ebml_read_binary(matroska, &id, &data, &size) < 0))
+                                                        break;
+                                                    track->encoding_settings = data;
+                                                    track->encoding_settings_len = size;
+                                                    break;
+                                                }
+
+                                                default:
+                                                    av_log(matroska->ctx, AV_LOG_INFO,
+                                                           "Unknown compression header entry "
+                                                           "0x%x - ignoring\n", id);
+                                                    /* pass-through */
+
+                                                case EBML_ID_VOID:
+                                                    res = ebml_read_skip(matroska);
+                                                    break;
+                                            }
+
+                                            if (matroska->level_up) {
+                                                matroska->level_up--;
+                                                break;
+                                            }
+                                        }
+                                        break;
+                                    }
+
+                                    default:
+                                        av_log(matroska->ctx, AV_LOG_INFO,
+                                               "Unknown content encoding header entry "
+                                               "0x%x - ignoring\n", id);
+                                        /* pass-through */
+
+                                    case EBML_ID_VOID:
+                                        res = ebml_read_skip(matroska);
+                                        break;
+                                }
+
+                                if (matroska->level_up) {
+                                    matroska->level_up--;
+                                    break;
+                                }
+                            }
+
+                            track->encoding_scope = encoding_scope;
+                            break;
+                        }
+
+                        default:
+                            av_log(matroska->ctx, AV_LOG_INFO,
+                                   "Unknown content encodings header entry "
+                                   "0x%x - ignoring\n", id);
+                            /* pass-through */
+
+                        case EBML_ID_VOID:
+                            res = ebml_read_skip(matroska);
+                            break;
+                    }
+
+                    if (matroska->level_up) {
+                        matroska->level_up--;
+                        break;
+                    }
+                }
+                break;
+            }
+
             default:
                 av_log(matroska->ctx, AV_LOG_INFO,
                        "Unknown track header entry 0x%x - ignoring\n", id);
@@ -1748,12 +1925,12 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska)
 
                         /* remember the peeked ID and the current position */
                         peek_id_cache = matroska->peek_id;
-                        before_pos = url_ftell(&matroska->ctx->pb);
+                        before_pos = url_ftell(matroska->ctx->pb);
 
                         /* seek */
                         if ((res = ebml_read_seek(matroska, seek_pos +
                                                matroska->segment_start)) < 0)
-                            return res;
+                            goto finish;
 
                         /* we don't want to lose our seekhead level, so we add
                          * a dummy. This is a crude hack. */
@@ -1788,14 +1965,14 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska)
                         switch (id) {
                             case MATROSKA_ID_CUES:
                                 if (!(res = matroska_parse_index(matroska)) ||
-                                    url_feof(&matroska->ctx->pb)) {
+                                    url_feof(matroska->ctx->pb)) {
                                     matroska->index_parsed = 1;
                                     res = 0;
                                 }
                                 break;
                             case MATROSKA_ID_TAGS:
                                 if (!(res = matroska_parse_metadata(matroska)) ||
-                                   url_feof(&matroska->ctx->pb)) {
+                                   url_feof(matroska->ctx->pb)) {
                                     matroska->metadata_parsed = 1;
                                     res = 0;
                                 }
@@ -1849,6 +2026,119 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska)
     return res;
 }
 
+static int
+matroska_parse_attachments(AVFormatContext *s)
+{
+    MatroskaDemuxContext *matroska = s->priv_data;
+    int res = 0;
+    uint32_t id;
+
+    av_log(matroska->ctx, AV_LOG_DEBUG, "parsing attachments...\n");
+
+    while (res == 0) {
+        if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+            res = AVERROR(EIO);
+            break;
+        } else if (matroska->level_up) {
+            matroska->level_up--;
+            break;
+        }
+
+        switch (id) {
+        case MATROSKA_ID_ATTACHEDFILE: {
+            char* name = NULL;
+            char* mime = NULL;
+            uint8_t* data = NULL;
+            int i, data_size = 0;
+            AVStream *st;
+
+            if ((res = ebml_read_master(matroska, &id)) < 0)
+                break;
+
+            while (res == 0) {
+                if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+                    res = AVERROR(EIO);
+                    break;
+                } else if (matroska->level_up) {
+                    matroska->level_up--;
+                    break;
+                }
+
+                switch (id) {
+                case MATROSKA_ID_FILENAME:
+                    res = ebml_read_utf8 (matroska, &id, &name);
+                    break;
+
+                case MATROSKA_ID_FILEMIMETYPE:
+                    res = ebml_read_ascii (matroska, &id, &mime);
+                    break;
+
+                case MATROSKA_ID_FILEDATA:
+                    res = ebml_read_binary(matroska, &id, &data, &data_size);
+                    break;
+
+                default:
+                    av_log(matroska->ctx, AV_LOG_INFO,
+                           "Unknown attachedfile ID 0x%x\n", id);
+                case EBML_ID_VOID:
+                    res = ebml_read_skip(matroska);
+                    break;
+                }
+
+                if (matroska->level_up) {
+                    matroska->level_up--;
+                    break;
+                }
+            }
+
+            if (!(name && mime && data && data_size > 0)) {
+                av_log(matroska->ctx, AV_LOG_ERROR, "incomplete attachment\n");
+                break;
+            }
+
+            st = av_new_stream(s, matroska->num_streams++);
+            if (st == NULL)
+                return AVERROR(ENOMEM);
+            st->filename = av_strdup(name);
+            st->codec->codec_id = CODEC_ID_NONE;
+            st->codec->codec_type = CODEC_TYPE_ATTACHMENT;
+            st->codec->extradata = av_malloc(data_size);
+            if(st->codec->extradata == NULL)
+                return AVERROR(ENOMEM);
+            st->codec->extradata_size = data_size;
+            memcpy(st->codec->extradata, data, data_size);
+
+            for (i=0; ff_mkv_mime_tags[i].id != CODEC_ID_NONE; i++) {
+                if (!strncmp(ff_mkv_mime_tags[i].str, mime,
+                             strlen(ff_mkv_mime_tags[i].str))) {
+                    st->codec->codec_id = ff_mkv_mime_tags[i].id;
+                    break;
+                }
+            }
+
+            av_log(matroska->ctx, AV_LOG_DEBUG, "new attachment: %s, %s, size %d \n", name, mime, data_size);
+            break;
+        }
+
+        default:
+            av_log(matroska->ctx, AV_LOG_INFO,
+                   "Unknown attachments ID 0x%x\n", id);
+            /* fall-through */
+
+        case EBML_ID_VOID:
+            res = ebml_read_skip(matroska);
+            break;
+        }
+
+        if (matroska->level_up) {
+            matroska->level_up--;
+            break;
+        }
+    }
+
+    return res;
+}
+
 #define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))
 
 static int
@@ -1868,14 +2158,10 @@ matroska_aac_profile (char *codec_id)
 static int
 matroska_aac_sri (int samplerate)
 {
-    static const int aac_sample_rates[] = {
-        96000, 88200, 64000, 48000, 44100, 32000,
-        24000, 22050, 16000, 12000, 11025,  8000,
-    };
     int sri;
 
-    for (sri=0; sri<ARRAY_SIZE(aac_sample_rates); sri++)
-        if (aac_sample_rates[sri] == samplerate)
+    for (sri=0; sri<ARRAY_SIZE(ff_mpeg4audio_sample_rates); sri++)
+        if (ff_mpeg4audio_sample_rates[sri] == samplerate)
             break;
     return sri;
 }
@@ -1931,7 +2217,7 @@ matroska_read_header (AVFormatContext    *s,
      * after the segment ID/length. */
     if ((res = ebml_read_master(matroska, &id)) < 0)
         return res;
-    matroska->segment_start = url_ftell(&s->pb);
+    matroska->segment_start = url_ftell(s->pb);
 
     matroska->time_scale = 1000000;
     /* we've found our segment, start reading the different contents in here */
@@ -1991,6 +2277,13 @@ matroska_read_header (AVFormatContext    *s,
                 break;
             }
 
+            case MATROSKA_ID_ATTACHMENTS: {
+                if ((res = ebml_read_master(matroska, &id)) < 0)
+                    break;
+                res = matroska_parse_attachments(s);
+                break;
+            }
+
             case MATROSKA_ID_CLUSTER: {
                 /* Do not read the master - this will be done in the next
                  * call to matroska_read_packet. */
@@ -2032,7 +2325,7 @@ matroska_read_header (AVFormatContext    *s,
             if (track->codec_id == NULL)
                 continue;
 
-            for(j=0; ff_mkv_codec_tags[j].str; j++){
+            for(j=0; ff_mkv_codec_tags[j].id != CODEC_ID_NONE; j++){
                 if(!strncmp(ff_mkv_codec_tags[j].str, track->codec_id,
                             strlen(ff_mkv_codec_tags[j].str))){
                     codec_id= ff_mkv_codec_tags[j].id;
@@ -2098,7 +2391,7 @@ matroska_read_header (AVFormatContext    *s,
                     return AVERROR(ENOMEM);
                 init_put_byte(&b, extradata, extradata_size, 1,
                               NULL, NULL, NULL, NULL);
-                put_buffer(&b, (uint8_t *) "TTA1", 4);
+                put_buffer(&b, "TTA1", 4);
                 put_le16(&b, 1);
                 put_le16(&b, audiotrack->channels);
                 put_le16(&b, audiotrack->bitdepth);
@@ -2143,15 +2436,6 @@ matroska_read_header (AVFormatContext    *s,
                 }
             }
 
-            else if (codec_id == CODEC_ID_TEXT) {
-                MatroskaSubtitleTrack *subtrack=(MatroskaSubtitleTrack *)track;
-                if (!strcmp(track->codec_id, "S_TEXT/ASS") ||
-                    !strcmp(track->codec_id, "S_TEXT/SSA") ||
-                    !strcmp(track->codec_id, "S_ASS") ||
-                    !strcmp(track->codec_id, "S_SSA"))
-                    subtrack->ass = 1;
-            }
-
             if (codec_id == CODEC_ID_NONE) {
                 av_log(matroska->ctx, AV_LOG_INFO,
                        "Unknown/unsupported CodecID %s.\n",
@@ -2171,6 +2455,9 @@ matroska_read_header (AVFormatContext    *s,
             if (strcmp(track->language, "und"))
                 strcpy(st->language, track->language);
 
+            if (track->flags & MATROSKA_TRACK_DEFAULT)
+                st->disposition |= AV_DISPOSITION_DEFAULT;
+
             if (track->default_duration)
                 av_reduce(&st->codec->time_base.num, &st->codec->time_base.den,
                           track->default_duration, 1000000000, 30000);
@@ -2225,8 +2512,9 @@ matroska_read_header (AVFormatContext    *s,
         for (i=0; i<matroska->num_indexes; i++) {
             MatroskaDemuxIndex *idx = &matroska->index[i];
             track = matroska_find_track_by_num(matroska, idx->track);
+            if (track < 0)  continue;
             stream = matroska->tracks[track]->stream_index;
-            if (stream >= 0)
+            if (stream >= 0 && stream < matroska->ctx->nb_streams)
                 av_add_index_entry(matroska->ctx->streams[stream],
                                    idx->pos, idx->time/matroska->time_scale,
                                    0, 0, AVINDEX_KEYFRAME);
@@ -2250,6 +2538,7 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
     uint32_t *lace_size = NULL;
     int n, flags, laces = 0;
     uint64_t num;
+    int stream_index;
 
     /* first byte(s): tracknum */
     if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) {
@@ -2268,9 +2557,12 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
         av_free(origdata);
         return res;
     }
-    if (matroska->tracks[track]->stream_index < 0)
+    stream_index = matroska->tracks[track]->stream_index;
+    if (stream_index < 0 || stream_index >= matroska->ctx->nb_streams) {
+        av_free(origdata);
         return res;
-    st = matroska->ctx->streams[matroska->tracks[track]->stream_index];
+    }
+    st = matroska->ctx->streams[stream_index];
     if (st->discard >= AVDISCARD_ALL) {
         av_free(origdata);
         return res;
@@ -2287,8 +2579,10 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
         is_keyframe = flags & 0x80 ? PKT_FLAG_KEY : 0;
 
     if (matroska->skip_to_keyframe) {
-        if (!is_keyframe || st != matroska->skip_to_stream)
+        if (!is_keyframe || st != matroska->skip_to_stream) {
+            av_free(origdata);
             return res;
+        }
         matroska->skip_to_keyframe = 0;
     }
 
@@ -2411,32 +2705,98 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
                     memcpy(pkt->data, audiotrack->buf
                            + a * (h*w / a - audiotrack->pkt_cnt--), a);
                     pkt->pos = pos;
-                    pkt->stream_index = matroska->tracks[track]->stream_index;
+                    pkt->stream_index = stream_index;
                     matroska_queue_packet(matroska, pkt);
                 }
             } else {
-                int offset = 0;
-
-                if (st->codec->codec_id == CODEC_ID_TEXT
-                    && ((MatroskaSubtitleTrack *)(matroska->tracks[track]))->ass) {
-                    int i;
-                    for (i=0; i<8 && data[offset]; offset++)
-                        if (data[offset] == ',')
-                            i++;
+                int result, offset = 0, ilen, olen, pkt_size = lace_size[n];
+                uint8_t *pkt_data = data;
+
+                if (matroska->tracks[track]->encoding_scope & 1) {
+                    switch (matroska->tracks[track]->encoding_algo) {
+                    case MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP:
+                        offset = matroska->tracks[track]->encoding_settings_len;
+                        break;
+                    case MATROSKA_TRACK_ENCODING_COMP_LZO:
+                        pkt_data = NULL;
+                        do {
+                            ilen = lace_size[n];
+                            olen = pkt_size *= 3;
+                            pkt_data = av_realloc(pkt_data,
+                                                  pkt_size+LZO_OUTPUT_PADDING);
+                            result = lzo1x_decode(pkt_data, &olen, data, &ilen);
+                        } while (result==LZO_OUTPUT_FULL && pkt_size<10000000);
+                        if (result) {
+                            av_free(pkt_data);
+                            continue;
+                        }
+                        pkt_size -= olen;
+                        break;
+#ifdef CONFIG_ZLIB
+                    case MATROSKA_TRACK_ENCODING_COMP_ZLIB: {
+                        z_stream zstream = {0};
+                        pkt_data = NULL;
+                        if (inflateInit(&zstream) != Z_OK)
+                            continue;
+                        zstream.next_in = data;
+                        zstream.avail_in = lace_size[n];
+                        do {
+                            pkt_size *= 3;
+                            pkt_data = av_realloc(pkt_data, pkt_size);
+                            zstream.avail_out = pkt_size - zstream.total_out;
+                            zstream.next_out = pkt_data + zstream.total_out;
+                            result = inflate(&zstream, Z_NO_FLUSH);
+                        } while (result==Z_OK && pkt_size<10000000);
+                        pkt_size = zstream.total_out;
+                        inflateEnd(&zstream);
+                        if (result != Z_STREAM_END) {
+                            av_free(pkt_data);
+                            continue;
+                        }
+                        break;
+                    }
+#endif
+#ifdef CONFIG_BZLIB
+                    case MATROSKA_TRACK_ENCODING_COMP_BZLIB: {
+                        bz_stream bzstream = {0};
+                        pkt_data = NULL;
+                        if (BZ2_bzDecompressInit(&bzstream, 0, 0) != BZ_OK)
+                            continue;
+                        bzstream.next_in = data;
+                        bzstream.avail_in = lace_size[n];
+                        do {
+                            pkt_size *= 3;
+                            pkt_data = av_realloc(pkt_data, pkt_size);
+                            bzstream.avail_out = pkt_size - bzstream.total_out_lo32;
+                            bzstream.next_out = pkt_data + bzstream.total_out_lo32;
+                            result = BZ2_bzDecompress(&bzstream);
+                        } while (result==BZ_OK && pkt_size<10000000);
+                        pkt_size = bzstream.total_out_lo32;
+                        BZ2_bzDecompressEnd(&bzstream);
+                        if (result != BZ_STREAM_END) {
+                            av_free(pkt_data);
+                            continue;
+                        }
+                        break;
+                    }
+#endif
+                    }
                 }
 
                 pkt = av_mallocz(sizeof(AVPacket));
                 /* XXX: prevent data copy... */
-                if (av_new_packet(pkt, lace_size[n]-offset) < 0) {
+                if (av_new_packet(pkt, pkt_size+offset) < 0) {
                     res = AVERROR(ENOMEM);
                     n = laces-1;
                     break;
                 }
-                memcpy (pkt->data, data+offset, lace_size[n]-offset);
+                if (offset)
+                    memcpy (pkt->data, matroska->tracks[track]->encoding_settings, offset);
+                memcpy (pkt->data+offset, pkt_data, pkt_size);
 
                 if (n == 0)
                     pkt->flags = is_keyframe;
-                pkt->stream_index = matroska->tracks[track]->stream_index;
+                pkt->stream_index = stream_index;
 
                 pkt->pts = timecode;
                 pkt->pos = pos;
@@ -2485,7 +2845,7 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska,
              * of the harder things, so this code is a bit complicated.
              * See http://www.matroska.org/ for documentation. */
             case MATROSKA_ID_BLOCK: {
-                pos = url_ftell(&matroska->ctx->pb);
+                pos = url_ftell(matroska->ctx->pb);
                 res = ebml_read_binary(matroska, &id, &data, &size);
                 break;
             }
@@ -2547,7 +2907,7 @@ matroska_parse_cluster (MatroskaDemuxContext *matroska)
     int size;
 
     av_log(matroska->ctx, AV_LOG_DEBUG,
-           "parsing cluster at %"PRId64"\n", url_ftell(&matroska->ctx->pb));
+           "parsing cluster at %"PRId64"\n", url_ftell(matroska->ctx->pb));
 
     while (res == 0) {
         if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
@@ -2576,7 +2936,7 @@ matroska_parse_cluster (MatroskaDemuxContext *matroska)
                 break;
 
             case MATROSKA_ID_SIMPLEBLOCK:
-                pos = url_ftell(&matroska->ctx->pb);
+                pos = url_ftell(matroska->ctx->pb);
                 res = ebml_read_binary(matroska, &id, &data, &size);
                 if (res == 0)
                     res = matroska_parse_block(matroska, data, size, pos,
@@ -2667,11 +3027,12 @@ matroska_read_seek (AVFormatContext *s, int stream_index, int64_t timestamp,
     if (index < 0)
         return 0;
 
+    matroska_clear_queue(matroska);
+
     /* do the seek */
-    url_fseek(&s->pb, st->index_entries[index].pos, SEEK_SET);
+    url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET);
     matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY);
     matroska->skip_to_stream = st;
-    matroska->num_packets = 0;
     matroska->peek_id = 0;
     return 0;
 }
@@ -2686,13 +3047,7 @@ matroska_read_close (AVFormatContext *s)
     av_free(matroska->muxing_app);
     av_free(matroska->index);
 
-    if (matroska->packets != NULL) {
-        for (n = 0; n < matroska->num_packets; n++) {
-            av_free_packet(matroska->packets[n]);
-            av_free(matroska->packets[n]);
-        }
-        av_free(matroska->packets);
-    }
+    matroska_clear_queue(matroska);
 
     for (n = 0; n < matroska->num_tracks; n++) {
         MatroskaTrack *track = matroska->tracks[n];