Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Sat, 28 Apr 2012 18:45:06 +0000 (20:45 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 28 Apr 2012 18:45:06 +0000 (20:45 +0200)
* qatar/master:
  h264: new assembly version of get_cabac for x86_64 with PIC
  h264: use one table instead of several for cabac functions
  h264: (trivial) remove unneeded macro argument in x86/cabac.h
  libschroedingerdec: check malloc
  segment: reorder seg_write_header allocation
  avio: make avio_close(NULL) a no-op
  mov: Parse EC3SpecificBox (dec3 atom).

Conflicts:
libavcodec/cabac.c
libavcodec/x86/cabac.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavcodec/libschroedingerdec.c
libavformat/aviobuf.c
libavformat/mov.c
libavformat/segment.c

@@@ -2,20 -2,20 +2,20 @@@
   * Dirac decoder support via Schroedinger libraries
   * Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju 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
   */
  
@@@ -106,6 -106,11 +106,11 @@@ static SchroBuffer *FindNextSchroParseU
          return NULL;
  
      in_buf = av_malloc(next_pu_offset);
+     if (!in_buf) {
+         av_log(parse_ctx, AV_LOG_ERROR, "Unable to allocate input buffer\n");
+         return NULL;
+     }
      memcpy(in_buf, parse_ctx->buf, next_pu_offset);
      enc_buf       = schro_buffer_new_with_data(in_buf, next_pu_offset);
      enc_buf->free = libschroedinger_decode_buffer_free;
  }
  
  /**
 -* Returns Libav chroma format.
 +* Returns FFmpeg chroma format.
  */
  static enum PixelFormat get_chroma_format(SchroChromaFormat schro_pix_fmt)
  {
@@@ -169,7 -174,7 +174,7 @@@ static void libschroedinger_handle_firs
  
      p_schro_params->format = schro_decoder_get_video_format(decoder);
  
 -    /* Tell Libav about sequence details. */
 +    /* Tell FFmpeg about sequence details. */
      if (av_image_check_size(p_schro_params->format->width, p_schro_params->format->height,
                              0, avccontext) < 0) {
          av_log(avccontext, AV_LOG_ERROR, "invalid dimensions (%dx%d)\n",
diff --combined libavformat/aviobuf.c
@@@ -2,20 -2,20 +2,20 @@@
   * buffered I/O
   * Copyright (c) 2000,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
   */
  
@@@ -80,7 -80,6 +80,7 @@@ int ffio_init_context(AVIOContext *s
      s->buffer_size = buffer_size;
      s->buf_ptr = buffer;
      s->opaque = opaque;
 +    s->direct = 0;
      url_resetbuf(s, write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ);
      s->write_packet = write_packet;
      s->read_packet = read_packet;
@@@ -118,25 -117,20 +118,25 @@@ AVIOContext *avio_alloc_context
      return s;
  }
  
 +static void writeout(AVIOContext *s, const uint8_t *data, int len)
 +{
 +    if (s->write_packet && !s->error){
 +        int ret= s->write_packet(s->opaque, data, len);
 +        if(ret < 0){
 +            s->error = ret;
 +        }
 +    }
 +    s->pos += len;
 +}
 +
  static void flush_buffer(AVIOContext *s)
  {
      if (s->buf_ptr > s->buffer) {
 -        if (s->write_packet && !s->error){
 -            int ret= s->write_packet(s->opaque, s->buffer, s->buf_ptr - s->buffer);
 -            if(ret < 0){
 -                s->error = ret;
 -            }
 -        }
 +        writeout(s, s->buffer, s->buf_ptr - s->buffer);
          if(s->update_checksum){
              s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr);
              s->checksum_ptr= s->buffer;
          }
 -        s->pos += s->buf_ptr - s->buffer;
      }
      s->buf_ptr = s->buffer;
  }
@@@ -164,11 -158,6 +164,11 @@@ void ffio_fill(AVIOContext *s, int b, i
  
  void avio_write(AVIOContext *s, const unsigned char *buf, int size)
  {
 +    if (s->direct && !s->update_checksum) {
 +        avio_flush(s);
 +        writeout(s, buf, size);
 +        return;
 +    }
      while (size > 0) {
          int len = FFMIN(s->buf_end - s->buf_ptr, size);
          memcpy(s->buf_ptr, buf, len);
@@@ -210,14 -199,13 +210,14 @@@ int64_t avio_seek(AVIOContext *s, int64
          offset += offset1;
      }
      offset1 = offset - pos;
 -    if (!s->must_flush &&
 +    if (!s->must_flush && (!s->direct || !s->seek) &&
          offset1 >= 0 && offset1 <= (s->buf_end - s->buffer)) {
          /* can do the seek inside the buffer */
          s->buf_ptr = s->buffer + offset1;
      } else if ((!s->seekable ||
                 offset1 <= s->buf_end + SHORT_SEEK_THRESHOLD - s->buffer) &&
                 !s->write_flag && offset1 >= 0 &&
 +               (!s->direct || !s->seek) &&
                (whence != SEEK_END || force)) {
          while(s->pos < offset && !s->eof_reached)
              fill_buffer(s);
      return offset;
  }
  
 +int64_t avio_skip(AVIOContext *s, int64_t offset)
 +{
 +    return avio_seek(s, offset, SEEK_CUR);
 +}
 +
  int64_t avio_size(AVIOContext *s)
  {
      int64_t size;
      return size;
  }
  
 +int url_feof(AVIOContext *s)
 +{
 +    if(!s)
 +        return 0;
 +    if(s->eof_reached){
 +        s->eof_reached=0;
 +        fill_buffer(s);
 +    }
 +    return s->eof_reached;
 +}
 +
  void avio_wl32(AVIOContext *s, unsigned int val)
  {
      avio_w8(s, val);
@@@ -402,7 -374,7 +402,7 @@@ static void fill_buffer(AVIOContext *s
      }
  
      /* make buffer smaller in case it ended up large after probing */
 -    if (s->buffer_size > max_buffer_size) {
 +    if (s->read_packet && s->buffer_size > max_buffer_size) {
          ffio_set_buf_size(s, max_buffer_size);
  
          s->checksum_ptr = dst = s->buffer;
@@@ -470,7 -442,7 +470,7 @@@ int avio_read(AVIOContext *s, unsigned 
          if (len > size)
              len = size;
          if (len == 0) {
 -            if(size > s->buffer_size && !s->update_checksum){
 +            if((s->direct || size > s->buffer_size) && !s->update_checksum){
                  if(s->read_packet)
                      len = s->read_packet(s->opaque, buf, size);
                  if (len <= 0) {
          }
      }
      if (size1 == size) {
 -        if (s->error)         return s->error;
 -        if (s->eof_reached)   return AVERROR_EOF;
 +        if (s->error)      return s->error;
 +        if (url_feof(s))   return AVERROR_EOF;
      }
      return size1 - size;
  }
@@@ -524,8 -496,8 +524,8 @@@ int ffio_read_partial(AVIOContext *s, u
      memcpy(buf, s->buf_ptr, len);
      s->buf_ptr += len;
      if (!len) {
 -        if (s->error)         return s->error;
 -        if (s->eof_reached)   return AVERROR_EOF;
 +        if (s->error)      return s->error;
 +        if (url_feof(s))   return AVERROR_EOF;
      }
      return len;
  }
@@@ -677,12 -649,11 +677,12 @@@ int ffio_fdopen(AVIOContext **s, URLCon
          return AVERROR(ENOMEM);
  
      *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, h,
 -                            ffurl_read, ffurl_write, ffurl_seek);
 +                            (void*)ffurl_read, (void*)ffurl_write, (void*)ffurl_seek);
      if (!*s) {
          av_free(buffer);
          return AVERROR(ENOMEM);
      }
 +    (*s)->direct = h->flags & AVIO_FLAG_DIRECT;
      (*s)->seekable = h->is_streamed ? 0 : AVIO_SEEKABLE_NORMAL;
      (*s)->max_packet_size = max_packet_size;
      if(h->prot) {
@@@ -742,7 -713,7 +742,7 @@@ int ffio_rewind_with_probe_data(AVIOCon
  
      alloc_size = FFMAX(s->buffer_size, new_size);
      if (alloc_size > buf_size)
 -        if (!(buf = av_realloc(buf, alloc_size)))
 +        if (!(buf = av_realloc_f(buf, 1, alloc_size)))
              return AVERROR(ENOMEM);
  
      if (new_size > buf_size) {
@@@ -785,8 -756,12 +785,12 @@@ int avio_open2(AVIOContext **s, const c
  
  int avio_close(AVIOContext *s)
  {
-     URLContext *h = s->opaque;
+     URLContext *h;
+     if (!s)
+         return 0;
  
+     h = s->opaque;
      av_free(s->buffer);
      av_free(s);
      return ffurl_close(h);
@@@ -859,7 -834,7 +863,7 @@@ static int dyn_buf_write(void *opaque, 
      }
  
      if (new_allocated_size > d->allocated_size) {
 -        d->buffer = av_realloc(d->buffer, new_allocated_size);
 +        d->buffer = av_realloc_f(d->buffer, 1, new_allocated_size);
          if(d->buffer == NULL)
               return AVERROR(ENOMEM);
          d->allocated_size = new_allocated_size;
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
   */
  
@@@ -31,8 -31,6 +31,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"
@@@ -72,11 -70,10 +72,11 @@@ static int mov_metadata_track_or_disc_n
  {
      char buf[16];
  
 -    short current, total;
 +    short current, total = 0;
      avio_rb16(pb); // unknown
      current = avio_rb16(pb);
 -    total = avio_rb16(pb);
 +    if (len >= 6)
 +        total = avio_rb16(pb);
      if (!total)
          snprintf(buf, sizeof(buf), "%d", current);
      else
@@@ -160,7 -157,7 +160,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;
@@@ -186,8 -183,6 +186,8 @@@ static int mov_read_udta_string(MOVCont
      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);
@@@ -312,33 -307,25 +312,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)
@@@ -401,7 -388,6 +401,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(url_feof(pb))
 +                    return AVERROR_EOF;
                  type = avio_rb16(pb);
                  len = avio_rb16(pb);
                  av_log(c->fc, AV_LOG_DEBUG, "type %d, len %d\n", type, len);
@@@ -498,8 -482,6 +498,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;
  }
  
@@@ -596,6 -565,34 +596,34 @@@ static int mov_read_dac3(MOVContext *c
      return 0;
  }
  
+ static int mov_read_dec3(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+ {
+     AVStream *st;
+     int eac3info, acmod, lfeon, bsmod;
+     if (c->fc->nb_streams < 1)
+         return 0;
+     st = c->fc->streams[c->fc->nb_streams-1];
+     /* No need to parse fields for additional independent substreams and its
+      * associated dependent substreams since libavcodec's E-AC-3 decoder
+      * does not support them yet. */
+     avio_rb16(pb); /* data_rate and num_ind_sub */
+     eac3info = avio_rb24(pb);
+     bsmod = (eac3info >> 12) & 0x1f;
+     acmod = (eac3info >>  9) & 0x7;
+     lfeon = (eac3info >>  8) & 0x1;
+     st->codec->channel_layout = avpriv_ac3_channel_layout_tab[acmod];
+     if (lfeon)
+         st->codec->channel_layout |= AV_CH_LOW_FREQUENCY;
+     st->codec->channels = av_get_channel_layout_nb_channels(st->codec->channel_layout);
+     st->codec->audio_service_type = bsmod;
+     if (st->codec->channels > 1 && bsmod == 0x7)
+         st->codec->audio_service_type = AV_AUDIO_SERVICE_TYPE_KARAOKE;
+     return 0;
+ }
  static int mov_read_chan(MOVContext *c, AVIOContext *pb, MOVAtom atom)
  {
      AVStream *st;
      if (atom.size < 16ULL + num_descr * 20ULL)
          return 0;
  
 -    av_dlog(c->fc, "chan: size=%ld version=%u flags=%u layout=%u bitmap=%u num_descr=%u\n",
 +    av_dlog(c->fc, "chan: size=%" PRId64 " version=%u flags=%u layout=%u bitmap=%u num_descr=%u\n",
              atom.size, version, flags, layout_tag, bitmap, num_descr);
  
      label_mask = 0;
      for (i = 0; i < num_descr; i++) {
 -        uint32_t label, cflags;
 +        uint32_t av_unused label, cflags;
          label     = avio_rb32(pb);          // mChannelLabel
          cflags    = avio_rb32(pb);          // mChannelFlags
          avio_rl32(pb);                      // mCoordinates[0]
@@@ -817,10 -814,6 +845,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;
  }
  
@@@ -853,7 -847,6 +881,7 @@@ static int mov_read_smi(MOVContext *c, 
      // 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_size = 0;
      st->codec->extradata = av_mallocz(atom.size + 0x5a + FF_INPUT_BUFFER_PADDING_SIZE);
      if (!st->codec->extradata)
          return AVERROR(ENOMEM);
@@@ -873,7 -866,7 +901,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) {
@@@ -931,8 -924,7 +959,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 CodecID 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, CODEC_ID_ALAC);
 +}
 +
 +static int mov_read_avss(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    return mov_read_extradata(c, pb, atom, CODEC_ID_AVS);
 +}
 +
 +static int mov_read_jp2h(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 +{
 +    return mov_read_extradata(c, pb, atom, CODEC_ID_JPEG2000);
 +}
 +
  static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom)
  {
      AVStream *st;
      if (st->codec->codec_id == CODEC_ID_QDM2 || st->codec->codec_id == 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);
@@@ -1030,7 -1001,6 +1058,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);
@@@ -1056,7 -1026,6 +1084,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);
@@@ -1085,7 -1054,6 +1113,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);
@@@ -1192,9 -1160,6 +1220,9 @@@ int ff_mov_read_stsd_entries(MOVContex
              avio_rb32(pb); /* reserved */
              avio_rb16(pb); /* reserved */
              dref_id = avio_rb16(pb);
 +        }else if (size <= 0){
 +            av_log(c->fc, AV_LOG_ERROR, "invalid size %d in stsd\n", size);
 +            return -1;
          }
  
          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 == 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 == 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 CODEC_ID_AC3:
 +        st->need_parsing = AVSTREAM_PARSE_FULL;
 +        break;
 +    case CODEC_ID_MPEG1VIDEO:
 +        st->need_parsing = AVSTREAM_PARSE_FULL;
 +        break;
      default:
          break;
      }
@@@ -1658,7 -1601,6 +1686,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;
@@@ -1731,8 -1673,10 +1759,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;
  
@@@ -1800,15 -1739,7 +1828,15 @@@ static int mov_read_ctts(MOVContext *c
  
          sc->ctts_data[i].count   = count;
          sc->ctts_data[i].duration= duration;
 -        if (duration < 0)
 +
 +        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);
      }
  
@@@ -1831,13 -1762,12 +1859,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_data && sc->stts_data &&
 +            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);
@@@ -2093,8 -2018,7 +2121,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",
@@@ -2229,21 -2153,6 +2257,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
@@@ -2320,9 -2229,6 +2348,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 */
@@@ -2506,7 -2412,7 +2534,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, atom.size - 4, c->fc->streams[0]->codec);
 +    return 0;
 +}
 +
  static const MOVParseTableEntry mov_default_parse_table[] = {
 -{ MKTAG('a','v','s','s'), mov_read_extradata },
 +{ 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','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('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('w','a','v','e'), mov_read_wave },
  { MKTAG('e','s','d','s'), mov_read_esds },
  { MKTAG('d','a','c','3'), mov_read_dac3 }, /* AC-3 info */
+ { MKTAG('d','e','c','3'), mov_read_dec3 }, /* EAC-3 info */
  { MKTAG('w','i','d','e'), mov_read_wide }, /* place holder */
  { MKTAG('w','f','e','x'), mov_read_wfex },
  { MKTAG('c','m','o','v'), mov_read_cmov },
@@@ -2716,7 -2612,7 +2745,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);
              }
          }
  
@@@ -2727,49 -2623,6 +2756,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);
          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) {
@@@ -2837,14 -2683,8 +2866,14 @@@ static int mov_read_header(AVFormatCont
      }
      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) {
 +        int i;
 +        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]);
 +    }
  
      if (mov->trex_data) {
          int i;
@@@ -2892,7 -2732,6 +2921,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);
@@@ -3032,16 -2871,6 +3061,16 @@@ static int mov_read_seek(AVFormatContex
      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 = {"mov,mp4,m4a,3gp,3g2,mj2", av_default_item_name, options, LIBAVUTIL_VERSION_INT};
 +
 +
  AVInputFormat ff_mov_demuxer = {
      .name           = "mov,mp4,m4a,3gp,3g2,mj2",
      .long_name      = NULL_IF_CONFIG_SMALL("QuickTime/MPEG-4/Motion JPEG 2000 format"),
      .read_packet    = mov_read_packet,
      .read_close     = mov_read_close,
      .read_seek      = mov_read_seek,
 +    .priv_class     = &class,
  };
diff --combined libavformat/segment.c
@@@ -113,10 -113,15 +113,15 @@@ static int seg_write_header(AVFormatCon
      seg->offset_time = 0;
      seg->recording_time = seg->time * 1000000;
  
+     oc = avformat_alloc_context();
+     if (!oc)
+         return AVERROR(ENOMEM);
      if (seg->list)
          if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
                                &s->interrupt_callback, NULL)) < 0)
-             return ret;
+             goto fail;
  
      for (i = 0; i< s->nb_streams; i++)
          seg->has_video +=
                 "More than a single video stream present, "
                 "expect issues decoding it.\n");
  
-     oc = avformat_alloc_context();
-     if (!oc) {
-         ret = AVERROR(ENOMEM);
-         goto fail;
-     }
      oc->oformat = av_guess_format(seg->format, s->filename, NULL);
  
      if (!oc->oformat) {
  
  fail:
      if (ret) {
 -        oc->streams = NULL;
 -        oc->nb_streams = 0;
 +        if (oc) {
 +            oc->streams = NULL;
 +            oc->nb_streams = 0;
 +            avformat_free_context(oc);
 +        }
          if (seg->list)
              avio_close(seg->pb);
 -        avformat_free_context(oc);
      }
      return ret;
  }