[009/250] avpacket: use AVBuffer to allow refcounting the packets.

Message ID 1354401337-7312-10-git-send-email-anton@khirnov.net
State RFC
Headers show

Commit Message

Anton Khirnov Dec. 1, 2012, 10:31 p.m.
This will allow us to avoid copying the packets in many cases.

This breaks ABI.
---
 libavcodec/avcodec.h      |   40 +++++++++++++--
 libavcodec/avpacket.c     |  120 +++++++++++++++++++++++++++++++++++----------
 libavcodec/utils.c        |   22 ++++++---
 libavcodec/version.h      |    3 ++
 libavformat/asfdec.c      |   15 ++++--
 libavformat/avformat.h    |   14 +++---
 libavformat/avidec.c      |    8 +++
 libavformat/flacdec.c     |   13 ++---
 libavformat/id3v2.c       |   16 +++---
 libavformat/id3v2.h       |    3 +-
 libavformat/matroskadec.c |   14 +++---
 libavformat/matroskaenc.c |   28 +++--------
 libavformat/mp3enc.c      |    6 ++-
 libavformat/mpegts.c      |   18 ++++---
 libavformat/mux.c         |    3 ++
 libavformat/mxg.c         |    6 +++
 libavformat/psxstr.c      |    4 ++
 libavformat/rmdec.c       |    4 ++
 libavformat/rtpdec.c      |    7 ++-
 libavformat/rtpdec_qt.c   |    7 ++-
 libavformat/utils.c       |   19 +++++--
 21 files changed, 259 insertions(+), 111 deletions(-)

Patch

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 5e358ca..298d6b0 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -34,6 +34,7 @@ 
 #include "libavutil/log.h"
 #include "libavutil/pixfmt.h"
 #include "libavutil/rational.h"
+#include "libavutil/buffer.h"
 
 #include "libavcodec/version.h"
 /**
@@ -884,18 +885,25 @@  enum AVPacketSideDataType {
  * ABI. Thus it may be allocated on stack and no new fields can be added to it
  * without libavcodec and libavformat major bump.
  *
- * The semantics of data ownership depends on the destruct field.
- * If it is set, the packet data is dynamically allocated and is valid
+ * The semantics of data ownership depends on the buf or destruct (deprecated)
+ * fields. If either is set, the packet data is dynamically allocated and is valid
  * indefinitely until av_free_packet() is called (which in turn calls the
- * destruct callback to free the data). If destruct is not set, the packet data
- * is typically backed by some static buffer somewhere and is only valid for a
- * limited time (e.g. until the next read call when demuxing).
+ * av_buffer_unref()/the destruct callback to free the data). If neither is set
+ * set, the packet data is typically backed by some static buffer somewhere and
+ * is only valid for a limited time (e.g. until the next read call when
+ * demuxing).
  *
  * The side data is always allocated with av_malloc() and is freed in
  * av_free_packet().
  */
 typedef struct AVPacket {
     /**
+     * A reference to the reference counted buffer where the packet data is
+     * stored.
+     * May be NULL, then the packet data is not reference counted.
+     */
+    AVBufferRef *buf;
+    /**
      * Presentation timestamp in AVStream->time_base units; the time at which
      * the decompressed packet will be presented to the user.
      * Can be AV_NOPTS_VALUE if it is not stored in the file.
@@ -934,8 +942,12 @@  typedef struct AVPacket {
      * Equals next_pts - this_pts in presentation order.
      */
     int   duration;
+#if FF_API_DESTRUCT_PACKET
+    attribute_deprecated
     void  (*destruct)(struct AVPacket *);
+    attribute_deprecated
     void  *priv;
+#endif
     int64_t pos;                            ///< byte position in stream, -1 if unknown
 
     /**
@@ -3393,10 +3405,14 @@  void avsubtitle_free(AVSubtitle *sub);
  * @{
  */
 
+#if FF_API_DESTRUCT_PACKET
 /**
  * Default packet destructor.
+ * @deprecated use the AVBuffer API instead
  */
+attribute_deprecated
 void av_destruct_packet(AVPacket *pkt);
+#endif
 
 /**
  * Initialize optional fields of a packet with default values.
@@ -3435,6 +3451,20 @@  void av_shrink_packet(AVPacket *pkt, int size);
 int av_grow_packet(AVPacket *pkt, int grow_by);
 
 /**
+ * Initialize a reference counted packet from av_malloc()ed data.
+ *
+ * @param pkt packet to be initialized. This function will set the data, size,
+ * buf and destruct fields, all other are left untouched.
+ * @param data data allocated by av_malloc() to be used as packet data. If this
+ * function returns successfully, the data is owned by the underlying AVBuffer.
+ * The caller may not access the data through other means.
+ * @param size size of data in bytes. This includes the required
+ * FF_INPUT_BUFFER_PADDING_SIZE padding, so actual usable packet size will be
+ * size - FF_INPUT_BUFFER_PADDING_SIZE.
+ */
+int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size);
+
+/**
  * @warning This is a hack - the packet memory allocation stuff is broken. The
  * packet is allocated if it was not really allocated.
  */
diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
index c26fb8e..103697b 100644
--- a/libavcodec/avpacket.c
+++ b/libavcodec/avpacket.c
@@ -22,9 +22,11 @@ 
 #include <string.h>
 
 #include "libavutil/avassert.h"
+#include "libavutil/common.h"
 #include "libavutil/mem.h"
 #include "avcodec.h"
 
+#if FF_API_DESTRUCT_PACKET
 void av_destruct_packet(AVPacket *pkt)
 {
     av_free(pkt->data);
@@ -32,6 +34,14 @@  void av_destruct_packet(AVPacket *pkt)
     pkt->size = 0;
 }
 
+/* a dummy destruct callback for the callers that assume AVPacket.destruct ==
+ * NULL => static data */
+static void dummy_destruct_packet(AVPacket *pkt)
+{
+    av_assert0(0);
+}
+#endif
+
 void av_init_packet(AVPacket *pkt)
 {
     pkt->pts                  = AV_NOPTS_VALUE;
@@ -41,27 +51,35 @@  void av_init_packet(AVPacket *pkt)
     pkt->convergence_duration = 0;
     pkt->flags                = 0;
     pkt->stream_index         = 0;
+#if FF_API_DESTRUCT_PACKET
     pkt->destruct             = NULL;
+#endif
+    pkt->buf                  = NULL;
     pkt->side_data            = NULL;
     pkt->side_data_elems      = 0;
 }
 
 int av_new_packet(AVPacket *pkt, int size)
 {
-    uint8_t *data = NULL;
-    if ((unsigned)size < (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE)
-        data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
-    if (data) {
-        memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
-    } else
-        size = 0;
+    AVBufferRef *buf = NULL;
+
+    if ((unsigned)size >= (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE)
+        return AVERROR(EINVAL);
+
+    buf = av_buffer_alloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+    if (!buf)
+        return AVERROR(ENOMEM);
+
+    memset(buf->data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
 
     av_init_packet(pkt);
-    pkt->data     = data;
+    pkt->buf      = buf;
+    pkt->data     = buf->data;
     pkt->size     = size;
-    pkt->destruct = av_destruct_packet;
-    if (!data)
-        return AVERROR(ENOMEM);
+#if FF_API_DESTRUCT_PACKET
+    pkt->destruct = dummy_destruct_packet;
+#endif
+
     return 0;
 }
 
@@ -75,33 +93,70 @@  void av_shrink_packet(AVPacket *pkt, int size)
 
 int av_grow_packet(AVPacket *pkt, int grow_by)
 {
-    void *new_ptr;
+    int new_size;
     av_assert0((unsigned)pkt->size <= INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE);
     if (!pkt->size)
         return av_new_packet(pkt, grow_by);
     if ((unsigned)grow_by >
         INT_MAX - (pkt->size + FF_INPUT_BUFFER_PADDING_SIZE))
         return -1;
-    new_ptr = av_realloc(pkt->data,
-                         pkt->size + grow_by + FF_INPUT_BUFFER_PADDING_SIZE);
-    if (!new_ptr)
-        return AVERROR(ENOMEM);
-    pkt->data  = new_ptr;
+
+    new_size = pkt->size + grow_by + FF_INPUT_BUFFER_PADDING_SIZE;
+    if (pkt->buf) {
+        av_buffer_realloc(&pkt->buf, new_size);
+        if (!pkt->buf)
+            return AVERROR(ENOMEM);
+    } else {
+        pkt->buf = av_buffer_alloc(new_size);
+        if (!pkt->buf)
+            return AVERROR(ENOMEM);
+        memcpy(pkt->buf->data, pkt->data, FFMIN(pkt->size, pkt->size + grow_by));
+#if FF_API_DESTRUCT_PACKET
+        pkt->destruct = dummy_destruct_packet;
+#endif
+    }
+    pkt->data  = pkt->buf->data;
     pkt->size += grow_by;
     memset(pkt->data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+
     return 0;
 }
 
-#define DUP_DATA(dst, src, size, padding)                               \
+int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
+{
+    if (size < FF_INPUT_BUFFER_PADDING_SIZE)
+        return AVERROR(EINVAL);
+
+    pkt->buf = av_buffer_create(data, size, av_buffer_default_free, NULL);
+    if (!pkt->buf)
+        return AVERROR(ENOMEM);
+
+    pkt->data = data;
+    pkt->size = size - FF_INPUT_BUFFER_PADDING_SIZE;
+#if FF_API_DESTRUCT_PACKET
+    pkt->destruct = dummy_destruct_packet;
+#endif
+
+    return 0;
+}
+
+#define ALLOC_MALLOC(data, size) data = av_malloc(size)
+#define ALLOC_BUF(data, size)                \
+do {                                         \
+    pkt->buf = av_buffer_alloc(size);        \
+    data = pkt->buf ? pkt->buf->data : NULL; \
+} while (0)
+
+#define DUP_DATA(dst, src, size, padding, ALLOC)                        \
     do {                                                                \
         void *data;                                                     \
         if (padding) {                                                  \
             if ((unsigned)(size) >                                      \
                 (unsigned)(size) + FF_INPUT_BUFFER_PADDING_SIZE)        \
                 goto failed_alloc;                                      \
-            data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);      \
+            ALLOC(data, size + FF_INPUT_BUFFER_PADDING_SIZE);           \
         } else {                                                        \
-            data = av_malloc(size);                                     \
+            ALLOC(data, size);                                          \
         }                                                               \
         if (!data)                                                      \
             goto failed_alloc;                                          \
@@ -116,30 +171,36 @@  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);
-        pkt->destruct = av_destruct_packet;
+        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);
+                     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);
+                         tmp_pkt.side_data[i].size, 1, ALLOC_MALLOC);
         }
     }
     return 0;
 
 failed_alloc:
