diff options
Diffstat (limited to 'player')
-rw-r--r-- | player/command.c | 15 | ||||
-rw-r--r-- | player/core.h | 1 | ||||
-rw-r--r-- | player/loadfile.c | 5 | ||||
-rw-r--r-- | player/main.c | 1 | ||||
-rw-r--r-- | player/playloop.c | 27 |
5 files changed, 44 insertions, 5 deletions
diff --git a/player/command.c b/player/command.c index 6682398b8b..68ce861c6f 100644 --- a/player/command.c +++ b/player/command.c @@ -465,6 +465,19 @@ static int mp_property_playback_speed(void *ctx, struct m_property *prop, return mp_property_generic_option(mpctx, prop, action, arg); } +static int mp_property_play_direction(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + if (action == M_PROPERTY_SET) { + if (mpctx->play_dir != *(int *)arg) { + queue_seek(mpctx, MPSEEK_ABSOLUTE, get_current_time(mpctx), + MPSEEK_EXACT, 0); + } + } + return mp_property_generic_option(mpctx, prop, action, arg); +} + static int mp_property_av_speed_correction(void *ctx, struct m_property *prop, int action, void *arg) { @@ -3561,6 +3574,8 @@ static const struct m_property mp_properties_base[] = { {"property-list", mp_property_list}, {"profile-list", mp_profile_list}, + {"play-direction", mp_property_play_direction}, + M_PROPERTY_ALIAS("video", "vid"), M_PROPERTY_ALIAS("audio", "aid"), M_PROPERTY_ALIAS("sub", "sid"), diff --git a/player/core.h b/player/core.h index f0a66ffdff..d2183a7537 100644 --- a/player/core.h +++ b/player/core.h @@ -326,6 +326,7 @@ typedef struct MPContext { enum playback_status video_status, audio_status; bool restart_complete; + int play_dir; // Factors to multiply with opts->playback_speed to get the total audio or // video speed (usually 1.0, but can be set to by the sync code). double speed_factor_v, speed_factor_a; diff --git a/player/loadfile.c b/player/loadfile.c index f4fad8a914..c16b8e8152 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -1551,6 +1551,11 @@ static void play_current_file(struct MPContext *mpctx) } double play_start_pts = get_play_start_pts(mpctx); + + // Backward playback -> start from end by default. + if (play_start_pts == MP_NOPTS_VALUE && opts->play_dir < 0) + play_start_pts = MPMAX(mpctx->demuxer->duration, 0); + if (play_start_pts != MP_NOPTS_VALUE) { /* * get_play_start_pts returns rebased values, but diff --git a/player/main.c b/player/main.c index 0a11bcf7d2..e1f3285984 100644 --- a/player/main.c +++ b/player/main.c @@ -280,6 +280,7 @@ struct MPContext *mp_create(void) .playback_abort = mp_cancel_new(mpctx), .thread_pool = mp_thread_pool_create(mpctx, 0, 1, 30), .stop_play = PT_STOP, + .play_dir = 1, }; pthread_mutex_init(&mpctx->abort_lock, NULL); diff --git a/player/playloop.c b/player/playloop.c index 61ade84755..85890c2ef1 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -42,6 +42,7 @@ #include "audio/out/ao.h" #include "demux/demux.h" #include "stream/stream.h" +#include "sub/dec_sub.h" #include "sub/osd.h" #include "video/out/vo.h" @@ -223,6 +224,14 @@ void reset_playback_state(struct MPContext *mpctx) reset_audio_state(mpctx); reset_subtitle_state(mpctx); + for (int n = 0; n < mpctx->num_tracks; n++) { + struct track *t = mpctx->tracks[n]; + if (t->dec) + t->dec->play_dir = mpctx->play_dir; + if (t->d_sub) + sub_set_play_dir(t->d_sub, mpctx->play_dir); + } + mpctx->hrseek_active = false; mpctx->hrseek_lastframe = false; mpctx->hrseek_backstep = false; @@ -317,6 +326,10 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek) if (!mpctx->demuxer->seekable) demux_flags |= SEEK_CACHED; + int play_dir = opts->play_dir; + if (play_dir < 0) + demux_flags |= SEEK_SATAN; + if (!demux_seek(mpctx->demuxer, demux_pts, demux_flags)) { if (!mpctx->demuxer->seekable) { MP_ERR(mpctx, "Cannot seek in this stream.\n"); @@ -325,6 +338,8 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek) return; } + mpctx->play_dir = play_dir; + // Seek external, extra files too: bool has_video = false; struct track *external_audio = NULL; @@ -336,7 +351,7 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek) main_new_pos += get_track_seek_offset(mpctx, track); if (demux_flags & SEEK_FACTOR) main_new_pos = seek_pts; - demux_seek(track->demuxer, main_new_pos, 0); + demux_seek(track->demuxer, main_new_pos, demux_flags & SEEK_SATAN); if (track->type == STREAM_AUDIO && !external_audio) external_audio = track; } @@ -357,7 +372,9 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek) // granularity is coarser than audio). The result would be playing video with // silence until the audio seek target is reached. Work around by blocking // the demuxer (decoders can't read) and seeking to video position later. - if (has_video && external_audio && !hr_seek && !(demux_flags & SEEK_FORWARD)) { + if (has_video && external_audio && !hr_seek && mpctx->play_dir > 0 && + !(demux_flags & SEEK_FORWARD)) + { MP_VERBOSE(mpctx, "delayed seek for aid=%d\n", external_audio->user_tid); demux_block_reading(external_audio->demuxer, true); mpctx->seek_slave = external_audio; @@ -370,7 +387,7 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek) if (hr_seek) { mpctx->hrseek_active = true; mpctx->hrseek_backstep = seek.type == MPSEEK_BACKSTEP; - mpctx->hrseek_pts = seek_pts; + mpctx->hrseek_pts = seek_pts * mpctx->play_dir; // allow decoder to drop frames before hrseek_pts bool hrseek_framedrop = !hr_seek_very_exact && opts->hr_seek_framedrop; @@ -472,7 +489,7 @@ double get_current_time(struct MPContext *mpctx) struct demuxer *demuxer = mpctx->demuxer; if (demuxer) { if (mpctx->playback_pts != MP_NOPTS_VALUE) - return mpctx->playback_pts; + return mpctx->playback_pts * mpctx->play_dir; if (mpctx->last_seek_pts != MP_NOPTS_VALUE) return mpctx->last_seek_pts; } @@ -630,7 +647,7 @@ static void handle_update_cache(struct MPContext *mpctx) int cache_buffer = 100; bool use_pause_on_low_cache = demux_is_network_cached(mpctx->demuxer) && - opts->cache_pause; + opts->cache_pause && mpctx->play_dir > 0; if (!mpctx->restart_complete) { // Audio or video is restarting, and initial buffering is enabled. Make |