1 /*
2 * dvdbackup - tool to rip DVDs from the command line
3 *
4 * Copyright (C) 2002 Olaf Beck <olaf_sc@yahoo.com>
5 * Copyright (C) 2008-2012 Benjamin Drung <benjamin.drung@gmail.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22 #include "dvdbackup.h"
23
24 /* internationalisation */
25 #include "gettext.h"
26 #define _(String) gettext(String)
27
28 /* C standard libraries */
29 #include <ctype.h>
30 #include <limits.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 /* C POSIX library */
36 #include <fcntl.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39
40 /* libdvdread */
41 #include <dvdread/dvd_reader.h>
42 #include <dvdread/ifo_read.h>
43
44
45 #define MAXNAME 256
46
47 /**
48 * Buffer size in DVD logical blocks (2 KiB).
49 * Currently set to 1 MiB.
50 */
51 #define BUFFER_SIZE 512
52
53 /**
54 * The maximum size of a VOB file is 1 GiB or 524288 in Video DVD logical block
55 * respectively.
56 */
57 #define MAX_VOB_SIZE 524288
58
59 #define DVD_SEC_SIZ 2048
60
61 /* Flag for verbose mode */
62 int verbose = 0;
63 int aspect;
64 int progress = 0;
65 char progressText[MAXNAME] = "n/a";
66
67 /* Structs to keep title set information in */
68
69 typedef struct {
70 off_t size_ifo;
71 off_t size_menu;
72 int number_of_vob_files;
73 off_t size_vob[10];
74 } title_set_t;
75
76 typedef struct {
77 int number_of_title_sets;
78 title_set_t* title_set;
79 } title_set_info_t;
80
81
82 typedef struct {
83 int title;
84 int title_set;
85 int vts_title;
86 int chapters;
87 int aspect_ratio;
88 int angles;
89 int audio_tracks;
90 int audio_channels;
91 int sub_pictures;
92 } titles_t;
93
94 typedef struct {
95 int main_title_set;
96 int number_of_titles;
97 titles_t* titles;
98 } titles_info_t;
99
100
101 static void bsort_max_to_min(int sector[], int title[], int size);
102
103
CheckSizeArray(const int size_array[],int reference,int target)104 static int CheckSizeArray(const int size_array[], int reference, int target) {
105 if(size_array[target] && (size_array[reference]/size_array[target] == 1) &&
106 ((size_array[reference] * 2 - size_array[target])/ size_array[target] == 1) &&
107 ((size_array[reference]%size_array[target] * 3) < size_array[reference]) ) {
108 /* We have a dual DVD with two feature films - now let's see if they have the same amount of chapters*/
109 return(1);
110 } else {
111 return(0);
112 }
113 }
114
115
CheckAudioSubChannels(int audio_audio_array[],int title_set_audio_array[],int subpicture_sub_array[],int title_set_sub_array[],int channels_channel_array[],int title_set_channel_array[],int reference,int candidate,int title_sets)116 static int CheckAudioSubChannels(int audio_audio_array[], int title_set_audio_array[],
117 int subpicture_sub_array[], int title_set_sub_array[],
118 int channels_channel_array[],int title_set_channel_array[],
119 int reference, int candidate, int title_sets) {
120
121 int temp, i, found_audio, found_sub, found_channels;
122
123 found_audio=0;
124 temp = audio_audio_array[reference];
125 for (i=0 ; i < title_sets ; i++ ) {
126 if ( audio_audio_array[i] < temp ) {
127 break;
128 }
129 if ( candidate == title_set_audio_array[i] ) {
130 found_audio=1;
131 break;
132 }
133
134 }
135
136 found_sub=0;
137 temp = subpicture_sub_array[reference];
138 for (i=0 ; i < title_sets ; i++ ) {
139 if ( subpicture_sub_array[i] < temp ) {
140 break;
141 }
142 if ( candidate == title_set_sub_array[i] ) {
143 found_sub=1;
144 break;
145 }
146
147 }
148
149
150 found_channels=0;
151 temp = channels_channel_array[reference];
152 for (i=0 ; i < title_sets ; i++ ) {
153 if ( channels_channel_array[i] < temp ) {
154 break;
155 }
156 if ( candidate == title_set_channel_array[i] ) {
157 found_channels=1;
158 break;
159 }
160
161 }
162
163
164 return(found_audio + found_sub + found_channels);
165 }
166
167
168
169
DVDWriteCells(dvd_reader_t * dvd,int cell_start_sector[],int cell_end_sector[],int length,int titles,title_set_info_t * title_set_info,titles_info_t * titles_info,char * targetdir,char * title_name)170 static int DVDWriteCells(dvd_reader_t * dvd, int cell_start_sector[],
171 int cell_end_sector[], int length, int titles,
172 title_set_info_t * title_set_info, titles_info_t * titles_info,
173 char * targetdir,char * title_name) {
174
175 /* Loop variables */
176 int i;
177
178 /* Vob control */
179 int vob = 1;
180
181 /* Temp filename,dirname */
182 char targetname[PATH_MAX];
183
184 /* Write buffer */
185
186 unsigned char * buffer=NULL;
187
188 /* File Handler */
189 int streamout;
190
191 int size;
192 int left;
193
194 int to_read;
195 int have_read;
196
197 /* Offsets */
198 int soffset;
199
200
201 /* DVD handler */
202 dvd_file_t* dvd_file = NULL;
203
204 int title_set;
205
206 #ifdef DEBUG
207 int number_of_vob_files;
208
209 fprintf(stderr,"DVDWriteCells: length is %d\n", length);
210 #endif
211
212
213 title_set = titles_info->titles[titles - 1].title_set;
214 #ifdef DEBUG
215 number_of_vob_files = title_set_info->title_set[title_set].number_of_vob_files;
216 fprintf(stderr,"DVDWriteCells: title set is %d\n", title_set);
217 fprintf(stderr,"DVDWriteCells: vob files are %d\n", number_of_vob_files);
218 #endif
219
220 /* Remove all old files silently if they exists */
221
222 for ( i = 0 ; i < 10 ; i++ ) {
223 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, i + 1);
224 #ifdef DEBUG
225 fprintf(stderr,"DVDWriteCells: file is %s\n", targetname);
226 #endif
227 unlink( targetname);
228 }
229
230
231 #ifdef DEBUG
232 for (i = 0; i < number_of_vob_files ; i++) {
233 fprintf(stderr,"vob %i size: %lld\n", i + 1, title_set_info->title_set[title_set].size_vob[i]);
234 }
235 #endif
236
237 /* Create VTS_XX_X.VOB */
238 if (title_set == 0) {
239 fprintf(stderr,_("Do not try to copy chapters from the VMG domain; there are none.\n"));
240 return(1);
241 } else {
242 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
243 }
244
245 #ifdef DEBUG
246 fprintf(stderr,"DVDWriteCells: 1\n");
247 #endif
248
249 if ((buffer = (unsigned char *)malloc(BUFFER_SIZE * DVD_VIDEO_LB_LEN * sizeof(unsigned char))) == NULL) {
250 fprintf(stderr, _("Out of memory copying %s\n"), targetname);
251 return(1);
252 }
253
254 #ifdef DEBUG
255 fprintf(stderr,"DVDWriteCells: 2\n");
256 #endif
257
258
259 if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1) {
260 fprintf(stderr, _("Error creating %s\n"), targetname);
261 perror(PACKAGE);
262 return(1);
263 }
264
265 #ifdef DEBUG
266 fprintf(stderr,"DVDWriteCells: 3\n");
267 #endif
268
269
270 if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
271 fprintf(stderr, _("Failed opening TITLE VOB\n"));
272 free(buffer);
273 close(streamout);
274 return(1);
275 }
276
277 size = 0;
278
279 for (i=0; i<length; i++) {
280 left = cell_end_sector[i] - cell_start_sector[i];
281 soffset = cell_start_sector[i];
282
283 while(left > 0) {
284 to_read = left;
285 if (to_read + size > MAX_VOB_SIZE) {
286 to_read = MAX_VOB_SIZE - size;
287 }
288 if (to_read > BUFFER_SIZE) {
289 to_read = BUFFER_SIZE;
290 }
291
292 if ((have_read = DVDReadBlocks(dvd_file,soffset, to_read, buffer)) < 0) {
293 fprintf(stderr, _("Error reading MENU VOB: %d != %d\n"), have_read, to_read);
294 free(buffer);
295 DVDCloseFile(dvd_file);
296 close(streamout);
297 return(1);
298 }
299 if (have_read < to_read) {
300 fprintf(stderr, _("DVDReadBlocks read %d blocks of %d blocks\n"), have_read, to_read);
301 }
302 if (write(streamout, buffer, have_read * DVD_VIDEO_LB_LEN) != have_read * DVD_VIDEO_LB_LEN) {
303 fprintf(stderr, _("Error writing TITLE VOB\n"));
304 free(buffer);
305 close(streamout);
306 return(1);
307 }
308 #ifdef DEBUG
309 fprintf(stderr,"Current soffset changed from %i to ",soffset);
310 #endif
311 soffset = soffset + have_read;
312 #ifdef DEBUG
313 fprintf(stderr,"%i\n",soffset);
314 #endif
315 left = left - have_read;
316 size = size + have_read;
317 if ((size >= MAX_VOB_SIZE) && (left > 0)) {
318 #ifdef DEBUG
319 fprintf(stderr,"size: %i, MAX_VOB_SIZE: %i\n ",size, MAX_VOB_SIZE);
320 #endif
321 close(streamout);
322 vob = vob + 1;
323 size = 0;
324 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
325 if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0666)) == -1) {
326 fprintf(stderr, _("Error creating %s\n"), targetname);
327 perror(PACKAGE);
328 return(1);
329 }
330 }
331 }
332 }
333
334 DVDCloseFile(dvd_file);
335 free(buffer);
336 close(streamout);
337
338 return(0);
339 }
340
341
342
FreeSortArrays(int chapter_chapter_array[],int title_set_chapter_array[],int angle_angle_array[],int title_set_angle_array[],int subpicture_sub_array[],int title_set_sub_array[],int audio_audio_array[],int title_set_audio_array[],int size_size_array[],int title_set_size_array[],int channels_channel_array[],int title_set_channel_array[])343 static void FreeSortArrays( int chapter_chapter_array[], int title_set_chapter_array[],
344 int angle_angle_array[], int title_set_angle_array[],
345 int subpicture_sub_array[], int title_set_sub_array[],
346 int audio_audio_array[], int title_set_audio_array[],
347 int size_size_array[], int title_set_size_array[],
348 int channels_channel_array[], int title_set_channel_array[]) {
349
350
351 free(chapter_chapter_array);
352 free(title_set_chapter_array);
353
354 free(angle_angle_array);
355 free(title_set_angle_array);
356
357 free(subpicture_sub_array);
358 free(title_set_sub_array);
359
360 free(audio_audio_array);
361 free(title_set_audio_array);
362
363 free(size_size_array);
364 free(title_set_size_array);
365
366 free(channels_channel_array);
367 free(title_set_channel_array);
368 }
369
370
DVDGetInfo(dvd_reader_t * _dvd)371 static titles_info_t * DVDGetInfo(dvd_reader_t * _dvd) {
372
373 /* title interation */
374 int counter, i, f;
375
376 /* Our guess */
377 int candidate;
378 int multi = 0;
379 int dual = 0;
380
381
382 int titles;
383 int title_sets;
384
385 /* Arrays for chapter, angle, subpicture, audio, size, aspect, channels - file_set relationship */
386
387 /* Size == number_of_titles */
388 int * chapter_chapter_array;
389 int * title_set_chapter_array;
390
391 int * angle_angle_array;
392 int * title_set_angle_array;
393
394 /* Size == number_of_title_sets */
395
396 int * subpicture_sub_array;
397 int * title_set_sub_array;
398
399 int * audio_audio_array;
400 int * title_set_audio_array;
401
402 int * size_size_array;
403 int * title_set_size_array;
404
405 int * channels_channel_array;
406 int * title_set_channel_array;
407
408 /* Temp helpers */
409 int channels;
410 int found;
411 int chapters_1;
412 int chapters_2;
413 int found_chapter;
414 int number_of_multi;
415
416
417 /* DVD handlers */
418 ifo_handle_t* vmg_ifo = NULL;
419 dvd_file_t* vts_title_file = NULL;
420
421 titles_info_t* titles_info = NULL;
422
423 /* Open main info file */
424 vmg_ifo = ifoOpen( _dvd, 0 );
425 if(!vmg_ifo) {
426 fprintf( stderr, _("Cannot open VMG info.\n"));
427 return (0);
428 }
429
430 titles = vmg_ifo->tt_srpt->nr_of_srpts;
431 title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;
432
433 if ((vmg_ifo->tt_srpt == 0) || (vmg_ifo->vts_atrt == 0)) {
434 ifoClose(vmg_ifo);
435 return(0);
436 }
437
438
439 if((titles_info = (titles_info_t *)malloc(sizeof(titles_info_t))) == NULL) {
440 fprintf(stderr, _("Out of memory creating titles info structure\n"));
441 return NULL;
442 }
443
444 titles_info->titles = (titles_t *)malloc((titles)* sizeof(titles_t));
445 titles_info->number_of_titles = titles;
446
447
448 chapter_chapter_array = malloc(titles * sizeof(int));
449 title_set_chapter_array = malloc(titles * sizeof(int));
450
451 /*currently not used in the guessing */
452 angle_angle_array = malloc(titles * sizeof(int));
453 title_set_angle_array = malloc(titles * sizeof(int));
454
455
456 subpicture_sub_array = malloc(title_sets * sizeof(int));
457 title_set_sub_array = malloc(title_sets * sizeof(int));
458
459 audio_audio_array = malloc(title_sets * sizeof(int));
460 title_set_audio_array = malloc(title_sets * sizeof(int));
461
462 size_size_array = malloc(title_sets * sizeof(int));
463 title_set_size_array = malloc(title_sets * sizeof(int));
464
465 channels_channel_array = malloc(title_sets * sizeof(int));
466 title_set_channel_array = malloc(title_sets * sizeof(int));
467
468 /* Check mallocs */
469 if(!titles_info->titles || !chapter_chapter_array || !title_set_chapter_array ||
470 !angle_angle_array || !title_set_angle_array || !subpicture_sub_array ||
471 !title_set_sub_array || !audio_audio_array || !title_set_audio_array ||
472 !size_size_array || !title_set_size_array || !channels_channel_array ||
473 !title_set_channel_array) {
474 fprintf(stderr, _("Out of memory creating arrays for titles info\n"));
475 free(titles_info);
476 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
477 angle_angle_array, title_set_angle_array,
478 subpicture_sub_array, title_set_sub_array,
479 audio_audio_array, title_set_audio_array,
480 size_size_array, title_set_size_array,
481 channels_channel_array, title_set_channel_array);
482 return NULL;
483 }
484
485 /* Interate over the titles nr_of_srpts */
486 for(counter = 0; counter < titles; counter++) {
487 /* For titles_info */
488 titles_info->titles[counter].title = counter + 1;
489 titles_info->titles[counter].title_set = vmg_ifo->tt_srpt->title[counter].title_set_nr;
490 titles_info->titles[counter].vts_title = vmg_ifo->tt_srpt->title[counter].vts_ttn;
491 titles_info->titles[counter].chapters = vmg_ifo->tt_srpt->title[counter].nr_of_ptts;
492 titles_info->titles[counter].angles = vmg_ifo->tt_srpt->title[counter].nr_of_angles;
493
494 /* For main title*/
495 chapter_chapter_array[counter] = vmg_ifo->tt_srpt->title[counter].nr_of_ptts;
496 title_set_chapter_array[counter] = vmg_ifo->tt_srpt->title[counter].title_set_nr;
497 angle_angle_array[counter] = vmg_ifo->tt_srpt->title[counter].nr_of_angles;
498 title_set_angle_array[counter] = vmg_ifo->tt_srpt->title[counter].title_set_nr;
499 }
500
501 /* Interate over vmg_nr_of_title_sets */
502
503 for(counter = 0; counter < title_sets; counter++) {
504
505 /* Picture*/
506 subpicture_sub_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_subp_streams;
507 title_set_sub_array[counter] = counter + 1;
508
509
510 /* Audio */
511 audio_audio_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_audio_streams;
512 title_set_audio_array[counter] = counter + 1;
513
514 channels=0;
515 for(i = 0; i < audio_audio_array[counter]; i++) {
516 if ( channels < vmg_ifo->vts_atrt->vts[counter].vtstt_audio_attr[i].channels + 1) {
517 channels = vmg_ifo->vts_atrt->vts[counter].vtstt_audio_attr[i].channels + 1;
518 }
519
520 }
521 channels_channel_array[counter] = channels;
522 title_set_channel_array[counter] = counter + 1;
523
524 /* For titles_info */
525 for (f=0; f < titles_info->number_of_titles ; f++ ) {
526 if ( titles_info->titles[f].title_set == counter + 1 ) {
527 titles_info->titles[f].aspect_ratio = vmg_ifo->vts_atrt->vts[counter].vtstt_vobs_video_attr.display_aspect_ratio;
528 titles_info->titles[f].sub_pictures = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_subp_streams;
529 titles_info->titles[f].audio_tracks = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_audio_streams;
530 titles_info->titles[f].audio_channels = channels;
531 }
532 }
533
534 }
535
536
537
538
539 for (counter=0; counter < title_sets; counter++ ) {
540
541 vts_title_file = DVDOpenFile(_dvd, counter + 1, DVD_READ_TITLE_VOBS);
542
543 if(vts_title_file != 0) {
544 size_size_array[counter] = DVDFileSize(vts_title_file);
545 DVDCloseFile(vts_title_file);
546 } else {
547 size_size_array[counter] = 0;
548 }
549
550 title_set_size_array[counter] = counter + 1;
551
552
553 }
554
555
556 /* Sort all arrays max to min */
557
558 bsort_max_to_min(chapter_chapter_array, title_set_chapter_array, titles);
559 bsort_max_to_min(angle_angle_array, title_set_angle_array, titles);
560 bsort_max_to_min(subpicture_sub_array, title_set_sub_array, title_sets);
561 bsort_max_to_min(audio_audio_array, title_set_audio_array, title_sets);
562 bsort_max_to_min(size_size_array, title_set_size_array, title_sets);
563 bsort_max_to_min(channels_channel_array, title_set_channel_array, title_sets);
564
565
566 /* Check if the second biggest one actually can be a feature title */
567 /* Here we will take do biggest/second and if that is bigger than one it's not a feauture title */
568 /* Now this is simply not enough since we have to check that the diff between the two of them is small enough
569 to consider the second one a feature title we are doing two checks (biggest + biggest - second) /second == 1
570 and biggest%second * 3 < biggest */
571
572 if ( title_sets > 1 && CheckSizeArray(size_size_array, 0, 1) == 1 ) {
573 /* We have a dual DVD with two feature films - now let's see if they have the same amount of chapters*/
574
575 chapters_1 = 0;
576 for (i=0 ; i < titles ; i++ ) {
577 if (titles_info->titles[i].title_set == title_set_size_array[0] ) {
578 if ( chapters_1 < titles_info->titles[i].chapters){
579 chapters_1 = titles_info->titles[i].chapters;
580 }
581 }
582 }
583
584 chapters_2 = 0;
585 for (i=0 ; i < titles ; i++ ) {
586 if (titles_info->titles[i].title_set == title_set_size_array[1] ) {
587 if ( chapters_2 < titles_info->titles[i].chapters){
588 chapters_2 = titles_info->titles[i].chapters;
589 }
590 }
591 }
592
593 if(vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio ==
594 vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio) {
595 /* In this case it's most likely so that we have a dual film but with different context
596 They are with in the same size range and have the same aspect ratio
597 I would guess that such a case is e.g. a DVD containing several episodes of a TV serie*/
598 candidate = title_set_size_array[0];
599 multi = 1;
600 } else if ( chapters_1 == chapters_2 && vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio !=
601 vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio){
602 /* In this case we have (guess only) the same context - they have the same number of chapters but different aspect ratio and are in the same size range*/
603 if ( vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio == aspect) {
604 candidate = title_set_size_array[0];
605 } else if ( vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio == aspect) {
606 candidate = title_set_size_array[1];
607 } else {
608 /* Okay we didn't have the prefered aspect ratio - just make the biggest one a candidate */
609 /* please send report if this happens*/
610 fprintf(stderr, _("You have encountered a very special DVD; please send a bug report along with all IFO files from this title\n"));
611 candidate = title_set_size_array[0];
612 }
613 dual = 1;
614 } else {
615 /* Can this case ever happen? */
616 candidate = title_set_size_array[0];
617 }
618 } else {
619 candidate = title_set_size_array[0];
620 }
621
622
623 /* Lets start checking audio,sub pictures and channels my guess is namly that a special suburb will put titles with a lot of
624 chapters just to make our backup hard */
625
626
627 found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
628 subpicture_sub_array, title_set_sub_array,
629 channels_channel_array, title_set_channel_array,
630 0 , candidate, title_sets);
631
632
633 /* Now let's see if we can find our candidate among the top most chapters */
634 found_chapter=6;
635 for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
636 if ( candidate == title_set_chapter_array[i] ) {
637 found_chapter=i+1;
638 break;
639 }
640 }
641
642 /* Close the VMG ifo file we got all the info we need */
643 ifoClose(vmg_ifo);
644
645
646 if (((found == 3) && (found_chapter == 1) && (dual == 0) && (multi == 0)) || ((found == 3) && (found_chapter < 3 ) && (dual == 1))) {
647
648 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
649 angle_angle_array, title_set_angle_array,
650 subpicture_sub_array, title_set_sub_array,
651 audio_audio_array, title_set_audio_array,
652 size_size_array, title_set_size_array,
653 channels_channel_array, title_set_channel_array);
654 titles_info->main_title_set = candidate;
655 return(titles_info);
656
657 }
658
659 if (multi == 1) {
660 for (i=0 ; i < title_sets ; ++i) {
661 if (CheckSizeArray(size_size_array, 0, i + 1) == 0) {
662 break;
663 }
664 }
665 number_of_multi = i;
666 for (i = 0; i < number_of_multi; i++ ) {
667 if (title_set_chapter_array[0] == i + 1) {
668 candidate = title_set_chapter_array[0];
669 }
670 }
671
672 found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
673 subpicture_sub_array, title_set_sub_array,
674 channels_channel_array, title_set_channel_array,
675 0 , candidate, title_sets);
676
677 if (found == 3) {
678 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
679 angle_angle_array, title_set_angle_array,
680 subpicture_sub_array, title_set_sub_array,
681 audio_audio_array, title_set_audio_array,
682 size_size_array, title_set_size_array,
683 channels_channel_array, title_set_channel_array);
684 titles_info->main_title_set = candidate;
685 return(titles_info);
686 }
687 }
688
689 /* We have now come to that state that we more or less have given up :( giving you a good guess of the main feature film*/
690 /*No matter what we will more or less only return the biggest VOB*/
691 /* Lets see if we can find our biggest one - then we return that one */
692 candidate = title_set_size_array[0];
693
694 found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
695 subpicture_sub_array, title_set_sub_array,
696 channels_channel_array, title_set_channel_array,
697 0 , candidate, title_sets);
698
699 /* Now let's see if we can find our candidate among the top most chapters */
700
701 found_chapter=5;
702 for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
703 if ( candidate == title_set_chapter_array[i] ) {
704 found_chapter=i+1;
705 break;
706 }
707
708 }
709
710 /* Here we take chapters in to consideration*/
711 if (found == 3) {
712 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
713 angle_angle_array, title_set_angle_array,
714 subpicture_sub_array, title_set_sub_array,
715 audio_audio_array, title_set_audio_array,
716 size_size_array, title_set_size_array,
717 channels_channel_array, title_set_channel_array);
718 titles_info->main_title_set = candidate;
719 return(titles_info);
720 }
721
722 /* Here we do but we lower the treshold for audio, sub and channels */
723
724 if ((found > 1 ) && (found_chapter <= 4)) {
725 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
726 angle_angle_array, title_set_angle_array,
727 subpicture_sub_array, title_set_sub_array,
728 audio_audio_array, title_set_audio_array,
729 size_size_array, title_set_size_array,
730 channels_channel_array, title_set_channel_array);
731 titles_info->main_title_set = candidate;
732 return(titles_info);
733
734 /* return it */
735 } else {
736 /* Here we give up and just return the biggest one :(*/
737 /* Just return the biggest badest one*/
738 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
739 angle_angle_array, title_set_angle_array,
740 subpicture_sub_array, title_set_sub_array,
741 audio_audio_array, title_set_audio_array,
742 size_size_array, title_set_size_array,
743 channels_channel_array, title_set_channel_array);
744 titles_info->main_title_set = candidate;
745 return(titles_info);
746 }
747
748
749 /* Some radom thoughts about DVD guessing */
750 /* We will now gather as much data about the DVD-Video as we can and
751 then make a educated guess which one is the main feature film of it*/
752
753
754 /* Make a tripple array with chapters, angles and title sets
755 - sort out dual title sets with a low number of chapters. Tradtionaly
756 the title set with most chapters is the main film. Number of angles is
757 keept as a reference point of low value*/
758
759 /* Make a dual array with number of audio streams, sub picture streams
760 and title sets. Tradtionaly the main film has many audio streams
761 since it's supposed be synchronised e.g. a English film synchronised/dubbed
762 in German. We are also keeping track of sub titles since it's also indication
763 of the main film*/
764
765 /* Which title set is the biggest one - dual array with title sets and size
766 The biggest one is usally the main film*/
767
768 /* Which title set is belonging to title 1 and how many chapters has it. Once
769 again tradtionaly title one is belonging to the main film*/
770
771 /* Yes a lot of rant - but it helps me think - some sketch on paper or in the mind
772 I sketch in the comments - beside it will help you understand the code*/
773
774 /* Okay let's see if the biggest one has most chapters, it also has more subtitles
775 and audio tracks than the second one and it's title one.
776 Done it must be the main film
777
778 Hmm the biggest one doesn't have the most chapters?
779
780 See if the second one has the same amount of chapters and is the biggest one
781 If so we probably have a 4:3 and 16:9 versions of film on the same disk
782
783 Now we fetch the 16:9 by default unless the forced to do 4:3
784 First check which one is which.
785 If the 16:9 is the biggest one and has the same or more subtitle, audio streams
786 then we are happy unless we are in force 4:3 mode :(
787 The same goes in reverse if we are in force 4:3 mode
788
789
790 Hmm, in force 4:3 mode - now we check how much smaller than the biggest one it is
791 (or the reverse if we are in 16:9 mode)
792
793 Generally a reverse division should render in 1 and with a small modulo - like wise
794 a normal modulo should give us a high modulo
795
796 If we get more than one it's of cource a fake however if we get just one we still need to check
797 if we subtract the smaller one from the bigger one we should end up with a small number - hence we
798 need to multiply it more than 4 times to get it bigger than the biggest one. Now we know that the
799 two biggest once are really big and possibly carry the same film in differnet formats.
800
801 We will now return the prefered one either 16:9 or 4:3 but we will first check that the one
802 we return at lest has two or more audio tracks. We don't want it if the other one has a lot
803 more sound (we may end up with a film that only has 2ch Dolby Digital so we want to check for
804 6ch DTS or Dolby Digital. If the prefered one doesn't have those features but the other once has
805 we will return the other one.
806 */
807
808 }
809
810
DVDCopyBlocks(dvd_file_t * dvd_file,int destination,int offset,int size,char * filename,read_error_strategy_t errorstrat)811 static int DVDCopyBlocks(dvd_file_t* dvd_file, int destination, int offset, int size, char* filename, read_error_strategy_t errorstrat) {
812 int i;
813
814 /* all sizes are in DVD logical blocks */
815 int remaining = size;
816 int total = size; // total size in blocks
817 float totalMiB = (float)(total) / 512.0f; // total size in [MiB]
818 int to_read = BUFFER_SIZE;
819 int act_read; /* number of buffers actually read */
820
821 /* Write buffer */
822 unsigned char buffer[BUFFER_SIZE * DVD_VIDEO_LB_LEN];
823 unsigned char buffer_zero[BUFFER_SIZE * DVD_VIDEO_LB_LEN];
824
825 for(i = 0; i < BUFFER_SIZE * DVD_VIDEO_LB_LEN; i++) {
826 buffer_zero[i] = '\0';
827 }
828
829 while( remaining > 0 ) {
830
831 if (to_read > remaining) {
832 to_read = remaining;
833 }
834
835 /* Reading blocks */
836 act_read = DVDReadBlocks(dvd_file, offset, to_read, buffer);
837
838 if(act_read != to_read) {
839 if(progress) {
840 fprintf(stdout, "\n");
841 }
842 if(act_read >= 0) {
843 fprintf(stderr, _("Error reading %s at block %d\n"), filename, offset+act_read);
844 } else {
845 fprintf(stderr, _("Error reading %s at block %d, read error returned\n"), filename, offset);
846 }
847 }
848
849 if(act_read > 0) {
850 /* Writing blocks */
851 if(write(destination, buffer, act_read * DVD_VIDEO_LB_LEN) != act_read * DVD_VIDEO_LB_LEN) {
852 if(progress) {
853 fprintf(stdout, "\n");
854 }
855 fprintf(stderr, _("Error writing %s.\n"), filename);
856 return(1);
857 }
858
859 offset += act_read;
860 remaining -= act_read;
861 }
862
863 if(act_read != to_read) {
864 int numBlanks = 0;
865
866 if(progress) {
867 fprintf(stdout, "\n");
868 }
869
870 if (act_read < 0) {
871 act_read = 0;
872 }
873
874 switch (errorstrat) {
875 case STRATEGY_ABORT:
876 fprintf(stderr, _("aborting\n"));
877 return 1;
878
879 case STRATEGY_SKIP_BLOCK:
880 numBlanks = 1;
881 fprintf(stderr, _("padding single block\n"));
882 break;
883
884 case STRATEGY_SKIP_MULTIBLOCK:
885 numBlanks = to_read - act_read;
886 fprintf(stderr, _("padding %d blocks\n"), numBlanks);
887 break;
888 }
889
890 if (write(destination, buffer_zero, numBlanks * DVD_VIDEO_LB_LEN) != numBlanks * DVD_VIDEO_LB_LEN) {
891 fprintf(stderr, _("Error writing %s (padding)\n"), filename);
892 return 1;
893 }
894
895 /* pretend we read what we padded */
896 offset += numBlanks;
897 remaining -= numBlanks;
898 }
899
900 if(progress) {
901 int done = total - remaining; // blocks done
902 if(remaining < BUFFER_SIZE || (done % BUFFER_SIZE) == 0) { // don't print too often
903 float doneMiB = (float)(done) / 512.0f; // [MiB] done
904 fprintf(stdout, "\r");
905 fprintf(stdout, _("Copying %s: %.0f%% done (%.0f/%.0f MiB)"),
906 progressText, doneMiB / totalMiB * 100.0f, doneMiB, totalMiB);
907 fflush(stdout);
908 }
909 }
910
911 }
912
913 if(progress) {
914 fprintf(stdout, "\n");
915 }
916
917 return 0;
918 }
919
920
921
DVDCopyTitleVobX(dvd_reader_t * dvd,title_set_info_t * title_set_info,int title_set,int vob,char * targetdir,char * title_name,read_error_strategy_t errorstrat)922 static int DVDCopyTitleVobX(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, int vob, char * targetdir,char * title_name, read_error_strategy_t errorstrat) {
923
924 /* Loop variable */
925 int i;
926
927 /* Temp filename,dirname */
928 char filename[PATH_MAX] = "VIDEO_TS.VOB";
929 char targetname[PATH_MAX];
930 struct stat fileinfo;
931
932 /* File Handler */
933 int streamout;
934
935 int size;
936
937 int offset = 0;
938 int tsize;
939
940 /* DVD handler */
941 dvd_file_t* dvd_file=NULL;
942
943 /* Return value */
944 int result;
945
946 /* create filename VIDEO_TS.VOB or VTS_XX_X.VOB */
947 if(title_set > 0) {
948 sprintf(filename, "VTS_%02i_%i.VOB", title_set, vob);
949 }
950
951 if (title_set_info->number_of_title_sets + 1 < title_set) {
952 fprintf(stderr,_("Failed num title test\n"));
953 return(1);
954 }
955
956 if (title_set_info->title_set[title_set].number_of_vob_files < vob ) {
957 fprintf(stderr,_("Failed vob test\n"));
958 return(1);
959 }
960
961 if (title_set_info->title_set[title_set].size_vob[0] == 0 ) {
962 fprintf(stderr,_("Failed vob 1 size test\n"));
963 return(0);
964 } else if (title_set_info->title_set[title_set].size_vob[vob - 1] == 0 ) {
965 fprintf(stderr,_("Failed vob %d test\n"), vob);
966 return(0);
967 } else {
968 size = title_set_info->title_set[title_set].size_vob[vob - 1]/DVD_VIDEO_LB_LEN;
969 if (title_set_info->title_set[title_set].size_vob[vob - 1]%DVD_VIDEO_LB_LEN != 0) {
970 fprintf(stderr, _("The Title VOB number %d of title set %d does not have a valid DVD size\n"), vob, title_set);
971 return(1);
972 }
973 }
974 #ifdef DEBUG
975 fprintf(stderr,"After we check the vob it self %d\n", vob);
976 #endif
977
978 /* Create VTS_XX_X.VOB */
979 if (title_set == 0) {
980 fprintf(stderr,_("Do not try to copy a Title VOB from the VMG domain; there are none.\n"));
981 return(1);
982 } else {
983 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
984 }
985
986
987
988 /* Now figure out the offset we will start at also check that the previus files are of valid DVD size */
989 for ( i = 0; i < vob - 1; i++ ) {
990 tsize = title_set_info->title_set[title_set].size_vob[i];
991 if (tsize%DVD_VIDEO_LB_LEN != 0) {
992 fprintf(stderr, _("The Title VOB number %d of title set %d does not have a valid DVD size\n"), i + 1, title_set);
993 return(1);
994 } else {
995 offset = offset + tsize/DVD_VIDEO_LB_LEN;
996 }
997 }
998 #ifdef DEBUG
999 fprintf(stderr,"The offset for vob %d is %d\n", vob, offset);
1000 #endif
1001
1002
1003 if (stat(targetname, &fileinfo) == 0) {
1004 /* TRANSLATORS: The sentence starts with "The title file %s exists[...]" */
1005 fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("title file"), targetname);
1006 if (! S_ISREG(fileinfo.st_mode)) {
1007 /* TRANSLATORS: The sentence starts with "The title file %s is not valid[...]" */
1008 fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("title file"), targetname);
1009 return(1);
1010 } else {
1011 if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0666)) == -1) {
1012 fprintf(stderr, _("Error opening %s\n"), targetname);
1013 perror(PACKAGE);
1014 return(1);
1015 }
1016 }
1017 } else {
1018 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0666)) == -1) {
1019 fprintf(stderr, _("Error creating %s\n"), targetname);
1020 perror(PACKAGE);
1021 return(1);
1022 }
1023 }
1024
1025 if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
1026 fprintf(stderr, _("Failed opening TITLE VOB\n"));
1027 close(streamout);
1028 return(1);
1029 }
1030
1031 result = DVDCopyBlocks(dvd_file, streamout, offset, size, filename, errorstrat);
1032
1033 DVDCloseFile(dvd_file);
1034 close(streamout);
1035 return result;
1036 }
1037
1038
DVDCopyMenu(dvd_reader_t * dvd,title_set_info_t * title_set_info,int title_set,char * targetdir,char * title_name,read_error_strategy_t errorstrat)1039 static int DVDCopyMenu(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, char * targetdir,char * title_name, read_error_strategy_t errorstrat) {
1040
1041 /* Temp filename,dirname */
1042 char filename[PATH_MAX] = "VIDEO_TS.VOB";
1043 char targetname[PATH_MAX];
1044 struct stat fileinfo;
1045
1046 /* File Handler */
1047 int streamout;
1048
1049 int size;
1050
1051 /* return value */
1052 int result;
1053
1054 /* DVD handler */
1055 dvd_file_t* dvd_file = NULL;
1056
1057 /* create filename VIDEO_TS.VOB or VTS_XX_0.VOB */
1058 if(title_set > 0) {
1059 sprintf(filename, "VTS_%02i_0.VOB", title_set);
1060 }
1061
1062 if (title_set_info->number_of_title_sets + 1 < title_set) {
1063 return(1);
1064 }
1065
1066 if (title_set_info->title_set[title_set].size_menu == 0 ) {
1067 return(0);
1068 } else {
1069 size = title_set_info->title_set[title_set].size_menu/DVD_VIDEO_LB_LEN;
1070 if (title_set_info->title_set[title_set].size_menu%DVD_VIDEO_LB_LEN != 0) {
1071 fprintf(stderr, _("Warning: The Menu VOB of title set %d (%s) does not have a valid DVD size.\n"), title_set, filename);
1072 }
1073 }
1074
1075 if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_MENU_VOBS))== 0) {
1076 fprintf(stderr, _("Failed opening %s\n"), filename);
1077 return(1);
1078 }
1079
1080 /* Create VIDEO_TS.VOB or VTS_XX_0.VOB */
1081 sprintf(targetname,"%s/%s/VIDEO_TS/%s",targetdir, title_name, filename);
1082
1083 if (stat(targetname, &fileinfo) == 0) {
1084 /* TRANSLATORS: The sentence starts with "The menu file %s exists[...]" */
1085 fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("menu file"), targetname);
1086 if (! S_ISREG(fileinfo.st_mode)) {
1087 /* TRANSLATORS: The sentence starts with "The menu file %s is not valid[...]" */
1088 fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("menu file"), targetname);
1089 DVDCloseFile(dvd_file);
1090 return(1);
1091 } else {
1092 if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0666)) == -1) {
1093 fprintf(stderr, _("Error opening %s\n"), targetname);
1094 perror(PACKAGE);
1095 DVDCloseFile(dvd_file);
1096 return(1);
1097 }
1098 }
1099 } else {
1100 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0666)) == -1) {
1101 fprintf(stderr, _("Error creating %s\n"), targetname);
1102 perror(PACKAGE);
1103 DVDCloseFile(dvd_file);
1104 return(1);
1105 }
1106 }
1107
1108 if(progress) {
1109 strncpy(progressText, _("menu"), MAXNAME);
1110 }
1111
1112 result = DVDCopyBlocks(dvd_file, streamout, 0, size, filename, errorstrat);
1113
1114 DVDCloseFile(dvd_file);
1115 close(streamout);
1116 return result;
1117
1118 }
1119
1120
DVDCopyIfoBup(dvd_reader_t * dvd,title_set_info_t * title_set_info,int title_set,char * targetdir,char * title_name)1121 static int DVDCopyIfoBup(dvd_reader_t* dvd, title_set_info_t* title_set_info, int title_set, char* targetdir, char* title_name) {
1122 /* Temp filename, dirname */
1123 char targetname_ifo[PATH_MAX], targetname_bup[PATH_MAX];
1124 struct stat fileinfo;
1125
1126 /* Write buffer */
1127 unsigned char* buffer = NULL;
1128
1129 /* File Handler */
1130 int streamout_ifo = -1, streamout_bup = -1;
1131
1132 int size;
1133
1134 /* DVD handler */
1135 dvd_file_t* ifo_file = NULL;
1136
1137
1138 if (title_set_info->number_of_title_sets + 1 < title_set) {
1139 return(1);
1140 }
1141
1142 if (title_set_info->title_set[title_set].size_ifo == 0 ) {
1143 return(0);
1144 } else {
1145 if (title_set_info->title_set[title_set].size_ifo%DVD_VIDEO_LB_LEN != 0) {
1146 fprintf(stderr, _("The IFO of title set %d does not have a valid DVD size\n"), title_set);
1147 return(1);
1148 }
1149 }
1150
1151 /* Create VIDEO_TS.IFO or VTS_XX_0.IFO */
1152
1153 if (title_set == 0) {
1154 sprintf(targetname_ifo,"%s/%s/VIDEO_TS/VIDEO_TS.IFO",targetdir, title_name);
1155 sprintf(targetname_bup,"%s/%s/VIDEO_TS/VIDEO_TS.BUP",targetdir, title_name);
1156 } else {
1157 sprintf(targetname_ifo,"%s/%s/VIDEO_TS/VTS_%02i_0.IFO",targetdir, title_name, title_set);
1158 sprintf(targetname_bup,"%s/%s/VIDEO_TS/VTS_%02i_0.BUP",targetdir, title_name, title_set);
1159 }
1160
1161 if (stat(targetname_ifo, &fileinfo) == 0) {
1162 /* TRANSLATORS: The sentence starts with "The IFO file %s exists[...]" */
1163 fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("IFO file"), targetname_ifo);
1164 if (! S_ISREG(fileinfo.st_mode)) {
1165 /* TRANSLATORS: The sentence starts with "The IFO file %s is not valid[...]" */
1166 fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("IFO file"), targetname_ifo);
1167 return(1);
1168 }
1169 }
1170
1171 if (stat(targetname_bup, &fileinfo) == 0) {
1172 /* TRANSLATORS: The sentence starts with "The BUP file %s exists[...]" */
1173 fprintf(stderr, _("The %s %s exists; will try to overwrite it.\n"), _("BUP file"), targetname_bup);
1174 if (! S_ISREG(fileinfo.st_mode)) {
1175 /* TRANSLATORS: The sentence starts with "The BUP file %s is not valid[...]" */
1176 fprintf(stderr,_("The %s %s is not valid, it may be a directory.\n"), _("BUP file"), targetname_bup);
1177 return(1);
1178 }
1179 }
1180
1181 if ((streamout_ifo = open(targetname_ifo, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
1182 fprintf(stderr, _("Error creating %s\n"), targetname_ifo);
1183 perror(PACKAGE);
1184 DVDCloseFile(ifo_file);
1185 free(buffer);
1186 close(streamout_ifo);
1187 close(streamout_bup);
1188 return 1;
1189 }
1190
1191 if ((streamout_bup = open(targetname_bup, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
1192 fprintf(stderr, _("Error creating %s\n"), targetname_bup);
1193 perror(PACKAGE);
1194 DVDCloseFile(ifo_file);
1195 free(buffer);
1196 close(streamout_ifo);
1197 close(streamout_bup);
1198 return 1;
1199 }
1200
1201 /* Copy VIDEO_TS.IFO, since it's a small file try to copy it in one shot */
1202
1203 if ((ifo_file = DVDOpenFile(dvd, title_set, DVD_READ_INFO_FILE))== 0) {
1204 fprintf(stderr, _("Failed opening IFO for title set %d\n"), title_set);
1205 DVDCloseFile(ifo_file);
1206 free(buffer);
1207 close(streamout_ifo);
1208 close(streamout_bup);
1209 return 1;
1210 }
1211
1212 size = DVDFileSize(ifo_file) * DVD_VIDEO_LB_LEN;
1213
1214 if ((buffer = (unsigned char *)malloc(size * sizeof(unsigned char))) == NULL) {
1215 perror(PACKAGE);
1216 DVDCloseFile(ifo_file);
1217 free(buffer);
1218 close(streamout_ifo);
1219 close(streamout_bup);
1220 return 1;
1221 }
1222
1223 DVDFileSeek(ifo_file, 0);
1224
1225 if (DVDReadBytes(ifo_file,buffer,size) != size) {
1226 fprintf(stderr, _("Error reading IFO for title set %d\n"), title_set);
1227 DVDCloseFile(ifo_file);
1228 free(buffer);
1229 close(streamout_ifo);
1230 close(streamout_bup);
1231 return 1;
1232 }
1233
1234
1235 if (write(streamout_ifo,buffer,size) != size) {
1236 fprintf(stderr, _("Error writing %s\n"),targetname_ifo);
1237 DVDCloseFile(ifo_file);
1238 free(buffer);
1239 close(streamout_ifo);
1240 close(streamout_bup);
1241 return 1;
1242 }
1243
1244 if (write(streamout_bup,buffer,size) != size) {
1245 fprintf(stderr, _("Error writing %s\n"),targetname_bup);
1246 DVDCloseFile(ifo_file);
1247 free(buffer);
1248 close(streamout_ifo);
1249 close(streamout_bup);
1250 return 1;
1251 }
1252
1253 return 0;
1254 }
1255
1256
DVDMirrorTitleX(dvd_reader_t * dvd,title_set_info_t * title_set_info,int title_set,char * targetdir,char * title_name,read_error_strategy_t errorstrat)1257 static int DVDMirrorTitleX(dvd_reader_t* dvd, title_set_info_t* title_set_info,
1258 int title_set, char* targetdir, char* title_name,
1259 read_error_strategy_t errorstrat) {
1260
1261 /* Loop through the vobs */
1262 int i;
1263 int n;
1264
1265 if ( DVDCopyIfoBup(dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
1266 return(1);
1267 }
1268
1269 if ( DVDCopyMenu(dvd, title_set_info, title_set, targetdir, title_name, errorstrat) != 0 ) {
1270 return(1);
1271 }
1272
1273 n = title_set_info->title_set[title_set].number_of_vob_files;
1274 for (i = 0; i < n; i++) {
1275 #ifdef DEBUG
1276 fprintf(stderr,"In the VOB copy loop for %d\n", i);
1277 #endif
1278 if(progress) {
1279 snprintf(progressText, MAXNAME, _("Title, part %i/%i"), i+1, n);
1280 }
1281
1282 if ( DVDCopyTitleVobX(dvd, title_set_info, title_set, i + 1, targetdir, title_name, errorstrat) != 0 ) {
1283 return(1);
1284 }
1285 }
1286
1287
1288 return(0);
1289 }
1290
DVDGetTitleName(const char * device,char * title)1291 int DVDGetTitleName(const char *device, char *title)
1292 {
1293 /* Variables for filehandel and title string interaction */
1294
1295 char tempBuf[DVD_SEC_SIZ];
1296 int filehandle, i;
1297 int length = 32;
1298 int word_length = 0;
1299
1300 /* Open DVD device */
1301
1302 if ( !(filehandle = open(device, O_RDONLY)) ) {
1303 fprintf(stderr, _("Cannot open specified device %s - check your DVD device\n"), device);
1304 return(1);
1305 }
1306
1307 /* Seek to title of first track, which is at (track_no * 32768) + 40 */
1308
1309 if(lseek(filehandle, 32768, SEEK_SET) != 32768) {
1310 close(filehandle);
1311 fprintf(stderr, _("Cannot seek DVD device %s - check your DVD device\n"), device);
1312 return(1);
1313 }
1314
1315 /* Read the DVD-Video title */
1316 if(DVD_SEC_SIZ != read(filehandle, tempBuf, DVD_SEC_SIZ)) {
1317 close(filehandle);
1318 fprintf(stderr, _("Cannot read title from DVD device %s\n"), device);
1319 return(1);
1320 }
1321 snprintf(title, length + 1, "%s", tempBuf + 40);
1322
1323 /* Remove trailing white space */
1324 while(title[length-1] == ' ') {
1325 title[length-1] = '\0';
1326 length--;
1327 }
1328
1329 /* convert title to lower case and replace underscores with spaces */
1330 for(i = 0; i < length; i++) {
1331 word_length++;
1332 if(word_length == 1) {
1333 title[i] = toupper(title[i]);
1334 } else {
1335 title[i] = tolower(title[i]);
1336 }
1337 if(title[i] == '_') {
1338 title[i] = ' ';
1339 }
1340 if(title[i] == ' ') {
1341 word_length = 0;
1342 }
1343 }
1344
1345 return(0);
1346 }
1347
1348
1349
bsort_min_to_max(int sector[],int title[],int size)1350 static void bsort_min_to_max(int sector[], int title[], int size){
1351
1352 int temp_title, temp_sector, i, j;
1353
1354 for ( i=0; i < size ; i++ ) {
1355 for ( j=0; j < size ; j++ ) {
1356 if (sector[i] < sector[j]) {
1357 temp_sector = sector[i];
1358 temp_title = title[i];
1359 sector[i] = sector[j];
1360 title[i] = title[j];
1361 sector[j] = temp_sector;
1362 title[j] = temp_title;
1363 }
1364 }
1365 }
1366 }
1367
bsort_max_to_min(int sector[],int title[],int size)1368 static void bsort_max_to_min(int sector[], int title[], int size){
1369
1370 int temp_title, temp_sector, i, j;
1371
1372 for ( i=0; i < size ; i++ ) {
1373 for ( j=0; j < size ; j++ ) {
1374 if (sector[i] > sector[j]) {
1375 temp_sector = sector[i];
1376 temp_title = title[i];
1377 sector[i] = sector[j];
1378 title[i] = title[j];
1379 sector[j] = temp_sector;
1380 title[j] = temp_title;
1381 }
1382 }
1383 }
1384 }
1385
1386
align_end_sector(int cell_start_sector[],int cell_end_sector[],int size)1387 static void align_end_sector(int cell_start_sector[],int cell_end_sector[], int size) {
1388
1389 int i;
1390
1391 for (i = 0; i < size - 1 ; i++) {
1392 if ( cell_end_sector[i] >= cell_start_sector[i + 1] ) {
1393 cell_end_sector[i] = cell_start_sector[i + 1] - 1;
1394 }
1395 }
1396 }
1397
1398
DVDFreeTitleSetInfo(title_set_info_t * title_set_info)1399 static void DVDFreeTitleSetInfo(title_set_info_t * title_set_info) {
1400 free(title_set_info->title_set);
1401 free(title_set_info);
1402 }
1403
1404
DVDFreeTitlesInfo(titles_info_t * titles_info)1405 static void DVDFreeTitlesInfo(titles_info_t * titles_info) {
1406 free(titles_info->titles);
1407 free(titles_info);
1408 }
1409
1410
DVDGetFileSet(dvd_reader_t * dvd)1411 static title_set_info_t* DVDGetFileSet(dvd_reader_t* dvd) {
1412
1413 /* title interation */
1414 int title_sets, counter, i;
1415
1416 /* DVD Video files */
1417 dvd_stat_t statbuf;
1418
1419 /* DVD IFO handler */
1420 ifo_handle_t* vmg_ifo = NULL;
1421
1422 /* The Title Set Info struct */
1423 title_set_info_t* title_set_info;
1424
1425 /* Open main info file */
1426 vmg_ifo = ifoOpen(dvd, 0);
1427 if(vmg_ifo == NULL) {
1428 fprintf( stderr, _("Cannot open Video Manager (VMG) info.\n"));
1429 return NULL;
1430 }
1431
1432 title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;
1433
1434 /* Close the VMG IFO file we got all the info we need */
1435 ifoClose(vmg_ifo);
1436
1437 title_set_info = (title_set_info_t*)malloc(sizeof(title_set_info_t));
1438 if(title_set_info == NULL) {
1439 perror(PACKAGE);
1440 return NULL;
1441 }
1442
1443 title_set_info->title_set = (title_set_t*)malloc((title_sets + 1) * sizeof(title_set_t));
1444 if(title_set_info->title_set == NULL) {
1445 perror(PACKAGE);
1446 free(title_set_info);
1447 return NULL;
1448 }
1449
1450 title_set_info->number_of_title_sets = title_sets;
1451
1452
1453 /* Find VIDEO_TS.IFO is present - must be present since we did a ifo open 0 */
1454
1455 if (DVDFileStat(dvd, 0, DVD_READ_INFO_FILE, &statbuf) != -1) {
1456 title_set_info->title_set[0].size_ifo = statbuf.size;
1457 } else {
1458 DVDFreeTitleSetInfo(title_set_info);
1459 return NULL;
1460 }
1461
1462 /* Find VIDEO_TS.VOB if present*/
1463
1464 if(DVDFileStat(dvd, 0, DVD_READ_MENU_VOBS, &statbuf) != -1) {
1465 title_set_info->title_set[0].size_menu = statbuf.size;
1466 } else {
1467 title_set_info->title_set[0].size_menu = 0 ;
1468 }
1469
1470 /* Take care of the titles which we don't have in VMG */
1471
1472 title_set_info->title_set[0].number_of_vob_files = 0;
1473 title_set_info->title_set[0].size_vob[0] = 0;
1474
1475 if ( verbose > 0 ){
1476 fprintf(stderr,_("\n\n\nFile sizes for Title set 0 VIDEO_TS.XXX\n"));
1477 fprintf(stderr,_("IFO = %jd, MENU_VOB = %jd\n"),(intmax_t)title_set_info->title_set[0].size_ifo, (intmax_t)title_set_info->title_set[0].size_menu);
1478 }
1479
1480 for(counter = 0; counter < title_sets; counter++) {
1481
1482 if(verbose > 1) {
1483 fprintf(stderr,_("At top of loop\n"));
1484 }
1485
1486
1487 if(DVDFileStat(dvd, counter + 1, DVD_READ_INFO_FILE, &statbuf) != -1) {
1488 title_set_info->title_set[counter+1].size_ifo = statbuf.size;
1489 } else {
1490 DVDFreeTitleSetInfo(title_set_info);
1491 return NULL;
1492 }
1493
1494 if(verbose > 1) {
1495 fprintf(stderr,_("After opening files\n"));
1496 }
1497
1498 /* Find VTS_XX_0.VOB if present */
1499
1500 if(DVDFileStat(dvd, counter + 1, DVD_READ_MENU_VOBS, &statbuf) != -1) {
1501 title_set_info->title_set[counter + 1].size_menu = statbuf.size;
1502 } else {
1503 title_set_info->title_set[counter + 1].size_menu = 0 ;
1504 }
1505
1506 if(verbose > 1) {
1507 fprintf(stderr,_("After Menu VOB check\n"));
1508 }
1509
1510 /* Find all VTS_XX_[1 to 9].VOB files if they are present */
1511
1512 i = 0;
1513 if(DVDFileStat(dvd, counter + 1, DVD_READ_TITLE_VOBS, &statbuf) != -1) {
1514 for(i = 0; i < statbuf.nr_parts; ++i) {
1515 title_set_info->title_set[counter + 1].size_vob[i] = statbuf.parts_size[i];
1516 }
1517 }
1518 title_set_info->title_set[counter + 1].number_of_vob_files = i;
1519
1520 if(verbose > 1) {
1521 fprintf(stderr,_("After Menu Title VOB check\n"));
1522 }
1523
1524 if(verbose > 0) {
1525 fprintf(stderr,_("\n\n\nFile sizes for Title set %d i.e. VTS_%02d_X.XXX\n"), counter + 1, counter + 1);
1526 fprintf(stderr,_("IFO: %jd, MENU: %jd\n"), (intmax_t)title_set_info->title_set[counter +1].size_ifo, (intmax_t)title_set_info->title_set[counter +1].size_menu);
1527 for (i = 0; i < title_set_info->title_set[counter + 1].number_of_vob_files ; i++) {
1528 fprintf(stderr, _("VOB %d is %jd\n"), i + 1, (intmax_t)title_set_info->title_set[counter + 1].size_vob[i]);
1529 }
1530 }
1531
1532 if(verbose > 1) {
1533 fprintf(stderr,_("Bottom of loop\n"));
1534 }
1535 }
1536
1537 /* Return the info */
1538 return title_set_info;
1539 }
1540
1541
DVDMirror(dvd_reader_t * _dvd,char * targetdir,char * title_name,read_error_strategy_t errorstrat)1542 int DVDMirror(dvd_reader_t * _dvd, char * targetdir,char * title_name, read_error_strategy_t errorstrat) {
1543
1544 int i;
1545 title_set_info_t * title_set_info=NULL;
1546
1547 title_set_info = DVDGetFileSet(_dvd);
1548 if (!title_set_info) {
1549 return(1);
1550 }
1551
1552 for ( i=0; i <= title_set_info->number_of_title_sets; i++) {
1553 if ( DVDMirrorTitleX(_dvd, title_set_info, i, targetdir, title_name, errorstrat) != 0 ) {
1554 fprintf(stderr,_("Mirror of Title set %d failed\n"), i);
1555 DVDFreeTitleSetInfo(title_set_info);
1556 return(1);
1557 }
1558 }
1559 return(0);
1560 }
1561
1562
DVDMirrorTitleSet(dvd_reader_t * _dvd,char * targetdir,char * title_name,int title_set,read_error_strategy_t errorstrat)1563 int DVDMirrorTitleSet(dvd_reader_t * _dvd, char * targetdir,char * title_name, int title_set, read_error_strategy_t errorstrat) {
1564
1565 title_set_info_t * title_set_info=NULL;
1566
1567
1568 #ifdef DEBUG
1569 fprintf(stderr,"In DVDMirrorTitleSet\n");
1570 #endif
1571
1572 title_set_info = DVDGetFileSet(_dvd);
1573
1574 if (!title_set_info) {
1575 return(1);
1576 }
1577
1578 if ( title_set > title_set_info->number_of_title_sets ) {
1579 fprintf(stderr, _("Cannot copy title_set %d there is only %d title_sets present on this DVD\n"), title_set, title_set_info->number_of_title_sets);
1580 DVDFreeTitleSetInfo(title_set_info);
1581 return(1);
1582 }
1583
1584 if ( DVDMirrorTitleX(_dvd, title_set_info, title_set, targetdir, title_name, errorstrat) != 0 ) {
1585 fprintf(stderr,_("Mirror of Title set %d failed\n"), title_set);
1586 DVDFreeTitleSetInfo(title_set_info);
1587 return(1);
1588 }
1589
1590 DVDFreeTitleSetInfo(title_set_info);
1591 return(0);
1592 }
1593
1594
DVDMirrorMainFeature(dvd_reader_t * _dvd,char * targetdir,char * title_name,read_error_strategy_t errorstrat)1595 int DVDMirrorMainFeature(dvd_reader_t * _dvd, char * targetdir,char * title_name, read_error_strategy_t errorstrat) {
1596
1597 title_set_info_t * title_set_info=NULL;
1598 titles_info_t * titles_info=NULL;
1599
1600
1601 titles_info = DVDGetInfo(_dvd);
1602 if (!titles_info) {
1603 fprintf(stderr, _("Guesswork of main feature film failed.\n"));
1604 return(1);
1605 }
1606
1607 title_set_info = DVDGetFileSet(_dvd);
1608 if (!title_set_info) {
1609 DVDFreeTitlesInfo(titles_info);
1610 return(1);
1611 }
1612
1613 if ( DVDMirrorTitleX(_dvd, title_set_info, titles_info->main_title_set, targetdir, title_name, errorstrat) != 0 ) {
1614 fprintf(stderr,_("Mirror of main feature file which is title set %d failed\n"), titles_info->main_title_set);
1615 DVDFreeTitleSetInfo(title_set_info);
1616 return(1);
1617 }
1618
1619 DVDFreeTitlesInfo(titles_info);
1620 DVDFreeTitleSetInfo(title_set_info);
1621 return(0);
1622 }
1623
1624
DVDMirrorChapters(dvd_reader_t * _dvd,char * targetdir,char * title_name,int start_chapter,int end_chapter,int titles)1625 int DVDMirrorChapters(dvd_reader_t * _dvd, char * targetdir,char * title_name, int start_chapter,int end_chapter, int titles) {
1626
1627
1628 int result;
1629 int chapters = 0;
1630 int i, s;
1631 int spg, epg;
1632 int pgc;
1633 int start_cell, end_cell;
1634 int vts_title;
1635
1636 title_set_info_t * title_set_info=NULL;
1637 titles_info_t * titles_info=NULL;
1638 ifo_handle_t * vts_ifo_info=NULL;
1639 int * cell_start_sector=NULL;
1640 int * cell_end_sector=NULL;
1641
1642 titles_info = DVDGetInfo(_dvd);
1643 if (!titles_info) {
1644 fprintf(stderr, _("Failed to obtain titles information\n"));
1645 return(1);
1646 }
1647
1648 title_set_info = DVDGetFileSet(_dvd);
1649 if (!title_set_info) {
1650 DVDFreeTitlesInfo(titles_info);
1651 return(1);
1652 }
1653
1654 if(titles == 0) {
1655 fprintf(stderr, _("No title specified for chapter extraction, will try to figure out main feature title\n"));
1656 for (i=0; i < titles_info->number_of_titles ; i++ ) {
1657 if ( titles_info->titles[i].title_set == titles_info->main_title_set ) {
1658 if(chapters < titles_info->titles[i].chapters) {
1659 chapters = titles_info->titles[i].chapters;
1660 titles = i + 1;
1661 }
1662 }
1663 }
1664 }
1665
1666 vts_ifo_info = ifoOpen(_dvd, titles_info->titles[titles - 1].title_set);
1667 if(!vts_ifo_info) {
1668 fprintf(stderr, _("Could not open title_set %d IFO file\n"), titles_info->titles[titles - 1].title_set);
1669 DVDFreeTitlesInfo(titles_info);
1670 DVDFreeTitleSetInfo(title_set_info);
1671 return(1);
1672 }
1673
1674 vts_title = titles_info->titles[titles - 1].vts_title;
1675
1676 if (end_chapter > titles_info->titles[titles - 1].chapters) {
1677 end_chapter = titles_info->titles[titles - 1].chapters;
1678 fprintf(stderr, _("Truncated the end_chapter; only %d chapters in %d title\n"), end_chapter,titles);
1679 }
1680
1681 if (start_chapter > titles_info->titles[titles - 1].chapters) {
1682 start_chapter = titles_info->titles[titles - 1].chapters;
1683 fprintf(stderr, _("Truncated the end_chapter; only %d chapters in %d title\n"), end_chapter,titles);
1684 }
1685
1686
1687
1688 /* We assume the same PGC for the whole title - this is not true and need to be fixed later on */
1689
1690 pgc = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgcn;
1691
1692
1693 /* Lookup PG for start chapter */
1694
1695 spg = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgn;
1696
1697 /* Look up start cell for this pgc/pg */
1698
1699 start_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[spg - 1];
1700
1701
1702 /* Lookup end cell*/
1703
1704
1705 if ( end_chapter < titles_info->titles[titles - 1].chapters ) {
1706 epg = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[end_chapter].pgn;
1707 #ifdef DEBUG
1708 fprintf(stderr,"DVDMirrorChapter: epg %d\n", epg);
1709 #endif
1710
1711 end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[epg -1] - 1;
1712 #ifdef DEBUG
1713 fprintf(stderr,"DVDMirrorChapter: end cell adjusted %d\n", end_cell);
1714 #endif
1715
1716 } else {
1717
1718 end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->nr_of_cells;
1719 #ifdef DEBUG
1720 fprintf(stderr,"DVDMirrorChapter: end cell adjusted 2 %d\n",end_cell);
1721 #endif
1722
1723 }
1724
1725 #ifdef DEBUG
1726 fprintf(stderr,"DVDMirrorChapter: star cell %d\n", start_cell);
1727 #endif
1728
1729
1730 /* Put all the cells start and end sector in a dual array */
1731
1732 cell_start_sector = (int *)malloc( (end_cell - start_cell + 1) * sizeof(int));
1733 if(!cell_start_sector) {
1734 fprintf(stderr,_("Memory allocation error 1\n"));
1735 DVDFreeTitlesInfo(titles_info);
1736 DVDFreeTitleSetInfo(title_set_info);
1737 ifoClose(vts_ifo_info);
1738 return(1);
1739 }
1740 cell_end_sector = (int *)malloc( (end_cell - start_cell + 1) * sizeof(int));
1741 if(!cell_end_sector) {
1742 fprintf(stderr,_("Memory allocation error\n"));
1743 DVDFreeTitlesInfo(titles_info);
1744 DVDFreeTitleSetInfo(title_set_info);
1745 ifoClose(vts_ifo_info);
1746 free(cell_start_sector);
1747 return(1);
1748 }
1749 #ifdef DEBUG
1750 fprintf(stderr,"DVDMirrorChapter: start cell is %d\n", start_cell);
1751 fprintf(stderr,"DVDMirrorChapter: end cell is %d\n", end_cell);
1752 fprintf(stderr,"DVDMirrorChapter: pgc is %d\n", pgc);
1753 #endif
1754
1755 for (i=0, s=start_cell; s < end_cell +1 ; i++, s++) {
1756
1757 cell_start_sector[i] = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].first_sector;
1758 cell_end_sector[i] = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].last_sector;
1759 #ifdef DEBUG
1760 fprintf(stderr,"DVDMirrorChapter: S is %d\n", s);
1761 fprintf(stderr,"DVDMirrorChapter: start sector %d\n", vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].first_sector);
1762 fprintf(stderr,"DVDMirrorChapter: end sector %d\n", vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].last_sector);
1763 #endif
1764 }
1765
1766 bsort_min_to_max(cell_start_sector, cell_end_sector, end_cell - start_cell + 1);
1767
1768 align_end_sector(cell_start_sector, cell_end_sector,end_cell - start_cell + 1);
1769
1770 #ifdef DEBUG
1771 for (i=0 ; i < end_cell - start_cell + 1; i++) {
1772 fprintf(stderr,"DVDMirrorChapter: Start sector is %d end sector is %d\n", cell_start_sector[i], cell_end_sector[i]);
1773 }
1774 #endif
1775
1776 result = DVDWriteCells(_dvd, cell_start_sector, cell_end_sector , end_cell - start_cell + 1, titles, title_set_info, titles_info, targetdir, title_name);
1777
1778 DVDFreeTitlesInfo(titles_info);
1779 DVDFreeTitleSetInfo(title_set_info);
1780 ifoClose(vts_ifo_info);
1781 free(cell_start_sector);
1782 free(cell_end_sector);
1783
1784 if( result != 0) {
1785 return(1);
1786 } else {
1787 return(0);
1788 }
1789 }
1790
1791
DVDMirrorTitles(dvd_reader_t * _dvd,char * targetdir,char * title_name,int titles)1792 int DVDMirrorTitles(dvd_reader_t * _dvd, char * targetdir,char * title_name, int titles) {
1793
1794 int end_chapter;
1795
1796 titles_info_t * titles_info=NULL;
1797
1798 #ifdef DEBUG
1799 fprintf(stderr,"In DVDMirrorTitles\n");
1800 #endif
1801
1802
1803
1804 titles_info = DVDGetInfo(_dvd);
1805 if (!titles_info) {
1806 fprintf(stderr, _("Failed to obtain titles information\n"));
1807 return(1);
1808 }
1809
1810
1811 end_chapter = titles_info->titles[titles - 1].chapters;
1812 #ifdef DEBUG
1813 fprintf(stderr,"DVDMirrorTitles: end_chapter %d\n", end_chapter);
1814 #endif
1815
1816 if (DVDMirrorChapters( _dvd, targetdir, title_name, 1, end_chapter, titles) != 0 ) {
1817 DVDFreeTitlesInfo(titles_info);
1818 return(1);
1819 }
1820
1821 DVDFreeTitlesInfo(titles_info);
1822
1823 return(0);
1824 }
1825
1826
1827 /**
1828 * Formats a filesize human readable. For example 25,05 KiB instead of
1829 * 25648 Bytes.
1830 */
format_filesize(off_t filesize,char * result)1831 static void format_filesize(off_t filesize, char* result) {
1832 char* prefix = "";
1833 double size = (double)filesize;
1834 int prefix_count = 0;
1835
1836 while(size > 1024 && prefix_count < 6) {
1837 size /= 1024;
1838 prefix_count++;
1839 }
1840
1841 if(prefix_count == 1) {
1842 prefix = "Ki";
1843 } else if(prefix_count == 2) {
1844 prefix = "Mi";
1845 } else if(prefix_count == 3) {
1846 prefix = "Gi";
1847 } else if(prefix_count == 4) {
1848 prefix = "Ti";
1849 } else if(prefix_count == 5) {
1850 prefix = "Pi";
1851 } else if(prefix_count == 6) {
1852 prefix = "Ei";
1853 }
1854
1855 sprintf(result, "%7.2f %sB", size, prefix);
1856 }
1857
1858
DVDDisplayInfo(dvd_reader_t * dvd,char * device)1859 int DVDDisplayInfo(dvd_reader_t* dvd, char* device) {
1860 int i, f;
1861 int chapters;
1862 int channels;
1863 int titles;
1864 char title_name[33] = "";
1865 char size[40] = "";
1866 title_set_info_t* title_set_info = NULL;
1867 titles_info_t* titles_info = NULL;
1868
1869 titles_info = DVDGetInfo(dvd);
1870 if (!titles_info) {
1871 fprintf(stderr, _("Guesswork of main feature film failed.\n"));
1872 return(1);
1873 }
1874
1875 title_set_info = DVDGetFileSet(dvd);
1876 if (!title_set_info) {
1877 DVDFreeTitlesInfo(titles_info);
1878 return(1);
1879 }
1880
1881 DVDGetTitleName(device, title_name);
1882
1883
1884 printf(_("DVD-Video information of the DVD with title \"%s\"\n\n"), title_name);
1885
1886 /* Print file structure */
1887
1888 printf(_("File Structure DVD\n"));
1889 printf("VIDEO_TS/\n");
1890 format_filesize(title_set_info->title_set[0].size_ifo, size);
1891 printf("\tVIDEO_TS.IFO\t%10jd\t%s\n", (intmax_t)title_set_info->title_set[0].size_ifo, size);
1892
1893 if (title_set_info->title_set[0].size_menu != 0 ) {
1894 format_filesize(title_set_info->title_set[0].size_menu, size);
1895 printf("\tVIDEO_TS.VOB\t%10jd\t%s\n", (intmax_t)title_set_info->title_set[0].size_menu, size);
1896 }
1897
1898 for(i = 0 ; i <= title_set_info->number_of_title_sets; i++) {
1899 format_filesize(title_set_info->title_set[i].size_ifo, size);
1900 printf("\tVTS_%02i_0.IFO\t%10jd\t%s\n", i, (intmax_t)title_set_info->title_set[i].size_ifo, size);
1901 if(title_set_info->title_set[i].size_menu != 0) {
1902 format_filesize(title_set_info->title_set[i].size_menu, size);
1903 printf("\tVTS_%02i_0.VOB\t%10jd\t%s\n", i, (intmax_t)title_set_info->title_set[i].size_menu, size);
1904 }
1905 if(title_set_info->title_set[i].number_of_vob_files != 0) {
1906 for(f = 0; f < title_set_info->title_set[i].number_of_vob_files; f++) {
1907 format_filesize(title_set_info->title_set[i].size_vob[f], size);
1908 printf("\tVTS_%02i_%i.VOB\t%10jd\t%s\n", i, f + 1, (intmax_t)title_set_info->title_set[i].size_vob[f], size);
1909 }
1910 }
1911 }
1912
1913 printf(_("\n\nMain feature:\n"));
1914 printf(_("\tTitle set containing the main feature is %d\n"), titles_info->main_title_set);
1915 for (i=0; i < titles_info->number_of_titles ; i++ ) {
1916 if (titles_info->titles[i].title_set == titles_info->main_title_set) {
1917 if(titles_info->titles[i].aspect_ratio == 3) {
1918 printf(_("\tThe aspect ratio of the main feature is 16:9\n"));
1919 } else if (titles_info->titles[i].aspect_ratio == 0) {
1920 printf(_("\tThe aspect ratio of the main feature is 4:3\n"));
1921 } else {
1922 printf(_("\tThe aspect ratio of the main feature is unknown\n"));
1923 }
1924
1925 printf(ngettext("\tThe main feature has %d angle\n",
1926 "\tThe main feature has %d angles\n",
1927 titles_info->titles[i].angles), titles_info->titles[i].angles);
1928 printf(ngettext("\tThe main feature has %d audio track\n",
1929 "\tThe main feature has %d audio tracks\n",
1930 titles_info->titles[i].audio_tracks), titles_info->titles[i].audio_tracks);
1931 printf(ngettext("\tThe main feature has %d subpicture channel\n",
1932 "\tThe main feature has %d subpicture channels\n",
1933 titles_info->titles[i].sub_pictures), titles_info->titles[i].sub_pictures);
1934 chapters=0;
1935 channels=0;
1936
1937 for (f=0; f < titles_info->number_of_titles ; f++ ) {
1938 if ( titles_info->titles[i].title_set == titles_info->main_title_set ) {
1939 if(chapters < titles_info->titles[f].chapters) {
1940 chapters = titles_info->titles[f].chapters;
1941 }
1942 if(channels < titles_info->titles[f].audio_channels) {
1943 channels = titles_info->titles[f].audio_channels;
1944 }
1945 }
1946 }
1947 printf(ngettext("\tThe main feature has a maximum of %d chapter in one of its titles\n",
1948 "\tThe main feature has a maximum of %d chapters in one of its titles\n",
1949 chapters), chapters);
1950 printf(ngettext("\tThe main feature has a maximum of %d audio channel in one of its titles\n",
1951 "\tThe main feature has a maximum of %d audio channels in one of its titles\n",
1952 channels), channels);
1953 break;
1954 }
1955 }
1956
1957 printf(_("\n\nTitle Sets:"));
1958 for (f=0; f < title_set_info->number_of_title_sets ; f++ ) {
1959 printf(_("\n\n\tTitle set %d\n"), f + 1);
1960 for (i=0; i < titles_info->number_of_titles ; i++ ) {
1961 if (titles_info->titles[i].title_set == f + 1) {
1962 if(titles_info->titles[i].aspect_ratio == 3) {
1963 printf(_("\t\tThe aspect ratio of title set %d is 16:9\n"), f + 1);
1964 } else if (titles_info->titles[i].aspect_ratio == 0) {
1965 printf(_("\t\tThe aspect ratio of title set %d is 4:3\n"), f + 1);
1966 } else {
1967 printf(_("\t\tThe aspect ratio of title set %d is unknown\n"), f + 1);
1968 }
1969 printf(ngettext("\t\tTitle set %d has %d angle\n",
1970 "\t\tTitle set %d has %d angles\n",
1971 titles_info->titles[i].angles), f + 1, titles_info->titles[i].angles);
1972 printf(ngettext("\t\tTitle set %d has %d audio track\n",
1973 "\t\tTitle set %d has %d audio tracks\n",
1974 titles_info->titles[i].audio_tracks), f + 1, titles_info->titles[i].audio_tracks);
1975 printf(ngettext("\t\tTitle set %d has %d subpicture channel\n",
1976 "\t\tTitle set %d has %d subpicture channels\n",
1977 titles_info->titles[i].sub_pictures), f + 1, titles_info->titles[i].sub_pictures);
1978 break;
1979 }
1980 }
1981
1982 titles = 0;
1983 for(i = 0; i < titles_info->number_of_titles; i++) {
1984 if (titles_info->titles[i].title_set == f + 1) {
1985 titles++;
1986 }
1987 }
1988 printf(ngettext("\n\t\tTitle included in title set %d is\n",
1989 "\n\t\tTitles included in title set %d are\n",
1990 titles), f + 1);
1991
1992 for (i=0; i < titles_info->number_of_titles ; i++ ) {
1993 if (titles_info->titles[i].title_set == f + 1) {
1994 printf(_("\t\t\tTitle %d:\n"), i + 1);
1995 printf(ngettext("\t\t\t\tTitle %d has %d chapter\n",
1996 "\t\t\t\tTitle %d has %d chapters\n",
1997 titles_info->titles[i].chapters), i + 1, titles_info->titles[i].chapters);
1998 printf(ngettext("\t\t\t\tTitle %d has %d audio channel\n",
1999 "\t\t\t\tTitle %d has %d audio channels\n",
2000 titles_info->titles[i].audio_channels), i + 1, titles_info->titles[i].audio_channels);
2001 }
2002 }
2003 }
2004 DVDFreeTitlesInfo(titles_info);
2005 DVDFreeTitleSetInfo(title_set_info);
2006
2007 return(0);
2008 }
2009