diff options
Diffstat (limited to 'demux')
-rw-r--r-- | demux/demux_lavf.c | 23 | ||||
-rw-r--r-- | demux/packet.c | 75 | ||||
-rw-r--r-- | demux/packet.h | 6 |
3 files changed, 39 insertions, 65 deletions
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index d8d177e27e..16a06829d4 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -780,23 +780,16 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) return 0; } -static void destroy_avpacket(void *pkt) -{ - av_free_packet(pkt); -} - static int demux_lavf_fill_buffer(demuxer_t *demux) { lavf_priv_t *priv = demux->priv; - demux_packet_t *dp; - AVPacket *pkt = talloc(NULL, AVPacket); + AVPacket *pkt = &(AVPacket){0}; int r = av_read_frame(priv->avfc, pkt); if (r < 0) { - talloc_free(pkt); + av_free_packet(pkt); return r == AVERROR(EAGAIN) ? 1 : -1; // eof } - talloc_set_destructor(pkt, destroy_avpacket); add_new_streams(demux); update_metadata(demux, pkt); @@ -806,18 +799,11 @@ static int demux_lavf_fill_buffer(demuxer_t *demux) AVStream *st = priv->avfc->streams[pkt->stream_index]; if (!demux_stream_is_selected(stream)) { - talloc_free(pkt); + av_free_packet(pkt); return 1; // don't signal EOF if skipping a packet } - // If the packet has pointers to temporary fields that could be - // overwritten/freed by next av_read_frame(), copy them to persistent - // allocations so we can safely queue the packet for any length of time. - if (av_dup_packet(pkt) < 0) - abort(); - - dp = new_demux_packet_fromdata(pkt->data, pkt->size); - dp->avpacket = talloc_steal(dp, pkt); + struct demux_packet *dp = new_demux_packet_from_avpacket(pkt); if (pkt->pts != AV_NOPTS_VALUE) dp->pts = pkt->pts * av_q2d(st->time_base); @@ -833,6 +819,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux) } else if (dp->dts != MP_NOPTS_VALUE) { priv->last_pts = dp->dts * AV_TIME_BASE; } + av_free_packet(pkt); demux_add_packet(stream, dp); return 1; } diff --git a/demux/packet.c b/demux/packet.c index 77ea78f7cc..2008113600 100644 --- a/demux/packet.c +++ b/demux/packet.c @@ -29,55 +29,58 @@ static void packet_destroy(void *ptr) { struct demux_packet *dp = ptr; - talloc_free(dp->avpacket); - av_free(dp->allocation); + av_packet_unref(dp->avpacket); } -static struct demux_packet *create_packet(size_t len) +// This actually preserves only data and side data, not PTS/DTS/pos/etc. +// It also allows avpkt->data==NULL with avpkt->size!=0 - the libavcodec API +// does not allow it, but we do it to simplify new_demux_packet(). +struct demux_packet *new_demux_packet_from_avpacket(struct AVPacket *avpkt) { - if (len > 1000000000) { + if (avpkt->size > 1000000000) { fprintf(stderr, "Attempt to allocate demux packet over 1 GB!\n"); abort(); } struct demux_packet *dp = talloc(NULL, struct demux_packet); talloc_set_destructor(dp, packet_destroy); *dp = (struct demux_packet) { - .len = len, .pts = MP_NOPTS_VALUE, .dts = MP_NOPTS_VALUE, .duration = -1, .pos = -1, .stream = -1, + .avpacket = talloc_zero(dp, AVPacket), }; - return dp; -} - -struct demux_packet *new_demux_packet(size_t len) -{ - struct demux_packet *dp = create_packet(len); - dp->buffer = av_malloc(len + FF_INPUT_BUFFER_PADDING_SIZE); - if (!dp->buffer) { - fprintf(stderr, "Memory allocation failure!\n"); + av_init_packet(dp->avpacket); + int r = -1; + if (avpkt->data) { + // We hope that this function won't need/access AVPacket input padding, + // because otherwise new_demux_packet_from() wouldn't work. + r = av_packet_ref(dp->avpacket, avpkt); + } else { + r = av_new_packet(dp->avpacket, avpkt->size); + } + if (r < 0) { + fprintf(stderr, "Out of memory when referencing packet.\n"); abort(); } - memset(dp->buffer + len, 0, FF_INPUT_BUFFER_PADDING_SIZE); - dp->allocation = dp->buffer; + dp->buffer = dp->avpacket->data; + dp->len = dp->avpacket->size; return dp; } -// data must already have suitable padding, and does not copy the data -struct demux_packet *new_demux_packet_fromdata(void *data, size_t len) +// Input data doesn't need to be padded. +struct demux_packet *new_demux_packet_from(void *data, size_t len) { - struct demux_packet *dp = create_packet(len); - dp->buffer = data; - return dp; + AVPacket pkt = { .data = data, .size = len }; + return new_demux_packet_from_avpacket(&pkt); } -struct demux_packet *new_demux_packet_from(void *data, size_t len) +struct demux_packet *new_demux_packet(size_t len) { - struct demux_packet *dp = new_demux_packet(len); - memcpy(dp->buffer, data, len); - return dp; + assert(len <= INT_MAX); + AVPacket pkt = { .data = NULL, .size = len }; + return new_demux_packet_from_avpacket(&pkt); } void demux_packet_shorten(struct demux_packet *dp, size_t len) @@ -92,28 +95,14 @@ void free_demux_packet(struct demux_packet *dp) talloc_free(dp); } -static void destroy_avpacket(void *pkt) -{ - av_free_packet(pkt); -} - struct demux_packet *demux_copy_packet(struct demux_packet *dp) { struct demux_packet *new = NULL; if (dp->avpacket) { - assert(dp->buffer == dp->avpacket->data); - assert(dp->len == dp->avpacket->size); - AVPacket *newavp = talloc_zero(NULL, AVPacket); - talloc_set_destructor(newavp, destroy_avpacket); - av_init_packet(newavp); - if (av_packet_ref(newavp, dp->avpacket) < 0) - abort(); - new = new_demux_packet_fromdata(newavp->data, newavp->size); - new->avpacket = newavp; - } - if (!new) { - new = new_demux_packet(dp->len); - memcpy(new->buffer, dp->buffer, new->len); + new = new_demux_packet_from_avpacket(dp->avpacket); + } else { + // Some packets might be not created by new_demux_packet*(). + new = new_demux_packet_from(dp->buffer, dp->len); } new->pts = dp->pts; new->dts = dp->dts; diff --git a/demux/packet.h b/demux/packet.h index 21c0a6dc8f..9c4e560e05 100644 --- a/demux/packet.h +++ b/demux/packet.h @@ -34,13 +34,11 @@ typedef struct demux_packet { bool keyframe; int stream; // source stream index struct demux_packet *next; - void *allocation; - struct AVPacket *avpacket; // original libavformat packet (demux_lavf) + struct AVPacket *avpacket; // keep the buffer allocation } demux_packet_t; struct demux_packet *new_demux_packet(size_t len); -// data must already have suitable padding -struct demux_packet *new_demux_packet_fromdata(void *data, size_t len); +struct demux_packet *new_demux_packet_from_avpacket(struct AVPacket *avpkt); struct demux_packet *new_demux_packet_from(void *data, size_t len); void demux_packet_shorten(struct demux_packet *dp, size_t len); void free_demux_packet(struct demux_packet *dp); |