2 * Copyright (C) 2002 Olaf Beck <olaf_sc@yahoo.com>
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.
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.
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
19 /* dvdbackup version 0.1 */
25 #include <sys/errno.h>
27 #include <sys/types.h>
33 #include <dvdread/dvd_reader.h>
34 #include <dvdread/ifo_read.h>
35 #include <dvdread/ifo_print.h>
40 /*Flag for verbose mode */
45 /* Structs to keep title set information in */
51 int number_of_vob_files;
56 int number_of_title_sets;
57 title_set_t *title_set;
80 void bsort_max_to_min(int sector[], int title[], int size);
83 To gather info about the dvd:
84 dvdbackup -i /dev/dvd -I
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.
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
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
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.
112 To backup the whole DVD
114 dvdbackup -M -i/dev/dvd -o/my/dvd/backup/dir/
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
121 To backup the main feature of the DVD:
123 dvdbackup -F -i/dev/dvd -o/my/dvd/backup/dir/
125 This action creates a valid DVD-Video structure
126 of the feature title set
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.
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.
137 To backup a title set
139 dvdbackup -T 2 -i/dev/dvd -o/my/dvd/backup/dir/
141 where "-T 2" specifies that you want to backup
142 title set 2 i.e. all VTS_02_X.XXX files.
144 This action creates a valid DVD-Video structure
145 of the specified title set
150 dvdbackup -t 1 -i/dev/dvd -o/my/dvd/backup/dir
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.
159 To backup a specific chapter or chapters from a title:
161 dvdbackup -t 1 -s 20 -e 25 -i/dev/dvd -o/my/dvd/backup/dir
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.
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
173 You can skip the -t switch and let the program guess the title although
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.
182 2 on title name error
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.
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).
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.
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");
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*/
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) {
246 int temp, i, found_audio, found_sub, found_channels;
249 temp = audio_audio_array[reference];
250 for (i=0 ; i < title_sets ; i++ ) {
251 if ( audio_audio_array[i] < temp ) {
254 if ( candidate == title_set_audio_array[i] ) {
262 temp = subpicture_sub_array[reference];
263 for (i=0 ; i < title_sets ; i++ ) {
264 if ( subpicture_sub_array[i] < temp ) {
267 if ( candidate == title_set_sub_array[i] ) {
276 temp = channels_channel_array[reference];
277 for (i=0 ; i < title_sets ; i++ ) {
278 if ( channels_channel_array[i] < temp ) {
281 if ( candidate == title_set_channel_array[i] ) {
289 return(found_audio + found_sub + found_channels);
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){
306 /* Temp filename,dirname */
307 char targetname[PATH_MAX];
311 unsigned char * buffer=NULL;
320 /* Buffer size in DVD sectors */
321 /* Currently set to 1MB */
332 dvd_file_t * dvd_file=NULL;
335 int number_of_vob_files;
338 fprintf(stderr,"DVDWriteCells: length is %d\n", length);
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;
346 fprintf(stderr,"DVDWriteCells: title set is %d\n", title_set);
347 fprintf(stderr,"DVDWriteCells: vob files are %d\n", number_of_vob_files);
353 /* Remove all old files silently if they exists */
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);
358 fprintf(stderr,"DVDWriteCells: file is %s\n", targetname);
369 /* Loop through all sectors and find the right vob */
370 for (f = 0; f < length ; f++) {
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*/
378 for ( i = 0; i < number_of_vob_files ; i++ ) {
381 tsize = title_set_info->title_set[title_set].size_vob[i];
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);
388 offset = offset + tsize/2048;
391 fprintf(stderr,"DVDWriteCells: soffset is %d\n", soffset);
392 fprintf(stderr,"DVDWriteCells: offset is %d\n", offset);
394 /* Find out if this is the right vob */
395 if( soffset <= cell_start_sector[f] && offset > cell_start_sector[f] ) {
397 fprintf(stderr,"DVDWriteCells: got it \n");
400 soffset = cell_start_sector[f];
401 if ( cell_end_sector[f] > offset ) {
402 leftover = cell_end_sector[f] - offset + 1;
404 size = cell_end_sector[f] - cell_start_sector[f] + 1;
407 fprintf(stderr,"DVDWriteCells: size is %d\n", size);
415 fprintf(stderr,"DVDWriteCells: Writing soffset is %d and leftover is %d\n", soffset, leftover);
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");
426 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
430 fprintf(stderr,"DVDWriteCells: 1\n");
434 if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(unsigned char))) == NULL) {
435 fprintf(stderr, "Out of memory coping %s\n", targetname);
440 fprintf(stderr,"DVDWriteCells: 2\n");
444 if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0644)) == -1) {
445 fprintf(stderr, "Error creating %s\n", targetname);
451 fprintf(stderr,"DVDWriteCells: 3\n");
455 if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
456 fprintf(stderr, "Faild opending TITLE VOB\n");
465 fprintf(stderr,"DVDWriteCells: left is %d\n", left);
473 if ( DVDReadBlocks(dvd_file,soffset,buff, buffer) != buff) {
474 fprintf(stderr, "Error reading MENU VOB\n");
476 DVDCloseFile(dvd_file);
482 if (write(streamout,buffer,buff * 2048) != buff * 2048) {
483 fprintf(stderr, "Error writing TITLE VOB\n");
489 soffset = soffset + buff;
494 DVDCloseFile(dvd_file);
499 if ( leftover != 0 ) {
503 if (title_set == 0) {
504 fprintf(stderr,"Don't try to copy chapters from the VMG domain there aren't any\n");
507 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
511 if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(unsigned char))) == NULL) {
512 fprintf(stderr, "Out of memory coping %s\n", targetname);
518 if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0644)) == -1) {
519 fprintf(stderr, "Error creating %s\n", targetname);
525 if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
526 fprintf(stderr, "Faild opending TITLE VOB\n");
539 if ( DVDReadBlocks(dvd_file,offset,buff, buffer) != buff) {
540 fprintf(stderr, "Error reading MENU VOB\n");
542 DVDCloseFile(dvd_file);
548 if (write(streamout,buffer,buff * 2048) != buff * 2048) {
549 fprintf(stderr, "Error writing TITLE VOB\n");
555 offset = offset + buff;
560 DVDCloseFile(dvd_file);
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[]) {
579 free(chapter_chapter_array);
580 free(title_set_chapter_array);
582 free(angle_angle_array);
583 free(title_set_angle_array);
585 free(subpicture_sub_array);
586 free(title_set_sub_array);
588 free(audio_audio_array);
589 free(title_set_audio_array);
591 free(size_size_array);
592 free(title_set_size_array);
594 free(channels_channel_array);
595 free(title_set_channel_array);
599 titles_info_t * DVDGetInfo(dvd_reader_t * _dvd) {
601 /* title interation */
613 /* Arrays for chapter, angle, subpicture, audio, size, aspect, channels - file_set relationship */
615 /* Size == number_of_titles */
616 int * chapter_chapter_array;
617 int * title_set_chapter_array;
619 int * angle_angle_array;
620 int * title_set_angle_array;
622 /* Size == number_of_title_sets */
624 int * subpicture_sub_array;
625 int * title_set_sub_array;
627 int * audio_audio_array;
628 int * title_set_audio_array;
630 int * size_size_array;
631 int * title_set_size_array;
633 int * channels_channel_array;
634 int * title_set_channel_array;
647 ifo_handle_t * vmg_ifo=NULL;
648 dvd_file_t * vts_title_file=NULL;
650 titles_info_t * titles_info=NULL;
652 /* Open main info file */
653 vmg_ifo = ifoOpen( _dvd, 0 );
655 fprintf( stderr, "Can't open VMG info.\n" );
659 titles = vmg_ifo->tt_srpt->nr_of_srpts;
660 title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;
662 if ((vmg_ifo->tt_srpt == 0) || (vmg_ifo->vts_atrt == 0)) {
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));
672 titles_info->number_of_titles = titles;
675 chapter_chapter_array = malloc(titles * sizeof(int));
676 title_set_chapter_array = malloc(titles * sizeof(int));
678 /*currently not used in the guessing */
679 angle_angle_array = malloc(titles * sizeof(int));
680 title_set_angle_array = malloc(titles * sizeof(int));
683 subpicture_sub_array = malloc(title_sets * sizeof(int));
684 title_set_sub_array = malloc(title_sets * sizeof(int));
686 audio_audio_array = malloc(title_sets * sizeof(int));
687 title_set_audio_array = malloc(title_sets * sizeof(int));
689 size_size_array = malloc(title_sets * sizeof(int));
690 title_set_size_array = malloc(title_sets * sizeof(int));
692 channels_channel_array = malloc(title_sets * sizeof(int));
693 title_set_channel_array = malloc(title_sets * sizeof(int));
696 /* Interate over the titles nr_of_srpts */
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;
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;
714 /* Interate over vmg_nr_of_title_sets */
716 for (counter=0; counter < title_sets ; counter++ ) {
719 subpicture_sub_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_subp_streams;
720 title_set_sub_array[counter] = counter + 1;
724 audio_audio_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_audio_streams;
725 title_set_audio_array[counter] = counter + 1;
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;
734 channels_channel_array[counter] = channels;
735 title_set_channel_array[counter] = counter + 1;
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;
750 /* Close the VMG ifo file we got all the info we need */
754 for (counter=0; counter < title_sets; counter++ ) {
756 vts_title_file = DVDOpenFile(_dvd, counter + 1, DVD_READ_TITLE_VOBS);
758 if (vts_title_file != 0) {
759 size_size_array[counter] = DVDFileSize(vts_title_file);
760 DVDCloseFile(vts_title_file);
762 size_size_array[counter] = 0;
765 title_set_size_array[counter] = counter + 1;
771 /* Sort all arrays max to min */
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);
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 */
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*/
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;
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;
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];
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];
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];
831 candidate = title_set_size_array[0];
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 */
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);
845 /* Now lets see if we can find our candidate among the top most chapters */
847 temp = chapter_chapter_array[0];
848 for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
849 if ( candidate == title_set_chapter_array[i] ) {
856 if (((found == 3) && (found_chapter == 1) && (dual == 0) && (multi == 0)) || ((found == 3) && (found_chapter < 3 ) && (dual == 1))) {
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;
870 for (i=0 ; i < title_sets ; ++i) {
871 if (CheckSizeArray(size_size_array, 0, i + 1) == 0) {
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];
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);
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;
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];
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);
909 /* Now lets see if we can find our candidate among the top most chapters */
912 temp = chapter_chapter_array[0];
913 for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
914 if ( candidate == title_set_chapter_array[i] ) {
921 /* Here we take chapters in to consideration*/
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;
933 /* Here we do but we lower the treshold for audio, sub and channels */
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;
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;
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*/
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*/
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
976 /* Which title set is the biggest one - dual array with title sets and size
977 The biggest one is usally the main film*/
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*/
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*/
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
989 Hmm the biggest one doesn't have the most chapters?
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
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
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)
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
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.
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.
1024 int DVDCopyTileVobX(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, int vob, char * targetdir,char * title_name) {
1029 /* Temp filename,dirname */
1030 char targetname[PATH_MAX];
1031 struct stat fileinfo;
1035 unsigned char * buffer=NULL;
1036 unsigned char buffy; /* :-) */
1044 /* Buffer size in DVD sectors */
1045 /* Currently set to 1MB */
1051 dvd_file_t * dvd_file=NULL;
1053 if (title_set_info->number_of_title_sets + 1 < title_set) {
1054 fprintf(stderr,"Faild num title test\n");
1058 if (title_set_info->title_set[title_set].number_of_vob_files < vob ) {
1059 fprintf(stderr,"Faild vob test\n");
1063 if (title_set_info->title_set[title_set].size_vob[0] == 0 ) {
1064 fprintf(stderr,"Faild vob 1 size test\n");
1066 } else if (title_set_info->title_set[title_set].size_vob[vob - 1] == 0 ) {
1067 fprintf(stderr,"Faild vob %d test\n", vob);
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);
1077 fprintf(stderr,"After we check the vob it self %d\n", vob);
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");
1085 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
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);
1097 offset = offset + tsize/2048;
1101 fprintf(stderr,"The offset for vob %d is %d\n", vob, offset);
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);
1111 if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
1112 fprintf(stderr, "Error opening %s\n", targetname);
1118 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
1119 fprintf(stderr, "Error creating %s\n", targetname);
1127 if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(buffy))) == NULL) {
1128 fprintf(stderr, "Out of memory coping %s\n", targetname);
1134 if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
1135 fprintf(stderr, "Faild opending TITLE VOB\n");
1146 if ( DVDReadBlocks(dvd_file,offset,buff, buffer) != buff) {
1147 fprintf(stderr, "Error reading MENU VOB\n");
1149 DVDCloseFile(dvd_file);
1155 if (write(streamout,buffer,buff * 2048) != buff * 2048) {
1156 fprintf(stderr, "Error writing TITLE VOB\n");
1162 offset = offset + buff;
1167 DVDCloseFile(dvd_file);
1177 int DVDCopyMenu(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, char * targetdir,char * title_name) {
1179 /* Temp filename,dirname */
1180 char targetname[PATH_MAX];
1181 struct stat fileinfo;
1185 unsigned char * buffer=NULL;
1186 unsigned char buffy; /* :-) */
1194 /* Buffer size in DVD sectors */
1195 /* Currently set to 1MB */
1201 dvd_file_t * dvd_file=NULL;
1203 if (title_set_info->number_of_title_sets + 1 < title_set) {
1207 if (title_set_info->title_set[title_set].size_menu == 0 ) {
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);
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);
1221 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_0.VOB",targetdir, title_name, title_set);
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);
1231 if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
1232 fprintf(stderr, "Error opening %s\n", targetname);
1238 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
1239 fprintf(stderr, "Error creating %s\n", targetname);
1247 if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(buffy))) == NULL) {
1248 fprintf(stderr, "Out of memory coping %s\n", targetname);
1254 if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_MENU_VOBS))== 0) {
1255 fprintf(stderr, "Faild opending MENU VOB\n");
1266 if ( DVDReadBlocks(dvd_file,offset,buff, buffer) != buff) {
1267 fprintf(stderr, "Error reading MENU VOB\n");
1269 DVDCloseFile(dvd_file);
1275 if (write(streamout,buffer,buff * 2048) != buff * 2048) {
1276 fprintf(stderr, "Error writing MENU VOB\n");
1282 offset = offset + buff;
1287 DVDCloseFile(dvd_file);
1295 int DVDCopyIfoBup (dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, char * targetdir,char * title_name) {
1297 /* Temp filename,dirname */
1298 char targetname[PATH_MAX];
1299 struct stat fileinfo;
1303 unsigned char * buffer=NULL;
1304 unsigned char buffy; /* :-) */
1312 dvd_file_t * dvd_file=NULL;
1315 if (title_set_info->number_of_title_sets + 1 < title_set) {
1319 if (title_set_info->title_set[title_set].size_ifo == 0 ) {
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);
1329 /* Create VIDEO_TS.IFO or VTS_XX_0.IFO */
1331 if (title_set == 0) {
1332 sprintf(targetname,"%s/%s/VIDEO_TS/VIDEO_TS.IFO",targetdir, title_name);
1334 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_0.IFO",targetdir, title_name, title_set);
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);
1343 if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
1344 fprintf(stderr, "Error opening %s\n", targetname);
1350 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
1351 fprintf(stderr, "Error creating %s\n", targetname);
1357 /* Copy VIDEO_TS.IFO, since it's a small file try to copy it in one shot */
1360 if ((buffer = (unsigned char *)malloc(size * sizeof(buffy))) == NULL) {
1361 fprintf(stderr, "Out of memory coping %s\n", targetname);
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);
1374 if ( DVDReadBytes(dvd_file,buffer,size) != size) {
1375 fprintf(stderr, "Error reading IFO for title set %d\n", title_set);
1377 DVDCloseFile(dvd_file);
1382 DVDCloseFile(dvd_file);
1384 if (write(streamout,buffer,size) != size) {
1385 fprintf(stderr, "Error writing %s\n",targetname);
1395 /* Create VIDEO_TS.BUP or VTS_XX_0.BUP */
1397 if (title_set == 0) {
1398 sprintf(targetname,"%s/%s/VIDEO_TS/VIDEO_TS.BUP",targetdir, title_name);
1400 sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_0.BUP",targetdir, title_name, title_set);
1404 if (title_set_info->title_set[title_set].size_bup == 0 ) {
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);
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);
1421 if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
1422 fprintf(stderr, "Error opening %s\n", targetname);
1428 if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
1429 fprintf(stderr, "Error creating %s\n", targetname);
1437 /* Copy VIDEO_TS.BUP or VTS_XX_0.BUP, since it's a small file try to copy it in one shot */
1439 if ((buffer = (unsigned char *)malloc(size * sizeof(buffy))) == NULL) {
1440 fprintf(stderr, "Out of memory coping %s\n", targetname);
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);
1453 if ( DVDReadBytes(dvd_file,buffer,size) != size) {
1454 fprintf(stderr, "Error reading BUP for title set %d\n", title_set);
1456 DVDCloseFile(dvd_file);
1461 DVDCloseFile(dvd_file);
1463 if (write(streamout,buffer,size) != size) {
1464 fprintf(stderr, "Error writing %s\n", targetname);
1477 int DVDMirrorVMG(dvd_reader_t * dvd, title_set_info_t * title_set_info,char * targetdir,char * title_name){
1479 if ( DVDCopyIfoBup(dvd, title_set_info, 0, targetdir, title_name) != 0 ) {
1483 if ( DVDCopyMenu(dvd, title_set_info, 0, targetdir, title_name) != 0 ) {
1489 int DVDMirrorTitleX(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, char * targetdir,char * title_name) {
1491 /* Loop through the vobs */
1496 if ( DVDCopyIfoBup(dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
1500 if ( DVDCopyMenu(dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
1504 for (i = 0; i < title_set_info->title_set[title_set].number_of_vob_files ; i++) {
1506 fprintf(stderr,"In the VOB copy loop for %d\n", i);
1508 if ( DVDCopyTileVobX(dvd, title_set_info, title_set, i + 1, targetdir, title_name) != 0 ) {
1517 int DVDGetTitleName(const char *device, char *title)
1519 /* Variables for filehandel and title string interaction */
1521 int filehandle, i, last;
1523 /* Open DVD device */
1525 if ( !(filehandle = open(device, O_RDONLY)) ) {
1526 fprintf(stderr, "Can't open secified device %s - check your DVD device\n", device);
1530 /* Seek to title of first track, which is at (track_no * 32768) + 40 */
1532 if ( 32808 != lseek(filehandle, 32808, SEEK_SET) ) {
1534 fprintf(stderr, "Can't seek DVD device %s - check your DVD device\n", device);
1538 /* Read the DVD-Video title */
1540 if ( 32 != read(filehandle, title, 32)) {
1542 fprintf(stderr, "Can't read title from DVD device %s\n", device);
1546 /* Terminate the title string */
1551 /* Remove trailing white space */
1554 for ( i = 0; i < 32; i++ ) {
1555 if ( title[i] != ' ' ) { last = i; }
1558 title[last + 1] = '\0';
1565 void bsort_min_to_max(int sector[], int title[], int size){
1567 int temp_title, temp_sector, i, j;
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;
1583 void bsort_max_to_min(int sector[], int title[], int size){
1585 int temp_title, temp_sector, i, j;
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;
1603 void uniq(int sector[], int title[], int title_sets_array[], int sector_sets_array[], int titles){
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];
1618 } while ( sector[j] == sector[j+1] );
1625 void align_end_sector(int cell_start_sector[],int cell_end_sector[], int size) {
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;
1639 void DVDFreeTitleSetInfo(title_set_info_t * title_set_info) {
1640 free(title_set_info->title_set);
1641 free(title_set_info);
1644 void DVDFreeTitlesInfo(titles_info_t * titles_info) {
1645 free(titles_info->titles);
1651 title_set_info_t *DVDGetFileSet(dvd_reader_t * _dvd) {
1653 /* title interation */
1654 int title_sets, counter, i;
1657 /* DVD Video files */
1658 char filename[MAXNAME];
1662 ifo_handle_t * vmg_ifo=NULL;
1664 /* The Title Set Info struct*/
1665 title_set_info_t * title_set_info;
1667 /* Open main info file */
1668 vmg_ifo = ifoOpen( _dvd, 0 );
1670 fprintf( stderr, "Can't open VMG info.\n" );
1675 title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;
1677 /* Close the VMG ifo file we got all the info we need */
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));
1684 title_set_info->number_of_title_sets = title_sets;
1687 /* Find VIDEO_TS.IFO is present - must be present since we did a ifo open 0*/
1689 sprintf(filename,"/VIDEO_TS/VIDEO_TS.IFO");
1691 if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1692 title_set_info->title_set[0].size_ifo = size;
1694 DVDFreeTitleSetInfo(title_set_info);
1700 /* Find VIDEO_TS.VOB if present*/
1702 sprintf(filename,"/VIDEO_TS/VIDEO_TS.VOB");
1704 if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1705 title_set_info->title_set[0].size_menu = size;
1707 title_set_info->title_set[0].size_menu = 0 ;
1710 /* Find VIDEO_TS.BUP if present */
1712 sprintf(filename,"/VIDEO_TS/VIDEO_TS.BUP");
1714 if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1715 title_set_info->title_set[0].size_bup = size;
1717 DVDFreeTitleSetInfo(title_set_info);
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");
1726 /* Take care of the titles which we don't have in VMG */
1728 title_set_info->title_set[0].number_of_vob_files = 0;
1729 title_set_info->title_set[0].size_vob[0] = 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 );
1739 if ( title_sets >= 1 ) {
1740 for (counter=0; counter < title_sets; counter++ ){
1743 fprintf(stderr,"At top of loop\n");
1747 sprintf(filename,"/VIDEO_TS/VTS_%02i_0.IFO",counter + 1);
1749 if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1750 title_set_info->title_set[counter + 1].size_ifo = size;
1752 DVDFreeTitleSetInfo(title_set_info);
1757 fprintf(stderr,"After opening files\n");
1761 /* Find VTS_XX_0.VOB if present*/
1763 sprintf(filename,"/VIDEO_TS/VTS_%02i_0.VOB", counter + 1);
1765 if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1766 title_set_info->title_set[counter + 1].size_menu = size;
1768 title_set_info->title_set[counter + 1].size_menu = 0 ;
1773 fprintf(stderr,"After Menu VOB check\n");
1777 /* Find all VTS_XX_[1 to 9].VOB files if they are present*/
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 ) {
1784 title_set_info->title_set[counter + 1].size_vob[i] = size;
1786 title_set_info->title_set[counter + 1].number_of_vob_files = i;
1789 fprintf(stderr,"After Menu Title VOB check\n");
1793 sprintf(filename,"/VIDEO_TS/VTS_%02i_0.BUP", counter + 1);
1795 if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
1796 title_set_info->title_set[counter +1].size_bup = size;
1798 DVDFreeTitleSetInfo(title_set_info);
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);
1809 fprintf(stderr,"After Menu Title BUP check\n");
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]);
1819 fprintf(stderr,"BUP: %d\n",title_set_info->title_set[counter +1].size_bup);
1823 fprintf(stderr,"Bottom of loop \n");
1829 /* Return the info */
1830 return(title_set_info);
1835 int DVDMirror(dvd_reader_t * _dvd, char * targetdir,char * title_name) {
1838 title_set_info_t * title_set_info=NULL;
1840 title_set_info = DVDGetFileSet(_dvd);
1841 if (!title_set_info) {
1846 if ( DVDMirrorVMG(_dvd, title_set_info, targetdir, title_name) != 0 ) {
1847 fprintf(stderr,"Mirror of VMG faild\n");
1848 DVDFreeTitleSetInfo(title_set_info);
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);
1862 int DVDMirrorTitleSet(dvd_reader_t * _dvd, char * targetdir,char * title_name, int title_set) {
1864 title_set_info_t * title_set_info=NULL;
1868 fprintf(stderr,"In DVDMirrorTitleSet\n");
1871 title_set_info = DVDGetFileSet(_dvd);
1873 if (!title_set_info) {
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);
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);
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);
1897 DVDFreeTitleSetInfo(title_set_info);
1901 int DVDMirrorMainFeature(dvd_reader_t * _dvd, char * targetdir,char * title_name) {
1903 title_set_info_t * title_set_info=NULL;
1904 titles_info_t * titles_info=NULL;
1907 titles_info = DVDGetInfo(_dvd);
1909 fprintf(stderr, "Guess work of main feature film faild\n");
1913 title_set_info = DVDGetFileSet(_dvd);
1914 if (!title_set_info) {
1915 DVDFreeTitlesInfo(titles_info);
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);
1925 DVDFreeTitlesInfo(titles_info);
1926 DVDFreeTitleSetInfo(title_set_info);
1931 int DVDMirrorChapters(dvd_reader_t * _dvd, char * targetdir,char * title_name, int start_chapter,int end_chapter, int titles) {
1940 int start_cell, end_cell;
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;
1949 /* To do free memory*/
1951 titles_info = DVDGetInfo(_dvd);
1953 fprintf(stderr, "Faild to obtain titles information\n");
1957 title_set_info = DVDGetFileSet(_dvd);
1958 if (!title_set_info) {
1959 DVDFreeTitlesInfo(titles_info);
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;
1976 vts_ifo_info = ifoOpen(_dvd, titles_info->titles[titles - 1].title_set);
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);
1984 vts_title = titles_info->titles[titles - 1].vts_title;
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);
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);
1998 /* We assume the same PGC for the whole title - this is not true and need to be fixed later on */
2000 pgc = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgcn;
2003 /* Lookup PG for start chapter */
2005 spg = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgn;
2007 /* Look up start cell for this pgc/pg */
2009 start_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[spg - 1];
2012 /* Lookup end cell*/
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;
2018 fprintf(stderr,"DVDMirrorChapter: epg %d\n", epg);
2021 end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[epg -1] - 1;
2023 fprintf(stderr,"DVDMirrorChapter: end cell adjusted %d\n", end_cell);
2028 end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->nr_of_cells;
2030 fprintf(stderr,"DVDMirrorChapter: end cell adjusted 2 %d\n",end_cell);
2036 fprintf(stderr,"DVDMirrorChapter: star cell %d\n", start_cell);
2040 /* Put all the cells start and end sector in a dual array */
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);
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);
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);
2065 for (i=0, s=start_cell; s < end_cell +1 ; i++, s++) {
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;
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);
2076 bsort_min_to_max(cell_start_sector, cell_end_sector, end_cell - start_cell + 1);
2078 align_end_sector(cell_start_sector, cell_end_sector,end_cell - start_cell + 1);
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]);
2086 result = DVDWriteCells(_dvd, cell_start_sector, cell_end_sector , end_cell - start_cell + 1, titles, title_set_info, titles_info, targetdir, title_name);
2088 DVDFreeTitlesInfo(titles_info);
2089 DVDFreeTitleSetInfo(title_set_info);
2090 ifoClose(vts_ifo_info);
2091 free(cell_start_sector);
2092 free(cell_end_sector);
2106 int DVDMirrorTitles(dvd_reader_t * _dvd, char * targetdir,char * title_name, int titles) {
2110 titles_info_t * titles_info=NULL;
2113 fprintf(stderr,"In DVDMirrorTitles\n");
2118 titles_info = DVDGetInfo(_dvd);
2120 fprintf(stderr, "Faild to obtain titles information\n");
2125 end_chapter = titles_info->titles[titles - 1].chapters;
2127 fprintf(stderr,"DVDMirrorTitles: end_chapter %d\n", end_chapter);
2130 if (DVDMirrorChapters( _dvd, targetdir, title_name, 1, end_chapter, titles) != 0 ) {
2131 DVDFreeTitlesInfo(titles_info);
2135 DVDFreeTitlesInfo(titles_info);
2140 int DVDDisplayInfo(dvd_reader_t * _dvd, char * dvd) {
2146 char title_name[33]="";
2147 title_set_info_t * title_set_info=NULL;
2148 titles_info_t * titles_info=NULL;
2151 titles_info = DVDGetInfo(_dvd);
2153 fprintf(stderr, "Guess work of main feature film faild\n");
2157 title_set_info = DVDGetFileSet(_dvd);
2158 if (!title_set_info) {
2159 DVDFreeTitlesInfo(titles_info);
2163 DVDGetTitleName(dvd,title_name);
2166 fprintf(stdout,"\n\n\nDVD-Video information of the DVD with tile %s\n\n", title_name);
2168 /* Print file structure */
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);
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);
2178 fprintf(stdout,"\tVIDEO_TS.BUP\t%i\n", title_set_info->title_set[0].size_bup);
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);
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]);
2190 fprintf(stdout,"\tVTS_%02i_0.BUP\t%i\n", i + 1, title_set_info->title_set[i + 1].size_bup);
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");
2202 fprintf(stdout,"\tThe aspect ratio of the main feature is unknown\n");
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);
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;
2215 if(channels < titles_info->titles[f].audio_channels) {
2216 channels = titles_info->titles[f].audio_channels;
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);
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);
2237 fprintf(stdout,"\t\tThe aspect ratio of title set %d is unknown\n", f + 1);
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);
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);
2254 DVDFreeTitlesInfo(titles_info);
2255 DVDFreeTitleSetInfo(title_set_info);
2260 int main(int argc, char *argv[]){
2272 int do_title_set = 0;
2282 /* DVD Video device */
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;
2294 /* Title of the DVD */
2295 char title_name[33]="";
2296 char * provided_title_name=NULL;
2299 char * targetdir=NULL;
2301 /* Temp filename,dirname */
2302 char targetname[PATH_MAX];
2303 struct stat fileinfo;
2306 /* The DVD main structure */
2307 dvd_reader_t * _dvd=NULL;
2311 /*Todo do isdigit check */
2313 while ((flags = getopt(argc, argv, "MFI?hi:v:a:o:n:s:e:t:T:")) != -1) {
2316 if(optarg[0]=='-') usage();
2320 if(optarg[0]=='-') usage();
2321 verbose_temp = optarg;
2324 if(optarg[0]=='-') usage();
2328 if(optarg[0]=='-') usage();
2329 provided_title_name = optarg;
2332 if(optarg[0]=='-') usage();
2333 aspect_temp = optarg;
2336 if(optarg[0]=='-') usage();
2337 start_chapter_temp = optarg;
2340 if(optarg[0]=='-') usage();
2341 end_chapter_temp = optarg;
2344 if(optarg[0]=='-') usage();
2345 titles_temp = optarg;
2348 if(optarg[0]=='-') usage();
2349 title_set_temp = optarg;
2377 if (targetdir == NULL && do_info == 0) {
2382 if(verbose_temp == NULL) {
2385 verbose = atoi(verbose_temp);
2388 if (aspect_temp == NULL) {
2389 /* Deafult to 16:9 aspect ratio */
2392 aspect = atoi(aspect_temp);
2395 if((aspect != 0) && (aspect != 3) && (do_info == 0)){
2400 if ( titles_temp != NULL) {
2401 titles = atoi(titles_temp);
2408 if ( start_chapter_temp !=NULL) {
2409 start_chapter = atoi(start_chapter_temp);
2410 if ( start_chapter < 1 || start_chapter > 99 ) {
2416 if (end_chapter_temp != NULL) {
2417 end_chapter = atoi(end_chapter_temp);
2418 if ( end_chapter < 1 || end_chapter > 99 ) {
2424 if ( end_chapter_temp != NULL || start_chapter_temp != NULL) {
2425 if( end_chapter_temp == NULL) {
2427 } else if ( start_chapter_temp == NULL) {
2430 if ( end_chapter < start_chapter ) {
2436 if ( titles_temp != NULL && ((end_chapter_temp != NULL) || (start_chapter_temp != NULL))) {
2438 } else if ((titles_temp != NULL) && ((end_chapter_temp == NULL) && (start_chapter_temp == NULL))) {
2441 if (do_chapter && (titles_temp == NULL)) {
2445 if ( title_set_temp != NULL ) {
2446 title_set = atoi(title_set_temp);
2447 if ( title_set > 99 || title_set < 0 ) {
2454 if (do_info + do_titles + do_chapter + do_feature + do_title_set + do_mirror > 1 ) {
2457 } else if ( do_info + do_titles + do_chapter + do_feature + do_title_set + do_mirror == 0) {
2462 fprintf(stderr,"After args\n");
2466 _dvd = DVDOpen(dvd);
2471 DVDDisplayInfo(_dvd, dvd);
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");
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");
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';
2495 strcpy(title_name,provided_title_name);
2501 sprintf(targetname,"%s",targetdir);
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");
2508 if (mkdir(targetname, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
2509 fprintf(stderr,"Faild creating target directory\n");
2517 sprintf(targetname,"%s/%s",targetdir, title_name);
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");
2524 if (mkdir(targetname, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
2525 fprintf(stderr,"Faild creating title directory\n");
2532 sprintf(targetname,"%s/%s/VIDEO_TS",targetdir, title_name);
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");
2539 if (mkdir(targetname, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
2540 fprintf(stderr,"Faild creating VIDEO_TS directory\n");
2549 fprintf(stderr,"After dirs\n");
2554 if ( DVDMirror(_dvd, targetdir, title_name) != 0 ) {
2555 fprintf(stderr, "Mirror of DVD faild\n");
2562 fprintf(stderr,"After Mirror\n");
2567 if (DVDMirrorTitleSet(_dvd, targetdir, title_name, title_set) != 0) {
2568 fprintf(stderr, "Mirror of title set %d faild\n", title_set);
2576 fprintf(stderr,"After Title Set\n");
2582 if ( DVDMirrorMainFeature(_dvd, targetdir, title_name) != 0 ) {
2583 fprintf(stderr, "Mirror of main feature film of DVD faild\n");
2591 if (DVDMirrorTitles(_dvd, targetdir, title_name, titles) != 0) {
2592 fprintf(stderr, "Mirror of title %d faild\n", titles);
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);