diff options
author | Anton Khirnov <anton@khirnov.net> | 2012-10-31 08:53:18 +0100 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2013-03-08 07:33:45 +0100 |
commit | 1afddbe59e96af75f1c07605afc95615569f388f (patch) | |
tree | 0e8223d9813de6976ec50dc1a5a7c7bf9a099450 /libavcodec | |
parent | 1cec0624d0e6f48590283a57169b58b9fe8449d3 (diff) | |
download | ffmpeg-1afddbe59e96af75f1c07605afc95615569f388f.tar.gz |
avpacket: use AVBuffer to allow refcounting the packets.
This will allow us to avoid copying the packets in many cases.
This breaks ABI.
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/avcodec.h | 42 | ||||
-rw-r--r-- | libavcodec/avpacket.c | 121 | ||||
-rw-r--r-- | libavcodec/utils.c | 18 | ||||
-rw-r--r-- | libavcodec/version.h | 3 |
4 files changed, 145 insertions, 39 deletions
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 120bfbcaae..1eba5e51bb 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -29,6 +29,7 @@ #include <errno.h> #include "libavutil/samplefmt.h" #include "libavutil/avutil.h" +#include "libavutil/buffer.h" #include "libavutil/cpu.h" #include "libavutil/dict.h" #include "libavutil/log.h" @@ -892,18 +893,24 @@ 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 - * 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). + * 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 + * av_buffer_unref()/the destruct callback to free the data). If neither is 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. @@ -942,8 +949,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 /** @@ -3413,10 +3424,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. @@ -3455,6 +3470,21 @@ 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 others 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, without the padding. I.e. the full buffer + * size is assumed to be size + FF_INPUT_BUFFER_PADDING_SIZE. + * + * @return 0 on success, a negative AVERROR on error + */ +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 c26fb8e35c..c94f28272a 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); + + av_buffer_realloc(&buf, 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,71 @@ 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) { + int ret = av_buffer_realloc(&pkt->buf, new_size); + if (ret < 0) + return ret; + } 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 >= INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE) + return AVERROR(EINVAL); + + pkt->buf = av_buffer_create(data, size + FF_INPUT_BUFFER_PADDING_SIZE, + av_buffer_default_free, NULL, 0); + if (!pkt->buf) + return AVERROR(ENOMEM); + + pkt->data = data; + pkt->size = 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 { \ + av_buffer_realloc(&pkt->buf, 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 +172,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 +210,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 2a78f7fc0e..091d34c158 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -887,13 +887,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 { @@ -1020,9 +1026,9 @@ 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; + ret = av_buffer_realloc(&avpkt->buf, avpkt->size); + if (ret >= 0) + avpkt->data = avpkt->buf->data; } avctx->frame_number++; @@ -1197,9 +1203,9 @@ 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; + ret = av_buffer_realloc(&avpkt->buf, avpkt->size); + if (ret >= 0) + avpkt->data = avpkt->buf->data; } avctx->frame_number++; diff --git a/libavcodec/version.h b/libavcodec/version.h index 5b65c2d6a0..78fcdbfaae 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -100,5 +100,8 @@ #ifndef FF_API_DEINTERLACE #define FF_API_DEINTERLACE (LIBAVCODEC_VERSION_MAJOR < 56) #endif +#ifndef FF_API_DESTRUCT_PACKET +#define FF_API_DESTRUCT_PACKET (LIBAVCODEC_VERSION_MAJOR < 56) +#endif #endif /* AVCODEC_VERSION_H */ |