diff options
Diffstat (limited to 'demux')
-rw-r--r-- | demux/demux_lavf.c | 81 |
1 files changed, 80 insertions, 1 deletions
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 058f13cabf..ad71937580 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -191,6 +191,11 @@ static const struct format_hack format_hacks[] = { {0} }; +struct nested_stream { + AVIOContext *id; + int64_t last_bytes; +}; + typedef struct lavf_priv { struct stream *stream; bool own_stream; @@ -210,8 +215,29 @@ typedef struct lavf_priv { struct demux_lavf_opts *opts; double mf_fps; + + // Proxying nested streams. + struct nested_stream *nested; + int num_nested; + int (*default_io_open)(struct AVFormatContext *s, AVIOContext **pb, + const char *url, int flags, AVDictionary **options); + void (*default_io_close)(struct AVFormatContext *s, AVIOContext *pb); } lavf_priv_t; +static void update_read_stats(struct demuxer *demuxer) +{ + lavf_priv_t *priv = demuxer->priv; + + for (int n = 0; n < priv->num_nested; n++) { + struct nested_stream *nest = &priv->nested[n]; + + int64_t cur = nest->id->bytes_read; + int64_t new = cur - nest->last_bytes; + nest->last_bytes = cur; + demuxer->total_unbuffered_read_bytes += new; + } +} + // At least mp4 has name="mov,mp4,m4a,3gp,3g2,mj2", so we split the name // on "," in general. static bool matches_avinputformat_name(struct lavf_priv *priv, @@ -793,6 +819,38 @@ static int block_io_open(struct AVFormatContext *s, AVIOContext **pb, return AVERROR(EACCES); } +static int nested_io_open(struct AVFormatContext *s, AVIOContext **pb, + const char *url, int flags, AVDictionary **options) +{ + struct demuxer *demuxer = s->opaque; + lavf_priv_t *priv = demuxer->priv; + + int r = priv->default_io_open(s, pb, url, flags, options); + if (r >= 0) { + struct nested_stream nest = { + .id = *pb, + }; + MP_TARRAY_APPEND(priv, priv->nested, priv->num_nested, nest); + } + return r; +} + +static void nested_io_close(struct AVFormatContext *s, AVIOContext *pb) +{ + struct demuxer *demuxer = s->opaque; + lavf_priv_t *priv = demuxer->priv; + + for (int n = 0; n < priv->num_nested; n++) { + if (priv->nested[n].id == pb) { + MP_TARRAY_REMOVE_AT(priv->nested, priv->num_nested, n); + break; + } + } + + + priv->default_io_close(s, pb); +} + static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) { AVFormatContext *avfc; @@ -887,8 +945,14 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) }; avfc->opaque = demuxer; - if (!demuxer->access_references) + if (demuxer->access_references) { + priv->default_io_open = avfc->io_open; + priv->default_io_close = avfc->io_close; + avfc->io_open = nested_io_open; + avfc->io_close = nested_io_close; + } else { avfc->io_open = block_io_open; + } mp_set_avdict(&dopts, lavfdopts->avopts); @@ -990,6 +1054,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux) AVPacket *pkt = &(AVPacket){0}; int r = av_read_frame(priv->avfc, pkt); + update_read_stats(demux); if (r < 0) { av_packet_unref(pkt); if (r == AVERROR(EAGAIN)) @@ -1080,6 +1145,8 @@ static void demux_seek_lavf(demuxer_t *demuxer, double seek_pts, int flags) av_strerror(r, buf, sizeof(buf)); MP_VERBOSE(demuxer, "Seek failed (%s)\n", buf); } + + update_read_stats(demuxer); } static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) @@ -1176,7 +1243,19 @@ static void demux_close_lavf(demuxer_t *demuxer) { lavf_priv_t *priv = demuxer->priv; if (priv) { + // This will be a dangling pointer; but see below. + AVIOContext *leaking = priv->avfc ? priv->avfc->pb : NULL; avformat_close_input(&priv->avfc); + // The ffmpeg garbage breaks its own API yet again: hls.c will call + // io_open on the main playlist, but never calls io_close. This happens + // to work out for us (since we don't really use custom I/O), but it's + // still weird. Compensate. + if (priv->num_nested == 1 && priv->nested[0].id == leaking) + priv->num_nested = 0; + if (priv->num_nested) { + MP_WARN(demuxer, "Leaking %d nested connections (FFmpeg bug).\n", + priv->num_nested); + } if (priv->pb) av_freep(&priv->pb->buffer); av_freep(&priv->pb); |