diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c index bab8186f51..013db04170 100644 --- a/libmpdemux/demux_lavf.c +++ b/libmpdemux/demux_lavf.c @@ -743,10 +743,15 @@ static void check_internet_radio_hack(struct demuxer *demuxer) } } +static int destroy_avpacket(void *pkt) +{ + av_free_packet(pkt); + return 0; +} + static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) { lavf_priv_t *priv = demux->priv; - AVPacket pkt; demux_packet_t *dp; demux_stream_t *ds; int id; @@ -754,8 +759,12 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) demux->filepos = stream_tell(demux->stream); - if (av_read_frame(priv->avfc, &pkt) < 0) + AVPacket *pkt = talloc(NULL, AVPacket); + if (av_read_frame(priv->avfc, pkt) < 0) { + talloc_free(pkt); return 0; + } + talloc_set_destructor(pkt, destroy_avpacket); // handle any new streams that might have been added for (id = priv->nb_streams_last; id < priv->avfc->nb_streams; id++) @@ -764,7 +773,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) priv->nb_streams_last = priv->avfc->nb_streams; - id = pkt.stream_index; + id = pkt->stream_index; if (id == demux->audio->id || priv->internet_radio_hack) { // audio @@ -787,39 +796,27 @@ static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) ds = demux->sub; sub_utf8 = 1; } else { - av_free_packet(&pkt); + talloc_free(pkt); return 1; } - if (0 /*pkt.destruct == av_destruct_packet*/) { - //ok kids, dont try this at home :) - dp = malloc(sizeof(demux_packet_t)); - dp->len = pkt.size; - dp->next = NULL; - dp->refcount = 1; - dp->master = NULL; - dp->buffer = pkt.data; - pkt.destruct = NULL; - } else { - dp = new_demux_packet(pkt.size); - memcpy(dp->buffer, pkt.data, pkt.size); - av_free_packet(&pkt); - } + dp = new_demux_packet_fromdata(pkt->data, pkt->size); + dp->avpacket = pkt; - int64_t ts = priv->use_dts ? pkt.dts : pkt.pts; + int64_t ts = priv->use_dts ? pkt->dts : pkt->pts; if (ts != AV_NOPTS_VALUE) { dp->pts = ts * av_q2d(priv->avfc->streams[id]->time_base); priv->last_pts = dp->pts * AV_TIME_BASE; // always set duration for subtitles, even if AV_PKT_FLAG_KEY isn't set, // otherwise they will stay on screen to long if e.g. ASS is demuxed // from mkv - if ((ds == demux->sub || (pkt.flags & AV_PKT_FLAG_KEY)) && - pkt.convergence_duration > 0) - dp->duration = pkt.convergence_duration * + if ((ds == demux->sub || (pkt->flags & AV_PKT_FLAG_KEY)) && + pkt->convergence_duration > 0) + dp->duration = pkt->convergence_duration * av_q2d(priv->avfc->streams[id]->time_base); } dp->pos = demux->filepos; - dp->flags = !!(pkt.flags & AV_PKT_FLAG_KEY); + dp->flags = !!(pkt->flags & AV_PKT_FLAG_KEY); // append packet to DS stream: ds_add_packet(ds, dp); return 1; diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c index c59fd3fdc7..d4c43ad657 100644 --- a/libmpdemux/demuxer.c +++ b/libmpdemux/demuxer.c @@ -176,7 +176,7 @@ const demuxer_desc_t *const demuxer_list[] = { NULL }; -struct demux_packet *new_demux_packet(size_t len) +static struct demux_packet *create_packet(size_t len) { if (len > 1000000000) { mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Attempt to allocate demux packet " @@ -194,6 +194,13 @@ struct demux_packet *new_demux_packet(size_t len) dp->refcount = 1; dp->master = NULL; dp->buffer = NULL; + dp->avpacket = NULL; + return dp; +} + +struct demux_packet *new_demux_packet(size_t len) +{ + struct demux_packet *dp = create_packet(len); dp->buffer = malloc(len + MP_INPUT_BUFFER_PADDING_SIZE); if (!dp->buffer) { mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Memory allocation failure!\n"); @@ -203,6 +210,14 @@ struct demux_packet *new_demux_packet(size_t len) return dp; } +// data must already have suitable padding +struct demux_packet *new_demux_packet_fromdata(void *data, size_t len) +{ + struct demux_packet *dp = create_packet(len); + dp->buffer = data; + return dp; +} + void resize_demux_packet(struct demux_packet *dp, size_t len) { if (len > 1000000000) { @@ -237,7 +252,10 @@ void free_demux_packet(struct demux_packet *dp) if (dp->master == NULL) { //dp is a master packet dp->refcount--; if (dp->refcount == 0) { - free(dp->buffer); + if (dp->avpacket) + talloc_free(dp->avpacket); + else + free(dp->buffer); free(dp); } return; diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h index b3fef45ed7..6f51dc76dc 100644 --- a/libmpdemux/demuxer.h +++ b/libmpdemux/demuxer.h @@ -122,7 +122,8 @@ enum timestamp_type { #define SEEK_FORWARD (1 << 2) #define SEEK_BACKWARD (1 << 3) -#define MP_INPUT_BUFFER_PADDING_SIZE 64 +// demux_lavf can pass lavf buffers using FF_INPUT_BUFFER_PADDING_SIZE instead +#define MP_INPUT_BUFFER_PADDING_SIZE 8 // Holds one packet/frame/whatever typedef struct demux_packet { @@ -136,6 +137,7 @@ typedef struct demux_packet { int refcount; // counter for the master packet, if 0, buffer can be free()d struct demux_packet *master; //in clones, pointer to the master packet struct demux_packet *next; + struct AVPacket *avpacket; // original libavformat packet (demux_lavf) } demux_packet_t; typedef struct demux_stream { @@ -302,6 +304,8 @@ typedef struct { } demux_program_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); void resize_demux_packet(struct demux_packet *dp, size_t len); struct demux_packet *clone_demux_packet(struct demux_packet *pack); void free_demux_packet(struct demux_packet *dp);