]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/matroskadec.c
Prevent invalid timestamps from being stored.
[ffmpeg] / libavformat / matroskadec.c
index 13c2e155288a20136c6d44b104851d53302aa6aa..bea76f47d9656b89e92bef2209ba89c577507e76 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;
@@ -49,16 +55,16 @@ typedef struct Track {
     char language[4];
 
     char *codec_id;
-    char *codec_name;
 
     unsigned char *codec_priv;
     int codec_priv_size;
 
+    double time_scale;
     uint64_t default_duration;
     MatroskaTrackFlags flags;
 
     int encoding_scope;
-    int encoding_algo;
+    MatroskaTrackEncodingCompAlgo encoding_algo;
     uint8_t *encoding_settings;
     int encoding_settings_len;
 } MatroskaTrack;
@@ -73,9 +79,6 @@ typedef struct MatroskaVideoTrack {
 
     uint32_t fourcc;
 
-    MatroskaAspectRatioMode ar_mode;
-    MatroskaEyeMode eye_mode;
-
     //..
 } MatroskaVideoTrack;
 
@@ -127,11 +130,6 @@ typedef struct MatroskaDemuxContext {
     MatroskaLevel levels[EBML_MAX_DEPTH];
     int level_up;
 
-    /* matroska stuff */
-    char *writing_app;
-    char *muxing_app;
-    int64_t created;
-
     /* timescale in the file */
     int64_t time_scale;
 
@@ -165,6 +163,8 @@ typedef struct MatroskaDemuxContext {
     AVStream *skip_to_stream;
 } MatroskaDemuxContext;
 
+#define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))
+
 /*
  * The first few functions handle EBML file parsing. The rest
  * is the document interpretation. Matroska really just is a
@@ -496,6 +496,7 @@ ebml_read_ascii (MatroskaDemuxContext *matroska,
         offset_t pos = url_ftell(pb);
         av_log(matroska->ctx, AV_LOG_ERROR,
                "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos);
+        av_free(*str);
         return AVERROR(EIO);
     }
     (*str)[size] = '\0';
@@ -516,19 +517,6 @@ ebml_read_utf8 (MatroskaDemuxContext *matroska,
   return ebml_read_ascii(matroska, id, str);
 }
 
-/*
- * Read the next element as a date (nanoseconds since 1/1/2000).
- * 0 is success, < 0 is failure.
- */
-
-static int
-ebml_read_date (MatroskaDemuxContext *matroska,
-                uint32_t             *id,
-                int64_t              *date)
-{
-  return ebml_read_sint(matroska, id, date);
-}
-
 /*
  * Read the next element, but only the header. The contents
  * are supposed to be sub-elements which can be read separately.
@@ -961,35 +949,15 @@ matroska_parse_info (MatroskaDemuxContext *matroska)
                 break;
             }
 
-            case MATROSKA_ID_WRITINGAPP: {
-                char *text;
-                if ((res = ebml_read_utf8(matroska, &id, &text)) < 0)
-                    break;
-                matroska->writing_app = text;
-                break;
-            }
-
-            case MATROSKA_ID_MUXINGAPP: {
-                char *text;
-                if ((res = ebml_read_utf8(matroska, &id, &text)) < 0)
-                    break;
-                matroska->muxing_app = text;
-                break;
-            }
-
-            case MATROSKA_ID_DATEUTC: {
-                int64_t time;
-                if ((res = ebml_read_date(matroska, &id, &time)) < 0)
-                    break;
-                matroska->created = time;
-                break;
-            }
-
             default:
                 av_log(matroska->ctx, AV_LOG_INFO,
                        "Unknown entry 0x%x in info header\n", id);
                 /* fall-through */
 
+            case MATROSKA_ID_WRITINGAPP:
+            case MATROSKA_ID_MUXINGAPP:
+            case MATROSKA_ID_DATEUTC:
+            case MATROSKA_ID_SEGMENTUID:
             case EBML_ID_VOID:
                 res = ebml_read_skip(matroska);
                 break;
@@ -1004,6 +972,82 @@ matroska_parse_info (MatroskaDemuxContext *matroska)
     return res;
 }
 
