diff options
author | Joachim Breuer <git@jmbreuer.net> | 2013-07-09 18:23:35 +0200 |
---|---|---|
committer | Joachim Breuer <git@jmbreuer.net> | 2013-07-13 09:05:24 +0200 |
commit | cc0ebb6db6f615dcb14e79b4b797bb3e711d669b (patch) | |
tree | 0223f90f105b09dac5f11cf68e6df3e41bcee8fb /lib/libdvd | |
parent | 296093925468c2d40d433d4e66a07e0ee6fb12e5 (diff) |
More accurate seeking with libdvdnav
http://trac.xbmc.org/ticket/12212 applied to current codebase
full credit should go to gnosygnu, see
http://forum.videolan.org/viewtopic.php?f=32&t=76308&start=20#p316583
Diffstat (limited to 'lib/libdvd')
-rw-r--r-- | lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h | 8 | ||||
-rw-r--r-- | lib/libdvd/libdvdnav/src/dvdnav_internal.h | 36 | ||||
-rw-r--r-- | lib/libdvd/libdvdnav/src/searching.c | 584 |
3 files changed, 628 insertions, 0 deletions
diff --git a/lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h b/lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h index 359b951aad..ca3f720ba3 100644 --- a/lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h +++ b/lib/libdvd/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/lib/libdvd/libdvdnav/src/dvdnav_internal.h b/lib/libdvd/libdvdnav/src/dvdnav_internal.h index d64a5ba7cd..c60752fdf0 100644 --- a/lib/libdvd/libdvdnav/src/dvdnav_internal.h +++ b/lib/libdvd/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/lib/libdvd/libdvdnav/src/searching.c b/lib/libdvd/libdvdnav/src/searching.c index a5e48fe7da..2df7212d3b 100644 --- a/lib/libdvd/libdvdnav/src/searching.c +++ b/lib/libdvd/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; +} |