Mercurial > mplayer.hg
annotate dvdread/dvd_udf.c @ 23978:ef6e50c3c172
Revert setting audio output channel count for FFmpeg
The FFmpeg API needs to be fixed before this can be done sanely.
ffdca wants the desired output channel count to be set in
avctx->channels. Unfortunately it also completely fails if the requested
number of channels is not available rather than returning a different
amount (if 6 channels are requested we'd probably rather use stereo than
fail completely).
ffvorbis ignores caller-set values in avctx->channels. It writes the
channel count there once during init. This means the caller can only
set the count before init because later there would be no indication
whether the channel count in avctx reflects real output.
ffwma requires the caller to supply the encoded channel count
in avctx->channels during init or it fails. So it is not possible to
set a different number of desired output channels there before init
either.
author | uau |
---|---|
date | Thu, 02 Aug 2007 21:54:14 +0000 |
parents | 22cb9d5f1e21 |
children | de28f9e8cb00 |
rev | line source |
---|---|
7029 | 1 /* |
2 * This code is based on dvdudf by: | |
3 * Christian Wolff <scarabaeus@convergence.de>. | |
4 * | |
5 * Modifications by: | |
6 * Billy Biggs <vektor@dumbterm.net>. | |
10723 | 7 * Björn Englund <d4bjorn@dtek.chalmers.se>. |
7029 | 8 * |
14938
25df9508f9a8
Mark modified files as such to comply more closely with GPL ¡ø2a.
diego
parents:
10723
diff
changeset
|
9 * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. |
18783 | 10 * detailed changelog at http://svn.mplayerhq.hu/mplayer/trunk/ |
14938
25df9508f9a8
Mark modified files as such to comply more closely with GPL ¡ø2a.
diego
parents:
10723
diff
changeset
|
11 * $Id$ |
25df9508f9a8
Mark modified files as such to comply more closely with GPL ¡ø2a.
diego
parents:
10723
diff
changeset
|
12 * |
7029 | 13 * dvdudf: parse and read the UDF volume information of a DVD Video |
14 * Copyright (C) 1999 Christian Wolff for convergence integrated media | |
15 * GmbH The author can be reached at scarabaeus@convergence.de, the | |
16 * project's page is at http://linuxtv.org/dvd/ | |
17 * | |
18 * This program is free software; you can redistribute it and/or modify | |
19 * it under the terms of the GNU General Public License as published by | |
20 * the Free Software Foundation; either version 2 of the License, or (at | |
21 * your option) any later version. | |
22 * | |
23 * This program is distributed in the hope that it will be useful, but | |
24 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
26 * General Public License for more details. | |
27 * | |
28 * You should have received a copy of the GNU General Public License | |
29 * along with this program; if not, write to the Free Software | |
30 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
31 * 02111-1307, USA. Or, point your browser to | |
32 * http://www.gnu.org/copyleft/gpl.html | |
33 */ | |
34 | |
15874 | 35 #include "config.h" |
36 | |
7029 | 37 #include <stdio.h> |
38 #include <stdlib.h> | |
39 #include <string.h> | |
9928 | 40 #ifndef __MINGW32__ |
7029 | 41 #include <sys/ioctl.h> |
9928 | 42 #endif |
7029 | 43 #include <sys/types.h> |
44 #include <sys/stat.h> | |
45 #include <unistd.h> | |
46 #include <inttypes.h> | |
47 | |
48 #include "dvd_reader.h" | |
49 #include "dvd_udf.h" | |
50 | |
51 /* Private but located in/shared with dvd_reader.c */ | |
15874 | 52 extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, |
7029 | 53 size_t block_count, unsigned char *data, |
54 int encrypted ); | |
55 | |
56 /* It's required to either fail or deliver all the blocks asked for. */ | |
57 static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number, | |
58 size_t block_count, unsigned char *data, | |
59 int encrypted ) | |
60 { | |
61 int ret; | |
62 size_t count = block_count; | |
63 | |
64 while(count > 0) { | |
65 | |
15874 | 66 ret = UDFReadBlocksRaw(device, lb_number, count, data, encrypted); |
7029 | 67 |
68 if(ret <= 0) { | |
69 /* One of the reads failed or nothing more to read, too bad. | |
70 * We won't even bother returning the reads that went ok. */ | |
71 return ret; | |
72 } | |
73 | |
74 count -= (size_t)ret; | |
75 lb_number += (uint32_t)ret; | |
76 } | |
77 | |
78 return block_count; | |
79 } | |
80 | |
81 | |
82 #ifndef NULL | |
83 #define NULL ((void *)0) | |
84 #endif | |
85 | |
86 struct Partition { | |
87 int valid; | |
88 char VolumeDesc[128]; | |
89 uint16_t Flags; | |
90 uint16_t Number; | |
91 char Contents[32]; | |
92 uint32_t AccessType; | |
93 uint32_t Start; | |
94 uint32_t Length; | |
95 }; | |
96 | |
97 struct AD { | |
98 uint32_t Location; | |
99 uint32_t Length; | |
100 uint8_t Flags; | |
101 uint16_t Partition; | |
102 }; | |
103 | |
10723 | 104 struct extent_ad { |
105 uint32_t location; | |
106 uint32_t length; | |
107 }; | |
108 | |
109 struct avdp_t { | |
110 struct extent_ad mvds; | |
111 struct extent_ad rvds; | |
112 }; | |
113 | |
114 struct pvd_t { | |
115 uint8_t VolumeIdentifier[32]; | |
116 uint8_t VolumeSetIdentifier[128]; | |
117 }; | |
118 | |
119 struct lbudf { | |
120 uint32_t lb; | |
121 uint8_t *data; | |
122 }; | |
123 | |
124 struct icbmap { | |
125 uint32_t lbn; | |
126 struct AD file; | |
127 uint8_t filetype; | |
128 }; | |
129 | |
15874 | 130 struct udf_cache { |
131 int avdp_valid; | |
132 struct avdp_t avdp; | |
133 int pvd_valid; | |
134 struct pvd_t pvd; | |
135 int partition_valid; | |
136 struct Partition partition; | |
137 int rooticb_valid; | |
138 struct AD rooticb; | |
139 int lb_num; | |
140 struct lbudf *lbs; | |
141 int map_num; | |
142 struct icbmap *maps; | |
143 }; | |
144 | |
145 typedef enum { | |
146 PartitionCache, RootICBCache, LBUDFCache, MapCache, AVDPCache, PVDCache | |
147 } UDFCacheType; | |
148 | |
149 extern void *GetUDFCacheHandle(dvd_reader_t *device); | |
150 extern void SetUDFCacheHandle(dvd_reader_t *device, void *cache); | |
151 | |
152 void FreeUDFCache(void *cache) | |
153 { | |
154 struct udf_cache *c = (struct udf_cache *)cache; | |
155 if(c == NULL) { | |
156 return; | |
157 } | |
158 if(c->lbs) { | |
159 free(c->lbs); | |
160 } | |
161 if(c->maps) { | |
162 free(c->maps); | |
163 } | |
164 free(c); | |
165 } | |
166 | |
167 | |
168 static int GetUDFCache(dvd_reader_t *device, UDFCacheType type, | |
169 uint32_t nr, void *data) | |
170 { | |
171 int n; | |
172 struct udf_cache *c; | |
173 | |
174 if(DVDUDFCacheLevel(device, -1) <= 0) { | |
175 return 0; | |
176 } | |
177 | |
178 c = (struct udf_cache *)GetUDFCacheHandle(device); | |
179 | |
180 if(c == NULL) { | |
181 return 0; | |
182 } | |
183 | |
184 switch(type) { | |
185 case AVDPCache: | |
186 if(c->avdp_valid) { | |
187 *(struct avdp_t *)data = c->avdp; | |
188 return 1; | |
189 } | |
190 break; | |
191 case PVDCache: | |
192 if(c->pvd_valid) { | |
193 *(struct pvd_t *)data = c->pvd; | |
194 return 1; | |
195 } | |
196 break; | |
197 case PartitionCache: | |
198 if(c->partition_valid) { | |
199 *(struct Partition *)data = c->partition; | |
200 return 1; | |
201 } | |
202 break; | |
203 case RootICBCache: | |
204 if(c->rooticb_valid) { | |
205 *(struct AD *)data = c->rooticb; | |
206 return 1; | |
207 } | |
208 break; | |
209 case LBUDFCache: | |
210 for(n = 0; n < c->lb_num; n++) { | |
211 if(c->lbs[n].lb == nr) { | |
212 *(uint8_t **)data = c->lbs[n].data; | |
213 return 1; | |
214 } | |
215 } | |
216 break; | |
217 case MapCache: | |
218 for(n = 0; n < c->map_num; n++) { | |
219 if(c->maps[n].lbn == nr) { | |
220 *(struct icbmap *)data = c->maps[n]; | |
221 return 1; | |
222 } | |
223 } | |
224 break; | |
225 default: | |
226 break; | |
227 } | |
228 | |
229 return 0; | |
230 } | |
231 | |
232 static int SetUDFCache(dvd_reader_t *device, UDFCacheType type, | |
233 uint32_t nr, void *data) | |
234 { | |
235 int n; | |
236 struct udf_cache *c; | |
237 | |
238 if(DVDUDFCacheLevel(device, -1) <= 0) { | |
239 return 0; | |
240 } | |
241 | |
242 c = (struct udf_cache *)GetUDFCacheHandle(device); | |
243 | |
244 if(c == NULL) { | |
245 c = calloc(1, sizeof(struct udf_cache)); | |
246 // fprintf(stderr, "calloc: %d\n", sizeof(struct udf_cache)); | |
247 if(c == NULL) { | |
248 return 0; | |
249 } | |
250 SetUDFCacheHandle(device, c); | |
251 } | |
252 | |
253 | |
254 switch(type) { | |
255 case AVDPCache: | |
256 c->avdp = *(struct avdp_t *)data; | |
257 c->avdp_valid = 1; | |
258 break; | |
259 case PVDCache: | |
260 c->pvd = *(struct pvd_t *)data; | |
261 c->pvd_valid = 1; | |
262 break; | |
263 case PartitionCache: | |
264 c->partition = *(struct Partition *)data; | |
265 c->partition_valid = 1; | |
266 break; | |
267 case RootICBCache: | |
268 c->rooticb = *(struct AD *)data; | |
269 c->rooticb_valid = 1; | |
270 break; | |
271 case LBUDFCache: | |
272 for(n = 0; n < c->lb_num; n++) { | |
273 if(c->lbs[n].lb == nr) { | |
274 /* replace with new data */ | |
275 c->lbs[n].data = *(uint8_t **)data; | |
276 c->lbs[n].lb = nr; | |
277 return 1; | |
278 } | |
279 } | |
280 c->lb_num++; | |
281 c->lbs = realloc(c->lbs, c->lb_num * sizeof(struct lbudf)); | |
282 /* | |
283 fprintf(stderr, "realloc lb: %d * %d = %d\n", | |
284 c->lb_num, sizeof(struct lbudf), | |
285 c->lb_num * sizeof(struct lbudf)); | |
286 */ | |
287 if(c->lbs == NULL) { | |
288 c->lb_num = 0; | |
289 return 0; | |
290 } | |
291 c->lbs[n].data = *(uint8_t **)data; | |
292 c->lbs[n].lb = nr; | |
293 break; | |
294 case MapCache: | |
295 for(n = 0; n < c->map_num; n++) { | |
296 if(c->maps[n].lbn == nr) { | |
297 /* replace with new data */ | |
298 c->maps[n] = *(struct icbmap *)data; | |
299 c->maps[n].lbn = nr; | |
300 return 1; | |
301 } | |
302 } | |
303 c->map_num++; | |
304 c->maps = realloc(c->maps, c->map_num * sizeof(struct icbmap)); | |
305 /* | |
306 fprintf(stderr, "realloc maps: %d * %d = %d\n", | |
307 c->map_num, sizeof(struct icbmap), | |
308 c->map_num * sizeof(struct icbmap)); | |
309 */ | |
310 if(c->maps == NULL) { | |
311 c->map_num = 0; | |
312 return 0; | |
313 } | |
314 c->maps[n] = *(struct icbmap *)data; | |
315 c->maps[n].lbn = nr; | |
316 break; | |
317 default: | |
318 return 0; | |
319 } | |
320 | |
321 return 1; | |
322 } | |
323 | |
324 | |
7029 | 325 /* For direct data access, LSB first */ |
326 #define GETN1(p) ((uint8_t)data[p]) | |
327 #define GETN2(p) ((uint16_t)data[p] | ((uint16_t)data[(p) + 1] << 8)) | |
328 #define GETN3(p) ((uint32_t)data[p] | ((uint32_t)data[(p) + 1] << 8) \ | |
329 | ((uint32_t)data[(p) + 2] << 16)) | |
330 #define GETN4(p) ((uint32_t)data[p] \ | |
331 | ((uint32_t)data[(p) + 1] << 8) \ | |
332 | ((uint32_t)data[(p) + 2] << 16) \ | |
333 | ((uint32_t)data[(p) + 3] << 24)) | |
334 /* This is wrong with regard to endianess */ | |
335 #define GETN(p, n, target) memcpy(target, &data[p], n) | |
336 | |
337 static int Unicodedecode( uint8_t *data, int len, char *target ) | |
338 { | |
339 int p = 1, i = 0; | |
340 | |
341 if( ( data[ 0 ] == 8 ) || ( data[ 0 ] == 16 ) ) do { | |
342 if( data[ 0 ] == 16 ) p++; /* Ignore MSB of unicode16 */ | |
343 if( p < len ) { | |
344 target[ i++ ] = data[ p++ ]; | |
345 } | |
346 } while( p < len ); | |
347 | |
348 target[ i ] = '\0'; | |
349 return 0; | |
350 } | |
351 | |
352 static int UDFDescriptor( uint8_t *data, uint16_t *TagID ) | |
353 { | |
354 *TagID = GETN2(0); | |
355 // TODO: check CRC 'n stuff | |
356 return 0; | |
357 } | |
358 | |
359 static int UDFExtentAD( uint8_t *data, uint32_t *Length, uint32_t *Location ) | |
360 { | |
361 *Length = GETN4(0); | |
362 *Location = GETN4(4); | |
363 return 0; | |
364 } | |
365 | |
366 static int UDFShortAD( uint8_t *data, struct AD *ad, | |
367 struct Partition *partition ) | |
368 { | |
369 ad->Length = GETN4(0); | |
370 ad->Flags = ad->Length >> 30; | |
371 ad->Length &= 0x3FFFFFFF; | |
372 ad->Location = GETN4(4); | |
373 ad->Partition = partition->Number; // use number of current partition | |
374 return 0; | |
375 } | |
376 | |
377 static int UDFLongAD( uint8_t *data, struct AD *ad ) | |
378 { | |
379 ad->Length = GETN4(0); | |
380 ad->Flags = ad->Length >> 30; | |
381 ad->Length &= 0x3FFFFFFF; | |
382 ad->Location = GETN4(4); | |
383 ad->Partition = GETN2(8); | |
384 //GETN(10, 6, Use); | |
385 return 0; | |
386 } | |
387 | |
388 static int UDFExtAD( uint8_t *data, struct AD *ad ) | |
389 { | |
390 ad->Length = GETN4(0); | |
391 ad->Flags = ad->Length >> 30; | |
392 ad->Length &= 0x3FFFFFFF; | |
393 ad->Location = GETN4(12); | |
394 ad->Partition = GETN2(16); | |
395 //GETN(10, 6, Use); | |
396 return 0; | |
397 } | |
398 | |
399 static int UDFICB( uint8_t *data, uint8_t *FileType, uint16_t *Flags ) | |
400 { | |
401 *FileType = GETN1(11); | |
402 *Flags = GETN2(18); | |
403 return 0; | |
404 } | |
405 | |
406 | |
407 static int UDFPartition( uint8_t *data, uint16_t *Flags, uint16_t *Number, | |
408 char *Contents, uint32_t *Start, uint32_t *Length ) | |
409 { | |
410 *Flags = GETN2(20); | |
411 *Number = GETN2(22); | |
412 GETN(24, 32, Contents); | |
413 *Start = GETN4(188); | |
414 *Length = GETN4(192); | |
415 return 0; | |
416 } | |
417 | |
418 /** | |
419 * Reads the volume descriptor and checks the parameters. Returns 0 on OK, 1 | |
420 * on error. | |
421 */ | |
422 static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor ) | |
423 { | |
424 uint32_t lbsize, MT_L, N_PM; | |
425 Unicodedecode(&data[84], 128, VolumeDescriptor); | |
426 lbsize = GETN4(212); // should be 2048 | |
427 MT_L = GETN4(264); // should be 6 | |
428 N_PM = GETN4(268); // should be 1 | |
429 if (lbsize != DVD_VIDEO_LB_LEN) return 1; | |
430 return 0; | |
431 } | |
432 | |
433 static int UDFFileEntry( uint8_t *data, uint8_t *FileType, | |
434 struct Partition *partition, struct AD *ad ) | |
435 { | |
436 uint16_t flags; | |
437 uint32_t L_EA, L_AD; | |
438 unsigned int p; | |
439 | |
440 UDFICB( &data[ 16 ], FileType, &flags ); | |
441 | |
442 /* Init ad for an empty file (i.e. there isn't a AD, L_AD == 0 ) */ | |
443 ad->Length = GETN4( 60 ); // Really 8 bytes a 56 | |
444 ad->Flags = 0; | |
445 ad->Location = 0; // what should we put here? | |
446 ad->Partition = partition->Number; // use number of current partition | |
447 | |
448 L_EA = GETN4( 168 ); | |
449 L_AD = GETN4( 172 ); | |
450 p = 176 + L_EA; | |
451 while( p < 176 + L_EA + L_AD ) { | |
452 switch( flags & 0x0007 ) { | |
453 case 0: UDFShortAD( &data[ p ], ad, partition ); p += 8; break; | |
454 case 1: UDFLongAD( &data[ p ], ad ); p += 16; break; | |
455 case 2: UDFExtAD( &data[ p ], ad ); p += 20; break; | |
456 case 3: | |
457 switch( L_AD ) { | |
458 case 8: UDFShortAD( &data[ p ], ad, partition ); break; | |
459 case 16: UDFLongAD( &data[ p ], ad ); break; | |
460 case 20: UDFExtAD( &data[ p ], ad ); break; | |
461 } | |
462 p += L_AD; | |
463 break; | |
464 default: | |
465 p += L_AD; break; | |
466 } | |
467 } | |
468 return 0; | |
469 } | |
470 | |
471 static int UDFFileIdentifier( uint8_t *data, uint8_t *FileCharacteristics, | |
472 char *FileName, struct AD *FileICB ) | |
473 { | |
474 uint8_t L_FI; | |
475 uint16_t L_IU; | |
476 | |
477 *FileCharacteristics = GETN1(18); | |
478 L_FI = GETN1(19); | |
479 UDFLongAD(&data[20], FileICB); | |
480 L_IU = GETN2(36); | |
481 if (L_FI) Unicodedecode(&data[38 + L_IU], L_FI, FileName); | |
482 else FileName[0] = '\0'; | |
483 return 4 * ((38 + L_FI + L_IU + 3) / 4); | |
484 } | |
485 | |
486 /** | |
487 * Maps ICB to FileAD | |
488 * ICB: Location of ICB of directory to scan | |
489 * FileType: Type of the file | |
490 * File: Location of file the ICB is pointing to | |
491 * return 1 on success, 0 on error; | |
492 */ | |
493 static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, | |
494 struct Partition *partition, struct AD *File ) | |
495 { | |
496 uint8_t LogBlock[DVD_VIDEO_LB_LEN]; | |
497 uint32_t lbnum; | |
498 uint16_t TagID; | |
15874 | 499 struct icbmap tmpmap; |
7029 | 500 |
501 lbnum = partition->Start + ICB.Location; | |
15874 | 502 tmpmap.lbn = lbnum; |
503 if(GetUDFCache(device, MapCache, lbnum, &tmpmap)) { | |
504 *FileType = tmpmap.filetype; | |
505 *File = tmpmap.file; | |
506 return 1; | |
507 } | |
508 | |
7029 | 509 do { |
510 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { | |
511 TagID = 0; | |
512 } else { | |
513 UDFDescriptor( LogBlock, &TagID ); | |
514 } | |
515 | |
516 if( TagID == 261 ) { | |
517 UDFFileEntry( LogBlock, FileType, partition, File ); | |
15874 | 518 tmpmap.file = *File; |
519 tmpmap.filetype = *FileType; | |
520 SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap); | |
7029 | 521 return 1; |
522 }; | |
523 } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 ) | |
524 / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) ); | |
525 | |
526 return 0; | |
527 } | |
528 | |
529 /** | |
530 * Dir: Location of directory to scan | |
531 * FileName: Name of file to look for | |
532 * FileICB: Location of ICB of the found file | |
533 * return 1 on success, 0 on error; | |
534 */ | |
535 static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, | |
15874 | 536 struct Partition *partition, struct AD *FileICB, |
537 int cache_file_info) | |
7029 | 538 { |
539 char filename[ MAX_UDF_FILE_NAME_LEN ]; | |
540 uint8_t directory[ 2 * DVD_VIDEO_LB_LEN ]; | |
541 uint32_t lbnum; | |
542 uint16_t TagID; | |
543 uint8_t filechar; | |
544 unsigned int p; | |
15874 | 545 uint8_t *cached_dir = NULL; |
546 uint32_t dir_lba; | |
547 struct AD tmpICB; | |
548 int found = 0; | |
549 int in_cache = 0; | |
7029 | 550 |
551 /* Scan dir for ICB of file */ | |
552 lbnum = partition->Start + Dir.Location; | |
15874 | 553 |
554 if(DVDUDFCacheLevel(device, -1) > 0) { | |
555 /* caching */ | |
556 | |
557 if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) { | |
558 dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN; | |
559 if((cached_dir = malloc(dir_lba * DVD_VIDEO_LB_LEN)) == NULL) { | |
560 return 0; | |
561 } | |
562 if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) { | |
563 free(cached_dir); | |
564 cached_dir = NULL; | |
565 } | |
566 /* | |
567 if(cached_dir) { | |
568 fprintf(stderr, "malloc dir: %d\n", | |
569 dir_lba * DVD_VIDEO_LB_LEN); | |
570 } | |
571 */ | |
572 SetUDFCache(device, LBUDFCache, lbnum, &cached_dir); | |
573 } else { | |
574 in_cache = 1; | |
575 } | |
576 | |
577 if(cached_dir == NULL) { | |
578 return 0; | |
579 } | |
580 | |
581 p = 0; | |
582 | |
583 while( p < Dir.Length ) { | |
584 UDFDescriptor( &cached_dir[ p ], &TagID ); | |
585 if( TagID == 257 ) { | |
586 p += UDFFileIdentifier( &cached_dir[ p ], &filechar, | |
587 filename, &tmpICB ); | |
588 if(cache_file_info && !in_cache) { | |
589 uint8_t tmpFiletype; | |
590 struct AD tmpFile; | |
591 | |
592 if( !strcasecmp( FileName, filename ) ) { | |
593 *FileICB = tmpICB; | |
594 found = 1; | |
595 | |
596 } | |
597 UDFMapICB(device, tmpICB, &tmpFiletype, | |
598 partition, &tmpFile); | |
599 } else { | |
600 if( !strcasecmp( FileName, filename ) ) { | |
601 *FileICB = tmpICB; | |
602 return 1; | |
603 } | |
604 } | |
605 } else { | |
606 if(cache_file_info && (!in_cache) && found) { | |
607 return 1; | |
608 } | |
609 return 0; | |
610 } | |
611 } | |
612 if(cache_file_info && (!in_cache) && found) { | |
613 return 1; | |
614 } | |
615 return 0; | |
616 } | |
7029 | 617 |
618 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { | |
619 return 0; | |
620 } | |
621 | |
622 p = 0; | |
623 while( p < Dir.Length ) { | |
624 if( p > DVD_VIDEO_LB_LEN ) { | |
625 ++lbnum; | |
626 p -= DVD_VIDEO_LB_LEN; | |
627 Dir.Length -= DVD_VIDEO_LB_LEN; | |
628 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { | |
629 return 0; | |
630 } | |
631 } | |
632 UDFDescriptor( &directory[ p ], &TagID ); | |
633 if( TagID == 257 ) { | |
634 p += UDFFileIdentifier( &directory[ p ], &filechar, | |
635 filename, FileICB ); | |
636 if( !strcasecmp( FileName, filename ) ) { | |
637 return 1; | |
638 } | |
639 } else { | |
640 return 0; | |
641 } | |
642 } | |
643 | |
644 return 0; | |
645 } | |
646 | |
10723 | 647 |
648 static int UDFGetAVDP( dvd_reader_t *device, | |
649 struct avdp_t *avdp) | |
650 { | |
651 uint8_t Anchor[ DVD_VIDEO_LB_LEN ]; | |
652 uint32_t lbnum, MVDS_location, MVDS_length; | |
653 uint16_t TagID; | |
654 uint32_t lastsector; | |
655 int terminate; | |
656 struct avdp_t; | |
657 | |
15874 | 658 if(GetUDFCache(device, AVDPCache, 0, avdp)) { |
659 return 1; | |
660 } | |
661 | |
10723 | 662 /* Find Anchor */ |
663 lastsector = 0; | |
664 lbnum = 256; /* Try #1, prime anchor */ | |
665 terminate = 0; | |
666 | |
667 for(;;) { | |
668 if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) { | |
669 UDFDescriptor( Anchor, &TagID ); | |
670 } else { | |
671 TagID = 0; | |
672 } | |
673 if (TagID != 2) { | |
674 /* Not an anchor */ | |
675 if( terminate ) return 0; /* Final try failed */ | |
676 | |
677 if( lastsector ) { | |
678 | |
679 /* We already found the last sector. Try #3, alternative | |
680 * backup anchor. If that fails, don't try again. | |
681 */ | |
682 lbnum = lastsector; | |
683 terminate = 1; | |
684 } else { | |
685 /* TODO: Find last sector of the disc (this is optional). */ | |
686 if( lastsector ) { | |
687 /* Try #2, backup anchor */ | |
688 lbnum = lastsector - 256; | |
689 } else { | |
690 /* Unable to find last sector */ | |
691 return 0; | |
692 } | |
693 } | |
694 } else { | |
695 /* It's an anchor! We can leave */ | |
696 break; | |
697 } | |
698 } | |
699 /* Main volume descriptor */ | |
700 UDFExtentAD( &Anchor[ 16 ], &MVDS_length, &MVDS_location ); | |
701 avdp->mvds.location = MVDS_location; | |
702 avdp->mvds.length = MVDS_length; | |
703 | |
704 /* Backup volume descriptor */ | |
705 UDFExtentAD( &Anchor[ 24 ], &MVDS_length, &MVDS_location ); | |
706 avdp->rvds.location = MVDS_location; | |
707 avdp->rvds.length = MVDS_length; | |
708 | |
15874 | 709 SetUDFCache(device, AVDPCache, 0, avdp); |
710 | |
10723 | 711 return 1; |
712 } | |
713 | |
7029 | 714 /** |
715 * Looks for partition on the disc. Returns 1 if partition found, 0 on error. | |
716 * partnum: Number of the partition, starting at 0. | |
717 * part: structure to fill with the partition information | |
718 */ | |
719 static int UDFFindPartition( dvd_reader_t *device, int partnum, | |
720 struct Partition *part ) | |
721 { | |
10723 | 722 uint8_t LogBlock[ DVD_VIDEO_LB_LEN ]; |
7029 | 723 uint32_t lbnum, MVDS_location, MVDS_length; |
724 uint16_t TagID; | |
10723 | 725 int i, volvalid; |
726 struct avdp_t avdp; | |
7029 | 727 |
10723 | 728 |
729 if(!UDFGetAVDP(device, &avdp)) { | |
730 return 0; | |
7029 | 731 } |
10723 | 732 |
7029 | 733 /* Main volume descriptor */ |
10723 | 734 MVDS_location = avdp.mvds.location; |
735 MVDS_length = avdp.mvds.length; | |
736 | |
7029 | 737 part->valid = 0; |
738 volvalid = 0; | |
739 part->VolumeDesc[ 0 ] = '\0'; | |
740 i = 1; | |
741 do { | |
742 /* Find Volume Descriptor */ | |
743 lbnum = MVDS_location; | |
744 do { | |
745 | |
746 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { | |
747 TagID = 0; | |
748 } else { | |
749 UDFDescriptor( LogBlock, &TagID ); | |
750 } | |
751 | |
752 if( ( TagID == 5 ) && ( !part->valid ) ) { | |
753 /* Partition Descriptor */ | |
754 UDFPartition( LogBlock, &part->Flags, &part->Number, | |
755 part->Contents, &part->Start, &part->Length ); | |
756 part->valid = ( partnum == part->Number ); | |
757 } else if( ( TagID == 6 ) && ( !volvalid ) ) { | |
758 /* Logical Volume Descriptor */ | |
759 if( UDFLogVolume( LogBlock, part->VolumeDesc ) ) { | |
760 /* TODO: sector size wrong! */ | |
761 } else { | |
762 volvalid = 1; | |
763 } | |
764 } | |
765 | |
766 } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 ) | |
767 / DVD_VIDEO_LB_LEN ) && ( TagID != 8 ) | |
768 && ( ( !part->valid ) || ( !volvalid ) ) ); | |
769 | |
770 if( ( !part->valid) || ( !volvalid ) ) { | |
10723 | 771 /* Backup volume descriptor */ |
772 MVDS_location = avdp.mvds.location; | |
773 MVDS_length = avdp.mvds.length; | |
7029 | 774 } |
775 } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) ); | |
776 | |
777 /* We only care for the partition, not the volume */ | |
778 return part->valid; | |
779 } | |
780 | |
781 uint32_t UDFFindFile( dvd_reader_t *device, char *filename, | |
782 uint32_t *filesize ) | |
783 { | |
784 uint8_t LogBlock[ DVD_VIDEO_LB_LEN ]; | |
785 uint32_t lbnum; | |
786 uint16_t TagID; | |
787 struct Partition partition; | |
788 struct AD RootICB, File, ICB; | |
789 char tokenline[ MAX_UDF_FILE_NAME_LEN ]; | |
790 char *token; | |
791 uint8_t filetype; | |
10723 | 792 |
7029 | 793 *filesize = 0; |
794 tokenline[0] = '\0'; | |
795 strcat( tokenline, filename ); | |
796 | |
10723 | 797 |
15874 | 798 if(!(GetUDFCache(device, PartitionCache, 0, &partition) && |
799 GetUDFCache(device, RootICBCache, 0, &RootICB))) { | |
10723 | 800 /* Find partition, 0 is the standard location for DVD Video.*/ |
801 if( !UDFFindPartition( device, 0, &partition ) ) return 0; | |
15874 | 802 SetUDFCache(device, PartitionCache, 0, &partition); |
10723 | 803 |
804 /* Find root dir ICB */ | |
805 lbnum = partition.Start; | |
806 do { | |
7029 | 807 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { |
808 TagID = 0; | |
809 } else { | |
810 UDFDescriptor( LogBlock, &TagID ); | |
811 } | |
812 | |
813 /* File Set Descriptor */ | |
814 if( TagID == 256 ) { // File Set Descriptor | |
815 UDFLongAD( &LogBlock[ 400 ], &RootICB ); | |
816 } | |
817 } while( ( lbnum < partition.Start + partition.Length ) | |
818 && ( TagID != 8 ) && ( TagID != 256 ) ); | |
819 | |
820 /* Sanity checks. */ | |
821 if( TagID != 256 ) return 0; | |
822 if( RootICB.Partition != 0 ) return 0; | |
15874 | 823 SetUDFCache(device, RootICBCache, 0, &RootICB); |
824 } | |
10723 | 825 |
7029 | 826 /* Find root dir */ |
827 if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0; | |
828 if( filetype != 4 ) return 0; /* Root dir should be dir */ | |
829 | |
10723 | 830 { |
15874 | 831 int cache_file_info = 0; |
10723 | 832 /* Tokenize filepath */ |
833 token = strtok(tokenline, "/"); | |
834 | |
835 while( token != NULL ) { | |
836 | |
15874 | 837 if( !UDFScanDir( device, File, token, &partition, &ICB, |
838 cache_file_info)) { | |
10723 | 839 return 0; |
840 } | |
841 if( !UDFMapICB( device, ICB, &filetype, &partition, &File ) ) { | |
842 return 0; | |
843 } | |
15874 | 844 if(!strcmp(token, "VIDEO_TS")) { |
845 cache_file_info = 1; | |
846 } | |
7029 | 847 token = strtok( NULL, "/" ); |
10723 | 848 } |
849 } | |
850 | |
7029 | 851 /* Sanity check. */ |
852 if( File.Partition != 0 ) return 0; | |
853 | |
854 *filesize = File.Length; | |
855 /* Hack to not return partition.Start for empty files. */ | |
856 if( !File.Location ) | |
857 return 0; | |
858 else | |
859 return partition.Start + File.Location; | |
860 } | |
10723 | 861 |
862 | |
863 | |
864 /** | |
865 * Gets a Descriptor . | |
866 * Returns 1 if descriptor found, 0 on error. | |
867 * id, tagid of descriptor | |
868 * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN). | |
869 */ | |
870 static int UDFGetDescriptor( dvd_reader_t *device, int id, | |
871 uint8_t *descriptor, int bufsize) | |
872 { | |
873 uint32_t lbnum, MVDS_location, MVDS_length; | |
874 struct avdp_t avdp; | |
875 uint16_t TagID; | |
876 uint32_t lastsector; | |
877 int i, terminate; | |
878 int desc_found = 0; | |
879 /* Find Anchor */ | |
880 lastsector = 0; | |
881 lbnum = 256; /* Try #1, prime anchor */ | |
882 terminate = 0; | |
883 if(bufsize < DVD_VIDEO_LB_LEN) { | |
884 return 0; | |
885 } | |
886 | |
887 if(!UDFGetAVDP(device, &avdp)) { | |
888 return 0; | |
889 } | |
890 | |
891 /* Main volume descriptor */ | |
892 MVDS_location = avdp.mvds.location; | |
893 MVDS_length = avdp.mvds.length; | |
894 | |
895 i = 1; | |
896 do { | |
897 /* Find Descriptor */ | |
898 lbnum = MVDS_location; | |
899 do { | |
900 | |
901 if( DVDReadLBUDF( device, lbnum++, 1, descriptor, 0 ) <= 0 ) { | |
902 TagID = 0; | |
903 } else { | |
904 UDFDescriptor( descriptor, &TagID ); | |
905 } | |
906 | |
907 if( (TagID == id) && ( !desc_found ) ) { | |
908 /* Descriptor */ | |
909 desc_found = 1; | |
910 } | |
911 } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 ) | |
912 / DVD_VIDEO_LB_LEN ) && ( TagID != 8 ) | |
913 && ( !desc_found) ); | |
914 | |
915 if( !desc_found ) { | |
916 /* Backup volume descriptor */ | |
917 MVDS_location = avdp.rvds.location; | |
918 MVDS_length = avdp.rvds.length; | |
919 } | |
920 } while( i-- && ( !desc_found ) ); | |
921 | |
922 return desc_found; | |
923 } | |
924 | |
925 | |
926 static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd) | |
927 { | |
928 uint8_t pvd_buf[DVD_VIDEO_LB_LEN]; | |
929 | |
15874 | 930 if(GetUDFCache(device, PVDCache, 0, pvd)) { |
931 return 1; | |
932 } | |
933 | |
10723 | 934 if(!UDFGetDescriptor( device, 1, pvd_buf, sizeof(pvd_buf))) { |
935 return 0; | |
936 } | |
937 | |
938 memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32); | |
939 memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128); | |
15874 | 940 SetUDFCache(device, PVDCache, 0, pvd); |
10723 | 941 |
942 return 1; | |
943 } | |
15874 | 944 |
945 /** | |
946 * Gets the Volume Identifier string, in 8bit unicode (latin-1) | |
947 * volid, place to put the string | |
948 * volid_size, size of the buffer volid points to | |
949 * returns the size of buffer needed for all data | |
950 */ | |
951 int UDFGetVolumeIdentifier(dvd_reader_t *device, char *volid, | |
952 unsigned int volid_size) | |
953 { | |
954 struct pvd_t pvd; | |
955 unsigned int volid_len; | |
956 | |
957 /* get primary volume descriptor */ | |
958 if(!UDFGetPVD(device, &pvd)) { | |
959 return 0; | |
960 } | |
961 | |
962 volid_len = pvd.VolumeIdentifier[31]; | |
963 if(volid_len > 31) { | |
964 /* this field is only 32 bytes something is wrong */ | |
965 volid_len = 31; | |
966 } | |
967 if(volid_size > volid_len) { | |
968 volid_size = volid_len; | |
969 } | |
970 Unicodedecode(pvd.VolumeIdentifier, volid_size, volid); | |
971 | |
972 return volid_len; | |
973 } | |
974 | |
975 /** | |
976 * Gets the Volume Set Identifier, as a 128-byte dstring (not decoded) | |
977 * WARNING This is not a null terminated string | |
978 * volsetid, place to put the data | |
979 * volsetid_size, size of the buffer volsetid points to | |
980 * the buffer should be >=128 bytes to store the whole volumesetidentifier | |
981 * returns the size of the available volsetid information (128) | |
982 * or 0 on error | |
983 */ | |
984 int UDFGetVolumeSetIdentifier(dvd_reader_t *device, uint8_t *volsetid, | |
985 unsigned int volsetid_size) | |
986 { | |
987 struct pvd_t pvd; | |
988 | |
989 /* get primary volume descriptor */ | |
990 if(!UDFGetPVD(device, &pvd)) { | |
991 return 0; | |
992 } | |
993 | |
994 | |
995 if(volsetid_size > 128) { | |
996 volsetid_size = 128; | |
997 } | |
998 | |
999 memcpy(volsetid, pvd.VolumeSetIdentifier, volsetid_size); | |
1000 | |
1001 return 128; | |
1002 } |