Merge commit 'c831ebf61629d219ebcaa9f02d262e67aad09d83'
authorMichael Niedermayer <michaelni@gmx.at>
Thu, 20 Sep 2012 18:37:26 +0000 (20:37 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Thu, 20 Sep 2012 18:39:47 +0000 (20:39 +0200)
* commit 'c831ebf61629d219ebcaa9f02d262e67aad09d83':
  matroskadec: split frame parsing
  matroskadec: split laces parsing

Conflicts:
libavformat/matroskadec.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavformat/matroskadec.c

@@@ -1,21 -1,21 +1,21 @@@
  /*
   * Matroska file demuxer
 - * Copyright (c) 2003-2008 The Libav Project
 + * Copyright (c) 2003-2008 The FFmpeg Project
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * 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.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * 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 Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -113,8 -113,7 +113,8 @@@ typedef struct 
      uint64_t display_height;
      uint64_t pixel_width;
      uint64_t pixel_height;
 -    uint64_t fourcc;
 +    EbmlBin color_space;
 +    uint64_t stereo_mode;
  } MatroskaTrackVideo;
  
  typedef struct {
  } MatroskaTrackAudio;
  
  typedef struct {
 +    uint64_t uid;
 +    uint64_t type;
 +} MatroskaTrackPlane;
 +
 +typedef struct {
 +    EbmlList combine_planes;
 +} MatroskaTrackOperation;
 +
 +typedef struct {
      uint64_t num;
      uint64_t uid;
      uint64_t type;
      uint64_t flag_forced;
      MatroskaTrackVideo video;
      MatroskaTrackAudio audio;
 +    MatroskaTrackOperation operation;
      EbmlList encodings;
  
      AVStream *stream;
@@@ -241,7 -230,6 +241,7 @@@ typedef struct 
      uint64_t time_scale;
      double   duration;
      char    *title;
 +    EbmlBin date_utc;
      EbmlList tracks;
      EbmlList attachments;
      EbmlList chapters;
@@@ -303,7 -291,7 +303,7 @@@ static EbmlSyntax matroska_info[] = 
      { MATROSKA_ID_TITLE,              EBML_UTF8,  0, offsetof(MatroskaDemuxContext,title) },
      { MATROSKA_ID_WRITINGAPP,         EBML_NONE },
      { MATROSKA_ID_MUXINGAPP,          EBML_NONE },
 -    { MATROSKA_ID_DATEUTC,            EBML_NONE },
 +    { MATROSKA_ID_DATEUTC,            EBML_BIN,  0, offsetof(MatroskaDemuxContext,date_utc) },
      { MATROSKA_ID_SEGMENTUID,         EBML_NONE },
      { 0 }
  };
@@@ -314,14 -302,14 +314,14 @@@ static EbmlSyntax matroska_track_video[
      { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_height) },
      { MATROSKA_ID_VIDEOPIXELWIDTH,    EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_width) },
      { MATROSKA_ID_VIDEOPIXELHEIGHT,   EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_height) },
 -    { MATROSKA_ID_VIDEOCOLORSPACE,    EBML_UINT, 0, offsetof(MatroskaTrackVideo,fourcc) },
 +    { MATROSKA_ID_VIDEOCOLORSPACE,    EBML_BIN,  0, offsetof(MatroskaTrackVideo,color_space) },
 +    { MATROSKA_ID_VIDEOSTEREOMODE,    EBML_UINT, 0, offsetof(MatroskaTrackVideo,stereo_mode) },
      { MATROSKA_ID_VIDEOPIXELCROPB,    EBML_NONE },
      { MATROSKA_ID_VIDEOPIXELCROPT,    EBML_NONE },
      { MATROSKA_ID_VIDEOPIXELCROPL,    EBML_NONE },
      { MATROSKA_ID_VIDEOPIXELCROPR,    EBML_NONE },
      { MATROSKA_ID_VIDEODISPLAYUNIT,   EBML_NONE },
      { MATROSKA_ID_VIDEOFLAGINTERLACED,EBML_NONE },
 -    { MATROSKA_ID_VIDEOSTEREOMODE,    EBML_NONE },
      { MATROSKA_ID_VIDEOASPECTRATIO,   EBML_NONE },
      { 0 }
  };
@@@ -353,22 -341,6 +353,22 @@@ static EbmlSyntax matroska_track_encodi
      { 0 }
  };
  
 +static EbmlSyntax matroska_track_plane[] = {
 +    { MATROSKA_ID_TRACKPLANEUID,  EBML_UINT, 0, offsetof(MatroskaTrackPlane,uid) },
 +    { MATROSKA_ID_TRACKPLANETYPE, EBML_UINT, 0, offsetof(MatroskaTrackPlane,type) },
 +    { 0 }
 +};
 +
 +static EbmlSyntax matroska_track_combine_planes[] = {
 +    { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n=matroska_track_plane} },
 +    { 0 }
 +};
 +
 +static EbmlSyntax matroska_track_operation[] = {
 +    { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n=matroska_track_combine_planes} },
 +    { 0 }
 +};
 +
  static EbmlSyntax matroska_track[] = {
      { MATROSKA_ID_TRACKNUMBER,          EBML_UINT, 0, offsetof(MatroskaTrack,num) },
      { MATROSKA_ID_TRACKNAME,            EBML_UTF8, 0, offsetof(MatroskaTrack,name) },
      { MATROSKA_ID_TRACKFLAGFORCED,      EBML_UINT, 0, offsetof(MatroskaTrack,flag_forced), {.u=0} },
      { MATROSKA_ID_TRACKVIDEO,           EBML_NEST, 0, offsetof(MatroskaTrack,video), {.n=matroska_track_video} },
      { MATROSKA_ID_TRACKAUDIO,           EBML_NEST, 0, offsetof(MatroskaTrack,audio), {.n=matroska_track_audio} },
 +    { MATROSKA_ID_TRACKOPERATION,       EBML_NEST, 0, offsetof(MatroskaTrack,operation), {.n=matroska_track_operation} },
      { MATROSKA_ID_TRACKCONTENTENCODINGS,EBML_NEST, 0, 0, {.n=matroska_track_encodings} },
      { MATROSKA_ID_TRACKFLAGENABLED,     EBML_NONE },
      { MATROSKA_ID_TRACKFLAGLACING,      EBML_NONE },
@@@ -527,7 -498,7 +527,7 @@@ static EbmlSyntax matroska_segments[] 
  static EbmlSyntax matroska_blockgroup[] = {
      { MATROSKA_ID_BLOCK,          EBML_BIN,  0, offsetof(MatroskaBlock,bin) },
      { MATROSKA_ID_SIMPLEBLOCK,    EBML_BIN,  0, offsetof(MatroskaBlock,bin) },
 -    { MATROSKA_ID_BLOCKDURATION,  EBML_UINT, 0, offsetof(MatroskaBlock,duration), {.u=AV_NOPTS_VALUE} },
 +    { MATROSKA_ID_BLOCKDURATION,  EBML_UINT, 0, offsetof(MatroskaBlock,duration) },
      { MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) },
      { 1,                          EBML_UINT, 0, offsetof(MatroskaBlock,non_simple), {.u=1} },
      { 0 }
@@@ -585,36 -556,6 +585,36 @@@ static EbmlSyntax matroska_clusters_inc
  
  static const char *const matroska_doctypes[] = { "matroska", "webm" };
  
 +static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos)
 +{
 +    AVIOContext *pb = matroska->ctx->pb;
 +    uint32_t id;
 +    matroska->current_id = 0;
 +    matroska->num_levels = 0;
 +
 +    // seek to next position to resync from
 +    if (avio_seek(pb, last_pos + 1, SEEK_SET) < 0 || avio_tell(pb) <= last_pos)
 +        goto eof;
 +
 +    id = avio_rb32(pb);
 +
 +    // try to find a toplevel element
 +    while (!url_feof(pb)) {
 +        if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS ||
 +            id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS ||
 +            id == MATROSKA_ID_SEEKHEAD || id == MATROSKA_ID_ATTACHMENTS ||
 +            id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS)
 +        {
 +            matroska->current_id = id;
 +            return 0;
 +        }
 +        id = (id << 8) | avio_r8(pb);
 +    }
 +eof:
 +    matroska->done = 1;
 +    return AVERROR_EOF;
 +}
 +
  /*
   * Return: Whether we reached the end of a level in the hierarchy or not.
   */
@@@ -652,7 -593,7 +652,7 @@@ static int ebml_read_num(MatroskaDemuxC
       * use it safely here to catch EOS. */
      if (!(total = avio_r8(pb))) {
          /* we might encounter EOS here */
 -        if (!pb->eof_reached) {
 +        if (!url_feof(pb)) {
              int64_t pos = avio_tell(pb);
              av_log(matroska->ctx, AV_LOG_ERROR,
                     "Read error at pos. %"PRIu64" (0x%"PRIx64")\n",
@@@ -946,10 -887,7 +946,10 @@@ static int ebml_parse_elem(MatroskaDemu
                       return ebml_parse_nest(matroska, syntax->def.n, data);
      case EBML_PASS:  return ebml_parse_id(matroska, syntax->def.n, id, data);
      case EBML_STOP:  return 1;
 -    default:         return avio_skip(pb,length)<0 ? AVERROR(EIO) : 0;
 +    default:
 +        if(ffio_limit(pb, length) != length)
 +            return AVERROR(EIO);
 +        return avio_skip(pb,length)<0 ? AVERROR(EIO) : 0;
      }
      if (res == AVERROR_INVALIDDATA)
          av_log(matroska->ctx, AV_LOG_ERROR, "Invalid element\n");
@@@ -1053,7 -991,7 +1053,7 @@@ static int matroska_decode_buffer(uint8
      int result = 0;
      int olen;
  
 -    if (pkt_size >= 10000000)
 +    if (pkt_size >= 10000000U)
          return AVERROR_INVALIDDATA;
  
      switch (encodings[0].compression.algo) {
          int header_size = encodings[0].compression.settings.size;
          uint8_t *header = encodings[0].compression.settings.data;
  
 +        if (header_size && !header) {
 +            av_log(0, AV_LOG_ERROR, "Compression size but no data in headerstrip\n");
 +            return -1;
 +        }
 +
          if (!header_size)
              return 0;
  
              pkt_data = newpktdata;
              zstream.avail_out = pkt_size - zstream.total_out;
              zstream.next_out = pkt_data + zstream.total_out;
 -            result = inflate(&zstream, Z_NO_FLUSH);
 +            if (pkt_data) {
 +                result = inflate(&zstream, Z_NO_FLUSH);
 +            } else
 +                result = Z_MEM_ERROR;
          } while (result==Z_OK && pkt_size<10000000);
          pkt_size = zstream.total_out;
          inflateEnd(&zstream);
              pkt_data = newpktdata;
              bzstream.avail_out = pkt_size - bzstream.total_out_lo32;
              bzstream.next_out = pkt_data + bzstream.total_out_lo32;
 -            result = BZ2_bzDecompress(&bzstream);
 +            if (pkt_data) {
 +                result = BZ2_bzDecompress(&bzstream);
 +            } else
 +                result = BZ_MEM_ERROR;
          } while (result==BZ_OK && pkt_size<10000000);
          pkt_size = bzstream.total_out_lo32;
          BZ2_bzDecompressEnd(&bzstream);
@@@ -1181,8 -1108,7 +1181,8 @@@ static void matroska_fix_ass_packet(Mat
      char *line, *layer, *ptr = pkt->data, *end = ptr+pkt->size;
      for (; *ptr!=',' && ptr<end-1; ptr++);
      if (*ptr == ',')
 -        layer = ++ptr;
 +        ptr++;
 +    layer = ptr;
      for (; *ptr!=',' && ptr<end-1; ptr++);
      if (*ptr == ',') {
          int64_t end_pts = pkt->pts + display_duration;
  
  static int matroska_merge_packets(AVPacket *out, AVPacket *in)
  {
 -    void *newdata = av_realloc(out->data, out->size+in->size);
 -    if (!newdata)
 -        return AVERROR(ENOMEM);
 -    out->data = newdata;
 -    memcpy(out->data+out->size, in->data, in->size);
 -    out->size += in->size;
 +    int ret = av_grow_packet(out, in->size);
 +    if (ret < 0)
 +        return ret;
 +    memcpy(out->data + out->size - in->size, in->data, in->size);
      av_destruct_packet(in);
      av_free(in);
      return 0;
@@@ -1226,7 -1154,7 +1226,7 @@@ static void matroska_convert_tag(AVForm
      int i;
  
      for (i=0; i < list->nb_elem; i++) {
 -        const char *lang = strcmp(tags[i].lang, "und") ? tags[i].lang : NULL;
 +        const char *lang= (tags[i].lang && strcmp(tags[i].lang, "und")) ? tags[i].lang : NULL;
  
          if (!tags[i].name) {
              av_log(s, AV_LOG_WARNING, "Skipping invalid tag with no TagName.\n");
@@@ -1357,20 -1285,26 +1357,20 @@@ static void matroska_execute_seekhead(M
              continue;
          }
  
 -        if (matroska_parse_seekhead_entry(matroska, i) < 0)
 +        if (matroska_parse_seekhead_entry(matroska, i) < 0) {
 +            // mark index as broken
 +            matroska->cues_parsing_deferred = -1;
              break;
 +        }
      }
  }
  
 -static void matroska_parse_cues(MatroskaDemuxContext *matroska) {
 -    EbmlList *seekhead_list = &matroska->seekhead;
 -    MatroskaSeekhead *seekhead = seekhead_list->elem;
 +static void matroska_add_index_entries(MatroskaDemuxContext *matroska) {
      EbmlList *index_list;
      MatroskaIndex *index;
      int index_scale = 1;
      int i, j;
  
 -    for (i = 0; i < seekhead_list->nb_elem; i++)
 -        if (seekhead[i].id == MATROSKA_ID_CUES)
 -            break;
 -    assert(i <= seekhead_list->nb_elem);
 -
 -    matroska_parse_seekhead_entry(matroska, i);
 -
      index_list = &matroska->index;
      index = index_list->elem;
      if (index_list->nb_elem
      }
  }
  
 +static void matroska_parse_cues(MatroskaDemuxContext *matroska) {
 +    EbmlList *seekhead_list = &matroska->seekhead;
 +    MatroskaSeekhead *seekhead = seekhead_list->elem;
 +    int i;
 +
 +    for (i = 0; i < seekhead_list->nb_elem; i++)
 +        if (seekhead[i].id == MATROSKA_ID_CUES)
 +            break;
 +    assert(i <= seekhead_list->nb_elem);
 +
 +    if (matroska_parse_seekhead_entry(matroska, i) < 0)
 +       matroska->cues_parsing_deferred = -1;
 +    matroska_add_index_entries(matroska);
 +}
 +
  static int matroska_aac_profile(char *codec_id)
  {
      static const char * const aac_profiles[] = { "MAIN", "LC", "SSR" };
@@@ -1428,17 -1347,6 +1428,17 @@@ static int matroska_aac_sri(int sampler
      return sri;
  }
  
 +static void matroska_metadata_creation_time(AVDictionary **metadata, int64_t date_utc)
 +{
 +    char buffer[32];
 +    /* Convert to seconds and adjust by number of seconds between 2001-01-01 and Epoch */
 +    time_t creation_time = date_utc / 1000000000 + 978307200;
 +    struct tm *ptm = gmtime(&creation_time);
 +    if (!ptm) return;
 +    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ptm);
 +    av_dict_set(metadata, "creation_time", buffer, 0);
 +}
 +
  static int matroska_read_header(AVFormatContext *s)
  {
      MatroskaDemuxContext *matroska = s->priv_data;
      MatroskaChapter *chapters;
      MatroskaTrack *tracks;
      uint64_t max_start = 0;
 +    int64_t pos;
      Ebml ebml = { 0 };
      AVStream *st;
 -    int i, j, res;
 +    int i, j, k, res;
  
      matroska->ctx = s;
  
      /* First read the EBML header. */
      if (ebml_parse(matroska, ebml_syntax, &ebml)
          || ebml.version > EBML_VERSION       || ebml.max_size > sizeof(uint64_t)
 -        || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 2) {
 +        || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 3 || !ebml.doctype) {
          av_log(matroska->ctx, AV_LOG_ERROR,
                 "EBML header using unsupported features\n"
                 "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
                 ebml.version, ebml.doctype, ebml.doctype_version);
          ebml_free(ebml_syntax, &ebml);
          return AVERROR_PATCHWELCOME;
 +    } else if (ebml.doctype_version == 3) {
 +        av_log(matroska->ctx, AV_LOG_WARNING,
 +               "EBML header using unsupported features\n"
 +               "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
 +               ebml.version, ebml.doctype, ebml.doctype_version);
      }
      for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++)
          if (!strcmp(ebml.doctype, matroska_doctypes[i]))
      ebml_free(ebml_syntax, &ebml);
  
      /* The next thing is a segment. */
 -    if ((res = ebml_parse(matroska, matroska_segments, matroska)) < 0)
 -        return res;
 +    pos = avio_tell(matroska->ctx->pb);
 +    res = ebml_parse(matroska, matroska_segments, matroska);
 +    // try resyncing until we find a EBML_STOP type element.
 +    while (res != 1) {
 +        res = matroska_resync(matroska, pos);
 +        if (res < 0)
 +            return res;
 +        pos = avio_tell(matroska->ctx->pb);
 +        res = ebml_parse(matroska, matroska_segment, matroska);
 +    }
      matroska_execute_seekhead(matroska);
  
      if (!matroska->time_scale)
                                    * 1000 / AV_TIME_BASE;
      av_dict_set(&s->metadata, "title", matroska->title, 0);
  
 +    if (matroska->date_utc.size == 8)
 +        matroska_metadata_creation_time(&s->metadata, AV_RB64(matroska->date_utc.data));
 +
      tracks = matroska->tracks.elem;
      for (i=0; i < matroska->tracks.nb_elem; i++) {
          MatroskaTrack *track = &tracks[i];
          enum AVCodecID codec_id = AV_CODEC_ID_NONE;
 -        EbmlList *encodings_list = &tracks->encodings;
 +        EbmlList *encodings_list = &track->encodings;
          MatroskaTrackEncoding *encodings = encodings_list->elem;
          uint8_t *extradata = NULL;
          int extradata_size = 0;
          int extradata_offset = 0;
 +        uint32_t fourcc = 0;
          AVIOContext b;
  
          /* Apply some sanity checks. */
                  track->video.display_width = track->video.pixel_width;
              if (!track->video.display_height)
                  track->video.display_height = track->video.pixel_height;
 +            if (track->video.color_space.size == 4)
 +                fourcc = AV_RL32(track->video.color_space.data);
          } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
              if (!track->audio.out_samplerate)
                  track->audio.out_samplerate = track->audio.samplerate;
              && track->codec_priv.size >= 40
              && track->codec_priv.data != NULL) {
              track->ms_compat = 1;
 -            track->video.fourcc = AV_RL32(track->codec_priv.data + 16);
 -            codec_id = ff_codec_get_id(ff_codec_bmp_tags, track->video.fourcc);
 +            fourcc = AV_RL32(track->codec_priv.data + 16);
 +            codec_id = ff_codec_get_id(ff_codec_bmp_tags, fourcc);
              extradata_offset = 40;
          } else if (!strcmp(track->codec_id, "A_MS/ACM")
                     && track->codec_priv.size >= 14
          } else if (!strcmp(track->codec_id, "V_QUICKTIME")
                     && (track->codec_priv.size >= 86)
                     && (track->codec_priv.data != NULL)) {
 -            track->video.fourcc = AV_RL32(track->codec_priv.data);
 -            codec_id=ff_codec_get_id(ff_codec_movvideo_tags, track->video.fourcc);
 +            fourcc = AV_RL32(track->codec_priv.data);
 +            codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc);
 +        } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX-12) {
 +            /* Only ALAC's magic cookie is stored in Matroska's track headers.
 +               Create the "atom size", "tag", and "tag version" fields the
 +               decoder expects manually. */
 +            extradata_size = 12 + track->codec_priv.size;
 +            extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
 +            if (extradata == NULL)
 +                return AVERROR(ENOMEM);
 +            AV_WB32(extradata, extradata_size);
 +            memcpy(&extradata[4], "alac", 4);
 +            AV_WB32(&extradata[8], 0);
 +            memcpy(&extradata[12], track->codec_priv.data, track->codec_priv.size);
          } else if (codec_id == AV_CODEC_ID_PCM_S16BE) {
              switch (track->audio.bitdepth) {
              case  8:  codec_id = AV_CODEC_ID_PCM_U8;     break;
                  extradata_size = 5;
              } else
                  extradata_size = 2;
 -        } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size) {
 -            /* Only ALAC's magic cookie is stored in Matroska's track headers.
 -               Create the "atom size", "tag", and "tag version" fields the
 -               decoder expects manually. */
 -            extradata_size = 12 + track->codec_priv.size;
 -            extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
 -            if (extradata == NULL)
 -                return AVERROR(ENOMEM);
 -            AV_WB32(extradata, extradata_size);
 -            memcpy(&extradata[4], "alac", 4);
 -            AV_WB32(&extradata[8], 0);
 -            memcpy(&extradata[12], track->codec_priv.data,
 -                                   track->codec_priv.size);
          } else if (codec_id == AV_CODEC_ID_TTA) {
              extradata_size = 30;
 -            extradata = av_mallocz(extradata_size);
 +            extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
              if (extradata == NULL)
                  return AVERROR(ENOMEM);
              ffio_init_context(&b, extradata, extradata_size, 1,
          } else if (codec_id == AV_CODEC_ID_RA_144) {
              track->audio.out_samplerate = 8000;
              track->audio.channels = 1;
 -        } else if (codec_id == AV_CODEC_ID_RA_288 || codec_id == AV_CODEC_ID_COOK ||
 -                   codec_id == AV_CODEC_ID_ATRAC3 || codec_id == AV_CODEC_ID_SIPR) {
 +        } else if ((codec_id == AV_CODEC_ID_RA_288 || codec_id == AV_CODEC_ID_COOK ||
 +                    codec_id == AV_CODEC_ID_ATRAC3 || codec_id == AV_CODEC_ID_SIPR)
 +                    && track->codec_priv.data) {
              int flavor;
 +
              ffio_init_context(&b, track->codec_priv.data,track->codec_priv.size,
                            0, NULL, NULL, NULL, NULL);
              avio_skip(&b, 22);
          }
  
          if (track->type == MATROSKA_TRACK_TYPE_VIDEO) {
 +            MatroskaTrackPlane *planes = track->operation.combine_planes.elem;
 +
              st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
 -            st->codec->codec_tag  = track->video.fourcc;
 +            st->codec->codec_tag  = fourcc;
              st->codec->width  = track->video.pixel_width;
              st->codec->height = track->video.pixel_height;
              av_reduce(&st->sample_aspect_ratio.num,
                        st->codec->height * track->video.display_width,
                        st->codec-> width * track->video.display_height,
                        255);
 -            if (st->codec->codec_id != AV_CODEC_ID_H264)
              st->need_parsing = AVSTREAM_PARSE_HEADERS;
              if (track->default_duration) {
                  av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
                  st->r_frame_rate = st->avg_frame_rate;
  #endif
              }
 +
 +            /* export stereo mode flag as metadata tag */
 +            if (track->video.stereo_mode && track->video.stereo_mode < MATROSKA_VIDEO_STEREO_MODE_COUNT)
 +                av_dict_set(&st->metadata, "stereo_mode", ff_matroska_video_stereo_mode[track->video.stereo_mode], 0);
 +
 +            /* if we have virtual track, mark the real tracks */
 +            for (j=0; j < track->operation.combine_planes.nb_elem; j++) {
 +                char buf[32];
 +                if (planes[j].type >= MATROSKA_VIDEO_STEREO_PLANE_COUNT)
 +                    continue;
 +                snprintf(buf, sizeof(buf), "%s_%d",
 +                         ff_matroska_video_stereo_plane[planes[j].type], i);
 +                for (k=0; k < matroska->tracks.nb_elem; k++)
 +                    if (planes[j].uid == tracks[k].uid) {
 +                        av_dict_set(&s->streams[k]->metadata,
 +                                    "stereo_mode", buf, 0);
 +                        break;
 +                    }
 +            }
          } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
              st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
              st->codec->sample_rate = track->audio.out_samplerate;
              av_dict_set(&st->metadata, "mimetype", attachements[j].mime, 0);
              st->codec->codec_id = AV_CODEC_ID_NONE;
              st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
 -            st->codec->extradata  = av_malloc(attachements[j].bin.size);
 +            st->codec->extradata  = av_malloc(attachements[j].bin.size + FF_INPUT_BUFFER_PADDING_SIZE);
              if(st->codec->extradata == NULL)
                  break;
              st->codec->extradata_size = attachements[j].bin.size;
              max_start = chapters[i].start;
          }
  
 +    matroska_add_index_entries(matroska);
 +
      matroska_convert_tags(s);
  
      return 0;
@@@ -1884,6 -1749,247 +1884,266 @@@ static void matroska_clear_queue(Matros
      }
  }
  
 -    assert(size > 0);
+ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
+                                 int size, int type,
+                                 uint32_t **lace_buf, int *laces)
+ {
+     int res = 0, n;
+     uint8_t *data = *buf;
+     uint32_t *lace_size;
+     if (!type) {
+         *laces = 1;
+         *lace_buf = av_mallocz(sizeof(int));
+         if (!*lace_buf)
+             return AVERROR(ENOMEM);
+         *lace_buf[0] = size;
+         return 0;
+     }
 -        if (size != (size / *laces) * size) {
++    av_assert0(size > 0);
+     *laces = *data + 1;
+     data += 1;
+     size -= 1;
+     lace_size = av_mallocz(*laces * sizeof(int));
+     if (!lace_size)
+         return AVERROR(ENOMEM);
+     switch (type) {
+     case 0x1: /* Xiph lacing */ {
+         uint8_t temp;
+         uint32_t total = 0;
+         for (n = 0; res == 0 && n < *laces - 1; n++) {
+             while (1) {
+                 if (size == 0) {
+                     res = AVERROR_EOF;
+                     break;
+                 }
+                 temp = *data;
+                 lace_size[n] += temp;
+                 data += 1;
+                 size -= 1;
+                 if (temp != 0xff)
+                     break;
+             }
+             total += lace_size[n];
+         }
+         if (size <= total) {
+             res = AVERROR_INVALIDDATA;
+             break;
+         }
+         lace_size[n] = size - total;
+         break;
+     }
+     case 0x2: /* fixed-size lacing */
 -                                uint64_t timecode, uint64_t duration,
++        if (size != (size / *laces) * *laces) {
+             res = AVERROR_INVALIDDATA;
+             break;
+         }
+         for (n = 0; n < *laces; n++)
+             lace_size[n] = size / *laces;
+         break;
+     case 0x3: /* EBML lacing */ {
+         uint64_t num;
+         uint32_t total;
+         n = matroska_ebmlnum_uint(matroska, data, size, &num);
+         if (n < 0) {
+             av_log(matroska->ctx, AV_LOG_INFO,
+                    "EBML block data error\n");
+             res = n;
+             break;
+         }
+         data += n;
+         size -= n;
+         total = lace_size[0] = num;
+         for (n = 1; res == 0 && n < *laces - 1; n++) {
+             int64_t snum;
+             int r;
+             r = matroska_ebmlnum_sint(matroska, data, size, &snum);
+             if (r < 0) {
+                 av_log(matroska->ctx, AV_LOG_INFO,
+                        "EBML block data error\n");
+                 res = r;
+                 break;
+             }
+             data += r;
+             size -= r;
+             lace_size[n] = lace_size[n - 1] + snum;
+             total += lace_size[n];
+         }
+         if (size <= total) {
+             res = AVERROR_INVALIDDATA;
+             break;
+         }
+         lace_size[*laces - 1] = size - total;
+         break;
+     }
+     }
+     *buf      = data;
+     *lace_buf = lace_size;
+     return res;
+ }
+ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
+                                    MatroskaTrack *track,
+                                    AVStream *st,
+                                    uint8_t *data, int size,
+                                    uint64_t timecode, uint64_t duration,
+                                    int64_t pos)
+ {
+     int a = st->codec->block_align;
+     int sps = track->audio.sub_packet_size;
+     int cfs = track->audio.coded_framesize;
+     int h = track->audio.sub_packet_h;
+     int y = track->audio.sub_packet_cnt;
+     int w = track->audio.frame_size;
+     int x;
+     if (!track->audio.pkt_cnt) {
+         if (track->audio.sub_packet_cnt == 0)
+             track->audio.buf_timecode = timecode;
+         if (st->codec->codec_id == AV_CODEC_ID_RA_288) {
+             if (size < cfs * h / 2) {
+                 av_log(matroska->ctx, AV_LOG_ERROR,
+                        "Corrupt int4 RM-style audio packet size\n");
+                 return AVERROR_INVALIDDATA;
+             }
+             for (x=0; x<h/2; x++)
+                 memcpy(track->audio.buf+x*2*w+y*cfs,
+                        data+x*cfs, cfs);
+         } else if (st->codec->codec_id == AV_CODEC_ID_SIPR) {
+             if (size < w) {
+                 av_log(matroska->ctx, AV_LOG_ERROR,
+                        "Corrupt sipr RM-style audio packet size\n");
+                 return AVERROR_INVALIDDATA;
+             }
+             memcpy(track->audio.buf + y*w, data, w);
+         } else {
+             if (size < sps * w / sps) {
+                 av_log(matroska->ctx, AV_LOG_ERROR,
+                        "Corrupt generic RM-style audio packet size\n");
+                 return AVERROR_INVALIDDATA;
+             }
+             for (x=0; x<w/sps; x++)
+                 memcpy(track->audio.buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps);
+         }
+         if (++track->audio.sub_packet_cnt >= h) {
+             if (st->codec->codec_id == AV_CODEC_ID_SIPR)
+                 ff_rm_reorder_sipr_data(track->audio.buf, h, w);
+             track->audio.sub_packet_cnt = 0;
+             track->audio.pkt_cnt = h*w / a;
+         }
+     }
+     while (track->audio.pkt_cnt) {
+         AVPacket *pkt = av_mallocz(sizeof(AVPacket));
+         av_new_packet(pkt, a);
+         memcpy(pkt->data, track->audio.buf
+                + a * (h*w / a - track->audio.pkt_cnt--), a);
+         pkt->pts = track->audio.buf_timecode;
+         track->audio.buf_timecode = AV_NOPTS_VALUE;
+         pkt->pos = pos;
+         pkt->stream_index = st->index;
+         dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
+     }
+     return 0;
+ }
+ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
+                                 MatroskaTrack *track,
+                                 AVStream *st,
+                                 uint8_t *data, int pkt_size,
 -    if (st->codec->codec_id == AV_CODEC_ID_TEXT)
 -        pkt->convergence_duration = duration;
 -    else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE)
 -        pkt->duration = duration;
++                                uint64_t timecode, uint64_t lace_duration,
+                                 int64_t pos, int is_keyframe)
+ {
+     MatroskaTrackEncoding *encodings = track->encodings.elem;
+     uint8_t *pkt_data = data;
+     int offset = 0, res;
+     AVPacket *pkt;
+     if (encodings && encodings->scope & 1) {
+         res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
+         if (res < 0)
+             return res;
+     }
+     if (st->codec->codec_id == AV_CODEC_ID_PRORES)
+         offset = 8;
+     pkt = av_mallocz(sizeof(AVPacket));
+     /* XXX: prevent data copy... */
+     if (av_new_packet(pkt, pkt_size + offset) < 0) {
+         av_free(pkt);
+         return AVERROR(ENOMEM);
+     }
+     if (st->codec->codec_id == AV_CODEC_ID_PRORES) {
+         uint8_t *buf = pkt->data;
+         bytestream_put_be32(&buf, pkt_size);
+         bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f'));
+     }
+     memcpy(pkt->data + offset, pkt_data, pkt_size);
+     if (pkt_data != data)
+         av_free(pkt_data);
+     pkt->flags = is_keyframe;
+     pkt->stream_index = st->index;
+     if (track->ms_compat)
+         pkt->dts = timecode;
+     else
+         pkt->pts = timecode;
+     pkt->pos = pos;
 -        matroska_fix_ass_packet(matroska, pkt, duration);
++    if (st->codec->codec_id == AV_CODEC_ID_SUBRIP) {
++        /*
++         * For backward compatibility.
++         * Historically, we have put subtitle duration
++         * in convergence_duration, on the off chance
++         * that the time_scale is less than 1us, which
++         * could result in a 32bit overflow on the
++         * normal duration field.
++         */
++        pkt->convergence_duration = lace_duration;
++    }
++
++    if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE ||
++        lace_duration <= INT_MAX) {
++        /*
++         * For non subtitle tracks, just store the duration
++         * as normal.
++         *
++         * If it's a subtitle track and duration value does
++         * not overflow a uint32, then also store it normally.
++         */
++        pkt->duration = lace_duration;
++    }
+     if (st->codec->codec_id == AV_CODEC_ID_SSA)
++        matroska_fix_ass_packet(matroska, pkt, lace_duration);
+     if (matroska->prev_pkt &&
+         timecode != AV_NOPTS_VALUE &&
+         matroska->prev_pkt->pts == timecode &&
+         matroska->prev_pkt->stream_index == st->index &&
+         st->codec->codec_id == AV_CODEC_ID_SSA)
+         matroska_merge_packets(matroska->prev_pkt, pkt);
+     else {
+         dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
+         matroska->prev_pkt = pkt;
+     }
+     return 0;
+ }
  static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
                                  int size, int64_t pos, uint64_t cluster_time,
                                  uint64_t duration, int is_keyframe,
      MatroskaTrack *track;
      int res = 0;
      AVStream *st;
-     AVPacket *pkt;
      int16_t block_time;
      uint32_t *lace_size = NULL;
      int n, flags, laces = 0;
      st = track->stream;
      if (st->discard >= AVDISCARD_ALL)
          return res;
 -    if (duration == AV_NOPTS_VALUE)
 -        duration = track->default_duration / matroska->time_scale;
 +    av_assert1(duration != AV_NOPTS_VALUE);
  
      block_time = AV_RB16(data);
      data += 2;
              is_keyframe = 0;  /* overlapping subtitles are not key frame */
          if (is_keyframe)
              av_add_index_entry(st, cluster_pos, timecode, 0,0,AVINDEX_KEYFRAME);
 -        track->end_timecode = FFMAX(track->end_timecode, timecode+duration);
      }
  
      if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
 -        if (!is_keyframe || timecode < matroska->skip_to_timecode)
 +        if (timecode < matroska->skip_to_timecode)
              return res;
 -        matroska->skip_to_keyframe = 0;
 +        if (!st->skip_to_keyframe) {
 +            av_log(matroska->ctx, AV_LOG_ERROR, "File is broken, keyframes not correctly marked!\n");
 +            matroska->skip_to_keyframe = 0;
 +        }
 +        if (is_keyframe)
 +            matroska->skip_to_keyframe = 0;
      }
  
-     switch ((flags & 0x06) >> 1) {
-         case 0x0: /* no lacing */
-             laces = 1;
-             lace_size = av_mallocz(sizeof(int));
-             lace_size[0] = size;
-             break;
+     res = matroska_parse_laces(matroska, &data, size, (flags & 0x06) >> 1,
+                                &lace_size, &laces);
  
-         case 0x1: /* Xiph lacing */
-         case 0x2: /* fixed-size lacing */
-         case 0x3: /* EBML lacing */
-             av_assert0(size>0); // size <=3 is checked before size-=3 above
-             laces = (*data) + 1;
-             data += 1;
-             size -= 1;
-             lace_size = av_mallocz(laces * sizeof(int));
-             switch ((flags & 0x06) >> 1) {
-                 case 0x1: /* Xiph lacing */ {
-                     uint8_t temp;
-                     uint32_t total = 0;
-                     for (n = 0; res == 0 && n < laces - 1; n++) {
-                         while (1) {
-                             if (size == 0) {
-                                 res = -1;
-                                 break;
-                             }
-                             temp = *data;
-                             lace_size[n] += temp;
-                             data += 1;
-                             size -= 1;
-                             if (temp != 0xff)
-                                 break;
-                         }
-                         total += lace_size[n];
-                     }
-                     if (size <= total) {
-                         res = AVERROR_INVALIDDATA;
-                         goto end;
-                     }
-                     lace_size[n] = size - total;
-                     break;
-                 }
+     if (res)
+         goto end;
  
-                 case 0x2: /* fixed-size lacing */
-                     if (size != (size / laces) * laces) {
-                         res = AVERROR_INVALIDDATA;
-                         goto end;
-                     }
-                     for (n = 0; n < laces; n++)
-                         lace_size[n] = size / laces;
-                     break;
++    if (!duration)
++        duration = track->default_duration * laces / matroska->time_scale;
 +
-                 case 0x3: /* EBML lacing */ {
-                     uint32_t total;
-                     n = matroska_ebmlnum_uint(matroska, data, size, &num);
-                     if (n < 0) {
-                         av_log(matroska->ctx, AV_LOG_INFO,
-                                "EBML block data error\n");
-                         res = n;
-                         goto end;
-                     }
-                     data += n;
-                     size -= n;
-                     total = lace_size[0] = num;
-                     for (n = 1; res == 0 && n < laces - 1; n++) {
-                         int64_t snum;
-                         int r;
-                         r = matroska_ebmlnum_sint(matroska, data, size, &snum);
-                         if (r < 0) {
-                             av_log(matroska->ctx, AV_LOG_INFO,
-                                    "EBML block data error\n");
-                             res = r;
-                             goto end;
-                         }
-                         data += r;
-                         size -= r;
-                         lace_size[n] = lace_size[n - 1] + snum;
-                         total += lace_size[n];
-                     }
-                     if (size <= total) {
-                         res = AVERROR_INVALIDDATA;
-                         goto end;
-                     }
-                     lace_size[laces - 1] = size - total;
-                     break;
-                 }
-             }
-             break;
-     }
-     if (res == 0) {
-         if (!duration)
-             duration = track->default_duration * laces / matroska->time_scale;
-         if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time))
-             track->end_timecode = FFMAX(track->end_timecode, timecode+duration);
-         for (n = 0; n < laces; n++) {
-             int64_t lace_duration = duration*(n+1) / laces - duration*n / laces;
-             if (lace_size[n] > size) {
-                 av_log(matroska->ctx, AV_LOG_ERROR, "Invalid packet size\n");
-                 break;
-             }
-             if ((st->codec->codec_id == AV_CODEC_ID_RA_288 ||
-                  st->codec->codec_id == AV_CODEC_ID_COOK ||
-                  st->codec->codec_id == AV_CODEC_ID_SIPR ||
-                  st->codec->codec_id == AV_CODEC_ID_ATRAC3) &&
-                  st->codec->block_align && track->audio.sub_packet_size) {
-                 int a = st->codec->block_align;
-                 int sps = track->audio.sub_packet_size;
-                 int cfs = track->audio.coded_framesize;
-                 int h = track->audio.sub_packet_h;
-                 int y = track->audio.sub_packet_cnt;
-                 int w = track->audio.frame_size;
-                 int x;
-                 if (!track->audio.pkt_cnt) {
-                     if (track->audio.sub_packet_cnt == 0)
-                         track->audio.buf_timecode = timecode;
-                     if (st->codec->codec_id == AV_CODEC_ID_RA_288) {
-                         if (size < cfs * h / 2) {
-                             av_log(matroska->ctx, AV_LOG_ERROR,
-                                    "Corrupt int4 RM-style audio packet size\n");
-                             res = AVERROR_INVALIDDATA;
-                             goto end;
-                         }
-                         for (x=0; x<h/2; x++)
-                             memcpy(track->audio.buf+x*2*w+y*cfs,
-                                    data+x*cfs, cfs);
-                     } else if (st->codec->codec_id == AV_CODEC_ID_SIPR) {
-                         if (size < w) {
-                             av_log(matroska->ctx, AV_LOG_ERROR,
-                                    "Corrupt sipr RM-style audio packet size\n");
-                             res = AVERROR_INVALIDDATA;
-                             goto end;
-                         }
-                         memcpy(track->audio.buf + y*w, data, w);
-                     } else {
-                         if (size < sps * w / sps) {
-                             av_log(matroska->ctx, AV_LOG_ERROR,
-                                    "Corrupt generic RM-style audio packet size\n");
-                             res = AVERROR_INVALIDDATA;
-                             goto end;
-                         }
-                         for (x=0; x<w/sps; x++)
-                             memcpy(track->audio.buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps);
-                     }
-                     if (++track->audio.sub_packet_cnt >= h) {
-                         if (st->codec->codec_id == AV_CODEC_ID_SIPR)
-                             ff_rm_reorder_sipr_data(track->audio.buf, h, w);
-                         track->audio.sub_packet_cnt = 0;
-                         track->audio.pkt_cnt = h*w / a;
-                     }
-                 }
-                 while (track->audio.pkt_cnt) {
-                     pkt = av_mallocz(sizeof(AVPacket));
-                     av_new_packet(pkt, a);
-                     memcpy(pkt->data, track->audio.buf
-                            + a * (h*w / a - track->audio.pkt_cnt--), a);
-                     pkt->pts = track->audio.buf_timecode;
-                     track->audio.buf_timecode = AV_NOPTS_VALUE;
-                     pkt->pos = pos;
-                     pkt->stream_index = st->index;
-                     dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
-                 }
-             } else {
-                 MatroskaTrackEncoding *encodings = track->encodings.elem;
-                 uint32_t pkt_size = lace_size[n];
-                 uint8_t *pkt_data = data;
-                 int offset = 0;
-                 if (encodings && encodings->scope & 1) {
-                     res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
-                     if (res < 0)
-                         break;
-                 }
-                 if (st->codec->codec_id == AV_CODEC_ID_PRORES)
-                     offset = 8;
-                 pkt = av_mallocz(sizeof(AVPacket));
-                 /* XXX: prevent data copy... */
-                 if (av_new_packet(pkt, pkt_size + offset) < 0) {
-                     av_free(pkt);
-                     res = AVERROR(ENOMEM);
-                     break;
-                 }
++    if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time))
++        track->end_timecode = FFMAX(track->end_timecode, timecode+duration);
 +
