diff --git a/core/mp_core.h b/core/mp_core.h index 25482ac3ef..58d6bb4791 100644 --- a/core/mp_core.h +++ b/core/mp_core.h @@ -280,6 +280,7 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount, int exact); int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts); double get_time_length(struct MPContext *mpctx); +double get_start_time(struct MPContext *mpctx); double get_current_time(struct MPContext *mpctx); int get_percent_pos(struct MPContext *mpctx); double get_current_pos_ratio(struct MPContext *mpctx); diff --git a/core/mplayer.c b/core/mplayer.c index 78de39cce7..6e0256fbaa 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -2769,9 +2769,12 @@ static int seek(MPContext *mpctx, struct seek_params seek, && seek.amount < mpctx->last_chapter_pts || seek.amount < 0) mpctx->last_chapter_seek = -2; - if (mpctx->timeline && seek.type == MPSEEK_FACTOR) { - seek.amount *= mpctx->timeline[mpctx->num_timeline_parts].start; - seek.type = MPSEEK_ABSOLUTE; + if (seek.type == MPSEEK_FACTOR) { + double len = get_time_length(mpctx); + if (len > 0 && !mpctx->demuxer->ts_resets_possible) { + seek.amount = seek.amount * len + get_start_time(mpctx); + seek.type = MPSEEK_ABSOLUTE; + } } if ((mpctx->demuxer->accurate_seek || mpctx->timeline) && seek.type == MPSEEK_RELATIVE) { @@ -2807,9 +2810,11 @@ static int seek(MPContext *mpctx, struct seek_params seek, int demuxer_style = 0; switch (seek.type) { case MPSEEK_FACTOR: - demuxer_style |= SEEK_FACTOR; // fallthrough + demuxer_style |= SEEK_ABSOLUTE | SEEK_FACTOR; + break; case MPSEEK_ABSOLUTE: demuxer_style |= SEEK_ABSOLUTE; + break; } if (hr_seek || seek.direction < 0) demuxer_style |= SEEK_BACKWARD; @@ -2970,7 +2975,7 @@ double get_current_time(struct MPContext *mpctx) return 0; } -static double get_start_time(struct MPContext *mpctx) +double get_start_time(struct MPContext *mpctx) { struct demuxer *demuxer = mpctx->demuxer; if (!demuxer) @@ -2990,7 +2995,7 @@ double get_current_pos_ratio(struct MPContext *mpctx) double start = get_start_time(mpctx); double len = get_time_length(mpctx); double pos = get_current_time(mpctx); - if (len > 0) { + if (len > 0 && !demuxer->ts_resets_possible) { ans = av_clipf((pos - start) / len, 0, 1); } else { int len = (demuxer->movi_end - demuxer->movi_start); diff --git a/demux/demux.h b/demux/demux.h index 554730d59f..41551975cc 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -234,6 +234,8 @@ typedef struct demuxer { /* 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; + // File format allows PTS resets (even if the current file is without) + bool ts_resets_possible; enum timestamp_type timestamp_type; bool warned_queue_overflow; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 3312c27523..50f9f1e8f0 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -585,6 +585,8 @@ static demuxer_t *demux_open_lavf(demuxer_t *demuxer) demuxer->video->id = -2; // audio-only / sub-only } + demuxer->ts_resets_possible = priv->avif->flags & AVFMT_TS_DISCONT; + // disabled because unreliable per-stream bitrate values returned // by libavformat trigger this heuristic incorrectly and break things #if 0 @@ -713,16 +715,27 @@ static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, priv->last_pts = 0; 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; - priv->last_pts += rel_seek_secs * priv->avfc->duration; - } else + if (demuxer->movi_end > 0 && demuxer->ts_resets_possible && + !(priv->avif->flags & AVFMT_NO_BYTE_SEEK)) + { + avsflags |= AVSEEK_FLAG_BYTE; + priv->last_pts = (demuxer->movi_end - demuxer->movi_start) * + rel_seek_secs; + } else if (priv->avfc->duration != 0 && + priv->avfc->duration != AV_NOPTS_VALUE) + { + priv->last_pts = rel_seek_secs * priv->avfc->duration; + } + } else { priv->last_pts += rel_seek_secs * AV_TIME_BASE; + } if (!priv->avfc->iformat->read_seek2) { // Normal seeking. diff --git a/demux/demux_mpg.c b/demux/demux_mpg.c index ab157be748..52153b9a6a 100644 --- a/demux/demux_mpg.c +++ b/demux/demux_mpg.c @@ -1134,6 +1134,8 @@ static demuxer_t* demux_mpg_es_open(demuxer_t* demuxer) demuxer->video->sh = new_sh_video(demuxer,0); // create dummy video stream header, id=0 sh_video=demuxer->video->sh;sh_video->ds=demuxer->video; + demuxer->ts_resets_possible = true; + return demuxer; } @@ -1142,6 +1144,9 @@ static demuxer_t *demux_mpg_gxf_open(demuxer_t *demuxer) { demuxer->video->sh = new_sh_video(demuxer,0); ((sh_video_t *)demuxer->video->sh)->ds = demuxer->video; demuxer->priv = (void *) 0xffffffff; + + demuxer->ts_resets_possible = true; + return demuxer; } @@ -1152,6 +1157,8 @@ static demuxer_t* demux_mpg_ps_open(demuxer_t* demuxer) sh_video=demuxer->video->sh;sh_video->ds=demuxer->video; + demuxer->ts_resets_possible = true; + if(demuxer->audio->id!=-2) { if(!ds_fill_buffer(demuxer->audio)){ mp_msg(MSGT_DEMUXER, MSGL_INFO, "MPEG: %s", diff --git a/demux/demux_ts.c b/demux/demux_ts.c index 5fe4d2e09c..42da41d532 100644 --- a/demux/demux_ts.c +++ b/demux/demux_ts.c @@ -990,6 +990,7 @@ static demuxer_t *demux_open_ts(demuxer_t * demuxer) demuxer->type= DEMUXER_TYPE_MPEG_TS; + demuxer->ts_resets_possible = true; stream_reset(demuxer->stream);