aboutsummaryrefslogtreecommitdiff
path: root/lib/libdvd/patches/libdvdnav-accurate_seek.diff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libdvd/patches/libdvdnav-accurate_seek.diff')
-rw-r--r--lib/libdvd/patches/libdvdnav-accurate_seek.diff689
1 files changed, 0 insertions, 689 deletions
diff --git a/lib/libdvd/patches/libdvdnav-accurate_seek.diff b/lib/libdvd/patches/libdvdnav-accurate_seek.diff
deleted file mode 100644
index efcda5f8d3..0000000000
--- a/lib/libdvd/patches/libdvdnav-accurate_seek.diff
+++ /dev/null
@@ -1,689 +0,0 @@
-More accurate seeking with libdvdnav
-
-applied to current codebase from:
- http://lists.mplayerhq.hu/pipermail/dvdnav-discuss/2012-December/001837.html
-
-full credit goes to gnosygnu, see
- http://forum.videolan.org/viewtopic.php?f=32&t=76308&start=20#p316583
- https://github.com/xbmc/xbmc/pull/2957#issuecomment-20855719
-
-related tickets:
- http://trac.xbmc.org/ticket/12212
- http://trac.xbmc.org/ticket/14493
-
-
-diff --git a/libdvdnav/src/dvdnav/dvdnav.h b/libdvdnav/src/dvdnav/dvdnav.h
-index 359b951..506a286 100644
---- a/libdvdnav/src/dvdnav/dvdnav.h
-+++ b/libdvdnav/src/dvdnav/dvdnav.h
-@@ -373,6 +373,14 @@ dvdnav_status_t dvdnav_sector_search(dvdnav_t *self,
- int64_t dvdnav_get_current_time(dvdnav_t *self);
-
- /*
-+ * Find the nearest vobu and jump to it
-+ *
-+ * Alternative to dvdnav_time_search
-+ */
-+dvdnav_status_t dvdnav_jump_to_sector_by_time(dvdnav_t *this,
-+ uint64_t time_in_pts_ticks, int32_t mode);
-+
-+/*
- * Stop playing the current position and start playback of the title
- * from the specified timecode.
- *
-diff --git a/libdvdnav/src/dvdnav_internal.h b/libdvdnav/src/dvdnav_internal.h
-index d64a5ba..df26014 100644
---- a/libdvdnav/src/dvdnav_internal.h
-+++ b/libdvdnav/src/dvdnav_internal.h
-@@ -125,6 +125,45 @@ typedef struct {
- } ATTRIBUTE_PACKED spu_status_t;
- #endif
-
-+/*
-+ * Describes a given time, and the closest sector, vobu and tmap index
-+ */
-+typedef struct {
-+ uint64_t time;
-+ uint32_t sector;
-+ uint32_t vobu_idx;
-+ int32_t tmap_idx;
-+} dvdnav_pos_data_t;
-+
-+/*
-+ * Encapsulates cell data
-+ */
-+typedef struct {
-+ int32_t idx;
-+ dvdnav_pos_data_t *bgn;
-+ dvdnav_pos_data_t *end;
-+} dvdnav_cell_data_t;
-+
-+/*
-+ * Encapsulates common variables used by internal functions of jump_to_time
-+ */
-+typedef struct {
-+ vobu_admap_t *admap;
-+ int32_t admap_len;
-+ vts_tmap_t *tmap;
-+ int32_t tmap_len;
-+ int32_t tmap_interval;
-+} dvdnav_jump_args_t;
-+
-+/*
-+ * Utility constants for jump_to_time
-+ */
-+#define TMAP_IDX_EDGE_BGN -1
-+#define TMAP_IDX_EDGE_END -2
-+#define JUMP_MODE_TIME_AFTER 1
-+#define JUMP_MODE_TIME_DEFAULT 0
-+#define JUMP_MODE_TIME_BEFORE -1
-+
- typedef struct dvdnav_vobu_s {
- int32_t vobu_start; /* Logical Absolute. MAX needed is 0x300000 */
- int32_t vobu_length;
-diff --git a/libdvdnav/src/searching.c b/libdvdnav/src/searching.c
-index a5e48fe..0115e2f 100644
---- a/libdvdnav/src/searching.c
-+++ b/libdvdnav/src/searching.c
-@@ -36,6 +36,7 @@
- #include "vm/decoder.h"
- #include "vm/vm.h"
- #include "dvdnav_internal.h"
-+#include <dvdread/ifo_read.h>
-
- /*
- #define LOG_DEBUG
-@@ -805,3 +806,593 @@ dvdnav_status_t dvdnav_set_state(dvdnav_t *this, dvd_state_t *save_state)
- pthread_mutex_unlock(&this->vm_lock);
- return DVDNAV_STATUS_OK;
- }
-+
-+
-+
-+/* Get an admap and admap_len */
-+static vobu_admap_t* dvdnav_admap_get(dvdnav_t *this, dvd_state_t *state,
-+ int32_t *admap_len) {
-+ vobu_admap_t *admap = NULL;
-+ switch(state->domain) {
-+ case FP_DOMAIN:
-+ case VMGM_DOMAIN:
-+ admap = this->vm->vmgi->menu_vobu_admap;
-+ break;
-+ case VTSM_DOMAIN:
-+ admap = this->vm->vtsi->menu_vobu_admap;
-+ break;
-+ case VTS_DOMAIN:
-+ admap = this->vm->vtsi->vts_vobu_admap;
-+ break;
-+ default: {
-+ fprintf(MSG_OUT, "Unknown domain");
-+ return NULL;
-+ }
-+ }
-+ if (admap == NULL) return NULL;
-+
-+ *admap_len = (admap->last_byte + 1 - VOBU_ADMAP_SIZE) / VOBU_ADMAP_SIZE;
-+ if (*admap_len <= 0) {
-+ fprintf(MSG_OUT, "admap_len <= 0");
-+ return NULL;
-+ }
-+ return admap;
-+}
-+
-+/* Get a tmap, tmap_len and tmap_interval */
-+static vts_tmap_t* dvdnav_tmap_get(dvdnav_t *this, dvd_state_t *state,
-+ int32_t *tmap_len, int32_t *tmap_interval) {
-+ int32_t vts_idx = 0;
-+ domain_t domain;
-+ ifo_handle_t *ifo = NULL;
-+ vts_tmapt_t *tmapt = NULL;
-+ uint16_t tmap_count = 0;
-+ int32_t pgcN = 0;
-+ vts_tmap_t *tmap = NULL;
-+ int32_t result = 0;
-+
-+ vts_idx = state->vtsN;
-+ domain = state->domain;
-+ switch(domain) {
-+ case FP_DOMAIN:
-+ case VTSM_DOMAIN:
-+ case VMGM_DOMAIN: {
-+ ifo = this->vm->vmgi;
-+ break;
-+ }
-+ case VTS_DOMAIN: {
-+ ifo = this->vm->vtsi;
-+ break;
-+ }
-+ default: {
-+ fprintf(MSG_OUT, "unknown domain for tmap");
-+ return NULL;
-+ }
-+ }
-+ if (ifo == NULL) return NULL;
-+ tmapt = ifo->vts_tmapt;
-+ /* HACK: ifo->vts_tmapt is NULL b/c ifo_read.c never loads it
-+ * load ifo->vts_tmapt directly*/
-+ if (tmapt == NULL) {
-+ result = ifoRead_VTS_TMAPT(ifo);
-+ if (!result) {
-+ return NULL;
-+ }
-+ tmapt = ifo->vts_tmapt;
-+ if (tmapt == NULL) return NULL;
-+ }
-+
-+ tmap_count = tmapt->nr_of_tmaps;
-+ pgcN = state->pgcN - 1; /* -1 b/c pgcN is base1 */
-+ if (pgcN < 0) {
-+ fprintf(MSG_OUT, "pgcN < 0");
-+ return NULL;
-+ }
-+
-+ /* get tmap */
-+ switch(domain) {
-+ case FP_DOMAIN:
-+ case VMGM_DOMAIN:
-+ case VTSM_DOMAIN: {
-+ if (tmap_count == 0) {
-+ fprintf(MSG_OUT, "tmap_count == 0");
-+ return NULL;
-+ }
-+ tmap = &tmapt->tmap[0]; /* ASSUME: vmgi only has one time map */
-+ break;
-+ }
-+ case VTS_DOMAIN: {
-+ if (pgcN >= tmap_count) {
-+ fprintf(MSG_OUT, "pgcN >= tmap_count; pgcN=%i tmap_count=%i",
-+ pgcN, tmap_count);
-+ return NULL;
-+ }
-+ tmap = &tmapt->tmap[pgcN];
-+ break;
-+ }
-+ }
-+ if (tmap == NULL) return NULL;
-+
-+ /* tmap->tmu is in seconds; convert to millisecs */
-+ *tmap_interval = tmap->tmu * 1000;
-+ if (*tmap_interval == 0) {
-+ fprintf(MSG_OUT, "tmap_interval == 0");
-+ return NULL;
-+ }
-+ *tmap_len = tmap->nr_of_entries;
-+ if (*tmap_len == 0) {
-+ fprintf(MSG_OUT, "tmap_len == 0");
-+ return NULL;
-+ }
-+ return tmap;
-+}
-+
-+/* Get a sector from a tmap */
-+static int32_t dvdnav_tmap_get_entry(vts_tmap_t *tmap, uint16_t tmap_len,
-+ int32_t idx, uint32_t *sector) {
-+ /* tmaps start at idx 0 which represents a sector at time 1 * tmap_interval
-+ * this creates a "fake" tmap index at idx -1 for sector 0 */
-+ if (idx == TMAP_IDX_EDGE_BGN) {
-+ *sector = 0;
-+ return 1;
-+ }
-+ if (idx < TMAP_IDX_EDGE_BGN || idx >= tmap_len) {
-+ fprintf(MSG_OUT, "idx out of bounds idx=%i %i", idx, tmap_len);
-+ return 0;
-+ }
-+ /* 0x7fffffff unsets discontinuity bit if present */
-+ *sector = tmap->map_ent[idx] & 0x7fffffff;
-+ return 1;
-+}
-+
-+/* Do a binary search for earlier admap index near find_sector */
-+static int32_t dvdnav_admap_search(vobu_admap_t *admap, uint32_t admap_len,
-+ uint32_t find_sector, uint32_t *vobu) {
-+ int32_t adj = 1;
-+ int32_t prv_pos = 0;
-+ int32_t prv_len = admap_len;
-+ int32_t cur_len = 0;
-+ int32_t cur_idx = 0;
-+ uint32_t cur_sector = 0;
-+ while (1) {
-+ cur_len = prv_len / 2;
-+ /* need to add 1 when prv_len == 3 (cur_len shoud go to 2, not 1) */
-+ if (prv_len % 2 == 1) ++cur_len;
-+ cur_idx = prv_pos + (cur_len * adj);
-+ if (cur_idx < 0) cur_idx = 0;
-+ else if (cur_idx >= admap_len) cur_idx = admap_len - 1;
-+
-+ cur_sector = admap->vobu_start_sectors[cur_idx];
-+ if (find_sector < cur_sector) adj = -1;
-+ else if (find_sector > cur_sector) adj = 1;
-+ else if (find_sector == cur_sector) {
-+ *vobu = cur_idx;
-+ return 1;
-+ }
-+ if (cur_len == 1) {/* no smaller intervals left */
-+ if (adj == -1) {/* last comparison was greater; take lesser */
-+ cur_idx -= 1;
-+ cur_sector = admap->vobu_start_sectors[cur_idx];
-+ }
-+ *vobu = cur_idx;
-+ return 1;
-+ }
-+ prv_len = cur_len;
-+ prv_pos = cur_idx;
-+ }
-+}
-+
-+/* Do a binary search for the earlier tmap entry near find_sector */
-+static int32_t dvdnav_tmap_search(vts_tmap_t *tmap, uint32_t tmap_len,
-+ uint32_t find_sector, int32_t *tmap_idx, uint32_t *sector) {
-+ int32_t adj = 1;
-+ int32_t prv_pos = 0;
-+ int32_t prv_len = tmap_len;
-+ int32_t result = 0;
-+ int32_t cur_len = 0;
-+ int32_t cur_idx = 0;
-+ uint32_t cur_sector = 0;
-+ while (1) {
-+ cur_len = prv_len / 2;
-+ /* need to add 1 when prv_len == 3 (cur_len shoud go to 2, not 1) */
-+ if (prv_len % 2 == 1) ++cur_len;
-+ cur_idx = prv_pos + (cur_len * adj);
-+ if (cur_idx < 0) cur_idx = 0;
-+ else if (cur_idx >= tmap_len) cur_idx = tmap_len - 1;
-+ cur_sector = 0;
-+ result = dvdnav_tmap_get_entry(tmap, tmap_len, cur_idx, &cur_sector);
-+ if (!result) return 0;
-+ if (find_sector < cur_sector) adj = -1;
-+ else if (find_sector > cur_sector) adj = 1;
-+ else if (find_sector == cur_sector) {
-+ *tmap_idx = cur_idx;
-+ *sector = cur_sector;
-+ return 1;
-+ }
-+ if (cur_len == 1) {/* no smaller intervals left */
-+ if (adj == -1) {/* last comparison was greater; take lesser */
-+ if (cur_idx == 0) { /* fake tmap index for sector 0 */
-+ cur_idx = TMAP_IDX_EDGE_BGN;
-+ cur_sector = 0;
-+ }
-+ else {
-+ cur_idx -= 1;
-+ result = dvdnav_tmap_get_entry(tmap, tmap_len, cur_idx, &cur_sector);
-+ if (!result) return 0;
-+ }
-+ }
-+ *tmap_idx = cur_idx;
-+ *sector = cur_sector;
-+ return 1;
-+ }
-+ prv_len = cur_len;
-+ prv_pos = cur_idx;
-+ }
-+}
-+
-+/* Find the cell for a given time */
-+static int32_t dvdnav_cell_find(dvdnav_t *this, dvd_state_t *state,
-+ uint64_t find_val, dvdnav_cell_data_t *cell_data) {
-+ uint32_t cells_len = 0;
-+ uint32_t cells_bgn = 0;
-+ uint32_t cells_end = 0;
-+ uint32_t cell_idx = 0;
-+ pgc_t *pgc = NULL;
-+ int pgN = 0;
-+ cell_playback_t *cell = NULL;
-+ int found = 0;
-+
-+ pgc = state->pgc;
-+ if (pgc == NULL) return 0;
-+ cells_len = pgc->nr_of_cells;
-+ if (cells_len == 0) {
-+ fprintf(MSG_OUT, "cells_len == 0");
-+ return 0;
-+ }
-+
-+ /* get cells_bgn, cells_end */
-+ if (this->pgc_based) {
-+ cells_bgn = 1;
-+ cells_end = cells_len;
-+ }
-+ else {
-+ pgN = state->pgN;
-+ cells_bgn = pgc->program_map[pgN - 1]; /* -1 b/c pgN is 1 based? */
-+ if (pgN < pgc->nr_of_programs) {
-+ cells_end = pgc->program_map[pgN] - 1;
-+ }
-+ else {
-+ cells_end = cells_len;
-+ }
-+ }
-+
-+ /* search cells */
-+ for (cell_idx = cells_bgn; cell_idx <= cells_end; cell_idx++) {
-+ cell = &(pgc->cell_playback[cell_idx - 1]); /* -1 b/c cell is base1 */
-+ /* if angle block, only consider first angleBlock
-+ * (others are "redundant" for purpose of search) */
-+ if ( cell->block_type == BLOCK_TYPE_ANGLE_BLOCK
-+ && cell->block_mode != BLOCK_MODE_FIRST_CELL) {
-+ continue;
-+ }
-+ cell_data->bgn->sector = cell->first_sector;
-+ cell_data->end->sector = cell->last_sector;
-+
-+ /* 90 pts to ms */
-+ cell_data->end->time += (dvdnav_convert_time(&cell->playback_time) / 90);
-+ if ( find_val >= cell_data->bgn->time
-+ && find_val <= cell_data->end->time) {
-+ found = 1;
-+ break;
-+ }
-+ cell_data->bgn->time = cell_data->end->time;
-+ }
-+
-+ /* found cell: set var */
-+ if (found) {
-+ cell_data->idx = cell_idx;
-+ }
-+ else
-+ fprintf(MSG_OUT, "cell not found; find=%"PRId64"", find_val);
-+ return found;
-+}
-+
-+/* Given two sectors and a fraction, calc the corresponding vobu */
-+static int32_t dvdnav_admap_interpolate_vobu(dvdnav_jump_args_t *args,
-+ dvdnav_pos_data_t *bgn, dvdnav_pos_data_t *end, uint32_t fraction,
-+ uint32_t *jump_sector) {
-+ int32_t result = 0;
-+ uint32_t vobu_len = 0;
-+ uint32_t vobu_adj = 0;
-+ uint32_t vobu_idx = 0;
-+
-+ /* get bgn->vobu_idx */
-+ result = dvdnav_admap_search(args->admap, args->admap_len,
-+ bgn->sector, &bgn->vobu_idx);
-+ if (!result) {
-+ fprintf(MSG_OUT, "admap_interpolate: could not find sector_bgn");
-+ return 0;
-+ }
-+
-+ /* get end->vobu_idx */
-+ result = dvdnav_admap_search(args->admap, args->admap_len,
-+ end->sector, &end->vobu_idx);
-+ if (!result) {
-+ fprintf(MSG_OUT, "admap_interpolate: could not find sector_end");
-+ return 0;
-+ }
-+
-+ vobu_len = end->vobu_idx - bgn->vobu_idx;
-+ /* +500 to round up else 74% of a 4 sec interval = 2 sec */
-+ vobu_adj = ((fraction * vobu_len) + 500) / 1000;
-+ /* HACK: need to add +1, or else will land too soon (not sure why) */
-+ vobu_adj++;
-+ vobu_idx = bgn->vobu_idx + vobu_adj;
-+ if (vobu_idx >= args->admap_len) {
-+ fprintf(MSG_OUT, "admap_interpolate: vobu_idx >= admap_len");
-+ return 0;
-+ }
-+ *jump_sector = args->admap->vobu_start_sectors[vobu_idx];
-+ return 1;
-+}
-+
-+/* Given two tmap entries and a time, calc the time for the lo tmap entry */
-+static int32_t dvdnav_tmap_calc_time_for_tmap_entry(dvdnav_jump_args_t *args,
-+ dvdnav_pos_data_t *lo, dvdnav_pos_data_t *hi,
-+ dvdnav_pos_data_t *pos, uint64_t *out_time) {
-+ int32_t result = 0;
-+ uint32_t vobu_pct = 0;
-+ uint64_t time_adj = 0;
-+
-+ if (lo->sector == hi->sector) {
-+ fprintf(MSG_OUT, "lo->sector == hi->sector: %i", lo->sector);
-+ return 0;
-+ }
-+
-+ /* get vobus corresponding to lo, hi, pos */
-+ result = dvdnav_admap_search(args->admap, args->admap_len,
-+ lo->sector, &lo->vobu_idx);
-+ if (!result) {
-+ fprintf(MSG_OUT, "lo->vobu: lo->sector=%i", lo->sector);
-+ return 0;
-+ }
-+ result = dvdnav_admap_search(args->admap, args->admap_len,
-+ hi->sector, &hi->vobu_idx);
-+ if (!result) {
-+ fprintf(MSG_OUT, "hi->vobu: hi->sector=%i", hi->sector);
-+ return 0;
-+ }
-+ result = dvdnav_admap_search(args->admap, args->admap_len,
-+ pos->sector, &pos->vobu_idx);
-+ if (!result) {
-+ fprintf(MSG_OUT, "pos->vobu: pos->sector=%i", pos->sector);
-+ return 0;
-+ }
-+
-+ /* calc position of cell relative to lo */
-+ vobu_pct = ((pos->vobu_idx - lo->vobu_idx) * 1000)
-+ / ( hi->vobu_idx - lo->vobu_idx);
-+ if (vobu_pct < 0 || vobu_pct > 1000) {
-+ fprintf(MSG_OUT, "vobu_pct must be between 0 and 1000");
-+ return 0;
-+ }
-+
-+ /* calc time of lo */
-+ time_adj = (uint64_t)((args->tmap_interval * vobu_pct) / 1000);
-+ *out_time = pos->time - time_adj;
-+ return 1;
-+}
-+
-+/* Find the tmap entries on either side of a given sector */
-+static int32_t dvdnav_tmap_get_entries_for_sector(dvdnav_t *this,
-+ dvd_state_t *state, dvdnav_jump_args_t *args,
-+ dvdnav_cell_data_t *cell_data, uint32_t find_sector,
-+ dvdnav_pos_data_t *lo, dvdnav_pos_data_t *hi) {
-+ int32_t result = 0;
-+
-+ result = dvdnav_tmap_search(args->tmap, args->tmap_len, find_sector,
-+ &lo->tmap_idx, &lo->sector);
-+ if (!result) {
-+ fprintf(MSG_OUT, "could not find lo idx: %i", find_sector);
-+ return 0;
-+ }
-+
-+ /* HACK: Most DVDs have a tmap that starts at sector 0
-+ * However, some have initial dummy cells that are not seekable
-+ * (restricted = y).
-+ * These cells will throw off the tmap calcs when in the first playable cell.
-+ * For now, assume that lo->sector is equal to the cell->bgn->sector
-+ * Note that for most DVDs this will be 0
-+ * (Since they will have no dummy cells and cell 1 will start at sector 0)
-+ */
-+ if (lo->tmap_idx == TMAP_IDX_EDGE_BGN) {
-+ lo->sector = cell_data->bgn->sector;
-+ }
-+
-+ if (lo->tmap_idx == args->tmap_len - 1) {
-+ /* lo is last tmap entry; "fake" entry for one beyond
-+ * and mark it with cell_end_sector */
-+ hi->tmap_idx = TMAP_IDX_EDGE_END;
-+ hi->sector = cell_data->end->sector;
-+ }
-+ else {
-+ hi->tmap_idx = lo->tmap_idx + 1;
-+ result = dvdnav_tmap_get_entry(args->tmap, args->tmap_len,
-+ hi->tmap_idx, &hi->sector);
-+ if (!result) {
-+ fprintf(MSG_OUT, "could not find hi idx: %i", find_sector);
-+ return 0;
-+ }
-+ }
-+ return 1;
-+}
-+
-+/* Find the nearest vobu by using the tmap */
-+static int32_t dvdnav_find_vobu_by_tmap(dvdnav_t *this, dvd_state_t *state,
-+ dvdnav_jump_args_t *args, dvdnav_cell_data_t *cell_data,
-+ dvdnav_pos_data_t *jump) {
-+ uint64_t seek_offset = 0;
-+ uint32_t seek_idx = 0;
-+ int32_t result = 0;
-+ dvdnav_pos_data_t *cell_bgn_lo = NULL;
-+ dvdnav_pos_data_t *cell_bgn_hi = NULL;
-+ dvdnav_pos_data_t *jump_lo = NULL;
-+ dvdnav_pos_data_t *jump_hi = NULL;
-+
-+ /* get tmap, tmap_len, tmap_interval */
-+ args->tmap = dvdnav_tmap_get(this, state,
-+ &args->tmap_len, &args->tmap_interval);
-+ if (args->tmap == NULL) return 0;
-+
-+ /* get tmap entries on either side of cell_bgn */
-+ cell_bgn_lo = &(dvdnav_pos_data_t){0};
-+ cell_bgn_hi = &(dvdnav_pos_data_t){0};
-+ result = dvdnav_tmap_get_entries_for_sector(this, state, args, cell_data,
-+ cell_data->bgn->sector, cell_bgn_lo, cell_bgn_hi);
-+ if (!result) return 0;
-+
-+ /* calc time of cell_bgn_lo */
-+ result = dvdnav_tmap_calc_time_for_tmap_entry(args, cell_bgn_lo, cell_bgn_hi,
-+ cell_data->bgn, &cell_bgn_lo->time);
-+ if (!result) return 0;
-+
-+ /* calc time of jump_time relative to cell_bgn_lo */
-+ seek_offset = jump->time - cell_bgn_lo->time;
-+ seek_idx = (uint32_t)(seek_offset / args->tmap_interval);
-+ uint32_t seek_remainder = seek_offset - (seek_idx * args->tmap_interval);
-+ uint32_t seek_pct = (seek_remainder * 1000) / args->tmap_interval;
-+
-+ /* get tmap entries on either side of jump_time */
-+ jump_lo = &(dvdnav_pos_data_t){0};
-+ jump_hi = &(dvdnav_pos_data_t){0};
-+
-+ /* if seek_idx == 0, then tmap_indexes are the same, do not re-get
-+ * also, note cell_bgn_lo will already have sector if TMAP_IDX_EDGE_BGN */
-+ if (seek_idx == 0) {
-+ jump_lo = cell_bgn_lo;
-+ jump_hi = cell_bgn_hi;
-+ }
-+ else {
-+ jump_lo->tmap_idx = (uint32_t)(cell_bgn_lo->tmap_idx + seek_idx);
-+ result = dvdnav_tmap_get_entry(args->tmap, args->tmap_len,
-+ jump_lo->tmap_idx, &jump_lo->sector);
-+ if (!result) return 0;
-+
-+ /* +1 handled by dvdnav_tmap_get_entry */
-+ jump_hi->tmap_idx = jump_lo->tmap_idx + 1;
-+ result = dvdnav_tmap_get_entry(args->tmap, args->tmap_len,
-+ jump_hi->tmap_idx, &jump_hi->sector);
-+ if (!result) return 0;
-+ }
-+
-+ /* interpolate sector */
-+ result = dvdnav_admap_interpolate_vobu(args, jump_lo, jump_hi,
-+ seek_pct, &jump->sector);
-+
-+ return result;
-+}
-+
-+/* Find the nearest vobu by using the cell boundaries */
-+static int32_t dvdnav_find_vobu_by_cell_boundaries(dvdnav_t *this,
-+ dvdnav_jump_args_t *args, dvdnav_cell_data_t *cell_data,
-+ dvdnav_pos_data_t *jump) {
-+ uint64_t jump_offset = 0;
-+ uint64_t cell_len = 0;
-+ uint32_t jump_pct = 0;
-+ int32_t result = 0;
-+
-+ /* get jump_offset */
-+ jump_offset = jump->time - cell_data->bgn->time;
-+ if (jump_offset < 0) {
-+ fprintf(MSG_OUT, "jump_offset < 0");
-+ return 0;
-+ }
-+ cell_len = cell_data->end->time - cell_data->bgn->time;
-+ if (cell_len < 0) {
-+ fprintf(MSG_OUT, "cell_len < 0");
-+ return 0;
-+ }
-+ jump_pct = (jump_offset * 1000) / cell_len;
-+
-+ /* get sector */
-+ /* NOTE: end cell sector in VTS_PGC is last sector of cell
-+ * this last sector is not the start of a VOBU
-+ * +1 to get sector that is the start of a VOBU
-+ * start of a VOBU is needed in order to index into admap */
-+ cell_data->end->sector += 1;
-+ result = dvdnav_admap_interpolate_vobu(args,
-+ cell_data->bgn, cell_data->end, jump_pct, &jump->sector);
-+ if (!result) {
-+ fprintf(MSG_OUT, "find_by_admap.interpolate");
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+/* Jump to sector by time */
-+/* NOTE: Mode is currently unimplemented. Only 0 should be passed. */
-+/* 1 and -1 are for future implementation */
-+/* 0: Default. Jump to a time which may be either <> time_in_pts_ticks */
-+/* 1: After. Always jump to a time that is > time_in_pts_ticks */
-+/* -1: Before. Always jump to a time that is < time_in_pts_ticks */
-+dvdnav_status_t dvdnav_jump_to_sector_by_time(dvdnav_t *this,
-+ uint64_t time_in_pts_ticks, int32_t mode) {
-+ if (mode != JUMP_MODE_TIME_DEFAULT) return DVDNAV_STATUS_ERR;
-+ int32_t result = DVDNAV_STATUS_ERR;
-+ dvd_state_t *state = NULL;
-+ uint32_t sector_off = 0;
-+ dvdnav_pos_data_t *jump = NULL;
-+ dvdnav_cell_data_t *cell_data = NULL;
-+ dvdnav_jump_args_t *args = NULL;
-+
-+ jump = &(dvdnav_pos_data_t){0};
-+ /* convert time to milliseconds */
-+ jump->time = time_in_pts_ticks / 90;
-+
-+ /* get variables that will be used across both functions */
-+ state = &(this->vm->state);
-+ if (state == NULL) goto exit;
-+
-+ /* get cell info */
-+ cell_data = &(dvdnav_cell_data_t){0};
-+ cell_data->bgn = &(dvdnav_pos_data_t){0};
-+ cell_data->end = &(dvdnav_pos_data_t){0};
-+ result = dvdnav_cell_find(this, state, jump->time, cell_data);
-+ if (!result) goto exit;
-+
-+ /* get admap */
-+ args = &(dvdnav_jump_args_t){0};
-+ args->admap = dvdnav_admap_get(this, state, &args->admap_len);
-+ if (args->admap == NULL) goto exit;
-+
-+ /* find sector */
-+ result = dvdnav_find_vobu_by_tmap(this, state, args, cell_data, jump);
-+ if (!result) {/* bad tmap; interpolate over cell */
-+ result = dvdnav_find_vobu_by_cell_boundaries(this, args, cell_data, jump);
-+ if (!result) {
-+ goto exit;
-+ }
-+ }
-+
-+#ifdef LOG_DEBUG
-+ fprintf(MSG_OUT, "libdvdnav: seeking to time=%lu\n", jump->time);
-+ fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, state->blockN);
-+#endif
-+
-+ /* jump to sector */
-+ sector_off = jump->sector - cell_data->bgn->sector;
-+ this->cur_cell_time = 0;
-+ if (vm_jump_cell_block(this->vm, cell_data->idx, sector_off)) {
-+ pthread_mutex_lock(&this->vm_lock);
-+ this->vm->hop_channel += HOP_SEEK;
-+ pthread_mutex_unlock(&this->vm_lock);
-+ result = DVDNAV_STATUS_OK;
-+ }
-+
-+#ifdef LOG_DEBUG
-+ fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u\n", state->cellN, state->blockN);
-+#endif
-+
-+exit:
-+ return result;
-+}