summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--stream/stream_dvdnav.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c
index cfbf438cf0..6f381c612f 100644
--- a/stream/stream_dvdnav.c
+++ b/stream/stream_dvdnav.c
@@ -565,18 +565,56 @@ static int control(stream_t *stream, int cmd, void *arg)
return STREAM_OK;
}
case STREAM_CTRL_SEEK_TO_TIME: {
- double d = *(double *)arg;
+ double *args = arg;
+ double d = args[0]; // absolute target timestamp
+ double r = args[1]; // if not SEEK_ABSOLUTE, the base time for d
+ int flags = args[2]; // from SEEK_* flags (demux.h)
+ if (flags & SEEK_HR)
+ d -= 10; // fudge offset; it's a hack, because fuck libdvd*
int64_t tm = (int64_t)(d * 90000);
if (tm < 0)
tm = 0;
if (priv->duration && tm >= (priv->duration * 90))
tm = priv->duration * 90 - 1;
- MP_VERBOSE(stream, "seek to PTS %f (%"PRId64")\n", d, tm);
- if (dvdnav_time_search(dvdnav, tm) != DVDNAV_STATUS_OK)
+ uint32_t pos, len;
+ if (dvdnav_get_position(dvdnav, &pos, &len) != DVDNAV_STATUS_OK)
break;
+ // The following is convoluted, because we have to translate between
+ // dvdnav's block/CBR-based seeking bullshit, and the player's
+ // timestamp-based high-level machinery.
+ if (!(flags & SEEK_ABSOLUTE) && !(flags & SEEK_HR) && priv->duration > 0)
+ {
+ int dir = (flags & SEEK_BACKWARD) ? -1 : 1;
+ // The user is making a relative seek (translated to absolute),
+ // and we try not to get the user stuck on "boundaries". So try
+ // to do block based seeks, which should workaround libdvdnav's
+ // terrible CBR-based seeking.
+ d -= r; // relative seek amount in seconds
+ d = d / (priv->duration / 1000.0) * len; // d is now in blocks
+ d += pos; // absolute target in blocks
+ if (dir > 0)
+ d = MPMAX(d, pos + 1.0);
+ if (dir < 0)
+ d = MPMIN(d, pos - 1.0);
+ d += 0.5; // round
+ uint32_t target = MPCLAMP(d, 0, len);
+ MP_VERBOSE(stream, "seek from block %lu to %lu, dir=%d\n",
+ (unsigned long)pos, (unsigned long)target, dir);
+ if (dvdnav_sector_search(dvdnav, target, SEEK_SET) != DVDNAV_STATUS_OK)
+ break;
+ } else {
+ // "old" method, should be good enough for large seeks. Used for
+ // hr-seeks (with fudge offset), because I fear that block-based
+ // seeking might be off too far for large jumps.
+ MP_VERBOSE(stream, "seek to PTS %f (%"PRId64")\n", d, tm);
+ if (dvdnav_time_search(dvdnav, tm) != DVDNAV_STATUS_OK)
+ break;
+ }
stream_drop_buffers(stream);
d = dvdnav_get_current_time(dvdnav) / 90000.0f;
MP_VERBOSE(stream, "landed at: %f\n", d);
+ if (dvdnav_get_position(dvdnav, &pos, &len) == DVDNAV_STATUS_OK)
+ MP_VERBOSE(stream, "block: %lu\n", (unsigned long)pos);
return STREAM_OK;
}
case STREAM_CTRL_GET_NUM_ANGLES: {