mirror of https://github.com/mpv-player/mpv
Add improved relative seek mode
When the new mode is active relative seeks are converted to absolute ones (current video pts + relative seek amount) and forward/backward flag before being sent to the demuxer. This mode is used if the demuxer has set the accurate_seek field in the demuxer struct and there is a video stream. At the moment the mkv and lavf demuxers enable the flag. This change is useful for later Matroska ordered chapter support (and for more general timelime editing), but also fixes problems in existing functionality. The main problem with the old mode, where relative seeks are passed directly to the demuxer, is that the user wants to seek relative to the currently displayed position but the demuxer does not know what that position is. There can be an arbitrary amount of buffering between the demuxer read position and what is displayed on the screen. In some situations this makes small seeks fail to move backward at all (especially visible at high playback speed, when audio needs to be demuxed and decoded further ahead to fill the output buffers after resampling). Some container formats that can be used with the lavf demuxer do not always have reliable timestamps that could be used for unambiguous absolute seeking. However I made the demuxer always enable the new mode because it already converted all seeks to absolute ones before sending them to libavformat, so cases without reliable absolute seeks were failing already and this should only improve the working cases.
This commit is contained in:
parent
3279403611
commit
73fb23c1cf
|
@ -22,6 +22,7 @@
|
|||
#include <stdlib.h>
|
||||
// #include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "options.h"
|
||||
|
@ -533,6 +534,8 @@ static demuxer_t* demux_open_lavf(demuxer_t *demuxer){
|
|||
demuxer->video->id=-2; // audio-only
|
||||
} //else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video;
|
||||
|
||||
demuxer->accurate_seek = true;
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
|
@ -612,6 +615,10 @@ static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, float audio
|
|||
} else {
|
||||
if (rel_seek_secs < 0) avsflags = AVSEEK_FLAG_BACKWARD;
|
||||
}
|
||||
if (flags & SEEK_FORWARD)
|
||||
avsflags = 0;
|
||||
else if (flags & SEEK_BACKWARD)
|
||||
avsflags = AVSEEK_FLAG_BACKWARD;
|
||||
if (flags & SEEK_FACTOR) {
|
||||
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
|
||||
return;
|
||||
|
|
|
@ -2295,6 +2295,8 @@ demux_mkv_open (demuxer_t *demuxer)
|
|||
demuxer->seekable = 1;
|
||||
}
|
||||
|
||||
demuxer->accurate_seek = true;
|
||||
|
||||
return DEMUXER_TYPE_MATROSKA;
|
||||
}
|
||||
|
||||
|
@ -2962,6 +2964,12 @@ demux_mkv_fill_buffer (demuxer_t *demuxer, demux_stream_t *ds)
|
|||
static void
|
||||
demux_mkv_seek (demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags)
|
||||
{
|
||||
if (!(flags & (SEEK_BACKWARD | SEEK_FORWARD))) {
|
||||
if (flags & SEEK_ABSOLUTE || rel_seek_secs < 0)
|
||||
flags |= SEEK_BACKWARD;
|
||||
else
|
||||
flags |= SEEK_FORWARD;
|
||||
}
|
||||
free_cached_dps (demuxer);
|
||||
if (!(flags & SEEK_FACTOR)) /* time in secs */
|
||||
{
|
||||
|
@ -3016,12 +3024,12 @@ demux_mkv_seek (demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int
|
|||
for (i=0; i < mkv_d->num_cluster_pos; i++)
|
||||
{
|
||||
diff = mkv_d->cluster_positions[i] - target_filepos;
|
||||
if (rel_seek_secs < 0 && diff < 0 && -diff < min_diff)
|
||||
if (flags & SEEK_BACKWARD && diff < 0 && -diff < min_diff)
|
||||
{
|
||||
cluster_pos = mkv_d->cluster_positions[i];
|
||||
min_diff = -diff;
|
||||
}
|
||||
else if (rel_seek_secs > 0
|
||||
else if (flags & SEEK_FORWARD
|
||||
&& (diff < 0 ? -1 * diff : diff) < min_diff)
|
||||
{
|
||||
cluster_pos = mkv_d->cluster_positions[i];
|
||||
|
@ -3045,14 +3053,14 @@ demux_mkv_seek (demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int
|
|||
diff = target_timecode + mkv_d->first_tc -
|
||||
(int64_t) mkv_d->indexes[i].timecode * mkv_d->tc_scale / 1000000.0;
|
||||
|
||||
if ((flags & SEEK_ABSOLUTE || target_timecode <= mkv_d->last_pts*1000)) {
|
||||
// Absolute seek or seek backward: find the last index
|
||||
// position before target time
|
||||
if (flags & SEEK_BACKWARD) {
|
||||
// Seek backward: find the last index position
|
||||
// before target time
|
||||
if (diff < 0 || diff >= min_diff)
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// Relative seek forward: find the first index position
|
||||
// Seek forward: find the first index position
|
||||
// after target time. If no such index exists, find last
|
||||
// position between current position and target time.
|
||||
if (diff <= 0) {
|
||||
|
@ -3076,8 +3084,10 @@ demux_mkv_seek (demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int
|
|||
|
||||
if (demuxer->video->id >= 0)
|
||||
mkv_d->v_skip_to_keyframe = 1;
|
||||
if (rel_seek_secs > 0.0)
|
||||
if (flags & SEEK_FORWARD)
|
||||
mkv_d->skip_to_timecode = target_timecode;
|
||||
else
|
||||
mkv_d->skip_to_timecode = 0;
|
||||
mkv_d->a_skip_to_keyframe = 1;
|
||||
|
||||
demux_mkv_fill_buffer(demuxer, NULL);
|
||||
|
|
|
@ -96,6 +96,8 @@ struct MPOpts;
|
|||
|
||||
#define SEEK_ABSOLUTE (1 << 0)
|
||||
#define SEEK_FACTOR (1 << 1)
|
||||
#define SEEK_FORWARD (1 << 2)
|
||||
#define SEEK_BACKWARD (1 << 3)
|
||||
|
||||
#define MP_INPUT_BUFFER_PADDING_SIZE 8
|
||||
|
||||
|
@ -221,6 +223,9 @@ typedef struct demuxer {
|
|||
int type; // demuxer type: mpeg PS, mpeg ES, avi, avi-ni, avi-nini, asf
|
||||
int file_format; // file format: mpeg/avi/asf
|
||||
int seekable; // flag
|
||||
/* Set if using absolute seeks for small movements is OK (no pts resets
|
||||
* that would make pts ambigious, preferably supports back/forward flags */
|
||||
bool accurate_seek;
|
||||
//
|
||||
demux_stream_t *audio; // audio buffer/demuxer
|
||||
demux_stream_t *video; // video buffer/demuxer
|
||||
|
|
10
mplayer.c
10
mplayer.c
|
@ -2463,6 +2463,16 @@ static void edl_update(MPContext *mpctx)
|
|||
static int seek(MPContext *mpctx, double amount, int style)
|
||||
{
|
||||
current_module = "seek";
|
||||
if (mpctx->demuxer->accurate_seek && mpctx->sh_video
|
||||
&& !(style & (SEEK_ABSOLUTE | SEEK_FACTOR))) {
|
||||
style |= SEEK_ABSOLUTE;
|
||||
if (amount > 0)
|
||||
style |= SEEK_FORWARD;
|
||||
else
|
||||
style |= SEEK_BACKWARD;
|
||||
amount += mpctx->sh_video->pts;
|
||||
}
|
||||
|
||||
if (demux_seek(mpctx->demuxer, amount, audio_delay, style) == 0)
|
||||
return -1;
|
||||
|
||||
|
|
Loading…
Reference in New Issue