Merge commit '1afddbe59e96af75f1c07605afc95615569f388f'
authorMichael Niedermayer <michaelni@gmx.at>
Fri, 8 Mar 2013 16:28:42 +0000 (17:28 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Fri, 8 Mar 2013 18:12:03 +0000 (19:12 +0100)
* commit '1afddbe59e96af75f1c07605afc95615569f388f':
  avpacket: use AVBuffer to allow refcounting the packets.

Conflicts:
libavcodec/avpacket.c
libavcodec/utils.c
libavdevice/v4l2.c
libavformat/avidec.c
libavformat/flacdec.c
libavformat/id3v2.c
libavformat/matroskaenc.c
libavformat/mux.c
libavformat/utils.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
24 files changed:
1  2 
ffmpeg.c
libavcodec/avcodec.h
libavcodec/avpacket.c
libavcodec/utils.c
libavcodec/version.h
libavdevice/v4l2.c
libavformat/asfdec.c
libavformat/avformat.h
libavformat/avidec.c
libavformat/flacdec.c
libavformat/id3v2.c
libavformat/id3v2.h
libavformat/matroskadec.c
libavformat/matroskaenc.c
libavformat/mp3enc.c
libavformat/mpegts.c
libavformat/mux.c
libavformat/mxg.c
libavformat/psxstr.c
libavformat/rmdec.c
libavformat/rtpdec.c
libavformat/rtpdec_qt.c
libavformat/subtitles.c
libavformat/utils.c

diff --cc ffmpeg.c
+++ b/ffmpeg.c
@@@ -564,16 -330,6 +564,17 @@@ static void write_frame(AVFormatContex
                                             &new_pkt.data, &new_pkt.size,
                                             pkt->data, pkt->size,
                                             pkt->flags & AV_PKT_FLAG_KEY);
 +        if(a == 0 && new_pkt.data != pkt->data && new_pkt.destruct) {
 +            uint8_t *t = av_malloc(new_pkt.size + FF_INPUT_BUFFER_PADDING_SIZE); //the new should be a subset of the old so cannot overflow
 +            if(t) {
 +                memcpy(t, new_pkt.data, new_pkt.size);
 +                memset(t + new_pkt.size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
 +                new_pkt.data = t;
++                new_pkt.buf = NULL;
 +                a = 1;
 +            } else
 +                a = AVERROR(ENOMEM);
 +        }
          if (a > 0) {
              av_free_packet(pkt);
              new_pkt.destruct = av_destruct_packet;
@@@ -29,8 -29,8 +29,9 @@@
  #include <errno.h>
  #include "libavutil/samplefmt.h"
  #include "libavutil/avutil.h"
+ #include "libavutil/buffer.h"
  #include "libavutil/cpu.h"
 +#include "libavutil/channel_layout.h"
  #include "libavutil/dict.h"
  #include "libavutil/log.h"
  #include "libavutil/pixfmt.h"
  #include <string.h>
  
  #include "libavutil/avassert.h"
+ #include "libavutil/common.h"
  #include "libavutil/mem.h"
  #include "avcodec.h"
 +#include "bytestream.h"
 +#include "internal.h"
 +
 +void ff_packet_free_side_data(AVPacket *pkt)
 +{
 +    int i;
 +    for (i = 0; i < pkt->side_data_elems; i++)
 +        av_free(pkt->side_data[i].data);
 +    av_freep(&pkt->side_data);
 +    pkt->side_data_elems = 0;
 +}
  
+ #if FF_API_DESTRUCT_PACKET
  void av_destruct_packet(AVPacket *pkt)
  {
      av_free(pkt->data);
@@@ -123,50 -168,41 +179,57 @@@ do 
          dst = data;                                                     \
      } while (0)
  
- static int copy_packet_data(AVPacket *dst, AVPacket *src)
 +/* Makes duplicates of data, side_data, but does not copy any other fields */
-     dst->data      = NULL;
-     dst->side_data = NULL;
-     DUP_DATA(dst->data, src->data, dst->size, 1);
-     dst->destruct = av_destruct_packet;
++static int copy_packet_data(AVPacket *pkt, AVPacket *src)
 +{
-     if (dst->side_data_elems) {
++    pkt->data      = NULL;
++    pkt->side_data = NULL;
++    DUP_DATA(pkt->data, src->data, pkt->size, 1, ALLOC_BUF);
++#if FF_API_DESTRUCT_PACKET
++    pkt->destruct = dummy_destruct_packet;
++#endif
 +
-         DUP_DATA(dst->side_data, src->side_data,
-                 dst->side_data_elems * sizeof(*dst->side_data), 0);
-         memset(dst->side_data, 0,
-                 dst->side_data_elems * sizeof(*dst->side_data));
-         for (i = 0; i < dst->side_data_elems; i++) {
-             DUP_DATA(dst->side_data[i].data, src->side_data[i].data,
-                     src->side_data[i].size, 1);
-             dst->side_data[i].size = src->side_data[i].size;
-             dst->side_data[i].type = src->side_data[i].type;
++    if (pkt->side_data_elems) {
 +        int i;
 +
-     av_destruct_packet(dst);
++        DUP_DATA(pkt->side_data, src->side_data,
++                pkt->side_data_elems * sizeof(*pkt->side_data), 0, ALLOC_MALLOC);
++        memset(pkt->side_data, 0,
++                pkt->side_data_elems * sizeof(*pkt->side_data));
++        for (i = 0; i < pkt->side_data_elems; i++) {
++            DUP_DATA(pkt->side_data[i].data, src->side_data[i].data,
++                    src->side_data[i].size, 1, ALLOC_MALLOC);
++            pkt->side_data[i].size = src->side_data[i].size;
++            pkt->side_data[i].type = src->side_data[i].type;
 +        }
 +    }
 +    return 0;
 +
 +failed_alloc:
++    av_destruct_packet(pkt);
 +    return AVERROR(ENOMEM);
 +}
 +
  int av_dup_packet(AVPacket *pkt)
  {
      AVPacket tmp_pkt;
  
-     if (pkt->destruct == NULL && pkt->data) {
+     if (!pkt->buf && pkt->data
+ #if FF_API_DESTRUCT_PACKET
+         && !pkt->destruct
+ #endif
+         ) {
          tmp_pkt = *pkt;
 -
 -        pkt->data      = NULL;
 -        pkt->side_data = NULL;
 -        DUP_DATA(pkt->data, tmp_pkt.data, pkt->size, 1, ALLOC_BUF);
 -#if FF_API_DESTRUCT_PACKET
 -        pkt->destruct = dummy_destruct_packet;
 -#endif
 -
 -        if (pkt->side_data_elems) {
 -            int i;
 -
 -            DUP_DATA(pkt->side_data, tmp_pkt.side_data,
 -                     pkt->side_data_elems * sizeof(*pkt->side_data), 0, ALLOC_MALLOC);
 -            memset(pkt->side_data, 0,
 -                   pkt->side_data_elems * sizeof(*pkt->side_data));
 -            for (i = 0; i < pkt->side_data_elems; i++)
 -                DUP_DATA(pkt->side_data[i].data, tmp_pkt.side_data[i].data,
 -                         tmp_pkt.side_data[i].size, 1, ALLOC_MALLOC);
 -        }
 +        return copy_packet_data(pkt, &tmp_pkt);
      }
      return 0;
 +}
  
 -failed_alloc:
 -    av_free_packet(pkt);
 -    return AVERROR(ENOMEM);
 +int av_copy_packet(AVPacket *dst, AVPacket *src)
 +{
 +    *dst = *src;
++    dst->buf = av_buffer_ref(src->buf);
 +    return copy_packet_data(dst, src);
  }
  
  void av_free_packet(AVPacket *pkt)
@@@ -226,84 -267,6 +294,88 @@@ uint8_t *av_packet_get_side_data(AVPack
      return NULL;
  }
  
-         p = av_malloc(size);
-         if (!p)
 +#define FF_MERGE_MARKER 0x8c4d9d108e25e9feULL
 +
 +int av_packet_merge_side_data(AVPacket *pkt){
 +    if(pkt->side_data_elems){
++        AVBufferRef *buf;
 +        int i;
 +        uint8_t *p;
 +        uint64_t size= pkt->size + 8LL + FF_INPUT_BUFFER_PADDING_SIZE;
 +        AVPacket old= *pkt;
 +        for (i=0; i<old.side_data_elems; i++) {
 +            size += old.side_data[i].size + 5LL;
 +        }
 +        if (size > INT_MAX)
 +            return AVERROR(EINVAL);
-         pkt->data = p;
-         pkt->destruct = av_destruct_packet;
++        buf = av_buffer_alloc(size);
++        if (!buf)
 +            return AVERROR(ENOMEM);
++        pkt->buf = buf;
++        pkt->data = p = buf->data;
++#if FF_API_DESTRUCT_PACKET
++        pkt->destruct = dummy_destruct_packet;
++#endif
 +        pkt->size = size - FF_INPUT_BUFFER_PADDING_SIZE;
 +        bytestream_put_buffer(&p, old.data, old.size);
 +        for (i=old.side_data_elems-1; i>=0; i--) {
 +            bytestream_put_buffer(&p, old.side_data[i].data, old.side_data[i].size);
 +            bytestream_put_be32(&p, old.side_data[i].size);
 +            *p++ = old.side_data[i].type | ((i==old.side_data_elems-1)*128);
 +        }
 +        bytestream_put_be64(&p, FF_MERGE_MARKER);
 +        av_assert0(p-pkt->data == pkt->size);
 +        memset(p, 0, FF_INPUT_BUFFER_PADDING_SIZE);
 +        av_free_packet(&old);
 +        pkt->side_data_elems = 0;
 +        pkt->side_data = NULL;
 +        return 1;
 +    }
 +    return 0;
 +}
 +
 +int av_packet_split_side_data(AVPacket *pkt){
 +    if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == FF_MERGE_MARKER){
 +        int i;
 +        unsigned int size;
 +        uint8_t *p;
 +
 +        p = pkt->data + pkt->size - 8 - 5;
 +        for (i=1; ; i++){
 +            size = AV_RB32(p);
 +            if (size>INT_MAX || p - pkt->data < size)
 +                return 0;
 +            if (p[4]&128)
 +                break;
 +            p-= size+5;
 +        }
 +
 +        pkt->side_data = av_malloc(i * sizeof(*pkt->side_data));
 +        if (!pkt->side_data)
 +            return AVERROR(ENOMEM);
 +
 +        p= pkt->data + pkt->size - 8 - 5;
 +        for (i=0; ; i++){
 +            size= AV_RB32(p);
 +            av_assert0(size<=INT_MAX && p - pkt->data >= size);
 +            pkt->side_data[i].data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
 +            pkt->side_data[i].size = size;
 +            pkt->side_data[i].type = p[4]&127;
 +            if (!pkt->side_data[i].data)
 +                return AVERROR(ENOMEM);
 +            memcpy(pkt->side_data[i].data, p-size, size);
 +            pkt->size -= size + 5;
 +            if(p[4]&128)
 +                break;
 +            p-= size+5;
 +        }
 +        pkt->size -= 8;
 +        pkt->side_data_elems = i+1;
 +        return 1;
 +    }
 +    return 0;
 +}
 +
  int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
                                 int size)
  {
@@@ -1144,33 -881,25 +1144,39 @@@ free_and_end
      goto end;
  }
  
 -int ff_alloc_packet(AVPacket *avpkt, int size)
 +int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int size)
  {
 -    if (size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE)
 +    if (size < 0 || avpkt->size < 0 || size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE) {
 +        av_log(avctx, AV_LOG_ERROR, "Size %d invalid\n", size);
          return AVERROR(EINVAL);
 +    }
 +
 +    if (avctx) {
 +        av_assert0(!avpkt->data || avpkt->data != avctx->internal->byte_buffer);
 +        if (!avpkt->data || avpkt->size < size) {
 +            av_fast_padded_malloc(&avctx->internal->byte_buffer, &avctx->internal->byte_buffer_size, size);
 +            avpkt->data = avctx->internal->byte_buffer;
 +            avpkt->size = avctx->internal->byte_buffer_size;
 +            avpkt->destruct = NULL;
 +        }
 +    }
  
      if (avpkt->data) {
+         AVBufferRef *buf = avpkt->buf;
+ #if FF_API_DESTRUCT_PACKET
          void *destruct = avpkt->destruct;
+ #endif
  
 -        if (avpkt->size < size)
 +        if (avpkt->size < size) {
 +            av_log(avctx, AV_LOG_ERROR, "User packet is too small (%d < %d)\n", avpkt->size, size);
              return AVERROR(EINVAL);
 +        }
  
          av_init_packet(avpkt);
+ #if FF_API_DESTRUCT_PACKET
          avpkt->destruct = destruct;
+ #endif
+         avpkt->buf      = buf;
          avpkt->size     = size;
          return 0;
      } else {
@@@ -1307,31 -1024,11 +1313,32 @@@ int attribute_align_arg avcodec_encode_
          } else {
              avpkt->size = 0;
          }
 +    }
 +    if (avpkt->data && avpkt->data == avctx->internal->byte_buffer) {
 +        needs_realloc = 0;
 +        if (user_pkt.data) {
 +            if (user_pkt.size >= avpkt->size) {
 +                memcpy(user_pkt.data, avpkt->data, avpkt->size);
 +            } else {
 +                av_log(avctx, AV_LOG_ERROR, "Provided packet is too small, needs to be %d\n", avpkt->size);
 +                avpkt->size = user_pkt.size;
 +                ret = -1;
 +            }
++            avpkt->buf      = user_pkt.buf;
 +            avpkt->data     = user_pkt.data;
 +            avpkt->destruct = user_pkt.destruct;
 +        } else {
 +            if (av_dup_packet(avpkt) < 0) {
 +                ret = AVERROR(ENOMEM);
 +            }
 +        }
 +    }
  
 -        if (!user_packet && avpkt->size) {
 -            ret = av_buffer_realloc(&avpkt->buf, avpkt->size);
 +    if (!ret) {
 +        if (needs_realloc && avpkt->data) {
-             uint8_t *new_data = av_realloc(avpkt->data, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
-             if (new_data)
-                 avpkt->data = new_data;
++            ret = av_buffer_realloc(&avpkt->buf, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
+             if (ret >= 0)
+                 avpkt->data = avpkt->buf->data;
          }
  
          avctx->frame_number++;
@@@ -1503,38 -1196,16 +1510,38 @@@ int attribute_align_arg avcodec_encode_
      av_assert0(avctx->codec->encode2);
  
      ret = avctx->codec->encode2(avctx, avpkt, frame, got_packet_ptr);
 +    av_assert0(ret <= 0);
 +
 +    if (avpkt->data && avpkt->data == avctx->internal->byte_buffer) {
 +        needs_realloc = 0;
 +        if (user_pkt.data) {
 +            if (user_pkt.size >= avpkt->size) {
 +                memcpy(user_pkt.data, avpkt->data, avpkt->size);
 +            } else {
 +                av_log(avctx, AV_LOG_ERROR, "Provided packet is too small, needs to be %d\n", avpkt->size);
 +                avpkt->size = user_pkt.size;
 +                ret = -1;
 +            }
++            avpkt->buf      = user_pkt.buf;
 +            avpkt->data     = user_pkt.data;
 +            avpkt->destruct = user_pkt.destruct;
 +        } else {
 +            if (av_dup_packet(avpkt) < 0) {
 +                ret = AVERROR(ENOMEM);
 +            }
 +        }
 +    }
 +
      if (!ret) {
          if (!*got_packet_ptr)
              avpkt->size = 0;
          else if (!(avctx->codec->capabilities & CODEC_CAP_DELAY))
              avpkt->pts = avpkt->dts = frame->pts;
  
-         if (needs_realloc && avpkt->data &&
-             avpkt->destruct == av_destruct_packet) {
-             uint8_t *new_data = av_realloc(avpkt->data, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
-             if (new_data)
-                 avpkt->data = new_data;
 -        if (!user_packet && avpkt->size) {
 -            ret = av_buffer_realloc(&avpkt->buf, avpkt->size);
++        if (needs_realloc && avpkt->data) {
++            ret = av_buffer_realloc(&avpkt->buf, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
+             if (ret >= 0)
+                 avpkt->data = avpkt->buf->data;
          }
  
          avctx->frame_number++;
Simple merge
  #if HAVE_SYS_VIDEOIO_H
  #include <sys/videoio.h>
  #else
 +#if HAVE_ASM_TYPES_H
 +#include <asm/types.h>
 +#endif
  #include <linux/videodev2.h>
  #endif
+ #include "libavutil/atomic.h"
  #include "libavutil/avassert.h"
  #include "libavutil/imgutils.h"
  #include "libavutil/log.h"
@@@ -102,22 -64,20 +103,22 @@@ struct video_data 
      int frame_format; /* V4L2_PIX_FMT_* */
      int width, height;
      int frame_size;
 -    int timeout;
      int interlaced;
      int top_field_first;
 +    int ts_mode;
 +    TimeFilter *timefilter;
 +    int64_t last_time_m;
  
      int buffers;
+     volatile int buffers_queued;
      void **buf_start;
      unsigned int *buf_len;
-     int *buf_dequeued;
      char *standard;
 +    v4l2_std_id std_id;
      int channel;
 -    char *video_size;   /**< String describing video size,
 -                             set by a private option. */
      char *pixel_format; /**< Set by a private option. */
      int list_format;    /**< Set by a private option. */
 +    int list_standard;  /**< Set by a private option. */
      char *framerate;    /**< Set by a private option. */
  };
  
@@@ -436,13 -369,9 +437,8 @@@ static int mmap_init(AVFormatContext *c
      if (s->buf_len == NULL) {
          av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer sizes\n");
          av_free(s->buf_start);
 -
          return AVERROR(ENOMEM);
      }
-     s->buf_dequeued = av_mallocz(sizeof(int) * s->buffers);
-     if (s->buf_dequeued == NULL) {
-         av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer array\n");
-         return AVERROR(ENOMEM);
-     }
  
      for (i = 0; i < req.count; i++) {
          struct v4l2_buffer buf = {
      return 0;
  }
  
- static int enqueue_buffer(int fd, int index)
+ #if FF_API_DESTRUCT_PACKET
+ static void dummy_release_buffer(AVPacket *pkt)
+ {
+     av_assert0(0);
+ }
+ #endif
+ static void mmap_release_buffer(void *opaque, uint8_t *data)
  {
-     int res;
      struct v4l2_buffer buf = { 0 };
+     int res, fd;
+     struct buff_data *buf_descriptor = opaque;
+     struct video_data *s = buf_descriptor->s;
  
-     buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
      buf.memory = V4L2_MEMORY_MMAP;
-     buf.index  = index;
+     buf.index = buf_descriptor->index;
+     fd = buf_descriptor->fd;
+     av_free(buf_descriptor);
  
 -    res = ioctl(fd, VIDIOC_QBUF, &buf);
 -    if (res < 0)
 +    if (v4l2_ioctl(fd, VIDIOC_QBUF, &buf) < 0) {
 +        res = AVERROR(errno);
-         av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", av_err2str(res));
-         return res;
+         av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n",
 -               strerror(errno));
++               av_err2str(res));
 +    }
-     return 0;
- }
 +
- static void mmap_release_buffer(AVPacket *pkt)
- {
-     struct buff_data *buf_descriptor = pkt->priv;
-     if (pkt->data == NULL)
-         return;
-     if (buf_descriptor->index == -1) {
-         av_free(pkt->data);
-     } else {
-         if (!enqueue_buffer(buf_descriptor->fd, buf_descriptor->index))
-             buf_descriptor->buf_dequeued[buf_descriptor->index] = 0;
-     }
-     av_free(buf_descriptor);
-     pkt->data = NULL;
-     pkt->size = 0;
+     avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
  }
  
 +#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
 +static int64_t av_gettime_monotonic(void)
 +{
 +    struct timespec tv;
 +
 +    clock_gettime(CLOCK_MONOTONIC, &tv);
 +    return (int64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
 +}
 +#endif
 +
 +static int init_convert_timestamp(AVFormatContext *ctx, int64_t ts)
 +{
 +    struct video_data *s = ctx->priv_data;
 +    int64_t now;
 +
 +    now = av_gettime();
 +    if (s->ts_mode == V4L_TS_ABS &&
 +        ts <= now + 1 * AV_TIME_BASE && ts >= now - 10 * AV_TIME_BASE) {
 +        av_log(ctx, AV_LOG_INFO, "Detected absolute timestamps\n");
 +        s->ts_mode = V4L_TS_CONVERT_READY;
 +        return 0;
 +    }
 +#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
 +    now = av_gettime_monotonic();
 +    if (s->ts_mode == V4L_TS_MONO2ABS ||
 +        (ts <= now + 1 * AV_TIME_BASE && ts >= now - 10 * AV_TIME_BASE)) {
 +        int64_t period = av_rescale_q(1, AV_TIME_BASE_Q,
 +                                      ctx->streams[0]->avg_frame_rate);
 +        av_log(ctx, AV_LOG_INFO, "Detected monotonic timestamps, converting\n");
 +        /* microseconds instead of seconds, MHz instead of Hz */
 +        s->timefilter = ff_timefilter_new(1, period, 1.0E-6);
 +        s->ts_mode = V4L_TS_CONVERT_READY;
 +        return 0;
 +    }
 +#endif
 +    av_log(ctx, AV_LOG_ERROR, "Unknown timestamps\n");
 +    return AVERROR(EIO);
 +}
 +
 +static int convert_timestamp(AVFormatContext *ctx, int64_t *ts)
 +{
 +    struct video_data *s = ctx->priv_data;
 +
 +    if (s->ts_mode) {
 +        int r = init_convert_timestamp(ctx, *ts);
 +        if (r < 0)
 +            return r;
 +    }
 +#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
 +    if (s->timefilter) {
 +        int64_t nowa = av_gettime();
 +        int64_t nowm = av_gettime_monotonic();
 +        ff_timefilter_update(s->timefilter, nowa, nowm - s->last_time_m);
 +        s->last_time_m = nowm;
 +        *ts = ff_timefilter_eval(s->timefilter, *ts - nowm);
 +    }
 +#endif
 +    return 0;
 +}
 +
  static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
  {
      struct video_data *s = ctx->priv_data;
          .type   = V4L2_BUF_TYPE_VIDEO_CAPTURE,
          .memory = V4L2_MEMORY_MMAP
      };
-     struct buff_data *buf_descriptor;
-     int res, i, free_buffers;
 -    struct pollfd p = { .fd = s->fd, .events = POLLIN };
+     int res;
  
 -    res = poll(&p, 1, s->timeout);
 -    if (res < 0)
 -        return AVERROR(errno);
 -
 -    if (!(p.revents & (POLLIN | POLLERR | POLLHUP)))
 -        return AVERROR(EAGAIN);
 -
      /* FIXME: Some special treatment might be needed in case of loss of signal... */
 -    while ((res = ioctl(s->fd, VIDIOC_DQBUF, &buf)) < 0 && (errno == EINTR));
 +    while ((res = v4l2_ioctl(s->fd, VIDIOC_DQBUF, &buf)) < 0 && (errno == EINTR));
      if (res < 0) {
-         if (errno == EAGAIN)
+         if (errno == EAGAIN) {
+             pkt->size = 0;
 -
              return AVERROR(EAGAIN);
 -        av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_DQBUF): %s\n",
 -               strerror(errno));
 -
 -        return AVERROR(errno);
+         }
 +        res = AVERROR(errno);
 +        av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_DQBUF): %s\n", av_err2str(res));
 +        return res;
      }
  
      if (buf.index >= s->buffers) {
          av_log(ctx, AV_LOG_ERROR, "Invalid buffer index received.\n");
          return AVERROR(EINVAL);
      }
+     avpriv_atomic_int_add_and_fetch(&s->buffers_queued, -1);
+     // always keep at least one buffer queued
+     av_assert0(avpriv_atomic_int_get(&s->buffers_queued) >= 1);
  
 +    /* CPIA is a compressed format and we don't know the exact number of bytes
 +     * used by a frame, so set it here as the driver announces it.
 +     */
 +    if (ctx->video_codec_id == AV_CODEC_ID_CPIA)
 +        s->frame_size = buf.bytesused;
 +
      if (s->frame_size > 0 && buf.bytesused != s->frame_size) {
          av_log(ctx, AV_LOG_ERROR,
                 "The v4l2 frame is %d bytes, but %d bytes are expected\n",
                 buf.bytesused, s->frame_size);
-         enqueue_buffer(s->fd, buf.index);
 -
          return AVERROR_INVALIDDATA;
      }
  
              return res;
          }
          memcpy(pkt->data, s->buf_start[buf.index], buf.bytesused);
-         enqueue_buffer(s->fd, buf.index);
-         buf_descriptor->index = -1;
 -        res = ioctl(s->fd, VIDIOC_QBUF, &buf);
++        res = v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf);
+         if (res < 0) {
+             av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF)\n");
+             av_free_packet(pkt);
+             return AVERROR(errno);
+         }
+         avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
      } else {
-         /* Image is at s->buff_start[buf.index] */
-         pkt->data = s->buf_start[buf.index];
+         struct buff_data *buf_descriptor;
+         pkt->data     = s->buf_start[buf.index];
+         pkt->size     = buf.bytesused;
+ #if FF_API_DESTRUCT_PACKET
+         pkt->destruct = dummy_release_buffer;
+ #endif
+         buf_descriptor = av_malloc(sizeof(struct buff_data));
+         if (buf_descriptor == NULL) {
+             /* Something went wrong... Since av_malloc() failed, we cannot even
+              * allocate a buffer for memcpying into it
+              */
+             av_log(ctx, AV_LOG_ERROR, "Failed to allocate a buffer descriptor\n");
 -            res = ioctl(s->fd, VIDIOC_QBUF, &buf);
++            res = v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf);
+             return AVERROR(ENOMEM);
+         }
+         buf_descriptor->fd    = s->fd;
          buf_descriptor->index = buf.index;
-         buf_descriptor->buf_dequeued[buf.index] = 1;
+         buf_descriptor->s     = s;
+         pkt->buf = av_buffer_create(pkt->data, pkt->size, mmap_release_buffer,
+                                     buf_descriptor, 0);
+         if (!pkt->buf) {
+             av_freep(&buf_descriptor);
+             return AVERROR(ENOMEM);
+         }
      }
-     pkt->size = buf.bytesused;
-     pkt->priv = buf_descriptor;
-     pkt->destruct = mmap_release_buffer;
      pkt->pts = buf.timestamp.tv_sec * INT64_C(1000000) + buf.timestamp.tv_usec;
-     res = convert_timestamp(ctx, &pkt->pts);
-     if (res < 0) {
-         mmap_release_buffer(pkt);
-         return res;
-     }
++    convert_timestamp(ctx, &pkt->pts);
  
      return s->buf_len[buf.index];
  }
@@@ -669,18 -548,23 +670,19 @@@ static int mmap_start(AVFormatContext *
              .memory = V4L2_MEMORY_MMAP
          };
  
 -        res = ioctl(s->fd, VIDIOC_QBUF, &buf);
 -        if (res < 0) {
 -            av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n",
 -                   strerror(errno));
 -
 -            return AVERROR(errno);
 +        if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) {
 +            res = AVERROR(errno);
 +            av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", av_err2str(res));
 +            return res;
          }
      }
+     s->buffers_queued = s->buffers;
  
      type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 -    res = ioctl(s->fd, VIDIOC_STREAMON, &type);
 -    if (res < 0) {
 -        av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n",
 -               strerror(errno));
 -
 -        return AVERROR(errno);
 +    if (v4l2_ioctl(s->fd, VIDIOC_STREAMON, &type) < 0) {
 +        res = AVERROR(errno);
 +        av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n", av_err2str(res));
 +        return res;
      }
  
      return 0;
@@@ -1021,9 -852,13 +1020,13 @@@ static int v4l2_read_close(AVFormatCont
  {
      struct video_data *s = s1->priv_data;
  
+     if (avpriv_atomic_int_get(&s->buffers_queued) != s->buffers)
+         av_log(s1, AV_LOG_WARNING, "Some buffers are still owned by the caller on "
+                "close.\n");
      mmap_close(s);
  
 -    close(s->fd);
 +    v4l2_close(s->fd);
      return 0;
  }
  
Simple merge
@@@ -2091,44 -1743,6 +2091,44 @@@ const struct AVCodecTag *avformat_get_r
   */
  
  /**
- void avformat_queue_attached_pictures(AVFormatContext *s);
 + * Guess the sample aspect ratio of a frame, based on both the stream and the
 + * frame aspect ratio.
 + *
 + * Since the frame aspect ratio is set by the codec but the stream aspect ratio
 + * is set by the demuxer, these two may not be equal. This function tries to
 + * return the value that you should use if you would like to display the frame.
 + *
 + * Basic logic is to use the stream aspect ratio if it is set to something sane
 + * otherwise use the frame aspect ratio. This way a container setting, which is
 + * usually easy to modify can override the coded value in the frames.
 + *
 + * @param format the format context which the stream is part of
 + * @param stream the stream which the frame is part of
 + * @param frame the frame with the aspect ratio to be determined
 + * @return the guessed (valid) sample_aspect_ratio, 0/1 if no idea
 + */
 +AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame);
 +
 +/**
 + * Check if the stream st contained in s is matched by the stream specifier
 + * spec.
 + *
 + * See the "stream specifiers" chapter in the documentation for the syntax
 + * of spec.
 + *
 + * @return  >0 if st is matched by spec;
 + *          0  if st is not matched by spec;
 + *          AVERROR code if spec is invalid
 + *
 + * @note  A stream specifier can match several streams in the format.
 + */
 +int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st,
 +                                    const char *spec);
 +
