]> git.pld-linux.org Git - packages/dvdbackup.git/blob - dvdbackup.c
- fix for libdvdread, rel 2
[packages/dvdbackup.git] / dvdbackup.c
1 /*
2  * Copyright (C) 2002  Olaf Beck <olaf_sc@yahoo.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 /* dvdbackup version 0.1 */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/errno.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <dvdread/dvd_reader.h>
34 #include <dvdread/ifo_read.h>
35 #include <dvdread/ifo_print.h>
36
37
38 #define MAXNAME 256
39
40 /*Flag for verbose mode */
41 int verbose;
42 int aspect;
43
44
45 /* Structs to keep title set information in */
46
47 typedef struct {
48   int           size_ifo;
49   int           size_menu;
50   int           size_bup;
51   int           number_of_vob_files;
52   int           size_vob[10];
53 } title_set_t;
54
55 typedef struct {
56   int           number_of_title_sets;
57   title_set_t  *title_set;
58 } title_set_info_t;
59
60
61 typedef struct {
62   int           title;
63   int           title_set;
64   int           vts_title;
65   int           chapters;
66   int           aspect_ratio;
67   int           angles;
68   int           audio_tracks;
69   int           audio_channels;
70   int           sub_pictures;
71 } titles_t;
72
73 typedef struct {
74   int           main_title_set;
75   int           number_of_titles;
76   titles_t      *titles;
77 } titles_info_t;
78
79
80 void bsort_max_to_min(int sector[], int title[], int size);
81
82 /* Usage:
83         To gather info about the dvd:
84                 dvdbackup -i /dev/dvd -I
85
86         Gerneral backup information:
87                 If your backup directory is /my/dvd/backup/dir/
88                 specified with the "-o" flag. Then dvdbackup
89                 will create a DVD-Video structure under
90                 /my/dvd/backup/dir/TITLE_NAME/VIDEO_TS.
91
92                 Since the title is "uniq" you can use the same dir
93                 for all your DVD backups. If it happens to have a
94                 generic title dvdbackup will exit with a return value
95                 of 2. And you will need to specify a title name with
96                 the -n switch.
97
98                 dvdbackup will always mimic the original DVD-Video
99                 structure. Hence if you e.g. use the -M (mirror) you
100                 will get an exact duplicate of the original. This
101                 means that every file will be have the same size as
102                 the original one. Like wise goes also for the -F
103                 and the -T switch.
104
105                 However the -t and (-t -s/-e) switch is a bit
106                 different the titles sectors will be written to the
107                 original file but not at the same offset as the
108                 original one since they may be gaps in the cell
109                 structure that we don't fill.
110
111
112         To backup the whole DVD
113
114                 dvdbackup -M -i/dev/dvd -o/my/dvd/backup/dir/
115
116                 This action creates a valid DVD-Video structure
117                 that can be burned to a DVD-/+R(W) with help of
118                 mkisofs version 1.11a27 or later
119
120
121         To backup the main feature of the DVD:
122
123                 dvdbackup -F -i/dev/dvd -o/my/dvd/backup/dir/
124
125                 This action creates a valid DVD-Video structure
126                 of the feature title set
127
128                 dvdbackup defaults to get the 16:9 version of the
129                 main feature if a 4:3 is also present on the DVD.
130                 To get the 4:3 version use -a 0.
131
132                 dvdbackup makes it best to make a inteligent guess
133                 what is the main feature of the DVD - in case it fails
134                 please send a bug report.
135
136
137         To backup a title set
138
139                 dvdbackup -T 2 -i/dev/dvd -o/my/dvd/backup/dir/
140
141                 where "-T 2" specifies that you want to backup
142                 title set 2 i.e. all VTS_02_X.XXX files.
143
144                 This action creates a valid DVD-Video structure
145                 of the specified title set
146
147
148         To backup a title:
149
150                 dvdbackup -t 1 -i/dev/dvd -o/my/dvd/backup/dir
151
152                 This action backups all cells that forms the
153                 specified title. Note that there can be sector
154                 gaps in between one cell and an other. dvdbackup
155                 will backup all sectors that belongs to the title
156                 but will skip sectors that aren't a part of the title.
157
158
159         To backup a specific chapter or chapters from a title:
160
161                 dvdbackup -t 1 -s 20 -e 25 -i/dev/dvd -o/my/dvd/backup/dir
162
163                 This action will backup chapter 20 to 25 in title 1, as with
164                 the backup of a title there can be sector gaps between one chapter
165                 (cell) and on other.dvdbackup will backup all sectors that belongs
166                 to the title 1 chapter 20 to 25 but will skip sectors that aren't
167                 a part of the title 1 chapter 20 to 25.
168
169                 To backup a single chapter e.g. chapter 20 do -s 20 -e 20
170                 To backup from chapter 20 to the end chapter use only -s 20
171                 To backup to chapter 20 from the first chapter use only -e 20
172
173                 You can skip the -t switch and let the program guess the title although
174                 it's not recomened.
175
176                 If you specify a chapter that his higher than the last chapter of the title
177                 dvdbackup will turncate to the highest chapter of the title.
178
179         Return values:
180                 0 on success
181                 1 on usage error
182                 2 on title name error
183                 -1 on failur
184
185
186         Todo - i.e. what's on the agenda.
187                 Make the main feature guessing algoritm better. Not that it doesn't do
188                 it's job, but it's implementation it's that great. I would also like
189                 to preserve more information about the main feature since that would
190                 let me preform better implementations in other functions that depends
191                 on the titles_info_t and title_set_info_t strcutures.
192
193                 Make it possible to extract cells in a title not just chapters (very
194                 easy so it will definitly be in the next version).
195
196                 Make a split mirror (-S) option that divides a DVD-9 to two valid DVD-5
197                 video structures. This is not a trivial hack and it's my main goal
198                 the next month or so. It involves writing ifoedit and vobedit
199                 libraries in order to be able to manipulate both the IFO structures
200                 and the VOB files. Out of this will most probably also come tscreate
201                 and vtscreate which will enable you to make a very simple DVD-Video
202                 from MPEG-1/2 source.
203
204 */
205
206
207 void usage(){
208         fprintf(stderr,"\nUsage: dvdbackup [options]\n");
209         fprintf(stderr,"\t-i device\twhere device is your dvd device\n");
210         fprintf(stderr,"\t-v X\t\twhere X is the amount of verbosity\n");
211         fprintf(stderr,"\t-I\t\tfor information about the DVD\n");
212         fprintf(stderr,"\t-o directory\twhere directory is your backup target\n");
213         fprintf(stderr,"\t-M\t\tbackup the whole DVD\n");
214         fprintf(stderr,"\t-F\t\tbackup the main feature of the DVD\n");
215         fprintf(stderr,"\t-T X\t\tbackup title set X\n");
216         fprintf(stderr,"\t-t X\t\tbackup title X\n");
217         fprintf(stderr,"\t-s X\t\tbackup from chapter X\n");
218         fprintf(stderr,"\t-e X\t\tbackup to chapter X\n");
219         fprintf(stderr,"\t-a 0\t\tto get aspect ratio 4:3 instead of 16:9 if both are present\n");
220         fprintf(stderr,"\t-h\t\tprint a brief usage message\n");
221         fprintf(stderr,"\t-?\t\tprint a brief usage message\n\n");
222         fprintf(stderr,"\t-i is manditory\n");
223         fprintf(stderr,"\t-o is manditory except if you use -I\n");
224         fprintf(stderr,"\t-a is option to the -F switch and has no effect on other options\n");
225         fprintf(stderr,"\t-s and -e should prefereibly be used together with -t \n\n");
226         exit(1);
227 }
228
229 int CheckSizeArray(const int size_array[], int reference, int target) {
230         if ( (size_array[reference]/size_array[target] == 1) &&
231              ((size_array[reference] * 2 - size_array[target])/ size_array[target] == 1) &&
232              ((size_array[reference]%size_array[target] * 3) < size_array[reference]) ) {
233                 /* We have a dual DVD with two feature films - now lets see if they have the same amount of chapters*/
234                 return(1);
235         } else {
236                 return(0);
237         }
238 }
239
240
241 int CheckAudioSubChannels(int audio_audio_array[], int title_set_audio_array[],
242                           int subpicture_sub_array[], int title_set_sub_array[],
243                           int channels_channel_array[],int title_set_channel_array[],
244                           int reference, int candidate, int title_sets) {
245
246         int temp, i, found_audio, found_sub, found_channels;
247
248         found_audio=0;
249         temp = audio_audio_array[reference];
250         for (i=0 ; i < title_sets ; i++ ) {
251                 if ( audio_audio_array[i] < temp ) {
252                         break;
253                 }
254                 if ( candidate == title_set_audio_array[i] ) {
255                         found_audio=1;
256                         break;
257                 }
258
259         }
260
261         found_sub=0;
262         temp = subpicture_sub_array[reference];
263         for (i=0 ; i < title_sets ; i++ ) {
264                 if ( subpicture_sub_array[i] < temp ) {
265                         break;
266                 }
267                 if ( candidate == title_set_sub_array[i] ) {
268                         found_sub=1;
269                         break;
270                 }
271
272         }
273
274
275         found_channels=0;
276         temp = channels_channel_array[reference];
277         for (i=0 ; i < title_sets ; i++ ) {
278                 if ( channels_channel_array[i] < temp ) {
279                         break;
280                 }
281                 if ( candidate == title_set_channel_array[i] ) {
282                         found_channels=1;
283                         break;
284                 }
285
286         }
287
288
289         return(found_audio + found_sub + found_channels);
290 }
291
292
293
294
295 int DVDWriteCells(dvd_reader_t * dvd, int cell_start_sector[], int cell_end_sector[],
296    int length, int titles, title_set_info_t * title_set_info, titles_info_t * titles_info, char * targetdir,char * title_name){
297
298
299         /* Loop variables */
300         int i, f;
301
302
303         /* Vob control */
304         int vob;
305
306         /* Temp filename,dirname */
307         char targetname[PATH_MAX];
308
309         /* Write buffer */
310
311         unsigned char * buffer=NULL;
312
313         /* File Handler */
314         int streamout;
315
316         int size;
317         int left;
318         int leftover;
319
320         /* Buffer size in DVD sectors */
321         /* Currently set to 1MB */
322         int buff = 512;
323         int tsize;
324
325
326         /* Offsets */
327         int soffset;
328         int offset;
329
330
331         /* DVD handler */
332         dvd_file_t   *  dvd_file=NULL;
333
334         int title_set;
335         int number_of_vob_files;
336
337 #ifdef DEBUG
338         fprintf(stderr,"DVDWriteCells: length is %d\n", length);
339
340 #endif
341
342
343         title_set = titles_info->titles[titles - 1].title_set;
344         number_of_vob_files = title_set_info->title_set[title_set].number_of_vob_files;
345 #ifdef DEBUG
346                 fprintf(stderr,"DVDWriteCells: title set is %d\n", title_set);
347                 fprintf(stderr,"DVDWriteCells: vob files are %d\n", number_of_vob_files);
348
349 #endif
350
351
352
353         /* Remove all old files silently if they exists */
354
355         for ( i = 0 ; i < 10 ; i++ ) {
356                 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, i + 1);
357 #ifdef DEBUG
358                 fprintf(stderr,"DVDWriteCells: file is %s\n", targetname);
359
360 #endif
361
362                 unlink( targetname);
363
364         }
365
366
367
368
369         /* Loop through all sectors and find the right vob */
370         for (f = 0; f < length ; f++) {
371
372                 soffset=0;
373                 offset=0;
374
375
376                 /* Now figure which vob we will use and write to that vob and if there is a left over write to the next vob*/
377
378                 for ( i = 0; i < number_of_vob_files ; i++ ) {
379
380
381                         tsize = title_set_info->title_set[title_set].size_vob[i];
382
383                         if (tsize%2048 != 0) {
384                                 fprintf(stderr, "The Title VOB number %d of title set %d doesn't have a valid DVD size\n", i + 1, title_set);
385                                 return(1);
386                         } else {
387                                 soffset = offset;
388                                 offset = offset + tsize/2048;
389                         }
390 #ifdef DEBUG
391                         fprintf(stderr,"DVDWriteCells: soffset is %d\n", soffset);
392                         fprintf(stderr,"DVDWriteCells: offset is %d\n", offset);
393 #endif
394                         /* Find out if this is the right vob */
395                         if( soffset <= cell_start_sector[f]  && offset > cell_start_sector[f] ) {
396 #ifdef DEBUG
397                                 fprintf(stderr,"DVDWriteCells: got it \n");
398 #endif
399                                 leftover=0;
400                                 soffset = cell_start_sector[f];
401                                 if ( cell_end_sector[f] > offset ) {
402                                         leftover = cell_end_sector[f] - offset + 1;
403                                 } else {
404                                         size = cell_end_sector[f] - cell_start_sector[f] + 1;
405                                 }
406 #ifdef DEBUG
407                                 fprintf(stderr,"DVDWriteCells: size is %d\n", size);
408 #endif
409                                 vob = i + 1;
410                                 break;
411                         }
412
413                 }
414 #ifdef DEBUG
415                 fprintf(stderr,"DVDWriteCells: Writing soffset is %d and leftover is %d\n", soffset, leftover);
416 #endif
417
418
419
420
421                 /* Create VTS_XX_X.VOB */
422                 if (title_set == 0) {
423                         fprintf(stderr,"Don't try to copy chapters from the VMG domain there aren't any\n");
424                         return(1);
425                 } else {
426                         sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
427                 }
428
429 #ifdef DEBUG
430                 fprintf(stderr,"DVDWriteCells: 1\n");
431 #endif
432
433
434                 if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(unsigned char))) == NULL) {
435                         fprintf(stderr, "Out of memory coping %s\n", targetname);
436                         return(1);
437                 }
438
439 #ifdef DEBUG
440                 fprintf(stderr,"DVDWriteCells: 2\n");
441 #endif
442
443
444                 if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0644)) == -1) {
445                         fprintf(stderr, "Error creating %s\n", targetname);
446                         perror("");
447                         return(1);
448                 }
449
450 #ifdef DEBUG
451                 fprintf(stderr,"DVDWriteCells: 3\n");
452 #endif
453
454
455                 if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
456                         fprintf(stderr, "Faild opending TITLE VOB\n");
457                         free(buffer);
458                         close(streamout);
459                         return(1);
460                 }
461
462                 left = size;
463
464 #ifdef DEBUG
465                 fprintf(stderr,"DVDWriteCells: left is %d\n", left);
466 #endif
467
468                 while( left > 0 ) {
469
470                         if (buff > left) {
471                                 buff = left;
472                         }
473                         if ( DVDReadBlocks(dvd_file,soffset,buff, buffer) != buff) {
474                                 fprintf(stderr, "Error reading MENU VOB\n");
475                                 free(buffer);
476                                 DVDCloseFile(dvd_file);
477                                 close(streamout);
478                                 return(1);
479                         }
480
481
482                         if (write(streamout,buffer,buff *  2048) != buff * 2048) {
483                                 fprintf(stderr, "Error writing TITLE VOB\n");
484                                 free(buffer);
485                                 close(streamout);
486                                 return(1);
487                         }
488
489                         soffset = soffset + buff;
490                         left = left - buff;
491
492                 }
493
494                 DVDCloseFile(dvd_file);
495                 free(buffer);
496                 close(streamout);
497
498
499                 if ( leftover != 0 ) {
500
501                         vob = vob + 1;
502
503                         if (title_set == 0) {
504                                 fprintf(stderr,"Don't try to copy chapters from the VMG domain there aren't any\n");
505                                 return(1);
506                         } else {
507                                 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
508                         }
509
510
511                         if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(unsigned char))) == NULL) {
512                                 fprintf(stderr, "Out of memory coping %s\n", targetname);
513                                 close(streamout);
514                                 return(1);
515                         }
516
517
518                         if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0644)) == -1) {
519                                 fprintf(stderr, "Error creating %s\n", targetname);
520                                 perror("");
521                                 return(1);
522                         }
523
524
525                         if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
526                                 fprintf(stderr, "Faild opending TITLE VOB\n");
527                                 free(buffer);
528                                 close(streamout);
529                                 return(1);
530                         }
531
532                         left = leftover;
533
534                         while( left > 0 ) {
535
536                                 if (buff > left) {
537                                         buff = left;
538                                 }
539                                 if ( DVDReadBlocks(dvd_file,offset,buff, buffer) != buff) {
540                                         fprintf(stderr, "Error reading MENU VOB\n");
541                                         free(buffer);
542                                         DVDCloseFile(dvd_file);
543                                         close(streamout);
544                                         return(1);
545                                 }
546
547
548                                 if (write(streamout,buffer,buff *  2048) != buff * 2048) {
549                                         fprintf(stderr, "Error writing TITLE VOB\n");
550                                         free(buffer);
551                                         close(streamout);
552                                         return(1);
553                                 }
554
555                                 offset = offset + buff;
556                                 left = left - buff;
557
558                         }
559
560                         DVDCloseFile(dvd_file);
561                         free(buffer);
562                         close(streamout);
563                 }
564
565         }
566         return(0);
567 }
568
569
570
571 void FreeSortArrays( int chapter_chapter_array[], int title_set_chapter_array[],
572                 int angle_angle_array[], int title_set_angle_array[],
573                 int subpicture_sub_array[], int title_set_sub_array[],
574                 int audio_audio_array[], int title_set_audio_array[],
575                 int size_size_array[], int title_set_size_array[],
576                 int channels_channel_array[], int title_set_channel_array[]) {
577
578
579         free(chapter_chapter_array);
580         free(title_set_chapter_array);
581
582         free(angle_angle_array);
583         free(title_set_angle_array);
584
585         free(subpicture_sub_array);
586         free(title_set_sub_array);
587
588         free(audio_audio_array);
589         free(title_set_audio_array);
590
591         free(size_size_array);
592         free(title_set_size_array);
593
594         free(channels_channel_array);
595         free(title_set_channel_array);
596 }
597
598
599 titles_info_t * DVDGetInfo(dvd_reader_t * _dvd) {
600
601         /* title interation */
602         int counter, i, f;
603
604         /* Our guess */
605         int candidate;
606         int multi = 0;
607         int dual = 0;
608
609
610         int titles;
611         int title_sets;
612
613         /* Arrays for chapter, angle, subpicture, audio, size, aspect, channels -  file_set relationship */
614
615         /* Size == number_of_titles */
616         int * chapter_chapter_array;
617         int * title_set_chapter_array;
618
619         int * angle_angle_array;
620         int * title_set_angle_array;
621
622         /* Size == number_of_title_sets */
623
624         int * subpicture_sub_array;
625         int * title_set_sub_array;
626
627         int * audio_audio_array;
628         int * title_set_audio_array;
629
630         int * size_size_array;
631         int * title_set_size_array;
632
633         int * channels_channel_array;
634         int * title_set_channel_array;
635
636         /* Temp helpers */
637         int channels;
638         int temp;
639         int found;
640         int chapters_1;
641         int chapters_2;
642         int found_chapter;
643         int number_of_multi;
644
645
646         /*DVD handlers*/
647         ifo_handle_t * vmg_ifo=NULL;
648         dvd_file_t   *  vts_title_file=NULL;
649
650         titles_info_t * titles_info=NULL;
651
652         /*  Open main info file */
653         vmg_ifo = ifoOpen( _dvd, 0 );
654         if( !vmg_ifo ) {
655                 fprintf( stderr, "Can't open VMG info.\n" );
656                 return (0);
657         }
658
659         titles = vmg_ifo->tt_srpt->nr_of_srpts;
660         title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;
661
662         if ((vmg_ifo->tt_srpt == 0) || (vmg_ifo->vts_atrt == 0)) {
663                 ifoClose(vmg_ifo);
664                 return(0);
665         }
666
667
668         /* Todo fix malloc check */
669         titles_info = ( titles_info_t *)malloc(sizeof(titles_info_t));
670         titles_info->titles = (titles_t *)malloc((titles)* sizeof(titles_t));
671
672         titles_info->number_of_titles = titles;
673
674
675         chapter_chapter_array = malloc(titles * sizeof(int));
676         title_set_chapter_array = malloc(titles * sizeof(int));
677
678         /*currently not used in the guessing */
679         angle_angle_array = malloc(titles * sizeof(int));
680         title_set_angle_array = malloc(titles * sizeof(int));
681
682
683         subpicture_sub_array = malloc(title_sets * sizeof(int));
684         title_set_sub_array = malloc(title_sets * sizeof(int));
685
686         audio_audio_array = malloc(title_sets * sizeof(int));
687         title_set_audio_array = malloc(title_sets * sizeof(int));
688
689         size_size_array = malloc(title_sets * sizeof(int));
690         title_set_size_array = malloc(title_sets * sizeof(int));
691
692         channels_channel_array = malloc(title_sets * sizeof(int));
693         title_set_channel_array = malloc(title_sets * sizeof(int));
694
695
696         /* Interate over the titles nr_of_srpts */
697
698
699         for (counter=0; counter < titles; counter++ )  {
700                 /* For titles_info */
701                 titles_info->titles[counter].title = counter + 1;
702                 titles_info->titles[counter].title_set = vmg_ifo->tt_srpt->title[counter].title_set_nr;
703                 titles_info->titles[counter].vts_title = vmg_ifo->tt_srpt->title[counter].vts_ttn;
704                 titles_info->titles[counter].chapters = vmg_ifo->tt_srpt->title[counter].nr_of_ptts;
705                 titles_info->titles[counter].angles = vmg_ifo->tt_srpt->title[counter].nr_of_angles;
706
707                 /* For main title*/
708                 chapter_chapter_array[counter] = vmg_ifo->tt_srpt->title[counter].nr_of_ptts;
709                 title_set_chapter_array[counter] = vmg_ifo->tt_srpt->title[counter].title_set_nr;
710                 angle_angle_array[counter] = vmg_ifo->tt_srpt->title[counter].nr_of_angles;
711                 title_set_angle_array[counter] = vmg_ifo->tt_srpt->title[counter].title_set_nr;
712         }
713
714         /* Interate over vmg_nr_of_title_sets */
715
716         for (counter=0; counter < title_sets ; counter++ )  {
717
718                 /* Picture*/
719                 subpicture_sub_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_subp_streams;
720                 title_set_sub_array[counter] = counter + 1;
721
722
723                 /* Audio */
724                 audio_audio_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_audio_streams;
725                 title_set_audio_array[counter] = counter + 1;
726
727                 channels=0;
728                 for  (i=0; i < audio_audio_array[counter]; i++) {
729                         if ( channels < vmg_ifo->vts_atrt->vts[counter].vtstt_audio_attr[i].channels + 1) {
730                                 channels = vmg_ifo->vts_atrt->vts[counter].vtstt_audio_attr[i].channels + 1;
731                         }
732
733                 }
734                 channels_channel_array[counter] = channels;
735                 title_set_channel_array[counter] = counter + 1;
736
737                 /* For tiles_info */
738                 for (f=0; f < titles_info->number_of_titles ; f++ ) {
739                         if ( titles_info->titles[f].title_set == counter + 1 ) {
740                                 titles_info->titles[f].aspect_ratio = vmg_ifo->vts_atrt->vts[counter].vtstt_vobs_video_attr.display_aspect_ratio;
741                                 titles_info->titles[f].sub_pictures = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_subp_streams;
742                                 titles_info->titles[f].audio_tracks = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_audio_streams;
743                                 titles_info->titles[f].audio_channels = channels;
744                         }
745                 }
746
747         }
748
749
750         /* Close the VMG ifo file we got all the info we need */
751         ifoClose(vmg_ifo);
752
753
754         for (counter=0; counter < title_sets; counter++ ) {
755
756                 vts_title_file = DVDOpenFile(_dvd, counter + 1, DVD_READ_TITLE_VOBS);
757
758                 if (vts_title_file  != 0) {
759                         size_size_array[counter] = DVDFileSize(vts_title_file);
760                         DVDCloseFile(vts_title_file);
761                 } else {
762                         size_size_array[counter] = 0;
763                 }
764
765                 title_set_size_array[counter] = counter + 1;
766
767
768         }
769
770
771         /* Sort all arrays max to min */
772
773         bsort_max_to_min(chapter_chapter_array, title_set_chapter_array, titles);
774         bsort_max_to_min(angle_angle_array, title_set_angle_array, titles);
775         bsort_max_to_min(subpicture_sub_array, title_set_sub_array, title_sets);
776         bsort_max_to_min(audio_audio_array, title_set_audio_array, title_sets);
777         bsort_max_to_min(size_size_array, title_set_size_array, title_sets);
778         bsort_max_to_min(channels_channel_array, title_set_channel_array, title_sets);
779
780
781         /* Check if the second biggest one actually can be a feature title */
782         /* Here we will take do biggest/second and if that is bigger than one it's not a feauture title */
783         /* Now this is simply not enough since we have to check that the diff between the two of them is small enough
784          to consider the second one a feature title we are doing two checks (biggest  + biggest - second) /second == 1
785          and biggest%second * 3 < biggest */
786
787         if ( CheckSizeArray(size_size_array, 0, 1)  == 1 ) {
788                 /* We have a dual DVD with two feature films - now lets see if they have the same amount of chapters*/
789
790                 chapters_1 = 0;
791                 for (i=0 ; i < titles ; i++ ) {
792                         if (titles_info->titles[i].title_set == title_set_size_array[0] ) {
793                                 if ( chapters_1 < titles_info->titles[i].chapters){
794                                         chapters_1 = titles_info->titles[i].chapters;
795                                 }
796                         }
797                 }
798
799                 chapters_2 = 0;
800                 for (i=0 ; i < titles ; i++ ) {
801                         if (titles_info->titles[i].title_set == title_set_size_array[1] ) {
802                                 if ( chapters_2 < titles_info->titles[i].chapters){
803                                         chapters_2 = titles_info->titles[i].chapters;
804                                 }
805                         }
806                 }
807
808                 if (  vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio ==
809                         vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio) {
810                         /* In this case it's most likely so that we have a dual film but with different context
811                         They are with in the same size range and have the same aspect ratio
812                         I would guess that such a case is e.g. a DVD containing several episodes of a TV serie*/
813                         candidate = title_set_size_array[0];
814                         multi = 1;
815                 } else if ( chapters_1 == chapters_2  && vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio !=
816                         vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio){
817                         /* 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*/
818                         if ( vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio == aspect) {
819                                 candidate = title_set_size_array[0];
820                         } else if ( vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio == aspect) {
821                                 candidate = title_set_size_array[1];
822                         } else {
823                                 /* Okay we didn't have the prefered aspect ratio - just make the biggest one a candidate */
824                                 /* please send  report if this happens*/
825                                 fprintf(stderr, "You have encountered a very special DVD, please send a bug report along with all IFO files from this title\n");
826                                 candidate = title_set_size_array[0];
827                         }
828                         dual = 1;
829                 }
830         } else {
831                 candidate = title_set_size_array[0];
832         }
833
834
835         /* Lets start checking audio,sub pictures and channels my guess is namly that a special suburb will put titles with a lot of
836          chapters just to make our backup hard */
837
838
839         found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
840                                       subpicture_sub_array, title_set_sub_array,
841                                       channels_channel_array, title_set_channel_array,
842                                       0 , candidate, title_sets);
843
844
845         /* Now lets see if we can find our candidate among the top most chapters */
846         found_chapter=6;
847         temp = chapter_chapter_array[0];
848         for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
849                 if ( candidate == title_set_chapter_array[i] ) {
850                         found_chapter=i+1;
851                         break;
852                 }
853         }
854
855
856         if (((found == 3) && (found_chapter == 1) && (dual == 0) && (multi == 0)) || ((found == 3) && (found_chapter < 3 ) && (dual == 1))) {
857
858                 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
859                                 angle_angle_array, title_set_angle_array,
860                                 subpicture_sub_array, title_set_sub_array,
861                                 audio_audio_array, title_set_audio_array,
862                                 size_size_array, title_set_size_array,
863                                 channels_channel_array, title_set_channel_array);
864                 titles_info->main_title_set = candidate;
865                 return(titles_info);
866
867         }
868
869         if (multi == 1) {
870                 for (i=0 ; i < title_sets ; ++i) {
871                         if (CheckSizeArray(size_size_array, 0, i + 1)  == 0) {
872                                         break;
873                         }
874                 }
875                 number_of_multi = i;
876                 for (i = 0; i < number_of_multi; i++ ) {
877                         if (title_set_chapter_array[0] == i + 1) {
878                                 candidate = title_set_chapter_array[0];
879                         }
880                 }
881
882                 found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
883                               subpicture_sub_array, title_set_sub_array,
884                               channels_channel_array, title_set_channel_array,
885                               0 , candidate, title_sets);
886
887                 if (found == 3) {
888                         FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
889                                         angle_angle_array, title_set_angle_array,
890                                         subpicture_sub_array, title_set_sub_array,
891                                         audio_audio_array, title_set_audio_array,
892                                         size_size_array, title_set_size_array,
893                                         channels_channel_array, title_set_channel_array);
894                         titles_info->main_title_set = candidate;
895                         return(titles_info);
896                 }
897         }
898
899         /* 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*/
900         /*No matter what we will more or less only return the biggest VOB*/
901         /* Lets see if we can find our biggest one - then we return that one */
902         candidate = title_set_size_array[0];
903
904         found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
905                                       subpicture_sub_array, title_set_sub_array,
906                                       channels_channel_array, title_set_channel_array,
907                                       0 , candidate, title_sets);
908
909         /* Now lets see if we can find our candidate among the top most chapters */
910
911         found_chapter=5;
912         temp = chapter_chapter_array[0];
913         for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
914                 if ( candidate == title_set_chapter_array[i] ) {
915                         found_chapter=i+1;
916                         break;
917                 }
918
919         }
920
921         /* Here we take chapters in to consideration*/
922         if (found == 3) {
923                 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
924                                 angle_angle_array, title_set_angle_array,
925                                 subpicture_sub_array, title_set_sub_array,
926                                 audio_audio_array, title_set_audio_array,
927                                 size_size_array, title_set_size_array,
928                                 channels_channel_array, title_set_channel_array);
929                 titles_info->main_title_set = candidate;
930                 return(titles_info);
931         }
932
933         /* Here we do but we lower the treshold for audio, sub and channels */
934
935         if ((found > 1 ) && (found_chapter <= 4)) {
936                 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
937                                 angle_angle_array, title_set_angle_array,
938                                 subpicture_sub_array, title_set_sub_array,
939                                 audio_audio_array, title_set_audio_array,
940                                 size_size_array, title_set_size_array,
941                                 channels_channel_array, title_set_channel_array);
942                 titles_info->main_title_set = candidate;
943                 return(titles_info);
944
945                 /* return it */
946         } else {
947                 /* Here we give up and just return the biggest one :(*/
948                 /* Just return the biggest badest one*/
949                 FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
950                                 angle_angle_array, title_set_angle_array,
951                                 subpicture_sub_array, title_set_sub_array,
952                                 audio_audio_array, title_set_audio_array,
953                                 size_size_array, title_set_size_array,
954                                 channels_channel_array, title_set_channel_array);
955                 titles_info->main_title_set = candidate;
956                 return(titles_info);
957         }
958
959
960         /* Some radom thoughts about DVD guessing */
961         /* We will now gather as much data about the DVD-Video as we can and
962         then make a educated guess which one is the main feature film of it*/
963
964
965         /* Make a tripple array with chapters, angles and title sets
966          - sort out dual title sets with a low number of chapters. Tradtionaly
967          the title set with most chapters is the main film. Number of angles is
968          keept as a reference point of low value*/
969
970         /* Make a dual array with number of audio streams, sub picture streams
971          and title sets. Tradtionaly the main film has many audio streams
972          since it's supposed be synconised e.g. a English film syncronised/dubbed
973          in German. We are also keeping track of sub titles since it's also indication
974          of the main film*/
975
976         /* Which title set is the biggest one - dual array with title sets and size
977          The biggest one is usally the main film*/
978
979         /* Which title set is belonging to title 1 and how many chapters has it. Once
980          again tradtionaly title one is belonging to the main film*/
981
982         /* Yes a lot of rant - but it helps me think - some sketch on paper or in the mind
983          I sketch in the comments - beside it will help you understand the code*/
984
985         /* Okay lets see if the biggest one has most chapters, it also has more subtitles
986          and audio tracks than the second one and it's title one.
987          Done it must be the main film
988
989          Hmm the biggest one doesn't have the most chapters?
990
991          See if the second one has the same amount of chapters and is the biggest one
992          If so we probably have a 4:3 and 16:9 versions of film on the same disk
993
994          Now we fetch the 16:9 by default unless the forced to do 4:3
995          First check which one is which.
996          If the 16:9 is the biggest one and has the same or more subtile, audio streams
997          then we are happy unless we are in force 4:3 mode :(
998          The same goes in reverse if we are in force 4:3 mode
999
1000
1001          Hmm, in force 4:3 mode - now we check how much smaller than the biggest one it is
1002          (or the reverse if we are in 16:9 mode)
1003
1004          Generally a reverse division should render in 1 and with a small modulo - like wise
1005          a normal modulo should give us a high modulo
1006
1007          If we get more than one it's of cource a fake however if we get just one we still need to check
1008          if we subtract the smaller one from the bigger one we should end up with a small number - hence we
1009          need to multiply it more than 4 times to get it bigger than the biggest one. Now we know that the
1010          two biggest once are really big and possibly carry the same film in differnet formats.
1011
1012          We will now return the prefered one either 16:9 or 4:3 but we will first check that the one
1013          we return at lest has two or more audio tracks. We don't want it if the other one has a lot
1014          more sound (we may end up with a film that only has 2ch Dolby Digital so we want to check for
1015          6ch DTS or Dolby Digital. If the prefered one doesn't have those features but the other once has
1016          we will return the other one.
1017          */
1018
1019 }
1020
1021
1022
1023
1024 int DVDCopyTileVobX(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, int vob, char * targetdir,char * title_name) {
1025
1026         /* Loop variable */
1027         int i;
1028
1029         /* Temp filename,dirname */
1030         char targetname[PATH_MAX];
1031         struct stat fileinfo;
1032
1033         /* Write buffer */
1034
1035         unsigned char * buffer=NULL;
1036         unsigned char buffy; /* :-) */
1037
1038         /* File Handler */
1039         int streamout;
1040
1041         int size;
1042         int left;
1043
1044         /* Buffer size in DVD sectors */
1045         /* Currently set to 1MB */
1046         int buff = 512;
1047         int offset = 0;
1048         int tsize;
1049
1050         /* DVD handler */
1051         dvd_file_t   *  dvd_file=NULL;
1052
1053         if (title_set_info->number_of_title_sets + 1 < title_set) {
1054                 fprintf(stderr,"Faild num title test\n");
1055                 return(1);
1056         }
1057
1058         if (title_set_info->title_set[title_set].number_of_vob_files < vob ) {
1059                 fprintf(stderr,"Faild vob test\n");
1060                 return(1);
1061         }
1062
1063         if (title_set_info->title_set[title_set].size_vob[0] == 0 ) {
1064                 fprintf(stderr,"Faild vob 1 size test\n");
1065                 return(0);
1066         } else if (title_set_info->title_set[title_set].size_vob[vob - 1] == 0 ) {
1067                 fprintf(stderr,"Faild vob %d test\n", vob);
1068                 return(0);
1069         } else {
1070                 size = title_set_info->title_set[title_set].size_vob[vob - 1]/2048;
1071                 if (title_set_info->title_set[title_set].size_vob[vob - 1]%2048 != 0) {
1072                         fprintf(stderr, "The Title VOB number %d of title set %d doesn't have a valid DVD size\n", vob, title_set);
1073                         return(1);
1074                 }
1075         }
1076 #ifdef DEBUG
1077         fprintf(stderr,"After we check the vob it self %d\n", vob);
1078 #endif
1079
1080         /* Create VTS_XX_X.VOB */
1081         if (title_set == 0) {
1082                 fprintf(stderr,"Don't try to copy a Title VOB from the VMG domain there aren't any\n");
1083                 return(1);
1084         } else {
1085                 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
1086         }
1087
1088
1089
1090         /* Now figure out the offset we will start at also check that the previus files are of valid DVD size */
1091         for ( i = 0; i < vob - 1; i++ ) {
1092                 tsize = title_set_info->title_set[title_set].size_vob[i];
1093                 if (tsize%2048 != 0) {
1094                         fprintf(stderr, "The Title VOB number %d of title set %d doesn't have a valid DVD size\n", i + 1, title_set);
1095                         return(1);
1096                 } else {
1097                         offset = offset + tsize/2048;
1098                 }
1099         }
1100 #ifdef DEBUG
1101         fprintf(stderr,"The offset for vob %d is %d\n", vob, offset);
1102 #endif
1103
1104
1105         if (stat(targetname, &fileinfo) == 0) {
1106                 fprintf(stderr, "The Title file %s exists will try to over write it.\n", targetname);
1107                 if (! S_ISREG(fileinfo.st_mode)) {
1108                         fprintf(stderr,"The Title %s file is not valid, it may be a directory\n", targetname);
1109                         return(1);
1110                 } else {
1111                         if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
1112                                 fprintf(stderr, "Error opening %s\n", targetname);
1113                                 perror("");
1114                                 return(1);
1115                         }
1116                 }
1117         } else {
1118                 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
1119                         fprintf(stderr, "Error creating %s\n", targetname);
1120                         perror("");
1121                         return(1);
1122                 }
1123         }
1124
1125         left = size;
1126
1127         if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(buffy))) == NULL) {
1128                 fprintf(stderr, "Out of memory coping %s\n", targetname);
1129                 close(streamout);
1130                 return(1);
1131         }
1132
1133
1134         if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
1135                 fprintf(stderr, "Faild opending TITLE VOB\n");
1136                 free(buffer);
1137                 close(streamout);
1138                 return(1);
1139         }
1140
1141         while( left > 0 ) {
1142
1143                 if (buff > left) {
1144                         buff = left;
1145                 }
1146                 if ( DVDReadBlocks(dvd_file,offset,buff, buffer) != buff) {
1147                         fprintf(stderr, "Error reading MENU VOB\n");
1148                         free(buffer);
1149                         DVDCloseFile(dvd_file);
1150                         close(streamout);
1151                         return(1);
1152                 }
1153
1154
1155                 if (write(streamout,buffer,buff *  2048) != buff * 2048) {
1156                         fprintf(stderr, "Error writing TITLE VOB\n");
1157                         free(buffer);
1158                         close(streamout);
1159                         return(1);
1160                 }
1161
1162                 offset = offset + buff;
1163                 left = left - buff;
1164
1165         }
1166
1167         DVDCloseFile(dvd_file);
1168         free(buffer);
1169         close(streamout);
1170         return(0);
1171
1172 }
1173
1174
1175
1176
1177 int DVDCopyMenu(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, char * targetdir,char * title_name) {
1178
1179         /* Temp filename,dirname */
1180         char targetname[PATH_MAX];
1181         struct stat fileinfo;
1182
1183         /* Write buffer */
1184
1185         unsigned char * buffer=NULL;
1186         unsigned char buffy; /* :-) */
1187
1188         /* File Handler */
1189         int streamout;
1190
1191         int size;
1192         int left;
1193
1194         /* Buffer size in DVD sectors */
1195         /* Currently set to 1MB */
1196         int buff = 512;
1197         int offset = 0;
1198
1199
1200         /* DVD handler */
1201         dvd_file_t   *  dvd_file=NULL;
1202
1203         if (title_set_info->number_of_title_sets + 1 < title_set) {
1204                 return(1);
1205         }
1206
1207         if (title_set_info->title_set[title_set].size_menu == 0 ) {
1208                 return(0);
1209         } else {
1210                 size = title_set_info->title_set[title_set].size_menu/2048;
1211                 if (title_set_info->title_set[title_set].size_menu%2048 != 0) {
1212                         fprintf(stderr, "The Menu VOB of title set %d doesn't have a valid DVD size\n", title_set);
1213                         return(1);
1214                 }
1215         }
1216
1217         /* Create VIDEO_TS.VOB or VTS_XX_0.VOB */
1218         if (title_set == 0) {
1219                 sprintf(targetname,"%s/%s/VIDEO_TS/VIDEO_TS.VOB",targetdir, title_name);
1220         } else {
1221                 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_0.VOB",targetdir, title_name, title_set);
1222         }
1223
1224
1225         if (stat(targetname, &fileinfo) == 0) {
1226                 fprintf(stderr, "The Menu file %s exists will try to over write it.\n", targetname);
1227                 if (! S_ISREG(fileinfo.st_mode)) {
1228                         fprintf(stderr,"The Menu %s file is not valid, it may be a directory\n", targetname);
1229                         return(1);
1230                 } else {
1231                         if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
1232                                 fprintf(stderr, "Error opening %s\n", targetname);
1233                                 perror("");
1234                                 return(1);
1235                         }
1236                 }
1237         } else {
1238                 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
1239                         fprintf(stderr, "Error creating %s\n", targetname);
1240                         perror("");
1241                         return(1);
1242                 }
1243         }
1244
1245         left = size;
1246
1247         if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(buffy))) == NULL) {
1248                 fprintf(stderr, "Out of memory coping %s\n", targetname);
1249                 close(streamout);
1250                 return(1);
1251         }
1252
1253
1254         if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_MENU_VOBS))== 0) {
1255                 fprintf(stderr, "Faild opending MENU VOB\n");
1256                 free(buffer);
1257                 close(streamout);
1258                 return(1);
1259         }
1260
1261         while( left > 0 ) {
1262
1263                 if (buff > left) {
1264                         buff = left;
1265                 }
1266                 if ( DVDReadBlocks(dvd_file,offset,buff, buffer) != buff) {
1267                         fprintf(stderr, "Error reading MENU VOB\n");
1268                         free(buffer);
1269                         DVDCloseFile(dvd_file);
1270                         close(streamout);
1271                         return(1);
1272                 }
1273
1274
1275                 if (write(streamout,buffer,buff *  2048) != buff * 2048) {
1276                         fprintf(stderr, "Error writing MENU VOB\n");
1277                         free(buffer);
1278                         close(streamout);
1279                         return(1);
1280                 }
1281
1282                 offset = offset + buff;
1283                 left = left - buff;
1284
1285         }
1286
1287         DVDCloseFile(dvd_file);
1288         free(buffer);
1289         close(streamout);
1290         return(0);
1291
1292 }
1293
1294
1295 int DVDCopyIfoBup (dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, char * targetdir,char * title_name) {
1296
1297         /* Temp filename,dirname */
1298         char targetname[PATH_MAX];
1299         struct stat fileinfo;
1300
1301         /* Write buffer */
1302
1303         unsigned char * buffer=NULL;
1304         unsigned char buffy; /* :-) */
1305
1306         /* File Handler */
1307         int streamout;
1308
1309         int size;
1310
1311         /* DVD handler */
1312         dvd_file_t   *  dvd_file=NULL;
1313
1314
1315         if (title_set_info->number_of_title_sets + 1 < title_set) {
1316                 return(1);
1317         }
1318
1319         if (title_set_info->title_set[title_set].size_ifo == 0 ) {
1320                 return(0);
1321         } else {
1322                 size = title_set_info->title_set[title_set].size_ifo;
1323                 if (title_set_info->title_set[title_set].size_ifo%2048 != 0) {
1324                         fprintf(stderr, "The IFO of title set %d doesn't have a valid DVD size\n", title_set);
1325                         return(1);
1326                 }
1327         }
1328
1329         /* Create VIDEO_TS.IFO or VTS_XX_0.IFO */
1330
1331         if (title_set == 0) {
1332                 sprintf(targetname,"%s/%s/VIDEO_TS/VIDEO_TS.IFO",targetdir, title_name);
1333         } else {
1334                 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_0.IFO",targetdir, title_name, title_set);
1335         }
1336
1337         if (stat(targetname, &fileinfo) == 0) {
1338                 fprintf(stderr, "The IFO file %s exists will try to over write it.\n", targetname);
1339                 if (! S_ISREG(fileinfo.st_mode)) {
1340                         fprintf(stderr,"The IFO %s file is not valid, it may be a directory\n", targetname);
1341                         return(1);
1342                 } else {
1343                         if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
1344                                 fprintf(stderr, "Error opening %s\n", targetname);
1345                                 perror("");
1346                                 return(1);
1347                         }
1348                 }
1349         } else {
1350                 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
1351                         fprintf(stderr, "Error creating %s\n", targetname);
1352                         perror("");
1353                         return(1);
1354                 }
1355         }
1356
1357         /* Copy VIDEO_TS.IFO, since it's a small file try to copy it in one shot */
1358
1359
1360         if ((buffer = (unsigned char *)malloc(size * sizeof(buffy))) == NULL) {
1361                 fprintf(stderr, "Out of memory coping %s\n", targetname);
1362                 close(streamout);
1363                 return(1);
1364         }
1365
1366
1367         if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_INFO_FILE))== 0) {
1368                 fprintf(stderr, "Faild opending IFO for tile set %d\n", title_set);
1369                 free(buffer);
1370                 close(streamout);
1371                 return(1);
1372         }
1373
1374         if ( DVDReadBytes(dvd_file,buffer,size) != size) {
1375                 fprintf(stderr, "Error reading IFO for title set %d\n", title_set);
1376                 free(buffer);
1377                 DVDCloseFile(dvd_file);
1378                 close(streamout);
1379                 return(1);
1380         }
1381
1382         DVDCloseFile(dvd_file);
1383
1384         if (write(streamout,buffer,size) != size) {
1385                 fprintf(stderr, "Error writing %s\n",targetname);
1386                 free(buffer);
1387                 close(streamout);
1388                 return(1);
1389         }
1390
1391         free(buffer);
1392         close(streamout);
1393
1394
1395         /* Create VIDEO_TS.BUP or VTS_XX_0.BUP */
1396
1397         if (title_set == 0) {
1398                 sprintf(targetname,"%s/%s/VIDEO_TS/VIDEO_TS.BUP",targetdir, title_name);
1399         } else {
1400                 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_0.BUP",targetdir, title_name, title_set);
1401         }
1402
1403
1404         if (title_set_info->title_set[title_set].size_bup == 0 ) {
1405                 return(0);
1406         } else {
1407                 size = title_set_info->title_set[title_set].size_bup;
1408                 if (title_set_info->title_set[title_set].size_bup%2048 != 0) {
1409                         fprintf(stderr, "The BUP of title set %d doesn't have a valid DVD size\n", title_set);
1410                         return(1);
1411                 }
1412         }
1413
1414
1415         if (stat(targetname, &fileinfo) == 0) {
1416                 fprintf(stderr, "The BUP file %s exists will try to over write it.\n", targetname);
1417                 if (! S_ISREG(fileinfo.st_mode)) {
1418                         fprintf(stderr,"The BUP %s file is not valid, it may be a directory\n", targetname);
1419                         return(1);
1420                 } else {
1421                         if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
1422                                 fprintf(stderr, "Error opening %s\n", targetname);
1423                                 perror("");
1424                                 return(1);
1425                         }
1426                 }
1427         } else {
1428                 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
1429                         fprintf(stderr, "Error creating %s\n", targetname);
1430                         perror("");
1431                         return(1);
1432                 }
1433         }
1434
1435
1436
1437         /* Copy VIDEO_TS.BUP or VTS_XX_0.BUP, since it's a small file try to copy it in one shot */
1438
1439         if ((buffer = (unsigned char *)malloc(size * sizeof(buffy))) == NULL) {
1440                 fprintf(stderr, "Out of memory coping %s\n", targetname);
1441                 close(streamout);
1442                 return(1);
1443         }
1444
1445
1446         if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_INFO_BACKUP_FILE))== 0) {
1447                 fprintf(stderr, "Faild opending BUP for title set %d\n", title_set);
1448                 free(buffer);
1449                 close(streamout);
1450                 return(1);
1451         }
1452
1453         if ( DVDReadBytes(dvd_file,buffer,size) != size) {
1454                 fprintf(stderr, "Error reading BUP for title set %d\n", title_set);
1455                 free(buffer);
1456                 DVDCloseFile(dvd_file);
1457                 close(streamout);
1458                 return(1);
1459         }
1460
1461         DVDCloseFile(dvd_file);
1462
1463         if (write(streamout,buffer,size) != size) {
1464                 fprintf(stderr, "Error writing %s\n", targetname);
1465                 free(buffer);
1466                 close(streamout);
1467                 return(1);
1468         }
1469
1470         free(buffer);
1471         close(streamout);
1472
1473         return(0);
1474 }
1475
1476
1477 int DVDMirrorVMG(dvd_reader_t * dvd, title_set_info_t *  title_set_info,char * targetdir,char * title_name){
1478
1479         if ( DVDCopyIfoBup(dvd, title_set_info, 0, targetdir, title_name) != 0 ) {
1480                 return(1);
1481         }
1482
1483         if ( DVDCopyMenu(dvd, title_set_info, 0, targetdir, title_name) != 0 ) {
1484                 return(1);
1485         }
1486         return(0);
1487 }
1488
1489 int DVDMirrorTitleX(dvd_reader_t * dvd, title_set_info_t *  title_set_info, int title_set, char * targetdir,char * title_name) {
1490
1491         /* Loop through the vobs */
1492         int i;
1493
1494
1495
1496         if ( DVDCopyIfoBup(dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
1497                 return(1);
1498         }
1499
1500         if ( DVDCopyMenu(dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
1501                 return(1);
1502         }
1503
1504         for (i = 0; i < title_set_info->title_set[title_set].number_of_vob_files ; i++) {
1505 #ifdef DEBUG
1506                 fprintf(stderr,"In the VOB copy loop for %d\n", i);
1507 #endif          
1508                 if ( DVDCopyTileVobX(dvd, title_set_info, title_set, i + 1, targetdir, title_name) != 0 ) {
1509                 return(1);
1510                 }
1511         }
1512
1513
1514         return(0);
1515 }
1516
1517 int DVDGetTitleName(const char *device, char *title)
1518 {
1519         /* Variables for filehandel and title string interaction */
1520
1521         int  filehandle, i, last;
1522
1523         /* Open DVD device */
1524
1525         if ( !(filehandle = open(device, O_RDONLY)) ) {
1526                 fprintf(stderr, "Can't open secified device %s - check your DVD device\n", device);
1527                 return(1);
1528         }
1529
1530         /* Seek to title of first track, which is at (track_no * 32768) + 40 */
1531
1532         if ( 32808 != lseek(filehandle, 32808, SEEK_SET) ) {
1533                 close(filehandle);
1534                 fprintf(stderr, "Can't seek DVD device %s - check your DVD device\n", device);
1535                 return(1);
1536         }
1537
1538         /* Read the DVD-Video title */
1539
1540         if ( 32 != read(filehandle, title, 32)) {
1541                 close(filehandle);
1542                 fprintf(stderr, "Can't read title from DVD device %s\n", device);
1543                 return(1);
1544         }
1545
1546         /* Terminate the title string */
1547
1548         title[32] = '\0';
1549
1550
1551         /* Remove trailing white space */
1552
1553         last = 32;
1554         for ( i = 0; i < 32; i++ ) {
1555                 if ( title[i] != ' ' ) { last = i; }
1556         }
1557
1558         title[last + 1] = '\0';
1559
1560         return(0);
1561 }
1562
1563
1564
1565 void bsort_min_to_max(int sector[], int title[], int size){
1566
1567         int temp_title, temp_sector, i, j;
1568
1569         for ( i=0; i < size ; i++ ) {
1570           for ( j=0; j < size ; j++ ) {
1571                 if (sector[i] < sector[j]) {
1572                         temp_sector = sector[i];
1573                         temp_title = title[i];
1574                         sector[i] = sector[j];
1575                         title[i] = title[j];
1576                         sector[j] = temp_sector;
1577                         title[j] = temp_title;
1578                 }
1579           }
1580         }
1581 }
1582
1583 void bsort_max_to_min(int sector[], int title[], int size){
1584
1585         int temp_title, temp_sector, i, j;
1586
1587         for ( i=0; i < size ; i++ ) {
1588           for ( j=0; j < size ; j++ ) {
1589                 if (sector[i] > sector[j]) {
1590                         temp_sector = sector[i];
1591                         temp_title = title[i];
1592                         sector[i] = sector[j];
1593                         title[i] = title[j];
1594                         sector[j] = temp_sector;
1595                         title[j] = temp_title;
1596                 }
1597           }
1598         }
1599 }
1600
1601
1602
1603 void uniq(int sector[], int title[], int title_sets_array[], int sector_sets_array[], int titles){
1604         int  i, j;
1605
1606
1607         for ( i=0, j=0; j < titles;) {
1608                 if (sector[j] != sector[j+1]) {
1609                         title_sets_array[i]  = title[j];
1610                         sector_sets_array[i] = sector[j];
1611                         i++ ;
1612                         j++ ;
1613                 } else {
1614                         do {
1615                              if (j < titles) {
1616                                 j++ ;
1617                            }
1618                         } while ( sector[j] == sector[j+1] );
1619
1620                 }
1621         }
1622
1623 }
1624
1625 void align_end_sector(int cell_start_sector[],int cell_end_sector[], int size) {
1626
1627         int i;
1628
1629         for (i = 0; i < size  - 1 ; i++) {
1630                 if ( cell_end_sector[i] >= cell_start_sector[i + 1] ) {
1631                         cell_end_sector[i] = cell_start_sector[i + 1] - 1;
1632                 }
1633         }
1634 }
1635
1636
1637
1638
1639 void DVDFreeTitleSetInfo(title_set_info_t * title_set_info) {
1640         free(title_set_info->title_set);
1641         free(title_set_info);
1642 }
1643
1644 void DVDFreeTitlesInfo(titles_info_t * titles_info) {
1645         free(titles_info->titles);
1646         free(titles_info);
1647 }
1648
1649
1650
1651 title_set_info_t *DVDGetFileSet(dvd_reader_t * _dvd) {
1652
1653         /* title interation */
1654         int title_sets, counter, i;
1655
1656
1657         /* DVD Video files */
1658         char    filename[MAXNAME];
1659         int     size;
1660
1661         /*DVD ifo handler*/
1662         ifo_handle_t *  vmg_ifo=NULL;
1663
1664         /* The Title Set Info struct*/
1665         title_set_info_t * title_set_info;
1666
1667         /*  Open main info file */
1668         vmg_ifo = ifoOpen( _dvd, 0 );
1669         if( !vmg_ifo ) {
1670                 fprintf( stderr, "Can't open VMG info.\n" );
1671                 return (0);
1672         }
1673
1674
1675         title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;
1676
1677         /* Close the VMG ifo file we got all the info we need */
1678         ifoClose(vmg_ifo);
1679
1680         /* Todo fix malloc check */
1681         title_set_info = (title_set_info_t *)malloc(sizeof(title_set_info_t));
1682         title_set_info->title_set = (title_set_t *)malloc((title_sets + 1)* sizeof(title_set_t));
1683
1684         title_set_info->number_of_title_sets = title_sets;
1685
1686
1687         /* Find VIDEO_TS.IFO is present - must be present since we did a ifo open 0*/
1688
1689         sprintf(filename,"/VIDEO_TS/VIDEO_TS.IFO");
1690
1691         if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1692                 title_set_info->title_set[0].size_ifo = size;
1693         } else {
1694                 DVDFreeTitleSetInfo(title_set_info);
1695                 return(0);
1696         }
1697
1698
1699
1700         /* Find VIDEO_TS.VOB if present*/
1701
1702         sprintf(filename,"/VIDEO_TS/VIDEO_TS.VOB");
1703
1704         if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1705                 title_set_info->title_set[0].size_menu = size;
1706         } else {
1707                 title_set_info->title_set[0].size_menu = 0 ;
1708         }
1709
1710         /* Find VIDEO_TS.BUP if present */
1711
1712         sprintf(filename,"/VIDEO_TS/VIDEO_TS.BUP");
1713
1714         if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1715                 title_set_info->title_set[0].size_bup = size;
1716         } else {
1717                 DVDFreeTitleSetInfo(title_set_info);
1718                 return(0);
1719         }
1720
1721         if (title_set_info->title_set[0].size_ifo != title_set_info->title_set[0].size_bup) {
1722                 fprintf(stderr,"BUP and IFO size not the same be warened!\n");
1723         }
1724
1725
1726         /* Take care of the titles which we don't have in VMG */
1727
1728         title_set_info->title_set[0].number_of_vob_files = 0;
1729         title_set_info->title_set[0].size_vob[0] = 0;
1730
1731
1732         if ( verbose > 0 ){
1733                 fprintf(stderr,"\n\n\nFile sizes for Title set 0 VIDEO_TS.XXX\n");
1734                 fprintf(stderr,"IFO = %d, MENU_VOB = %d, BUP = %d\n",title_set_info->title_set[0].size_ifo, title_set_info->title_set[0].size_menu, title_set_info->title_set[0].size_bup );
1735
1736         }
1737
1738
1739         if ( title_sets >= 1 ) {
1740                 for (counter=0; counter < title_sets; counter++ ){
1741
1742                         if ( verbose > 1 ){
1743                                 fprintf(stderr,"At top of loop\n");
1744                         }
1745
1746
1747                         sprintf(filename,"/VIDEO_TS/VTS_%02i_0.IFO",counter + 1);
1748
1749                         if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1750                                 title_set_info->title_set[counter + 1].size_ifo = size;
1751                         } else {
1752                                 DVDFreeTitleSetInfo(title_set_info);
1753                                 return(0);
1754                         }
1755
1756                         if ( verbose > 1 ){
1757                                 fprintf(stderr,"After opening files\n");
1758                         }
1759
1760
1761                         /* Find VTS_XX_0.VOB if present*/
1762
1763                         sprintf(filename,"/VIDEO_TS/VTS_%02i_0.VOB", counter + 1);
1764
1765                         if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1766                                 title_set_info->title_set[counter + 1].size_menu = size;
1767                         } else {
1768                                 title_set_info->title_set[counter + 1].size_menu = 0 ;
1769                         }
1770
1771
1772                         if ( verbose > 1 ){
1773                                 fprintf(stderr,"After Menu VOB check\n");
1774                         }
1775
1776
1777                         /* Find all VTS_XX_[1 to 9].VOB files if they are present*/
1778
1779                         for( i = 0; i < 9; ++i ) {
1780                                 sprintf(filename,"/VIDEO_TS/VTS_%02i_%i.VOB", counter + 1, i + 1 );
1781                                 if(UDFFindFile(_dvd, filename, &size) == 0 ) {
1782                                         break;
1783                                 }
1784                                 title_set_info->title_set[counter + 1].size_vob[i] = size;
1785                         }
1786                         title_set_info->title_set[counter + 1].number_of_vob_files = i;
1787
1788                         if ( verbose > 1 ){
1789                                 fprintf(stderr,"After Menu Title VOB check\n");
1790                         }
1791
1792
1793                         sprintf(filename,"/VIDEO_TS/VTS_%02i_0.BUP", counter + 1);
1794
1795                         if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1796                                 title_set_info->title_set[counter +1].size_bup = size;
1797                         } else {
1798                                 DVDFreeTitleSetInfo(title_set_info);
1799                                 return(0);
1800                         }
1801
1802                         if (title_set_info->title_set[counter +1].size_ifo != title_set_info->title_set[counter + 1].size_bup) {
1803                                 fprintf(stderr,"BUP and IFO size for fileset %d is not the same be warened!\n", counter + 1);
1804                         }
1805
1806
1807
1808                         if ( verbose > 1 ){
1809                                 fprintf(stderr,"After Menu Title BUP check\n");
1810                         }
1811
1812
1813                         if ( verbose > 0 ) {
1814                                 fprintf(stderr,"\n\n\nFile sizes for Title set %d i.e.VTS_%02d_X.XXX\n", counter + 1, counter + 1);
1815                                 fprintf(stderr,"IFO: %d, MENU: %d\n", title_set_info->title_set[counter +1].size_ifo, title_set_info->title_set[counter +1].size_menu);
1816                                 for (i = 0; i < title_set_info->title_set[counter + 1].number_of_vob_files ; i++) {
1817                                         fprintf(stderr, "VOB %d is %d\n", i + 1, title_set_info->title_set[counter + 1].size_vob[i]);
1818                                 }
1819                                 fprintf(stderr,"BUP: %d\n",title_set_info->title_set[counter +1].size_bup);
1820                         }
1821
1822                         if ( verbose > 1 ){
1823                                 fprintf(stderr,"Bottom of loop \n");
1824                         }
1825                 }
1826
1827         }
1828
1829         /* Return the info */
1830         return(title_set_info);
1831
1832
1833 }
1834
1835 int DVDMirror(dvd_reader_t * _dvd, char * targetdir,char * title_name) {
1836
1837         int i;
1838         title_set_info_t * title_set_info=NULL;
1839
1840         title_set_info = DVDGetFileSet(_dvd);
1841         if (!title_set_info) {
1842                 DVDClose(_dvd);
1843                 return(1);
1844         }
1845
1846         if ( DVDMirrorVMG(_dvd, title_set_info, targetdir, title_name) != 0 ) {
1847                 fprintf(stderr,"Mirror of VMG faild\n");
1848                 DVDFreeTitleSetInfo(title_set_info);
1849                 return(1);
1850         }
1851
1852         for ( i=0; i < title_set_info->number_of_title_sets; i++) {
1853                 if ( DVDMirrorTitleX(_dvd, title_set_info, i + 1, targetdir, title_name) != 0 ) {
1854                         fprintf(stderr,"Mirror of Title set %d faild\n", i + 1);
1855                         DVDFreeTitleSetInfo(title_set_info);
1856                         return(1);
1857                 }
1858         }
1859         return(0);
1860 }
1861
1862 int DVDMirrorTitleSet(dvd_reader_t * _dvd, char * targetdir,char * title_name, int title_set) {
1863
1864         title_set_info_t * title_set_info=NULL;
1865
1866
1867 #ifdef DEBUG
1868         fprintf(stderr,"In DVDMirrorTitleSet\n");
1869 #endif
1870
1871         title_set_info = DVDGetFileSet(_dvd);
1872
1873         if (!title_set_info) {
1874                 DVDClose(_dvd);
1875                 return(1);
1876         }
1877
1878         if ( title_set > title_set_info->number_of_title_sets ) {
1879                 fprintf(stderr, "Can't copy title_set %d there is only %d title_sets present on this DVD\n", title_set, title_set_info->number_of_title_sets);
1880                 DVDFreeTitleSetInfo(title_set_info);
1881                 return(1);
1882         }
1883
1884         if ( title_set == 0 ) {
1885                 if ( DVDMirrorVMG(_dvd, title_set_info, targetdir, title_name) != 0 ) {
1886                         fprintf(stderr,"Mirror of Title set 0 (VMG) faild\n");
1887                         DVDFreeTitleSetInfo(title_set_info);
1888                         return(1);
1889                 }
1890         } else {
1891                 if ( DVDMirrorTitleX(_dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
1892                         fprintf(stderr,"Mirror of Title set %d faild\n", title_set);
1893                         DVDFreeTitleSetInfo(title_set_info);
1894                         return(1);
1895                 }
1896         }
1897         DVDFreeTitleSetInfo(title_set_info);
1898         return(0);
1899 }
1900
1901 int DVDMirrorMainFeature(dvd_reader_t * _dvd, char * targetdir,char * title_name) {
1902
1903         title_set_info_t * title_set_info=NULL;
1904         titles_info_t * titles_info=NULL;
1905
1906
1907         titles_info = DVDGetInfo(_dvd);
1908         if (!titles_info) {
1909                 fprintf(stderr, "Guess work of main feature film faild\n");
1910                 return(1);
1911         }
1912
1913         title_set_info = DVDGetFileSet(_dvd);
1914         if (!title_set_info) {
1915                 DVDFreeTitlesInfo(titles_info);
1916                 return(1);
1917         }
1918
1919         if ( DVDMirrorTitleX(_dvd, title_set_info, titles_info->main_title_set, targetdir, title_name) != 0 ) {
1920                 fprintf(stderr,"Mirror of main featur file which is title set %d faild\n", titles_info->main_title_set);
1921                 DVDFreeTitleSetInfo(title_set_info);
1922                 return(1);
1923         }
1924
1925         DVDFreeTitlesInfo(titles_info);
1926         DVDFreeTitleSetInfo(title_set_info);
1927         return(0);
1928 }
1929
1930
1931 int DVDMirrorChapters(dvd_reader_t * _dvd, char * targetdir,char * title_name, int start_chapter,int  end_chapter, int titles) {
1932
1933
1934         int result;
1935         int chapters = 0;
1936         int feature;
1937         int i, s;
1938         int spg, epg;
1939         int pgc;
1940         int start_cell, end_cell;
1941         int vts_title;
1942
1943         title_set_info_t * title_set_info=NULL;
1944         titles_info_t * titles_info=NULL;
1945         ifo_handle_t * vts_ifo_info=NULL;
1946         int * cell_start_sector=NULL;
1947         int * cell_end_sector=NULL;
1948
1949         /* To do free memory*/
1950
1951         titles_info = DVDGetInfo(_dvd);
1952         if (!titles_info) {
1953                 fprintf(stderr, "Faild to obtain titles information\n");
1954                 return(1);
1955         }
1956
1957         title_set_info = DVDGetFileSet(_dvd);
1958         if (!title_set_info) {
1959                 DVDFreeTitlesInfo(titles_info);
1960                 return(1);
1961         }
1962
1963         if(titles == 0) {
1964                 fprintf(stderr, "No title specified for chapter extraction, will try to figure out main feature title\n");
1965                 feature = titles_info->main_title_set;
1966                 for (i=0; i < titles_info->number_of_titles ; i++ ) {
1967                         if ( titles_info->titles[i].title_set == titles_info->main_title_set ) {
1968                                 if(chapters < titles_info->titles[i].chapters) {
1969                                         chapters = titles_info->titles[i].chapters;
1970                                         titles = i + 1;
1971                                 }
1972                         }
1973                 }
1974         }
1975
1976         vts_ifo_info = ifoOpen(_dvd, titles_info->titles[titles - 1].title_set);
1977         if(!vts_ifo_info) {
1978                 fprintf(stderr, "Coundn't open tile_set %d IFO file\n", titles_info->titles[titles - 1].title_set);
1979                 DVDFreeTitlesInfo(titles_info);
1980                 DVDFreeTitleSetInfo(title_set_info);
1981                 return(1);
1982         }
1983
1984         vts_title = titles_info->titles[titles - 1].vts_title;
1985
1986         if (end_chapter > titles_info->titles[titles - 1].chapters) {
1987                 end_chapter = titles_info->titles[titles - 1].chapters;
1988                 fprintf(stderr, "Turncated the end_chapter only %d chapters in %d title\n", end_chapter,titles);
1989         }
1990
1991         if (start_chapter > titles_info->titles[titles - 1].chapters) {
1992                 start_chapter = titles_info->titles[titles - 1].chapters;
1993                 fprintf(stderr, "Turncated the end_chapter only %d chapters in %d title\n", end_chapter,titles);
1994         }
1995
1996
1997
1998         /* We assume the same PGC for the whole title - this is not true and need to be fixed later on */
1999
2000         pgc = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgcn;
2001
2002
2003         /* Lookup  PG for start chapter */
2004
2005         spg = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgn;
2006
2007         /* Look up start cell for this pgc/pg */
2008
2009         start_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[spg - 1];
2010
2011
2012         /* Lookup end cell*/
2013
2014
2015         if ( end_chapter < titles_info->titles[titles - 1].chapters ) {
2016                 epg = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[end_chapter].pgn;
2017 #ifdef DEBUG
2018                 fprintf(stderr,"DVDMirrorChapter: epg %d\n", epg);
2019 #endif
2020
2021                 end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[epg -1] - 1;
2022 #ifdef DEBUG
2023                 fprintf(stderr,"DVDMirrorChapter: end cell adjusted %d\n", end_cell);
2024 #endif
2025
2026         } else {
2027
2028                 end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->nr_of_cells;
2029 #ifdef DEBUG
2030                 fprintf(stderr,"DVDMirrorChapter: end cell adjusted 2 %d\n",end_cell);
2031 #endif
2032
2033         }
2034
2035 #ifdef DEBUG
2036         fprintf(stderr,"DVDMirrorChapter: star cell %d\n", start_cell);
2037 #endif
2038
2039
2040         /* Put all the cells start and end sector in a dual array */
2041
2042         cell_start_sector = (int *)malloc( (end_cell - start_cell + 1) * sizeof(int));
2043         if(!cell_start_sector) {
2044                 fprintf(stderr,"Memory allocation error 1\n");
2045                 DVDFreeTitlesInfo(titles_info);
2046                 DVDFreeTitleSetInfo(title_set_info);
2047                 ifoClose(vts_ifo_info);
2048                 return(1);
2049         }
2050         cell_end_sector = (int *)malloc( (end_cell - start_cell + 1) * sizeof(int));
2051         if(!cell_end_sector) {
2052                 fprintf(stderr,"Memory allocation error\n");
2053                 DVDFreeTitlesInfo(titles_info);
2054                 DVDFreeTitleSetInfo(title_set_info);
2055                 ifoClose(vts_ifo_info);
2056                 free(cell_start_sector);
2057                 return(1);
2058         }
2059 #ifdef DEBUG
2060         fprintf(stderr,"DVDMirrorChapter: start cell is %d\n", start_cell);
2061         fprintf(stderr,"DVDMirrorChapter: end cell is %d\n", end_cell);
2062         fprintf(stderr,"DVDMirrorChapter: pgc is %d\n", pgc);
2063 #endif
2064
2065         for (i=0, s=start_cell; s < end_cell +1 ; i++, s++) {
2066
2067                 cell_start_sector[i] =  vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].first_sector;
2068                 cell_end_sector[i] =  vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].last_sector;
2069 #ifdef DEBUG
2070                 fprintf(stderr,"DVDMirrorChapter: S is %d\n", s);
2071                 fprintf(stderr,"DVDMirrorChapter: start sector %d\n", vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].first_sector);
2072                 fprintf(stderr,"DVDMirrorChapter: end sector %d\n", vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].last_sector);
2073 #endif
2074         }
2075
2076         bsort_min_to_max(cell_start_sector, cell_end_sector, end_cell - start_cell + 1);
2077
2078         align_end_sector(cell_start_sector, cell_end_sector,end_cell - start_cell + 1);
2079
2080 #ifdef DEBUG
2081         for (i=0 ; i < end_cell - start_cell + 1; i++) {
2082                 fprintf(stderr,"DVDMirrorChapter: Start sector is %d end sector is %d\n", cell_start_sector[i], cell_end_sector[i]);
2083         }
2084 #endif
2085
2086         result = DVDWriteCells(_dvd, cell_start_sector, cell_end_sector , end_cell - start_cell + 1, titles, title_set_info, titles_info, targetdir, title_name);
2087
2088         DVDFreeTitlesInfo(titles_info);
2089         DVDFreeTitleSetInfo(title_set_info);
2090         ifoClose(vts_ifo_info);
2091         free(cell_start_sector);
2092         free(cell_end_sector);
2093
2094         if( result != 0) {
2095                 return(1);
2096         } else {
2097                 return(0);
2098         }
2099 }
2100
2101
2102
2103
2104
2105
2106 int DVDMirrorTitles(dvd_reader_t * _dvd, char * targetdir,char * title_name, int titles) {
2107
2108         int end_chapter;
2109
2110         titles_info_t * titles_info=NULL;
2111
2112 #ifdef DEBUG
2113         fprintf(stderr,"In DVDMirrorTitles\n");
2114 #endif
2115
2116
2117
2118         titles_info = DVDGetInfo(_dvd);
2119         if (!titles_info) {
2120                 fprintf(stderr, "Faild to obtain titles information\n");
2121                 return(1);
2122         }
2123
2124
2125         end_chapter = titles_info->titles[titles - 1].chapters;
2126 #ifdef DEBUG
2127         fprintf(stderr,"DVDMirrorTitles: end_chapter %d\n", end_chapter);
2128 #endif
2129
2130         if (DVDMirrorChapters( _dvd, targetdir, title_name, 1, end_chapter, titles) != 0 ) {
2131                 DVDFreeTitlesInfo(titles_info);
2132                 return(1);
2133         }
2134
2135         DVDFreeTitlesInfo(titles_info);
2136
2137         return(0);
2138 }
2139
2140 int DVDDisplayInfo(dvd_reader_t * _dvd, char * dvd) {
2141
2142
2143         int i, f;
2144         int chapters;
2145         int channels;
2146         char title_name[33]="";
2147         title_set_info_t * title_set_info=NULL;
2148         titles_info_t * titles_info=NULL;
2149
2150
2151         titles_info = DVDGetInfo(_dvd);
2152         if (!titles_info) {
2153                 fprintf(stderr, "Guess work of main feature film faild\n");
2154                 return(1);
2155         }
2156
2157         title_set_info = DVDGetFileSet(_dvd);
2158         if (!title_set_info) {
2159                 DVDFreeTitlesInfo(titles_info);
2160                 return(1);
2161         }
2162
2163         DVDGetTitleName(dvd,title_name);
2164
2165
2166         fprintf(stdout,"\n\n\nDVD-Video information of the DVD with tile %s\n\n", title_name);
2167
2168         /* Print file structure */
2169
2170         fprintf(stdout,"File Structure DVD\n");
2171         fprintf(stdout,"VIDEO_TS/\n");
2172         fprintf(stdout,"\tVIDEO_TS.IFO\t%i\n", title_set_info->title_set[0].size_ifo);
2173
2174         if (title_set_info->title_set[0].size_menu != 0 ) {
2175                 fprintf(stdout,"\tVIDEO_TS.VOB\t%i\n", title_set_info->title_set[0].size_menu);
2176         }
2177
2178         fprintf(stdout,"\tVIDEO_TS.BUP\t%i\n", title_set_info->title_set[0].size_bup);
2179
2180         for( i = 0 ; i < title_set_info->number_of_title_sets ; i++) {
2181                 fprintf(stdout,"\tVTS_%02i_0.IFO\t%i\n", i + 1, title_set_info->title_set[i + 1].size_ifo);
2182                 if (title_set_info->title_set[i + 1].size_menu != 0 ) {
2183                         fprintf(stdout,"\tVTS_%02i_0.VOB\t%i\n", i + 1, title_set_info->title_set[i + 1].size_menu);
2184                 }
2185                 if (title_set_info->title_set[i + 1].number_of_vob_files != 0) {
2186                         for( f = 0; f < title_set_info->title_set[i + 1].number_of_vob_files ; f++ ) {
2187                                 fprintf(stdout,"\tVTS_%02i_%i.VOB\t%i\n", i + 1, f + 1, title_set_info->title_set[i + 1].size_vob[f]);
2188                         }
2189                 }
2190                 fprintf(stdout,"\tVTS_%02i_0.BUP\t%i\n", i + 1, title_set_info->title_set[i + 1].size_bup);
2191         }
2192
2193         fprintf(stdout,"\n\nMain feature:\n");
2194         fprintf(stdout,"\tTitle set containing the main feature is  %d\n", titles_info->main_title_set);
2195         for (i=0; i < titles_info->number_of_titles ; i++ ) {
2196                 if (titles_info->titles[i].title_set == titles_info->main_title_set) {
2197                         if(titles_info->titles[i].aspect_ratio == 3) {
2198                                 fprintf(stdout,"\tThe aspect ratio of the main feature is 16:9\n");
2199                         } else if (titles_info->titles[i].aspect_ratio == 0) {
2200                                 fprintf(stdout,"\tThe aspect ratio of the main feature is 4:3\n");
2201                         } else {
2202                                 fprintf(stdout,"\tThe aspect ratio of the main feature is unknown\n");
2203                         }
2204                         fprintf(stdout,"\tThe main feature has %d angle(s)\n", titles_info->titles[i].angles);
2205                         fprintf(stdout,"\tThe main feature has %d audio_track(s)\n", titles_info->titles[i].angles);
2206                         fprintf(stdout,"\tThe main feature has %d subpicture channel(s)\n",titles_info->titles[i].sub_pictures);
2207                         chapters=0;
2208                         channels=0;
2209
2210                         for (f=0; f < titles_info->number_of_titles ; f++ ) {
2211                                 if ( titles_info->titles[i].title_set == titles_info->main_title_set ) {
2212                                         if(chapters < titles_info->titles[f].chapters) {
2213                                                 chapters = titles_info->titles[f].chapters;
2214                                         }
2215                                         if(channels < titles_info->titles[f].audio_channels) {
2216                                                 channels = titles_info->titles[f].audio_channels;
2217                                         }
2218                                 }
2219                         }
2220                         fprintf(stdout,"\tThe main feature has a maximum of %d chapter(s) in on of it's titles\n", chapters);
2221                         fprintf(stdout,"\tThe main feature has a maximum of %d audio channel(s) in on of it's titles\n", channels);
2222                         break;
2223                 }
2224
2225         }
2226
2227         fprintf(stdout,"\n\nTitle Sets:");
2228         for (f=0; f < title_set_info->number_of_title_sets ; f++ ) {
2229                 fprintf(stdout,"\n\n\tTitle set %d\n", f + 1);
2230                 for (i=0; i < titles_info->number_of_titles ; i++ ) {
2231                         if (titles_info->titles[i].title_set == f + 1) {
2232                                 if(titles_info->titles[i].aspect_ratio == 3) {
2233                                         fprintf(stdout,"\t\tThe aspect ratio of title set %d is 16:9\n", f + 1);
2234                                 } else if (titles_info->titles[i].aspect_ratio == 0) {
2235                                         fprintf(stdout,"\t\tThe aspect ratio of title set %d is 4:3\n", f + 1);
2236                                 } else {
2237                                         fprintf(stdout,"\t\tThe aspect ratio of title set %d is unknown\n", f + 1);
2238                                 }
2239                                 fprintf(stdout,"\t\tTitle set %d has %d angle(s)\n", f + 1, titles_info->titles[i].angles);
2240                                 fprintf(stdout,"\t\tTitle set %d has %d audio_track(s)\n", f + 1, titles_info->titles[i].angles);
2241                                 fprintf(stdout,"\t\tTitle set %d has %d subpicture channel(s)\n", f + 1, titles_info->titles[i].sub_pictures);
2242                                 break;
2243                         }
2244                 }
2245                 fprintf(stdout,"\n\t\tTitles included in title set %d is/are\n", f + 1);
2246                 for (i=0; i < titles_info->number_of_titles ; i++ ) {
2247                         if (titles_info->titles[i].title_set == f + 1) {
2248                                 fprintf(stdout,"\t\t\tTitle %d:\n", i + 1);
2249                                 fprintf(stdout,"\t\t\t\tTitle %d has %d chapter(s)\n", i + 1, titles_info->titles[i].chapters);
2250                                 fprintf(stdout,"\t\t\t\tTitle %d has %d audio channle(s)\n", i + 1, titles_info->titles[i].audio_channels);
2251                         }
2252                 }
2253         }
2254         DVDFreeTitlesInfo(titles_info);
2255         DVDFreeTitleSetInfo(title_set_info);
2256
2257         return(0);
2258 }
2259
2260 int main(int argc, char *argv[]){
2261
2262         /* Args */
2263         int flags;
2264
2265         /* Switches */
2266         int title_set = 0;
2267         int titles;
2268         int start_chapter;
2269         int end_chapter;
2270
2271         int do_mirror = 0;
2272         int do_title_set = 0;
2273         int do_chapter = 0;
2274         int do_titles = 0;
2275         int do_feature = 0;
2276         int do_info = 0;
2277
2278
2279
2280         int return_code;
2281
2282         /* DVD Video device */
2283         char * dvd=NULL;
2284
2285         /* Temp switch helpers */
2286         char * verbose_temp=NULL;
2287         char * aspect_temp=NULL;
2288         char * start_chapter_temp=NULL;
2289         char * end_chapter_temp=NULL;
2290         char * titles_temp=NULL;
2291         char * title_set_temp=NULL;
2292
2293
2294         /* Title of the DVD */
2295         char title_name[33]="";
2296         char * provided_title_name=NULL;
2297
2298         /* Targer dir */
2299         char * targetdir=NULL;
2300
2301         /* Temp filename,dirname */
2302         char targetname[PATH_MAX];
2303         struct stat fileinfo;
2304
2305
2306         /* The DVD main structure */
2307         dvd_reader_t *  _dvd=NULL;
2308
2309
2310
2311         /*Todo do isdigit check */
2312
2313         while ((flags = getopt(argc, argv, "MFI?hi:v:a:o:n:s:e:t:T:")) != -1) {
2314                 switch (flags) {
2315                 case 'i':
2316                         if(optarg[0]=='-') usage();
2317                         dvd = optarg;
2318                         break;
2319                 case 'v':
2320                         if(optarg[0]=='-') usage();
2321                         verbose_temp = optarg;
2322                         break;
2323                 case 'o':
2324                         if(optarg[0]=='-') usage();
2325                         targetdir = optarg;
2326                         break;
2327                 case 'n':
2328                         if(optarg[0]=='-') usage();
2329                         provided_title_name = optarg;
2330                         break;
2331                 case 'a':
2332                         if(optarg[0]=='-') usage();
2333                         aspect_temp = optarg;
2334                         break;
2335                 case 's':
2336                         if(optarg[0]=='-') usage();
2337                         start_chapter_temp = optarg;
2338                         break;
2339                 case 'e':
2340                         if(optarg[0]=='-') usage();
2341                         end_chapter_temp = optarg;
2342                         break;
2343                 case 't':
2344                         if(optarg[0]=='-') usage();
2345                         titles_temp = optarg;
2346                         break;
2347                 case 'T':
2348                         if(optarg[0]=='-') usage();
2349                         title_set_temp = optarg;
2350                         break;
2351                 case 'M':
2352                         do_mirror = 1;
2353                         break;
2354                 case 'F':
2355                         do_feature = 1;
2356                         break;
2357                 case 'I':
2358                         do_info = 1;
2359                         break;
2360
2361                 case '?':
2362                         usage();
2363                         break;
2364                 case 'h':
2365                         usage();
2366                         break;
2367                 default:
2368                         usage();
2369                 }
2370         }
2371
2372         if (dvd == NULL) {
2373                 usage();
2374                 exit(1);
2375         }
2376
2377         if (targetdir == NULL && do_info == 0) {
2378                 usage();
2379                 exit(1);
2380         }
2381
2382         if(verbose_temp == NULL) {
2383                 verbose = 0;
2384         } else {
2385                 verbose = atoi(verbose_temp);
2386         }
2387
2388         if (aspect_temp == NULL) {
2389                 /* Deafult to 16:9 aspect ratio */
2390                 aspect = 3;
2391         } else {
2392                 aspect = atoi(aspect_temp);
2393         }
2394
2395         if((aspect != 0) && (aspect != 3) && (do_info == 0)){
2396                 usage();
2397                 exit(1);
2398         }
2399
2400         if ( titles_temp != NULL) {
2401                 titles = atoi(titles_temp);
2402                 if ( titles < 1 ) {
2403                         usage();
2404                         exit(1);
2405                 }
2406         }
2407
2408         if ( start_chapter_temp !=NULL) {
2409                 start_chapter = atoi(start_chapter_temp);
2410                 if ( start_chapter < 1 || start_chapter > 99 ) {
2411                         usage();
2412                         exit(1);
2413                 }
2414         }
2415
2416         if (end_chapter_temp != NULL) {
2417                 end_chapter = atoi(end_chapter_temp);
2418                 if ( end_chapter < 1 || end_chapter > 99 ) {
2419                         usage();
2420                         exit(1);
2421                 }
2422         }
2423
2424         if ( end_chapter_temp != NULL || start_chapter_temp != NULL) {
2425                 if( end_chapter_temp == NULL) {
2426                         end_chapter = 99;
2427                 } else if ( start_chapter_temp == NULL) {
2428                         start_chapter = 1;
2429                 }
2430                 if ( end_chapter < start_chapter ) {
2431                         usage();
2432                         exit(1);
2433                 }
2434         }
2435
2436         if ( titles_temp != NULL && ((end_chapter_temp != NULL) || (start_chapter_temp != NULL))) {
2437                 do_chapter = 1;
2438         } else if ((titles_temp != NULL) && ((end_chapter_temp == NULL) && (start_chapter_temp == NULL))) {
2439                 do_titles=1;
2440         }
2441         if (do_chapter && (titles_temp == NULL)) {
2442                 titles = 0;
2443         }
2444
2445         if ( title_set_temp != NULL ) {
2446                 title_set = atoi(title_set_temp);
2447                 if ( title_set > 99 || title_set < 0 ) {
2448                         usage();
2449                         exit(1);
2450                 }
2451                 do_title_set = 1;
2452         }
2453
2454         if (do_info + do_titles + do_chapter + do_feature + do_title_set  + do_mirror > 1 ) {
2455                 usage();
2456                 exit(1);
2457         } else if ( do_info + do_titles + do_chapter + do_feature + do_title_set  + do_mirror == 0) {
2458                 usage();
2459                 exit(1);
2460         }
2461 #ifdef DEBUG
2462         fprintf(stderr,"After args\n");
2463 #endif
2464
2465
2466         _dvd = DVDOpen(dvd);
2467         if(!_dvd) exit(-1);
2468
2469
2470         if (do_info) {
2471                 DVDDisplayInfo(_dvd, dvd);
2472                 DVDClose(_dvd);
2473                 exit(0);
2474         }
2475
2476
2477         if(provided_title_name == NULL) {
2478                 if (DVDGetTitleName(dvd,title_name) != 0) {
2479                         fprintf(stderr,"You must provide a title name when you read your DVD-Video structure direct from the HD\n");
2480                         DVDClose(_dvd);
2481                         exit(1);
2482                 }
2483                 if (strstr(title_name, "DVD_VIDEO") != NULL) {
2484                         fprintf(stderr,"The DVD-Video title on the disk is DVD_VIDEO which is to generic please provide a title with the -n switch\n");
2485                         DVDClose(_dvd);
2486                         exit(2);
2487                 }
2488
2489         } else {
2490                 if (strlen(provided_title_name) > 32) {
2491                         fprintf(stderr,"The title name specified is longer than 32 charachters, truncating the title name\n");
2492                         strncpy(title_name,provided_title_name, 32);
2493                         title_name[32]='\0';
2494                 } else {
2495                         strcpy(title_name,provided_title_name);
2496                 }
2497         }
2498
2499
2500
2501         sprintf(targetname,"%s",targetdir);
2502
2503         if (stat(targetname, &fileinfo) == 0) {
2504                 if (! S_ISDIR(fileinfo.st_mode)) {
2505                         fprintf(stderr,"The target directory is not valid, it may be a ordinary file\n");
2506                 }
2507         } else {
2508                 if (mkdir(targetname, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
2509                         fprintf(stderr,"Faild creating target directory\n");
2510                         perror("");
2511                         DVDClose(_dvd);
2512                         exit(-1);
2513                 }
2514         }
2515
2516
2517         sprintf(targetname,"%s/%s",targetdir, title_name);
2518
2519         if (stat(targetname, &fileinfo) == 0) {
2520                 if (! S_ISDIR(fileinfo.st_mode)) {
2521                         fprintf(stderr,"The title directory is not valid, it may be a ordinary file\n");
2522                 }
2523         } else {
2524                 if (mkdir(targetname, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
2525                         fprintf(stderr,"Faild creating title directory\n");
2526                         perror("");
2527                         DVDClose(_dvd);
2528                         exit(-1);
2529                 }
2530         }
2531
2532         sprintf(targetname,"%s/%s/VIDEO_TS",targetdir, title_name);
2533
2534         if (stat(targetname, &fileinfo) == 0) {
2535                 if (! S_ISDIR(fileinfo.st_mode)) {
2536                         fprintf(stderr,"The VIDEO_TS directory is not valid, it may be a ordinary file\n");
2537                 }
2538         } else {
2539                 if (mkdir(targetname, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
2540                         fprintf(stderr,"Faild creating VIDEO_TS directory\n");
2541                         perror("");
2542                         DVDClose(_dvd);
2543                         exit(-1);
2544                 }
2545         }
2546
2547
2548 #ifdef DEBUG
2549         fprintf(stderr,"After dirs\n");
2550 #endif
2551
2552
2553         if(do_mirror) {
2554                 if ( DVDMirror(_dvd, targetdir, title_name)  != 0 ) {
2555                         fprintf(stderr, "Mirror of DVD faild\n");
2556                         return_code = -1;
2557                 } else {
2558                         return_code = 0;
2559                 }
2560         }
2561 #ifdef DEBUG
2562         fprintf(stderr,"After Mirror\n");
2563 #endif
2564
2565
2566         if (do_title_set) {
2567                 if (DVDMirrorTitleSet(_dvd, targetdir, title_name, title_set) != 0) {
2568                         fprintf(stderr, "Mirror of title set %d faild\n", title_set);
2569                         return_code = -1;
2570                 } else {
2571                         return_code  = 0;
2572                 }
2573
2574         }
2575 #ifdef DEBUG
2576         fprintf(stderr,"After Title Set\n");
2577 #endif
2578
2579
2580
2581         if(do_feature) {
2582                 if ( DVDMirrorMainFeature(_dvd, targetdir, title_name)  != 0 ) {
2583                         fprintf(stderr, "Mirror of main feature film of DVD faild\n");
2584                         return_code = -1;
2585                 } else {
2586                         return_code = 0;
2587                 }
2588         }
2589
2590         if(do_titles) {
2591                 if (DVDMirrorTitles(_dvd, targetdir, title_name, titles) != 0) {
2592                         fprintf(stderr, "Mirror of title  %d faild\n", titles);
2593                         return_code = -1;
2594                 } else {
2595                         return_code  = 0;
2596                 }
2597         }
2598
2599
2600         if(do_chapter) {
2601                 if (DVDMirrorChapters(_dvd, targetdir, title_name, start_chapter, end_chapter, titles) != 0) {
2602                         fprintf(stderr, "Mirror of chapters %d to %d in title %d faild\n", start_chapter, end_chapter, titles);
2603                         return_code = -1;
2604                 } else {
2605                         return_code  = 0;
2606                 }
2607         }
2608
2609
2610         DVDClose(_dvd);
2611         exit(return_code);
2612 }
2613
2614
2615
This page took 0.457161 seconds and 3 git commands to generate.