From 82f2613adee9d18ad9baba6da42ba94c5dbbccbb Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 10 Jul 2019 21:38:37 +0200 Subject: command, demux: add AB-loop keyframe cache align command Helper for the ab-loop-dump-cache command, see manpage additions. This is kind of shit. Not only is this a very "special" feature, but it also vomits more messy code into the big and already bloated demux.c, and the implementation is sort of duplicated with the dump-cache code. (Except it's different.) In addition, the results sort of depend what a video player would do with the dump-cache output, or what the user wants (for example, a user might be more interested in the range of output audio, instead of the video). But hey, I don't actually need to justify it. I'm only justifying it for fun. --- DOCS/man/input.rst | 9 +++++++ demux/demux.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ demux/demux.h | 3 +++ player/command.c | 22 ++++++++++++++++ 4 files changed, 111 insertions(+) diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index fdbe4e5fd8..393ac9b9ee 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -974,6 +974,15 @@ Input Commands that are Possibly Subject to Change The author reserves the right to remove this command if enough motivation is found to move this functionality to a trivial Lua script. +``ab-loop-align-cache`` + Re-adjust the A/B loop points to the start and end within the cache the + ``ab-loop-dump-cache`` command will (probably) dump. Basically, it aligns + the times on keyframes. The guess might be off especially at the end (due to + granularity issues due to remuxing). If the cache shrinks in the meantime, + the points set by the command will not be the effective parameters either. + + This command has an even more uncertain future than ``ab-loop-dump-cache`` + and might disappear without replacement if the author decides it's useless. Undocumented commands: ``ao-reload`` (experimental/internal). diff --git a/demux/demux.c b/demux/demux.c index 19a57a7c32..a26e3a155c 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -4174,6 +4174,83 @@ int demux_cache_dump_get_status(struct demuxer *demuxer) return status; } +// Return what range demux_cache_dump_set() would (probably) yield. This is a +// conservative amount (in addition to internal consistency of this code, it +// depends on what a player will do with the resulting file). +// Use for_end==true to get the end of dumping, other the start. +// Returns NOPTS if nothing was found. +double demux_probe_cache_dump_target(struct demuxer *demuxer, double pts, + bool for_end) +{ + struct demux_internal *in = demuxer->in; + assert(demuxer == in->d_user); + + double res = MP_NOPTS_VALUE; + if (pts == MP_NOPTS_VALUE) + return pts; + + pthread_mutex_lock(&in->lock); + + pts = MP_ADD_PTS(pts, -in->ts_offset); + + // (When determining the end, look before the keyframe at pts, so subtract + // an arbitrary amount to round down.) + double seek_pts = for_end ? pts - 0.001 : pts; + int flags = 0; + struct demux_cached_range *r = find_cache_seek_range(in, seek_pts, flags); + if (r) { + if (!for_end) + adjust_cache_seek_target(in, r, &pts, &flags); + + double t[STREAM_TYPE_COUNT]; + for (int n = 0; n < STREAM_TYPE_COUNT; n++) + t[n] = MP_NOPTS_VALUE; + + for (int n = 0; n < in->num_streams; n++) { + struct demux_stream *ds = in->streams[n]->ds; + struct demux_queue *q = r->streams[n]; + + struct demux_packet *dp = find_seek_target(q, pts, flags); + if (dp) { + if (for_end) { + while (dp) { + double pdts = MP_PTS_OR_DEF(dp->dts, dp->pts); + + if (pdts != MP_NOPTS_VALUE && pdts >= pts && dp->keyframe) + break; + + t[ds->type] = MP_PTS_MAX(t[ds->type], pdts); + + dp = dp->next; + } + } else { + double start; + compute_keyframe_times(dp, &start, NULL); + start = MP_PTS_MAX(start, r->seek_start); + t[ds->type] = MP_PTS_MAX(t[ds->type], start); + } + } + } + + res = t[STREAM_VIDEO]; + if (res == MP_NOPTS_VALUE) + res = t[STREAM_AUDIO]; + if (res == MP_NOPTS_VALUE) { + for (int n = 0; n < STREAM_TYPE_COUNT; n++) { + res = t[n]; + if (res != MP_NOPTS_VALUE) + break; + } + } + } + + res = MP_ADD_PTS(res, in->ts_offset); + + pthread_mutex_unlock(&in->lock); + + return res; +} + // Used by demuxers to report the amount of transferred bytes. This is for // streams which circumvent demuxer->stream (stream statistics are handled by // demux.c itself). diff --git a/demux/demux.h b/demux/demux.h index 3716f28b87..ebebd0853f 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -296,6 +296,9 @@ bool demux_cache_dump_set(struct demuxer *demuxer, double start, double end, char *file); int demux_cache_dump_get_status(struct demuxer *demuxer); +double demux_probe_cache_dump_target(struct demuxer *demuxer, double pts, + bool for_end); + bool demux_is_network_cached(demuxer_t *demuxer); void demux_report_unbuffered_read_bytes(struct demuxer *demuxer, int64_t new); diff --git a/player/command.c b/player/command.c index b4c2ad1201..8c4f8de5ea 100644 --- a/player/command.c +++ b/player/command.c @@ -5336,6 +5336,26 @@ static void cmd_ab_loop(void *p) } } +static void cmd_align_cache_ab(void *p) +{ + struct mp_cmd_ctx *cmd = p; + struct MPContext *mpctx = cmd->mpctx; + + if (!mpctx->demuxer) + return; + + double a = demux_probe_cache_dump_target(mpctx->demuxer, + mpctx->opts->ab_loop[0], false); + double b = demux_probe_cache_dump_target(mpctx->demuxer, + mpctx->opts->ab_loop[1], true); + + mp_property_do("ab-loop-a", M_PROPERTY_SET, &a, mpctx); + mp_property_do("ab-loop-b", M_PROPERTY_SET, &b, mpctx); + + // Happens to cover both properties. + show_property_osd(mpctx, "ab-loop-b", cmd->on_osd); +} + static void cmd_drop_buffers(void *p) { struct mp_cmd_ctx *cmd = p; @@ -5986,6 +6006,8 @@ const struct mp_cmd_def mp_cmds[] = { .can_abort = true, }, + { "ab-loop-align-cache", cmd_align_cache_ab }, + {0} }; -- cgit v1.2.3