📄 searching.c
字号:
/* * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net> * * This file is part of libdvdnav, a DVD navigation library. * * libdvdnav is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * libdvdnav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * $Id: searching.c,v 1.20 2006/09/17 13:01:08 valtri Exp $ * */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <assert.h>#include "dvdnav_internal.h"#include "dvdnav.h"/*#define LOG_DEBUG*//* Searching API calls *//* Scan the ADMAP for a particular block number. *//* Return placed in vobu. *//* Returns error status *//* FIXME: Maybe need to handle seeking outside current cell. */static dvdnav_status_t dvdnav_scan_admap(dvdnav_t *this, int32_t domain, uint32_t seekto_block, uint32_t *vobu) { vobu_admap_t *admap = NULL;#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: Seeking to target %u ...\n", seekto_block);#endif *vobu = -1; /* Search through the VOBU_ADMAP for the nearest VOBU * to the target block */ switch(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, "libdvdnav: Error: Unknown domain for seeking.\n"); } if(admap) { uint32_t address = 0; uint32_t vobu_start, next_vobu; int32_t found = 0; /* Search through ADMAP for best sector */ vobu_start = SRI_END_OF_CELL; /* FIXME: Implement a faster search algorithm */ while((!found) && ((address<<2) < admap->last_byte)) { next_vobu = admap->vobu_start_sectors[address]; /* fprintf(MSG_OUT, "libdvdnav: Found block %u\n", next_vobu); */ if(vobu_start <= seekto_block && next_vobu > seekto_block) { found = 1; } else { vobu_start = next_vobu; } address ++; } if(found) { *vobu = vobu_start; return DVDNAV_STATUS_OK; } else { fprintf(MSG_OUT, "libdvdnav: Could not locate block\n"); return DVDNAV_STATUS_ERR; } } fprintf(MSG_OUT, "libdvdnav: admap not located\n"); return DVDNAV_STATUS_ERR;}dvdnav_status_t dvdnav_time_search(dvdnav_t *this, uint64_t time) { uint64_t target = time; uint64_t length = 0; uint32_t first_cell_nr, last_cell_nr, cell_nr; int32_t found; cell_playback_t *cell; dvd_state_t *state; if(this->position_current.still != 0) { printerr("Cannot seek in a still frame."); return DVDNAV_STATUS_ERR; } pthread_mutex_lock(&this->vm_lock); state = &(this->vm->state); if(!state->pgc) { printerr("No current PGC."); pthread_mutex_unlock(&this->vm_lock); return DVDNAV_STATUS_ERR; } if (this->pgc_based) { first_cell_nr = 1; last_cell_nr = state->pgc->nr_of_cells; } else { /* Find start cell of program. */ first_cell_nr = state->pgc->program_map[state->pgN-1]; /* Find end cell of program */ if(state->pgN < state->pgc->nr_of_programs) last_cell_nr = state->pgc->program_map[state->pgN] - 1; else last_cell_nr = state->pgc->nr_of_cells; } found = 0; for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr) && !found; cell_nr ++) { cell = &(state->pgc->cell_playback[cell_nr-1]); length = dvdnav_convert_time(&cell->playback_time); if (target >= length) { target -= length; } else { /* FIXME: there must be a better way than interpolation */ target = target * (cell->last_sector - cell->first_sector + 1) / length; target += cell->first_sector; found = 1; break; } } if(found) { int32_t vobu;#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n", cell_nr, first_cell_nr, last_cell_nr);#endif if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) { int32_t start = state->pgc->cell_playback[cell_nr-1].first_sector; if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) {#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" , state->cellN, state->blockN, target, vobu, start);#endif this->vm->hop_channel += HOP_SEEK; pthread_mutex_unlock(&this->vm_lock); return DVDNAV_STATUS_OK; } } } fprintf(MSG_OUT, "libdvdnav: Error when seeking\n"); printerr("Error when seeking."); pthread_mutex_unlock(&this->vm_lock); return DVDNAV_STATUS_ERR;}dvdnav_status_t dvdnav_sector_search(dvdnav_t *this, uint64_t offset, int32_t origin) { uint32_t target = 0; uint32_t length = 0; uint32_t first_cell_nr, last_cell_nr, cell_nr; int32_t found; cell_playback_t *cell; dvd_state_t *state; dvdnav_status_t result; if(this->position_current.still != 0) { printerr("Cannot seek in a still frame."); return DVDNAV_STATUS_ERR; } result = dvdnav_get_position(this, &target, &length); if(!result) { return DVDNAV_STATUS_ERR; } pthread_mutex_lock(&this->vm_lock); state = &(this->vm->state); if(!state->pgc) { printerr("No current PGC."); pthread_mutex_unlock(&this->vm_lock); return DVDNAV_STATUS_ERR; }#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: seeking to offset=%lu pos=%u length=%u\n", offset, target, length); fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, state->blockN);#endif switch(origin) { case SEEK_SET: if(offset > length) { printerr("Request to seek behind end."); pthread_mutex_unlock(&this->vm_lock); return DVDNAV_STATUS_ERR; } target = offset; break; case SEEK_CUR: if(target + offset > length) { printerr("Request to seek behind end."); pthread_mutex_unlock(&this->vm_lock); return DVDNAV_STATUS_ERR; } target += offset; break; case SEEK_END: if(length - offset < 0) { printerr("Request to seek before start."); pthread_mutex_unlock(&this->vm_lock); return DVDNAV_STATUS_ERR; } target = length - offset; break; default: /* Error occured */ printerr("Illegal seek mode."); pthread_mutex_unlock(&this->vm_lock); return DVDNAV_STATUS_ERR; } if (this->pgc_based) { first_cell_nr = 1; last_cell_nr = state->pgc->nr_of_cells; } else { /* Find start cell of program. */ first_cell_nr = state->pgc->program_map[state->pgN-1]; /* Find end cell of program */ if(state->pgN < state->pgc->nr_of_programs) last_cell_nr = state->pgc->program_map[state->pgN] - 1; else last_cell_nr = state->pgc->nr_of_cells; } found = 0; for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr) && !found; cell_nr ++) { cell = &(state->pgc->cell_playback[cell_nr-1]); length = cell->last_sector - cell->first_sector + 1; if (target >= length) { target -= length; } else { /* convert the target sector from Cell-relative to absolute physical sector */ target += cell->first_sector; found = 1; break; } } if(found) { int32_t vobu;#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n", cell_nr, first_cell_nr, last_cell_nr);#endif if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) { int32_t start = state->pgc->cell_playback[cell_nr-1].first_sector; if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) {#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" , state->cellN, state->blockN, target, vobu, start);#endif this->vm->hop_channel += HOP_SEEK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -