Mercurial > mplayer.hg
annotate libmpdvdkit2/dvd_reader.c @ 13738:39004f891def
seeking based on the largest timestamp in an mpeg stream
It is often more accurate than the current seeking and it has the
additional benefit of giving the (almost) precise total time of the movie.
patch by Michael Behrisch < behrisch at informatik.hu-berlin.de >
author | aurel |
---|---|
date | Sat, 23 Oct 2004 00:05:38 +0000 |
parents | 663fdd72e594 |
children | 25df9508f9a8 |
rev | line source |
---|---|
7029 | 1 /* |
2 * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>, | |
3 * Håkan Hjort <d95hjort@dtek.chalmers.se> | |
4 * | |
5 * This program is free software; you can redistribute it and/or modify | |
6 * it under the terms of the GNU General Public License as published by | |
7 * the Free Software Foundation; either version 2 of the License, or (at | |
8 * your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, but | |
11 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU General Public License | |
16 * along with this program; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. | |
18 */ | |
19 | |
7033 | 20 #include "config.h" |
21 | |
7029 | 22 #include <sys/types.h> |
23 #include <sys/stat.h> | |
24 #include <sys/time.h> /* For the timing of dvdcss_title crack. */ | |
25 #include <fcntl.h> | |
26 #include <stdlib.h> | |
27 #include <stdio.h> | |
28 #include <errno.h> | |
29 #include <string.h> | |
30 #include <unistd.h> | |
31 #include <limits.h> | |
32 #include <dirent.h> | |
33 | |
34 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)|| defined(__DARWIN__) | |
35 #define SYS_BSD 1 | |
36 #endif | |
37 | |
38 #if defined(__sun) | |
39 #include <sys/mnttab.h> | |
7423
ad967766679a
hpux DVD support fixes by Martin Gansser <mgansser@ngi.de>
arpi
parents:
7358
diff
changeset
|
40 #elif defined(hpux) |
ad967766679a
hpux DVD support fixes by Martin Gansser <mgansser@ngi.de>
arpi
parents:
7358
diff
changeset
|
41 #include </usr/conf/h/mnttab.h> |
7029 | 42 #elif defined(SYS_BSD) |
43 #include <fstab.h> | |
44 #elif defined(__linux__) | |
45 #include <mntent.h> | |
46 #endif | |
47 | |
10825 | 48 #ifdef __MINGW32__ |
49 #include <sys/timeb.h> | |
50 static void gettimeofday(struct timeval* t,void* timezone){ | |
51 struct timeb timebuffer; | |
52 ftime( &timebuffer ); | |
53 t->tv_sec=timebuffer.time; | |
54 t->tv_usec=1000*timebuffer.millitm; | |
55 } | |
56 #endif | |
57 | |
7029 | 58 #include "dvd_udf.h" |
59 #include "dvd_input.h" | |
60 #include "dvd_reader.h" | |
61 | |
62 struct dvd_reader_s { | |
63 /* Basic information. */ | |
64 int isImageFile; | |
65 | |
66 /* Hack for keeping track of the css status. | |
67 * 0: no css, 1: perhaps (need init of keys), 2: have done init */ | |
68 int css_state; | |
69 int css_title; /* Last title that we have called DVDinpute_title for. */ | |
70 | |
71 /* Information required for an image file. */ | |
72 dvd_input_t dev; | |
73 | |
74 /* Information required for a directory path drive. */ | |
75 char *path_root; | |
76 }; | |
77 | |
78 struct dvd_file_s { | |
79 /* Basic information. */ | |
80 dvd_reader_t *dvd; | |
81 | |
82 /* Hack for selecting the right css title. */ | |
83 int css_title; | |
84 | |
85 /* Information required for an image file. */ | |
86 uint32_t lb_start; | |
87 uint32_t seek_pos; | |
88 | |
89 /* Information required for a directory path drive. */ | |
90 size_t title_sizes[ 9 ]; | |
91 dvd_input_t title_devs[ 9 ]; | |
92 | |
93 /* Calculated at open-time, size in blocks. */ | |
94 ssize_t filesize; | |
95 }; | |
96 | |
97 /* Loop over all titles and call dvdcss_title to crack the keys. */ | |
98 static int initAllCSSKeys( dvd_reader_t *dvd ) | |
99 { | |
100 struct timeval all_s, all_e; | |
101 struct timeval t_s, t_e; | |
102 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
103 uint32_t start, len; | |
104 int title; | |
105 | |
106 fprintf( stderr, "\n" ); | |
107 fprintf( stderr, "libdvdread: Attempting to retrieve all CSS keys\n" ); | |
108 fprintf( stderr, "libdvdread: This can take a _long_ time, " | |
109 "please be patient\n\n" ); | |
110 | |
111 gettimeofday(&all_s, NULL); | |
112 | |
113 for( title = 0; title < 100; title++ ) { | |
114 gettimeofday( &t_s, NULL ); | |
115 if( title == 0 ) { | |
116 sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" ); | |
117 } else { | |
118 sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 0 ); | |
119 } | |
120 start = UDFFindFile( dvd, filename, &len ); | |
121 if( start != 0 && len != 0 ) { | |
122 /* Perform CSS key cracking for this title. */ | |
123 fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", | |
124 filename, start ); | |
125 if( DVDinput_title( dvd->dev, (int)start ) < 0 ) { | |
126 fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename, start); | |
127 } | |
128 gettimeofday( &t_e, NULL ); | |
129 fprintf( stderr, "libdvdread: Elapsed time %ld\n", | |
130 (long int) t_e.tv_sec - t_s.tv_sec ); | |
131 } | |
132 | |
133 if( title == 0 ) continue; | |
134 | |
135 gettimeofday( &t_s, NULL ); | |
136 sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 1 ); | |
137 start = UDFFindFile( dvd, filename, &len ); | |
138 if( start == 0 || len == 0 ) break; | |
139 | |
140 /* Perform CSS key cracking for this title. */ | |
141 fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", | |
142 filename, start ); | |
143 if( DVDinput_title( dvd->dev, (int)start ) < 0 ) { | |
144 fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename, start); | |
145 } | |
146 gettimeofday( &t_e, NULL ); | |
147 fprintf( stderr, "libdvdread: Elapsed time %ld\n", | |
148 (long int) t_e.tv_sec - t_s.tv_sec ); | |
149 } | |
150 title--; | |
151 | |
152 fprintf( stderr, "libdvdread: Found %d VTS's\n", title ); | |
153 gettimeofday(&all_e, NULL); | |
154 fprintf( stderr, "libdvdread: Elapsed time %ld\n", | |
155 (long int) all_e.tv_sec - all_s.tv_sec ); | |
156 | |
157 return 0; | |
158 } | |
159 | |
160 | |
7033 | 161 #ifndef HAVE_MPLAYER |
162 #include "get_path.c" | |
163 #else | |
164 extern char * get_path( char * filename ); | |
165 #endif | |
166 | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
8881
diff
changeset
|
167 //extern char * dvdcss_cache_dir; |
7029 | 168 |
169 /** | |
170 * Open a DVD image or block device file. | |
171 */ | |
172 static dvd_reader_t *DVDOpenImageFile( const char *location, int have_css ) | |
173 { | |
174 dvd_reader_t *dvd; | |
175 dvd_input_t dev; | |
7033 | 176 |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
8881
diff
changeset
|
177 /* setup cache dir is no longer needed, it's now implemented in libdvdcss.c |
7033 | 178 if(!dvdcss_cache_dir){ |
179 dvdcss_cache_dir=get_path( "" ); | |
180 if ( dvdcss_cache_dir ) { mkdir( dvdcss_cache_dir,493 ); free( dvdcss_cache_dir ); } | |
181 dvdcss_cache_dir=get_path( "DVDKeys" ); | |
182 if(dvdcss_cache_dir) mkdir( dvdcss_cache_dir,493 ); | |
183 } | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
8881
diff
changeset
|
184 */ |
7029 | 185 |
7033 | 186 /* open it */ |
7029 | 187 dev = DVDinput_open( location ); |
188 if( !dev ) { | |
189 fprintf( stderr, "libdvdread: Can't open %s for reading\n", location ); | |
190 return 0; | |
191 } | |
192 | |
193 dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); | |
194 if( !dvd ) return 0; | |
195 dvd->isImageFile = 1; | |
196 dvd->dev = dev; | |
197 dvd->path_root = 0; | |
198 | |
199 if( have_css ) { | |
200 /* Only if DVDCSS_METHOD = title, a bit if it's disc or if | |
201 * DVDCSS_METHOD = key but region missmatch. Unfortunaly we | |
202 * don't have that information. */ | |
203 | |
204 dvd->css_state = 1; /* Need key init. */ | |
205 } | |
206 | |
207 return dvd; | |
208 } | |
209 | |
210 static dvd_reader_t *DVDOpenPath( const char *path_root ) | |
211 { | |
212 dvd_reader_t *dvd; | |
213 | |
214 dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); | |
215 if( !dvd ) return 0; | |
216 dvd->isImageFile = 0; | |
217 dvd->dev = 0; | |
218 dvd->path_root = strdup( path_root ); | |
219 | |
220 return dvd; | |
221 } | |
222 | |
223 #if defined(__sun) | |
224 /* /dev/rdsk/c0t6d0s0 (link to /devices/...) | |
225 /vol/dev/rdsk/c0t6d0/?? | |
226 /vol/rdsk/<name> */ | |
227 static char *sun_block2char( const char *path ) | |
228 { | |
229 char *new_path; | |
230 | |
231 /* Must contain "/dsk/" */ | |
232 if( !strstr( path, "/dsk/" ) ) return (char *) strdup( path ); | |
233 | |
234 /* Replace "/dsk/" with "/rdsk/" */ | |
235 new_path = malloc( strlen(path) + 2 ); | |
236 strcpy( new_path, path ); | |
237 strcpy( strstr( new_path, "/dsk/" ), "" ); | |
238 strcat( new_path, "/rdsk/" ); | |
239 strcat( new_path, strstr( path, "/dsk/" ) + strlen( "/dsk/" ) ); | |
240 | |
241 return new_path; | |
242 } | |
243 #endif | |
244 | |
245 #if defined(SYS_BSD) | |
246 /* FreeBSD /dev/(r)(a)cd0c (a is for atapi), recomended to _not_ use r | |
247 OpenBSD /dev/rcd0c, it needs to be the raw device | |
248 NetBSD /dev/rcd0[d|c|..] d for x86, c (for non x86), perhaps others | |
249 Darwin /dev/rdisk0, it needs to be the raw device | |
250 BSD/OS /dev/sr0c (if not mounted) or /dev/rsr0c ('c' any letter will do) */ | |
251 static char *bsd_block2char( const char *path ) | |
252 { | |
253 char *new_path; | |
254 | |
255 /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */ | |
10511 | 256 if( strncmp( path, "/dev/", 5 ) || !strncmp( path, "/dev/r", 6 ) ) |
7029 | 257 return (char *) strdup( path ); |
258 | |
259 /* Replace "/dev/" with "/dev/r" */ | |
260 new_path = malloc( strlen(path) + 2 ); | |
261 strcpy( new_path, "/dev/r" ); | |
262 strcat( new_path, path + strlen( "/dev/" ) ); | |
263 | |
264 return new_path; | |
265 } | |
266 #endif | |
267 | |
268 dvd_reader_t *DVDOpen( const char *path ) | |
269 { | |
270 struct stat fileinfo; | |
271 int ret, have_css; | |
272 char *dev_name = 0; | |
273 | |
274 if( !path ) return 0; | |
275 | |
12431
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
276 #ifdef WIN32 |
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
277 /* Stat doesn't work on devices under mingwin/cygwin. */ |
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
278 if( path[0] && path[1] == ':' && path[2] == '\0' ) |
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
279 { |
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
280 /* Don't try to stat the file */ |
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
281 fileinfo.st_mode = S_IFBLK; |
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
282 } |
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
283 else |
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
284 #endif |
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
285 { |
7029 | 286 ret = stat( path, &fileinfo ); |
287 if( ret < 0 ) { | |
288 /* If we can't stat the file, give up */ | |
289 fprintf( stderr, "libdvdread: Can't stat %s\n", path ); | |
290 perror(""); | |
291 return 0; | |
292 } | |
12431
663fdd72e594
Encrypted dvd playback now accepts -dvd-drive e: on mingw. fix from libdvdread, left out the various cosmetics changes for now
faust3
parents:
10825
diff
changeset
|
293 } |
7029 | 294 |
295 /* Try to open libdvdcss or fall back to standard functions */ | |
296 have_css = DVDInputSetup(); | |
297 | |
298 /* First check if this is a block/char device or a file*/ | |
299 if( S_ISBLK( fileinfo.st_mode ) || | |
300 S_ISCHR( fileinfo.st_mode ) || | |
301 S_ISREG( fileinfo.st_mode ) ) { | |
302 | |
303 /** | |
304 * Block devices and regular files are assumed to be DVD-Video images. | |
305 */ | |
306 #if defined(__sun) | |
307 return DVDOpenImageFile( sun_block2char( path ), have_css ); | |
308 #elif defined(SYS_BSD) | |
309 return DVDOpenImageFile( bsd_block2char( path ), have_css ); | |
310 #else | |
311 return DVDOpenImageFile( path, have_css ); | |
312 #endif | |
313 | |
314 } else if( S_ISDIR( fileinfo.st_mode ) ) { | |
315 dvd_reader_t *auth_drive = 0; | |
316 char *path_copy; | |
317 #if defined(SYS_BSD) | |
318 struct fstab* fe; | |
319 #elif defined(__sun) || defined(__linux__) | |
320 FILE *mntfile; | |
321 #endif | |
322 | |
323 /* XXX: We should scream real loud here. */ | |
324 if( !(path_copy = strdup( path ) ) ) return 0; | |
325 | |
326 /* Resolve any symlinks and get the absolut dir name. */ | |
327 { | |
328 char *new_path; | |
329 int cdir = open( ".", O_RDONLY ); | |
330 | |
331 if( cdir >= 0 ) { | |
332 chdir( path_copy ); | |
333 new_path = getcwd( NULL, PATH_MAX ); | |
10443 | 334 #ifndef __MINGW32__ |
7029 | 335 fchdir( cdir ); |
10443 | 336 #endif |
7029 | 337 close( cdir ); |
338 if( new_path ) { | |
339 free( path_copy ); | |
340 path_copy = new_path; | |
341 } | |
342 } | |
343 } | |
344 | |
345 /** | |
346 * If we're being asked to open a directory, check if that directory | |
347 * is the mountpoint for a DVD-ROM which we can use instead. | |
348 */ | |
349 | |
350 if( strlen( path_copy ) > 1 ) { | |
351 if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) | |
352 path_copy[ strlen( path_copy ) - 1 ] = '\0'; | |
353 } | |
354 | |
355 if( strlen( path_copy ) > 9 ) { | |
356 if( !strcasecmp( &(path_copy[ strlen( path_copy ) - 9 ]), | |
357 "/video_ts" ) ) { | |
358 path_copy[ strlen( path_copy ) - 9 ] = '\0'; | |
359 } | |
360 } | |
361 | |
362 #if defined(SYS_BSD) | |
363 if( ( fe = getfsfile( path_copy ) ) ) { | |
364 dev_name = bsd_block2char( fe->fs_spec ); | |
365 fprintf( stderr, | |
366 "libdvdread: Attempting to use device %s" | |
367 " mounted on %s for CSS authentication\n", | |
368 dev_name, | |
369 fe->fs_file ); | |
370 auth_drive = DVDOpenImageFile( dev_name, have_css ); | |
371 } | |
372 #elif defined(__sun) | |
373 mntfile = fopen( MNTTAB, "r" ); | |
374 if( mntfile ) { | |
375 struct mnttab mp; | |
376 int res; | |
377 | |
378 while( ( res = getmntent( mntfile, &mp ) ) != -1 ) { | |
379 if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) { | |
380 dev_name = sun_block2char( mp.mnt_special ); | |
381 fprintf( stderr, | |
382 "libdvdread: Attempting to use device %s" | |
383 " mounted on %s for CSS authentication\n", | |
384 dev_name, | |
385 mp.mnt_mountp ); | |
386 auth_drive = DVDOpenImageFile( dev_name, have_css ); | |
387 break; | |
388 } | |
389 } | |
390 fclose( mntfile ); | |
391 } | |
392 #elif defined(__linux__) | |
393 mntfile = fopen( MOUNTED, "r" ); | |
394 if( mntfile ) { | |
395 struct mntent *me; | |
396 | |
397 while( ( me = getmntent( mntfile ) ) ) { | |
398 if( !strcmp( me->mnt_dir, path_copy ) ) { | |
399 fprintf( stderr, | |
400 "libdvdread: Attempting to use device %s" | |
401 " mounted on %s for CSS authentication\n", | |
402 me->mnt_fsname, | |
403 me->mnt_dir ); | |
404 auth_drive = DVDOpenImageFile( me->mnt_fsname, have_css ); | |
405 dev_name = strdup(me->mnt_fsname); | |
406 break; | |
407 } | |
408 } | |
409 fclose( mntfile ); | |
410 } | |
7033 | 411 #elif defined(WIN32) |
412 dev_name = strdup(path); | |
413 auth_drive = DVDOpenImageFile( path, have_css ); | |
7029 | 414 #endif |
415 if( !dev_name ) { | |
416 fprintf( stderr, "libdvdread: Couldn't find device name.\n" ); | |
417 } else if( !auth_drive ) { | |
418 fprintf( stderr, "libdvdread: Device %s inaccessible, " | |
419 "CSS authentication not available.\n", dev_name ); | |
420 } | |
421 | |
422 free( dev_name ); | |
423 free( path_copy ); | |
424 | |
425 /** | |
426 * If we've opened a drive, just use that. | |
427 */ | |
428 if( auth_drive ) return auth_drive; | |
429 | |
430 /** | |
431 * Otherwise, we now try to open the directory tree instead. | |
432 */ | |
433 return DVDOpenPath( path ); | |
434 } | |
435 | |
436 /* If it's none of the above, screw it. */ | |
437 fprintf( stderr, "libdvdread: Could not open %s\n", path ); | |
438 return 0; | |
439 } | |
440 | |
441 void DVDClose( dvd_reader_t *dvd ) | |
442 { | |
443 if( dvd ) { | |
444 if( dvd->dev ) DVDinput_close( dvd->dev ); | |
445 if( dvd->path_root ) free( dvd->path_root ); | |
446 free( dvd ); | |
447 dvd = 0; | |
448 } | |
449 } | |
450 | |
451 /** | |
452 * Open an unencrypted file on a DVD image file. | |
453 */ | |
454 static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *dvd, char *filename ) | |
455 { | |
456 uint32_t start, len; | |
457 dvd_file_t *dvd_file; | |
458 | |
459 start = UDFFindFile( dvd, filename, &len ); | |
460 if( !start ) return 0; | |
461 | |
462 dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); | |
463 if( !dvd_file ) return 0; | |
464 dvd_file->dvd = dvd; | |
465 dvd_file->lb_start = start; | |
466 dvd_file->seek_pos = 0; | |
467 memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); | |
468 memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); | |
469 dvd_file->filesize = len / DVD_VIDEO_LB_LEN; | |
470 | |
471 return dvd_file; | |
472 } | |
473 | |
474 /** | |
475 * Searches for <file> in directory <path>, ignoring case. | |
476 * Returns 0 and full filename in <filename>. | |
477 * or -1 on file not found. | |
478 * or -2 on path not found. | |
479 */ | |
480 static int findDirFile( const char *path, const char *file, char *filename ) | |
481 { | |
482 DIR *dir; | |
483 struct dirent *ent; | |
484 | |
485 dir = opendir( path ); | |
486 if( !dir ) return -2; | |
487 | |
488 while( ( ent = readdir( dir ) ) != NULL ) { | |
489 if( !strcasecmp( ent->d_name, file ) ) { | |
490 sprintf( filename, "%s%s%s", path, | |
491 ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ), | |
492 ent->d_name ); | |
493 return 0; | |
494 } | |
495 } | |
496 | |
497 return -1; | |
498 } | |
499 | |
500 static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename ) | |
501 { | |
502 char video_path[ PATH_MAX + 1 ]; | |
503 const char *nodirfile; | |
504 int ret; | |
505 | |
506 /* Strip off the directory for our search */ | |
507 if( !strncasecmp( "/VIDEO_TS/", file, 10 ) ) { | |
508 nodirfile = &(file[ 10 ]); | |
509 } else { | |
510 nodirfile = file; | |
511 } | |
512 | |
513 ret = findDirFile( dvd->path_root, nodirfile, filename ); | |
514 if( ret < 0 ) { | |
515 /* Try also with adding the path, just in case. */ | |
516 sprintf( video_path, "%s/VIDEO_TS/", dvd->path_root ); | |
517 ret = findDirFile( video_path, nodirfile, filename ); | |
518 if( ret < 0 ) { | |
519 /* Try with the path, but in lower case. */ | |
520 sprintf( video_path, "%s/video_ts/", dvd->path_root ); | |
521 ret = findDirFile( video_path, nodirfile, filename ); | |
522 if( ret < 0 ) { | |
523 return 0; | |
524 } | |
525 } | |
526 } | |
527 | |
528 return 1; | |
529 } | |
530 | |
531 /** | |
532 * Open an unencrypted file from a DVD directory tree. | |
533 */ | |
534 static dvd_file_t *DVDOpenFilePath( dvd_reader_t *dvd, char *filename ) | |
535 { | |
536 char full_path[ PATH_MAX + 1 ]; | |
537 dvd_file_t *dvd_file; | |
538 struct stat fileinfo; | |
539 dvd_input_t dev; | |
540 | |
541 /* Get the full path of the file. */ | |
542 if( !findDVDFile( dvd, filename, full_path ) ) return 0; | |
543 | |
544 dev = DVDinput_open( full_path ); | |
545 if( !dev ) return 0; | |
546 | |
547 dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); | |
548 if( !dvd_file ) return 0; | |
549 dvd_file->dvd = dvd; | |
550 dvd_file->lb_start = 0; | |
551 dvd_file->seek_pos = 0; | |
552 memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); | |
553 memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); | |
554 dvd_file->filesize = 0; | |
555 | |
556 if( stat( full_path, &fileinfo ) < 0 ) { | |
557 fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); | |
558 free( dvd_file ); | |
559 return 0; | |
560 } | |
561 dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; | |
562 dvd_file->title_devs[ 0 ] = dev; | |
563 dvd_file->filesize = dvd_file->title_sizes[ 0 ]; | |
564 | |
565 return dvd_file; | |
566 } | |
567 | |
568 static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *dvd, int title, int menu ) | |
569 { | |
570 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
571 uint32_t start, len; | |
572 dvd_file_t *dvd_file; | |
573 | |
574 if( title == 0 ) { | |
575 sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" ); | |
576 } else { | |
577 sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, menu ? 0 : 1 ); | |
578 } | |
579 start = UDFFindFile( dvd, filename, &len ); | |
580 if( start == 0 ) return 0; | |
581 | |
582 dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); | |
583 if( !dvd_file ) return 0; | |
584 dvd_file->dvd = dvd; | |
585 /*Hack*/ dvd_file->css_title = title << 1 | menu; | |
586 dvd_file->lb_start = start; | |
587 dvd_file->seek_pos = 0; | |
588 memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); | |
589 memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); | |
590 dvd_file->filesize = len / DVD_VIDEO_LB_LEN; | |
591 | |
592 /* Calculate the complete file size for every file in the VOBS */ | |
593 if( !menu ) { | |
594 int cur; | |
595 | |
596 for( cur = 2; cur < 10; cur++ ) { | |
597 sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, cur ); | |
598 if( !UDFFindFile( dvd, filename, &len ) ) break; | |
599 dvd_file->filesize += len / DVD_VIDEO_LB_LEN; | |
600 } | |
601 } | |
602 | |
603 if( dvd->css_state == 1 /* Need key init */ ) { | |
7033 | 604 // initAllCSSKeys( dvd ); |
605 // dvd->css_state = 2; | |
7029 | 606 } |
607 /* | |
608 if( DVDinput_seek( dvd_file->dvd->dev, | |
609 (int)start, DVDINPUT_SEEK_KEY ) < 0 ) { | |
610 fprintf( stderr, "libdvdread: Error cracking CSS key for %s\n", | |
611 filename ); | |
612 } | |
613 */ | |
614 | |
615 return dvd_file; | |
616 } | |
617 | |
618 static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *dvd, int title, int menu ) | |
619 { | |
620 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
621 char full_path[ PATH_MAX + 1 ]; | |
622 struct stat fileinfo; | |
623 dvd_file_t *dvd_file; | |
624 int i; | |
625 | |
626 dvd_file = (dvd_file_t *) malloc( sizeof( dvd_file_t ) ); | |
627 if( !dvd_file ) return 0; | |
628 dvd_file->dvd = dvd; | |
629 /*Hack*/ dvd_file->css_title = title << 1 | menu; | |
630 dvd_file->lb_start = 0; | |
631 dvd_file->seek_pos = 0; | |
632 memset( dvd_file->title_sizes, 0, sizeof( dvd_file->title_sizes ) ); | |
633 memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) ); | |
634 dvd_file->filesize = 0; | |
635 | |
636 if( menu ) { | |
637 dvd_input_t dev; | |
638 | |
639 if( title == 0 ) { | |
640 sprintf( filename, "VIDEO_TS.VOB" ); | |
641 } else { | |
642 sprintf( filename, "VTS_%02i_0.VOB", title ); | |
643 } | |
644 if( !findDVDFile( dvd, filename, full_path ) ) { | |
645 free( dvd_file ); | |
646 return 0; | |
647 } | |
648 | |
649 dev = DVDinput_open( full_path ); | |
650 if( dev == NULL ) { | |
651 free( dvd_file ); | |
652 return 0; | |
653 } | |
654 | |
655 if( stat( full_path, &fileinfo ) < 0 ) { | |
656 fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); | |
657 free( dvd_file ); | |
658 return 0; | |
659 } | |
660 dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; | |
661 dvd_file->title_devs[ 0 ] = dev; | |
662 DVDinput_seek( dvd_file->title_devs[0], 0, DVDINPUT_SEEK_KEY ); | |
663 dvd_file->filesize = dvd_file->title_sizes[ 0 ]; | |
664 | |
665 } else { | |
666 for( i = 0; i < 9; ++i ) { | |
667 | |
668 sprintf( filename, "VTS_%02i_%i.VOB", title, i + 1 ); | |
669 if( !findDVDFile( dvd, filename, full_path ) ) { | |
670 break; | |
671 } | |
672 | |
673 if( stat( full_path, &fileinfo ) < 0 ) { | |
674 fprintf( stderr, "libdvdread: Can't stat() %s.\n", filename ); | |
675 break; | |
676 } | |
677 | |
678 dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; | |
679 dvd_file->title_devs[ i ] = DVDinput_open( full_path ); | |
680 dvd_file->filesize += dvd_file->title_sizes[ i ]; | |
8881
1e40d4a2466f
Function DVDOpenVOBPath only decrypts first VOB file and since each VOB file has
arpi
parents:
7423
diff
changeset
|
681 DVDinput_seek( dvd_file->title_devs[ i ], 0, DVDINPUT_SEEK_KEY ); |
7029 | 682 } |
8881
1e40d4a2466f
Function DVDOpenVOBPath only decrypts first VOB file and since each VOB file has
arpi
parents:
7423
diff
changeset
|
683 if( !dvd_file->title_devs[ 0 ] ) { |
7029 | 684 free( dvd_file ); |
685 return 0; | |
686 } | |
687 } | |
688 | |
689 return dvd_file; | |
690 } | |
691 | |
692 dvd_file_t *DVDOpenFile( dvd_reader_t *dvd, int titlenum, | |
693 dvd_read_domain_t domain ) | |
694 { | |
695 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
696 | |
697 switch( domain ) { | |
698 case DVD_READ_INFO_FILE: | |
699 if( titlenum == 0 ) { | |
700 sprintf( filename, "/VIDEO_TS/VIDEO_TS.IFO" ); | |
701 } else { | |
702 sprintf( filename, "/VIDEO_TS/VTS_%02i_0.IFO", titlenum ); | |
703 } | |
704 break; | |
705 case DVD_READ_INFO_BACKUP_FILE: | |
706 if( titlenum == 0 ) { | |
707 sprintf( filename, "/VIDEO_TS/VIDEO_TS.BUP" ); | |
708 } else { | |
709 sprintf( filename, "/VIDEO_TS/VTS_%02i_0.BUP", titlenum ); | |
710 } | |
711 break; | |
712 case DVD_READ_MENU_VOBS: | |
713 if( dvd->isImageFile ) { | |
714 return DVDOpenVOBUDF( dvd, titlenum, 1 ); | |
715 } else { | |
716 return DVDOpenVOBPath( dvd, titlenum, 1 ); | |
717 } | |
718 break; | |
719 case DVD_READ_TITLE_VOBS: | |
720 if( titlenum == 0 ) return 0; | |
721 if( dvd->isImageFile ) { | |
722 return DVDOpenVOBUDF( dvd, titlenum, 0 ); | |
723 } else { | |
724 return DVDOpenVOBPath( dvd, titlenum, 0 ); | |
725 } | |
726 break; | |
727 default: | |
728 fprintf( stderr, "libdvdread: Invalid domain for file open.\n" ); | |
729 return 0; | |
730 } | |
731 | |
732 if( dvd->isImageFile ) { | |
733 return DVDOpenFileUDF( dvd, filename ); | |
734 } else { | |
735 return DVDOpenFilePath( dvd, filename ); | |
736 } | |
737 } | |
738 | |
739 void DVDCloseFile( dvd_file_t *dvd_file ) | |
740 { | |
741 int i; | |
742 | |
743 if( dvd_file ) { | |
744 if( dvd_file->dvd->isImageFile ) { | |
745 ; | |
746 } else { | |
747 for( i = 0; i < 9; ++i ) { | |
748 if( dvd_file->title_devs[ i ] ) { | |
749 DVDinput_close( dvd_file->title_devs[i] ); | |
750 } | |
751 } | |
752 } | |
753 | |
754 free( dvd_file ); | |
755 dvd_file = 0; | |
756 } | |
757 } | |
758 | |
759 /* Internal, but used from dvd_udf.c */ | |
760 int DVDReadBlocksUDFRaw( dvd_reader_t *device, uint32_t lb_number, | |
761 size_t block_count, unsigned char *data, | |
762 int encrypted ) | |
763 { | |
764 int ret; | |
765 | |
766 if( !device->dev ) { | |
767 fprintf( stderr, "libdvdread: Fatal error in block read.\n" ); | |
768 return 0; | |
769 } | |
770 | |
771 ret = DVDinput_seek( device->dev, (int) lb_number, DVDINPUT_NOFLAGS ); | |
772 if( ret != (int) lb_number ) { | |
773 fprintf( stderr, "libdvdread: Can't seek to block %u\n", lb_number ); | |
774 return 0; | |
775 } | |
776 | |
777 return DVDinput_read( device->dev, (char *) data, | |
778 (int) block_count, encrypted ); | |
779 } | |
780 | |
781 /* This is using a single input and starting from 'dvd_file->lb_start' offset. | |
782 * | |
783 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset' | |
784 * into the buffer located at 'data' and if 'encrypted' is set | |
785 * descramble the data if it's encrypted. Returning either an | |
786 * negative error or the number of blocks read. */ | |
787 static int DVDReadBlocksUDF( dvd_file_t *dvd_file, uint32_t offset, | |
788 size_t block_count, unsigned char *data, | |
789 int encrypted ) | |
790 { | |
791 return DVDReadBlocksUDFRaw( dvd_file->dvd, dvd_file->lb_start + offset, | |
792 block_count, data, encrypted ); | |
793 } | |
794 | |
795 /* This is using possibly several inputs and starting from an offset of '0'. | |
796 * | |
797 * Reads 'block_count' blocks from 'dvd_file' at block offset 'offset' | |
798 * into the buffer located at 'data' and if 'encrypted' is set | |
799 * descramble the data if it's encrypted. Returning either an | |
800 * negative error or the number of blocks read. */ | |
801 static int DVDReadBlocksPath( dvd_file_t *dvd_file, unsigned int offset, | |
802 size_t block_count, unsigned char *data, | |
803 int encrypted ) | |
804 { | |
805 int i; | |
806 int ret, ret2, off; | |
807 | |
808 ret = 0; | |
809 ret2 = 0; | |
810 for( i = 0; i < 9; ++i ) { | |
811 if( !dvd_file->title_sizes[ i ] ) return 0; /* Past end of file */ | |
812 | |
813 if( offset < dvd_file->title_sizes[ i ] ) { | |
814 if( ( offset + block_count ) <= dvd_file->title_sizes[ i ] ) { | |
815 off = DVDinput_seek( dvd_file->title_devs[ i ], | |
816 (int)offset, DVDINPUT_NOFLAGS ); | |
817 if( off < 0 || off != (int)offset ) { | |
818 fprintf( stderr, "libdvdread: Can't seek to block %d\n", | |
819 offset ); | |
820 return off < 0 ? off : 0; | |
821 } | |
822 ret = DVDinput_read( dvd_file->title_devs[ i ], data, | |
823 (int)block_count, encrypted ); | |
824 break; | |
825 } else { | |
826 size_t part1_size = dvd_file->title_sizes[ i ] - offset; | |
827 /* FIXME: Really needs to be a while loop. | |
828 * (This is only true if you try and read >1GB at a time) */ | |
829 | |
830 /* Read part 1 */ | |
831 off = DVDinput_seek( dvd_file->title_devs[ i ], | |
832 (int)offset, DVDINPUT_NOFLAGS ); | |
833 if( off < 0 || off != (int)offset ) { | |
834 fprintf( stderr, "libdvdread: Can't seek to block %d\n", | |
835 offset ); | |
836 return off < 0 ? off : 0; | |
837 } | |
838 ret = DVDinput_read( dvd_file->title_devs[ i ], data, | |
839 (int)part1_size, encrypted ); | |
840 if( ret < 0 ) return ret; | |
841 /* FIXME: This is wrong if i is the last file in the set. | |
842 * also error from this read will not show in ret. */ | |
7358
bb40478265df
I experienced several segfaults when trying to play (unencrypted) DVDs
arpi
parents:
7033
diff
changeset
|
843 |
bb40478265df
I experienced several segfaults when trying to play (unencrypted) DVDs
arpi
parents:
7033
diff
changeset
|
844 /* Does the next part exist? If not then return now. */ |
bb40478265df
I experienced several segfaults when trying to play (unencrypted) DVDs
arpi
parents:
7033
diff
changeset
|
845 if( !dvd_file->title_devs[ i + 1 ] ) return ret; |
bb40478265df
I experienced several segfaults when trying to play (unencrypted) DVDs
arpi
parents:
7033
diff
changeset
|
846 |
7029 | 847 /* Read part 2 */ |
848 off = DVDinput_seek( dvd_file->title_devs[ i + 1 ], | |
849 0, DVDINPUT_NOFLAGS ); | |
850 if( off < 0 || off != 0 ) { | |
851 fprintf( stderr, "libdvdread: Can't seek to block %d\n", | |
852 0 ); | |
853 return off < 0 ? off : 0; | |
854 } | |
855 ret2 = DVDinput_read( dvd_file->title_devs[ i + 1 ], | |
856 data + ( part1_size | |
857 * (int64_t)DVD_VIDEO_LB_LEN ), | |
858 (int)(block_count - part1_size), | |
859 encrypted ); | |
860 if( ret2 < 0 ) return ret2; | |
861 break; | |
862 } | |
863 } else { | |
864 offset -= dvd_file->title_sizes[ i ]; | |
865 } | |
866 } | |
867 | |
868 return ret + ret2; | |
869 } | |
870 | |
871 /* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */ | |
872 ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset, | |
873 size_t block_count, unsigned char *data ) | |
874 { | |
875 int ret; | |
876 | |
877 /* Hack, and it will still fail for multiple opens in a threaded app ! */ | |
878 if( dvd_file->dvd->css_title != dvd_file->css_title ) { | |
879 dvd_file->dvd->css_title = dvd_file->css_title; | |
880 if( dvd_file->dvd->isImageFile ) { | |
881 DVDinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start ); | |
882 } else { | |
883 DVDinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start ); | |
884 } | |
885 } | |
886 | |
887 if( dvd_file->dvd->isImageFile ) { | |
888 ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset, | |
889 block_count, data, DVDINPUT_READ_DECRYPT ); | |
890 } else { | |
891 ret = DVDReadBlocksPath( dvd_file, (unsigned int)offset, | |
892 block_count, data, DVDINPUT_READ_DECRYPT ); | |
893 } | |
894 | |
895 return (ssize_t)ret; | |
896 } | |
897 | |
10017
535a53c058f8
There are conflicting definitions for DVDFileSeek in the .c and .h file.
diego
parents:
9333
diff
changeset
|
898 int DVDFileSeek( dvd_file_t *dvd_file, int offset ) |
7029 | 899 { |
900 if( offset > dvd_file->filesize * DVD_VIDEO_LB_LEN ) { | |
901 return -1; | |
902 } | |
903 dvd_file->seek_pos = (uint32_t) offset; | |
904 return offset; | |
905 } | |
906 | |
907 ssize_t DVDReadBytes( dvd_file_t *dvd_file, void *data, size_t byte_size ) | |
908 { | |
909 unsigned char *secbuf; | |
910 unsigned int numsec, seek_sector, seek_byte; | |
911 int ret; | |
912 | |
913 seek_sector = dvd_file->seek_pos / DVD_VIDEO_LB_LEN; | |
914 seek_byte = dvd_file->seek_pos % DVD_VIDEO_LB_LEN; | |
915 | |
916 numsec = ( ( seek_byte + byte_size ) / DVD_VIDEO_LB_LEN ) + 1; | |
917 secbuf = (unsigned char *) malloc( numsec * DVD_VIDEO_LB_LEN ); | |
918 if( !secbuf ) { | |
919 fprintf( stderr, "libdvdread: Can't allocate memory " | |
920 "for file read!\n" ); | |
921 return 0; | |
922 } | |
923 | |
924 if( dvd_file->dvd->isImageFile ) { | |
925 ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector, | |
926 (size_t) numsec, secbuf, DVDINPUT_NOFLAGS ); | |
927 } else { | |
928 ret = DVDReadBlocksPath( dvd_file, seek_sector, | |
929 (size_t) numsec, secbuf, DVDINPUT_NOFLAGS ); | |
930 } | |
931 | |
932 if( ret != (int) numsec ) { | |
933 free( secbuf ); | |
934 return ret < 0 ? ret : 0; | |
935 } | |
936 | |
937 memcpy( data, &(secbuf[ seek_byte ]), byte_size ); | |
938 free( secbuf ); | |
939 | |
940 dvd_file->seek_pos += byte_size; | |
941 return byte_size; | |
942 } | |
943 | |
944 ssize_t DVDFileSize( dvd_file_t *dvd_file ) | |
945 { | |
946 return dvd_file->filesize; | |
947 } |