++int avformat_queue_attached_pictures(AVFormatContext *s);
 +
 +
 +/**
   * @}
   */
  
@@@ -1162,10 -1083,16 +1164,16 @@@ resync
          }
  
          if (CONFIG_DV_DEMUXER && avi->dv_demux) {
+             AVBufferRef *avbuf = pkt->buf;
+ #if FF_API_DESTRUCT_PACKET
              dstr = pkt->destruct;
+ #endif
              size = avpriv_dv_produce_packet(avi->dv_demux, pkt,
 -                                    pkt->data, pkt->size);
 +                                    pkt->data, pkt->size, pkt->pos);
+ #if FF_API_DESTRUCT_PACKET
              pkt->destruct = dstr;
+ #endif
+             pkt->buf = avbuf;
              pkt->flags |= AV_PKT_FLAG_KEY;
              if (size < 0)
                  av_free_packet(pkt);
@@@ -110,10 -111,11 +111,10 @@@ static int parse_picture(AVFormatContex
              ret = AVERROR_INVALIDDATA;
          goto fail;
      }
-     if (!(data = av_malloc(len))) {
+     if (!(data = av_buffer_alloc(len))) {
 -        ret = AVERROR(ENOMEM);
 -        goto fail;
 +        RETURN_ERROR(AVERROR(ENOMEM));
      }
-     if (avio_read(pb, data, len) != len) {
+     if (avio_read(pb, data->data, len) != len) {
          av_log(s, AV_LOG_ERROR, "Error reading attached picture data.\n");
          if (s->error_recognition & AV_EF_EXPLODE)
              ret = AVERROR(EIO);
@@@ -489,9 -476,8 +489,8 @@@ static void read_apic(AVFormatContext *
          goto fail;
      }
  
-     apic->len   = taglen;
-     apic->data  = av_malloc(taglen);
-     if (!apic->data || !apic->len || avio_read(pb, apic->data, taglen) != taglen)
+     apic->buf = av_buffer_alloc(taglen);
 -    if (!apic->buf || avio_read(pb, apic->buf->data, taglen) != taglen)
++    if (!apic->buf || !taglen || avio_read(pb, apic->buf->data, taglen) != taglen)
          goto fail;
  
      new_extra->tag    = "APIC";
Simple merge
@@@ -1198,11 -1107,11 +1198,12 @@@ static int matroska_decode_buffer(uint8
  static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
                                      AVPacket *pkt, uint64_t display_duration)
  {
-     char *line, *layer, *ptr = pkt->data, *end = ptr+pkt->size;
+     AVBufferRef *line;
+     char *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;
@@@ -1043,8 -968,6 +1042,7 @@@ static int mkv_write_header(AVFormatCon
  
      av_init_packet(&mkv->cur_audio_pkt);
      mkv->cur_audio_pkt.size = 0;
-     mkv->audio_buffer_size  = 0;
 +    mkv->cluster_pos = -1;
  
      avio_flush(pb);
      return 0;
Simple merge
Simple merge
@@@ -533,50 -417,25 +533,53 @@@ int ff_interleave_add_packet(AVFormatCo
                                int (*compare)(AVFormatContext *, AVPacket *, AVPacket *))
  {
      AVPacketList **next_point, *this_pktl;
 +    AVStream *st   = s->streams[pkt->stream_index];
 +    int chunked    = s->max_chunk_size || s->max_chunk_duration;
  
      this_pktl      = av_mallocz(sizeof(AVPacketList));
 +    if (!this_pktl)
 +        return AVERROR(ENOMEM);
      this_pktl->pkt = *pkt;
+ #if FF_API_DESTRUCT_PACKET
      pkt->destruct  = NULL;           // do not free original but only the copy
 -    av_dup_packet(&this_pktl->pkt);  // duplicate the packet if it uses non-alloced memory
+ #endif
+     pkt->buf       = NULL;
 +    av_dup_packet(&this_pktl->pkt);  // duplicate the packet if it uses non-allocated memory
  
      if (s->streams[pkt->stream_index]->last_in_packet_buffer) {
 -        next_point = &(s->streams[pkt->stream_index]->last_in_packet_buffer->next);
 -    } else
 +        next_point = &(st->last_in_packet_buffer->next);
 +    } else {
          next_point = &s->packet_buffer;
 +    }
  
 +    if (chunked) {
 +        uint64_t max= av_rescale_q_rnd(s->max_chunk_duration, AV_TIME_BASE_Q, st->time_base, AV_ROUND_UP);
 +        st->interleaver_chunk_size     += pkt->size;
 +        st->interleaver_chunk_duration += pkt->duration;
 +        if (   (s->max_chunk_size && st->interleaver_chunk_size > s->max_chunk_size)
 +            || (max && st->interleaver_chunk_duration           > max)) {
 +            st->interleaver_chunk_size      = 0;
 +            this_pktl->pkt.flags |= CHUNK_START;
 +            if (max && st->interleaver_chunk_duration > max) {
 +                int64_t syncoffset = (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)*max/2;
 +                int64_t syncto = av_rescale(pkt->dts + syncoffset, 1, max)*max - syncoffset;
 +
 +                st->interleaver_chunk_duration += (pkt->dts - syncto)/8 - max;
 +            } else
 +                st->interleaver_chunk_duration = 0;
 +        }
 +    }
      if (*next_point) {
 +        if (chunked && !(this_pktl->pkt.flags & CHUNK_START))
 +            goto next_non_null;
 +
          if (compare(s, &s->packet_buffer_end->pkt, pkt)) {
 -            while (!compare(s, &(*next_point)->pkt, pkt))
 +            while (   *next_point
 +                   && ((chunked && !((*next_point)->pkt.flags&CHUNK_START))
 +                       || !compare(s, &(*next_point)->pkt, pkt)))
                  next_point = &(*next_point)->next;
 -            goto next_non_null;
 +            if (*next_point)
 +                goto next_non_null;
          } else {
              next_point = &(s->packet_buffer_end->next);
          }
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 37ba0cb,0000000..2af0450
mode 100644,000000..100644
--- /dev/null
@@@ -1,230 -1,0 +1,231 @@@
-         sub->destruct = NULL;
 +/*
 + * Copyright (c) 2012 Clément Bœsch
 + *
 + * This file is part of FFmpeg.
 + *
 + * 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.
 + *
 + * 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 FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +#include "avformat.h"
 +#include "subtitles.h"
++#include "libavutil/avassert.h"
 +#include "libavutil/avstring.h"
 +
 +AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q,
 +                                    const uint8_t *event, int len, int merge)
 +{
 +    AVPacket *subs, *sub;
 +
 +    if (merge && q->nb_subs > 0) {
 +        /* merge with previous event */
 +
 +        int old_len;
 +        sub = &q->subs[q->nb_subs - 1];
 +        old_len = sub->size;
 +        if (av_grow_packet(sub, len) < 0)
 +            return NULL;
 +        memcpy(sub->data + old_len, event, len);
 +    } else {
 +        /* new event */
 +
 +        if (q->nb_subs >= INT_MAX/sizeof(*q->subs) - 1)
 +            return NULL;
 +        subs = av_fast_realloc(q->subs, &q->allocated_size,
 +                               (q->nb_subs + 1) * sizeof(*q->subs));
 +        if (!subs)
 +            return NULL;
 +        q->subs = subs;
 +        sub = &subs[q->nb_subs++];
 +        if (av_new_packet(sub, len) < 0)
 +            return NULL;
-     *pkt = *sub;
 +        sub->flags |= AV_PKT_FLAG_KEY;
 +        sub->pts = sub->dts = 0;
 +        memcpy(sub->data, event, len);
 +    }
 +    return sub;
 +}
 +
 +static int cmp_pkt_sub(const void *a, const void *b)
 +{
 +    const AVPacket *s1 = a;
 +    const AVPacket *s2 = b;
 +    if (s1->pts == s2->pts) {
 +        if (s1->pos == s2->pos)
 +            return 0;
 +        return s1->pos > s2->pos ? 1 : -1;
 +    }
 +    return s1->pts > s2->pts ? 1 : -1;
 +}
 +
 +void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q)
 +{
 +    int i;
 +
 +    qsort(q->subs, q->nb_subs, sizeof(*q->subs), cmp_pkt_sub);
 +    for (i = 0; i < q->nb_subs; i++)
 +        if (q->subs[i].duration == -1 && i < q->nb_subs - 1)
 +            q->subs[i].duration = q->subs[i + 1].pts - q->subs[i].pts;
 +}
 +
 +int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt)
 +{
 +    AVPacket *sub = q->subs + q->current_sub_idx;
 +
 +    if (q->current_sub_idx == q->nb_subs)
 +        return AVERROR_EOF;
-         av_destruct_packet(&q->subs[i]);
++    av_copy_packet(pkt, sub);
++
 +    pkt->dts = pkt->pts;
 +    q->current_sub_idx++;
 +    return 0;
 +}
 +
 +int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int stream_index,
 +                            int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
 +{
 +    if (flags & AVSEEK_FLAG_BYTE) {
 +        return AVERROR(ENOSYS);
 +    } else if (flags & AVSEEK_FLAG_FRAME) {
 +        if (ts < 0 || ts >= q->nb_subs)
 +            return AVERROR(ERANGE);
 +        q->current_sub_idx = ts;
 +    } else {
 +        int i, idx = -1;
 +        int64_t min_ts_diff = INT64_MAX;
 +        int64_t ts_selected;
 +        /* TODO: q->subs[] is sorted by pts so we could do a binary search */
 +        for (i = 0; i < q->nb_subs; i++) {
 +            int64_t pts = q->subs[i].pts;
 +            uint64_t ts_diff = FFABS(pts - ts);
 +            if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) {
 +                min_ts_diff = ts_diff;
 +                idx = i;
 +            }
 +        }
 +        if (idx < 0)
 +            return AVERROR(ERANGE);
 +        /* look back in the latest subtitles for overlapping subtitles */
 +        ts_selected = q->subs[idx].pts;
 +        for (i = idx - 1; i >= 0; i--) {
 +            if (q->subs[i].duration <= 0)
 +                continue;
 +            if (q->subs[i].pts > ts_selected - q->subs[i].duration)
 +                idx = i;
 +            else
 +                break;
 +        }
 +        q->current_sub_idx = idx;
 +    }
 +    return 0;
 +}
 +
 +void ff_subtitles_queue_clean(FFDemuxSubtitlesQueue *q)
 +{
 +    int i;
 +
 +    for (i = 0; i < q->nb_subs; i++)
++        av_free_packet(&q->subs[i]);
 +    av_freep(&q->subs);
 +    q->nb_subs = q->allocated_size = q->current_sub_idx = 0;
 +}
 +
 +int ff_smil_extract_next_chunk(AVIOContext *pb, AVBPrint *buf, char *c)
 +{
 +    int i = 0;
 +    char end_chr;
 +
 +    if (!*c) // cached char?
 +        *c = avio_r8(pb);
 +    if (!*c)
 +        return 0;
 +
 +    end_chr = *c == '<' ? '>' : '<';
 +    do {
 +        av_bprint_chars(buf, *c, 1);
 +        *c = avio_r8(pb);
 +        i++;
 +    } while (*c != end_chr && *c);
 +    if (end_chr == '>') {
 +        av_bprint_chars(buf, '>', 1);
 +        *c = 0;
 +    }
 +    return i;
 +}
 +
 +const char *ff_smil_get_attr_ptr(const char *s, const char *attr)
 +{
 +    int in_quotes = 0;
 +    const int len = strlen(attr);
 +
 +    while (*s) {
 +        while (*s) {
 +            if (!in_quotes && av_isspace(*s))
 +                break;
 +            in_quotes ^= *s == '"'; // XXX: support escaping?
 +            s++;
 +        }
 +        while (av_isspace(*s))
 +            s++;
 +        if (!av_strncasecmp(s, attr, len) && s[len] == '=')
 +            return s + len + 1 + (s[len + 1] == '"');
 +    }
 +    return NULL;
 +}
 +
 +static inline int is_eol(char c)
 +{
 +    return c == '\r' || c == '\n';
 +}
 +
 +void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf)
 +{
 +    char eol_buf[5];
 +    int n = 0, i = 0, nb_eol = 0;
 +
 +    av_bprint_clear(buf);
 +
 +    for (;;) {
 +        char c = avio_r8(pb);
 +
 +        if (!c)
 +            break;
 +
 +        /* ignore all initial line breaks */
 +        if (n == 0 && is_eol(c))
 +            continue;
 +
 +        /* line break buffering: we don't want to add the trailing \r\n */
 +        if (is_eol(c)) {
 +            nb_eol += c == '\n';
 +            if (nb_eol == 2)
 +                break;
 +            eol_buf[i++] = c;
 +            if (i == sizeof(eol_buf) - 1)
 +                break;
 +            continue;
 +        }
 +
 +        /* only one line break followed by data: we flush the line breaks
 +         * buffer */
 +        if (i) {
 +            eol_buf[i] = 0;
 +            av_bprintf(buf, "%s", eol_buf);
 +            i = nb_eol = 0;
 +        }
 +
 +        av_bprint_chars(buf, c, 1);
 +        n++;
 +    }
 +}
@@@ -555,7 -464,7 +555,7 @@@ static AVPacket *add_to_pktbuf(AVPacket
      return &pktl->pkt;
  }
  
- void avformat_queue_attached_pictures(AVFormatContext *s)
 -static int queue_attached_pictures(AVFormatContext *s)
++int avformat_queue_attached_pictures(AVFormatContext *s)
  {
      int i;
      for (i = 0; i < s->nb_streams; i++)
@@@ -626,18 -534,15 +630,19 @@@ int avformat_open_input(AVFormatContex
          if ((ret = s->iformat->read_header(s)) < 0)
              goto fail;
  
 -    if (id3v2_extra_meta &&
 -        (ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
 -        goto fail;
 +    if (id3v2_extra_meta) {
 +        if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac")) {
 +            if((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
 +                goto fail;
 +        } else
 +            av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n");
 +    }
      ff_id3v2_free_extra_meta(&id3v2_extra_meta);
  
-     avformat_queue_attached_pictures(s);
 -    if ((ret = queue_attached_pictures(s)) < 0)
++    if ((ret = avformat_queue_attached_pictures(s)) < 0)
+         goto fail;
  
 -    if (s->pb && !s->data_offset)
 +    if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
          s->data_offset = avio_tell(s->pb);
  
      s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
@@@ -1327,14 -1069,22 +1332,18 @@@ static int parse_packet(AVFormatContex
               st->parser->pict_type == AV_PICTURE_TYPE_I))
              out_pkt.flags |= AV_PKT_FLAG_KEY;
  
 -        compute_pkt_fields(s, st, st->parser, &out_pkt);
 +        if(st->parser->key_frame == -1 && st->parser->pict_type==AV_PICTURE_TYPE_NONE && (pkt->flags&AV_PKT_FLAG_KEY))
 +            out_pkt.flags |= AV_PKT_FLAG_KEY;
  
 -        if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&
 -            out_pkt.flags & AV_PKT_FLAG_KEY) {
 -            ff_reduce_index(s, st->index);
 -            av_add_index_entry(st, st->parser->frame_offset, out_pkt.dts,
 -                               0, 0, AVINDEX_KEYFRAME);
 -        }
 +        compute_pkt_fields(s, st, st->parser, &out_pkt);
  
          if (out_pkt.data == pkt->data && out_pkt.size == pkt->size) {
+             out_pkt.buf   = pkt->buf;
+             pkt->buf      = NULL;
+ #if FF_API_DESTRUCT_PACKET
              out_pkt.destruct = pkt->destruct;
              pkt->destruct = NULL;
+ #endif
          }
          if ((ret = av_dup_packet(&out_pkt)) < 0)
              goto fail;
@@@ -2085,7 -1744,7 +2094,7 @@@ int av_seek_frame(AVFormatContext *s, i
      int ret = seek_frame_internal(s, stream_index, timestamp, flags);
  
      if (ret >= 0)
-         avformat_queue_attached_pictures(s);
 -        ret = queue_attached_pictures(s);
++        ret = avformat_queue_attached_pictures(s);
  
      return ret;
  }
@@@ -2116,7 -1760,7 +2125,7 @@@ int avformat_seek_file(AVFormatContext 
          ret = s->iformat->read_seek2(s, stream_index, min_ts, ts, max_ts, flags);
  
          if (ret >= 0)
-             avformat_queue_attached_pictures(s);
 -            ret = queue_attached_pictures(s);
++            ret = avformat_queue_attached_pictures(s);
          return ret;
      }