summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
Diffstat (limited to 'player')
-rw-r--r--player/command.c15
-rw-r--r--player/core.h1
-rw-r--r--player/loadfile.c5
-rw-r--r--player/main.c1
-rw-r--r--player/playloop.c27
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