+static int
+matroska_decode_buffer(uint8_t** buf, int* buf_size, MatroskaTrack *track)
+{
+    uint8_t* data = *buf;
+    int isize = *buf_size;
+    uint8_t* pkt_data = NULL;
+    int pkt_size = isize;
+    int result = 0;
+    int olen;
+
+    switch (track->encoding_algo) {
+    case MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP:
+        return track->encoding_settings_len;
+    case MATROSKA_TRACK_ENCODING_COMP_LZO:
+        do {
+            olen = pkt_size *= 3;
+            pkt_data = av_realloc(pkt_data,
+                                  pkt_size+LZO_OUTPUT_PADDING);
+            result = lzo1x_decode(pkt_data, &olen, data, &isize);
+        } while (result==LZO_OUTPUT_FULL && pkt_size<10000000);
+        if (result)
+            goto failed;
+        pkt_size -= olen;
+        break;
+#ifdef CONFIG_ZLIB
+    case MATROSKA_TRACK_ENCODING_COMP_ZLIB: {
+        z_stream zstream = {0};
+        if (inflateInit(&zstream) != Z_OK)
+            return -1;
+        zstream.next_in = data;
+        zstream.avail_in = isize;
+        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)
+            goto failed;
+        break;
+    }
+#endif
+#ifdef CONFIG_BZLIB
+    case MATROSKA_TRACK_ENCODING_COMP_BZLIB: {
+        bz_stream bzstream = {0};
+        if (BZ2_bzDecompressInit(&bzstream, 0, 0) != BZ_OK)
+            return -1;
+        bzstream.next_in = data;
+        bzstream.avail_in = isize;
+        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)
+            goto failed;
+        break;
+    }
+#endif
+    }
+
+    *buf = pkt_data;
+    *buf_size = pkt_size;
+    return 0;
+ failed:
+    av_free(pkt_data);
+    return -1;
+}
+
 static int
 matroska_add_stream (MatroskaDemuxContext *matroska)
 {
@@ -1011,17 +1055,17 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
     uint32_t id;
     MatroskaTrack *track;
 
+    /* start with the master */
+    if ((res = ebml_read_master(matroska, &id)) < 0)
+        return res;
+
     av_log(matroska->ctx, AV_LOG_DEBUG, "parsing track, adding stream..,\n");
 
-    /* Allocate a generic track. As soon as we know its type we'll realloc. */
+    /* Allocate a generic track. */
     track = av_mallocz(MAX_TRACK_SIZE);
-    matroska->num_tracks++;
+    track->time_scale = 1.0;
     strcpy(track->language, "eng");
 
-    /* start with the master */
-    if ((res = ebml_read_master(matroska, &id)) < 0)
-        return res;
-
     /* try reading the trackentry headers */
     while (res == 0) {
         if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
@@ -1075,10 +1119,9 @@ 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;
                 break;
             }
 
@@ -1182,46 +1225,6 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
                             break;
                         }
 
-                        /* stereo mode (whether the video has two streams,
-                         * where one is for the left eye and the other for
-                         * the right eye, which creates a 3D-like
-                         * effect) */
-                        case MATROSKA_ID_VIDEOSTEREOMODE: {
-                            uint64_t num;
-                            if ((res = ebml_read_uint(matroska, &id,
-                                                      &num)) < 0)
-                                break;
-                            if (num != MATROSKA_EYE_MODE_MONO &&
-                                num != MATROSKA_EYE_MODE_LEFT &&
-                                num != MATROSKA_EYE_MODE_RIGHT &&
-                                num != MATROSKA_EYE_MODE_BOTH) {
-                                av_log(matroska->ctx, AV_LOG_INFO,
-                                       "Ignoring unknown eye mode 0x%x\n",
-                                       (uint32_t) num);
-                                break;
-                            }
-                            videotrack->eye_mode = num;
-                            break;
-                        }
-
-                        /* aspect ratio behaviour */
-                        case MATROSKA_ID_VIDEOASPECTRATIO: {
-                            uint64_t num;
-                            if ((res = ebml_read_uint(matroska, &id,
-                                                      &num)) < 0)
-                                break;
-                            if (num != MATROSKA_ASPECT_RATIO_MODE_FREE &&
-                                num != MATROSKA_ASPECT_RATIO_MODE_KEEP &&
-                                num != MATROSKA_ASPECT_RATIO_MODE_FIXED) {
-                                av_log(matroska->ctx, AV_LOG_INFO,
-                                       "Ignoring unknown aspect ratio 0x%x\n",
-                                       (uint32_t) num);
-                                break;
-                            }
-                            videotrack->ar_mode = num;
-                            break;
-                        }
-
                         /* colorspace (only matters for raw video)
                          * fourcc */
                         case MATROSKA_ID_VIDEOCOLORSPACE: {
@@ -1239,6 +1242,8 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
                                    "0x%x - ignoring\n", id);
                             /* pass-through */
 
