0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02:00

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.
This commit is contained in:
wm4 2019-07-10 21:38:37 +02:00
parent 1dd0b2fe34
commit 82f2613ade
4 changed files with 111 additions and 0 deletions

View File

@ -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).

View File

@ -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).

View File

@ -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);

View File

@ -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}
};