-    av_destruct_packet(pkt);
+    av_free_packet(pkt);
     return AVERROR(ENOMEM);
 }
 
@@ -148,8 +209,13 @@  void av_free_packet(AVPacket *pkt)
     if (pkt) {
         int i;
 
-        if (pkt->destruct)
+        if (pkt->buf)
+            av_buffer_unref(&pkt->buf);
+#if FF_API_DESTRUCT_PACKET
+        else if (pkt->destruct)
             pkt->destruct(pkt);
+        pkt->destruct = NULL;
+#endif
         pkt->data            = NULL;
         pkt->size            = 0;
 
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 1185a35..21a2ced 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -878,13 +878,19 @@  int ff_alloc_packet(AVPacket *avpkt, int size)
         return AVERROR(EINVAL);
 
     if (avpkt->data) {
+        AVBufferRef *buf = avpkt->buf;
+#if FF_API_DESTRUCT_PACKET
         void *destruct = avpkt->destruct;
+#endif
 
         if (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 {
@@ -1011,9 +1017,12 @@  int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
         }
 
         if (!user_packet && avpkt->size) {
-            uint8_t *new_data = av_realloc(avpkt->data, avpkt->size);
-            if (new_data)
-                avpkt->data = new_data;
+            av_buffer_realloc(&avpkt->buf, avpkt->size);
+            if (!avpkt->buf) {
+                ret = AVERROR(ENOMEM);
+                goto end;
+            }
+            avpkt->data = avpkt->buf->data;
         }
 
         avctx->frame_number++;
@@ -1188,9 +1197,10 @@  int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx,
             avpkt->pts = avpkt->dts = frame->pts;
 
         if (!user_packet && avpkt->size) {
-            uint8_t *new_data = av_realloc(avpkt->data, avpkt->size);
-            if (new_data)
-                avpkt->data = new_data;
+            av_buffer_realloc(&avpkt->buf, avpkt->size);
+            if (!avpkt->buf)
+                return AVERROR(ENOMEM);
+            avpkt->data = avpkt->buf->data;
         }
 
         avctx->frame_number++;
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 45ff507..6117a22 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -91,5 +91,8 @@ 
 #ifndef FF_API_MMI
 #define FF_API_MMI               (LIBAVCODEC_VERSION_MAJOR < 55)
 #endif
+#ifndef FF_API_DESTRUCT_PACKET
+#define FF_API_DESTRUCT_PACKET   (LIBAVCODEC_VERSION_MAJOR < 56)
+#endif
 
 #endif /* AVCODEC_VERSION_H */
diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c
index c6b322d..daa791e 100644
--- a/libavformat/asfdec.c
+++ b/libavformat/asfdec.c
@@ -1162,8 +1162,10 @@  static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk
                            asf_st->ds_packet_size, asf_st->ds_span);
                 } else {
                     /* packet descrambling */
-                    uint8_t *newdata = av_malloc(asf_st->pkt.size + FF_INPUT_BUFFER_PADDING_SIZE);
-                    if (newdata) {
+                    AVBufferRef *buf = av_buffer_alloc(asf_st->pkt.size +
+                                                       FF_INPUT_BUFFER_PADDING_SIZE);
+                    if (buf) {
+                        uint8_t *newdata = buf->data;
                         int offset = 0;
                         memset(newdata + asf_st->pkt.size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
                         while (offset < asf_st->pkt.size) {
@@ -1178,13 +1180,18 @@  static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk
                                    asf_st->ds_chunk_size);
                             offset += asf_st->ds_chunk_size;
                         }
-                        av_free(asf_st->pkt.data);
-                        asf_st->pkt.data = newdata;
+                        av_buffer_unref(&asf_st->pkt.buf);
+                        asf_st->pkt.buf  = buf;
+                        asf_st->pkt.data = buf->data;
                     }
                 }
             }
             asf_st->frag_offset         = 0;
             *pkt                        = asf_st->pkt;
+#if FF_API_DESTRUCT_PACKET
+            asf_st->pkt.destruct        = NULL;
+#endif
+            asf_st->pkt.buf             = 0;
             asf_st->pkt.size            = 0;
             asf_st->pkt.data            = 0;
             asf_st->pkt.side_data_elems = 0;
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 51635c4..093d10c 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -158,9 +158,9 @@ 
  * information will be in AVStream.time_base units, i.e. it has to be
  * multiplied by the timebase to convert them to seconds.
  *
- * If AVPacket.destruct is set on the returned packet, then the packet is
+ * If AVPacket.buf is set on the returned packet, then the packet is
  * allocated dynamically and the user may keep it indefinitely.
- * Otherwise, if AVPacket.destruct is NULL, the packet data is backed by a
+ * Otherwise, if AVPacket.buf is NULL, the packet data is backed by a
  * static storage somewhere inside the demuxer and the packet is only valid
  * until the next av_read_frame() call or closing the file. If the caller
  * requires a longer lifetime, av_dup_packet() will make an av_malloc()ed copy
@@ -1313,7 +1313,7 @@  int av_read_packet(AVFormatContext *s, AVPacket *pkt);
  * omit invalid data between valid frames so as to give the decoder the maximum
  * information possible for decoding.
  *
- * If pkt->destruct is NULL, then the packet is valid until the next
+ * If pkt->buf is NULL, then the packet is valid until the next
  * av_read_frame() or until av_close_input_file(). Otherwise the packet is valid
  * indefinitely. In both cases the packet must be freed with
  * av_free_packet when it is no longer needed. For video, the packet contains
@@ -1461,10 +1461,10 @@  int av_write_frame(AVFormatContext *s, AVPacket *pkt);
  * demuxer level.
  *
  * @param s media file handle
- * @param pkt The packet containing the data to be written. Libavformat takes
- * ownership of the data and will free it when it sees fit using the packet's
- * @ref AVPacket.destruct "destruct" field. The caller must not access the data
- * after this function returns, as it may already be freed.
+ * @param pkt The packet containing the data to be written. pkt->buf must be set
+ * to a valid AVBufferRef describing the packet data. Libavformat takes
+ * ownership of this reference and will unref it when it see fit. The caller
+ * must not access the data through this reference after this function returns.
  * This can be NULL (at any time, not just at the end), to flush the
  * interleaving queues.
  * Packet's @ref AVPacket.stream_index "stream_index" field must be set to the
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index a3af5cf..341ff25 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -977,7 +977,9 @@  static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
     AVIContext *avi = s->priv_data;
     AVIOContext *pb = s->pb;
     int err;
+#if FF_API_DESTRUCT_PACKET
     void* dstr;
+#endif
 
     if (CONFIG_DV_DEMUXER && avi->dv_demux) {
         int size = avpriv_dv_get_packet(avi->dv_demux, pkt);
@@ -1078,10 +1080,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);
+#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);
diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c
index f19f95d..7aaec9e 100644
--- a/libavformat/flacdec.c
+++ b/libavformat/flacdec.c
@@ -32,7 +32,8 @@  static int parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
 {
     const CodecMime *mime = ff_id3v2_mime_tags;
     enum  AVCodecID      id = AV_CODEC_ID_NONE;
-    uint8_t mimetype[64], *desc = NULL, *data = NULL;
+    AVBufferRef *data = NULL;
+    uint8_t mimetype[64], *desc = NULL;
     AVIOContext *pb = NULL;
     AVStream *st;
     int type, width, height;
@@ -110,11 +111,11 @@  static int parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
             ret = AVERROR_INVALIDDATA;
         goto fail;
     }
-    if (!(data = av_malloc(len))) {
+    if (!(data = av_buffer_alloc(len))) {
         ret = AVERROR(ENOMEM);
         goto fail;
     }
-    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);
@@ -128,9 +129,9 @@  static int parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
     }
 
     av_init_packet(&st->attached_pic);
-    st->attached_pic.data         = data;
+    st->attached_pic.buf          = data;
+    st->attached_pic.data         = data->data;
     st->attached_pic.size         = len;
-    st->attached_pic.destruct     = av_destruct_packet;
     st->attached_pic.stream_index = st->index;
     st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
 
@@ -148,8 +149,8 @@  static int parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
     return 0;
 
 fail:
+    av_buffer_unref(&data);
     av_freep(&desc);
-    av_freep(&data);
     av_freep(&pb);
     return ret;
 
diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 4516ac7..80c2e88 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -420,7 +420,7 @@  finish:
 static void free_apic(void *obj)
 {
     ID3v2ExtraMetaAPIC *apic = obj;
-    av_freep(&apic->data);
+    av_buffer_unref(&apic->buf);
     av_freep(&apic->description);
     av_freep(&apic);
 }
@@ -476,9 +476,8 @@  static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag
         goto fail;
     }
 
-    apic->len   = taglen;
-    apic->data  = av_malloc(taglen);
-    if (!apic->data || avio_read(pb, apic->data, taglen) != taglen)
+    apic->buf   = av_buffer_alloc(taglen);
+    if (!apic->buf || avio_read(pb, apic->buf->data, taglen) != taglen)
         goto fail;
 
     new_extra->tag    = "APIC";