+                        case MATROSKA_ID_VIDEOSTEREOMODE:
+                        case MATROSKA_ID_VIDEOASPECTRATIO:
                         case EBML_ID_VOID:
                             res = ebml_read_skip(matroska);
                             break;
@@ -1357,15 +1362,6 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
                 break;
             }
 
-                /* name of the codec */
-            case MATROSKA_ID_CODECNAME: {
-                char *text;
-                if ((res = ebml_read_utf8(matroska, &id, &text)) < 0)
-                    break;
-                track->codec_name = text;
-                break;
-            }
-
                 /* name of this track */
             case MATROSKA_ID_TRACKNAME: {
                 char *text;
@@ -1500,9 +1496,15 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
                                                     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");
+                                                               "Unsupported compression algo\n");
                                                     track->encoding_algo = num;
                                                     break;
                                                 }
@@ -1576,6 +1578,14 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
                 break;
             }
 
+            case MATROSKA_ID_TRACKTIMECODESCALE: {
+                double num;
+                if ((res = ebml_read_float(matroska, &id, &num)) < 0)
+                    break;
+                track->time_scale = num;
+                break;
+            }
+
             default:
                 av_log(matroska->ctx, AV_LOG_INFO,
                        "Unknown track header entry 0x%x - ignoring\n", id);
@@ -1583,6 +1593,9 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
 
             case EBML_ID_VOID:
             /* we ignore these because they're nothing useful. */
+            case MATROSKA_ID_TRACKFLAGFORCED:
+            case MATROSKA_ID_CODECNAME:
+            case MATROSKA_ID_CODECDECODEALL:
             case MATROSKA_ID_CODECINFOURL:
             case MATROSKA_ID_CODECDOWNLOADURL:
             case MATROSKA_ID_TRACKMINCACHE:
@@ -1597,6 +1610,28 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
         }
     }
 
+    if (track->codec_priv_size && track->encoding_scope & 2) {
+        uint8_t *orig_priv = track->codec_priv;
+        int offset = matroska_decode_buffer(&track->codec_priv,
+                                            &track->codec_priv_size, track);
+        if (offset > 0) {
+            track->codec_priv = av_malloc(track->codec_priv_size + offset);
+            memcpy(track->codec_priv, track->encoding_settings, offset);
+            memcpy(track->codec_priv+offset, orig_priv, track->codec_priv_size);
+            track->codec_priv_size += offset;
+            av_free(orig_priv);
+        } else if (!offset) {
+            av_free(orig_priv);
+        } else
+            av_log(matroska->ctx, AV_LOG_ERROR,
+                   "Failed to decode codec private data\n");
+    }
+
+    if (track->type && matroska->num_tracks < ARRAY_SIZE(matroska->tracks)) {
+        matroska->tracks[matroska->num_tracks++] = track;
+    } else {
+        av_free(track);
+    }
     return res;
 }
 
@@ -1857,6 +1892,7 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska)
             case MATROSKA_ID_SEEKENTRY: {
                 uint32_t seek_id = 0, peek_id_cache = 0;
                 uint64_t seek_pos = (uint64_t) -1, t;
+                int dummy_level = 0;
 
                 if ((res = ebml_read_master(matroska, &id)) < 0)
                     break;
@@ -1933,6 +1969,7 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska)
                         level.length = (uint64_t)-1;
                         matroska->levels[matroska->num_levels] = level;
                         matroska->num_levels++;
