Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Mon, 17 Sep 2012 13:12:25 +0000 (15:12 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Mon, 17 Sep 2012 13:15:43 +0000 (15:15 +0200)
* qatar/master:
  avconv: flush filtered frames before reconfiguring filters
  mov: stsd entries must be at least 16 byte
  mov: detect EOF in mov_read_dref()
  file: return proper error on seek failures

Conflicts:
libavformat/file.c
libavformat/mov.c

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

diff --combined libavformat/file.c
@@@ -2,20 -2,20 +2,20 @@@
   * buffered file I/O
   * Copyright (c) 2001 Fabrice Bellard
   *
 - * 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
   */
  
  #include "os_support.h"
  #include "url.h"
  
 +/* Some systems may not have S_ISFIFO */
 +#ifndef S_ISFIFO
 +#  ifdef S_IFIFO
 +#    define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
 +#  else
 +#    define S_ISFIFO(m) 0
 +#  endif
 +#endif
  
  /* standard file protocol */
  
@@@ -66,15 -58,13 +66,15 @@@ static const AVClass file_class = 
  static int file_read(URLContext *h, unsigned char *buf, int size)
  {
      FileContext *c = h->priv_data;
 -    return read(c->fd, buf, size);
 +    int r = read(c->fd, buf, size);
 +    return (-1 == r)?AVERROR(errno):r;
  }
  
  static int file_write(URLContext *h, const unsigned char *buf, int size)
  {
      FileContext *c = h->priv_data;
 -    return write(c->fd, buf, size);
 +    int r = write(c->fd, buf, size);
 +    return (-1 == r)?AVERROR(errno):r;
  }
  
  static int file_get_handle(URLContext *h)
@@@ -103,7 -93,6 +103,7 @@@ static int file_open(URLContext *h, con
      FileContext *c = h->priv_data;
      int access;
      int fd;
 +    struct stat st;
  
      av_strstart(filename, "file:", &filename);
  
      if (fd == -1)
          return AVERROR(errno);
      c->fd = fd;
 +
 +    h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
 +
      return 0;
  }
  
  static int64_t file_seek(URLContext *h, int64_t pos, int whence)
  {
      FileContext *c = h->priv_data;
+     int ret;
      if (whence == AVSEEK_SIZE) {
          struct stat st;
-         int ret = fstat(c->fd, &st);
 -
+         ret = fstat(c->fd, &st);
 -        return ret < 0 ? AVERROR(errno) : st.st_size;
 +        return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
      }
-     return lseek(c->fd, pos, whence);
+     ret = lseek(c->fd, pos, whence);
+     return ret < 0 ? AVERROR(errno) : ret;
  }
  
  static int file_close(URLContext *h)
diff --combined libavformat/mov.c
@@@ -3,20 -3,20 +3,20 @@@
   * Copyright (c) 2001 Fabrice Bellard
   * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
   *
 - * 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
   */
  
@@@ -32,8 -32,6 +32,8 @@@
  #include "libavutil/mathematics.h"
  #include "libavutil/avstring.h"
  #include "libavutil/dict.h"
 +#include "libavutil/opt.h"
 +#include "libavutil/timecode.h"
  #include "libavcodec/ac3tab.h"
  #include "avformat.h"
  #include "internal.h"
@@@ -131,74 -129,6 +131,74 @@@ static int mov_metadata_gnre(MOVContex
      return 0;
  }
  
 +static int mov_read_custom_metadata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    char key[1024]={0}, data[1024]={0};
 +    int i;
 +    AVStream *st;
 +    MOVStreamContext *sc;
 +
 +    if (c->fc->nb_streams < 1)
 +        return 0;
 +    st = c->fc->streams[c->fc->nb_streams-1];
 +    sc = st->priv_data;
 +
 +    if (atom.size <= 8) return 0;
 +
 +    for (i = 0; i < 3; i++) { // Parse up to three sub-atoms looking for name and data.
 +        int data_size = avio_rb32(pb);
 +        int tag = avio_rl32(pb);
 +        int str_size = 0, skip_size = 0;
 +        char *target = NULL;
 +
 +        switch (tag) {
 +        case MKTAG('n','a','m','e'):
 +            avio_rb32(pb); // version/flags
 +            str_size = skip_size = data_size - 12;
 +            atom.size -= 12;
 +            target = key;
 +            break;
 +        case MKTAG('d','a','t','a'):
 +            avio_rb32(pb); // version/flags
 +            avio_rb32(pb); // reserved (zero)
 +            str_size = skip_size = data_size - 16;
 +            atom.size -= 16;
 +            target = data;
 +            break;
 +        default:
 +            skip_size = data_size - 8;
 +            str_size = 0;
 +            break;
 +        }
 +
 +        if (target) {
 +            str_size = FFMIN3(sizeof(data)-1, str_size, atom.size);
 +            avio_read(pb, target, str_size);
 +            target[str_size] = 0;
 +        }
 +        atom.size -= skip_size;
 +
 +        // If we didn't read the full data chunk for the sub-atom, skip to the end of it.
 +        if (skip_size > str_size) avio_skip(pb, skip_size - str_size);
 +    }
 +
 +    if (*key && *data) {
 +        if (strcmp(key, "iTunSMPB") == 0) {
 +            int priming, remainder, samples;
 +            if(sscanf(data, "%*X %X %X %X", &priming, &remainder, &samples) == 3){
 +                if(priming>0 && priming<16384)
 +                    sc->start_pad = priming;
 +                return 1;
 +            }
 +        }
 +        if (strcmp(key, "cdec") == 0) {
 +//             av_dict_set(&st->metadata, key, data, 0);
 +            return 1;
 +        }
 +    }
 +    return 0;
 +}
 +
  static const uint32_t mac_to_unicode[128] = {
      0x00C4,0x00C5,0x00C7,0x00C9,0x00D1,0x00D6,0x00DC,0x00E1,
      0x00E0,0x00E2,0x00E4,0x00E3,0x00E5,0x00E7,0x00E9,0x00E8,
@@@ -229,7 -159,7 +229,7 @@@ static int mov_read_mac_string(MOVConte
          uint8_t t, c = avio_r8(pb);
          if (c < 0x80 && p < end)
              *p++ = c;
 -        else
 +        else if (p < end)
              PUT_UTF8(mac_to_unicode[c-0x80], t, if (p < end) *p++ = t;);
      }
      *p = 0;
@@@ -289,9 -219,6 +289,9 @@@ static int mov_read_udta_string(MOVCont
      uint32_t data_type = 0, str_size;
      int (*parse)(MOVContext*, AVIOContext*, unsigned, const char*) = NULL;
  
 +    if (c->itunes_metadata && atom.type == MKTAG('-','-','-','-'))
 +        return mov_read_custom_metadata(c, pb, atom);
 +
      switch (atom.type) {
      case MKTAG(0xa9,'n','a','m'): key = "title";     break;
      case MKTAG(0xa9,'a','u','t'):
      case MKTAG(0xa9,'w','r','t'): key = "composer";  break;
      case MKTAG( 'c','p','r','t'):
      case MKTAG(0xa9,'c','p','y'): key = "copyright"; break;
 +    case MKTAG(0xa9,'g','r','p'): key = "grouping"; break;
 +    case MKTAG(0xa9,'l','y','r'): key = "lyrics"; break;
      case MKTAG(0xa9,'c','m','t'):
      case MKTAG(0xa9,'i','n','f'): key = "comment";   break;
      case MKTAG(0xa9,'a','l','b'): key = "album";     break;
      if (parse)
          parse(c, pb, str_size, key);
      else {
 -        if (data_type == 3 || (data_type == 0 && langcode < 0x800)) { // MAC Encoded
 +        if (data_type == 3 || (data_type == 0 && (langcode < 0x400 || langcode == 0x7fff))) { // MAC Encoded
              mov_read_mac_string(c, pb, str_size, str, sizeof(str));
          } else {
              avio_read(pb, str, str_size);
@@@ -442,7 -367,6 +442,7 @@@ static int mov_read_dref(MOVContext *c
      if (entries >= UINT_MAX / sizeof(*sc->drefs))
          return AVERROR_INVALIDDATA;
      av_free(sc->drefs);
 +    sc->drefs_count = 0;
      sc->drefs = av_mallocz(entries * sizeof(*sc->drefs));
      if (!sc->drefs)
          return AVERROR(ENOMEM);
              avio_skip(pb, 16);
  
              for (type = 0; type != -1 && avio_tell(pb) < next; ) {
 -                if (pb->eof_reached)
 +                if(url_feof(pb))
                      return AVERROR_EOF;
                  type = avio_rb16(pb);
                  len = avio_rb16(pb);
@@@ -539,8 -463,6 +539,8 @@@ static int mov_read_hdlr(MOVContext *c
      AVStream *st;
      uint32_t type;
      uint32_t av_unused ctype;
 +    int title_size;
 +    char *title_str;
  
      if (c->fc->nb_streams < 1) // meta before first trak
          return 0;
      avio_rb32(pb); /* component flags */
      avio_rb32(pb); /* component flags mask */
  
 +    title_size = atom.size - 24;
 +    if (title_size > 0) {
 +        title_str = av_malloc(title_size + 1); /* Add null terminator */
 +        if (!title_str)
 +            return AVERROR(ENOMEM);
 +        avio_read(pb, title_str, title_size);
 +        title_str[title_size] = 0;
 +        if (title_str[0])
 +            av_dict_set(&st->metadata, "handler_name", title_str +
 +                        (!c->isom && title_str[0] == title_size - 1), 0);
 +        av_freep(&title_str);
 +    }
 +
      return 0;
  }
  
@@@ -783,8 -692,7 +783,8 @@@ static void mov_metadata_creation_time(
      char buffer[32];
      if (time) {
          struct tm *ptm;
 -        time -= 2082844800;  /* seconds between 1904-01-01 and Epoch */
 +        if(time >= 2082844800)
 +            time -= 2082844800;  /* seconds between 1904-01-01 and Epoch */
          ptm = gmtime(&time);
          if (!ptm) return;
          strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ptm);
@@@ -851,10 -759,6 +851,10 @@@ static int mov_read_mvhd(MOVContext *c
      av_dlog(c->fc, "time scale = %i\n", c->time_scale);
  
      c->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */
 +    // set the AVCodecContext duration because the duration of individual tracks
 +    // may be inaccurate
 +    if (c->time_scale > 0)
 +        c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale);
      avio_rb32(pb); /* preferred scale */
  
      avio_rb16(pb); /* preferred volume */
      avio_rb32(pb); /* selection duration */
      avio_rb32(pb); /* current time */
      avio_rb32(pb); /* next track ID */
 -
 -    return 0;
 -}
 -
 -static int mov_read_smi(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 -{
 -    AVStream *st;
 -
 -    if (c->fc->nb_streams < 1)
 -        return 0;
 -    st = c->fc->streams[c->fc->nb_streams-1];
 -
 -    if ((uint64_t)atom.size > (1<<30))
 -        return AVERROR_INVALIDDATA;
 -
 -    // currently SVQ3 decoder expect full STSD header - so let's fake it
 -    // this should be fixed and just SMI header should be passed
 -    av_free(st->codec->extradata);
 -    st->codec->extradata = av_mallocz(atom.size + 0x5a + FF_INPUT_BUFFER_PADDING_SIZE);
 -    if (!st->codec->extradata)
 -        return AVERROR(ENOMEM);
 -    st->codec->extradata_size = 0x5a + atom.size;
 -    memcpy(st->codec->extradata, "SVQ3", 4); // fake
 -    avio_read(pb, st->codec->extradata + 0x5a, atom.size);
 -    av_dlog(c->fc, "Reading SMI %"PRId64"  %s\n", atom.size, st->codec->extradata + 0x5a);
      return 0;
  }
  
@@@ -882,7 -811,7 +882,7 @@@ static int mov_read_enda(MOVContext *c
          return 0;
      st = c->fc->streams[c->fc->nb_streams-1];
  
 -    little_endian = avio_rb16(pb);
 +    little_endian = avio_rb16(pb) & 0xFF;
      av_dlog(c->fc, "enda %d\n", little_endian);
      if (little_endian == 1) {
          switch (st->codec->codec_id) {
@@@ -940,8 -869,7 +940,8 @@@ static int mov_read_fiel(MOVContext *c
  }
  
  /* FIXME modify qdm2/svq3/h264 decoders to take full atom as extradata */
 -static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom,
 +                              enum AVCodecID codec_id)
  {
      AVStream *st;
      uint64_t size;
      if (c->fc->nb_streams < 1) // will happen with jp2 files
          return 0;
      st= c->fc->streams[c->fc->nb_streams-1];
 +
 +    if (st->codec->codec_id != codec_id)
 +        return 0; /* unexpected codec_id - don't mess with extradata */
 +
      size= (uint64_t)st->codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE;
      if (size > INT_MAX || (uint64_t)atom.size > INT_MAX)
          return AVERROR_INVALIDDATA;
      return 0;
  }
  
 +/* wrapper functions for reading ALAC/AVS/MJPEG/MJPEG2000 extradata atoms only for those codecs */
 +static int mov_read_alac(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    return mov_read_extradata(c, pb, atom, AV_CODEC_ID_ALAC);
 +}
 +
 +static int mov_read_avss(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    return mov_read_extradata(c, pb, atom, AV_CODEC_ID_AVS);
 +}
 +
 +static int mov_read_jp2h(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    return mov_read_extradata(c, pb, atom, AV_CODEC_ID_JPEG2000);
 +}
 +
 +static int mov_read_avid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    return mov_read_extradata(c, pb, atom, AV_CODEC_ID_AVUI);
 +}
 +
 +static int mov_read_svq3(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    return mov_read_extradata(c, pb, atom, AV_CODEC_ID_SVQ3);
 +}
 +
  static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom)
  {
      AVStream *st;
      if (st->codec->codec_id == AV_CODEC_ID_QDM2 || st->codec->codec_id == AV_CODEC_ID_QDMC) {
          // pass all frma atom to codec, needed at least for QDMC and QDM2
          av_free(st->codec->extradata);
 +        st->codec->extradata_size = 0;
          st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
          if (!st->codec->extradata)
              return AVERROR(ENOMEM);
@@@ -1049,7 -946,6 +1049,7 @@@ static int mov_read_glbl(MOVContext *c
              return mov_read_default(c, pb, atom);
      }
      av_free(st->codec->extradata);
 +    st->codec->extradata_size = 0;
      st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
      if (!st->codec->extradata)
          return AVERROR(ENOMEM);
@@@ -1075,7 -971,6 +1075,7 @@@ static int mov_read_dvc1(MOVContext *c
          return 0;
  
      av_free(st->codec->extradata);
 +    st->codec->extradata_size = 0;
      st->codec->extradata = av_mallocz(atom.size - 7 + FF_INPUT_BUFFER_PADDING_SIZE);
      if (!st->codec->extradata)
          return AVERROR(ENOMEM);
@@@ -1104,7 -999,6 +1104,7 @@@ static int mov_read_strf(MOVContext *c
          return AVERROR_INVALIDDATA;
  
      av_free(st->codec->extradata);
 +    st->codec->extradata_size = 0;
      st->codec->extradata = av_mallocz(atom.size - 40 + FF_INPUT_BUFFER_PADDING_SIZE);
      if (!st->codec->extradata)
          return AVERROR(ENOMEM);
@@@ -1204,16 -1098,16 +1204,16 @@@ int ff_mov_read_stsd_entries(MOVContex
          int dref_id = 1;
          MOVAtom a = { AV_RL32("stsd") };
          int64_t start_pos = avio_tell(pb);
-         int size = avio_rb32(pb); /* size */
 -        uint32_t size = avio_rb32(pb); /* size */
++        int64_t size = avio_rb32(pb); /* size */
          uint32_t format = avio_rl32(pb); /* data format */
  
          if (size >= 16) {
              avio_rb32(pb); /* reserved */
              avio_rb16(pb); /* reserved */
              dref_id = avio_rb16(pb);
-         }else if (size <= 0){
 -        } else {
++        }else if (size <= 7){
              av_log(c->fc, AV_LOG_ERROR, "invalid size %d in stsd\n", size);
-             return -1;
+             return AVERROR_INVALIDDATA;
          }
  
          if (st->codec->codec_tag &&
              /* Multiple fourcc, we skip JPEG. This is not correct, we should
               * export it as a separate AVStream but this needs a few changes
               * in the MOV demuxer, patch welcome. */
 -        multiple_stsd:
              av_log(c->fc, AV_LOG_WARNING, "multiple fourcc not supported\n");
              avio_skip(pb, size - (avio_tell(pb) - start_pos));
              continue;
          }
          /* we cannot demux concatenated h264 streams because of different extradata */
          if (st->codec->codec_tag && st->codec->codec_tag == AV_RL32("avc1"))
 -            goto multiple_stsd;
 +            av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 might not play corrently.\n");
          sc->pseudo_stream_id = st->codec->codec_tag ? -1 : pseudo_stream_id;
          sc->dref_id= dref_id;
  
                  id = ff_codec_get_id(ff_codec_bmp_tags, format);
              if (id > 0)
                  st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
 -            else if (st->codec->codec_type == AVMEDIA_TYPE_DATA){
 +            else if (st->codec->codec_type == AVMEDIA_TYPE_DATA ||
 +                     (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE &&
 +                      st->codec->codec_id == AV_CODEC_ID_NONE)){
                  id = ff_codec_get_id(ff_codec_movsubtitle_tags, format);
                  if (id > 0)
                      st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
                  (color_depth == 8)) {
                  /* for palette traversal */
                  unsigned int color_start, color_count, color_end;
 -                unsigned char r, g, b;
 +                unsigned char a, r, g, b;
  
                  if (color_greyscale) {
                      int color_index, color_dec;
                      color_index = 255;
                      color_dec = 256 / (color_count - 1);
                      for (j = 0; j < color_count; j++) {
 +                        if (id == AV_CODEC_ID_CINEPAK){
 +                            r = g = b = color_count - 1 - color_index;
 +                        }else
                          r = g = b = color_index;
                          sc->palette[j] =
 -                            (r << 16) | (g << 8) | (b);
 +                            (0xFFU << 24) | (r << 16) | (g << 8) | (b);
                          color_index -= color_dec;
                          if (color_index < 0)
                              color_index = 0;
                          g = color_table[j * 3 + 1];
                          b = color_table[j * 3 + 2];
                          sc->palette[j] =
 -                            (r << 16) | (g << 8) | (b);
 +                            (0xFFU << 24) | (r << 16) | (g << 8) | (b);
                      }
                  } else {
                      /* load the palette from the file */
                      if ((color_start <= 255) &&
                          (color_end <= 255)) {
                          for (j = color_start; j <= color_end; j++) {
 -                            /* each R, G, or B component is 16 bits;
 -                             * only use the top 8 bits; skip alpha bytes
 -                             * up front */
 -                            avio_r8(pb);
 +                            /* each A, R, G, or B component is 16 bits;
 +                             * only use the top 8 bits */
 +                            a = avio_r8(pb);
                              avio_r8(pb);
                              r = avio_r8(pb);
                              avio_r8(pb);
                              b = avio_r8(pb);
                              avio_r8(pb);
                              sc->palette[j] =
 -                                (r << 16) | (g << 8) | (b);
 +                                (a << 24 ) | (r << 16) | (g << 8) | (b);
                          }
                      }
                  }
              st->codec->width = sc->width;
              st->codec->height = sc->height;
          } else {
 -            /* other codec type, just skip (rtp, mp4s, tmcd ...) */
 +            if (st->codec->codec_tag == MKTAG('t','m','c','d')) {
 +                MOVStreamContext *tmcd_ctx = st->priv_data;
 +                int val;
 +                avio_rb32(pb);       /* reserved */
 +                val = avio_rb32(pb); /* flags */
 +                tmcd_ctx->tmcd_flags = val;
 +                if (val & 1)
 +                    st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE;
 +                avio_rb32(pb); /* time scale */
 +                avio_rb32(pb); /* frame duration */
 +                st->codec->time_base.den = avio_r8(pb); /* number of frame */
 +                st->codec->time_base.num = 1;
 +            }
 +            /* other codec type, just skip (rtp, mp4s, ...) */
              avio_skip(pb, size - (avio_tell(pb) - start_pos));
          }
          /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */
              st->codec->sample_rate = AV_RB32(st->codec->extradata+32);
          }
          break;
 +    case AV_CODEC_ID_AC3:
 +        st->need_parsing = AVSTREAM_PARSE_FULL;
 +        break;
 +    case AV_CODEC_ID_MPEG1VIDEO:
 +        st->need_parsing = AVSTREAM_PARSE_FULL;
 +        break;
      case AV_CODEC_ID_VC1:
          st->need_parsing = AVSTREAM_PARSE_FULL;
          break;
@@@ -1681,7 -1553,6 +1681,7 @@@ static int mov_read_stsz(MOVContext *c
          sample_size = avio_rb32(pb);
          if (!sc->sample_size) /* do not overwrite value computed in stsd */
              sc->sample_size = sample_size;
 +        sc->alt_sample_size = sample_size;
          field_size = 32;
      } else {
          sample_size = 0;
@@@ -1754,8 -1625,10 +1754,8 @@@ static int mov_read_stts(MOVContext *c
      av_dlog(c->fc, "track[%i].stts.entries = %i\n",
              c->fc->nb_streams-1, entries);
  
 -    if (!entries)
 -        return 0;
      if (entries >= UINT_MAX / sizeof(*sc->stts_data))
 -        return AVERROR(EINVAL);
 +        return -1;
  
      sc->stts_data = av_malloc(entries * sizeof(*sc->stts_data));
      if (!sc->stts_data)
  
          sample_count=avio_rb32(pb);
          sample_duration = avio_rb32(pb);
 +        /* sample_duration < 0 is invalid based on the spec */
 +        if (sample_duration < 0) {
 +            av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta in STTS %d\n", sample_duration);
 +            sample_duration = 1;
 +        }
          sc->stts_data[i].count= sample_count;
          sc->stts_data[i].duration= sample_duration;
  
@@@ -1823,18 -1691,7 +1823,18 @@@ static int mov_read_ctts(MOVContext *c
  
          sc->ctts_data[i].count   = count;
          sc->ctts_data[i].duration= duration;
 -        if (duration < 0)
 +
 +        av_dlog(c->fc, "count=%d, duration=%d\n",
 +                count, duration);
 +
 +        if (FFABS(duration) > (1<<28) && i+2<entries) {
 +            av_log(c->fc, AV_LOG_WARNING, "CTTS invalid\n");
 +            av_freep(&sc->ctts_data);
 +            sc->ctts_count = 0;
 +            return 0;
 +        }
 +
 +        if (duration < 0 && i+2<entries)
              sc->dts_shift = FFMAX(sc->dts_shift, -duration);
      }
  
@@@ -1857,13 -1714,12 +1857,13 @@@ static void mov_build_index(MOVContext 
      AVIndexEntry *mem;
  
      /* adjust first dts according to edit list */
 -    if (sc->time_offset && mov->time_scale > 0) {
 -        if (sc->time_offset < 0)
 -            sc->time_offset = av_rescale(sc->time_offset, sc->time_scale, mov->time_scale);
 +    if ((sc->empty_duration || sc->start_time) && mov->time_scale > 0) {
 +        if (sc->empty_duration)
 +            sc->empty_duration = av_rescale(sc->empty_duration, sc->time_scale, mov->time_scale);
 +        sc->time_offset = sc->start_time - sc->empty_duration;
          current_dts = -sc->time_offset;
 -        if (sc->ctts_data && sc->stts_data && sc->stts_data[0].duration &&
 -            sc->ctts_data[0].duration / sc->stts_data[0].duration > 16) {
 +        if (sc->ctts_count>0 && sc->stts_count>0 &&
 +            sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) {
              /* more than 16 frames delay, dts are likely wrong
                 this happens with files created by iMovie */
              sc->wrong_dts = 1;
          unsigned int stts_sample = 0;
          unsigned int sample_size;
          unsigned int distance = 0;
 -        int key_off = (sc->keyframes && sc->keyframes[0] > 0) || (sc->stps_data && sc->stps_data[0] > 0);
 +        int key_off = (sc->keyframe_count && sc->keyframes[0] > 0) || (sc->stps_data && sc->stps_data[0] > 0);
  
          current_dts -= sc->dts_shift;
  
 -        if (!sc->sample_count)
 +        if (!sc->sample_count || st->nb_index_entries)
              return;
          if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries)
              return;
                  }
                  if (keyframe)
                      distance = 0;
 -                sample_size = sc->sample_size > 0 ? sc->sample_size : sc->sample_sizes[current_sample];
 +                sample_size = sc->alt_sample_size > 0 ? sc->alt_sample_size : sc->sample_sizes[current_sample];
                  if (sc->pseudo_stream_id == -1 ||
                     sc->stsc_data[stsc_index].id - 1 == sc->pseudo_stream_id) {
                      AVIndexEntry *e = &st->index_entries[st->nb_index_entries++];
      }
  }
  
 -static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref,
 -                         AVIOInterruptCB *int_cb)
 +static int mov_open_dref(AVIOContext **pb, const char *src, MOVDref *ref,
 +                         AVIOInterruptCB *int_cb, int use_absolute_path, AVFormatContext *fc)
  {
      /* try relative path, we do not try the absolute because it can leak information about our
         system to an attacker */
      if (ref->nlvl_to > 0 && ref->nlvl_from > 0) {
          char filename[1024];
 -        char *src_path;
 +        const char *src_path;
          int i, l;
  
          /* find a source dir */
              if (!avio_open2(pb, filename, AVIO_FLAG_READ, int_cb, NULL))
                  return 0;
          }
 +    } else if (use_absolute_path) {
 +        av_log(fc, AV_LOG_WARNING, "Using absolute path on user request, "
 +               "this is a possible security issue\n");
 +        if (!avio_open2(pb, ref->path, AVIO_FLAG_READ, int_cb, NULL))
 +            return 0;
      }
  
      return AVERROR(ENOENT);
@@@ -2119,8 -1970,7 +2119,8 @@@ static int mov_read_trak(MOVContext *c
  
      if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) {
          MOVDref *dref = &sc->drefs[sc->dref_id - 1];
 -        if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback) < 0)
 +        if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback,
 +            c->use_absolute_path, c->fc) < 0)
              av_log(c->fc, AV_LOG_ERROR,
                     "stream %d, error opening alias: path='%s', dir='%s', "
                     "filename='%s', volume='%s', nlvl_from=%d, nlvl_to=%d\n",
@@@ -2254,21 -2104,6 +2254,21 @@@ static int mov_read_tkhd(MOVContext *c
      sc->width = width >> 16;
      sc->height = height >> 16;
  
 +    //Assign clockwise rotate values based on transform matrix so that
 +    //we can compensate for iPhone orientation during capture.
 +
 +    if (display_matrix[1][0] == -65536 && display_matrix[0][1] == 65536) {
 +         av_dict_set(&st->metadata, "rotate", "90", 0);
 +    }
 +
 +    if (display_matrix[0][0] == -65536 && display_matrix[1][1] == -65536) {
 +         av_dict_set(&st->metadata, "rotate", "180", 0);
 +    }
 +
 +    if (display_matrix[1][0] == 65536 && display_matrix[0][1] == -65536) {
 +         av_dict_set(&st->metadata, "rotate", "270", 0);
 +    }
 +
      // transform the display width/height according to the matrix
      // skip this if the display matrix is the default identity matrix
      // or if it is rotating the picture, ex iPhone 3GS
@@@ -2345,9 -2180,6 +2345,9 @@@ static int mov_read_trex(MOVContext *c
      trex = av_realloc(c->trex_data, (c->trex_count+1)*sizeof(*c->trex_data));
      if (!trex)
          return AVERROR(ENOMEM);
 +
 +    c->fc->duration = AV_NOPTS_VALUE; // the duration from mvhd is not representing the whole file when fragments are used.
 +
      c->trex_data = trex;
      trex = &c->trex_data[c->trex_count++];
      avio_r8(pb); /* version */
@@@ -2492,7 -2324,7 +2492,7 @@@ static int mov_read_cmov(MOVContext *c
      if (avio_rl32(pb) != MKTAG('d','c','o','m'))
          return AVERROR_INVALIDDATA;
      if (avio_rl32(pb) != MKTAG('z','l','i','b')) {
 -        av_log(c->fc, AV_LOG_ERROR, "unknown compression for cmov atom !");
 +        av_log(c->fc, AV_LOG_ERROR, "unknown compression for cmov atom !\n");
          return AVERROR_INVALIDDATA;
      }
      avio_rb32(pb); /* cmvd atom */
@@@ -2531,7 -2363,7 +2531,7 @@@ free_and_return
  static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
  {
      MOVStreamContext *sc;
 -    int i, edit_count, version;
 +    int i, edit_count, version, edit_start_index = 0;
  
      if (c->fc->nb_streams < 1)
          return 0;
              time     = (int32_t)avio_rb32(pb); /* media time */
          }
          avio_rb32(pb); /* Media rate */
 -        if (i == 0 && time >= -1) {
 -            sc->time_offset = time != -1 ? time : -duration;
 -        }
 +        if (i == 0 && time == -1) {
 +            sc->empty_duration = duration;
 +            edit_start_index = 1;
 +        } else if (i == edit_start_index && time >= 0)
 +            sc->start_time = time;
      }
  
      if (edit_count > 1)
      return 0;
  }
  
 +static int mov_read_chan2(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    if (atom.size < 16)
 +        return 0;
 +    avio_skip(pb, 4);
 +    ff_mov_read_chan(c->fc, pb, c->fc->streams[0],  atom.size - 4);
 +    return 0;
 +}
 +
 +static int mov_read_tref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    uint32_t i, size;
 +    MOVStreamContext *sc;
 +
 +    if (c->fc->nb_streams < 1)
 +        return AVERROR_INVALIDDATA;
 +    sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data;
 +
 +    size = avio_rb32(pb);
 +    if (size < 12)
 +        return 0;
 +
 +    sc->trefs_count = (size - 4) / 8;
 +    sc->trefs = av_malloc(sc->trefs_count * sizeof(*sc->trefs));
 +    if (!sc->trefs)
 +        return AVERROR(ENOMEM);
 +
 +    sc->tref_type = avio_rl32(pb);
 +    for (i = 0; i < sc->trefs_count; i++)
 +        sc->trefs[i] = avio_rb32(pb);
 +    return 0;
 +}
 +
  static const MOVParseTableEntry mov_default_parse_table[] = {
 -{ MKTAG('a','v','s','s'), mov_read_extradata },
 +{ MKTAG('A','C','L','R'), mov_read_avid },
 +{ MKTAG('A','P','R','G'), mov_read_avid },
 +{ MKTAG('A','A','L','P'), mov_read_avid },
 +{ MKTAG('A','R','E','S'), mov_read_avid },
 +{ MKTAG('a','v','s','s'), mov_read_avss },
  { MKTAG('c','h','p','l'), mov_read_chpl },
  { MKTAG('c','o','6','4'), mov_read_stco },
  { MKTAG('c','t','t','s'), mov_read_ctts }, /* composition time to sample */
  { MKTAG('g','l','b','l'), mov_read_glbl },
  { MKTAG('h','d','l','r'), mov_read_hdlr },
  { MKTAG('i','l','s','t'), mov_read_ilst },
 -{ MKTAG('j','p','2','h'), mov_read_extradata },
 +{ MKTAG('j','p','2','h'), mov_read_jp2h },
  { MKTAG('m','d','a','t'), mov_read_mdat },
  { MKTAG('m','d','h','d'), mov_read_mdhd },
  { MKTAG('m','d','i','a'), mov_read_default },
  { MKTAG('m','o','o','v'), mov_read_moov },
  { MKTAG('m','v','e','x'), mov_read_default },
  { MKTAG('m','v','h','d'), mov_read_mvhd },
 -{ MKTAG('S','M','I',' '), mov_read_smi }, /* Sorenson extension ??? */
 -{ MKTAG('a','l','a','c'), mov_read_extradata }, /* alac specific atom */
 +{ MKTAG('S','M','I',' '), mov_read_svq3 },
 +{ MKTAG('a','l','a','c'), mov_read_alac }, /* alac specific atom */
  { MKTAG('a','v','c','C'), mov_read_glbl },
  { MKTAG('p','a','s','p'), mov_read_pasp },
  { MKTAG('s','t','b','l'), mov_read_default },
  { MKTAG('t','f','h','d'), mov_read_tfhd }, /* track fragment header */
  { MKTAG('t','r','a','k'), mov_read_trak },
  { MKTAG('t','r','a','f'), mov_read_default },
 -{ MKTAG('t','r','e','f'), mov_read_default },
 +{ MKTAG('t','r','e','f'), mov_read_tref },
  { MKTAG('c','h','a','p'), mov_read_chap },
  { MKTAG('t','r','e','x'), mov_read_trex },
  { MKTAG('t','r','u','n'), mov_read_trun },
@@@ -2675,33 -2468,25 +2675,33 @@@ static int mov_read_default(MOVContext 
  
      if (atom.size < 0)
          atom.size = INT64_MAX;
 -    while (total_size + 8 < atom.size && !pb->eof_reached) {
 +    while (total_size + 8 <= atom.size && !url_feof(pb)) {
          int (*parse)(MOVContext*, AVIOContext*, MOVAtom) = NULL;
          a.size = atom.size;
          a.type=0;
          if (atom.size >= 8) {
              a.size = avio_rb32(pb);
              a.type = avio_rl32(pb);
 +            if (atom.type != MKTAG('r','o','o','t') &&
 +                atom.type != MKTAG('m','o','o','v'))
 +            {
 +                if (a.type == MKTAG('t','r','a','k') || a.type == MKTAG('m','d','a','t'))
 +                {
 +                    av_log(c->fc, AV_LOG_ERROR, "Broken file, trak/mdat not at top-level\n");
 +                    avio_skip(pb, -8);
 +                    return 0;
 +                }
 +            }
 +            total_size += 8;
 +            if (a.size == 1) { /* 64 bit extended size */
 +                a.size = avio_rb64(pb) - 8;
 +                total_size += 8;
 +            }
          }
          av_dlog(c->fc, "type: %08x '%.4s' parent:'%.4s' sz: %"PRId64" %"PRId64" %"PRId64"\n",
                  a.type, (char*)&a.type, (char*)&atom.type, a.size, total_size, atom.size);
 -        total_size += 8;
 -        if (a.size == 1) { /* 64 bit extended size */
 -            a.size = avio_rb64(pb) - 8;
 -            total_size += 8;
 -        }
          if (a.size == 0) {
 -            a.size = atom.size - total_size;
 -            if (a.size <= 8)
 -                break;
 +            a.size = atom.size - total_size + 8;
          }
          a.size -= 8;
          if (a.size < 0)
              left = a.size - avio_tell(pb) + start_pos;
              if (left > 0) /* skip garbage at atom end */
                  avio_skip(pb, left);
 +            else if(left < 0) {
 +                av_log(c->fc, AV_LOG_DEBUG, "undoing overread of %"PRId64" in '%.4s'\n", -left, (char*)&a.type);
 +                avio_seek(pb, left, SEEK_CUR);
 +            }
          }
  
          total_size += a.size;
@@@ -2855,7 -2636,7 +2855,7 @@@ static void mov_read_chapters(AVFormatC
                  if (len == 1 || len == 2)
                      title[len] = 0;
                  else
 -                    avio_get_str(sc->pb, len - 2, title + 2, title_len - 2);
 +                    avio_get_str(sc->pb, INT_MAX, title + 2, len - 1);
              }
          }
  
@@@ -2866,49 -2647,6 +2866,49 @@@ finish
      avio_seek(sc->pb, cur_pos, SEEK_SET);
  }
  
 +static int parse_timecode_in_framenum_format(AVFormatContext *s, AVStream *st,
 +                                             uint32_t value, int flags)
 +{
 +    AVTimecode tc;
 +    char buf[AV_TIMECODE_STR_SIZE];
 +    AVRational rate = {st->codec->time_base.den,
 +                       st->codec->time_base.num};
 +    int ret = av_timecode_init(&tc, rate, flags, 0, s);
 +    if (ret < 0)
 +        return ret;
 +    av_dict_set(&st->metadata, "timecode",
 +                av_timecode_make_string(&tc, buf, value), 0);
 +    return 0;
 +}
 +
 +static int mov_read_timecode_track(AVFormatContext *s, AVStream *st)
 +{
 +    MOVStreamContext *sc = st->priv_data;
 +    int flags = 0;
 +    int64_t cur_pos = avio_tell(sc->pb);
 +    uint32_t value;
 +
 +    if (!st->nb_index_entries)
 +        return -1;
 +
 +    avio_seek(sc->pb, st->index_entries->pos, SEEK_SET);
 +    value = avio_rb32(s->pb);
 +
 +    if (sc->tmcd_flags & 0x0001) flags |= AV_TIMECODE_FLAG_DROPFRAME;
 +    if (sc->tmcd_flags & 0x0002) flags |= AV_TIMECODE_FLAG_24HOURSMAX;
 +    if (sc->tmcd_flags & 0x0004) flags |= AV_TIMECODE_FLAG_ALLOWNEGATIVE;
 +
 +    /* Assume Counter flag is set to 1 in tmcd track (even though it is likely
 +     * not the case) and thus assume "frame number format" instead of QT one.
 +     * No sample with tmcd track can be found with a QT timecode at the moment,
 +     * despite what the tmcd track "suggests" (Counter flag set to 0 means QT
 +     * format). */
 +    parse_timecode_in_framenum_format(s, st, value, flags);
 +
 +    avio_seek(sc->pb, cur_pos, SEEK_SET);
 +    return 0;
 +}
 +
  static int mov_read_close(AVFormatContext *s)
  {
      MOVContext *mov = s->priv_data;
              av_freep(&sc->drefs[j].dir);
          }
          av_freep(&sc->drefs);
 +        av_freep(&sc->trefs);
          if (sc->pb && sc->pb != s->pb)
              avio_close(sc->pb);
 +        sc->pb = NULL;
 +        av_freep(&sc->chunk_offsets);
 +        av_freep(&sc->keyframes);
 +        av_freep(&sc->sample_sizes);
 +        av_freep(&sc->stps_data);
 +        av_freep(&sc->stsc_data);
 +        av_freep(&sc->stts_data);
      }
  
      if (mov->dv_demux) {
      return 0;
  }
  
 +static int tmcd_is_referenced(AVFormatContext *s, int tmcd_id)
 +{
 +    int i, j;
 +
 +    for (i = 0; i < s->nb_streams; i++) {
 +        AVStream *st = s->streams[i];
 +        MOVStreamContext *sc = st->priv_data;
 +
 +        if (s->streams[i]->codec->codec_type != AVMEDIA_TYPE_VIDEO)
 +            continue;
 +        for (j = 0; j < sc->trefs_count; j++)
 +            if (tmcd_id == sc->trefs[j])
 +                return 1;
 +    }
 +    return 0;
 +}
 +
 +/* look for a tmcd track not referenced by any video track, and export it globally */
 +static void export_orphan_timecode(AVFormatContext *s)
 +{
 +    int i;
 +
 +    for (i = 0; i < s->nb_streams; i++) {
 +        AVStream *st = s->streams[i];
 +
 +        if (st->codec->codec_tag  == MKTAG('t','m','c','d') &&
 +            !tmcd_is_referenced(s, i + 1)) {
 +            AVDictionaryEntry *tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
 +            if (tcr) {
 +                av_dict_set(&s->metadata, "timecode", tcr->value, 0);
 +                break;
 +            }
 +        }
 +    }
 +}
 +
  static int mov_read_header(AVFormatContext *s)
  {
      MOVContext *mov = s->priv_data;
      AVIOContext *pb = s->pb;
 -    int err;
 +    int i, err;
      MOVAtom atom = { AV_RL32("root") };
  
      mov->fc = s;
      }
      av_dlog(mov->fc, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb));
  
 -    if (pb->seekable && mov->chapter_track > 0)
 -        mov_read_chapters(s);
 +    if (pb->seekable) {
 +        if (mov->chapter_track > 0)
 +            mov_read_chapters(s);
 +        for (i = 0; i < s->nb_streams; i++)
 +            if (s->streams[i]->codec->codec_tag == AV_RL32("tmcd"))
 +                mov_read_timecode_track(s, s->streams[i]);
 +    }
 +
 +    /* copy timecode metadata from tmcd tracks to the related video streams */
 +    for (i = 0; i < s->nb_streams; i++) {
 +        AVStream *st = s->streams[i];
 +        MOVStreamContext *sc = st->priv_data;
 +        if (sc->tref_type == AV_RL32("tmcd") && sc->trefs_count) {
 +            AVDictionaryEntry *tcr;
 +            int tmcd_st_id = sc->trefs[0] - 1;
 +
 +            if (tmcd_st_id < 0 || tmcd_st_id >= s->nb_streams)
 +                continue;
 +            tcr = av_dict_get(s->streams[tmcd_st_id]->metadata, "timecode", NULL, 0);
 +            if (tcr)
 +                av_dict_set(&st->metadata, "timecode", tcr->value, 0);
 +        }
 +    }
 +    export_orphan_timecode(s);
 +
 +    for (i = 0; i < s->nb_streams; i++) {
 +        AVStream *st = s->streams[i];
 +        MOVStreamContext *sc = st->priv_data;
 +        if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->codec->codec_id == AV_CODEC_ID_AAC) {
 +            if(!sc->start_pad)
 +                sc->start_pad = 1024;
 +            st->skip_samples = sc->start_pad;
 +        }
 +    }
  
      if (mov->trex_data) {
 -        int i;
          for (i = 0; i < s->nb_streams; i++) {
              AVStream *st = s->streams[i];
              MOVStreamContext *sc = st->priv_data;
@@@ -3093,7 -2756,6 +3093,7 @@@ static int mov_read_packet(AVFormatCont
      AVIndexEntry *sample;
      AVStream *st = NULL;
      int ret;
 +    mov->fc = s;
   retry:
      sample = mov_find_next_sample(s, &st);
      if (!sample) {
          avio_seek(s->pb, mov->next_root_atom, SEEK_SET);
          mov->next_root_atom = 0;
          if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 ||
 -            s->pb->eof_reached)
 +            url_feof(s->pb))
              return AVERROR_EOF;
          av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb));
          goto retry;
          }
  #if CONFIG_DV_DEMUXER
          if (mov->dv_demux && sc->dv_audio_container) {
 -            avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size);
 +            avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos);
              av_free(pkt->data);
              pkt->size = 0;
              ret = avpriv_dv_get_packet(mov->dv_demux, pkt);
@@@ -3211,6 -2873,8 +3211,6 @@@ static int mov_read_seek(AVFormatContex
  
      if (stream_index >= s->nb_streams)
          return AVERROR_INVALIDDATA;
 -    if (sample_time < 0)
 -        sample_time = 0;
  
      st = s->streams[stream_index];
      sample = mov_seek_stream(s, st, sample_time, flags);
      seek_timestamp = st->index_entries[sample].timestamp;
  
      for (i = 0; i < s->nb_streams; i++) {
 +        MOVStreamContext *sc = s->streams[i]->priv_data;
          st = s->streams[i];
 +        st->skip_samples = (sample_time <= 0) ? sc->start_pad : 0;
 +
          if (stream_index == i)
              continue;
  
      return 0;
  }
  
 +static const AVOption options[] = {
 +    {"use_absolute_path",
 +        "allow using absolute path when opening alias, this is a possible security issue",
 +        offsetof(MOVContext, use_absolute_path), FF_OPT_TYPE_INT, {.dbl = 0},
 +        0, 1, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM},
 +    {NULL}
 +};
 +
 +static const AVClass class = {
 +    .class_name = "mov,mp4,m4a,3gp,3g2,mj2",
 +    .item_name  = av_default_item_name,
 +    .option     = options,
 +    .version    = LIBAVUTIL_VERSION_INT,
 +};
 +
  AVInputFormat ff_mov_demuxer = {
      .name           = "mov,mp4,m4a,3gp,3g2,mj2",
      .long_name      = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
      .read_packet    = mov_read_packet,
      .read_close     = mov_read_close,
      .read_seek      = mov_read_seek,
 +    .priv_class     = &class,
  };