diff options
Diffstat (limited to 'lib/libdvd/patches/libdvdnav-accurate_seek.diff')
-rw-r--r-- | lib/libdvd/patches/libdvdnav-accurate_seek.diff | 689 |
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; -+} |