+                        dummy_level = 1;
 
                         /* check ID */
                         if (!(id = ebml_peek_id (matroska,
@@ -1969,13 +2006,14 @@ matroska_parse_seekhead (MatroskaDemuxContext *matroska)
 
                     finish:
                         /* remove dummy level */
-                        while (matroska->num_levels) {
-                            matroska->num_levels--;
-                            length =
-                                matroska->levels[matroska->num_levels].length;
-                            if (length == (uint64_t)-1)
-                                break;
-                        }
+                        if (dummy_level)
+                            while (matroska->num_levels) {
+                                matroska->num_levels--;
+                                length =
+                                  matroska->levels[matroska->num_levels].length;
+                                if (length == (uint64_t)-1)
+                                    break;
+                            }
 
                         /* seek back */
                         if ((res = ebml_read_seek(matroska, before_pos)) < 0)
@@ -2068,6 +2106,7 @@ matroska_parse_attachments(AVFormatContext *s)
                 default:
                     av_log(matroska->ctx, AV_LOG_INFO,
                            "Unknown attachedfile ID 0x%x\n", id);
+                case MATROSKA_ID_FILEUID:
                 case EBML_ID_VOID:
                     res = ebml_read_skip(matroska);
                     break;
@@ -2127,7 +2166,161 @@ matroska_parse_attachments(AVFormatContext *s)
     return res;
 }
 
-#define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))
+static int
+matroska_parse_chapters(AVFormatContext *s)
+{
+    MatroskaDemuxContext *matroska = s->priv_data;
+    int res = 0;
+    uint32_t id;
+
+    av_log(s, AV_LOG_DEBUG, "parsing chapters...\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_EDITIONENTRY: {
+            uint64_t end = AV_NOPTS_VALUE, start = AV_NOPTS_VALUE;
+            int64_t uid= -1;
+            char* title = NULL;
+            /* if there is more than one chapter edition
+               we take only the first one */
+            if(s->chapters) {
+                    ebml_read_skip(matroska);
+                    break;
+            }
+
+            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_CHAPTERATOM:
+                    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_CHAPTERTIMEEND:
+                            res = ebml_read_uint(matroska, &id, &end);
+                            break;
+
+                        case MATROSKA_ID_CHAPTERTIMESTART:
+                            res = ebml_read_uint(matroska, &id, &start);
+                            break;
+
+                        case MATROSKA_ID_CHAPTERDISPLAY:
+                            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_CHAPSTRING:
+                                    res = ebml_read_utf8(matroska, &id, &title);
+                                    break;
+
+                                default:
+                                    av_log(s, AV_LOG_INFO, "Ignoring unknown Chapter display ID 0x%x\n", id);
+                                case EBML_ID_VOID:
+                                    res = ebml_read_skip(matroska);
+                                    break;
+                                }
+
+                                if (matroska->level_up) {
+                                    matroska->level_up--;
+                                    break;
+                                }
+                            }
+                            break;
+
+                        case MATROSKA_ID_CHAPTERUID:
+                            res = ebml_read_uint(matroska, &id, &uid);
+                            break;
+                        default:
+                            av_log(s, AV_LOG_INFO, "Ignoring unknown Chapter atom ID 0x%x\n", id);
+                        case MATROSKA_ID_CHAPTERFLAGHIDDEN:
+                        case EBML_ID_VOID:
+                            res = ebml_read_skip(matroska);
+                            break;
+                        }
+
+                        if (matroska->level_up) {
+                            matroska->level_up--;
+                            break;
+                        }
+                    }
+
+                    if (start != AV_NOPTS_VALUE && uid != -1) {
+                        if(!ff_new_chapter(s, uid, (AVRational){1, 1000000000}, start, end, title))
+                            res= AVERROR(ENOMEM);
+                    }
+                    av_free(title);
+                    break;
+
+                default:
+                    av_log(s, AV_LOG_INFO, "Ignoring unknown Edition entry ID 0x%x\n", id);
+                case MATROSKA_ID_EDITIONUID:
+                case MATROSKA_ID_EDITIONFLAGHIDDEN:
+                case MATROSKA_ID_EDITIONFLAGDEFAULT:
+                case EBML_ID_VOID:
+                    res = ebml_read_skip(matroska);
+                    break;
+                }
+
+
+                if (matroska->level_up) {
+                    matroska->level_up--;
+                    break;
+                }
+            }
+        break;
+        }
+
+        default:
+            av_log(s, AV_LOG_INFO, "Expected an Edition entry (0x%x), but found 0x%x\n", MATROSKA_ID_EDITIONENTRY, id);
+        case EBML_ID_VOID:
+            res = ebml_read_skip(matroska);
+            break;
+        }
+
+        if (matroska->level_up) {
+            matroska->level_up--;
+            break;
+        }
+    }
+
+    return res;
+}
 
 static int
 matroska_aac_profile (char *codec_id)
