📄 dvdnav.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: dvdnav.c,v 1.34 2005/10/15 14:04:05 jcdutton Exp $ * */#ifdef HAVE_CONFIG_H#include "config.h"#endif/*#define LOG_DEBUG*/#include "dvdnav_internal.h"#include "read_cache.h"#include "nav_read.h"#include <stdlib.h>#include <stdio.h>#include <sys/time.h>#include "remap.h"static dvdnav_status_t dvdnav_clear(dvdnav_t * this) { /* clear everything except file, vm, mutex, readahead */ if (this->file) DVDCloseFile(this->file); this->file = NULL; memset(&this->pci,0,sizeof(this->pci)); memset(&this->dsi,0,sizeof(this->dsi)); this->last_cmd_nav_lbn = SRI_END_OF_CELL; /* Set initial values of flags */ this->position_current.still = 0; this->skip_still = 0; this->sync_wait = 0; this->sync_wait_skip = 0; this->spu_clut_changed = 0; this->started = 0; dvdnav_read_cache_clear(this->cache); return DVDNAV_STATUS_OK;}dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) { dvdnav_t *this; struct timeval time; /* Create a new structure */ fprintf(MSG_OUT, "libdvdnav: Using dvdnav version %s from http://xine.sf.net\n", VERSION); (*dest) = NULL; this = (dvdnav_t*)malloc(sizeof(dvdnav_t)); if(!this) return DVDNAV_STATUS_ERR; memset(this, 0, (sizeof(dvdnav_t) ) ); /* Make sure this structure is clean */ pthread_mutex_init(&this->vm_lock, NULL); /* Initialise the error string */ printerr(""); /* Initialise the VM */ this->vm = vm_new_vm(); if(!this->vm) { printerr("Error initialising the DVD VM."); pthread_mutex_destroy(&this->vm_lock); free(this); return DVDNAV_STATUS_ERR; } if(!vm_reset(this->vm, path)) { printerr("Error starting the VM / opening the DVD device."); pthread_mutex_destroy(&this->vm_lock); vm_free_vm(this->vm); free(this); return DVDNAV_STATUS_ERR; } /* Set the path. FIXME: Is a deep copy 'right' */ strncpy(this->path, path, MAX_PATH_LEN); /* Pre-open and close a file so that the CSS-keys are cached. */ this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), 0, DVD_READ_MENU_VOBS); /* Start the read-ahead cache. */ this->cache = dvdnav_read_cache_new(this); /* Seed the random numbers. So that the DVD VM Command rand() * gives a different start value each time a DVD is played. */ gettimeofday(&time, NULL); srand(time.tv_usec); dvdnav_clear(this); (*dest) = this; return DVDNAV_STATUS_OK;}dvdnav_status_t dvdnav_close(dvdnav_t *this) {#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: close:called\n");#endif if(!this) { printerr("Passed a NULL pointer."); return DVDNAV_STATUS_ERR; } if (this->file) { DVDCloseFile(this->file);#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: close:file closing\n");#endif this->file = NULL; } /* Free the VM */ if(this->vm) vm_free_vm(this->vm); pthread_mutex_destroy(&this->vm_lock); /* We leave the final freeing of the entire structure to the cache, * because we don't know, if there are still buffers out in the wild, * that must return first. */ if(this->cache) dvdnav_read_cache_free(this->cache); else free(this); return DVDNAV_STATUS_OK;}dvdnav_status_t dvdnav_reset(dvdnav_t *this) { dvdnav_status_t result;#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: reset:called\n");#endif if(!this) { printerr("Passed a NULL pointer."); return DVDNAV_STATUS_ERR; } pthread_mutex_lock(&this->vm_lock); #ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: reseting vm\n");#endif if(!vm_reset(this->vm, NULL)) { printerr("Error restarting the VM."); pthread_mutex_unlock(&this->vm_lock); return DVDNAV_STATUS_ERR; }#ifdef LOG_DEBUG fprintf(MSG_OUT, "libdvdnav: clearing dvdnav\n");#endif result = dvdnav_clear(this); pthread_mutex_unlock(&this->vm_lock); return result;}dvdnav_status_t dvdnav_path(dvdnav_t *this, const char** path) { if(!this || !path) { printerr("Passed a NULL pointer."); return DVDNAV_STATUS_ERR; } (*path) = this->path; return DVDNAV_STATUS_OK;}const char* dvdnav_err_to_string(dvdnav_t *this) { if(!this) return "Hey! You gave me a NULL pointer you naughty person!"; return this->err_str;}/* converts a dvd_time_t to PTS ticks */int64_t dvdnav_convert_time(dvd_time_t *time) { int64_t result; int64_t frames; result = (time->hour >> 4 ) * 10 * 60 * 60 * 90000; result += (time->hour & 0x0f) * 60 * 60 * 90000; result += (time->minute >> 4 ) * 10 * 60 * 90000; result += (time->minute & 0x0f) * 60 * 90000; result += (time->second >> 4 ) * 10 * 90000; result += (time->second & 0x0f) * 90000; frames = ((time->frame_u & 0x30) >> 4) * 10; frames += ((time->frame_u & 0x0f) ) ; if (time->frame_u & 0x80) result += frames * 3000; else result += frames * 3600; return result;}/* * Returns 1 if block contains NAV packet, 0 otherwise. * Processes said NAV packet if present. * * Most of the code in here is copied from xine's MPEG demuxer * so any bugs which are found in that should be corrected here also. */static int32_t dvdnav_decode_packet(dvdnav_t *this, uint8_t *p, dsi_t *nav_dsi, pci_t *nav_pci) { int32_t bMpeg1 = 0; uint32_t nHeaderLen; uint32_t nPacketLen; uint32_t nStreamID; if (p[3] == 0xBA) { /* program stream pack header */ int32_t nStuffingBytes; bMpeg1 = (p[4] & 0x40) == 0; if (bMpeg1) { p += 12; } else { /* mpeg2 */ nStuffingBytes = p[0xD] & 0x07; p += 14 + nStuffingBytes; } } if (p[3] == 0xbb) { /* program stream system header */ nHeaderLen = (p[4] << 8) | p[5]; p += 6 + nHeaderLen; } /* we should now have a PES packet here */ if (p[0] || p[1] || (p[2] != 1)) { fprintf(MSG_OUT, "libdvdnav: demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]); return 0; } nPacketLen = p[4] << 8 | p[5]; nStreamID = p[3]; nHeaderLen = 6; p += nHeaderLen; if (nStreamID == 0xbf) { /* Private stream 2 */#if 0 int32_t i; fprintf(MSG_OUT, "libdvdnav: nav packet=%u\n",p-p_start-6); for(i=0;i<80;i++) fprintf(MSG_OUT, "%02x ",p[i-6]); fprintf(MSG_OUT, "\n");#endif if(p[0] == 0x00) { navRead_PCI(nav_pci, p+1); } p += nPacketLen; /* We should now have a DSI packet. */ if(p[6] == 0x01) { nPacketLen = p[4] << 8 | p[5]; p += 6; navRead_DSI(nav_dsi, p+1); } return 1; } return 0;}/* DSI is used for most angle stuff. * PCI is used for only non-seemless angle stuff */ static int32_t dvdnav_get_vobu(dvdnav_t *this, dsi_t *nav_dsi, pci_t *nav_pci, dvdnav_vobu_t *vobu) { uint32_t next; int32_t angle, num_angle; vobu->vobu_start = nav_dsi->dsi_gi.nv_pck_lbn; /* Absolute offset from start of disk */ vobu->vobu_length = nav_dsi->dsi_gi.vobu_ea; /* Relative offset from vobu_start */ /* * If we're not at the end of this cell, we can determine the next * VOBU to display using the VOBU_SRI information section of the * DSI. Using this value correctly follows the current angle, * avoiding the doubled scenes in The Matrix, and makes our life * really happy. * * vobu_next is an offset value, 0x3fffffff = SRI_END_OF_CELL * DVDs are about 6 Gigs, which is only up to 0x300000 blocks * Should really assert if bit 31 != 1 */ #if 0 /* Old code -- may still be useful one day */ if(nav_dsi->vobu_sri.next_vobu != SRI_END_OF_CELL ) { vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff ); } else { vobu->vobu_next = vobu->vobu_length; }#else /* Relative offset from vobu_start */ vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff );#endif vm_get_angle_info(this->vm, &angle, &num_angle); /* FIMXE: The angle reset doesn't work for some reason for the moment */#if 0 if((num_angle < angle) && (angle != 1)) { fprintf(MSG_OUT, "libdvdnav: angle ends!\n"); /* This is to switch back to angle one when we * finish with angles. */ dvdnav_angle_change(this, 1); } #endif if(num_angle != 0) { if((next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1]) != 0) { if((next & 0x3fffffff) != 0) { if(next & 0x80000000) vobu->vobu_next = - (int32_t)(next & 0x3fffffff); else vobu->vobu_next = + (int32_t)(next & 0x3fffffff); } } else if((next = nav_dsi->sml_agli.data[angle-1].address) != 0) { vobu->vobu_length = nav_dsi->sml_pbi.ilvu_ea; if((next & 0x80000000) && (next != 0x7fffffff)) vobu->vobu_next = - (int32_t)(next & 0x3fffffff); else vobu->vobu_next = + (int32_t)(next & 0x3fffffff); } } return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -