diff options
author | Joachim Breuer <git@jmbreuer.net> | 2013-07-11 09:17:14 +0200 |
---|---|---|
committer | Joachim Breuer <git@jmbreuer.net> | 2013-07-13 09:05:24 +0200 |
commit | 24d9d5005652410baf200599a9ba966d66b90e44 (patch) | |
tree | 188692aac7152b8de03a22443a3fe4a881156c77 /lib | |
parent | cc0ebb6db6f615dcb14e79b4b797bb3e711d669b (diff) |
Add diff in lib/libdvd/patches for tracking against upstream
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libdvd/patches/libdvdnav-accurate_seek.diff | 677 |
1 files changed, 677 insertions, 0 deletions
diff --git a/lib/libdvd/patches/libdvdnav-accurate_seek.diff b/lib/libdvd/patches/libdvdnav-accurate_seek.diff new file mode 100644 index 0000000000..a97dccee68 --- /dev/null +++ b/lib/libdvd/patches/libdvdnav-accurate_seek.diff @@ -0,0 +1,677 @@ +More accurate seeking with libdvdnav + +applied to current codebase from: + http://lists.mplayerhq.hu/pipermail/dvdnav-discuss/2011-November/001612.html + +full credit goes to gnosygnu, see + http://forum.videolan.org/viewtopic.php?f=32&t=76308&start=20#p316583 + +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..ca3f720 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); ++ ++/* + * 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..c60752f 100644 +--- a/libdvdnav/src/dvdnav_internal.h ++++ b/libdvdnav/src/dvdnav_internal.h +@@ -125,6 +125,42 @@ 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 ++ + 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..2df7212 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,586 @@ 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 sector */ ++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; ++} ++ ++dvdnav_status_t dvdnav_jump_to_sector_by_time(dvdnav_t *this, ++ uint64_t time_in_pts_ticks) { ++ int32_t result = 1; ++ 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 = 1; ++ } ++ ++#ifdef LOG_DEBUG ++ fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u\n", state->cellN, state->blockN); ++#endif ++ ++exit: ++ return result; ++} |