@@ -2279,6 +2472,13 @@ matroska_read_header (AVFormatContext    *s,
                 break;
             }
 
+            case MATROSKA_ID_CHAPTERS: {
+                if ((res = ebml_read_master(matroska, &id)) < 0)
+                    return res;
+                res = matroska_parse_chapters(s);
+                break;
+            }
+
             default:
                 av_log(matroska->ctx, AV_LOG_INFO,
                        "Unknown matroska file header ID 0x%x\n", id);
@@ -2436,7 +2636,7 @@ matroska_read_header (AVFormatContext    *s,
             st = av_new_stream(s, track->stream_index);
             if (st == NULL)
                 return AVERROR(ENOMEM);
-            av_set_pts_info(st, 64, matroska->time_scale, 1000*1000*1000); /* 64 bit pts in ns */
+            av_set_pts_info(st, 64, matroska->time_scale*track->time_scale, 1000*1000*1000); /* 64 bit pts in ns */
 
             st->codec->codec_id = codec_id;
             st->start_time = 0;
@@ -2504,7 +2704,7 @@ matroska_read_header (AVFormatContext    *s,
             stream = matroska->tracks[track]->stream_index;
             if (stream >= 0 && stream < matroska->ctx->nb_streams)
                 av_add_index_entry(matroska->ctx->streams[stream],
-                                   idx->pos, idx->time/matroska->time_scale,
+                                   idx->pos, idx->time/AV_TIME_BASE,
                                    0, 0, AVINDEX_KEYFRAME);
         }
     }
@@ -2584,10 +2784,7 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
         case 0x1: /* xiph lacing */
         case 0x2: /* fixed-size lacing */
         case 0x3: /* EBML lacing */
-            if (size == 0) {
-                res = -1;
-                break;
-            }
+            assert(size>0); // size <=3 is checked before size-=3 above
             laces = (*data) + 1;
             data += 1;
             size -= 1;
@@ -2697,35 +2894,20 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
                     matroska_queue_packet(matroska, pkt);
                 }
             } else {
-                int result, offset = 0, ilen, olen, pkt_size = lace_size[n];
+                int offset = 0, 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;
-                    }
+                    offset = matroska_decode_buffer(&pkt_data, &pkt_size,
+                                                    matroska->tracks[track]);
+                    if (offset < 0)
+                        continue;
                 }
 
                 pkt = av_mallocz(sizeof(AVPacket));
                 /* XXX: prevent data copy... */
                 if (av_new_packet(pkt, pkt_size+offset) < 0) {
+                    av_free(pkt);
                     res = AVERROR(ENOMEM);
                     n = laces-1;
                     break;
@@ -2734,6 +2916,9 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
                     memcpy (pkt->data, matroska->tracks[track]->encoding_settings, offset);
                 memcpy (pkt->data+offset, pkt_data, pkt_size);
 
+                if (pkt_data != data)
+                    av_free(pkt_data);
+
                 if (n == 0)
                     pkt->flags = is_keyframe;
                 pkt->stream_index = stream_index;
@@ -2974,6 +3159,7 @@ matroska_read_seek (AVFormatContext *s, int stream_index, int64_t timestamp,
     matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY);
     matroska->skip_to_stream = st;
     matroska->peek_id = 0;
+    av_update_cur_dts(s, st, st->index_entries[index].timestamp);
     return 0;
 }
 
@@ -2983,8 +3169,6 @@ matroska_read_close (AVFormatContext *s)
     MatroskaDemuxContext *matroska = s->priv_data;
     int n = 0;
 
-    av_free(matroska->writing_app);
-    av_free(matroska->muxing_app);
     av_free(matroska->index);
 
     matroska_clear_queue(matroska);
@@ -2992,7 +3176,6 @@ matroska_read_close (AVFormatContext *s)
     for (n = 0; n < matroska->num_tracks; n++) {
         MatroskaTrack *track = matroska->tracks[n];
         av_free(track->codec_id);
-        av_free(track->codec_name);
         av_free(track->codec_priv);
         av_free(track->name);
 
@@ -3009,7 +3192,7 @@ matroska_read_close (AVFormatContext *s)
 
 AVInputFormat matroska_demuxer = {
     "matroska",
-    "Matroska file format",
+    NULL_IF_CONFIG_SMALL("Matroska file format"),
     sizeof(MatroskaDemuxContext),
     matroska_probe,
     matroska_read_header,