@@ -734,14 +733,13 @@  int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta)
         av_dict_set(&st->metadata, "comment", apic->type, 0);
 
         av_init_packet(&st->attached_pic);
-        st->attached_pic.data         = apic->data;
-        st->attached_pic.size         = apic->len;
-        st->attached_pic.destruct     = av_destruct_packet;
+        st->attached_pic.buf          = apic->buf;
+        st->attached_pic.data         = apic->buf->data;
+        st->attached_pic.size         = apic->buf->size;
         st->attached_pic.stream_index = st->index;
         st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
 
-        apic->data = NULL;
-        apic->len  = 0;
+        apic->buf = NULL;
     }
 
     return 0;
diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h
index cb2fb02..7cb4296 100644
--- a/libavformat/id3v2.h
+++ b/libavformat/id3v2.h
@@ -67,8 +67,7 @@  typedef struct ID3v2ExtraMetaGEOB {
 } ID3v2ExtraMetaGEOB;
 
 typedef struct ID3v2ExtraMetaAPIC {
-    uint8_t     *data;
-    int          len;
+    AVBufferRef *buf;
     const char  *type;
     uint8_t     *description;
     enum AVCodecID id;
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index bf67253..58698b1 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -1107,7 +1107,8 @@  static int matroska_decode_buffer(uint8_t** buf, int* buf_size,
 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;
@@ -1125,13 +1126,14 @@  static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
         es = ec/   100;  ec -=    100*es;
         *ptr++ = '\0';
         len = 50 + end-ptr + FF_INPUT_BUFFER_PADDING_SIZE;
-        if (!(line = av_malloc(len)))
+        if (!(line = av_buffer_alloc(len)))
             return;
-        snprintf(line,len,"Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n",
+        snprintf(line->data, len,"Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n",
                  layer, sh, sm, ss, sc, eh, em, es, ec, ptr);
-        av_free(pkt->data);
-        pkt->data = line;
-        pkt->size = strlen(line);
+        av_buffer_unref(&pkt->buf);
+        pkt->buf  = line;
+        pkt->data = line->data;
+        pkt->size = strlen(line->data);
     }
 }
 
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index b37d10c..b1e4a1e 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -90,7 +90,6 @@  typedef struct MatroskaMuxContext {
     mkv_cues        *cues;
     mkv_track       *tracks;
 
-    unsigned int    audio_buffer_size;
     AVPacket        cur_audio_pkt;
 
     int have_attachments;
@@ -969,7 +968,6 @@  static int mkv_write_header(AVFormatContext *s)
 
     av_init_packet(&mkv->cur_audio_pkt);
     mkv->cur_audio_pkt.size = 0;
-    mkv->audio_buffer_size  = 0;
 
     avio_flush(pb);
     return 0;
@@ -1180,19 +1178,6 @@  static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
     return 0;
 }
 
-static int mkv_copy_packet(MatroskaMuxContext *mkv, const AVPacket *pkt)
-{
-    uint8_t *data           = mkv->cur_audio_pkt.data;
-    mkv->cur_audio_pkt      = *pkt;
-    mkv->cur_audio_pkt.data = av_fast_realloc(data, &mkv->audio_buffer_size, pkt->size);
-    if (!mkv->cur_audio_pkt.data)
-        return AVERROR(ENOMEM);
-
-    memcpy(mkv->cur_audio_pkt.data, pkt->data, pkt->size);
-    mkv->cur_audio_pkt.size = pkt->size;
-    return 0;
-}
-
 static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     MatroskaMuxContext *mkv = s->priv_data;
@@ -1219,7 +1204,7 @@  static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
     // check if we have an audio packet cached
     if (mkv->cur_audio_pkt.size > 0) {
         ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt);
-        mkv->cur_audio_pkt.size = 0;
+        av_free_packet(&mkv->cur_audio_pkt);
         if (ret < 0) {
             av_log(s, AV_LOG_ERROR, "Could not write cached audio packet ret:%d\n", ret);
             return ret;
@@ -1228,9 +1213,11 @@  static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
 
     // buffer an audio packet to ensure the packet containing the video
     // keyframe's timecode is contained in the same cluster for WebM
-    if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
-        ret = mkv_copy_packet(mkv, pkt);
-    else
+    if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+        mkv->cur_audio_pkt = *pkt;
+        mkv->cur_audio_pkt.buf = av_buffer_ref(pkt->buf);
+        ret = mkv->cur_audio_pkt.buf ? 0 : AVERROR(ENOMEM);
+    } else
         ret = mkv_write_packet_internal(s, pkt);
     return ret;
 }
