Mercurial > mplayer.hg
changeset 15874:483e955893b8
update libdvdread to v0.9.4
author | aurel |
---|---|
date | Thu, 30 Jun 2005 22:48:26 +0000 |
parents | 276da0bb6207 |
children | 50960b929dd0 |
files | libmpdvdkit2/Makefile libmpdvdkit2/README libmpdvdkit2/bswap.h libmpdvdkit2/config.h libmpdvdkit2/dvd_input.c libmpdvdkit2/dvd_input.h libmpdvdkit2/dvd_reader.c libmpdvdkit2/dvd_reader.h libmpdvdkit2/dvd_udf.c libmpdvdkit2/dvd_udf.h libmpdvdkit2/ifo_print.c libmpdvdkit2/ifo_print.h libmpdvdkit2/ifo_read.c libmpdvdkit2/ifo_read.h libmpdvdkit2/ifo_types.h libmpdvdkit2/nav_print.c libmpdvdkit2/nav_print.h libmpdvdkit2/nav_read.c libmpdvdkit2/nav_read.h libmpdvdkit2/nav_types.h |
diffstat | 20 files changed, 1994 insertions(+), 617 deletions(-) [+] |
line wrap: on
line diff
--- a/libmpdvdkit2/Makefile Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/Makefile Thu Jun 30 22:48:26 2005 +0000 @@ -15,6 +15,7 @@ libdvdcss.c \ nav_print.c \ nav_read.c \ + md5.c \ #bsdi_ioctl.c @@ -34,7 +35,8 @@ # -funroll-loops removed, triggered gcc 3.0.4 (3.x?) bug CFLAGS= -I. $(OPTFLAGS) $(EXTRA_INC)\ - -DSYS_LINUX -D__USE_UNIX98 -D_REENTRANT -D_GNU_SOURCE + -DSYS_LINUX -D__USE_UNIX98 -D_REENTRANT -D_GNU_SOURCE \ + -DHAVE_DVDCSS_DVDCSS_H -DSTDC_HEADERS .c.o: $(CC) $(CFLAGS) -c -o $@ $<
--- a/libmpdvdkit2/README Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/README Thu Jun 30 22:48:26 2005 +0000 @@ -1,12 +1,12 @@ -MPlayer DVD-kit v2.2 :) +MPlayer DVD-kit v2.3 :) made by Pontscho & A'rpi for the MPlayer project What the hell is this? ====================== Nothing special, just a collection of sources and patches and fixes: -- dvdread 0.9.3 + static libdvdcss (removed dlopen code) -- libdvdcss 1.2.5 +- dvdread 0.9.4 + static libdvdcss +- libdvdcss 1.2.8 - optimizations enabled, asserts disabled everything packed together with _static_ linking to maximize performance.
--- a/libmpdvdkit2/bswap.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/bswap.h Thu Jun 30 22:48:26 2005 +0000 @@ -32,6 +32,11 @@ #else +/* For __FreeBSD_version */ +#if defined(HAVE_SYS_PARAM_H) +#include <sys/param.h> +#endif + #if defined(__linux__) #include <byteswap.h> #define B2N_16(x) x = bswap_16(x) @@ -50,6 +55,18 @@ #define B2N_32(x) x = swap32(x) #define B2N_64(x) x = swap64(x) +#elif defined(__FreeBSD__) && __FreeBSD_version >= 470000 +#include <sys/endian.h> +#define B2N_16(x) x = be16toh(x) +#define B2N_32(x) x = be32toh(x) +#define B2N_64(x) x = be64toh(x) + +#elif defined(__DragonFly__) +#include <sys/endian.h> +#define B2N_16(x) x = be16toh(x) +#define B2N_32(x) x = be32toh(x) +#define B2N_64(x) x = be64toh(x) + #elif defined(ARCH_X86) inline static unsigned short bswap_16(unsigned short x) { @@ -88,17 +105,12 @@ } #define B2N_64(x) x = bswap_64(x) -#elif defined(__DragonFly__) -#include <sys/endian.h> -#define B2N_16(x) x = be16toh(x) -#define B2N_32(x) x = be32toh(x) -#define B2N_64(x) x = be64toh(x) - /* This is a slow but portable implementation, it has multiple evaluation * problems so beware. - * FreeBSD and Solaris don't have <byteswap.h> or any other such + * Old FreeBSD's and Solaris don't have <byteswap.h> or any other such * functionality! */ + #elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(__CYGWIN__) #define B2N_16(x) \ x = ((((x) & 0xff00) >> 8) | \
--- a/libmpdvdkit2/config.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/config.h Thu Jun 30 22:48:26 2005 +0000 @@ -1,6 +1,6 @@ /* Version number of package */ -#define VERSION "1.2.2" +#define VERSION "1.2.3" #define HAVE_UNISTD_H 1 /* Define if your processor stores words with the most significant
--- a/libmpdvdkit2/dvd_input.c Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/dvd_input.c Thu Jun 30 22:48:26 2005 +0000 @@ -21,6 +21,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ +#include "config.h" + #include <stdio.h> #include <stdlib.h> #include <fcntl.h> @@ -29,21 +31,34 @@ #include "dvd_reader.h" #include "dvd_input.h" -#include "dvdcss.h" +/* The function pointers that is the exported interface of this file. */ +dvd_input_t (*dvdinput_open) (const char *); +int (*dvdinput_close) (dvd_input_t); +int (*dvdinput_seek) (dvd_input_t, int); +int (*dvdinput_title) (dvd_input_t, int); +int (*dvdinput_read) (dvd_input_t, void *, int, int); +char * (*dvdinput_error) (dvd_input_t); -dvdcss_handle (*DVDcss_open) (const char *); -int (*DVDcss_close) (dvdcss_handle); -int (*DVDcss_seek) (dvdcss_handle, int, int); -int (*DVDcss_title) (dvdcss_handle, int); -int (*DVDcss_read) (dvdcss_handle, void *, int, int); -char * (*DVDcss_error) (dvdcss_handle); - -dvd_input_t (*DVDinput_open) (const char *); -int (*DVDinput_close) (dvd_input_t); -int (*DVDinput_seek) (dvd_input_t, int, int); -int (*DVDinput_title) (dvd_input_t, int); -int (*DVDinput_read) (dvd_input_t, void *, int, int); -char * (*DVDinput_error) (dvd_input_t); +#ifdef HAVE_DVDCSS_DVDCSS_H +/* linking to libdvdcss */ +#include "dvdcss.h" +#define DVDcss_open(a) dvdcss_open((char*)(a)) +#define DVDcss_close dvdcss_close +#define DVDcss_seek dvdcss_seek +#define DVDcss_title dvdcss_title +#define DVDcss_read dvdcss_read +#define DVDcss_error dvdcss_error +#else +/* dlopening libdvdcss */ +#include <dlfcn.h> +typedef struct dvdcss_s *dvdcss_handle; +static dvdcss_handle (*DVDcss_open) (const char *); +static int (*DVDcss_close) (dvdcss_handle); +static int (*DVDcss_seek) (dvdcss_handle, int, int); +static int (*DVDcss_title) (dvdcss_handle, int); +static int (*DVDcss_read) (dvdcss_handle, void *, int, int); +static char * (*DVDcss_error) (dvdcss_handle); +#endif /* The DVDinput handle, add stuff here for new input methods. */ struct dvd_input_s { @@ -61,7 +76,7 @@ static dvd_input_t css_open(const char *target) { dvd_input_t dev; - + /* Allocate the handle structure */ dev = (dvd_input_t) malloc(sizeof(struct dvd_input_s)); if(dev == NULL) { @@ -72,7 +87,7 @@ /* Really open it with libdvdcss */ dev->dvdcss = DVDcss_open(target); if(dev->dvdcss == 0) { - fprintf(stderr, "libdvdread: Could not open device with libdvdcss.\n"); + fprintf(stderr, "libdvdread: Could not open %s with libdvdcss.\n", target); free(dev); return NULL; } @@ -91,9 +106,10 @@ /** * seek into the device. */ -static int css_seek(dvd_input_t dev, int blocks, int flags) +static int css_seek(dvd_input_t dev, int blocks) { - return DVDcss_seek(dev->dvdcss, blocks, flags); + /* DVDINPUT_NOFLAGS should match the DVDCSS_NOFLAGS value. */ + return DVDcss_seek(dev->dvdcss, blocks, DVDINPUT_NOFLAGS); } /** @@ -131,34 +147,207 @@ + + + +/** + * initialize and open a DVD device or file. + */ +static dvd_input_t file_open(const char *target) +{ + dvd_input_t dev; + + /* Allocate the library structure */ + dev = (dvd_input_t) malloc(sizeof(dvd_input_t)); + if(dev == NULL) { + fprintf(stderr, "libdvdread: Could not allocate memory.\n"); + return NULL; + } + + /* Open the device */ + dev->fd = open(target, O_RDONLY); + if(dev->fd < 0) { + perror("libdvdread: Could not open input"); + free(dev); + return NULL; + } + + return dev; +} + +/** + * return the last error message + */ +static char *file_error(dvd_input_t dev) +{ + /* use strerror(errno)? */ + return (char *)"unknown error"; +} + +/** + * seek into the device. + */ +static int file_seek(dvd_input_t dev, int blocks) +{ + off_t pos; + + pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET); + if(pos < 0) { + return pos; + } + /* assert pos % DVD_VIDEO_LB_LEN == 0 */ + return (int) (pos / DVD_VIDEO_LB_LEN); +} + +/** + * set the block for the begining of a new title (key). + */ +static int file_title(dvd_input_t dev, int block) +{ + return -1; +} + +/** + * read data from the device. + */ +static int file_read(dvd_input_t dev, void *buffer, int blocks, int flags) +{ + size_t len; + ssize_t ret; + + len = (size_t)blocks * DVD_VIDEO_LB_LEN; + + while(len > 0) { + + ret = read(dev->fd, buffer, len); + + if(ret < 0) { + /* One of the reads failed, too bad. We won't even bother + * returning the reads that went ok, and as in the posix spec + * the file postition is left unspecified after a failure. */ + return ret; + } + + if(ret == 0) { + /* Nothing more to read. Return the whole blocks, if any, that we got. + and adjust the file possition back to the previous block boundary. */ + size_t bytes = (size_t)blocks * DVD_VIDEO_LB_LEN - len; + off_t over_read = -(bytes % DVD_VIDEO_LB_LEN); + /*off_t pos =*/ lseek(dev->fd, over_read, SEEK_CUR); + /* should have pos % 2048 == 0 */ + return (int) (bytes / DVD_VIDEO_LB_LEN); + } + + len -= ret; + } + + return blocks; +} + +/** + * close the DVD device and clean up. + */ +static int file_close(dvd_input_t dev) +{ + int ret; + + ret = close(dev->fd); + + if(ret < 0) + return ret; + + free(dev); + + return 0; +} + + /** * Setup read functions with either libdvdcss or minimal DVD access. */ -int DVDInputSetup(void) +int dvdinput_setup(void) { - DVDcss_open = dvdcss_open; - DVDcss_close = dvdcss_close; - DVDcss_title = dvdcss_title; - DVDcss_seek = dvdcss_seek; - DVDcss_read = dvdcss_read; - DVDcss_error = dvdcss_error; + void *dvdcss_library = NULL; + char **dvdcss_version = NULL; + +#ifdef HAVE_DVDCSS_DVDCSS_H + /* linking to libdvdcss */ + dvdcss_library = &dvdcss_library; /* Give it some value != NULL */ + /* the DVDcss_* functions have been #defined at the top */ + dvdcss_version = &dvdcss_interface_2; + +#else + /* dlopening libdvdcss */ + dvdcss_library = dlopen("libdvdcss.so.2", RTLD_LAZY); + + if(dvdcss_library != NULL) { +#if defined(__OpenBSD__) && !defined(__ELF__) +#define U_S "_" +#else +#define U_S +#endif + DVDcss_open = (dvdcss_handle (*)(const char*)) + dlsym(dvdcss_library, U_S "dvdcss_open"); + DVDcss_close = (int (*)(dvdcss_handle)) + dlsym(dvdcss_library, U_S "dvdcss_close"); + DVDcss_title = (int (*)(dvdcss_handle, int)) + dlsym(dvdcss_library, U_S "dvdcss_title"); + DVDcss_seek = (int (*)(dvdcss_handle, int, int)) + dlsym(dvdcss_library, U_S "dvdcss_seek"); + DVDcss_read = (int (*)(dvdcss_handle, void*, int, int)) + dlsym(dvdcss_library, U_S "dvdcss_read"); + DVDcss_error = (char* (*)(dvdcss_handle)) + dlsym(dvdcss_library, U_S "dvdcss_error"); + dvdcss_version = (char **)dlsym(dvdcss_library, U_S "dvdcss_interface_2"); + + if(dlsym(dvdcss_library, U_S "dvdcss_crack")) { + fprintf(stderr, + "libdvdread: Old (pre-0.0.2) version of libdvdcss found.\n" + "libdvdread: You should get the latest version from " + "http://www.videolan.org/\n" ); + dlclose(dvdcss_library); + dvdcss_library = NULL; + } else if(!DVDcss_open || !DVDcss_close || !DVDcss_title || !DVDcss_seek + || !DVDcss_read || !DVDcss_error || !dvdcss_version) { + fprintf(stderr, "libdvdread: Missing symbols in libdvdcss.so.2, " + "this shouldn't happen !\n"); + dlclose(dvdcss_library); + } + } +#endif /* HAVE_DVDCSS_DVDCSS_H */ + + if(dvdcss_library != NULL) { /* char *psz_method = getenv( "DVDCSS_METHOD" ); char *psz_verbose = getenv( "DVDCSS_VERBOSE" ); fprintf(stderr, "DVDCSS_METHOD %s\n", psz_method); fprintf(stderr, "DVDCSS_VERBOSE %s\n", psz_verbose); */ -// fprintf(stderr, "libdvdread: Using libdvdcss version %s for DVD access\n", -// *dvdcss_version); + /* + fprintf(stderr, "libdvdread: Using libdvdcss version %s for DVD access\n", + *dvdcss_version); + */ - /* libdvdcss wraper functions */ - DVDinput_open = css_open; - DVDinput_close = css_close; - DVDinput_seek = css_seek; - DVDinput_title = css_title; - DVDinput_read = css_read; - DVDinput_error = css_error; + /* libdvdcss wrapper functions */ + dvdinput_open = css_open; + dvdinput_close = css_close; + dvdinput_seek = css_seek; + dvdinput_title = css_title; + dvdinput_read = css_read; + dvdinput_error = css_error; return 1; + } else { + fprintf(stderr, "libdvdread: Encrypted DVD support unavailable.\n"); + + /* libdvdcss replacement functions */ + dvdinput_open = file_open; + dvdinput_close = file_close; + dvdinput_seek = file_seek; + dvdinput_title = file_title; + dvdinput_read = file_read; + dvdinput_error = file_error; + return 0; + } }
--- a/libmpdvdkit2/dvd_input.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/dvd_input.h Thu Jun 30 22:48:26 2005 +0000 @@ -5,10 +5,6 @@ * Copyright (C) 2001, 2002 Samuel Hocevar <sam@zoy.org>, * Håkan Hjort <d95hjort@dtek.chalmers.se> * - * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. - * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ - * $Id$ - * * This program 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 @@ -31,25 +27,21 @@ #define DVDINPUT_READ_DECRYPT (1 << 0) -#define DVDINPUT_SEEK_MPEG (1 << 0) -#define DVDINPUT_SEEK_KEY (1 << 1) - - typedef struct dvd_input_s *dvd_input_t; /** - * Pointers which will be filled either the input meathods functions. + * Pointers which will be filled either the input methods functions. */ -extern dvd_input_t (*DVDinput_open) (const char *); -extern int (*DVDinput_close) (dvd_input_t); -extern int (*DVDinput_seek) (dvd_input_t, int, int); -extern int (*DVDinput_title) (dvd_input_t, int); -extern int (*DVDinput_read) (dvd_input_t, void *, int, int); -extern char * (*DVDinput_error) (dvd_input_t); +extern dvd_input_t (*dvdinput_open) (const char *); +extern int (*dvdinput_close) (dvd_input_t); +extern int (*dvdinput_seek) (dvd_input_t, int); +extern int (*dvdinput_title) (dvd_input_t, int); +extern int (*dvdinput_read) (dvd_input_t, void *, int, int); +extern char * (*dvdinput_error) (dvd_input_t); /** * Setup function accessed by dvd_reader.c. Returns 1 if there is CSS support. */ -int DVDInputSetup(void); +int dvdinput_setup(void); #endif /* DVD_INPUT_H_INCLUDED */
--- a/libmpdvdkit2/dvd_reader.c Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/dvd_reader.c Thu Jun 30 22:48:26 2005 +0000 @@ -1,6 +1,7 @@ /* - * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>, - * Håkan Hjort <d95hjort@dtek.chalmers.se> + * Copyright (C) 2001, 2002, 2003 Billy Biggs <vektor@dumbterm.net>, + * Håkan Hjort <d95hjort@dtek.chalmers.se>, + * Björn Englund <d4bjorn@dtek.chalmers.se> * * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ @@ -62,6 +63,9 @@ #include "dvd_udf.h" #include "dvd_input.h" #include "dvd_reader.h" +#include "md5.h" + +#define DEFAULT_UDF_CACHE_LEVEL 0 struct dvd_reader_s { /* Basic information. */ @@ -70,13 +74,17 @@ /* Hack for keeping track of the css status. * 0: no css, 1: perhaps (need init of keys), 2: have done init */ int css_state; - int css_title; /* Last title that we have called DVDinpute_title for. */ + int css_title; /* Last title that we have called dvdinpute_title for. */ /* Information required for an image file. */ dvd_input_t dev; /* Information required for a directory path drive. */ char *path_root; + + /* Filesystem cache */ + int udfcache_level; /* 0 - turned off, 1 - on */ + void *udfcache; }; struct dvd_file_s { @@ -98,6 +106,42 @@ ssize_t filesize; }; +/** + * Set the level of caching on udf + * level = 0 (no caching) + * level = 1 (caching filesystem info) + */ +int DVDUDFCacheLevel(dvd_reader_t *device, int level) +{ + struct dvd_reader_s *dev = (struct dvd_reader_s *)device; + + if(level > 0) { + level = 1; + } else if(level < 0) { + return dev->udfcache_level; + } + + dev->udfcache_level = level; + + return level; +} + +void *GetUDFCacheHandle(dvd_reader_t *device) +{ + struct dvd_reader_s *dev = (struct dvd_reader_s *)device; + + return dev->udfcache; +} + +void SetUDFCacheHandle(dvd_reader_t *device, void *cache) +{ + struct dvd_reader_s *dev = (struct dvd_reader_s *)device; + + dev->udfcache = cache; +} + + + /* Loop over all titles and call dvdcss_title to crack the keys. */ static int initAllCSSKeys( dvd_reader_t *dvd ) { @@ -107,6 +151,10 @@ uint32_t start, len; int title; + char *nokeys_str = getenv("DVDREAD_NOKEYS"); + if(nokeys_str != NULL) + return 0; + fprintf( stderr, "\n" ); fprintf( stderr, "libdvdread: Attempting to retrieve all CSS keys\n" ); fprintf( stderr, "libdvdread: This can take a _long_ time, " @@ -126,7 +174,7 @@ /* Perform CSS key cracking for this title. */ fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", filename, start ); - if( DVDinput_title( dvd->dev, (int)start ) < 0 ) { + if( dvdinput_title( dvd->dev, (int)start ) < 0 ) { fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename, start); } gettimeofday( &t_e, NULL ); @@ -144,7 +192,7 @@ /* Perform CSS key cracking for this title. */ fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", filename, start ); - if( DVDinput_title( dvd->dev, (int)start ) < 0 ) { + if( dvdinput_title( dvd->dev, (int)start ) < 0 ) { fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename, start); } gettimeofday( &t_e, NULL ); @@ -177,18 +225,8 @@ { dvd_reader_t *dvd; dvd_input_t dev; - - /* setup cache dir is no longer needed, it's now implemented in libdvdcss.c - if(!dvdcss_cache_dir){ - dvdcss_cache_dir=get_path( "" ); - if ( dvdcss_cache_dir ) { mkdir( dvdcss_cache_dir,493 ); free( dvdcss_cache_dir ); } - dvdcss_cache_dir=get_path( "DVDKeys" ); - if(dvdcss_cache_dir) mkdir( dvdcss_cache_dir,493 ); - } - */ - /* open it */ - dev = DVDinput_open( location ); + dev = dvdinput_open( location ); if( !dev ) { fprintf( stderr, "libdvdread: Can't open %s for reading\n", location ); return 0; @@ -200,6 +238,9 @@ dvd->dev = dev; dvd->path_root = 0; + dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL; + dvd->udfcache = NULL; + if( have_css ) { /* Only if DVDCSS_METHOD = title, a bit if it's disc or if * DVDCSS_METHOD = key but region missmatch. Unfortunaly we @@ -207,6 +248,7 @@ dvd->css_state = 1; /* Need key init. */ } + dvd->css_title = 0; return dvd; } @@ -221,6 +263,12 @@ dvd->dev = 0; dvd->path_root = strdup( path_root ); + dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL; + dvd->udfcache = NULL; + + dvd->css_state = 0; /* Only used in the UDF path */ + dvd->css_title = 0; /* Only matters in the UDF path */ + return dvd; } @@ -275,7 +323,8 @@ int ret, have_css; char *dev_name = 0; - if( !path ) return 0; + if( path == NULL ) + return 0; #ifdef WIN32 /* Stat doesn't work on devices under mingwin/cygwin. */ @@ -297,7 +346,7 @@ } /* Try to open libdvdcss or fall back to standard functions */ - have_css = DVDInputSetup(); + have_css = dvdinput_setup(); /* First check if this is a block/char device or a file*/ if( S_ISBLK( fileinfo.st_mode ) || @@ -445,10 +494,10 @@ void DVDClose( dvd_reader_t *dvd ) { if( dvd ) { - if( dvd->dev ) DVDinput_close( dvd->dev ); + if( dvd->dev ) dvdinput_close( dvd->dev ); if( dvd->path_root ) free( dvd->path_root ); + if( dvd->udfcache ) FreeUDFCache( dvd->udfcache ); free( dvd ); - dvd = 0; } } @@ -545,7 +594,7 @@ /* Get the full path of the file. */ if( !findDVDFile( dvd, filename, full_path ) ) return 0; - dev = DVDinput_open( full_path ); + dev = dvdinput_open( full_path ); if( !dev ) return 0; dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); @@ -609,8 +658,7 @@ // dvd->css_state = 2; } /* - if( DVDinput_seek( dvd_file->dvd->dev, - (int)start, DVDINPUT_SEEK_KEY ) < 0 ) { + if( dvdinput_title( dvd_file->dvd->dev, (int)start ) < 0 ) { fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n", filename ); } @@ -636,7 +684,7 @@ memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); dvd_file->filesize = 0; - + if( menu ) { dvd_input_t dev; @@ -650,7 +698,7 @@ return 0; } - dev = DVDinput_open( full_path ); + dev = dvdinput_open( full_path ); if( dev == NULL ) { free( dvd_file ); return 0; @@ -663,7 +711,7 @@ } dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; dvd_file->title_devs[ 0 ] = dev; - DVDinput_seek( dvd_file->title_devs[0], 0, DVDINPUT_SEEK_KEY ); + dvdinput_title( dvd_file->title_devs[0], 0); dvd_file->filesize = dvd_file->title_sizes[ 0 ]; } else { @@ -680,9 +728,9 @@ } dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; - dvd_file->title_devs[ i ] = DVDinput_open( full_path ); + dvd_file->title_devs[ i ] = dvdinput_open( full_path ); + dvdinput_title( dvd_file->title_devs[ i ], 0 ); dvd_file->filesize += dvd_file->title_sizes[ i ]; - DVDinput_seek( dvd_file->title_devs[ i ], 0, DVDINPUT_SEEK_KEY ); } if( !dvd_file->title_devs[ 0 ] ) { free( dvd_file ); @@ -697,6 +745,10 @@ dvd_read_domain_t domain ) { char filename[ MAX_UDF_FILE_NAME_LEN ]; + + /* Check arguments. */ + if( dvd == NULL || titlenum < 0 ) + return NULL; switch( domain ) { case DVD_READ_INFO_FILE: @@ -730,7 +782,7 @@ break; default: fprintf( stderr, "libdvdread: Invalid domain for file open.\n" ); - return 0; + return NULL; } if( dvd->isImageFile ) { @@ -750,7 +802,7 @@ } else { for( i = 0; i < 9; ++i ) { if( dvd_file->title_devs[ i ] ) { - DVDinput_close( dvd_file->title_devs[i] ); + dvdinput_close( dvd_file->title_devs[i] ); } } } @@ -761,7 +813,7 @@ } /* Internal, but used from dvd_udf.c */ -int DVDReadBlocksUDFRaw( dvd_reader_t *device, uint32_t lb_number, +int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted ) { @@ -772,13 +824,13 @@ return 0; } - ret = DVDinput_seek( device->dev, (int) lb_number, DVDINPUT_NOFLAGS ); + ret = dvdinput_seek( device->dev, (int) lb_number ); if( ret != (int) lb_number ) { fprintf( stderr, "libdvdread: Can't seek to block %u\n", lb_number ); return 0; } - return DVDinput_read( device->dev, (char *) data, + return dvdinput_read( device->dev, (char *) data, (int) block_count, encrypted ); } @@ -792,8 +844,8 @@ size_t block_count, unsigned char *data, int encrypted ) { - return DVDReadBlocksUDFRaw( dvd_file->dvd, dvd_file->lb_start + offset, - block_count, data, encrypted ); + return UDFReadBlocksRaw( dvd_file->dvd, dvd_file->lb_start + offset, + block_count, data, encrypted ); } /* This is using possibly several inputs and starting from an offset of '0'. @@ -816,14 +868,13 @@ if( offset < dvd_file->title_sizes[ i ] ) { if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) { - off = DVDinput_seek( dvd_file->title_devs[ i ], - (int)offset, DVDINPUT_NOFLAGS ); + off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset ); if( off < 0 || off != (int)offset ) { fprintf( stderr, "libdvdread: Can't seek to block %d\n", offset ); return off < 0 ? off : 0; } - ret = DVDinput_read( dvd_file->title_devs[ i ], data, + ret = dvdinput_read( dvd_file->title_devs[ i ], data, (int)block_count, encrypted ); break; } else { @@ -832,31 +883,29 @@ * (This is only true if you try and read >1GB at a time) */ /* Read part 1 */ - off = DVDinput_seek( dvd_file->title_devs[ i ], - (int)offset, DVDINPUT_NOFLAGS ); + off = dvdinput_seek( dvd_file->title_devs[ i ], (int)offset ); if( off < 0 || off != (int)offset ) { fprintf( stderr, "libdvdread: Can't seek to block %d\n", offset ); return off < 0 ? off : 0; } - ret = DVDinput_read( dvd_file->title_devs[ i ], data, + ret = dvdinput_read( dvd_file->title_devs[ i ], data, (int)part1_size, encrypted ); if( ret < 0 ) return ret; /* FIXME: This is wrong if i is the last file in the set. * also error from this read will not show in ret. */ - - /* Does the next part exist? If not then return now. */ - if( !dvd_file->title_devs[ i + 1 ] ) return ret; + + /* Does the next part exist? If not then return now. */ + if( !dvd_file->title_devs[ i + 1 ] ) return ret; /* Read part 2 */ - off = DVDinput_seek( dvd_file->title_devs[ i + 1 ], - 0, DVDINPUT_NOFLAGS ); + off = dvdinput_seek( dvd_file->title_devs[ i + 1 ], 0 ); if( off < 0 || off != 0 ) { fprintf( stderr, "libdvdread: Can't seek to block %d\n", 0 ); return off < 0 ? off : 0; } - ret2 = DVDinput_read( dvd_file->title_devs[ i + 1 ], + ret2 = dvdinput_read( dvd_file->title_devs[ i + 1 ], data + ( part1_size * (int64_t)DVD_VIDEO_LB_LEN ), (int)(block_count - part1_size), @@ -878,14 +927,20 @@ { int ret; + /* Check arguments. */ + if( dvd_file == NULL || offset < 0 || data == NULL ) + return -1; + /* Hack, and it will still fail for multiple opens in a threaded app ! */ if( dvd_file->dvd->css_title != dvd_file->css_title ) { dvd_file->dvd->css_title = dvd_file->css_title; if( dvd_file->dvd->isImageFile ) { - DVDinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start ); - } else { - DVDinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start ); - } + dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start ); + } + /* Here each vobu has it's own dvdcss handle, so no need to update + else { + dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start ); + }*/ } if( dvd_file->dvd->isImageFile ) { @@ -901,11 +956,15 @@ int DVDFileSeek( dvd_file_t *dvd_file, int offset ) { - if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) { + /* Check arguments. */ + if( dvd_file == NULL || offset < 0 ) return -1; - } - dvd_file->seek_pos = (uint32_t) offset; - return offset; + + if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) { + return -1; + } + dvd_file->seek_pos = (uint32_t) offset; + return offset; } ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size ) @@ -914,10 +973,16 @@ unsigned int numsec, seek_sector, seek_byte; int ret; + /* Check arguments. */ + if( dvd_file == NULL || data == NULL ) + return -1; + seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN; seek_byte = dvd_file->seek_pos % DVD_VIDEO_LB_LEN; - numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) + 1; + numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) + + ( ( ( seek_byte + byte_size ) % DVD_VIDEO_LB_LEN ) ? 1 : 0 ); + secbuf = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN ); if( !secbuf ) { fprintf( stderr, "libdvdread: Can't allocate memory " @@ -947,5 +1012,139 @@ ssize_t DVDFileSize( dvd_file_t *dvd_file ) { + /* Check arguments. */ + if( dvd_file == NULL ) + return -1; + return dvd_file->filesize; } + +int DVDDiscID( dvd_reader_t *dvd, unsigned char *discid ) +{ + struct md5_ctx ctx; + int title; + + /* Check arguments. */ + if( dvd == NULL || discid == NULL ) + return 0; + + /* Go through the first 10 IFO:s, in order, + * and md5sum them, i.e VIDEO_TS.IFO and VTS_0?_0.IFO */ + md5_init_ctx( &ctx ); + for( title = 0; title < 10; title++ ) { + dvd_file_t *dvd_file = DVDOpenFile( dvd, title, DVD_READ_INFO_FILE ); + if( dvd_file != NULL ) { + ssize_t bytes_read; + size_t file_size = dvd_file->filesize * DVD_VIDEO_LB_LEN; + char *buffer = malloc( file_size ); + + if( buffer == NULL ) { + fprintf( stderr, "libdvdread: DVDDiscId, failed to " + "allocate memory for file read!\n" ); + return -1; + } + bytes_read = DVDReadBytes( dvd_file, buffer, file_size ); + if( bytes_read != file_size ) { + fprintf( stderr, "libdvdread: DVDDiscId read returned %d bytes" + ", wanted %d\n", bytes_read, file_size ); + DVDCloseFile( dvd_file ); + return -1; + } + + md5_process_bytes( buffer, file_size, &ctx ); + + DVDCloseFile( dvd_file ); + free( buffer ); + } + } + md5_finish_ctx( &ctx, discid ); + + return 0; +} + + +int DVDISOVolumeInfo( dvd_reader_t *dvd, + char *volid, unsigned int volid_size, + unsigned char *volsetid, unsigned int volsetid_size ) +{ + unsigned char *buffer; + int ret; + + /* Check arguments. */ + if( dvd == NULL ) + return 0; + + if( dvd->dev == NULL ) { + /* No block access, so no ISO... */ + return -1; + } + + buffer = malloc( DVD_VIDEO_LB_LEN ); + if( buffer == NULL ) { + fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to " + "allocate memory for file read!\n" ); + return -1; + } + + ret = UDFReadBlocksRaw( dvd, 16, 1, buffer, 0 ); + if( ret != 1 ) { + fprintf( stderr, "libdvdread: DVDISOVolumeInfo, failed to " + "read ISO9660 Primary Volume Descriptor!\n" ); + return -1; + } + + if( (volid != NULL) && (volid_size > 0) ) { + unsigned int n; + for(n = 0; n < 32; n++) { + if(buffer[40+n] == 0x20) { + break; + } + } + + if(volid_size > n+1) { + volid_size = n+1; + } + + memcpy(volid, &buffer[40], volid_size-1); + volid[volid_size-1] = '\0'; + } + + if( (volsetid != NULL) && (volsetid_size > 0) ) { + if(volsetid_size > 128) { + volsetid_size = 128; + } + memcpy(volsetid, &buffer[190], volsetid_size); + } + return 0; +} + + +int DVDUDFVolumeInfo( dvd_reader_t *dvd, + char *volid, unsigned int volid_size, + unsigned char *volsetid, unsigned int volsetid_size ) +{ + int ret; + /* Check arguments. */ + if( dvd == NULL ) + return -1; + + if( dvd->dev == NULL ) { + /* No block access, so no UDF VolumeSet Identifier */ + return -1; + } + + if( (volid != NULL) && (volid_size > 0) ) { + ret = UDFGetVolumeIdentifier(dvd, volid, volid_size); + if(!ret) { + return -1; + } + } + if( (volsetid != NULL) && (volsetid_size > 0) ) { + ret = UDFGetVolumeSetIdentifier(dvd, volsetid, volsetid_size); + if(!ret) { + return -1; + } + } + + return 0; +}
--- a/libmpdvdkit2/dvd_reader.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/dvd_reader.h Thu Jun 30 22:48:26 2005 +0000 @@ -3,7 +3,8 @@ /* * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>, - * Håkan Hjort <d95hjort@dtek.chalmers.se> + * Håkan Hjort <d95hjort@dtek.chalmers.se>, + * Björn Englund <d4bjorn@dtek.chalmers.se> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,128 +24,241 @@ #include <sys/types.h> /** - * The length of one Logical Block of a DVD Video. + * The DVD access interface. + * + * This file contains the functions that form the interface to to + * reading files located on a DVD. + */ + +/** + * The current version. + */ +#define DVDREAD_VERSION 904 + +/** + * The length of one Logical Block of a DVD. */ #define DVD_VIDEO_LB_LEN 2048 /** - * Maximum length of filenames for UDF. + * Maximum length of filenames allowed in UDF. */ #define MAX_UDF_FILE_NAME_LEN 2048 #ifdef __cplusplus extern "C" { #endif - + +/** + * Opaque type that is used as a handle for one instance of an opened DVD. + */ typedef struct dvd_reader_s dvd_reader_t; + +/** + * Opaque type for a file read handle, much like a normal fd or FILE *. + */ typedef struct dvd_file_s dvd_file_t; /** - * dvd = DVDOpen(path); - * * Opens a block device of a DVD-ROM file, or an image file, or a directory - * name for a mounted DVD or HD copy of a DVD. Returns 0 if we can't get any - * of those methods to work. + * name for a mounted DVD or HD copy of a DVD. * * If the given file is a block device, or is the mountpoint for a block * device, then that device is used for CSS authentication using libdvdcss. * If no device is available, then no CSS authentication is performed, * and we hope that the image is decrypted. * - * If the path given is a directory, then the files in that directory may be in - * any one of these formats: + * If the path given is a directory, then the files in that directory may be + * in any one of these formats: * * path/VIDEO_TS/VTS_01_1.VOB * path/video_ts/vts_01_1.vob * path/VTS_01_1.VOB * path/vts_01_1.vob + * + * @param path Specifies the the device, file or directory to be used. + * @return If successful a a read handle is returned. Otherwise 0 is returned. + * + * dvd = DVDOpen(path); */ dvd_reader_t *DVDOpen( const char * ); /** - * DVDClose(dvd); + * Closes and cleans up the DVD reader object. + * + * You must close all open files before calling this function. * - * Closes and cleans up the DVD reader object. You must close all open files - * before calling this function. + * @param dvd A read handle that should be closed. + * + * DVDClose(dvd); */ void DVDClose( dvd_reader_t * ); /** - * INFO_FILE : VIDEO_TS.IFO (manager) - * VTS_XX_0.IFO (title) - * - * INFO_BACKUP_FILE: VIDEO_TS.BUP (manager) - * VTS_XX_0.BUP (title) - * - * MENU_VOBS : VIDEO_TS.VOB (manager) - * VTS_XX_0.VOB (title) - * - * TITLE_VOBS : VTS_XX_[1-9].VOB (title) - * All files in the title set are opened and - * read as a single file. + * */ typedef enum { - DVD_READ_INFO_FILE, - DVD_READ_INFO_BACKUP_FILE, - DVD_READ_MENU_VOBS, - DVD_READ_TITLE_VOBS + DVD_READ_INFO_FILE, /**< VIDEO_TS.IFO or VTS_XX_0.IFO (title) */ + DVD_READ_INFO_BACKUP_FILE, /**< VIDEO_TS.BUP or VTS_XX_0.BUP (title) */ + DVD_READ_MENU_VOBS, /**< VIDEO_TS.VOB or VTS_XX_0.VOB (title) */ + DVD_READ_TITLE_VOBS /**< VTS_XX_[1-9].VOB (title). All files in + the title set are opened and read as a + single file. */ } dvd_read_domain_t; /** - * dvd_file = DVDOpenFile(dvd, titlenum, domain); + * Opens a file on the DVD given the title number and domain. + * + * If the title number is 0, the video manager information is opened + * (VIDEO_TS.[IFO,BUP,VOB]). Returns a file structure which may be + * used for reads, or 0 if the file was not found. * - * Opens a file on the DVD given the title number and domain. If the title - * number is 0, the video manager information is opened - * (VIDEO_TS.[IFO,BUP,VOB]). Returns a file structure which may be used for - * reads, or 0 if the file was not found. - */ -dvd_file_t *DVDOpenFile( dvd_reader_t *, int, - dvd_read_domain_t ); + * @param dvd A dvd read handle. + * @param titlenum Which Video Title Set should be used, VIDEO_TS is 0. + * @param domain Which domain. + * @return If successful a a file read handle is returned, otherwise 0. + * + * dvd_file = DVDOpenFile(dvd, titlenum, domain); */ +dvd_file_t *DVDOpenFile( dvd_reader_t *, int, dvd_read_domain_t ); /** - * DVDCloseFile(dvd_file); + * Closes a file and frees the associated structure. * - * Closes a file and frees the associated structure. + * @param dvd_file The file read handle to be closed. + * + * DVDCloseFile(dvd_file); */ void DVDCloseFile( dvd_file_t * ); /** - * blocks_read = DVDReadBlocks(dvd_file, offset, block_count, data); - * * Reads block_count number of blocks from the file at the given block offset. * Returns number of blocks read on success, -1 on error. This call is only * for reading VOB data, and should not be used when reading the IFO files. * When reading from an encrypted drive, blocks are decrypted using libdvdcss * where required. + * + * @param dvd_file A file read handle. + * @param offset Block offset from the start of the file to start reading at. + * @param block_count Number of block to read. + * @param data Pointer to a buffer to write the data into. + * @return Returns number of blocks read on success, -1 on error. + * + * blocks_read = DVDReadBlocks(dvd_file, offset, block_count, data); */ ssize_t DVDReadBlocks( dvd_file_t *, int, size_t, unsigned char * ); /** - * offset_set = DVDFileSeek(dvd_file, seek_offset); - * * Seek to the given position in the file. Returns the resulting position in * bytes from the beginning of the file. The seek position is only used for * byte reads from the file, the block read call always reads from the given * offset. + * + * @param dvd_file A file read handle. + * @param seek_offset Byte offset from the start of the file to seek to. + * @return The resulting position in bytes from the beginning of the file. + * + * offset_set = DVDFileSeek(dvd_file, seek_offset); */ int DVDFileSeek( dvd_file_t *, int ); /** - * bytes_read = DVDReadBytes(dvd_file, data, bytes); - * * Reads the given number of bytes from the file. This call can only be used * on the information files, and may not be used for reading from a VOB. This * reads from and increments the currrent seek position for the file. + * + * @param dvd_file A file read handle. + * @param data Pointer to a buffer to write the data into. + * @param bytes Number of bytes to read. + * @return Returns number of bytes read on success, -1 on error. + * + * bytes_read = DVDReadBytes(dvd_file, data, bytes); */ ssize_t DVDReadBytes( dvd_file_t *, void *, size_t ); /** - * blocks = DVDFileSize(dvd_file); + * Returns the file size in blocks. * - * Returns the file size in blocks. + * @param dvd_file A file read handle. + * @return The size of the file in blocks, -1 on error. + * + * blocks = DVDFileSize(dvd_file); */ ssize_t DVDFileSize( dvd_file_t * ); +/** + * Get a unique 128 bit disc ID. + * This is the MD5 sum of VIDEO_TS.IFO and the VTS_0?_0.IFO files + * in title order (those that exist). + * If you need a 'text' representation of the id, print it as a + * hexadecimal number, using lowercase letters, discid[0] first. + * I.e. the same format as the command-line 'md5sum' program uses. + * + * @param dvd A read handle to get the disc ID from + * @param discid The buffer to put the disc ID into. The buffer must + * have room for 128 bits (16 chars). + * @return 0 on success, -1 on error. + */ +int DVDDiscID( dvd_reader_t *, unsigned char * ); + +/** + * Get the UDF VolumeIdentifier and VolumeSetIdentifier + * from the PrimaryVolumeDescriptor. + * + * @param dvd A read handle to get the disc ID from + * @param volid The buffer to put the VolumeIdentifier into. + * The VolumeIdentifier is latin-1 encoded (8bit unicode) + * null terminated and max 32 bytes (including '\0') + * @param volid_size No more than volid_size bytes will be copied to volid. + * If the VolumeIdentifier is truncated because of this + * it will still be null terminated. + * @param volsetid The buffer to put the VolumeSetIdentifier into. + * The VolumeIdentifier is 128 bytes as + * stored in the UDF PrimaryVolumeDescriptor. + * Note that this is not a null terminated string. + * @param volsetid_size At most volsetid_size bytes will be copied to volsetid. + * @return 0 on success, -1 on error. + */ +int DVDUDFVolumeInfo( dvd_reader_t *, char *, unsigned int, + unsigned char *, unsigned int ); + +/** + * Get the ISO9660 VolumeIdentifier and VolumeSetIdentifier + * + * * Only use this function as fallback if DVDUDFVolumeInfo returns 0 * + * * this will happen on a disc mastered only with a iso9660 filesystem * + * * All video DVD discs have UDF filesystem * + * + * @param dvd A read handle to get the disc ID from + * @param volid The buffer to put the VolumeIdentifier into. + * The VolumeIdentifier is coded with '0-9','A-Z','_' + * null terminated and max 33 bytes (including '\0') + * @param volid_size No more than volid_size bytes will be copied to volid. + * If the VolumeIdentifier is truncated because of this + * it will still be null terminated. + * @param volsetid The buffer to put the VolumeSetIdentifier into. + * The VolumeIdentifier is 128 bytes as + * stored in the ISO9660 PrimaryVolumeDescriptor. + * Note that this is not a null terminated string. + * @param volsetid_size At most volsetid_size bytes will be copied to volsetid. + * @return 0 on success, -1 on error. + */ +int DVDISOVolumeInfo( dvd_reader_t *, char *, unsigned int, + unsigned char *, unsigned int ); + +/** + * Sets the level of caching that is done when reading from a device + * + * @param dvd A read handle to get the disc ID from + * @param level The level of caching wanted. + * -1 - returns the current setting. + * 0 - UDF Cache turned off. + * 1 - (default level) Pointers to IFO files and some data from + * PrimaryVolumeDescriptor are cached. + * + * @return The level of caching. + */ +int DVDUDFCacheLevel( dvd_reader_t *, int ); + #ifdef __cplusplus }; #endif
--- a/libmpdvdkit2/dvd_udf.c Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/dvd_udf.c Thu Jun 30 22:48:26 2005 +0000 @@ -5,8 +5,6 @@ * Modifications by: * Billy Biggs <vektor@dumbterm.net>. * Björn Englund <d4bjorn@dtek.chalmers.se>. - * Joey Parrish <joey@nicewarrior.org>. - * - updated from libdvdread 0.9.4 and removed udf caching * * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ @@ -34,10 +32,11 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include "config.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> -//#include <assert.h> #ifndef __MINGW32__ #include <sys/ioctl.h> #endif @@ -50,7 +49,7 @@ #include "dvd_udf.h" /* Private but located in/shared with dvd_reader.c */ -extern int DVDReadBlocksUDFRaw( dvd_reader_t *device, uint32_t lb_number, +extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted ); @@ -64,7 +63,7 @@ while(count > 0) { - ret = DVDReadBlocksUDFRaw(device, lb_number, count, data, encrypted); + ret = UDFReadBlocksRaw(device, lb_number, count, data, encrypted); if(ret <= 0) { /* One of the reads failed or nothing more to read, too bad. @@ -128,6 +127,201 @@ uint8_t filetype; }; +struct udf_cache { + int avdp_valid; + struct avdp_t avdp; + int pvd_valid; + struct pvd_t pvd; + int partition_valid; + struct Partition partition; + int rooticb_valid; + struct AD rooticb; + int lb_num; + struct lbudf *lbs; + int map_num; + struct icbmap *maps; +}; + +typedef enum { + PartitionCache, RootICBCache, LBUDFCache, MapCache, AVDPCache, PVDCache +} UDFCacheType; + +extern void *GetUDFCacheHandle(dvd_reader_t *device); +extern void SetUDFCacheHandle(dvd_reader_t *device, void *cache); + +void FreeUDFCache(void *cache) +{ + struct udf_cache *c = (struct udf_cache *)cache; + if(c == NULL) { + return; + } + if(c->lbs) { + free(c->lbs); + } + if(c->maps) { + free(c->maps); + } + free(c); +} + + +static int GetUDFCache(dvd_reader_t *device, UDFCacheType type, + uint32_t nr, void *data) +{ + int n; + struct udf_cache *c; + + if(DVDUDFCacheLevel(device, -1) <= 0) { + return 0; + } + + c = (struct udf_cache *)GetUDFCacheHandle(device); + + if(c == NULL) { + return 0; + } + + switch(type) { + case AVDPCache: + if(c->avdp_valid) { + *(struct avdp_t *)data = c->avdp; + return 1; + } + break; + case PVDCache: + if(c->pvd_valid) { + *(struct pvd_t *)data = c->pvd; + return 1; + } + break; + case PartitionCache: + if(c->partition_valid) { + *(struct Partition *)data = c->partition; + return 1; + } + break; + case RootICBCache: + if(c->rooticb_valid) { + *(struct AD *)data = c->rooticb; + return 1; + } + break; + case LBUDFCache: + for(n = 0; n < c->lb_num; n++) { + if(c->lbs[n].lb == nr) { + *(uint8_t **)data = c->lbs[n].data; + return 1; + } + } + break; + case MapCache: + for(n = 0; n < c->map_num; n++) { + if(c->maps[n].lbn == nr) { + *(struct icbmap *)data = c->maps[n]; + return 1; + } + } + break; + default: + break; + } + + return 0; +} + +static int SetUDFCache(dvd_reader_t *device, UDFCacheType type, + uint32_t nr, void *data) +{ + int n; + struct udf_cache *c; + + if(DVDUDFCacheLevel(device, -1) <= 0) { + return 0; + } + + c = (struct udf_cache *)GetUDFCacheHandle(device); + + if(c == NULL) { + c = calloc(1, sizeof(struct udf_cache)); + // fprintf(stderr, "calloc: %d\n", sizeof(struct udf_cache)); + if(c == NULL) { + return 0; + } + SetUDFCacheHandle(device, c); + } + + + switch(type) { + case AVDPCache: + c->avdp = *(struct avdp_t *)data; + c->avdp_valid = 1; + break; + case PVDCache: + c->pvd = *(struct pvd_t *)data; + c->pvd_valid = 1; + break; + case PartitionCache: + c->partition = *(struct Partition *)data; + c->partition_valid = 1; + break; + case RootICBCache: + c->rooticb = *(struct AD *)data; + c->rooticb_valid = 1; + break; + case LBUDFCache: + for(n = 0; n < c->lb_num; n++) { + if(c->lbs[n].lb == nr) { + /* replace with new data */ + c->lbs[n].data = *(uint8_t **)data; + c->lbs[n].lb = nr; + return 1; + } + } + c->lb_num++; + c->lbs = realloc(c->lbs, c->lb_num * sizeof(struct lbudf)); + /* + fprintf(stderr, "realloc lb: %d * %d = %d\n", + c->lb_num, sizeof(struct lbudf), + c->lb_num * sizeof(struct lbudf)); + */ + if(c->lbs == NULL) { + c->lb_num = 0; + return 0; + } + c->lbs[n].data = *(uint8_t **)data; + c->lbs[n].lb = nr; + break; + case MapCache: + for(n = 0; n < c->map_num; n++) { + if(c->maps[n].lbn == nr) { + /* replace with new data */ + c->maps[n] = *(struct icbmap *)data; + c->maps[n].lbn = nr; + return 1; + } + } + c->map_num++; + c->maps = realloc(c->maps, c->map_num * sizeof(struct icbmap)); + /* + fprintf(stderr, "realloc maps: %d * %d = %d\n", + c->map_num, sizeof(struct icbmap), + c->map_num * sizeof(struct icbmap)); + */ + if(c->maps == NULL) { + c->map_num = 0; + return 0; + } + c->maps[n] = *(struct icbmap *)data; + c->maps[n].lbn = nr; + break; + default: + return 0; + } + + return 1; +} + + /* For direct data access, LSB first */ #define GETN1(p) ((uint8_t)data[p]) #define GETN2(p) ((uint16_t)data[p] | ((uint16_t)data[(p) + 1] << 8)) @@ -302,8 +496,16 @@ uint8_t LogBlock[DVD_VIDEO_LB_LEN]; uint32_t lbnum; uint16_t TagID; + struct icbmap tmpmap; lbnum = partition->Start + ICB.Location; + tmpmap.lbn = lbnum; + if(GetUDFCache(device, MapCache, lbnum, &tmpmap)) { + *FileType = tmpmap.filetype; + *File = tmpmap.file; + return 1; + } + do { if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { TagID = 0; @@ -313,6 +515,9 @@ if( TagID == 261 ) { UDFFileEntry( LogBlock, FileType, partition, File ); + tmpmap.file = *File; + tmpmap.filetype = *FileType; + SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap); return 1; }; } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 ) @@ -328,7 +533,8 @@ * return 1 on success, 0 on error; */ static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, - struct Partition *partition, struct AD *FileICB ) + struct Partition *partition, struct AD *FileICB, + int cache_file_info) { char filename[ MAX_UDF_FILE_NAME_LEN ]; uint8_t directory[ 2 * DVD_VIDEO_LB_LEN ]; @@ -336,9 +542,78 @@ uint16_t TagID; uint8_t filechar; unsigned int p; + uint8_t *cached_dir = NULL; + uint32_t dir_lba; + struct AD tmpICB; + int found = 0; + int in_cache = 0; /* Scan dir for ICB of file */ lbnum = partition->Start + Dir.Location; + + if(DVDUDFCacheLevel(device, -1) > 0) { + /* caching */ + + if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) { + dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN; + if((cached_dir = malloc(dir_lba * DVD_VIDEO_LB_LEN)) == NULL) { + return 0; + } + if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) { + free(cached_dir); + cached_dir = NULL; + } + /* + if(cached_dir) { + fprintf(stderr, "malloc dir: %d\n", + dir_lba * DVD_VIDEO_LB_LEN); + } + */ + SetUDFCache(device, LBUDFCache, lbnum, &cached_dir); + } else { + in_cache = 1; + } + + if(cached_dir == NULL) { + return 0; + } + + p = 0; + + while( p < Dir.Length ) { + UDFDescriptor( &cached_dir[ p ], &TagID ); + if( TagID == 257 ) { + p += UDFFileIdentifier( &cached_dir[ p ], &filechar, + filename, &tmpICB ); + if(cache_file_info && !in_cache) { + uint8_t tmpFiletype; + struct AD tmpFile; + + if( !strcasecmp( FileName, filename ) ) { + *FileICB = tmpICB; + found = 1; + + } + UDFMapICB(device, tmpICB, &tmpFiletype, + partition, &tmpFile); + } else { + if( !strcasecmp( FileName, filename ) ) { + *FileICB = tmpICB; + return 1; + } + } + } else { + if(cache_file_info && (!in_cache) && found) { + return 1; + } + return 0; + } + } + if(cache_file_info && (!in_cache) && found) { + return 1; + } + return 0; + } if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { return 0; @@ -380,6 +655,10 @@ int terminate; struct avdp_t; + if(GetUDFCache(device, AVDPCache, 0, avdp)) { + return 1; + } + /* Find Anchor */ lastsector = 0; lbnum = 256; /* Try #1, prime anchor */ @@ -427,6 +706,8 @@ avdp->rvds.location = MVDS_location; avdp->rvds.length = MVDS_length; + SetUDFCache(device, AVDPCache, 0, avdp); + return 1; } @@ -514,8 +795,11 @@ strcat( tokenline, filename ); + if(!(GetUDFCache(device, PartitionCache, 0, &partition) && + GetUDFCache(device, RootICBCache, 0, &RootICB))) { /* Find partition, 0 is the standard location for DVD Video.*/ if( !UDFFindPartition( device, 0, &partition ) ) return 0; + SetUDFCache(device, PartitionCache, 0, &partition); /* Find root dir ICB */ lbnum = partition.Start; @@ -536,23 +820,30 @@ /* Sanity checks. */ if( TagID != 256 ) return 0; if( RootICB.Partition != 0 ) return 0; + SetUDFCache(device, RootICBCache, 0, &RootICB); + } /* Find root dir */ if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0; if( filetype != 4 ) return 0; /* Root dir should be dir */ { + int cache_file_info = 0; /* Tokenize filepath */ token = strtok(tokenline, "/"); while( token != NULL ) { - if( !UDFScanDir( device, File, token, &partition, &ICB)) { + if( !UDFScanDir( device, File, token, &partition, &ICB, + cache_file_info)) { return 0; } if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) ) { return 0; } + if(!strcmp(token, "VIDEO_TS")) { + cache_file_info = 1; + } token = strtok( NULL, "/" ); } } @@ -636,12 +927,76 @@ { uint8_t pvd_buf[DVD_VIDEO_LB_LEN]; + if(GetUDFCache(device, PVDCache, 0, pvd)) { + return 1; + } + if(!UDFGetDescriptor( device, 1, pvd_buf, sizeof(pvd_buf))) { return 0; } memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32); memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128); + SetUDFCache(device, PVDCache, 0, pvd); return 1; } + +/** + * Gets the Volume Identifier string, in 8bit unicode (latin-1) + * volid, place to put the string + * volid_size, size of the buffer volid points to + * returns the size of buffer needed for all data + */ +int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid, + unsigned int volid_size) +{ + struct pvd_t pvd; + unsigned int volid_len; + + /* get primary volume descriptor */ + if(!UDFGetPVD(device, &pvd)) { + return 0; + } + + volid_len = pvd.VolumeIdentifier[31]; + if(volid_len > 31) { + /* this field is only 32 bytes something is wrong */ + volid_len = 31; + } + if(volid_size > volid_len) { + volid_size = volid_len; + } + Unicodedecode(pvd.VolumeIdentifier, volid_size, volid); + + return volid_len; +} + +/** + * Gets the Volume Set Identifier, as a 128-byte dstring (not decoded) + * WARNING This is not a null terminated string + * volsetid, place to put the data + * volsetid_size, size of the buffer volsetid points to + * the buffer should be >=128 bytes to store the whole volumesetidentifier + * returns the size of the available volsetid information (128) + * or 0 on error + */ +int UDFGetVolumeSetIdentifier(dvd_reader_t *device, uint8_t *volsetid, + unsigned int volsetid_size) +{ + struct pvd_t pvd; + + /* get primary volume descriptor */ + if(!UDFGetPVD(device, &pvd)) { + return 0; + } + + + if(volsetid_size > 128) { + volsetid_size = 128; + } + + memcpy(volsetid, pvd.VolumeSetIdentifier, volsetid_size); + + return 128; +}
--- a/libmpdvdkit2/dvd_udf.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/dvd_udf.h Thu Jun 30 22:48:26 2005 +0000 @@ -7,7 +7,8 @@ * * Modifications by: * Billy Biggs <vektor@dumbterm.net>. - * + * Björn Englund <d4bjorn@dtek.chalmers.se>. + * * dvdudf: parse and read the UDF volume information of a DVD Video * Copyright (C) 1999 Christian Wolff for convergence integrated media * GmbH The author can be reached at scarabaeus@convergence.de, the @@ -47,6 +48,11 @@ */ uint32_t UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *size ); +void FreeUDFCache(void *cache); +int UDFGetVolumeIdentifier(dvd_reader_t *device, + char *volid, unsigned int volid_size); +int UDFGetVolumeSetIdentifier(dvd_reader_t *device, + uint8_t *volsetid, unsigned int volsetid_size); #ifdef __cplusplus }; #endif
--- a/libmpdvdkit2/ifo_print.c Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/ifo_print.c Thu Jun 30 22:48:26 2005 +0000 @@ -1,10 +1,7 @@ /* - * Copyright (C) 2000, 2001, 2002 Björn Englund <d4bjorn@dtek.chalmers.se>, - * Håkan Hjort <d95hjort@dtek.chalmers.se> - * - * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. - * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ - * $Id$ + * Copyright (C) 2000, 2001, 2002, 2003 + * Björn Englund <d4bjorn@dtek.chalmers.se>, + * Håkan Hjort <d95hjort@dtek.chalmers.se> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,26 +18,27 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" + #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <inttypes.h> #include <string.h> #include <ctype.h> -//#include <assert.h> -#include "config.h" // Needed for WORDS_BIGENDIAN #include "ifo_types.h" #include "ifo_read.h" #include "ifo_print.h" +#include "dvdread_internal.h" /* Put this in some other file / package? It's used in nav_print too. */ -static void ifoPrint_time(int level, dvd_time_t *dtime) { +static void ifoPrint_time(dvd_time_t *dtime) { const char *rate; - assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa); - assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa); - assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa); - assert((dtime->frame_u&0xf) < 0xa); + CHECK_VALUE((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa); + CHECK_VALUE((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa); + CHECK_VALUE((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa); + CHECK_VALUE((dtime->frame_u&0xf) < 0xa); printf("%02x:%02x:%02x.%02x", dtime->hour, @@ -79,7 +77,7 @@ printf("\n"); } -static void ifoPrint_video_attributes(int level, video_attr_t *attr) { +static void ifoPrint_video_attributes(video_attr_t *attr) { /* The following test is shorter but not correct ISO C, memcmp(attr,my_friendly_zeros, sizeof(video_attr_t)) */ @@ -90,6 +88,7 @@ && attr->unknown1 == 0 && attr->line21_cc_1 == 0 && attr->line21_cc_2 == 0 + && attr->bit_rate == 0 && attr->video_format == 0 && attr->letterboxed == 0 && attr->film_mode == 0) { @@ -149,7 +148,7 @@ } printf("U%x ", attr->unknown1); - assert(!attr->unknown1); + CHECK_VALUE(!attr->unknown1); if(attr->line21_cc_1 || attr->line21_cc_2) { printf("NTSC CC "); @@ -158,6 +157,17 @@ if(attr->line21_cc_2) printf("2 "); } + + switch(attr->bit_rate) { + case 0: + printf("Variable Bit Rate "); + break; + case 1: + printf("Constant Bit Rate "); + break; + default: + printf("(please send a bug report)"); + } { int height = 480; @@ -192,7 +202,7 @@ } } -static void ifoPrint_audio_attributes(int level, audio_attr_t *attr) { +static void ifoPrint_audio_attributes(audio_attr_t *attr) { if(attr->audio_format == 0 && attr->multichannel_extension == 0 @@ -201,8 +211,10 @@ && attr->quantization == 0 && attr->sample_frequency == 0 && attr->channels == 0 + && attr->lang_code == 0 && attr->lang_extension == 0 - && attr->unknown1 == 0 + && attr->code_extension == 0 + && attr->unknown3 == 0 && attr->unknown1 == 0) { printf("-- Unspecified --"); return; @@ -240,10 +252,11 @@ switch(attr->lang_type) { case 0: // not specified - assert(attr->lang_code == 0 || attr->lang_code == 0xffff); + CHECK_VALUE(attr->lang_code == 0 || attr->lang_code == 0xffff); break; case 1: - printf("%c%c ", attr->lang_code>>8, attr->lang_code & 0xff); + printf("%c%c (%c) ", attr->lang_code>>8, attr->lang_code & 0xff, + attr->lang_extension ? attr->lang_extension : ' '); break; default: printf("(please send a bug report) "); @@ -294,7 +307,7 @@ printf("%dCh ", attr->channels + 1); - switch(attr->lang_extension) { + switch(attr->code_extension) { case 0: printf("Not specified "); break; @@ -315,34 +328,64 @@ printf("(please send a bug report) "); } - printf("%d ", attr->unknown1); - printf("%d ", attr->unknown2); + printf("%d ", attr->unknown3); + if(attr->application_mode == 1) { + printf("ca=%d ", attr->app_info.karaoke.channel_assignment); + printf("%d ", attr->app_info.karaoke.version); + if(attr->app_info.karaoke.mc_intro) + printf("mc intro "); + printf("%s ", attr->app_info.karaoke.mode ? "duet" : "solo"); + printf("%d ", attr->app_info.karaoke.unknown4); + } + if(attr->application_mode == 2) { + if(attr->app_info.surround.dolby_encoded) { + printf("dolby surround "); + } + printf("%d ", attr->app_info.surround.unknown5); + printf("%d ", attr->app_info.surround.unknown6); + } } -static void ifoPrint_subp_attributes(int level, subp_attr_t *attr) { +static void ifoPrint_subp_attributes(subp_attr_t *attr) { if(attr->type == 0 + && attr->code_mode == 0 && attr->lang_code == 0 + && attr->lang_extension == 0 && attr->zero1 == 0 && attr->zero2 == 0 - && attr->lang_extension== 0) { + && attr->code_extension == 0) { printf("-- Unspecified --"); return; } - printf("type %02x ", attr->type); - - if(isalpha((int)(attr->lang_code >> 8)) - && isalpha((int)(attr->lang_code & 0xff))) { - printf("%c%c ", attr->lang_code >> 8, attr->lang_code & 0xff); + switch(attr->code_mode) { + case 0: + printf("Coding Mode RLE "); + break; + case 1: + printf("Coding Mode Extended "); + break; + default: + printf("(please send a bug report) "); + } + + if(attr->type == 1) { + if(isalpha((int)(attr->lang_code >> 8)) + && isalpha((int)(attr->lang_code & 0xff))) { + printf("%c%c ", attr->lang_code >> 8, attr->lang_code & 0xff); + } else { + printf("%02x%02x ", attr->lang_code >> 8, attr->lang_code & 0xff); + } } else { - printf("%02x%02x ", 0xff & (unsigned)(attr->lang_code >> 8), - 0xff & (unsigned)(attr->lang_code & 0xff)); + printf("lang not specified "); } printf("%d ", attr->zero1); printf("%d ", attr->zero2); - + printf("%d ", attr->code_extension); + + /* Is this correct? should it not be subp_code_ext here instead? */ switch(attr->lang_extension) { case 0: printf("Not specified "); @@ -498,20 +541,20 @@ printf("Start sector of VMGM_VOBU_ADMAP: %08x\n", vmgi_mat->vmgm_vobu_admap); printf("Video attributes of VMGM_VOBS: "); - ifoPrint_video_attributes(5, &vmgi_mat->vmgm_video_attr); + ifoPrint_video_attributes(&vmgi_mat->vmgm_video_attr); printf("\n"); printf("VMGM Number of Audio attributes: %i\n", vmgi_mat->nr_of_vmgm_audio_streams); if(vmgi_mat->nr_of_vmgm_audio_streams > 0) { printf("\tstream %i status: ", 1); - ifoPrint_audio_attributes(5, &vmgi_mat->vmgm_audio_attr); + ifoPrint_audio_attributes(&vmgi_mat->vmgm_audio_attr); printf("\n"); } printf("VMGM Number of Sub-picture attributes: %i\n", vmgi_mat->nr_of_vmgm_subp_streams); if(vmgi_mat->nr_of_vmgm_subp_streams > 0) { printf("\tstream %2i status: ", 1); - ifoPrint_subp_attributes(5, &vmgi_mat->vmgm_subp_attr); + ifoPrint_subp_attributes(&vmgi_mat->vmgm_subp_attr); printf("\n"); } } @@ -540,14 +583,14 @@ printf("Start sector of VTS_VOBU_ADMAP: %08x\n", vtsi_mat->vts_vobu_admap); printf("Video attributes of VTSM_VOBS: "); - ifoPrint_video_attributes(5, &vtsi_mat->vtsm_video_attr); + ifoPrint_video_attributes(&vtsi_mat->vtsm_video_attr); printf("\n"); printf("VTSM Number of Audio attributes: %i\n", vtsi_mat->nr_of_vtsm_audio_streams); if(vtsi_mat->nr_of_vtsm_audio_streams > 0) { printf("\tstream %i status: ", 1); - ifoPrint_audio_attributes(5, &vtsi_mat->vtsm_audio_attr); + ifoPrint_audio_attributes(&vtsi_mat->vtsm_audio_attr); printf("\n"); } @@ -555,19 +598,19 @@ vtsi_mat->nr_of_vtsm_subp_streams); if(vtsi_mat->nr_of_vtsm_subp_streams > 0) { printf("\tstream %2i status: ", 1); - ifoPrint_subp_attributes(5, &vtsi_mat->vtsm_subp_attr); + ifoPrint_subp_attributes(&vtsi_mat->vtsm_subp_attr); printf("\n"); } printf("Video attributes of VTS_VOBS: "); - ifoPrint_video_attributes(5, &vtsi_mat->vts_video_attr); + ifoPrint_video_attributes(&vtsi_mat->vts_video_attr); printf("\n"); printf("VTS Number of Audio attributes: %i\n", vtsi_mat->nr_of_vts_audio_streams); for(i = 0; i < vtsi_mat->nr_of_vts_audio_streams; i++) { printf("\tstream %i status: ", i); - ifoPrint_audio_attributes(5, &vtsi_mat->vts_audio_attr[i]); + ifoPrint_audio_attributes(&vtsi_mat->vts_audio_attr[i]); printf("\n"); } @@ -575,9 +618,11 @@ vtsi_mat->nr_of_vts_subp_streams); for(i = 0; i < vtsi_mat->nr_of_vts_subp_streams; i++) { printf("\tstream %2i status: ", i); - ifoPrint_subp_attributes(5, &vtsi_mat->vts_subp_attr[i]); + ifoPrint_subp_attributes(&vtsi_mat->vts_subp_attr[i]); printf("\n"); } + + /* FIXME: Add printing of MultiChannel Extension */ } @@ -631,7 +676,7 @@ for(i=0;i<nr;i++) { printf("Cell: %3i ", i + 1); - ifoPrint_time(5, &cell_playback[i].playback_time); + ifoPrint_time(&cell_playback[i].playback_time); printf("\t"); if(cell_playback[i].block_mode || cell_playback[i].block_type) { @@ -709,7 +754,7 @@ printf("Number of Cells: %i\n", pgc->nr_of_cells); /* Check that time is 0:0:0:0 also if nr_of_programs==0 */ printf("Playback time: "); - ifoPrint_time(5, &pgc->playback_time); printf("\n"); + ifoPrint_time(&pgc->playback_time); printf("\n"); /* If no programs/no time then does this mean anything? */ printf("Prohibited user operations: "); @@ -734,7 +779,12 @@ printf("GoUp PGC number: %i\n", pgc->goup_pgc_nr); if(pgc->nr_of_programs != 0) { printf("Still time: %i seconds (255=inf)\n", pgc->still_time); - printf("PG Playback mode %02x\n", pgc->pg_playback_mode); + if(pgc->pg_playback_mode == 0) + printf("PG Playback mode: Sequential\n"); + else if(!(pgc->pg_playback_mode & 0x80)) + printf("PG Playback mode: Random %i\n", pgc->pg_playback_mode); + else + printf("PG Playback mode: Shuffle %i\n", pgc->pg_playback_mode & 0x7f ); } if(pgc->nr_of_programs != 0) { @@ -764,8 +814,23 @@ printf("\tNumber of PTTs: %i\n", tt_srpt->title[i].nr_of_ptts); printf("\tNumber of angles: %i\n", tt_srpt->title[i].nr_of_angles); - printf("\tTitle playback type: %02x\n", /* XXX: TODO FIXME */ - *(uint8_t *)&(tt_srpt->title[i].pb_ty)); + printf("\tTitle playback type: %s%s%s%s%s%s%s\n", + tt_srpt->title[i].pb_ty.multi_or_random_pgc_title ? + " One Random PGC Title or Multi PGC Title" : + " One Sequential PGC Title", + tt_srpt->title[i].pb_ty.jlc_exists_in_cell_cmd ? + "" : ", No Link/Jump/Call exists in Cell command", + tt_srpt->title[i].pb_ty.jlc_exists_in_prepost_cmd ? + "" : ", No Link/Jump/Call exists in Pre- and/or Post-command", + tt_srpt->title[i].pb_ty.jlc_exists_in_button_cmd ? + "" : ", No Link/Jump/Call exists in Button command", + tt_srpt->title[i].pb_ty.jlc_exists_in_tt_dom ? + "" : ", No Link/Jump/Call exists in TT_DOM", + tt_srpt->title[i].pb_ty.chapter_search_or_play ? + ", UOP1 (TT_Play and PTT_Search) prohibited" : "", + tt_srpt->title[i].pb_ty.title_or_time_play ? + ", UOP0 (Time_Play and Time_Search) prohibited" : "" + ); printf("\tParental ID field: %04x\n", tt_srpt->title[i].parental_id); printf("\tTitle set starting sector %08x\n", @@ -780,6 +845,8 @@ vts_ptt_srpt->nr_of_srpts, vts_ptt_srpt->last_byte); for(i=0;i<vts_ptt_srpt->nr_of_srpts;i++) { + printf("\nVTS_PTT number %d has a offset %d relative to VTS_PTT_SRPT\n", + i + 1, vts_ptt_srpt->ttu_offset[i]); for(j=0;j<vts_ptt_srpt->title[i].nr_of_ptts;j++) { printf("VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n", i + 1, j + 1, @@ -790,40 +857,57 @@ } -static void hexdump(uint8_t *ptr, int len) { - while(len--) - printf("%02x ", *ptr++); -} - void ifoPrint_PTL_MAIT(ptl_mait_t *ptl_mait) { - int i, j; + int i, level, vts; printf("Number of Countries: %i\n", ptl_mait->nr_of_countries); printf("Number of VTSs: %i\n", ptl_mait->nr_of_vtss); - //printf("Last byte: %i\n", ptl_mait->last_byte); + printf("Last byte: %i\n", ptl_mait->last_byte); for(i = 0; i < ptl_mait->nr_of_countries; i++) { - printf("Country code: %c%c\n", + + printf("Start byte: %i\n", ptl_mait->countries[i].pf_ptl_mai_start_byte); + printf("Parental Masks for country: %c%c\n", ptl_mait->countries[i].country_code >> 8, ptl_mait->countries[i].country_code & 0xff); - /* - printf("Start byte: %04x %i\n", - ptl_mait->countries[i].pf_ptl_mai_start_byte, - ptl_mait->countries[i].pf_ptl_mai_start_byte); - */ - /* This seems to be pointing at a array with 8 2byte fields per VTS - ? and one extra for the menu? always an odd number of VTSs on - all the dics I tested so it might be padding to even also. - If it is for the menu it probably the first entry. */ - for(j=0;j<8;j++) { - hexdump( (uint8_t *)ptl_mait->countries - PTL_MAIT_COUNTRY_SIZE - + ptl_mait->countries[i].pf_ptl_mai_start_byte - + j*(ptl_mait->nr_of_vtss+1)*2, (ptl_mait->nr_of_vtss+1)*2); + + for(vts = 0; vts <= ptl_mait->nr_of_vtss; vts++) { + if( vts == 0 ) { + printf("VMG "); + } else { + printf("VTS %2d ", vts); + } + for(level = 0; level < 8; level++) { + printf("%d: %04x ", level, + ptl_mait->countries[i].pf_ptl_mai[vts][level] ); + } printf("\n"); } } } +void ifoPrint_VTS_TMAPT(vts_tmapt_t *vts_tmapt) { + unsigned int timeunit; + int i, j; + + printf("Number of VTS_TMAPS: %i\n", vts_tmapt->nr_of_tmaps); + printf("Last byte: %i\n", vts_tmapt->last_byte); + + for(i = 0; i < vts_tmapt->nr_of_tmaps; i++) { + printf("TMAP %i\n", i + 1); + printf(" offset %d relative to VTS_TMAPTI\n", vts_tmapt->tmap_offset[i]); + printf(" Time unit (seconds): %i\n", vts_tmapt->tmap[i].tmu); + printf(" Number of entries: %i\n", vts_tmapt->tmap[i].nr_of_entries); + timeunit = vts_tmapt->tmap[i].tmu; + for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++) { + unsigned int ac_time = timeunit * (j + 1); + printf("Time: %2i:%02i:%02i VOBU Sector: 0x%08x %s\n", + ac_time / (60 * 60), (ac_time / 60) % 60, ac_time % 60, + vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff, + (vts_tmapt->tmap[i].map_ent[j] >> 31) ? "discontinuity" : ""); + } + } +} void ifoPrint_C_ADT(c_adt_t *c_adt) { int i, entries; @@ -870,9 +954,10 @@ printf("Number of Menu Language Units (PGCI_LU): %3i\n", pgci_ut->nr_of_lus); for(i = 0; i < pgci_ut->nr_of_lus; i++) { - printf("\nMenu Language Code: %c%c\n", + printf("\nMenu Language Code: %c%c (%c)\n", pgci_ut->lu[i].lang_code >> 8, - pgci_ut->lu[i].lang_code & 0xff); + pgci_ut->lu[i].lang_code & 0xff, + pgci_ut->lu[i].lang_extension ? pgci_ut->lu[i].lang_extension :' '); printf("Menu Existence: %02x\n", pgci_ut->lu[i].exists); ifoPrint_PGCIT(pgci_ut->lu[i].pgcit); } @@ -885,31 +970,31 @@ printf("VTS_CAT Application type: %08x\n", vts_attributes->vts_cat); printf("Video attributes of VTSM_VOBS: "); - ifoPrint_video_attributes(5, &vts_attributes->vtsm_vobs_attr); + ifoPrint_video_attributes(&vts_attributes->vtsm_vobs_attr); printf("\n"); printf("Number of Audio streams: %i\n", vts_attributes->nr_of_vtsm_audio_streams); if(vts_attributes->nr_of_vtsm_audio_streams > 0) { printf("\tstream %i attributes: ", 1); - ifoPrint_audio_attributes(5, &vts_attributes->vtsm_audio_attr); + ifoPrint_audio_attributes(&vts_attributes->vtsm_audio_attr); printf("\n"); } printf("Number of Subpicture streams: %i\n", vts_attributes->nr_of_vtsm_subp_streams); if(vts_attributes->nr_of_vtsm_subp_streams > 0) { printf("\tstream %2i attributes: ", 1); - ifoPrint_subp_attributes(5, &vts_attributes->vtsm_subp_attr); + ifoPrint_subp_attributes(&vts_attributes->vtsm_subp_attr); printf("\n"); } printf("Video attributes of VTSTT_VOBS: "); - ifoPrint_video_attributes(5, &vts_attributes->vtstt_vobs_video_attr); + ifoPrint_video_attributes(&vts_attributes->vtstt_vobs_video_attr); printf("\n"); printf("Number of Audio streams: %i\n", vts_attributes->nr_of_vtstt_audio_streams); for(i = 0; i < vts_attributes->nr_of_vtstt_audio_streams; i++) { printf("\tstream %i attributes: ", i); - ifoPrint_audio_attributes(5, &vts_attributes->vtstt_audio_attr[i]); + ifoPrint_audio_attributes(&vts_attributes->vtstt_audio_attr[i]); printf("\n"); } @@ -917,7 +1002,7 @@ vts_attributes->nr_of_vtstt_subp_streams); for(i = 0; i < vts_attributes->nr_of_vtstt_subp_streams; i++) { printf("\tstream %2i attributes: ", i); - ifoPrint_subp_attributes(5, &vts_attributes->vtstt_subp_attr[i]); + ifoPrint_subp_attributes(&vts_attributes->vtstt_subp_attr[i]); printf("\n"); } } @@ -929,6 +1014,8 @@ printf("Number of Video Title Sets: %3i\n", vts_atrt->nr_of_vtss); for(i = 0; i < vts_atrt->nr_of_vtss; i++) { printf("\nVideo Title Set %i\n", i + 1); + printf(" offset %d relative to VMG_VTS_ATRT\n", + vts_atrt->vts_atrt_offsets[i]); ifoPrint_VTS_ATTRIBUTES(&vts_atrt->vts[i]); } } @@ -1022,6 +1109,14 @@ } else { printf("No Menu PGCI Unit table present\n"); } + + printf("\nTime Search table\n"); + printf( "-----------------\n"); + if(ifohandle->vts_tmapt) { + ifoPrint_VTS_TMAPT(ifohandle->vts_tmapt); + } else { + printf("No Time Search table present\n"); + } printf("\nMenu Cell Adress table\n"); printf( "-----------------\n");
--- a/libmpdvdkit2/ifo_print.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/ifo_print.h Thu Jun 30 22:48:26 2005 +0000 @@ -53,6 +53,7 @@ void ifoPrint_PGC(pgc_t *); void ifoPrint_PGCIT(pgcit_t *); void ifoPrint_PGCI_UT(pgci_ut_t *); +void ifoPrint_VTS_TMAPT(vts_tmapt_t *); void ifoPrint_C_ADT(c_adt_t *); void ifoPrint_VOBU_ADMAP(vobu_admap_t *);
--- a/libmpdvdkit2/ifo_read.c Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/ifo_read.c Thu Jun 30 22:48:26 2005 +0000 @@ -1,10 +1,7 @@ /* - * Copyright (C) 2000, 2001, 2002 Björn Englund <d4bjorn@dtek.chalmers.se>, - * Håkan Hjort <d95hjort@dtek.chalmers.se> - * - * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. - * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ - * $Id$ + * Copyright (C) 2000, 2001, 2002, 2003 + * Björn Englund <d4bjorn@dtek.chalmers.se>, + * Håkan Hjort <d95hjort@dtek.chalmers.se> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,25 +18,29 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" + #include <stdio.h> #include <stdlib.h> -#include <unistd.h> #include <inttypes.h> #include <string.h> -//#include <assert.h> -#include "dvd_reader.h" - -#include "config.h" // Needed for WORDS_BIGENDIAN #include "bswap.h" #include "ifo_types.h" #include "ifo_read.h" +#include "dvd_reader.h" +#include "dvdread_internal.h" #ifndef DVD_BLOCK_LEN #define DVD_BLOCK_LEN 2048 #endif #ifndef NDEBUG +#define CHECK_ZERO0(arg) \ + if(arg != 0) { \ + fprintf(stderr, "*** Zero check failed in %s:%i\n for %s = 0x%x\n", \ + __FILE__, __LINE__, # arg, arg); \ + } #define CHECK_ZERO(arg) \ if(memcmp(my_friendly_zeros, &arg, sizeof(arg))) { \ unsigned int i_CZ; \ @@ -51,6 +52,7 @@ } static const uint8_t my_friendly_zeros[2048]; #else +#define CHECK_ZERO0(arg) (void)(arg) #define CHECK_ZERO(arg) (void)(arg) #endif @@ -87,7 +89,7 @@ static void ifoFree_PGCIT_internal(pgcit_t *pgcit); -static int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) { +static inline int DVDFileSeek_( dvd_file_t *dvd_file, uint32_t offset ) { return (DVDFileSeek(dvd_file, (int)offset) == (int)offset); } @@ -102,6 +104,8 @@ memset(ifofile, 0, sizeof(ifo_handle_t)); ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE); + if(!ifofile->file) /* Should really catch any error and try to fallback */ + ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE); if(!ifofile->file) { if(title) { fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title); @@ -150,6 +154,7 @@ ifoRead_PGCI_UT(ifofile); + ifoRead_VTS_TMAPT(ifofile); ifoRead_C_ADT(ifofile); ifoRead_VOBU_ADMAP(ifofile); @@ -184,6 +189,8 @@ memset(ifofile, 0, sizeof(ifo_handle_t)); ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_FILE); + if(!ifofile->file) /* Should really catch any error and try to fallback */ + ifofile->file = DVDOpenFile(dvd, 0, DVD_READ_INFO_BACKUP_FILE); if(!ifofile->file) { fprintf(stderr, "libdvdread: Can't open file VIDEO_TS.IFO.\n"); free(ifofile); @@ -215,6 +222,8 @@ } ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_FILE); + if(!ifofile->file) /* Should really catch any error and try to fallback */ + ifofile->file = DVDOpenFile(dvd, title, DVD_READ_INFO_BACKUP_FILE); if(!ifofile->file) { fprintf(stderr, "libdvdread: Can't open file VTS_%02d_0.IFO.\n", title); free(ifofile); @@ -320,33 +329,33 @@ CHECK_ZERO(vmgi_mat->zero_8); CHECK_ZERO(vmgi_mat->zero_9); CHECK_ZERO(vmgi_mat->zero_10); - assert(vmgi_mat->vmg_last_sector != 0); - assert(vmgi_mat->vmgi_last_sector != 0); - assert(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector); - assert(vmgi_mat->vmg_nr_of_volumes != 0); - assert(vmgi_mat->vmg_this_volume_nr != 0); - assert(vmgi_mat->vmg_this_volume_nr <= vmgi_mat->vmg_nr_of_volumes); - assert(vmgi_mat->disc_side == 1 || vmgi_mat->disc_side == 2); - assert(vmgi_mat->vmg_nr_of_title_sets != 0); - assert(vmgi_mat->vmgi_last_byte >= 341); - assert(vmgi_mat->vmgi_last_byte / DVD_BLOCK_LEN <= + CHECK_VALUE(vmgi_mat->vmg_last_sector != 0); + CHECK_VALUE(vmgi_mat->vmgi_last_sector != 0); + CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector); + CHECK_VALUE(vmgi_mat->vmgi_last_sector * 2 <= vmgi_mat->vmg_last_sector); + CHECK_VALUE(vmgi_mat->vmg_nr_of_volumes != 0); + CHECK_VALUE(vmgi_mat->vmg_this_volume_nr != 0); + CHECK_VALUE(vmgi_mat->vmg_this_volume_nr <= vmgi_mat->vmg_nr_of_volumes); + CHECK_VALUE(vmgi_mat->disc_side == 1 || vmgi_mat->disc_side == 2); + CHECK_VALUE(vmgi_mat->vmg_nr_of_title_sets != 0); + CHECK_VALUE(vmgi_mat->vmgi_last_byte >= 341); + CHECK_VALUE(vmgi_mat->vmgi_last_byte / DVD_BLOCK_LEN <= vmgi_mat->vmgi_last_sector); - /* It seems that first_play_pgc might be optional. */ - assert(vmgi_mat->first_play_pgc != 0 && - vmgi_mat->first_play_pgc < vmgi_mat->vmgi_last_byte); - assert(vmgi_mat->vmgm_vobs == 0 || + /* It seems that first_play_pgc is optional. */ + CHECK_VALUE(vmgi_mat->first_play_pgc < vmgi_mat->vmgi_last_byte); + CHECK_VALUE(vmgi_mat->vmgm_vobs == 0 || (vmgi_mat->vmgm_vobs > vmgi_mat->vmgi_last_sector && vmgi_mat->vmgm_vobs < vmgi_mat->vmg_last_sector)); - assert(vmgi_mat->tt_srpt <= vmgi_mat->vmgi_last_sector); - assert(vmgi_mat->vmgm_pgci_ut <= vmgi_mat->vmgi_last_sector); - assert(vmgi_mat->ptl_mait <= vmgi_mat->vmgi_last_sector); - assert(vmgi_mat->vts_atrt <= vmgi_mat->vmgi_last_sector); - assert(vmgi_mat->txtdt_mgi <= vmgi_mat->vmgi_last_sector); - assert(vmgi_mat->vmgm_c_adt <= vmgi_mat->vmgi_last_sector); - assert(vmgi_mat->vmgm_vobu_admap <= vmgi_mat->vmgi_last_sector); + CHECK_VALUE(vmgi_mat->tt_srpt <= vmgi_mat->vmgi_last_sector); + CHECK_VALUE(vmgi_mat->vmgm_pgci_ut <= vmgi_mat->vmgi_last_sector); + CHECK_VALUE(vmgi_mat->ptl_mait <= vmgi_mat->vmgi_last_sector); + CHECK_VALUE(vmgi_mat->vts_atrt <= vmgi_mat->vmgi_last_sector); + CHECK_VALUE(vmgi_mat->txtdt_mgi <= vmgi_mat->vmgi_last_sector); + CHECK_VALUE(vmgi_mat->vmgm_c_adt <= vmgi_mat->vmgi_last_sector); + CHECK_VALUE(vmgi_mat->vmgm_vobu_admap <= vmgi_mat->vmgi_last_sector); - assert(vmgi_mat->nr_of_vmgm_audio_streams <= 1); - assert(vmgi_mat->nr_of_vmgm_subp_streams <= 1); + CHECK_VALUE(vmgi_mat->nr_of_vmgm_audio_streams <= 1); + CHECK_VALUE(vmgi_mat->nr_of_vmgm_subp_streams <= 1); return 1; } @@ -422,34 +431,44 @@ CHECK_ZERO(vtsi_mat->zero_18); CHECK_ZERO(vtsi_mat->zero_19); CHECK_ZERO(vtsi_mat->zero_20); - assert(vtsi_mat->vtsi_last_sector*2 <= vtsi_mat->vts_last_sector); - assert(vtsi_mat->vtsi_last_byte/DVD_BLOCK_LEN <= vtsi_mat->vtsi_last_sector); - assert(vtsi_mat->vtsm_vobs == 0 || - (vtsi_mat->vtsm_vobs > vtsi_mat->vtsi_last_sector && + CHECK_ZERO(vtsi_mat->zero_21); + CHECK_VALUE(vtsi_mat->vtsi_last_sector*2 <= vtsi_mat->vts_last_sector); + CHECK_VALUE(vtsi_mat->vtsi_last_byte/DVD_BLOCK_LEN <= vtsi_mat->vtsi_last_sector); + CHECK_VALUE(vtsi_mat->vtsm_vobs == 0 || + (vtsi_mat->vtsm_vobs > vtsi_mat->vtsi_last_sector && vtsi_mat->vtsm_vobs < vtsi_mat->vts_last_sector)); - assert(vtsi_mat->vtstt_vobs == 0 || + CHECK_VALUE(vtsi_mat->vtstt_vobs == 0 || (vtsi_mat->vtstt_vobs > vtsi_mat->vtsi_last_sector && vtsi_mat->vtstt_vobs < vtsi_mat->vts_last_sector)); - assert(vtsi_mat->vts_ptt_srpt <= vtsi_mat->vtsi_last_sector); - assert(vtsi_mat->vts_pgcit <= vtsi_mat->vtsi_last_sector); - assert(vtsi_mat->vtsm_pgci_ut <= vtsi_mat->vtsi_last_sector); - assert(vtsi_mat->vts_tmapt <= vtsi_mat->vtsi_last_sector); - assert(vtsi_mat->vtsm_c_adt <= vtsi_mat->vtsi_last_sector); - assert(vtsi_mat->vtsm_vobu_admap <= vtsi_mat->vtsi_last_sector); - assert(vtsi_mat->vts_c_adt <= vtsi_mat->vtsi_last_sector); - assert(vtsi_mat->vts_vobu_admap <= vtsi_mat->vtsi_last_sector); + CHECK_VALUE(vtsi_mat->vts_ptt_srpt <= vtsi_mat->vtsi_last_sector); + CHECK_VALUE(vtsi_mat->vts_pgcit <= vtsi_mat->vtsi_last_sector); + CHECK_VALUE(vtsi_mat->vtsm_pgci_ut <= vtsi_mat->vtsi_last_sector); + CHECK_VALUE(vtsi_mat->vts_tmapt <= vtsi_mat->vtsi_last_sector); + CHECK_VALUE(vtsi_mat->vtsm_c_adt <= vtsi_mat->vtsi_last_sector); + CHECK_VALUE(vtsi_mat->vtsm_vobu_admap <= vtsi_mat->vtsi_last_sector); + CHECK_VALUE(vtsi_mat->vts_c_adt <= vtsi_mat->vtsi_last_sector); + CHECK_VALUE(vtsi_mat->vts_vobu_admap <= vtsi_mat->vtsi_last_sector); - assert(vtsi_mat->nr_of_vtsm_audio_streams <= 1); - assert(vtsi_mat->nr_of_vtsm_subp_streams <= 1); + CHECK_VALUE(vtsi_mat->nr_of_vtsm_audio_streams <= 1); + CHECK_VALUE(vtsi_mat->nr_of_vtsm_subp_streams <= 1); - assert(vtsi_mat->nr_of_vts_audio_streams <= 8); + CHECK_VALUE(vtsi_mat->nr_of_vts_audio_streams <= 8); for(i = vtsi_mat->nr_of_vts_audio_streams; i < 8; i++) CHECK_ZERO(vtsi_mat->vts_audio_attr[i]); - assert(vtsi_mat->nr_of_vts_subp_streams <= 32); + CHECK_VALUE(vtsi_mat->nr_of_vts_subp_streams <= 32); for(i = vtsi_mat->nr_of_vts_subp_streams; i < 32; i++) CHECK_ZERO(vtsi_mat->vts_subp_attr[i]); - + + for(i = 0; i < 8; i++) { + CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero1); + CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero2); + CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero3); + CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero4); + CHECK_ZERO0(vtsi_mat->vts_mu_audio_attr[i].zero5); + CHECK_ZERO(vtsi_mat->vts_mu_audio_attr[i].zero6); + } + return 1; } @@ -470,7 +489,7 @@ B2N_16(cmd_tbl->nr_of_post); B2N_16(cmd_tbl->nr_of_cell); - assert(cmd_tbl->nr_of_pre + cmd_tbl->nr_of_post + cmd_tbl->nr_of_cell<= 255); + CHECK_VALUE(cmd_tbl->nr_of_pre + cmd_tbl->nr_of_post + cmd_tbl->nr_of_cell<= 255); if(cmd_tbl->nr_of_pre != 0) { unsigned int pre_cmds_size = cmd_tbl->nr_of_pre * COMMAND_DATA_SIZE; @@ -572,9 +591,9 @@ B2N_32(cell_playback[i].last_sector); /* Changed < to <= because this was false in the movie 'Pi'. */ - assert(cell_playback[i].last_vobu_start_sector <= + CHECK_VALUE(cell_playback[i].last_vobu_start_sector <= cell_playback[i].last_sector); - assert(cell_playback[i].first_sector <= + CHECK_VALUE(cell_playback[i].first_sector <= cell_playback[i].last_vobu_start_sector); } @@ -627,7 +646,7 @@ B2N_32(pgc->palette[i]); CHECK_ZERO(pgc->zero_1); - assert(pgc->nr_of_programs <= pgc->nr_of_cells); + CHECK_VALUE(pgc->nr_of_programs <= pgc->nr_of_cells); /* verify time (look at print_time) */ for(i = 0; i < 8; i++) @@ -641,13 +660,13 @@ if(pgc->nr_of_programs == 0) { CHECK_ZERO(pgc->still_time); CHECK_ZERO(pgc->pg_playback_mode); // ?? - assert(pgc->program_map_offset == 0); - assert(pgc->cell_playback_offset == 0); - assert(pgc->cell_position_offset == 0); + CHECK_VALUE(pgc->program_map_offset == 0); + CHECK_VALUE(pgc->cell_playback_offset == 0); + CHECK_VALUE(pgc->cell_position_offset == 0); } else { - assert(pgc->program_map_offset != 0); - assert(pgc->cell_playback_offset != 0); - assert(pgc->cell_position_offset != 0); + CHECK_VALUE(pgc->program_map_offset != 0); + CHECK_VALUE(pgc->cell_playback_offset != 0); + CHECK_VALUE(pgc->cell_position_offset != 0); } if(pgc->command_tbl_offset != 0) { @@ -728,11 +747,10 @@ if(!ifofile->vmgi_mat) return 0; - /* It seems that first_play_pgc might be optional after all. */ - if(ifofile->vmgi_mat->first_play_pgc == 0) { /* mandatory */ - ifofile->first_play_pgc = 0; - return 0; /* change this to a 1 if it's optional. */ - } + /* It seems that first_play_pgc is optional after all. */ + ifofile->first_play_pgc = 0; + if(ifofile->vmgi_mat->first_play_pgc == 0) + return 1; ifofile->first_play_pgc = (pgc_t *)malloc(sizeof(pgc_t)); if(!ifofile->first_play_pgc) @@ -825,22 +843,22 @@ CHECK_ZERO(tt_srpt->zero_1); - assert(tt_srpt->nr_of_srpts != 0); - assert(tt_srpt->nr_of_srpts < 100); // ?? - assert((int)tt_srpt->nr_of_srpts * sizeof(title_info_t) <= info_length); + CHECK_VALUE(tt_srpt->nr_of_srpts != 0); + CHECK_VALUE(tt_srpt->nr_of_srpts < 100); // ?? + CHECK_VALUE((int)tt_srpt->nr_of_srpts * sizeof(title_info_t) <= info_length); for(i = 0; i < tt_srpt->nr_of_srpts; i++) { - assert(tt_srpt->title[i].pb_ty.zero_1 == 0); - assert(tt_srpt->title[i].nr_of_angles != 0); - assert(tt_srpt->title[i].nr_of_angles < 10); - //assert(tt_srpt->title[i].nr_of_ptts != 0); + CHECK_VALUE(tt_srpt->title[i].pb_ty.zero_1 == 0); + CHECK_VALUE(tt_srpt->title[i].nr_of_angles != 0); + CHECK_VALUE(tt_srpt->title[i].nr_of_angles < 10); + //CHECK_VALUE(tt_srpt->title[i].nr_of_ptts != 0); // XXX: this assertion breaks Ghostbusters: - assert(tt_srpt->title[i].nr_of_ptts < 1000); // ?? - assert(tt_srpt->title[i].title_set_nr != 0); - assert(tt_srpt->title[i].title_set_nr < 100); // ?? - assert(tt_srpt->title[i].vts_ttn != 0); - assert(tt_srpt->title[i].vts_ttn < 100); // ?? - //assert(tt_srpt->title[i].title_set_sector != 0); + CHECK_VALUE(tt_srpt->title[i].nr_of_ptts < 1000); // ?? + CHECK_VALUE(tt_srpt->title[i].title_set_nr != 0); + CHECK_VALUE(tt_srpt->title[i].title_set_nr < 100); // ?? + CHECK_VALUE(tt_srpt->title[i].vts_ttn != 0); + CHECK_VALUE(tt_srpt->title[i].vts_ttn < 100); // ?? + //CHECK_VALUE(tt_srpt->title[i].title_set_sector != 0); } // Make this a function @@ -906,8 +924,8 @@ B2N_32(vts_ptt_srpt->last_byte); CHECK_ZERO(vts_ptt_srpt->zero_1); - assert(vts_ptt_srpt->nr_of_srpts != 0); - assert(vts_ptt_srpt->nr_of_srpts < 100); // ?? + CHECK_VALUE(vts_ptt_srpt->nr_of_srpts != 0); + CHECK_VALUE(vts_ptt_srpt->nr_of_srpts < 100); // ?? info_length = vts_ptt_srpt->last_byte + 1 - VTS_PTT_SRPT_SIZE; @@ -931,8 +949,10 @@ Magic Knight Rayearth Daybreak is mastered very strange and has Titles with 0 PTTs. They all have a data[i] offsets beyond the end of of the vts_ptt_srpt structure. */ - assert(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1 + 4); + CHECK_VALUE(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1 + 4); } + + vts_ptt_srpt->ttu_offset = data; vts_ptt_srpt->title = malloc(vts_ptt_srpt->nr_of_srpts * sizeof(ttu_t)); if(!vts_ptt_srpt->title) { @@ -951,7 +971,7 @@ Magic Knight Rayearth Daybreak is mastered very strange and has Titles with 0 PTTs. */ if(n < 0) n = 0; - assert(n % 4 == 0); + CHECK_VALUE(n % 4 == 0); vts_ptt_srpt->title[i].nr_of_ptts = n / 4; vts_ptt_srpt->title[i].ptt = malloc(n * sizeof(ptt_info_t)); @@ -965,14 +985,13 @@ } for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) { /* The assert placed here because of Magic Knight Rayearth Daybreak */ - assert(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1); + CHECK_VALUE(data[i] + sizeof(ptt_info_t) <= vts_ptt_srpt->last_byte + 1); vts_ptt_srpt->title[i].ptt[j].pgcn = *(uint16_t*)(((char *)data) + data[i] + 4*j - VTS_PTT_SRPT_SIZE); vts_ptt_srpt->title[i].ptt[j].pgn = *(uint16_t*)(((char *)data) + data[i] + 4*j + 2 - VTS_PTT_SRPT_SIZE); } } - free(data); for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) { for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) { @@ -982,12 +1001,12 @@ } for(i = 0; i < vts_ptt_srpt->nr_of_srpts; i++) { - assert(vts_ptt_srpt->title[i].nr_of_ptts < 1000); // ?? + CHECK_VALUE(vts_ptt_srpt->title[i].nr_of_ptts < 1000); // ?? for(j = 0; j < vts_ptt_srpt->title[i].nr_of_ptts; j++) { - assert(vts_ptt_srpt->title[i].ptt[j].pgcn != 0 ); - assert(vts_ptt_srpt->title[i].ptt[j].pgcn < 1000); // ?? - assert(vts_ptt_srpt->title[i].ptt[j].pgn != 0); - assert(vts_ptt_srpt->title[i].ptt[j].pgn < 100); // ?? + CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn != 0 ); + CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgcn < 1000); // ?? + CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn != 0); + CHECK_VALUE(vts_ptt_srpt->title[i].ptt[j].pgn < 100); // ?? } } @@ -1003,6 +1022,7 @@ int i; for(i = 0; i < ifofile->vts_ptt_srpt->nr_of_srpts; i++) free(ifofile->vts_ptt_srpt->title[i].ptt); + free(ifofile->vts_ptt_srpt->ttu_offset); free(ifofile->vts_ptt_srpt->title); free(ifofile->vts_ptt_srpt); ifofile->vts_ptt_srpt = 0; @@ -1013,7 +1033,7 @@ int ifoRead_PTL_MAIT(ifo_handle_t *ifofile) { ptl_mait_t *ptl_mait; int info_length; - unsigned int i; + unsigned int i, j; if(!ifofile) return 0; @@ -1024,8 +1044,7 @@ if(ifofile->vmgi_mat->ptl_mait == 0) return 1; - if(!DVDFileSeek_(ifofile->file, - ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN)) + if(!DVDFileSeek_(ifofile->file, ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN)) return 0; ptl_mait = (ptl_mait_t *)malloc(sizeof(ptl_mait_t)); @@ -1044,26 +1063,29 @@ B2N_16(ptl_mait->nr_of_vtss); B2N_32(ptl_mait->last_byte); - info_length = ptl_mait->last_byte + 1 - PTL_MAIT_SIZE; + CHECK_VALUE(ptl_mait->nr_of_countries != 0); + CHECK_VALUE(ptl_mait->nr_of_countries < 100); // ?? + CHECK_VALUE(ptl_mait->nr_of_vtss != 0); + CHECK_VALUE(ptl_mait->nr_of_vtss < 100); // ?? + CHECK_VALUE(ptl_mait->nr_of_countries * PTL_MAIT_COUNTRY_SIZE + <= ptl_mait->last_byte + 1 - PTL_MAIT_SIZE); - assert(ptl_mait->nr_of_countries != 0); - assert(ptl_mait->nr_of_countries < 100); // ?? - assert(ptl_mait->nr_of_vtss != 0); - assert(ptl_mait->nr_of_vtss < 100); // ?? - assert(ptl_mait->nr_of_countries * PTL_MAIT_COUNTRY_SIZE <= info_length); - - /* Change this to read and 'translate' the tables too. - I.e don't read so much here */ + info_length = ptl_mait->nr_of_countries * sizeof(ptl_mait_country_t); ptl_mait->countries = (ptl_mait_country_t *)malloc(info_length); if(!ptl_mait->countries) { free(ptl_mait); ifofile->ptl_mait = 0; return 0; } - if(!(DVDReadBytes(ifofile->file, ptl_mait->countries, info_length))) { - fprintf(stderr, "libdvdread: Unable to read PTL_MAIT.\n"); - ifoFree_PTL_MAIT(ifofile); - return 0; + + for(i = 0; i < ptl_mait->nr_of_countries; i++) { + if(!(DVDReadBytes(ifofile->file, &ptl_mait->countries[i], PTL_MAIT_COUNTRY_SIZE))) { + fprintf(stderr, "libdvdread: Unable to read PTL_MAIT.\n"); + free(ptl_mait->countries); + free(ptl_mait); + ifofile->ptl_mait = 0; + return 0; + } } for(i = 0; i < ptl_mait->nr_of_countries; i++) { @@ -1074,25 +1096,221 @@ for(i = 0; i < ptl_mait->nr_of_countries; i++) { CHECK_ZERO(ptl_mait->countries[i].zero_1); CHECK_ZERO(ptl_mait->countries[i].zero_2); - assert(ptl_mait->countries[i].pf_ptl_mai_start_byte + - 8 * (ptl_mait->nr_of_vtss + 1) * 2 <= ptl_mait->last_byte + 1); + CHECK_VALUE(ptl_mait->countries[i].pf_ptl_mai_start_byte + + 8*2 * (ptl_mait->nr_of_vtss + 1) <= ptl_mait->last_byte + 1); } + for(i = 0; i < ptl_mait->nr_of_countries; i++) { + uint16_t *pf_temp; + + if(!DVDFileSeek_(ifofile->file, + ifofile->vmgi_mat->ptl_mait * DVD_BLOCK_LEN + + ptl_mait->countries[i].pf_ptl_mai_start_byte)) { + fprintf(stderr, "libdvdread: Unable to seak PTL_MAIT table.\n"); + free(ptl_mait->countries); + free(ptl_mait); + return 0; + } + info_length = (ptl_mait->nr_of_vtss + 1) * sizeof(pf_level_t); + pf_temp = (uint16_t *)malloc(info_length); + if(!pf_temp) { + for(j = 0; j < i ; j++) { + free(ptl_mait->countries[j].pf_ptl_mai); + } + free(ptl_mait->countries); + free(ptl_mait); + return 0; + } + if(!(DVDReadBytes(ifofile->file, pf_temp, info_length))) { + fprintf(stderr, "libdvdread: Unable to read PTL_MAIT table.\n"); + free(pf_temp); + for(j = 0; j < i ; j++) { + free(ptl_mait->countries[j].pf_ptl_mai); + } + free(ptl_mait->countries); + free(ptl_mait); + return 0; + } + for (j = 0; j < ((ptl_mait->nr_of_vtss + 1) * 8); j++) { + B2N_16(pf_temp[j]); + } + ptl_mait->countries[i].pf_ptl_mai = (pf_level_t *)malloc(info_length); + if(!ptl_mait->countries[i].pf_ptl_mai) { + free(pf_temp); + for(j = 0; j < i ; j++) { + free(ptl_mait->countries[j].pf_ptl_mai); + } + free(ptl_mait->countries); + free(ptl_mait); + return 0; + } + { /* Transpose the array so we can use C indexing. */ + int level, vts; + for(level = 0; level < 8; level++) { + for(vts = 0; vts <= ptl_mait->nr_of_vtss; vts++) { + ptl_mait->countries[i].pf_ptl_mai[vts][level] = + pf_temp[(7-level)*(ptl_mait->nr_of_vtss+1) + vts]; + } + } + free(pf_temp); + } + } return 1; } - void ifoFree_PTL_MAIT(ifo_handle_t *ifofile) { + unsigned int i; + if(!ifofile) return; if(ifofile->ptl_mait) { + for(i = 0; i < ifofile->ptl_mait->nr_of_countries; i++) { + free(ifofile->ptl_mait->countries[i].pf_ptl_mai); + } free(ifofile->ptl_mait->countries); free(ifofile->ptl_mait); ifofile->ptl_mait = 0; } } +int ifoRead_VTS_TMAPT(ifo_handle_t *ifofile) { + vts_tmapt_t *vts_tmapt; + uint32_t *vts_tmap_srp; + unsigned int offset; + int info_length; + unsigned int i, j; + + if(!ifofile) + return 0; + + if(!ifofile->vtsi_mat) + return 0; + + if(ifofile->vtsi_mat->vts_tmapt == 0) { /* optional(?) */ + ifofile->vts_tmapt = NULL; + fprintf(stderr,"Please send bug report - no VTS_TMAPT ?? \n"); + return 1; + } + + offset = ifofile->vtsi_mat->vts_tmapt * DVD_BLOCK_LEN; + + if(!DVDFileSeek_(ifofile->file, offset)) + return 0; + + vts_tmapt = (vts_tmapt_t *)malloc(sizeof(vts_tmapt_t)); + if(!vts_tmapt) + return 0; + + ifofile->vts_tmapt = vts_tmapt; + + if(!(DVDReadBytes(ifofile->file, vts_tmapt, VTS_TMAPT_SIZE))) { + fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n"); + free(vts_tmapt); + ifofile->vts_tmapt = NULL; + return 0; + } + + B2N_16(vts_tmapt->nr_of_tmaps); + B2N_32(vts_tmapt->last_byte); + + CHECK_ZERO(vts_tmapt->zero_1); + + info_length = vts_tmapt->nr_of_tmaps * 4; + + vts_tmap_srp = (uint32_t *)malloc(info_length); + if(!vts_tmap_srp) { + free(vts_tmapt); + ifofile->vts_tmapt = NULL; + return 0; + } + + vts_tmapt->tmap_offset = vts_tmap_srp; + + if(!(DVDReadBytes(ifofile->file, vts_tmap_srp, info_length))) { + fprintf(stderr, "libdvdread: Unable to read VTS_TMAPT.\n"); + free(vts_tmap_srp); + free(vts_tmapt); + ifofile->vts_tmapt = NULL; + return 0; + } + + for (i = 0; i < vts_tmapt->nr_of_tmaps; i++) { + B2N_32(vts_tmap_srp[i]); + } + + + info_length = vts_tmapt->nr_of_tmaps * sizeof(vts_tmap_t); + + vts_tmapt->tmap = (vts_tmap_t *)malloc(info_length); + if(!vts_tmapt->tmap) { + free(vts_tmap_srp); + free(vts_tmapt); + ifofile->vts_tmapt = NULL; + return 0; + } + + memset(vts_tmapt->tmap, 0, info_length); /* So ifoFree_VTS_TMAPT works. */ + + for(i = 0; i < vts_tmapt->nr_of_tmaps; i++) { + if(!DVDFileSeek_(ifofile->file, offset + vts_tmap_srp[i])) { + ifoFree_VTS_TMAPT(ifofile); + return 0; + } + + if(!(DVDReadBytes(ifofile->file, &vts_tmapt->tmap[i], VTS_TMAP_SIZE))) { + fprintf(stderr, "libdvdread: Unable to read VTS_TMAP.\n"); + ifoFree_VTS_TMAPT(ifofile); + return 0; + } + + B2N_16(vts_tmapt->tmap[i].nr_of_entries); + CHECK_ZERO(vts_tmapt->tmap[i].zero_1); + + if(vts_tmapt->tmap[i].nr_of_entries == 0) { /* Early out if zero entries */ + vts_tmapt->tmap[i].map_ent = NULL; + continue; + } + + info_length = vts_tmapt->tmap[i].nr_of_entries * sizeof(map_ent_t); + + vts_tmapt->tmap[i].map_ent = (map_ent_t *)malloc(info_length); + if(!vts_tmapt->tmap[i].map_ent) { + ifoFree_VTS_TMAPT(ifofile); + return 0; + } + + if(!(DVDReadBytes(ifofile->file, vts_tmapt->tmap[i].map_ent, info_length))) { + fprintf(stderr, "libdvdread: Unable to read VTS_TMAP_ENT.\n"); + ifoFree_VTS_TMAPT(ifofile); + return 0; + } + + for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++) + B2N_32(vts_tmapt->tmap[i].map_ent[j]); + } + + return 1; +} + +void ifoFree_VTS_TMAPT(ifo_handle_t *ifofile) { + unsigned int i; + + if(!ifofile) + return; + + if(ifofile->vts_tmapt) { + for(i = 0; i < ifofile->vts_tmapt->nr_of_tmaps; i++) + if(ifofile->vts_tmapt->tmap[i].map_ent) + free(ifofile->vts_tmapt->tmap[i].map_ent); + free(ifofile->vts_tmapt->tmap); + free(ifofile->vts_tmapt->tmap_offset); + free(ifofile->vts_tmapt); + ifofile->vts_tmapt = NULL; + } +} + + int ifoRead_TITLE_C_ADT(ifo_handle_t *ifofile) { if(!ifofile) @@ -1168,7 +1386,7 @@ /* assert(c_adt->nr_of_vobs > 0); Magic Knight Rayearth Daybreak is mastered very strange and has Titles with a VOBS that has no cells. */ - assert(info_length % sizeof(cell_adr_t) == 0); + CHECK_VALUE(info_length % sizeof(cell_adr_t) == 0); /* assert(info_length / sizeof(cell_adr_t) >= c_adt->nr_of_vobs); Enemy of the State region 2 (de) has Titles where nr_of_vobs field @@ -1194,10 +1412,10 @@ B2N_32(c_adt->cell_adr_table[i].last_sector); CHECK_ZERO(c_adt->cell_adr_table[i].zero_1); - assert(c_adt->cell_adr_table[i].vob_id > 0); - assert(c_adt->cell_adr_table[i].vob_id <= c_adt->nr_of_vobs); - assert(c_adt->cell_adr_table[i].cell_id > 0); - assert(c_adt->cell_adr_table[i].start_sector < + CHECK_VALUE(c_adt->cell_adr_table[i].vob_id > 0); + CHECK_VALUE(c_adt->cell_adr_table[i].vob_id <= c_adt->nr_of_vobs); + CHECK_VALUE(c_adt->cell_adr_table[i].cell_id > 0); + CHECK_VALUE(c_adt->cell_adr_table[i].start_sector < c_adt->cell_adr_table[i].last_sector); } @@ -1301,7 +1519,7 @@ /* assert(info_length > 0); Magic Knight Rayearth Daybreak is mastered very strange and has Titles with a VOBS that has no VOBUs. */ - assert(info_length % sizeof(uint32_t) == 0); + CHECK_VALUE(info_length % sizeof(uint32_t) == 0); vobu_admap->vobu_start_sectors = (uint32_t *)malloc(info_length); if(!vobu_admap->vobu_start_sectors) { @@ -1387,7 +1605,7 @@ /* assert(pgcit->nr_of_pgci_srp != 0); Magic Knight Rayearth Daybreak is mastered very strange and has Titles with 0 PTTs. */ - assert(pgcit->nr_of_pgci_srp < 10000); // ?? seen max of 1338 + CHECK_VALUE(pgcit->nr_of_pgci_srp < 10000); // ?? seen max of 1338 info_length = pgcit->nr_of_pgci_srp * PGCI_SRP_SIZE; data = malloc(info_length); @@ -1410,12 +1628,12 @@ ptr += PGCI_LU_SIZE; B2N_16(pgcit->pgci_srp[i].ptl_id_mask); B2N_32(pgcit->pgci_srp[i].pgc_start_byte); - assert(pgcit->pgci_srp[i].unknown1 == 0); + CHECK_VALUE(pgcit->pgci_srp[i].unknown1 == 0); } free(data); for(i = 0; i < pgcit->nr_of_pgci_srp; i++) - assert(pgcit->pgci_srp[i].pgc_start_byte + PGC_SIZE <= pgcit->last_byte+1); + CHECK_VALUE(pgcit->pgci_srp[i].pgc_start_byte + PGC_SIZE <= pgcit->last_byte+1); for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { pgcit->pgci_srp[i].pgc = malloc(sizeof(pgc_t)); @@ -1507,9 +1725,9 @@ B2N_32(pgci_ut->last_byte); CHECK_ZERO(pgci_ut->zero_1); - assert(pgci_ut->nr_of_lus != 0); - assert(pgci_ut->nr_of_lus < 100); // ?? 3-4 ? - assert((uint32_t)pgci_ut->nr_of_lus * PGCI_LU_SIZE < pgci_ut->last_byte); + CHECK_VALUE(pgci_ut->nr_of_lus != 0); + CHECK_VALUE(pgci_ut->nr_of_lus < 100); // ?? 3-4 ? + CHECK_VALUE((uint32_t)pgci_ut->nr_of_lus * PGCI_LU_SIZE < pgci_ut->last_byte); info_length = pgci_ut->nr_of_lus * PGCI_LU_SIZE; data = malloc(info_length); @@ -1542,7 +1760,6 @@ free(data); for(i = 0; i < pgci_ut->nr_of_lus; i++) { - CHECK_ZERO(pgci_ut->lu[i].zero_1); // Maybe this is only defined for v1.1 and later titles? /* If the bits in 'lu[i].exists' are enumerated abcd efgh then: VTS_x_yy.IFO VIDEO_TS.IFO @@ -1552,7 +1769,7 @@ d == 0x86 "Angle" e == 0x87 "PTT" */ - assert((pgci_ut->lu[i].exists & 0x07) == 0); + CHECK_VALUE((pgci_ut->lu[i].exists & 0x07) == 0); } for(i = 0; i < pgci_ut->nr_of_lus; i++) { @@ -1634,21 +1851,21 @@ CHECK_ZERO(vts_attributes->zero_5); CHECK_ZERO(vts_attributes->zero_6); CHECK_ZERO(vts_attributes->zero_7); - assert(vts_attributes->nr_of_vtsm_audio_streams <= 1); - assert(vts_attributes->nr_of_vtsm_subp_streams <= 1); - assert(vts_attributes->nr_of_vtstt_audio_streams <= 8); + CHECK_VALUE(vts_attributes->nr_of_vtsm_audio_streams <= 1); + CHECK_VALUE(vts_attributes->nr_of_vtsm_subp_streams <= 1); + CHECK_VALUE(vts_attributes->nr_of_vtstt_audio_streams <= 8); for(i = vts_attributes->nr_of_vtstt_audio_streams; i < 8; i++) CHECK_ZERO(vts_attributes->vtstt_audio_attr[i]); - assert(vts_attributes->nr_of_vtstt_subp_streams <= 32); + CHECK_VALUE(vts_attributes->nr_of_vtstt_subp_streams <= 32); { unsigned int nr_coded; - assert(vts_attributes->last_byte + 1 >= VTS_ATTRIBUTES_MIN_SIZE); + CHECK_VALUE(vts_attributes->last_byte + 1 >= VTS_ATTRIBUTES_MIN_SIZE); nr_coded = (vts_attributes->last_byte + 1 - VTS_ATTRIBUTES_MIN_SIZE)/6; // This is often nr_coded = 70, how do you know how many there really are? if(nr_coded > 32) { // We haven't read more from disk/file anyway nr_coded = 32; } - assert(vts_attributes->nr_of_vtstt_subp_streams <= nr_coded); + CHECK_VALUE(vts_attributes->nr_of_vtstt_subp_streams <= nr_coded); for(i = vts_attributes->nr_of_vtstt_subp_streams; i < nr_coded; i++) CHECK_ZERO(vts_attributes->vtstt_subp_attr[i]); } @@ -1692,9 +1909,9 @@ B2N_32(vts_atrt->last_byte); CHECK_ZERO(vts_atrt->zero_1); - assert(vts_atrt->nr_of_vtss != 0); - assert(vts_atrt->nr_of_vtss < 100); //?? - assert((uint32_t)vts_atrt->nr_of_vtss * (4 + VTS_ATTRIBUTES_MIN_SIZE) + + CHECK_VALUE(vts_atrt->nr_of_vtss != 0); + CHECK_VALUE(vts_atrt->nr_of_vtss < 100); //?? + CHECK_VALUE((uint32_t)vts_atrt->nr_of_vtss * (4 + VTS_ATTRIBUTES_MIN_SIZE) + VTS_ATRT_SIZE < vts_atrt->last_byte + 1); info_length = vts_atrt->nr_of_vtss * sizeof(uint32_t); @@ -1704,6 +1921,9 @@ ifofile->vts_atrt = 0; return 0; } + + vts_atrt->vts_atrt_offsets = data; + if(!(DVDReadBytes(ifofile->file, data, info_length))) { free(data); free(vts_atrt); @@ -1713,7 +1933,7 @@ for(i = 0; i < vts_atrt->nr_of_vtss; i++) { B2N_32(data[i]); - assert(data[i] + VTS_ATTRIBUTES_MIN_SIZE < vts_atrt->last_byte + 1); + CHECK_VALUE(data[i] + VTS_ATTRIBUTES_MIN_SIZE < vts_atrt->last_byte + 1); } info_length = vts_atrt->nr_of_vtss * sizeof(vts_attributes_t); @@ -1735,10 +1955,9 @@ } // This assert cant be in ifoRead_VTS_ATTRIBUTES - assert(offset + vts_atrt->vts[i].last_byte <= vts_atrt->last_byte + 1); + CHECK_VALUE(offset + vts_atrt->vts[i].last_byte <= vts_atrt->last_byte + 1); // Is this check correct? } - free(data); return 1; } @@ -1750,6 +1969,7 @@ if(ifofile->vts_atrt) { free(ifofile->vts_atrt->vts); + free(ifofile->vts_atrt->vts_atrt_offsets); free(ifofile->vts_atrt); ifofile->vts_atrt = 0; }
--- a/libmpdvdkit2/ifo_read.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/ifo_read.h Thu Jun 30 22:48:26 2005 +0000 @@ -114,8 +114,7 @@ * * Reads in the first play program chain data, filling the * ifofile->first_play_pgc structure. This data is only located in the video - * manager information file. This structure is mandatory, and must be included - * in the VMGI file. **Possibly this is only optional.** + * manager information file (VMGI). This structure is optional. */ int ifoRead_FP_PGC(ifo_handle_t *); @@ -141,7 +140,17 @@ * VTSI files, this fills the ifofile->vtsm_pgci_ut structure. */ int ifoRead_PGCI_UT(ifo_handle_t *); - + +/** + * okay = ifoRead_VTS_TMAPT(ifofile); + * + * Reads in the VTS Time Map Table, this data is only located in the video + * title set information file. This fills the ifofile->vts_tmapt structure + * and all its substructures. When pressent enables VOBU level time-based + * seeking for One_Sequential_PGC_Titles. + */ +int ifoRead_VTS_TMAPT(ifo_handle_t *); + /** * okay = ifoRead_C_ADT(ifofile); * @@ -209,6 +218,7 @@ void ifoFree_FP_PGC(ifo_handle_t *); void ifoFree_PGCIT(ifo_handle_t *); void ifoFree_PGCI_UT(ifo_handle_t *); +void ifoFree_VTS_TMAPT(ifo_handle_t *); void ifoFree_C_ADT(ifo_handle_t *); void ifoFree_TITLE_C_ADT(ifo_handle_t *); void ifoFree_VOBU_ADMAP(ifo_handle_t *);
--- a/libmpdvdkit2/ifo_types.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/ifo_types.h Thu Jun 30 22:48:26 2005 +0000 @@ -63,7 +63,7 @@ uint8_t hour; uint8_t minute; uint8_t second; - uint8_t frame_u; // The two high bits are the frame rate. + uint8_t frame_u; /* The two high bits are the frame rate. */ } ATTRIBUTE_PACKED dvd_time_t; /** @@ -87,7 +87,8 @@ unsigned int line21_cc_1 : 1; unsigned int line21_cc_2 : 1; - unsigned int unknown1 : 2; + unsigned int unknown1 : 1; + unsigned int bit_rate : 1; unsigned int picture_size : 2; unsigned int letterboxed : 1; @@ -102,14 +103,15 @@ unsigned int letterboxed : 1; unsigned int picture_size : 2; - unsigned int unknown1 : 2; + unsigned int bit_rate : 1; + unsigned int unknown1 : 1; unsigned int line21_cc_2 : 1; unsigned int line21_cc_1 : 1; #endif } ATTRIBUTE_PACKED video_attr_t; /** - * Audio Attributes. (Incomplete/Wrong?) + * Audio Attributes. */ typedef struct { #ifdef WORDS_BIGENDIAN @@ -134,13 +136,99 @@ unsigned int quantization : 2; #endif uint16_t lang_code; - uint8_t lang_code2; // ?? uint8_t lang_extension; - uint16_t unknown2; + uint8_t code_extension; + uint8_t unknown3; + union { + struct ATTRIBUTE_PACKED { +#ifdef WORDS_BIGENDIAN + unsigned int unknown4 : 1; + unsigned int channel_assignment : 3; + unsigned int version : 2; + unsigned int mc_intro : 1; /* probably 0: true, 1:false */ + unsigned int mode : 1; /* Karaoke mode 0: solo 1: duet */ +#else + unsigned int mode : 1; + unsigned int mc_intro : 1; + unsigned int version : 2; + unsigned int channel_assignment : 3; + unsigned int unknown4 : 1; +#endif + } karaoke; + struct ATTRIBUTE_PACKED { +#ifdef WORDS_BIGENDIAN + unsigned int unknown5 : 4; + unsigned int dolby_encoded : 1; /* suitable for surround decoding */ + unsigned int unknown6 : 3; +#else + unsigned int unknown6 : 3; + unsigned int dolby_encoded : 1; + unsigned int unknown5 : 4; +#endif + } surround; + } app_info; } ATTRIBUTE_PACKED audio_attr_t; + /** - * Subpicture Attributes.(Incomplete/Wrong) + * MultiChannel Extension + */ +typedef struct { +#ifdef WORDS_BIGENDIAN + unsigned int zero1 : 7; + unsigned int ach0_gme : 1; + + unsigned int zero2 : 7; + unsigned int ach1_gme : 1; + + unsigned int zero3 : 4; + unsigned int ach2_gv1e : 1; + unsigned int ach2_gv2e : 1; + unsigned int ach2_gm1e : 1; + unsigned int ach2_gm2e : 1; + + unsigned int zero4 : 4; + unsigned int ach3_gv1e : 1; + unsigned int ach3_gv2e : 1; + unsigned int ach3_gmAe : 1; + unsigned int ach3_se2e : 1; + + unsigned int zero5 : 4; + unsigned int ach4_gv1e : 1; + unsigned int ach4_gv2e : 1; + unsigned int ach4_gmBe : 1; + unsigned int ach4_seBe : 1; +#else + unsigned int ach0_gme : 1; + unsigned int zero1 : 7; + + unsigned int ach1_gme : 1; + unsigned int zero2 : 7; + + unsigned int ach2_gm2e : 1; + unsigned int ach2_gm1e : 1; + unsigned int ach2_gv2e : 1; + unsigned int ach2_gv1e : 1; + unsigned int zero3 : 4; + + unsigned int ach3_se2e : 1; + unsigned int ach3_gmAe : 1; + unsigned int ach3_gv2e : 1; + unsigned int ach3_gv1e : 1; + unsigned int zero4 : 4; + + unsigned int ach4_seBe : 1; + unsigned int ach4_gmBe : 1; + unsigned int ach4_gv2e : 1; + unsigned int ach4_gv1e : 1; + unsigned int zero5 : 4; +#endif + uint8_t zero6[19]; +} ATTRIBUTE_PACKED multichannel_ext_t; + + +/** + * Subpicture Attributes. */ typedef struct { /* @@ -153,11 +241,19 @@ * language: indicates language if type == 1 * lang extension: if type == 1 contains the lang extension */ - uint8_t type; - uint8_t zero1; +#ifdef WORDS_BIGENDIAN + unsigned int code_mode : 3; + unsigned int zero1 : 3; + unsigned int type : 2; +#else + unsigned int type : 2; + unsigned int zero1 : 3; + unsigned int code_mode : 3; +#endif + uint8_t zero2; uint16_t lang_code; - uint8_t lang_extension; - uint8_t zero2; + uint8_t lang_extension; + uint8_t code_extension; } ATTRIBUTE_PACKED subp_attr_t; @@ -193,8 +289,8 @@ unsigned int stc_discontinuity: 1; unsigned int seamless_angle : 1; - unsigned int unknown1 : 1; - unsigned int restricted : 1; + unsigned int playback_mode : 1; /**< When set, enter StillMode after each VOBU */ + unsigned int restricted : 1; /**< ?? drop out of fastforward? */ unsigned int unknown2 : 6; #else unsigned int seamless_angle : 1; @@ -206,7 +302,7 @@ unsigned int unknown2 : 6; unsigned int restricted : 1; - unsigned int unknown1 : 1; + unsigned int playback_mode : 1; #endif uint8_t still_time; uint8_t cell_cmd_nr; @@ -239,65 +335,65 @@ */ typedef struct { #ifdef WORDS_BIGENDIAN - unsigned int zero : 7; // 25-31 - unsigned int video_pres_mode_change : 1; // 24 + unsigned int zero : 7; /* 25-31 */ + unsigned int video_pres_mode_change : 1; /* 24 */ - unsigned int karaoke_audio_pres_mode_change : 1; // 23 - unsigned int angle_change : 1; // 22 - unsigned int subpic_stream_change : 1; // 21 - unsigned int audio_stream_change : 1; // 20 - unsigned int pause_on : 1; // 19 - unsigned int still_off : 1; // 18 - unsigned int button_select_or_activate : 1; // 17 - unsigned int resume : 1; // 16 + unsigned int karaoke_audio_pres_mode_change : 1; /* 23 */ + unsigned int angle_change : 1; + unsigned int subpic_stream_change : 1; + unsigned int audio_stream_change : 1; + unsigned int pause_on : 1; + unsigned int still_off : 1; + unsigned int button_select_or_activate : 1; + unsigned int resume : 1; /* 16 */ - unsigned int chapter_menu_call : 1; // 15 - unsigned int angle_menu_call : 1; // 14 - unsigned int audio_menu_call : 1; // 13 - unsigned int subpic_menu_call : 1; // 12 - unsigned int root_menu_call : 1; // 11 - unsigned int title_menu_call : 1; // 10 - unsigned int backward_scan : 1; // 9 - unsigned int forward_scan : 1; // 8 + unsigned int chapter_menu_call : 1; /* 15 */ + unsigned int angle_menu_call : 1; + unsigned int audio_menu_call : 1; + unsigned int subpic_menu_call : 1; + unsigned int root_menu_call : 1; + unsigned int title_menu_call : 1; + unsigned int backward_scan : 1; + unsigned int forward_scan : 1; /* 8 */ - unsigned int next_pg_search : 1; // 7 - unsigned int prev_or_top_pg_search : 1; // 6 - unsigned int time_or_chapter_search : 1; // 5 - unsigned int go_up : 1; // 4 - unsigned int stop : 1; // 3 - unsigned int title_play : 1; // 2 - unsigned int chapter_search_or_play : 1; // 1 - unsigned int title_or_time_play : 1; // 0 + unsigned int next_pg_search : 1; /* 7 */ + unsigned int prev_or_top_pg_search : 1; + unsigned int time_or_chapter_search : 1; + unsigned int go_up : 1; + unsigned int stop : 1; + unsigned int title_play : 1; + unsigned int chapter_search_or_play : 1; + unsigned int title_or_time_play : 1; /* 0 */ #else - unsigned int video_pres_mode_change : 1; // 24 - unsigned int zero : 7; // 25-31 + unsigned int video_pres_mode_change : 1; /* 24 */ + unsigned int zero : 7; /* 25-31 */ - unsigned int resume : 1; // 16 - unsigned int button_select_or_activate : 1; // 17 - unsigned int still_off : 1; // 18 - unsigned int pause_on : 1; // 19 - unsigned int audio_stream_change : 1; // 20 - unsigned int subpic_stream_change : 1; // 21 - unsigned int angle_change : 1; // 22 - unsigned int karaoke_audio_pres_mode_change : 1; // 23 + unsigned int resume : 1; /* 16 */ + unsigned int button_select_or_activate : 1; + unsigned int still_off : 1; + unsigned int pause_on : 1; + unsigned int audio_stream_change : 1; + unsigned int subpic_stream_change : 1; + unsigned int angle_change : 1; + unsigned int karaoke_audio_pres_mode_change : 1; /* 23 */ - unsigned int forward_scan : 1; // 8 - unsigned int backward_scan : 1; // 9 - unsigned int title_menu_call : 1; // 10 - unsigned int root_menu_call : 1; // 11 - unsigned int subpic_menu_call : 1; // 12 - unsigned int audio_menu_call : 1; // 13 - unsigned int angle_menu_call : 1; // 14 - unsigned int chapter_menu_call : 1; // 15 + unsigned int forward_scan : 1; /* 8 */ + unsigned int backward_scan : 1; + unsigned int title_menu_call : 1; + unsigned int root_menu_call : 1; + unsigned int subpic_menu_call : 1; + unsigned int audio_menu_call : 1; + unsigned int angle_menu_call : 1; + unsigned int chapter_menu_call : 1; /* 15 */ - unsigned int title_or_time_play : 1; // 0 - unsigned int chapter_search_or_play : 1; // 1 - unsigned int title_play : 1; // 2 - unsigned int stop : 1; // 3 - unsigned int go_up : 1; // 4 - unsigned int time_or_chapter_search : 1; // 5 - unsigned int prev_or_top_pg_search : 1; // 6 - unsigned int next_pg_search : 1; // 7 + unsigned int title_or_time_play : 1; /* 0 */ + unsigned int chapter_search_or_play : 1; + unsigned int title_play : 1; + unsigned int stop : 1; + unsigned int go_up : 1; + unsigned int time_or_chapter_search : 1; + unsigned int prev_or_top_pg_search : 1; + unsigned int next_pg_search : 1; /* 7 */ #endif } ATTRIBUTE_PACKED user_ops_t; @@ -365,7 +461,7 @@ */ typedef struct { uint16_t lang_code; - uint8_t zero_1; + uint8_t lang_extension; uint8_t exists; uint32_t lang_start_byte; pgcit_t *pgcit; @@ -401,7 +497,7 @@ uint16_t nr_of_vobs; /* VOBs */ uint16_t zero_1; uint32_t last_byte; - cell_adr_t *cell_adr_table; + cell_adr_t *cell_adr_table; /* No explicit size given. */ } ATTRIBUTE_PACKED c_adt_t; #define C_ADT_SIZE 8 @@ -457,11 +553,11 @@ video_attr_t vmgm_video_attr; uint8_t zero_7; - uint8_t nr_of_vmgm_audio_streams; // should be 0 or 1 + uint8_t nr_of_vmgm_audio_streams; /* should be 0 or 1 */ audio_attr_t vmgm_audio_attr; audio_attr_t zero_8[7]; uint8_t zero_9[17]; - uint8_t nr_of_vmgm_subp_streams; // should be 0 or 1 + uint8_t nr_of_vmgm_subp_streams; /* should be 0 or 1 */ subp_attr_t vmgm_subp_attr; subp_attr_t zero_10[27]; /* XXX: how much 'padding' here? */ } ATTRIBUTE_PACKED vmgi_mat_t; @@ -469,21 +565,21 @@ typedef struct { #ifdef WORDS_BIGENDIAN unsigned int zero_1 : 1; - unsigned int multi_or_random_pgc_title : 1; // 0 == one sequential pgc title + unsigned int multi_or_random_pgc_title : 1; /* 0: one sequential pgc title */ unsigned int jlc_exists_in_cell_cmd : 1; unsigned int jlc_exists_in_prepost_cmd : 1; unsigned int jlc_exists_in_button_cmd : 1; unsigned int jlc_exists_in_tt_dom : 1; - unsigned int chapter_search_or_play : 1; // UOP 1 - unsigned int title_or_time_play : 1; // UOP 0 + unsigned int chapter_search_or_play : 1; /* UOP 1 */ + unsigned int title_or_time_play : 1; /* UOP 0 */ #else - unsigned int title_or_time_play : 1; // UOP 0 - unsigned int chapter_search_or_play : 1; // UOP 1 + unsigned int title_or_time_play : 1; + unsigned int chapter_search_or_play : 1; unsigned int jlc_exists_in_tt_dom : 1; unsigned int jlc_exists_in_button_cmd : 1; unsigned int jlc_exists_in_prepost_cmd : 1; unsigned int jlc_exists_in_cell_cmd : 1; - unsigned int multi_or_random_pgc_title : 1; // 0 == one sequential pgc title + unsigned int multi_or_random_pgc_title : 1; unsigned int zero_1 : 1; #endif } ATTRIBUTE_PACKED playback_type_t; @@ -512,6 +608,13 @@ } ATTRIBUTE_PACKED tt_srpt_t; #define TT_SRPT_SIZE 8 + +/** + * Parental Management Information Unit Table. + * Level 1 (US: G), ..., 7 (US: NC-17), 8 + */ +typedef uint16_t pf_level_t[8]; + /** * Parental Management Information Unit Table. */ @@ -520,7 +623,7 @@ uint16_t zero_1; uint16_t pf_ptl_mai_start_byte; uint16_t zero_2; - /* uint16_t *pf_ptl_mai // table of nr_of_vtss+1 x 8 */ + pf_level_t *pf_ptl_mai; /* table of (nr_of_vtss + 1), video_ts is first */ } ATTRIBUTE_PACKED ptl_mait_country_t; #define PTL_MAIT_COUNTRY_SIZE 8 @@ -544,12 +647,12 @@ video_attr_t vtsm_vobs_attr; uint8_t zero_1; - uint8_t nr_of_vtsm_audio_streams; // should be 0 or 1 + uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */ audio_attr_t vtsm_audio_attr; audio_attr_t zero_2[7]; uint8_t zero_3[16]; uint8_t zero_4; - uint8_t nr_of_vtsm_subp_streams; // should be 0 or 1 + uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */ subp_attr_t vtsm_subp_attr; subp_attr_t zero_5[27]; @@ -575,6 +678,7 @@ uint16_t zero_1; uint32_t last_byte; vts_attributes_t *vts; + uint32_t *vts_atrt_offsets; /* offsets table for each vts_attributes */ } ATTRIBUTE_PACKED vts_atrt_t; #define VTS_ATRT_SIZE 8 @@ -585,18 +689,18 @@ uint32_t last_byte; /* offsets are relative here */ uint16_t offsets[100]; /* == nr_of_srpts + 1 (first is disc title) */ #if 0 - uint16_t unknown; // 0x48 ?? 0x48 words (16bit) info following + uint16_t unknown; /* 0x48 ?? 0x48 words (16bit) info following */ uint16_t zero_1; - uint8_t type_of_info;//?? 01 == disc, 02 == Title, 04 == Title part + uint8_t type_of_info; /* ?? 01 == disc, 02 == Title, 04 == Title part */ uint8_t unknown1; uint8_t unknown2; uint8_t unknown3; - uint8_t unknown4;//?? allways 0x30 language?, text format? + uint8_t unknown4; /* ?? allways 0x30 language?, text format? */ uint8_t unknown5; - uint16_t offset; // from first + uint16_t offset; /* from first */ - char text[12]; // ended by 0x09 + char text[12]; /* ended by 0x09 */ #endif } ATTRIBUTE_PACKED txtdt_t; @@ -656,7 +760,7 @@ uint32_t vts_ptt_srpt; /* sector */ uint32_t vts_pgcit; /* sector */ uint32_t vtsm_pgci_ut; /* sector */ - uint32_t vts_tmapt; /* sector */ // XXX: FIXME TODO Implement + uint32_t vts_tmapt; /* sector */ uint32_t vtsm_c_adt; /* sector */ uint32_t vtsm_vobu_admap; /* sector */ uint32_t vts_c_adt; /* sector */ @@ -665,11 +769,11 @@ video_attr_t vtsm_video_attr; uint8_t zero_14; - uint8_t nr_of_vtsm_audio_streams; // should be 0 or 1 + uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */ audio_attr_t vtsm_audio_attr; audio_attr_t zero_15[7]; uint8_t zero_16[17]; - uint8_t nr_of_vtsm_subp_streams; // should be 0 or 1 + uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */ subp_attr_t vtsm_subp_attr; subp_attr_t zero_17[27]; uint8_t zero_18[2]; @@ -681,6 +785,8 @@ uint8_t zero_20[17]; uint8_t nr_of_vts_subp_streams; subp_attr_t vts_subp_attr[32]; + uint16_t zero_21; + multichannel_ext_t vts_mu_audio_attr[8]; /* XXX: how much 'padding' here, if any? */ } ATTRIBUTE_PACKED vtsi_mat_t; @@ -708,10 +814,41 @@ uint16_t zero_1; uint32_t last_byte; ttu_t *title; + uint32_t *ttu_offset; /* offset table for each ttu */ } ATTRIBUTE_PACKED vts_ptt_srpt_t; #define VTS_PTT_SRPT_SIZE 8 +/** + * Time Map Entry. + */ +/* Should this be bit field at all or just the uint32_t? */ +typedef uint32_t map_ent_t; + +/** + * Time Map. + */ +typedef struct { + uint8_t tmu; /* Time unit, in seconds */ + uint8_t zero_1; + uint16_t nr_of_entries; + map_ent_t *map_ent; +} ATTRIBUTE_PACKED vts_tmap_t; +#define VTS_TMAP_SIZE 4 + +/** + * Time Map Table. + */ +typedef struct { + uint16_t nr_of_tmaps; + uint16_t zero_1; + uint32_t last_byte; + vts_tmap_t *tmap; + uint32_t *tmap_offset; /* offset table for each tmap */ +} ATTRIBUTE_PACKED vts_tmapt_t; +#define VTS_TMAPT_SIZE 8 + + #if PRAGMA_PACK #pragma pack() #endif @@ -743,7 +880,7 @@ vtsi_mat_t *vtsi_mat; vts_ptt_srpt_t *vts_ptt_srpt; pgcit_t *vts_pgcit; - int *vts_tmapt; // FIXME add/correct the type + vts_tmapt_t *vts_tmapt; c_adt_t *vts_c_adt; vobu_admap_t *vts_vobu_admap; } ifo_handle_t;
--- a/libmpdvdkit2/nav_print.c Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/nav_print.c Thu Jun 30 22:48:26 2005 +0000 @@ -1,9 +1,5 @@ /* - * Copyright (C) 2000, 2001, 2002 Håkan Hjort <d95hjort@dtek.chalmers.se> - * - * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. - * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ - * $Id$ + * Copyright (C) 2000, 2001, 2002, 2003 Håkan Hjort <d95hjort@dtek.chalmers.se> * * Much of the contents in this file is based on VOBDUMP. * @@ -27,21 +23,21 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" + #include <stdio.h> #include <inttypes.h> -//#include <assert.h> -#include "config.h" // Needed for WORDS_BIGENDIAN #include "nav_types.h" #include "nav_print.h" - +#include "dvdread_internal.h" static void print_time(dvd_time_t *dtime) { const char *rate; - assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa); - assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa); - assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa); - assert((dtime->frame_u&0xf) < 0xa); + CHECK_VALUE((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa); + CHECK_VALUE((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa); + CHECK_VALUE((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa); + CHECK_VALUE((dtime->frame_u&0xf) < 0xa); printf("%02x:%02x:%02x.%02x", dtime->hour,
--- a/libmpdvdkit2/nav_print.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/nav_print.h Thu Jun 30 22:48:26 2005 +0000 @@ -2,8 +2,8 @@ #define NAV_PRINT_H_INCLUDED /* - * Copyright (C) 2001 Billy Biggs <vektor@dumbterm.net>, - * Håkan Hjort <d95hjort@dtek.chalmers.se> + * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>, + * Håkan Hjort <d95hjort@dtek.chalmers.se> * * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ @@ -26,17 +26,25 @@ #include "nav_types.h" +/** + * Pretty printing of the NAV packets, PCI and DSI structs. + */ + #ifdef __cplusplus extern "C" { #endif /** * Prints information contained in the PCI to stdout. + * + * @param pci Pointer to the PCI data structure to be printed. */ void navPrint_PCI(pci_t *); /** * Prints information contained in the DSI to stdout. + * + * @param dsi Pointer to the DSI data structure to be printed. */ void navPrint_DSI(dsi_t *);
--- a/libmpdvdkit2/nav_read.c Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/nav_read.c Thu Jun 30 22:48:26 2005 +0000 @@ -1,9 +1,5 @@ /* - * Copyright (C) 2000, 2001, 2002 Håkan Hjort <d95hjort@dtek.chalmers.se> - * - * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. - * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ - * $Id$ + * Copyright (C) 2000, 2001, 2002, 2003 Håkan Hjort <d95hjort@dtek.chalmers.se> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,20 +16,21 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" + #include <stdio.h> #include <string.h> #include <inttypes.h> -//#include <assert.h> -#include "config.h" // Needed for WORDS_BIGENDIAN #include "bswap.h" #include "nav_types.h" #include "nav_read.h" +#include "dvdread_internal.h" void navRead_PCI(pci_t *pci, unsigned char *buffer) { - int i, j, k; + int i, j; - assert(sizeof(pci_t) == PCI_BYTES - 1); // -1 for substream id + CHECK_VALUE(sizeof(pci_t) == PCI_BYTES - 1); // -1 for substream id memcpy(pci, buffer, sizeof(pci_t)); @@ -61,84 +58,99 @@ for(j = 0; j < 2; j++) B2N_32(pci->hli.btn_colit.btn_coli[i][j]); -#if !defined(WORDS_BIGENDIAN) + /* NOTE: I've had to change the structure from the disk layout to get + * the packing to work with Sun's Forte C compiler. */ + /* pci hli btni */ for(i = 0; i < 36; i++) { - char tmp[6], swap; - memcpy(tmp, &(pci->hli.btnit[i]), 6); - /* This is a B2N_24() */ - swap = tmp[0]; tmp[0] = tmp[2]; tmp[2] = swap; - /* This is a B2N_24() */ - swap = tmp[3]; tmp[3] = tmp[5]; tmp[5] = swap; - memcpy(&(pci->hli.btnit[i]), tmp, 6); + char tmp[sizeof(pci->hli.btnit[i])], swap; + memcpy(tmp, &(pci->hli.btnit[i]), sizeof(pci->hli.btnit[i])); + /* Byte 4 to 7 are 'rotated' was: ABCD EFGH IJ is: ABCG DEFH IJ */ + swap = tmp[6]; + tmp[6] = tmp[5]; + tmp[5] = tmp[4]; + tmp[4] = tmp[3]; + tmp[3] = swap; + + /* Then there are the two B2N_24(..) calls */ +#ifndef WORDS_BIGENDIAN + swap = tmp[0]; + tmp[0] = tmp[2]; + tmp[2] = swap; + + swap = tmp[4]; + tmp[4] = tmp[6]; + tmp[6] = swap; +#endif + memcpy(&(pci->hli.btnit[i]), tmp, sizeof(pci->hli.btnit[i])); } -#endif +#ifndef NDEBUG /* Asserts */ /* pci pci gi */ - assert(pci->pci_gi.zero1 == 0); + CHECK_VALUE(pci->pci_gi.zero1 == 0); /* pci hli hli_gi */ - assert(pci->hli.hl_gi.zero1 == 0); - assert(pci->hli.hl_gi.zero2 == 0); - assert(pci->hli.hl_gi.zero3 == 0); - assert(pci->hli.hl_gi.zero4 == 0); - assert(pci->hli.hl_gi.zero5 == 0); + CHECK_VALUE(pci->hli.hl_gi.zero1 == 0); + CHECK_VALUE(pci->hli.hl_gi.zero2 == 0); + CHECK_VALUE(pci->hli.hl_gi.zero3 == 0); + CHECK_VALUE(pci->hli.hl_gi.zero4 == 0); + CHECK_VALUE(pci->hli.hl_gi.zero5 == 0); /* Are there buttons defined here? */ if((pci->hli.hl_gi.hli_ss & 0x03) != 0) { - assert(pci->hli.hl_gi.btn_ns != 0); - assert(pci->hli.hl_gi.btngr_ns != 0); + CHECK_VALUE(pci->hli.hl_gi.btn_ns != 0); + CHECK_VALUE(pci->hli.hl_gi.btngr_ns != 0); } else { - assert((pci->hli.hl_gi.btn_ns != 0 && pci->hli.hl_gi.btngr_ns != 0) + CHECK_VALUE((pci->hli.hl_gi.btn_ns != 0 && pci->hli.hl_gi.btngr_ns != 0) || (pci->hli.hl_gi.btn_ns == 0 && pci->hli.hl_gi.btngr_ns == 0)); } /* pci hli btnit */ for(i = 0; i < pci->hli.hl_gi.btngr_ns; i++) { for(j = 0; j < (36 / pci->hli.hl_gi.btngr_ns); j++) { -#ifdef HAVE_ASSERT_H int n = (36 / pci->hli.hl_gi.btngr_ns) * i + j; -#endif - assert(pci->hli.btnit[n].zero1 == 0); - assert(pci->hli.btnit[n].zero2 == 0); - assert(pci->hli.btnit[n].zero3 == 0); - assert(pci->hli.btnit[n].zero4 == 0); - assert(pci->hli.btnit[n].zero5 == 0); - assert(pci->hli.btnit[n].zero6 == 0); + CHECK_VALUE(pci->hli.btnit[n].zero1 == 0); + CHECK_VALUE(pci->hli.btnit[n].zero2 == 0); + CHECK_VALUE(pci->hli.btnit[n].zero3 == 0); + CHECK_VALUE(pci->hli.btnit[n].zero4 == 0); + CHECK_VALUE(pci->hli.btnit[n].zero5 == 0); + CHECK_VALUE(pci->hli.btnit[n].zero6 == 0); if (j < pci->hli.hl_gi.btn_ns) { - assert(pci->hli.btnit[n].x_start <= pci->hli.btnit[n].x_end); - assert(pci->hli.btnit[n].y_start <= pci->hli.btnit[n].y_end); - assert(pci->hli.btnit[n].up <= pci->hli.hl_gi.btn_ns); - assert(pci->hli.btnit[n].down <= pci->hli.hl_gi.btn_ns); - assert(pci->hli.btnit[n].left <= pci->hli.hl_gi.btn_ns); - assert(pci->hli.btnit[n].right <= pci->hli.hl_gi.btn_ns); + CHECK_VALUE(pci->hli.btnit[n].x_start <= pci->hli.btnit[n].x_end); + CHECK_VALUE(pci->hli.btnit[n].y_start <= pci->hli.btnit[n].y_end); + CHECK_VALUE(pci->hli.btnit[n].up <= pci->hli.hl_gi.btn_ns); + CHECK_VALUE(pci->hli.btnit[n].down <= pci->hli.hl_gi.btn_ns); + CHECK_VALUE(pci->hli.btnit[n].left <= pci->hli.hl_gi.btn_ns); + CHECK_VALUE(pci->hli.btnit[n].right <= pci->hli.hl_gi.btn_ns); //vmcmd_verify(pci->hli.btnit[n].cmd); } else { - assert(pci->hli.btnit[n].btn_coln == 0); - assert(pci->hli.btnit[n].auto_action_mode == 0); - assert(pci->hli.btnit[n].x_start == 0); - assert(pci->hli.btnit[n].y_start == 0); - assert(pci->hli.btnit[n].x_end == 0); - assert(pci->hli.btnit[n].y_end == 0); - assert(pci->hli.btnit[n].up == 0); - assert(pci->hli.btnit[n].down == 0); - assert(pci->hli.btnit[n].left == 0); - assert(pci->hli.btnit[n].right == 0); + int k; + CHECK_VALUE(pci->hli.btnit[n].btn_coln == 0); + CHECK_VALUE(pci->hli.btnit[n].auto_action_mode == 0); + CHECK_VALUE(pci->hli.btnit[n].x_start == 0); + CHECK_VALUE(pci->hli.btnit[n].y_start == 0); + CHECK_VALUE(pci->hli.btnit[n].x_end == 0); + CHECK_VALUE(pci->hli.btnit[n].y_end == 0); + CHECK_VALUE(pci->hli.btnit[n].up == 0); + CHECK_VALUE(pci->hli.btnit[n].down == 0); + CHECK_VALUE(pci->hli.btnit[n].left == 0); + CHECK_VALUE(pci->hli.btnit[n].right == 0); for (k = 0; k < 8; k++) - assert(pci->hli.btnit[n].cmd.bytes[k] == 0); //CHECK_ZERO? + CHECK_VALUE(pci->hli.btnit[n].cmd.bytes[k] == 0); //CHECK_ZERO? } } } +#endif /* !NDEBUG */ } void navRead_DSI(dsi_t *dsi, unsigned char *buffer) { int i; - assert(sizeof(dsi_t) == DSI_BYTES - 1); // -1 for substream id + CHECK_VALUE(sizeof(dsi_t) == DSI_BYTES - 1); // -1 for substream id memcpy(dsi, buffer, sizeof(dsi_t)); @@ -187,6 +199,6 @@ /* Asserts */ /* dsi dsi gi */ - assert(dsi->dsi_gi.zero1 == 0); + CHECK_VALUE(dsi->dsi_gi.zero1 == 0); }
--- a/libmpdvdkit2/nav_read.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/nav_read.h Thu Jun 30 22:48:26 2005 +0000 @@ -2,7 +2,7 @@ #define NAV_READ_H_INCLUDED /* - * Copyright (C) 2000, 2001 Håkan Hjort <d95hjort@dtek.chalmers.se>. + * Copyright (C) 2000, 2001, 2002 Håkan Hjort <d95hjort@dtek.chalmers.se>. * * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ @@ -25,17 +25,27 @@ #include "nav_types.h" +/** + * Parsing of NAV data, PCI and DSI parts. + */ + #ifdef __cplusplus extern "C" { #endif /** - * Reads the PCI packet data pointed to into pci struct. - */ + * Reads the PCI packet data pointed to into th pci struct. + * + * @param pci Pointer to the PCI data structure to be filled in. + * @param bufffer Pointer to the buffer of the on disc PCI data. + */ void navRead_PCI(pci_t *, unsigned char *); /** * Reads the DSI packet data pointed to into dsi struct. + * + * @param dsi Pointer to the DSI data structure to be filled in. + * @param bufffer Pointer to the buffer of the on disc DSI data. */ void navRead_DSI(dsi_t *, unsigned char *);
--- a/libmpdvdkit2/nav_types.h Thu Jun 30 22:41:40 2005 +0000 +++ b/libmpdvdkit2/nav_types.h Thu Jun 30 22:48:26 2005 +0000 @@ -2,7 +2,7 @@ #define NAV_TYPES_H_INCLUDED /* - * Copyright (C) 2000, 2001 Håkan Hjort <d95hjort@dtek.chalmers.se> + * Copyright (C) 2000, 2001, 2002 Håkan Hjort <d95hjort@dtek.chalmers.se> * * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. * detailed CVS changelog at http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/ @@ -34,7 +34,7 @@ */ #include <inttypes.h> -#include "ifo_types.h" // only dvd_time_t, vm_cmd_t and user_ops_t +#include "ifo_types.h" /* only dvd_time_t, vm_cmd_t and user_ops_t */ #undef ATTRIBUTE_PACKED @@ -74,14 +74,14 @@ * PCI General Information */ typedef struct { - uint32_t nv_pck_lbn; - uint16_t vobu_cat; - uint16_t zero1; - user_ops_t vobu_uop_ctl; - uint32_t vobu_s_ptm; - uint32_t vobu_e_ptm; - uint32_t vobu_se_e_ptm; - dvd_time_t e_eltm; + uint32_t nv_pck_lbn; /**< sector address of this nav pack */ + uint16_t vobu_cat; /**< 'category' of vobu */ + uint16_t zero1; /**< reserved */ + user_ops_t vobu_uop_ctl; /**< UOP of vobu */ + uint32_t vobu_s_ptm; /**< start presentation time of vobu */ + uint32_t vobu_e_ptm; /**< end presentation time of vobu */ + uint32_t vobu_se_e_ptm; /**< end ptm of sequence end in vobu */ + dvd_time_t e_eltm; /**< Cell elapsed time */ char vobu_isrc[32]; } ATTRIBUTE_PACKED pci_gi_t; @@ -89,26 +89,32 @@ * Non Seamless Angle Information */ typedef struct { - uint32_t nsml_agl_dsta[9]; + uint32_t nsml_agl_dsta[9]; /**< address of destination vobu in AGL_C#n */ } ATTRIBUTE_PACKED nsml_agli_t; /** * Highlight General Information + * + * For btngrX_dsp_ty the bits have the following meaning: + * 000b: normal 4/3 only buttons + * XX1b: wide (16/9) buttons + * X1Xb: letterbox buttons + * 1XXb: pan&scan buttons */ typedef struct { - uint16_t hli_ss; ///< only low 2 bits - uint32_t hli_s_ptm; - uint32_t hli_e_ptm; - uint32_t btn_se_e_ptm; + uint16_t hli_ss; /**< status, only low 2 bits 0: no buttons, 1: different 2: equal 3: eual except for button cmds */ + uint32_t hli_s_ptm; /**< start ptm of hli */ + uint32_t hli_e_ptm; /**< end ptm of hli */ + uint32_t btn_se_e_ptm; /**< end ptm of button select */ #ifdef WORDS_BIGENDIAN - unsigned int zero1 : 2; - unsigned int btngr_ns : 2; - unsigned int zero2 : 1; - unsigned int btngr1_dsp_ty : 3; - unsigned int zero3 : 1; - unsigned int btngr2_dsp_ty : 3; - unsigned int zero4 : 1; - unsigned int btngr3_dsp_ty : 3; + unsigned int zero1 : 2; /**< reserved */ + unsigned int btngr_ns : 2; /**< number of button groups 1, 2 or 3 with 36/18/12 buttons */ + unsigned int zero2 : 1; /**< reserved */ + unsigned int btngr1_dsp_ty : 3; /**< display type of subpic stream for button group 1 */ + unsigned int zero3 : 1; /**< reserved */ + unsigned int btngr2_dsp_ty : 3; /**< display type of subpic stream for button group 2 */ + unsigned int zero4 : 1; /**< reserved */ + unsigned int btngr3_dsp_ty : 3; /**< display type of subpic stream for button group 3 */ #else unsigned int btngr1_dsp_ty : 3; unsigned int zero2 : 1; @@ -119,56 +125,69 @@ unsigned int btngr2_dsp_ty : 3; unsigned int zero3 : 1; #endif - uint8_t btn_ofn; - uint8_t btn_ns; ///< only low 6 bits - uint8_t nsl_btn_ns; ///< only low 6 bits - uint8_t zero5; - uint8_t fosl_btnn; ///< only low 6 bits - uint8_t foac_btnn; ///< only low 6 bits + uint8_t btn_ofn; /**< button offset number range 0-255 */ + uint8_t btn_ns; /**< number of valid buttons <= 36/18/12 (low 6 bits) */ + uint8_t nsl_btn_ns; /**< number of buttons selectable by U_BTNNi (low 6 bits) nsl_btn_ns <= btn_ns */ + uint8_t zero5; /**< reserved */ + uint8_t fosl_btnn; /**< forcedly selected button (low 6 bits) */ + uint8_t foac_btnn; /**< forcedly activated button (low 6 bits) */ } ATTRIBUTE_PACKED hl_gi_t; /** * Button Color Information Table + * Each entry beeing a 32bit word that contains the color indexs and alpha + * values to use. They are all represented by 4 bit number and stored + * like this [Ci3, Ci2, Ci1, Ci0, A3, A2, A1, A0]. The actual palette + * that the indexes reference is in the PGC. + * @TODO split the uint32_t into a struct */ typedef struct { - uint32_t btn_coli[3][2]; + uint32_t btn_coli[3][2]; /**< [button color number-1][select:0/action:1] */ } ATTRIBUTE_PACKED btn_colit_t; /** * Button Information + * + * NOTE: I've had to change the structure from the disk layout to get + * the packing to work with Sun's Forte C compiler. + * The 4 and 7 bytes are 'rotated' was: ABC DEF GHIJ is: ABCG DEFH IJ */ typedef struct { #ifdef WORDS_BIGENDIAN - unsigned int btn_coln : 2; - unsigned int x_start : 10; - unsigned int zero1 : 2; - unsigned int x_end : 10; - unsigned int auto_action_mode : 2; - unsigned int y_start : 10; - unsigned int zero2 : 2; - unsigned int y_end : 10; + unsigned int btn_coln : 2; /**< button color number */ + unsigned int x_start : 10; /**< x start offset within the overlay */ + unsigned int zero1 : 2; /**< reserved */ + unsigned int x_end : 10; /**< x end offset within the overlay */ + + unsigned int zero3 : 2; /**< reserved */ + unsigned int up : 6; /**< button index when pressing up */ - unsigned int zero3 : 2; - unsigned int up : 6; - unsigned int zero4 : 2; - unsigned int down : 6; - unsigned int zero5 : 2; - unsigned int left : 6; - unsigned int zero6 : 2; - unsigned int right : 6; + unsigned int auto_action_mode : 2; /**< 0: no, 1: activated if selected */ + unsigned int y_start : 10; /**< y start offset within the overlay */ + unsigned int zero2 : 2; /**< reserved */ + unsigned int y_end : 10; /**< y end offset within the overlay */ + + unsigned int zero4 : 2; /**< reserved */ + unsigned int down : 6; /**< button index when pressing down */ + unsigned int zero5 : 2; /**< reserved */ + unsigned int left : 6; /**< button index when pressing left */ + unsigned int zero6 : 2; /**< reserved */ + unsigned int right : 6; /**< button index when pressing right */ #else unsigned int x_end : 10; unsigned int zero1 : 2; unsigned int x_start : 10; unsigned int btn_coln : 2; + + unsigned int up : 6; + unsigned int zero3 : 2; + unsigned int y_end : 10; unsigned int zero2 : 2; unsigned int y_start : 10; unsigned int auto_action_mode : 2; - unsigned int up : 6; - unsigned int zero3 : 2; unsigned int down : 6; unsigned int zero4 : 2; unsigned int left : 6; @@ -206,27 +225,27 @@ */ typedef struct { uint32_t nv_pck_scr; - uint32_t nv_pck_lbn; - uint32_t vobu_ea; - uint32_t vobu_1stref_ea; - uint32_t vobu_2ndref_ea; - uint32_t vobu_3rdref_ea; - uint16_t vobu_vob_idn; - uint8_t zero1; - uint8_t vobu_c_idn; - dvd_time_t c_eltm; + uint32_t nv_pck_lbn; /**< sector address of this nav pack */ + uint32_t vobu_ea; /**< end address of this VOBU */ + uint32_t vobu_1stref_ea; /**< end address of the 1st reference image */ + uint32_t vobu_2ndref_ea; /**< end address of the 2nd reference image */ + uint32_t vobu_3rdref_ea; /**< end address of the 3rd reference image */ + uint16_t vobu_vob_idn; /**< VOB Id number that this VOBU is part of */ + uint8_t zero1; /**< reserved */ + uint8_t vobu_c_idn; /**< Cell Id number that this VOBU is part of */ + dvd_time_t c_eltm; /**< Cell elapsed time */ } ATTRIBUTE_PACKED dsi_gi_t; /** * Seamless Playback Information */ typedef struct { - uint16_t category; ///< category of seamless VOBU - uint32_t ilvu_ea; ///< end address of interleaved Unit (sectors) - uint32_t ilvu_sa; ///< start address of next interleaved unit (sectors) - uint16_t size; ///< size of next interleaved unit (sectors) - uint32_t vob_v_s_s_ptm; ///< video start ptm in vob - uint32_t vob_v_e_e_ptm; ///< video end ptm in vob + uint16_t category; /**< 'category' of seamless VOBU */ + uint32_t ilvu_ea; /**< end address of interleaved Unit */ + uint32_t ilvu_sa; /**< start address of next interleaved unit */ + uint16_t size; /**< size of next interleaved unit */ + uint32_t vob_v_s_s_ptm; /**< video start ptm in vob */ + uint32_t vob_v_e_e_ptm; /**< video end ptm in vob */ struct { uint32_t stp_ptm1; uint32_t stp_ptm2; @@ -239,8 +258,8 @@ * Seamless Angle Infromation for one angle */ typedef struct { - uint32_t address; ///< Sector offset to next ILVU, high bit is before/after - uint16_t size; ///< Byte size of the ILVU poited to by address. + uint32_t address; /**< offset to next ILVU, high bit is before/after */ + uint16_t size; /**< byte size of the ILVU pointed to by address */ } ATTRIBUTE_PACKED sml_agl_data_t; /** @@ -254,11 +273,11 @@ * VOBU Search Information */ typedef struct { - uint32_t next_video; ///< Next vobu that contains video - uint32_t fwda[19]; ///< Forwards, time + uint32_t next_video; /**< Next vobu that contains video */ + uint32_t fwda[19]; /**< Forwards, time */ uint32_t next_vobu; uint32_t prev_vobu; - uint32_t bwda[19]; ///< Backwards, time + uint32_t bwda[19]; /**< Backwards, time */ uint32_t prev_video; } ATTRIBUTE_PACKED vobu_sri_t; @@ -268,8 +287,8 @@ * Synchronous Information */ typedef struct { - uint16_t a_synca[8]; ///< Sector offset to first audio packet for this VOBU - uint32_t sp_synca[32]; ///< Sector offset to first subpicture packet + uint16_t a_synca[8]; /**< offset to first audio packet for this VOBU */ + uint32_t sp_synca[32]; /**< offset to first subpicture packet */ } ATTRIBUTE_PACKED synci_t; /**