-                 if (st->codec->codec_id == AV_CODEC_ID_PRORES) {
-                     uint8_t *buf = pkt->data;
-                     bytestream_put_be32(&buf, pkt_size);
-                     bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f'));
-                 }
+     for (n = 0; n < laces; n++) {
++        int64_t lace_duration = duration*(n+1) / laces - duration*n / laces;
 +
-                 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 = st->index;
-                 if (track->ms_compat)
-                     pkt->dts = timecode;
-                 else
-                     pkt->pts = timecode;
-                 pkt->pos = pos;
-                 if (st->codec->codec_id == AV_CODEC_ID_SUBRIP) {
-                     /*
-                      * For backward compatibility.
-                      * Historically, we have put subtitle duration
-                      * in convergence_duration, on the off chance
-                      * that the time_scale is less than 1us, which
-                      * could result in a 32bit overflow on the
-                      * normal duration field.
-                      */
-                     pkt->convergence_duration = lace_duration;
-                 }
++        if (lace_size[n] > size) {
++            av_log(matroska->ctx, AV_LOG_ERROR, "Invalid packet size\n");
++            break;
++        }
 +
-                 if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE ||
-                     lace_duration <= INT_MAX) {
-                     /*
-                      * For non subtitle tracks, just store the duration
-                      * as normal.
-                      *
-                      * If it's a subtitle track and duration value does
-                      * not overflow a uint32, then also store it normally.
-                      */
-                     pkt->duration = lace_duration;
-                 }
+         if ((st->codec->codec_id == AV_CODEC_ID_RA_288 ||
+              st->codec->codec_id == AV_CODEC_ID_COOK ||
+              st->codec->codec_id == AV_CODEC_ID_SIPR ||
+              st->codec->codec_id == AV_CODEC_ID_ATRAC3) &&
+              st->codec->block_align && track->audio.sub_packet_size) {
  
-                 if (st->codec->codec_id == AV_CODEC_ID_SSA)
-                     matroska_fix_ass_packet(matroska, pkt, lace_duration);
-                 if (matroska->prev_pkt &&
-                     timecode != AV_NOPTS_VALUE &&
-                     matroska->prev_pkt->pts == timecode &&
-                     matroska->prev_pkt->stream_index == st->index &&
-                     st->codec->codec_id == AV_CODEC_ID_SSA)
-                     matroska_merge_packets(matroska->prev_pkt, pkt);
-                 else {
-                     dynarray_add(&matroska->packets,&matroska->num_packets,pkt);
-                     matroska->prev_pkt = pkt;
-                 }
-             }
+             res = matroska_parse_rm_audio(matroska, track, st, data, size,
+                                           timecode, duration, pos);
+             if (res)
+                 goto end;
  
-             if (timecode != AV_NOPTS_VALUE)
-                 timecode = lace_duration ? timecode + lace_duration : AV_NOPTS_VALUE;
-             data += lace_size[n];
-             size -= lace_size[n];
+         } else {
+             res = matroska_parse_frame(matroska, track, st, data, lace_size[n],
 -                                      timecode, duration,
++                                      timecode, lace_duration,
+                                       pos, !n? is_keyframe : 0);
+             if (res)
+                 goto end;
          }
 -            timecode = duration ? timecode + duration : AV_NOPTS_VALUE;
+         if (timecode != AV_NOPTS_VALUE)
++            timecode = lace_duration ? timecode + lace_duration : AV_NOPTS_VALUE;
+         data += lace_size[n];
+         size -= lace_size[n];
      }
  
  end:
@@@ -2249,7 -2126,7 +2296,7 @@@ static int matroska_parse_cluster_incre
          if (blocks[i].bin.size > 0 && blocks[i].bin.data) {
              int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1;
              if (!blocks[i].non_simple)
 -                blocks[i].duration = AV_NOPTS_VALUE;
 +                blocks[i].duration = 0;
              res = matroska_parse_block(matroska,
                                         blocks[i].bin.data, blocks[i].bin.size,
                                         blocks[i].bin.pos,
@@@ -2279,9 -2156,11 +2326,9 @@@ static int matroska_parse_cluster(Matro
      res = ebml_parse(matroska, matroska_clusters, &cluster);
      blocks_list = &cluster.blocks;
      blocks = blocks_list->elem;
 -    for (i=0; i<blocks_list->nb_elem && !res; i++)
 +    for (i=0; i<blocks_list->nb_elem; i++)
          if (blocks[i].bin.size > 0 && blocks[i].bin.data) {
              int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1;
 -            if (!blocks[i].non_simple)
 -                blocks[i].duration = AV_NOPTS_VALUE;
              res=matroska_parse_block(matroska,
                                       blocks[i].bin.data, blocks[i].bin.size,
                                       blocks[i].bin.pos,  cluster.timecode,
                                       pos);
          }
      ebml_free(matroska_cluster, &cluster);
 -    if (res < 0)  matroska->done = 1;
      return res;
  }
  
  static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt)
  {
      MatroskaDemuxContext *matroska = s->priv_data;
 -    int ret = 0;
  
 -    while (!ret && matroska_deliver_packet(matroska, pkt)) {
 +    while (matroska_deliver_packet(matroska, pkt)) {
 +        int64_t pos = avio_tell(matroska->ctx->pb);
          if (matroska->done)
              return AVERROR_EOF;
 -        ret = matroska_parse_cluster(matroska);
 -    }
 -
 -    if (ret == AVERROR_INVALIDDATA) {
 -        pkt->flags |= AV_PKT_FLAG_CORRUPT;
 -        return 0;
 +        if (matroska_parse_cluster(matroska) < 0)
 +            matroska_resync(matroska, pos);
      }
  
 -    return ret;
 +    return 0;
  }
  
  static int matroska_read_seek(AVFormatContext *s, int stream_index,
      int i, index, index_sub, index_min;
  
      /* Parse the CUES now since we need the index data to seek. */
 -    if (matroska->cues_parsing_deferred) {
 -        matroska_parse_cues(matroska);
 +    if (matroska->cues_parsing_deferred > 0) {
          matroska->cues_parsing_deferred = 0;
 +        matroska_parse_cues(matroska);
      }
  
      if (!st->nb_index_entries)
 -        return 0;
 +        goto err;
      timestamp = FFMAX(timestamp, st->index_entries[0].timestamp);
  
      if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) {
      }
  
      matroska_clear_queue(matroska);
 -    if (index < 0)
 -        return 0;
 +    if (index < 0 || (matroska->cues_parsing_deferred < 0 && index == st->nb_index_entries - 1))
 +        goto err;
  
      index_min = index;
      for (i=0; i < matroska->tracks.nb_elem; i++) {
  
      avio_seek(s->pb, st->index_entries[index_min].pos, SEEK_SET);
      matroska->current_id = 0;
 +    st->skip_to_keyframe =
      matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY);
      matroska->skip_to_timecode = st->index_entries[index].timestamp;
      matroska->done = 0;
 +    matroska->num_levels = 0;
      ff_update_cur_dts(s, st, st->index_entries[index].timestamp);
      return 0;
 +err:
 +    // slightly hackish but allows proper fallback to
 +    // the generic seeking code.
 +    matroska_clear_queue(matroska);
 +    matroska->current_id = 0;
 +    st->skip_to_keyframe =
 +    matroska->skip_to_keyframe = 0;
 +    matroska->done = 0;
 +    matroska->num_levels = 0;
 +    return -1;
  }
  
  static int matroska_read_close(AVFormatContext *s)