@@ -1245,7 +1232,7 @@  static int mkv_write_trailer(AVFormatContext *s)
     // check if we have an audio packet cached
     if (mkv->cur_audio_pkt.size > 0) {
         ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt);
-        mkv->cur_audio_pkt.size = 0;
+        av_free_packet(&mkv->cur_audio_pkt);
         if (ret < 0) {
             av_log(s, AV_LOG_ERROR, "Could not write cached audio packet ret:%d\n", ret);
             return ret;
@@ -1282,7 +1269,6 @@  static int mkv_write_trailer(AVFormatContext *s)
     av_free(mkv->tracks);
     av_freep(&mkv->cues->entries);
     av_freep(&mkv->cues);
-    av_destruct_packet(&mkv->cur_audio_pkt);
 
     return 0;
 }
diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c
index c969777..4d7c798 100644
--- a/libavformat/mp3enc.c
+++ b/libavformat/mp3enc.c
@@ -343,7 +343,11 @@  static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt)
                 return AVERROR(ENOMEM);
 
             pktl->pkt     = *pkt;
-            pkt->destruct = NULL;
+            pktl->pkt.buf = av_buffer_ref(pkt->buf);
+            if (!pktl->pkt.buf) {
+                av_freep(&pktl);
+                return AVERROR(ENOMEM);
+            }
 
             if (mp3->queue_end)
                 mp3->queue_end->next = pktl;
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 4aabcd7..e4add03 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -19,6 +19,7 @@ 
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/buffer.h"
 #include "libavutil/crc.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/log.h"
@@ -173,7 +174,7 @@  typedef struct PESContext {
     int64_t pts, dts;
     int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */
     uint8_t header[MAX_PES_HEADER_SIZE];
-    uint8_t *buffer;
+    AVBufferRef *buffer;
     SLConfigDescr sl;
 } PESContext;
 
@@ -364,7 +365,7 @@  static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter)
         av_freep(&filter->u.section_filter.section_buf);
     else if (filter->type == MPEGTS_PES) {
         PESContext *pes = filter->u.pes_filter.opaque;
-        av_freep(&pes->buffer);
+        av_buffer_unref(&pes->buffer);
         /* referenced private data will be freed later in
          * avformat_close_input */
         if (!((PESContext *)filter->u.pes_filter.opaque)->st) {
@@ -635,8 +636,8 @@  static void new_pes_packet(PESContext *pes, AVPacket *pkt)
 {
     av_init_packet(pkt);
 
-    pkt->destruct = av_destruct_packet;
-    pkt->data = pes->buffer;
+    pkt->buf  = pes->buffer;
+    pkt->data = pes->buffer->data;
     pkt->size = pes->data_index;
 
     if(pes->total_size != MAX_PES_PAYLOAD &&
@@ -806,7 +807,8 @@  static int mpegts_push_data(MpegTSFilter *filter,
                         pes->total_size = MAX_PES_PAYLOAD;
 
                     /* allocate pes buffer */
-                    pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE);
+                    pes->buffer = av_buffer_alloc(pes->total_size +
+                                                  FF_INPUT_BUFFER_PADDING_SIZE);
                     if (!pes->buffer)
                         return AVERROR(ENOMEM);
 
@@ -908,7 +910,7 @@  static int mpegts_push_data(MpegTSFilter *filter,
                 if (pes->data_index > 0 && pes->data_index+buf_size > pes->total_size) {
                     new_pes_packet(pes, ts->pkt);
                     pes->total_size = MAX_PES_PAYLOAD;
-                    pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE);
+                    pes->buffer = av_buffer_alloc(pes->total_size + FF_INPUT_BUFFER_PADDING_SIZE);
                     if (!pes->buffer)
                         return AVERROR(ENOMEM);
                     ts->stop_parse = 1;
@@ -917,7 +919,7 @@  static int mpegts_push_data(MpegTSFilter *filter,
                     // not sure if this is legal in ts but see issue #2392
                     buf_size = pes->total_size;
                 }
-                memcpy(pes->buffer+pes->data_index, p, buf_size);
+                memcpy(pes->buffer->data + pes->data_index, p, buf_size);
                 pes->data_index += buf_size;
             }
             buf_size = 0;
@@ -1794,7 +1796,7 @@  static int handle_packets(MpegTSContext *ts, int nb_packets)
             if (ts->pids[i]) {
                 if (ts->pids[i]->type == MPEGTS_PES) {
                    PESContext *pes = ts->pids[i]->u.pes_filter.opaque;
-                   av_freep(&pes->buffer);
+                   av_buffer_unref(&pes->buffer);
                    pes->data_index = 0;
                    pes->state = MPEGTS_SKIP; /* skip until pes header */
                 }
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 96eecb5..d4a0ae5 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -420,7 +420,10 @@  void ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
 
     this_pktl      = av_mallocz(sizeof(AVPacketList));
     this_pktl->pkt = *pkt;
+#if FF_API_DESTRUCT_PACKET
     pkt->destruct  = NULL;           // do not free original but only the copy
+#endif
+    pkt->buf       = NULL;
     av_dup_packet(&this_pktl->pkt);  // duplicate the packet if it uses non-alloced memory
 
     if (s->streams[pkt->stream_index]->last_in_packet_buffer) {
diff --git a/libavformat/mxg.c b/libavformat/mxg.c
index 8959134..ea54fe2 100644
--- a/libavformat/mxg.c
+++ b/libavformat/mxg.c
@@ -168,7 +168,10 @@  static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt)
 
                 pkt->pts = pkt->dts = mxg->dts;
                 pkt->stream_index = 0;
+#if FF_API_DESTRUCT_PACKET
                 pkt->destruct = NULL;
+#endif
+                pkt->buf  = NULL;
                 pkt->size = mxg->buffer_ptr - mxg->soi_ptr;
                 pkt->data = mxg->soi_ptr;
 
@@ -206,7 +209,10 @@  static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt)
                     /* time (GMT) of first sample in usec since 1970, little-endian */
                     pkt->pts = pkt->dts = AV_RL64(startmarker_ptr + 8);
                     pkt->stream_index = 1;
+#if FF_API_DESTRUCT_PACKET
                     pkt->destruct = NULL;
+#endif
+                    pkt->buf  = NULL;
                     pkt->size = size - 14;
                     pkt->data = startmarker_ptr + 16;
 
diff --git a/libavformat/psxstr.c b/libavformat/psxstr.c
index 633d61d..313a1d8 100644
--- a/libavformat/psxstr.c
+++ b/libavformat/psxstr.c
@@ -201,6 +201,10 @@  static int str_read_packet(AVFormatContext *s,
                     *ret_pkt = *pkt;
                     pkt->data= NULL;
                     pkt->size= -1;
+                    pkt->buf = NULL;
+#if FF_API_DESTRUCT_PACKET
+                    pkt->destruct = NULL;
+#endif
                     return 0;
                 }
 
diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c
index 3cf2c97..7746740 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -678,6 +678,10 @@  static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
         *pkt= vst->pkt;
         vst->pkt.data= NULL;
         vst->pkt.size= 0;
+        vst->pkt.buf = NULL;
+#if FF_API_DESTRUCT_PACKET
+        vst->pkt.destruct = NULL;
+#endif
         if(vst->slices != vst->cur_slice) //FIXME find out how to set slices correct from the begin
             memmove(pkt->data + 1 + 8*vst->cur_slice, pkt->data + 1 + 8*vst->slices,
                 vst->videobufpos - 1 - 8*vst->slices);
diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c
index a305dd6..467498d 100644
--- a/libavformat/rtpdec.c
+++ b/libavformat/rtpdec.c
@@ -806,11 +806,14 @@  int ff_parse_fmtp(AVStream *stream, PayloadContext *data, const char *p,
 
 int ff_rtp_finalize_packet(AVPacket *pkt, AVIOContext **dyn_buf, int stream_idx)
 {
+    int ret;
     av_init_packet(pkt);
 
     pkt->size = avio_close_dyn_buf(*dyn_buf, &pkt->data);
     pkt->stream_index = stream_idx;
-    pkt->destruct     = av_destruct_packet;
     *dyn_buf = NULL;
-    return pkt->size;
+    if ((ret = av_packet_from_data(pkt, pkt->data, pkt->size +
+                                   FF_INPUT_BUFFER_PADDING_SIZE)) < 0)
+        av_freep(&pkt->data);
+    return ret;
 }
diff --git a/libavformat/rtpdec_qt.c b/libavformat/rtpdec_qt.c
index 3093132..e330b77 100644
--- a/libavformat/rtpdec_qt.c
+++ b/libavformat/rtpdec_qt.c
@@ -186,12 +186,15 @@  static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt,
         memcpy(qt->pkt.data + qt->pkt.size, buf + avio_tell(&pb), alen);
         qt->pkt.size += alen;
         if (has_marker_bit) {
-            *pkt = qt->pkt;
+            int ret = av_packet_from_data(pkt, qt->pkt.data, qt->pkt.size +
+                                          FF_INPUT_BUFFER_PADDING_SIZE);
+            if (ret < 0)
+                return ret;
+
             qt->pkt.size = 0;
             qt->pkt.data = NULL;
             pkt->flags        = flags & RTP_FLAG_KEY ? AV_PKT_FLAG_KEY : 0;
             pkt->stream_index = st->index;
-            pkt->destruct     = av_destruct_packet;
             memset(pkt->data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
             return 0;
         }
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 12b054d..607387a 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -464,16 +464,20 @@  static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
     return &pktl->pkt;
 }
 
-static void queue_attached_pictures(AVFormatContext *s)
+static int queue_attached_pictures(AVFormatContext *s)
 {
     int i;
     for (i = 0; i < s->nb_streams; i++)
         if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC &&
             s->streams[i]->discard < AVDISCARD_ALL) {
             AVPacket copy = s->streams[i]->attached_pic;
-            copy.destruct = NULL;
+            copy.buf      = av_buffer_ref(copy.buf);
+            if (!copy.buf)
+                return AVERROR(ENOMEM);
+
             add_to_pktbuf(&s->raw_packet_buffer, &copy, &s->raw_packet_buffer_end);
         }
+    return 0;
 }
 
 int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
@@ -535,7 +539,8 @@  int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
         goto fail;
     ff_id3v2_free_extra_meta(&id3v2_extra_meta);
 
-    queue_attached_pictures(s);
+    if ((ret = queue_attached_pictures(s)) < 0)
+        goto fail;
 
     if (s->pb && !s->data_offset)
         s->data_offset = avio_tell(s->pb);
@@ -1074,8 +1079,12 @@  static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
         }
 
         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;
@@ -1735,7 +1744,7 @@  int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int f
     int ret = seek_frame_internal(s, stream_index, timestamp, flags);
 
     if (ret >= 0)
-        queue_attached_pictures(s);
+        ret = queue_attached_pictures(s);
 
     return ret;
 }
@@ -1751,7 +1760,7 @@  int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int
         ret = s->iformat->read_seek2(s, stream_index, min_ts, ts, max_ts, flags);
 
         if (ret >= 0)
-            queue_attached_pictures(s);
+            ret = queue_attached_pictures(s);
         return ret;
     }