NTSC <-> PAL VOB conversion?

Stephen Hocking shocking at houston.rr.com
Thu Jul 22 14:40:54 PDT 2004


All,

Now that I've figured out how to back up my DVDs, using libdvdread,
cdrecord and dvdbackup, I'm curious to know if anyone's managed to
figure out a way to convert the VOBs to a different video format.
The dvdbackup program I use creates a directory structure on disk
that one can mess with. Any ideas?



	Stephen

-------------- next part --------------
/*
 * Copyright (C) 2002  Olaf Beck <olaf_sc at yahoo.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* dvdbackup version 0.1 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/errno.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <dvdread/dvd_reader.h>
#include <dvdread/ifo_read.h>
#include <dvdread/ifo_print.h>


#define MAXNAME 256

/*Flag for verbose mode */
int verbose;
int aspect;


/* Structs to keep title set information in */

typedef struct {
  int		size_ifo;
  int		size_menu;
  int		size_bup;
  int		number_of_vob_files;
  int		size_vob[10];
} title_set_t;

typedef struct {
  int		number_of_title_sets;
  title_set_t  *title_set;
} title_set_info_t;


typedef struct {
  int		title;
  int		title_set;
  int		vts_title;
  int		chapters;
  int		aspect_ratio;
  int		angles;
  int		audio_tracks;
  int		audio_channels;
  int		sub_pictures;
} titles_t;

typedef struct {
  int		main_title_set;
  int		number_of_titles;
  titles_t	*titles;
} titles_info_t;


void bsort_max_to_min(int sector[], int title[], int size);

/* Usage:
	To gather info about the dvd:
		dvdbackup -i /dev/dvd -I

	Gerneral backup information:
		If your backup directory is /my/dvd/backup/dir/
		specified with the "-o" flag. Then dvdbackup
		will create a DVD-Video structure under
		/my/dvd/backup/dir/TITLE_NAME/VIDEO_TS.

		Since the title is "uniq" you can use the same dir
		for all your DVD backups. If it happens to have a
		generic title dvdbackup will exit with a return value
		of 2. And you will need to specify a title name with
		the -n switch.

		dvdbackup will always mimic the original DVD-Video
		structure. Hence if you e.g. use the -M (mirror) you
		will get an exact duplicate of the original. This
		means that every file will be have the same size as
		the original one. Like wise goes also for the -F
		and the -T switch.

		However the -t and (-t -s/-e) switch is a bit
		different the titles sectors will be written to the
		original file but not at the same offset as the
		original one since they may be gaps in the cell
		structure that we don't fill.


	To backup the whole DVD

		dvdbackup -M -i/dev/dvd -o/my/dvd/backup/dir/

		This action creates a valid DVD-Video structure
		that can be burned to a DVD-/+R(W) with help of
		mkisofs version 1.11a27 or later


	To backup the main feature of the DVD:

		dvdbackup -F -i/dev/dvd -o/my/dvd/backup/dir/

		This action creates a valid DVD-Video structure
		of the feature title set

		dvdbackup defaults to get the 16:9 version of the
		main feature if a 4:3 is also present on the DVD.
		To get the 4:3 version use -a 0.

		dvdbackup makes it best to make a inteligent guess
		what is the main feature of the DVD - in case it fails
		please send a bug report.


	To backup a title set

		dvdbackup -T 2 -i/dev/dvd -o/my/dvd/backup/dir/

		where "-T 2" specifies that you want to backup
		title set 2 i.e. all VTS_02_X.XXX files.

		This action creates a valid DVD-Video structure
		of the specified title set


	To backup a title:

		dvdbackup -t 1 -i/dev/dvd -o/my/dvd/backup/dir

		This action backups all cells that forms the
		specified title. Note that there can be sector
		gaps in between one cell and an other. dvdbackup
		will backup all sectors that belongs to the title
		but will skip sectors that aren't a part of the title.


	To backup a specific chapter or chapters from a title:

		dvdbackup -t 1 -s 20 -e 25 -i/dev/dvd -o/my/dvd/backup/dir

		This action will backup chapter 20 to 25 in title 1, as with
		the backup of a title there can be sector gaps between one chapter
		(cell) and on other.dvdbackup will backup all sectors that belongs
		to the title 1 chapter 20 to 25 but will skip sectors that aren't
		a part of the title 1 chapter 20 to 25.

		To backup a single chapter e.g. chapter 20 do -s 20 -e 20
		To backup from chapter 20 to the end chapter use only -s 20
		To backup to chapter 20 from the first chapter use only -e 20

		You can skip the -t switch and let the program guess the title although
		it's not recomened.

		If you specify a chapter that his higher than the last chapter of the title
		dvdbackup will turncate to the highest chapter of the title.

	Return values:
		0 on success
		1 on usage error
		2 on title name error
		-1 on failur


	Todo - i.e. what's on the agenda.
		Make the main feature guessing algoritm better. Not that it doesn't do
		it's job, but it's implementation it's that great. I would also like
		to preserve more information about the main feature since that would
		let me preform better implementations in other functions that depends
		on the titles_info_t and title_set_info_t strcutures.

		Make it possible to extract cells in a title not just chapters (very
		easy so it will definitly be in the next version).

		Make a split mirror (-S) option that divides a DVD-9 to two valid DVD-5
		video structures. This is not a trivial hack and it's my main goal
		the next month or so. It involves writing ifoedit and vobedit
		libraries in order to be able to manipulate both the IFO structures
		and the VOB files. Out of this will most probably also come tscreate
		and vtscreate which will enable you to make a very simple DVD-Video
		from MPEG-1/2 source.

*/


void usage(){
	fprintf(stderr,"\nUsage: dvdbackup [options]\n");
	fprintf(stderr,"\t-i device\twhere device is your dvd device\n");
	fprintf(stderr,"\t-v X\t\twhere X is the amount of verbosity\n");
	fprintf(stderr,"\t-I\t\tfor information about the DVD\n");
	fprintf(stderr,"\t-o directory\twhere directory is your backup target\n");
	fprintf(stderr,"\t-M\t\tbackup the whole DVD\n");
	fprintf(stderr,"\t-F\t\tbackup the main feature of the DVD\n");
	fprintf(stderr,"\t-T X\t\tbackup title set X\n");
	fprintf(stderr,"\t-t X\t\tbackup title X\n");
	fprintf(stderr,"\t-s X\t\tbackup from chapter X\n");
	fprintf(stderr,"\t-e X\t\tbackup to chapter X\n");
	fprintf(stderr,"\t-a 0\t\tto get aspect ratio 4:3 instead of 16:9 if both are present\n");
	fprintf(stderr,"\t-h\t\tprint a brief usage message\n");
	fprintf(stderr,"\t-?\t\tprint a brief usage message\n\n");
	fprintf(stderr,"\t-i is manditory\n");
	fprintf(stderr,"\t-o is manditory except if you use -I\n");
	fprintf(stderr,"\t-a is option to the -F switch and has no effect on other options\n");
	fprintf(stderr,"\t-s and -e should prefereibly be used together with -t \n\n");
	exit(1);
}

int CheckSizeArray(const int size_array[], int reference, int target) {
	if ( (size_array[reference]/size_array[target] == 1) &&
	     ((size_array[reference] * 2 - size_array[target])/ size_array[target] == 1) &&
	     ((size_array[reference]%size_array[target] * 3) < size_array[reference]) ) {
		/* We have a dual DVD with two feature films - now lets see if they have the same amount of chapters*/
		return(1);
	} else {
		return(0);
	}
}


int CheckAudioSubChannels(int audio_audio_array[], int title_set_audio_array[],
			  int subpicture_sub_array[], int title_set_sub_array[],
			  int channels_channel_array[],int title_set_channel_array[],
			  int reference, int candidate, int title_sets) {

	int temp, i, found_audio, found_sub, found_channels;

	found_audio=0;
	temp = audio_audio_array[reference];
	for (i=0 ; i < title_sets ; i++ ) {
		if ( audio_audio_array[i] < temp ) {
			break;
		}
		if ( candidate == title_set_audio_array[i] ) {
			found_audio=1;
			break;
		}

	}

	found_sub=0;
	temp = subpicture_sub_array[reference];
	for (i=0 ; i < title_sets ; i++ ) {
		if ( subpicture_sub_array[i] < temp ) {
			break;
		}
		if ( candidate == title_set_sub_array[i] ) {
			found_sub=1;
			break;
		}

	}


	found_channels=0;
	temp = channels_channel_array[reference];
	for (i=0 ; i < title_sets ; i++ ) {
		if ( channels_channel_array[i] < temp ) {
			break;
		}
		if ( candidate == title_set_channel_array[i] ) {
			found_channels=1;
			break;
		}

	}


	return(found_audio + found_sub + found_channels);
}




int DVDWriteCells(dvd_reader_t * dvd, int cell_start_sector[], int cell_end_sector[],
   int length, int titles, title_set_info_t * title_set_info, titles_info_t * titles_info, char * targetdir,char * title_name){


	/* Loop variables */
	int i, f;


	/* Vob control */
	int vob;

	/* Temp filename,dirname */
	char targetname[PATH_MAX];

	/* Write buffer */

	unsigned char * buffer=NULL;

	/* File Handler */
	int streamout;

	int size;
	int left;
	int leftover;

	/* Buffer size in DVD sectors */
	/* Currently set to 1MB */
	int buff = 512;
	int tsize;


	/* Offsets */
	int soffset;
	int offset;


	/* DVD handler */
	dvd_file_t   *	dvd_file=NULL;

	int title_set;
	int number_of_vob_files;

#ifdef DEBUG
	fprintf(stderr,"DVDWriteCells: length is %d\n", length);

#endif


	title_set = titles_info->titles[titles - 1].title_set;
	number_of_vob_files = title_set_info->title_set[title_set].number_of_vob_files;
#ifdef DEBUG
		fprintf(stderr,"DVDWriteCells: title set is %d\n", title_set);
		fprintf(stderr,"DVDWriteCells: vob files are %d\n", number_of_vob_files);

#endif



	/* Remove all old files silently if they exists */

	for ( i = 0 ; i < 10 ; i++ ) {
		sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, i + 1);
#ifdef DEBUG
		fprintf(stderr,"DVDWriteCells: file is %s\n", targetname);

#endif

		unlink( targetname);

	}




	/* Loop through all sectors and find the right vob */
	for (f = 0; f < length ; f++) {

		soffset=0;
		offset=0;


		/* Now figure which vob we will use and write to that vob and if there is a left over write to the next vob*/

		for ( i = 0; i < number_of_vob_files ; i++ ) {


			tsize = title_set_info->title_set[title_set].size_vob[i];

			if (tsize%2048 != 0) {
				fprintf(stderr, "The Title VOB number %d of title set %d doesn't have a valid DVD size\n", i + 1, title_set);
				return(1);
			} else {
				soffset = offset;
				offset = offset + tsize/2048;
			}
#ifdef DEBUG
			fprintf(stderr,"DVDWriteCells: soffset is %d\n", soffset);
			fprintf(stderr,"DVDWriteCells: offset is %d\n", offset);
#endif
			/* Find out if this is the right vob */
			if( soffset <= cell_start_sector[f]  && offset > cell_start_sector[f] ) {
#ifdef DEBUG
				fprintf(stderr,"DVDWriteCells: got it \n");
#endif
				leftover=0;
				soffset = cell_start_sector[f];
				if ( cell_end_sector[f] > offset ) {
					leftover = cell_end_sector[f] - offset + 1;
				} else {
					size = cell_end_sector[f] - cell_start_sector[f] + 1;
				}
#ifdef DEBUG
				fprintf(stderr,"DVDWriteCells: size is %d\n", size);
#endif
				vob = i + 1;
				break;
			}

		}
#ifdef DEBUG
		fprintf(stderr,"DVDWriteCells: Writing soffset is %d and leftover is %d\n", soffset, leftover);
#endif




		/* Create VTS_XX_X.VOB */
		if (title_set == 0) {
			fprintf(stderr,"Don't try to copy chapters from the VMG domain there aren't any\n");
			return(1);
		} else {
			sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
		}

#ifdef DEBUG
		fprintf(stderr,"DVDWriteCells: 1\n");
#endif


		if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(unsigned char))) == NULL) {
			fprintf(stderr, "Out of memory coping %s\n", targetname);
			return(1);
		}

#ifdef DEBUG
		fprintf(stderr,"DVDWriteCells: 2\n");
#endif


		if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0644)) == -1) {
			fprintf(stderr, "Error creating %s\n", targetname);
			perror("");
			return(1);
		}

#ifdef DEBUG
		fprintf(stderr,"DVDWriteCells: 3\n");
#endif


		if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
			fprintf(stderr, "Faild opending TITLE VOB\n");
			free(buffer);
			close(streamout);
			return(1);
		}

		left = size;

#ifdef DEBUG
		fprintf(stderr,"DVDWriteCells: left is %d\n", left);
#endif

		while( left > 0 ) {

			if (buff > left) {
				buff = left;
			}
			if ( DVDReadBlocks(dvd_file,soffset,buff, buffer) != buff) {
				fprintf(stderr, "Error reading MENU VOB\n");
				free(buffer);
				DVDCloseFile(dvd_file);
				close(streamout);
				return(1);
			}


			if (write(streamout,buffer,buff *  2048) != buff * 2048) {
				fprintf(stderr, "Error writing TITLE VOB\n");
				free(buffer);
				close(streamout);
				return(1);
			}

			soffset = soffset + buff;
			left = left - buff;

		}

		DVDCloseFile(dvd_file);
		free(buffer);
		close(streamout);


		if ( leftover != 0 ) {

			vob = vob + 1;

			if (title_set == 0) {
				fprintf(stderr,"Don't try to copy chapters from the VMG domain there aren't any\n");
				return(1);
			} else {
				sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
			}


			if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(unsigned char))) == NULL) {
				fprintf(stderr, "Out of memory coping %s\n", targetname);
				close(streamout);
				return(1);
			}


			if ((streamout = open(targetname, O_WRONLY | O_CREAT | O_APPEND, 0644)) == -1) {
				fprintf(stderr, "Error creating %s\n", targetname);
				perror("");
				return(1);
			}


			if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
				fprintf(stderr, "Faild opending TITLE VOB\n");
				free(buffer);
				close(streamout);
				return(1);
			}

			left = leftover;

			while( left > 0 ) {

				if (buff > left) {
					buff = left;
				}
				if ( DVDReadBlocks(dvd_file,offset,buff, buffer) != buff) {
					fprintf(stderr, "Error reading MENU VOB\n");
					free(buffer);
					DVDCloseFile(dvd_file);
					close(streamout);
					return(1);
				}


				if (write(streamout,buffer,buff *  2048) != buff * 2048) {
					fprintf(stderr, "Error writing TITLE VOB\n");
					free(buffer);
					close(streamout);
					return(1);
				}

				offset = offset + buff;
				left = left - buff;

			}

			DVDCloseFile(dvd_file);
			free(buffer);
			close(streamout);
		}

	}
	return(0);
}



void FreeSortArrays( int chapter_chapter_array[], int title_set_chapter_array[],
		int angle_angle_array[], int title_set_angle_array[],
		int subpicture_sub_array[], int title_set_sub_array[],
		int audio_audio_array[], int title_set_audio_array[],
		int size_size_array[], int title_set_size_array[],
		int channels_channel_array[], int title_set_channel_array[]) {


	free(chapter_chapter_array);
	free(title_set_chapter_array);

	free(angle_angle_array);
	free(title_set_angle_array);

	free(subpicture_sub_array);
	free(title_set_sub_array);

	free(audio_audio_array);
	free(title_set_audio_array);

	free(size_size_array);
	free(title_set_size_array);

	free(channels_channel_array);
	free(title_set_channel_array);
}


titles_info_t * DVDGetInfo(dvd_reader_t * _dvd) {

	/* title interation */
	int counter, i, f;

	/* Our guess */
	int candidate;
	int multi = 0;
	int dual = 0;


	int titles;
	int title_sets;

	/* Arrays for chapter, angle, subpicture, audio, size, aspect, channels -  file_set relationship */

	/* Size == number_of_titles */
	int * chapter_chapter_array;
	int * title_set_chapter_array;

	int * angle_angle_array;
	int * title_set_angle_array;

	/* Size == number_of_title_sets */

	int * subpicture_sub_array;
	int * title_set_sub_array;

	int * audio_audio_array;
	int * title_set_audio_array;

	int * size_size_array;
	int * title_set_size_array;

	int * channels_channel_array;
	int * title_set_channel_array;

	/* Temp helpers */
	int channels;
	int temp;
	int found;
	int chapters_1;
	int chapters_2;
	int found_chapter;
	int number_of_multi;


	/*DVD handlers*/
	ifo_handle_t * vmg_ifo=NULL;
	dvd_file_t   *  vts_title_file=NULL;

	titles_info_t * titles_info=NULL;

	/*  Open main info file */
	vmg_ifo = ifoOpen( _dvd, 0 );
	if( !vmg_ifo ) {
        	fprintf( stderr, "Can't open VMG info.\n" );
        	return (0);
    	}

	titles = vmg_ifo->tt_srpt->nr_of_srpts;
	title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;

	if ((vmg_ifo->tt_srpt == 0) || (vmg_ifo->vts_atrt == 0)) {
		ifoClose(vmg_ifo);
		return(0);
	}


	/* Todo fix malloc check */
	titles_info = ( titles_info_t *)malloc(sizeof(titles_info_t));
	titles_info->titles = (titles_t *)malloc((titles)* sizeof(titles_t));

	titles_info->number_of_titles = titles;


	chapter_chapter_array = malloc(titles * sizeof(int));
	title_set_chapter_array = malloc(titles * sizeof(int));

	/*currently not used in the guessing */
	angle_angle_array = malloc(titles * sizeof(int));
	title_set_angle_array = malloc(titles * sizeof(int));


	subpicture_sub_array = malloc(title_sets * sizeof(int));
	title_set_sub_array = malloc(title_sets * sizeof(int));

	audio_audio_array = malloc(title_sets * sizeof(int));
	title_set_audio_array = malloc(title_sets * sizeof(int));

	size_size_array = malloc(title_sets * sizeof(int));
	title_set_size_array = malloc(title_sets * sizeof(int));

	channels_channel_array = malloc(title_sets * sizeof(int));
	title_set_channel_array = malloc(title_sets * sizeof(int));


	/* Interate over the titles nr_of_srpts */


	for (counter=0; counter < titles; counter++ )  {
		/* For titles_info */
		titles_info->titles[counter].title = counter + 1;
		titles_info->titles[counter].title_set = vmg_ifo->tt_srpt->title[counter].title_set_nr;
		titles_info->titles[counter].vts_title = vmg_ifo->tt_srpt->title[counter].vts_ttn;
		titles_info->titles[counter].chapters = vmg_ifo->tt_srpt->title[counter].nr_of_ptts;
		titles_info->titles[counter].angles = vmg_ifo->tt_srpt->title[counter].nr_of_angles;

		/* For main title*/
		chapter_chapter_array[counter] = vmg_ifo->tt_srpt->title[counter].nr_of_ptts;
		title_set_chapter_array[counter] = vmg_ifo->tt_srpt->title[counter].title_set_nr;
		angle_angle_array[counter] = vmg_ifo->tt_srpt->title[counter].nr_of_angles;
		title_set_angle_array[counter] = vmg_ifo->tt_srpt->title[counter].title_set_nr;
	}

	/* Interate over vmg_nr_of_title_sets */

	for (counter=0; counter < title_sets ; counter++ )  {

		/* Picture*/
		subpicture_sub_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_subp_streams;
		title_set_sub_array[counter] = counter + 1;


		/* Audio */
		audio_audio_array[counter] = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_audio_streams;
		title_set_audio_array[counter] = counter + 1;

		channels=0;
		for  (i=0; i < audio_audio_array[counter]; i++) {
			if ( channels < vmg_ifo->vts_atrt->vts[counter].vtstt_audio_attr[i].channels + 1) {
				channels = vmg_ifo->vts_atrt->vts[counter].vtstt_audio_attr[i].channels + 1;
			}

		}
		channels_channel_array[counter] = channels;
		title_set_channel_array[counter] = counter + 1;

		/* For tiles_info */
		for (f=0; f < titles_info->number_of_titles ; f++ ) {
			if ( titles_info->titles[f].title_set == counter + 1 ) {
				titles_info->titles[f].aspect_ratio = vmg_ifo->vts_atrt->vts[counter].vtstt_vobs_video_attr.display_aspect_ratio;
				titles_info->titles[f].sub_pictures = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_subp_streams;
				titles_info->titles[f].audio_tracks = vmg_ifo->vts_atrt->vts[counter].nr_of_vtstt_audio_streams;
				titles_info->titles[f].audio_channels = channels;
			}
		}

	}


	/* Close the VMG ifo file we got all the info we need */
        ifoClose(vmg_ifo);


	for (counter=0; counter < title_sets; counter++ ) {

		vts_title_file = DVDOpenFile(_dvd, counter + 1, DVD_READ_TITLE_VOBS);

		if (vts_title_file  != 0) {
			size_size_array[counter] = DVDFileSize(vts_title_file);
			DVDCloseFile(vts_title_file);
		} else {
			size_size_array[counter] = 0;
		}

		title_set_size_array[counter] = counter + 1;


	}


	/* Sort all arrays max to min */

	bsort_max_to_min(chapter_chapter_array, title_set_chapter_array, titles);
	bsort_max_to_min(angle_angle_array, title_set_angle_array, titles);
	bsort_max_to_min(subpicture_sub_array, title_set_sub_array, title_sets);
	bsort_max_to_min(audio_audio_array, title_set_audio_array, title_sets);
	bsort_max_to_min(size_size_array, title_set_size_array, title_sets);
	bsort_max_to_min(channels_channel_array, title_set_channel_array, title_sets);


	/* Check if the second biggest one actually can be a feature title */
	/* Here we will take do biggest/second and if that is bigger than one it's not a feauture title */
	/* Now this is simply not enough since we have to check that the diff between the two of them is small enough
	 to consider the second one a feature title we are doing two checks (biggest  + biggest - second) /second == 1
	 and biggest%second * 3 < biggest */

	if ( CheckSizeArray(size_size_array, 0, 1)  == 1 ) {
		/* We have a dual DVD with two feature films - now lets see if they have the same amount of chapters*/

		chapters_1 = 0;
		for (i=0 ; i < titles ; i++ ) {
			if (titles_info->titles[i].title_set == title_set_size_array[0] ) {
				if ( chapters_1 < titles_info->titles[i].chapters){
					chapters_1 = titles_info->titles[i].chapters;
				}
			}
		}

		chapters_2 = 0;
		for (i=0 ; i < titles ; i++ ) {
			if (titles_info->titles[i].title_set == title_set_size_array[1] ) {
				if ( chapters_2 < titles_info->titles[i].chapters){
					chapters_2 = titles_info->titles[i].chapters;
				}
			}
		}

		if (  vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio ==
			vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio) {
			/* In this case it's most likely so that we have a dual film but with different context
			They are with in the same size range and have the same aspect ratio
			I would guess that such a case is e.g. a DVD containing several episodes of a TV serie*/
			candidate = title_set_size_array[0];
			multi = 1;
		} else if ( chapters_1 == chapters_2  && vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio !=
			vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio){
			/* 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*/
			if ( vmg_ifo->vts_atrt->vts[title_set_size_array[0] - 1].vtstt_vobs_video_attr.display_aspect_ratio == aspect) {
				candidate = title_set_size_array[0];
			} else if ( vmg_ifo->vts_atrt->vts[title_set_size_array[1] - 1].vtstt_vobs_video_attr.display_aspect_ratio == aspect) {
				candidate = title_set_size_array[1];
			} else {
				/* Okay we didn't have the prefered aspect ratio - just make the biggest one a candidate */
				/* please send  report if this happens*/
				fprintf(stderr, "You have encountered a very special DVD, please send a bug report along with all IFO files from this title\n");
				candidate = title_set_size_array[0];
			}
			dual = 1;
		}
	} else {
		candidate = title_set_size_array[0];
	}


	/* Lets start checking audio,sub pictures and channels my guess is namly that a special suburb will put titles with a lot of
	 chapters just to make our backup hard */


	found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
				      subpicture_sub_array, title_set_sub_array,
				      channels_channel_array, title_set_channel_array,
				      0 , candidate, title_sets);


	/* Now lets see if we can find our candidate among the top most chapters */
	found_chapter=6;
	temp = chapter_chapter_array[0];
	for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
		if ( candidate == title_set_chapter_array[i] ) {
			found_chapter=i+1;
			break;
		}
	}


	if (((found == 3) && (found_chapter == 1) && (dual == 0) && (multi == 0)) || ((found == 3) && (found_chapter < 3 ) && (dual == 1))) {

		FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
				angle_angle_array, title_set_angle_array,
				subpicture_sub_array, title_set_sub_array,
				audio_audio_array, title_set_audio_array,
				size_size_array, title_set_size_array,
				channels_channel_array, title_set_channel_array);
		titles_info->main_title_set = candidate;
		return(titles_info);

	}

	if (multi == 1) {
		for (i=0 ; i < title_sets ; ++i) {
			if (CheckSizeArray(size_size_array, 0, i + 1)  == 0) {
					break;
			}
		}
		number_of_multi = i;
		for (i = 0; i < number_of_multi; i++ ) {
			if (title_set_chapter_array[0] == i + 1) {
				candidate = title_set_chapter_array[0];
			}
		}

		found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
			      subpicture_sub_array, title_set_sub_array,
			      channels_channel_array, title_set_channel_array,
			      0 , candidate, title_sets);

		if (found == 3) {
			FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
					angle_angle_array, title_set_angle_array,
					subpicture_sub_array, title_set_sub_array,
					audio_audio_array, title_set_audio_array,
					size_size_array, title_set_size_array,
					channels_channel_array, title_set_channel_array);
			titles_info->main_title_set = candidate;
			return(titles_info);
		}
	}

	/* 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*/
	/*No matter what we will more or less only return the biggest VOB*/
	/* Lets see if we can find our biggest one - then we return that one */
	candidate = title_set_size_array[0];

	found = CheckAudioSubChannels(audio_audio_array, title_set_audio_array,
				      subpicture_sub_array, title_set_sub_array,
				      channels_channel_array, title_set_channel_array,
				      0 , candidate, title_sets);

	/* Now lets see if we can find our candidate among the top most chapters */

	found_chapter=5;
	temp = chapter_chapter_array[0];
	for (i=0 ; (i < titles) && (i < 4) ; i++ ) {
		if ( candidate == title_set_chapter_array[i] ) {
			found_chapter=i+1;
			break;
		}

	}

	/* Here we take chapters in to consideration*/
	if (found == 3) {
		FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
				angle_angle_array, title_set_angle_array,
				subpicture_sub_array, title_set_sub_array,
				audio_audio_array, title_set_audio_array,
				size_size_array, title_set_size_array,
				channels_channel_array, title_set_channel_array);
		titles_info->main_title_set = candidate;
		return(titles_info);
	}

	/* Here we do but we lower the treshold for audio, sub and channels */

	if ((found > 1 ) && (found_chapter <= 4)) {
		FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
				angle_angle_array, title_set_angle_array,
				subpicture_sub_array, title_set_sub_array,
				audio_audio_array, title_set_audio_array,
				size_size_array, title_set_size_array,
				channels_channel_array, title_set_channel_array);
		titles_info->main_title_set = candidate;
		return(titles_info);

		/* return it */
	} else {
		/* Here we give up and just return the biggest one :(*/
		/* Just return the biggest badest one*/
		FreeSortArrays( chapter_chapter_array, title_set_chapter_array,
				angle_angle_array, title_set_angle_array,
				subpicture_sub_array, title_set_sub_array,
				audio_audio_array, title_set_audio_array,
				size_size_array, title_set_size_array,
				channels_channel_array, title_set_channel_array);
		titles_info->main_title_set = candidate;
		return(titles_info);
	}


	/* Some radom thoughts about DVD guessing */
	/* We will now gather as much data about the DVD-Video as we can and
	then make a educated guess which one is the main feature film of it*/


	/* Make a tripple array with chapters, angles and title sets
	 - sort out dual title sets with a low number of chapters. Tradtionaly
	 the title set with most chapters is the main film. Number of angles is
	 keept as a reference point of low value*/

	/* Make a dual array with number of audio streams, sub picture streams
	 and title sets. Tradtionaly the main film has many audio streams
	 since it's supposed be synconised e.g. a English film syncronised/dubbed
	 in German. We are also keeping track of sub titles since it's also indication
	 of the main film*/

	/* Which title set is the biggest one - dual array with title sets and size
	 The biggest one is usally the main film*/

	/* Which title set is belonging to title 1 and how many chapters has it. Once
	 again tradtionaly title one is belonging to the main film*/

	/* Yes a lot of rant - but it helps me think - some sketch on paper or in the mind
	 I sketch in the comments - beside it will help you understand the code*/

	/* Okay lets see if the biggest one has most chapters, it also has more subtitles
	 and audio tracks than the second one and it's title one.
	 Done it must be the main film

	 Hmm the biggest one doesn't have the most chapters?

	 See if the second one has the same amount of chapters and is the biggest one
	 If so we probably have a 4:3 and 16:9 versions of film on the same disk

	 Now we fetch the 16:9 by default unless the forced to do 4:3
	 First check which one is which.
	 If the 16:9 is the biggest one and has the same or more subtile, audio streams
	 then we are happy unless we are in force 4:3 mode :(
	 The same goes in reverse if we are in force 4:3 mode


	 Hmm, in force 4:3 mode - now we check how much smaller than the biggest one it is
	 (or the reverse if we are in 16:9 mode)

	 Generally a reverse division should render in 1 and with a small modulo - like wise
	 a normal modulo should give us a high modulo

	 If we get more than one it's of cource a fake however if we get just one we still need to check
	 if we subtract the smaller one from the bigger one we should end up with a small number - hence we
	 need to multiply it more than 4 times to get it bigger than the biggest one. Now we know that the
	 two biggest once are really big and possibly carry the same film in differnet formats.

	 We will now return the prefered one either 16:9 or 4:3 but we will first check that the one
	 we return at lest has two or more audio tracks. We don't want it if the other one has a lot
	 more sound (we may end up with a film that only has 2ch Dolby Digital so we want to check for
	 6ch DTS or Dolby Digital. If the prefered one doesn't have those features but the other once has
	 we will return the other one.
	 */

}




int DVDCopyTileVobX(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, int vob, char * targetdir,char * title_name) {

	/* Loop variable */
	int i;

	/* Temp filename,dirname */
	char targetname[PATH_MAX];
	struct stat fileinfo;

	/* Write buffer */

	unsigned char * buffer=NULL;
	unsigned char buffy; /* :-) */

	/* File Handler */
	int streamout;

	int size;
	int left;

	/* Buffer size in DVD sectors */
	/* Currently set to 1MB */
	int buff = 512;
	int offset = 0;
	int tsize;

	/* DVD handler */
	dvd_file_t   *	dvd_file=NULL;

	if (title_set_info->number_of_title_sets + 1 < title_set) {
		fprintf(stderr,"Faild num title test\n");
		return(1);
	}

	if (title_set_info->title_set[title_set].number_of_vob_files < vob ) {
		fprintf(stderr,"Faild vob test\n");
		return(1);
	}

	if (title_set_info->title_set[title_set].size_vob[0] == 0 ) {
		fprintf(stderr,"Faild vob 1 size test\n");
		return(0);
	} else if (title_set_info->title_set[title_set].size_vob[vob - 1] == 0 ) {
		fprintf(stderr,"Faild vob %d test\n", vob);
		return(0);
	} else {
		size = title_set_info->title_set[title_set].size_vob[vob - 1]/2048;
		if (title_set_info->title_set[title_set].size_vob[vob - 1]%2048 != 0) {
			fprintf(stderr, "The Title VOB number %d of title set %d doesn't have a valid DVD size\n", vob, title_set);
			return(1);
		}
	}
#ifdef DEBUG
	fprintf(stderr,"After we check the vob it self %d\n", vob);
#endif

	/* Create VTS_XX_X.VOB */
	if (title_set == 0) {
		fprintf(stderr,"Don't try to copy a Title VOB from the VMG domain there aren't any\n");
		return(1);
	} else {
		sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_%i.VOB",targetdir, title_name, title_set, vob);
	}



	/* Now figure out the offset we will start at also check that the previus files are of valid DVD size */
	for ( i = 0; i < vob - 1; i++ ) {
		tsize = title_set_info->title_set[title_set].size_vob[i];
		if (tsize%2048 != 0) {
			fprintf(stderr, "The Title VOB number %d of title set %d doesn't have a valid DVD size\n", i + 1, title_set);
			return(1);
		} else {
			offset = offset + tsize/2048;
		}
	}
#ifdef DEBUG
	fprintf(stderr,"The offset for vob %d is %d\n", vob, offset);
#endif


	if (stat(targetname, &fileinfo) == 0) {
		fprintf(stderr, "The Title file %s exists will try to over write it.\n", targetname);
		if (! S_ISREG(fileinfo.st_mode)) {
			fprintf(stderr,"The Title %s file is not valid, it may be a directory\n", targetname);
			return(1);
		} else {
			if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
				fprintf(stderr, "Error opening %s\n", targetname);
				perror("");
				return(1);
			}
		}
	} else {
		if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
			fprintf(stderr, "Error creating %s\n", targetname);
			perror("");
			return(1);
		}
	}

	left = size;

	if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(buffy))) == NULL) {
		fprintf(stderr, "Out of memory coping %s\n", targetname);
		close(streamout);
		return(1);
	}


	if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_TITLE_VOBS))== 0) {
		fprintf(stderr, "Faild opending TITLE VOB\n");
		free(buffer);
		close(streamout);
		return(1);
	}

	while( left > 0 ) {

		if (buff > left) {
			buff = left;
		}
		if ( DVDReadBlocks(dvd_file,offset,buff, buffer) != buff) {
			fprintf(stderr, "Error reading MENU VOB\n");
			free(buffer);
			DVDCloseFile(dvd_file);
			close(streamout);
			return(1);
		}


		if (write(streamout,buffer,buff *  2048) != buff * 2048) {
			fprintf(stderr, "Error writing TITLE VOB\n");
			free(buffer);
			close(streamout);
			return(1);
		}

		offset = offset + buff;
		left = left - buff;

	}

	DVDCloseFile(dvd_file);
	free(buffer);
	close(streamout);
	return(0);

}




int DVDCopyMenu(dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, char * targetdir,char * title_name) {

	/* Temp filename,dirname */
	char targetname[PATH_MAX];
	struct stat fileinfo;

	/* Write buffer */

	unsigned char * buffer=NULL;
	unsigned char buffy; /* :-) */

	/* File Handler */
	int streamout;

	int size;
	int left;

	/* Buffer size in DVD sectors */
	/* Currently set to 1MB */
	int buff = 512;
	int offset = 0;


	/* DVD handler */
	dvd_file_t   *	dvd_file=NULL;

	if (title_set_info->number_of_title_sets + 1 < title_set) {
		return(1);
	}

	if (title_set_info->title_set[title_set].size_menu == 0 ) {
		return(0);
	} else {
		size = title_set_info->title_set[title_set].size_menu/2048;
		if (title_set_info->title_set[title_set].size_menu%2048 != 0) {
			fprintf(stderr, "The Menu VOB of title set %d doesn't have a valid DVD size\n", title_set);
			return(1);
		}
	}

	/* Create VIDEO_TS.VOB or VTS_XX_0.VOB */
	if (title_set == 0) {
		sprintf(targetname,"%s/%s/VIDEO_TS/VIDEO_TS.VOB",targetdir, title_name);
	} else {
		sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_0.VOB",targetdir, title_name, title_set);
	}


	if (stat(targetname, &fileinfo) == 0) {
		fprintf(stderr, "The Menu file %s exists will try to over write it.\n", targetname);
		if (! S_ISREG(fileinfo.st_mode)) {
			fprintf(stderr,"The Menu %s file is not valid, it may be a directory\n", targetname);
			return(1);
		} else {
			if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
				fprintf(stderr, "Error opening %s\n", targetname);
				perror("");
				return(1);
			}
		}
	} else {
		if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
			fprintf(stderr, "Error creating %s\n", targetname);
			perror("");
			return(1);
		}
	}

	left = size;

	if ((buffer = (unsigned char *)malloc(buff * 2048 * sizeof(buffy))) == NULL) {
		fprintf(stderr, "Out of memory coping %s\n", targetname);
		close(streamout);
		return(1);
	}


	if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_MENU_VOBS))== 0) {
		fprintf(stderr, "Faild opending MENU VOB\n");
		free(buffer);
		close(streamout);
		return(1);
	}

	while( left > 0 ) {

		if (buff > left) {
			buff = left;
		}
		if ( DVDReadBlocks(dvd_file,offset,buff, buffer) != buff) {
			fprintf(stderr, "Error reading MENU VOB\n");
			free(buffer);
			DVDCloseFile(dvd_file);
			close(streamout);
			return(1);
		}


		if (write(streamout,buffer,buff *  2048) != buff * 2048) {
			fprintf(stderr, "Error writing MENU VOB\n");
			free(buffer);
			close(streamout);
			return(1);
		}

		offset = offset + buff;
		left = left - buff;

	}

	DVDCloseFile(dvd_file);
	free(buffer);
	close(streamout);
	return(0);

}


int DVDCopyIfoBup (dvd_reader_t * dvd, title_set_info_t * title_set_info, int title_set, char * targetdir,char * title_name) {

	/* Temp filename,dirname */
	char targetname[PATH_MAX];
	struct stat fileinfo;

	/* Write buffer */

	unsigned char * buffer=NULL;
	unsigned char buffy; /* :-) */

	/* File Handler */
	int streamout;

	int size;

	/* DVD handler */
	dvd_file_t   *	dvd_file=NULL;


	if (title_set_info->number_of_title_sets + 1 < title_set) {
		return(1);
	}

	if (title_set_info->title_set[title_set].size_ifo == 0 ) {
		return(0);
	} else {
		size = title_set_info->title_set[title_set].size_ifo;
		if (title_set_info->title_set[title_set].size_ifo%2048 != 0) {
			fprintf(stderr, "The IFO of title set %d doesn't have a valid DVD size\n", title_set);
			return(1);
		}
	}

	/* Create VIDEO_TS.IFO or VTS_XX_0.IFO */

	if (title_set == 0) {
		sprintf(targetname,"%s/%s/VIDEO_TS/VIDEO_TS.IFO",targetdir, title_name);
	} else {
		sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_0.IFO",targetdir, title_name, title_set);
	}

	if (stat(targetname, &fileinfo) == 0) {
		fprintf(stderr, "The IFO file %s exists will try to over write it.\n", targetname);
		if (! S_ISREG(fileinfo.st_mode)) {
			fprintf(stderr,"The IFO %s file is not valid, it may be a directory\n", targetname);
			return(1);
		} else {
			if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
				fprintf(stderr, "Error opening %s\n", targetname);
				perror("");
				return(1);
			}
		}
	} else {
		if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
			fprintf(stderr, "Error creating %s\n", targetname);
			perror("");
			return(1);
		}
	}

	/* Copy VIDEO_TS.IFO, since it's a small file try to copy it in one shot */


	if ((buffer = (unsigned char *)malloc(size * sizeof(buffy))) == NULL) {
		fprintf(stderr, "Out of memory coping %s\n", targetname);
		close(streamout);
		return(1);
	}


	if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_INFO_FILE))== 0) {
		fprintf(stderr, "Faild opending IFO for tile set %d\n", title_set);
		free(buffer);
		close(streamout);
		return(1);
	}

	if ( DVDReadBytes(dvd_file,buffer,size) != size) {
		fprintf(stderr, "Error reading IFO for title set %d\n", title_set);
		free(buffer);
		DVDCloseFile(dvd_file);
		close(streamout);
		return(1);
	}

	DVDCloseFile(dvd_file);

	if (write(streamout,buffer,size) != size) {
		fprintf(stderr, "Error writing %s\n",targetname);
		free(buffer);
		close(streamout);
		return(1);
	}

	free(buffer);
	close(streamout);


	/* Create VIDEO_TS.BUP or VTS_XX_0.BUP */

	if (title_set == 0) {
		sprintf(targetname,"%s/%s/VIDEO_TS/VIDEO_TS.BUP",targetdir, title_name);
	} else {
		sprintf(targetname,"%s/%s/VIDEO_TS/VTS_%02i_0.BUP",targetdir, title_name, title_set);
	}


	if (title_set_info->title_set[title_set].size_bup == 0 ) {
		return(0);
	} else {
		size = title_set_info->title_set[title_set].size_bup;
		if (title_set_info->title_set[title_set].size_bup%2048 != 0) {
			fprintf(stderr, "The BUP of title set %d doesn't have a valid DVD size\n", title_set);
			return(1);
		}
	}


	if (stat(targetname, &fileinfo) == 0) {
		fprintf(stderr, "The BUP file %s exists will try to over write it.\n", targetname);
		if (! S_ISREG(fileinfo.st_mode)) {
			fprintf(stderr,"The BUP %s file is not valid, it may be a directory\n", targetname);
			return(1);
		} else {
			if ((streamout = open(targetname, O_WRONLY | O_TRUNC, 0644)) == -1) {
				fprintf(stderr, "Error opening %s\n", targetname);
				perror("");
				return(1);
			}
		}
	} else {
		if ((streamout = open(targetname, O_WRONLY | O_CREAT, 0644)) == -1) {
			fprintf(stderr, "Error creating %s\n", targetname);
			perror("");
			return(1);
		}
	}



	/* Copy VIDEO_TS.BUP or VTS_XX_0.BUP, since it's a small file try to copy it in one shot */

	if ((buffer = (unsigned char *)malloc(size * sizeof(buffy))) == NULL) {
		fprintf(stderr, "Out of memory coping %s\n", targetname);
		close(streamout);
		return(1);
	}


	if ((dvd_file = DVDOpenFile(dvd, title_set, DVD_READ_INFO_BACKUP_FILE))== 0) {
		fprintf(stderr, "Faild opending BUP for title set %d\n", title_set);
		free(buffer);
		close(streamout);
		return(1);
	}

	if ( DVDReadBytes(dvd_file,buffer,size) != size) {
		fprintf(stderr, "Error reading BUP for title set %d\n", title_set);
		free(buffer);
		DVDCloseFile(dvd_file);
		close(streamout);
		return(1);
	}

	DVDCloseFile(dvd_file);

	if (write(streamout,buffer,size) != size) {
		fprintf(stderr, "Error writing %s\n", targetname);
		free(buffer);
		close(streamout);
		return(1);
	}

	free(buffer);
	close(streamout);

	return(0);
}


int DVDMirrorVMG(dvd_reader_t * dvd, title_set_info_t *  title_set_info,char * targetdir,char * title_name){

	if ( DVDCopyIfoBup(dvd, title_set_info, 0, targetdir, title_name) != 0 ) {
		return(1);
	}

	if ( DVDCopyMenu(dvd, title_set_info, 0, targetdir, title_name) != 0 ) {
		return(1);
	}
	return(0);
}

int DVDMirrorTitleX(dvd_reader_t * dvd, title_set_info_t *  title_set_info, int title_set, char * targetdir,char * title_name) {

	/* Loop through the vobs */
	int i;



	if ( DVDCopyIfoBup(dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
		return(1);
	}

	if ( DVDCopyMenu(dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
		return(1);
	}

	for (i = 0; i < title_set_info->title_set[title_set].number_of_vob_files ; i++) {
#ifdef DEBUG
		fprintf(stderr,"In the VOB copy loop for %d\n", i);
#endif		
		if ( DVDCopyTileVobX(dvd, title_set_info, title_set, i + 1, targetdir, title_name) != 0 ) {
		return(1);
		}
	}


	return(0);
}

int DVDGetTitleName(const char *device, char *title)
{
	/* Variables for filehandel and title string interaction */

	int  filehandle, i, last;

	/* Open DVD device */

	if ( !(filehandle = open(device, O_RDONLY)) ) {
		fprintf(stderr, "Can't open secified device %s - check your DVD device\n", device);
		return(1);
	}

	/* Seek to title of first track, which is at (track_no * 32768) + 40 */

	if ( 32808 != lseek(filehandle, 32808, SEEK_SET) ) {
		close(filehandle);
		fprintf(stderr, "Can't seek DVD device %s - check your DVD device\n", device);
		return(1);
	}

	/* Read the DVD-Video title */

	if ( 32 != read(filehandle, title, 32)) {
		close(filehandle);
		fprintf(stderr, "Can't read title from DVD device %s\n", device);
		return(1);
	}

	/* Terminate the title string */

	title[32] = '\0';


	/* Remove trailing white space */

	last = 32;
	for ( i = 0; i < 32; i++ ) {
		if ( title[i] != ' ' ) { last = i; }
	}

	title[last + 1] = '\0';

	return(0);
}



void bsort_min_to_max(int sector[], int title[], int size){

	int temp_title, temp_sector, i, j;

	for ( i=0; i < size ; i++ ) {
	  for ( j=0; j < size ; j++ ) {
		if (sector[i] < sector[j]) {
			temp_sector = sector[i];
			temp_title = title[i];
			sector[i] = sector[j];
			title[i] = title[j];
			sector[j] = temp_sector;
			title[j] = temp_title;
		}
	  }
	}
}

void bsort_max_to_min(int sector[], int title[], int size){

	int temp_title, temp_sector, i, j;

	for ( i=0; i < size ; i++ ) {
	  for ( j=0; j < size ; j++ ) {
		if (sector[i] > sector[j]) {
			temp_sector = sector[i];
			temp_title = title[i];
			sector[i] = sector[j];
			title[i] = title[j];
			sector[j] = temp_sector;
			title[j] = temp_title;
		}
	  }
	}
}



void uniq(int sector[], int title[], int title_sets_array[], int sector_sets_array[], int titles){
	int  i, j;


	for ( i=0, j=0; j < titles;) {
		if (sector[j] != sector[j+1]) {
			title_sets_array[i]  = title[j];
			sector_sets_array[i] = sector[j];
			i++ ;
			j++ ;
		} else {
			do {
			     if (j < titles) {
				j++ ;
			   }
			} while ( sector[j] == sector[j+1] );

		}
	}

}

void align_end_sector(int cell_start_sector[],int cell_end_sector[], int size) {

	int i;

	for (i = 0; i < size  - 1 ; i++) {
		if ( cell_end_sector[i] >= cell_start_sector[i + 1] ) {
			cell_end_sector[i] = cell_start_sector[i + 1] - 1;
		}
	}
}




void DVDFreeTitleSetInfo(title_set_info_t * title_set_info) {
	free(title_set_info->title_set);
	free(title_set_info);
}

void DVDFreeTitlesInfo(titles_info_t * titles_info) {
	free(titles_info->titles);
	free(titles_info);
}



title_set_info_t *DVDGetFileSet(dvd_reader_t * _dvd) {

	/* title interation */
	int title_sets, counter, i;


	/* DVD Video files */
	char	filename[MAXNAME];
	int	size;

	/*DVD ifo handler*/
	ifo_handle_t * 	vmg_ifo=NULL;

	/* The Title Set Info struct*/
	title_set_info_t * title_set_info;

	/*  Open main info file */
	vmg_ifo = ifoOpen( _dvd, 0 );
	if( !vmg_ifo ) {
        	fprintf( stderr, "Can't open VMG info.\n" );
        	return (0);
    	}


	title_sets = vmg_ifo->vmgi_mat->vmg_nr_of_title_sets;

	/* Close the VMG ifo file we got all the info we need */
        ifoClose(vmg_ifo);

	/* Todo fix malloc check */
	title_set_info = (title_set_info_t *)malloc(sizeof(title_set_info_t));
	title_set_info->title_set = (title_set_t *)malloc((title_sets + 1)* sizeof(title_set_t));

	title_set_info->number_of_title_sets = title_sets;


	/* Find VIDEO_TS.IFO is present - must be present since we did a ifo open 0*/

	sprintf(filename,"/VIDEO_TS/VIDEO_TS.IFO");

	if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
		title_set_info->title_set[0].size_ifo = size;
	} else {
		DVDFreeTitleSetInfo(title_set_info);
		return(0);
	}



	/* Find VIDEO_TS.VOB if present*/

	sprintf(filename,"/VIDEO_TS/VIDEO_TS.VOB");

	if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
		title_set_info->title_set[0].size_menu = size;
	} else {
		title_set_info->title_set[0].size_menu = 0 ;
	}

	/* Find VIDEO_TS.BUP if present */

	sprintf(filename,"/VIDEO_TS/VIDEO_TS.BUP");

	if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
		title_set_info->title_set[0].size_bup = size;
	} else {
		DVDFreeTitleSetInfo(title_set_info);
		return(0);
	}

	if (title_set_info->title_set[0].size_ifo != title_set_info->title_set[0].size_bup) {
		fprintf(stderr,"BUP and IFO size not the same be warened!\n");
	}


	/* Take care of the titles which we don't have in VMG */

	title_set_info->title_set[0].number_of_vob_files = 0;
	title_set_info->title_set[0].size_vob[0] = 0;


	if ( verbose > 0 ){
		fprintf(stderr,"\n\n\nFile sizes for Title set 0 VIDEO_TS.XXX\n");
		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 );

	}


	if ( title_sets >= 1 ) {
 		for (counter=0; counter < title_sets; counter++ ){

			if ( verbose > 1 ){
				fprintf(stderr,"At top of loop\n");
			}


			sprintf(filename,"/VIDEO_TS/VTS_%02i_0.IFO",counter + 1);

			if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
				title_set_info->title_set[counter + 1].size_ifo = size;
			} else {
				DVDFreeTitleSetInfo(title_set_info);
				return(0);
			}

			if ( verbose > 1 ){
				fprintf(stderr,"After opening files\n");
			}


			/* Find VTS_XX_0.VOB if present*/

			sprintf(filename,"/VIDEO_TS/VTS_%02i_0.VOB", counter + 1);

			if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
				title_set_info->title_set[counter + 1].size_menu = size;
			} else {
				title_set_info->title_set[counter + 1].size_menu = 0 ;
			}


			if ( verbose > 1 ){
				fprintf(stderr,"After Menu VOB check\n");
			}


			/* Find all VTS_XX_[1 to 9].VOB files if they are present*/

			for( i = 0; i < 9; ++i ) {
				sprintf(filename,"/VIDEO_TS/VTS_%02i_%i.VOB", counter + 1, i + 1 );
				if(UDFFindFile(_dvd, filename, &size) == 0 ) {
					break;
				}
				title_set_info->title_set[counter + 1].size_vob[i] = size;
			}
			title_set_info->title_set[counter + 1].number_of_vob_files = i;

			if ( verbose > 1 ){
				fprintf(stderr,"After Menu Title VOB check\n");
			}


			sprintf(filename,"/VIDEO_TS/VTS_%02i_0.BUP", counter + 1);

			if ( UDFFindFile(_dvd, filename, &size) != 0 ) {
				title_set_info->title_set[counter +1].size_bup = size;
			} else {
				DVDFreeTitleSetInfo(title_set_info);
				return(0);
			}

			if (title_set_info->title_set[counter +1].size_ifo != title_set_info->title_set[counter + 1].size_bup) {
				fprintf(stderr,"BUP and IFO size for fileset %d is not the same be warened!\n", counter + 1);
			}



			if ( verbose > 1 ){
				fprintf(stderr,"After Menu Title BUP check\n");
			}


			if ( verbose > 0 ) {
				fprintf(stderr,"\n\n\nFile sizes for Title set %d i.e.VTS_%02d_X.XXX\n", counter + 1, counter + 1);
				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);
				for (i = 0; i < title_set_info->title_set[counter + 1].number_of_vob_files ; i++) {
					fprintf(stderr, "VOB %d is %d\n", i + 1, title_set_info->title_set[counter + 1].size_vob[i]);
				}
				fprintf(stderr,"BUP: %d\n",title_set_info->title_set[counter +1].size_bup);
			}

			if ( verbose > 1 ){
				fprintf(stderr,"Bottom of loop \n");
			}
		}

        }

	/* Return the info */
	return(title_set_info);


}

int DVDMirror(dvd_reader_t * _dvd, char * targetdir,char * title_name) {

	int i;
	title_set_info_t * title_set_info=NULL;

	title_set_info = DVDGetFileSet(_dvd);
	if (!title_set_info) {
		DVDClose(_dvd);
		return(1);
	}

	if ( DVDMirrorVMG(_dvd, title_set_info, targetdir, title_name) != 0 ) {
		fprintf(stderr,"Mirror of VMG faild\n");
		DVDFreeTitleSetInfo(title_set_info);
		return(1);
	}

	for ( i=0; i < title_set_info->number_of_title_sets; i++) {
		if ( DVDMirrorTitleX(_dvd, title_set_info, i + 1, targetdir, title_name) != 0 ) {
			fprintf(stderr,"Mirror of Title set %d faild\n", i + 1);
			DVDFreeTitleSetInfo(title_set_info);
			return(1);
		}
	}
	return(0);
}

int DVDMirrorTitleSet(dvd_reader_t * _dvd, char * targetdir,char * title_name, int title_set) {

	title_set_info_t * title_set_info=NULL;


#ifdef DEBUG
	fprintf(stderr,"In DVDMirrorTitleSet\n");
#endif

	title_set_info = DVDGetFileSet(_dvd);

	if (!title_set_info) {
		DVDClose(_dvd);
		return(1);
	}

	if ( title_set > title_set_info->number_of_title_sets ) {
		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);
		DVDFreeTitleSetInfo(title_set_info);
		return(1);
	}

	if ( title_set == 0 ) {
		if ( DVDMirrorVMG(_dvd, title_set_info, targetdir, title_name) != 0 ) {
			fprintf(stderr,"Mirror of Title set 0 (VMG) faild\n");
			DVDFreeTitleSetInfo(title_set_info);
			return(1);
		}
	} else {
		if ( DVDMirrorTitleX(_dvd, title_set_info, title_set, targetdir, title_name) != 0 ) {
			fprintf(stderr,"Mirror of Title set %d faild\n", title_set);
			DVDFreeTitleSetInfo(title_set_info);
			return(1);
		}
	}
	DVDFreeTitleSetInfo(title_set_info);
	return(0);
}

int DVDMirrorMainFeature(dvd_reader_t * _dvd, char * targetdir,char * title_name) {

	title_set_info_t * title_set_info=NULL;
	titles_info_t * titles_info=NULL;


	titles_info = DVDGetInfo(_dvd);
	if (!titles_info) {
		fprintf(stderr, "Guess work of main feature film faild\n");
		return(1);
	}

	title_set_info = DVDGetFileSet(_dvd);
	if (!title_set_info) {
		DVDFreeTitlesInfo(titles_info);
		return(1);
	}

	if ( DVDMirrorTitleX(_dvd, title_set_info, titles_info->main_title_set, targetdir, title_name) != 0 ) {
		fprintf(stderr,"Mirror of main featur file which is title set %d faild\n", titles_info->main_title_set);
		DVDFreeTitleSetInfo(title_set_info);
		return(1);
	}

	DVDFreeTitlesInfo(titles_info);
	DVDFreeTitleSetInfo(title_set_info);
	return(0);
}


int DVDMirrorChapters(dvd_reader_t * _dvd, char * targetdir,char * title_name, int start_chapter,int  end_chapter, int titles) {


	int result;
	int chapters = 0;
	int feature;
	int i, s;
	int spg, epg;
	int pgc;
	int start_cell, end_cell;
	int vts_title;

	title_set_info_t * title_set_info=NULL;
	titles_info_t * titles_info=NULL;
	ifo_handle_t * vts_ifo_info=NULL;
	int * cell_start_sector=NULL;
	int * cell_end_sector=NULL;

	/* To do free memory*/

	titles_info = DVDGetInfo(_dvd);
	if (!titles_info) {
		fprintf(stderr, "Faild to obtain titles information\n");
		return(1);
	}

	title_set_info = DVDGetFileSet(_dvd);
	if (!title_set_info) {
		DVDFreeTitlesInfo(titles_info);
		return(1);
	}

	if(titles == 0) {
		fprintf(stderr, "No title specified for chapter extraction, will try to figure out main feature title\n");
		feature = titles_info->main_title_set;
		for (i=0; i < titles_info->number_of_titles ; i++ ) {
			if ( titles_info->titles[i].title_set == titles_info->main_title_set ) {
				if(chapters < titles_info->titles[i].chapters) {
					chapters = titles_info->titles[i].chapters;
					titles = i + 1;
				}
			}
		}
	}

	vts_ifo_info = ifoOpen(_dvd, titles_info->titles[titles - 1].title_set);
	if(!vts_ifo_info) {
		fprintf(stderr, "Coundn't open tile_set %d IFO file\n", titles_info->titles[titles - 1].title_set);
		DVDFreeTitlesInfo(titles_info);
		DVDFreeTitleSetInfo(title_set_info);
		return(1);
	}

	vts_title = titles_info->titles[titles - 1].vts_title;

	if (end_chapter > titles_info->titles[titles - 1].chapters) {
		end_chapter = titles_info->titles[titles - 1].chapters;
		fprintf(stderr, "Turncated the end_chapter only %d chapters in %d title\n", end_chapter,titles);
	}

	if (start_chapter > titles_info->titles[titles - 1].chapters) {
		start_chapter = titles_info->titles[titles - 1].chapters;
		fprintf(stderr, "Turncated the end_chapter only %d chapters in %d title\n", end_chapter,titles);
	}



	/* We assume the same PGC for the whole title - this is not true and need to be fixed later on */

	pgc = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgcn;


	/* Lookup  PG for start chapter */

	spg = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[start_chapter - 1].pgn;

	/* Look up start cell for this pgc/pg */

	start_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[spg - 1];


	/* Lookup end cell*/


	if ( end_chapter < titles_info->titles[titles - 1].chapters ) {
		epg = vts_ifo_info->vts_ptt_srpt->title[vts_title - 1].ptt[end_chapter].pgn;
#ifdef DEBUG
		fprintf(stderr,"DVDMirrorChapter: epg %d\n", epg);
#endif

		end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->program_map[epg -1] - 1;
#ifdef DEBUG
		fprintf(stderr,"DVDMirrorChapter: end cell adjusted %d\n", end_cell);
#endif

	} else {

		end_cell = vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->nr_of_cells;
#ifdef DEBUG
		fprintf(stderr,"DVDMirrorChapter: end cell adjusted 2 %d\n",end_cell);
#endif

	}

#ifdef DEBUG
	fprintf(stderr,"DVDMirrorChapter: star cell %d\n", start_cell);
#endif


	/* Put all the cells start and end sector in a dual array */

	cell_start_sector = (int *)malloc( (end_cell - start_cell + 1) * sizeof(int));
	if(!cell_start_sector) {
		fprintf(stderr,"Memory allocation error 1\n");
		DVDFreeTitlesInfo(titles_info);
		DVDFreeTitleSetInfo(title_set_info);
		ifoClose(vts_ifo_info);
		return(1);
	}
	cell_end_sector = (int *)malloc( (end_cell - start_cell + 1) * sizeof(int));
	if(!cell_end_sector) {
		fprintf(stderr,"Memory allocation error\n");
		DVDFreeTitlesInfo(titles_info);
		DVDFreeTitleSetInfo(title_set_info);
		ifoClose(vts_ifo_info);
		free(cell_start_sector);
		return(1);
	}
#ifdef DEBUG
	fprintf(stderr,"DVDMirrorChapter: start cell is %d\n", start_cell);
	fprintf(stderr,"DVDMirrorChapter: end cell is %d\n", end_cell);
	fprintf(stderr,"DVDMirrorChapter: pgc is %d\n", pgc);
#endif

	for (i=0, s=start_cell; s < end_cell +1 ; i++, s++) {

		cell_start_sector[i] =  vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].first_sector;
		cell_end_sector[i] =  vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].last_sector;
#ifdef DEBUG
		fprintf(stderr,"DVDMirrorChapter: S is %d\n", s);
		fprintf(stderr,"DVDMirrorChapter: start sector %d\n", vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].first_sector);
		fprintf(stderr,"DVDMirrorChapter: end sector %d\n", vts_ifo_info->vts_pgcit->pgci_srp[pgc - 1].pgc->cell_playback[s - 1].last_sector);
#endif
	}

	bsort_min_to_max(cell_start_sector, cell_end_sector, end_cell - start_cell + 1);

	align_end_sector(cell_start_sector, cell_end_sector,end_cell - start_cell + 1);

#ifdef DEBUG
	for (i=0 ; i < end_cell - start_cell + 1; i++) {
		fprintf(stderr,"DVDMirrorChapter: Start sector is %d end sector is %d\n", cell_start_sector[i], cell_end_sector[i]);
	}
#endif

	result = DVDWriteCells(_dvd, cell_start_sector, cell_end_sector , end_cell - start_cell + 1, titles, title_set_info, titles_info, targetdir, title_name);

	DVDFreeTitlesInfo(titles_info);
	DVDFreeTitleSetInfo(title_set_info);
	ifoClose(vts_ifo_info);
	free(cell_start_sector);
	free(cell_end_sector);

	if( result != 0) {
		return(1);
	} else {
		return(0);
	}
}






int DVDMirrorTitles(dvd_reader_t * _dvd, char * targetdir,char * title_name, int titles) {

	int end_chapter;

	titles_info_t * titles_info=NULL;

#ifdef DEBUG
	fprintf(stderr,"In DVDMirrorTitles\n");
#endif



	titles_info = DVDGetInfo(_dvd);
	if (!titles_info) {
		fprintf(stderr, "Faild to obtain titles information\n");
		return(1);
	}


	end_chapter = titles_info->titles[titles - 1].chapters;
#ifdef DEBUG
	fprintf(stderr,"DVDMirrorTitles: end_chapter %d\n", end_chapter);
#endif

	if (DVDMirrorChapters( _dvd, targetdir, title_name, 1, end_chapter, titles) != 0 ) {
		DVDFreeTitlesInfo(titles_info);
		return(1);
	}

	DVDFreeTitlesInfo(titles_info);

	return(0);
}

int DVDDisplayInfo(dvd_reader_t * _dvd, char * dvd) {


	int i, f;
	int chapters;
	int channels;
	char title_name[33]="";
	title_set_info_t * title_set_info=NULL;
	titles_info_t * titles_info=NULL;


	titles_info = DVDGetInfo(_dvd);
	if (!titles_info) {
		fprintf(stderr, "Guess work of main feature film faild\n");
		return(1);
	}

	title_set_info = DVDGetFileSet(_dvd);
	if (!title_set_info) {
		DVDFreeTitlesInfo(titles_info);
		return(1);
	}

	DVDGetTitleName(dvd,title_name);


	fprintf(stdout,"\n\n\nDVD-Video information of the DVD with tile %s\n\n", title_name);

	/* Print file structure */

	fprintf(stdout,"File Structure DVD\n");
	fprintf(stdout,"VIDEO_TS/\n");
	fprintf(stdout,"\tVIDEO_TS.IFO\t%i\n", title_set_info->title_set[0].size_ifo);

	if (title_set_info->title_set[0].size_menu != 0 ) {
		fprintf(stdout,"\tVIDEO_TS.VOB\t%i\n", title_set_info->title_set[0].size_menu);
	}

	fprintf(stdout,"\tVIDEO_TS.BUP\t%i\n", title_set_info->title_set[0].size_bup);

	for( i = 0 ; i < title_set_info->number_of_title_sets ; i++) {
		fprintf(stdout,"\tVTS_%02i_0.IFO\t%i\n", i + 1, title_set_info->title_set[i + 1].size_ifo);
		if (title_set_info->title_set[i + 1].size_menu != 0 ) {
			fprintf(stdout,"\tVTS_%02i_0.VOB\t%i\n", i + 1, title_set_info->title_set[i + 1].size_menu);
		}
		if (title_set_info->title_set[i + 1].number_of_vob_files != 0) {
			for( f = 0; f < title_set_info->title_set[i + 1].number_of_vob_files ; f++ ) {
				fprintf(stdout,"\tVTS_%02i_%i.VOB\t%i\n", i + 1, f + 1, title_set_info->title_set[i + 1].size_vob[f]);
			}
		}
		fprintf(stdout,"\tVTS_%02i_0.BUP\t%i\n", i + 1, title_set_info->title_set[i + 1].size_bup);
	}

	fprintf(stdout,"\n\nMain feature:\n");
	fprintf(stdout,"\tTitle set containing the main feature is  %d\n", titles_info->main_title_set);
	for (i=0; i < titles_info->number_of_titles ; i++ ) {
		if (titles_info->titles[i].title_set == titles_info->main_title_set) {
			if(titles_info->titles[i].aspect_ratio == 3) {
				fprintf(stdout,"\tThe aspect ratio of the main feature is 16:9\n");
			} else if (titles_info->titles[i].aspect_ratio == 0) {
				fprintf(stdout,"\tThe aspect ratio of the main feature is 4:3\n");
			} else {
				fprintf(stdout,"\tThe aspect ratio of the main feature is unknown\n");
			}
			fprintf(stdout,"\tThe main feature has %d angle(s)\n", titles_info->titles[i].angles);
			fprintf(stdout,"\tThe main feature has %d audio_track(s)\n", titles_info->titles[i].angles);
			fprintf(stdout,"\tThe main feature has %d subpicture channel(s)\n",titles_info->titles[i].sub_pictures);
			chapters=0;
			channels=0;

			for (f=0; f < titles_info->number_of_titles ; f++ ) {
                        	if ( titles_info->titles[i].title_set == titles_info->main_title_set ) {
                                	if(chapters < titles_info->titles[f].chapters) {
                                        	chapters = titles_info->titles[f].chapters;
					}
					if(channels < titles_info->titles[f].audio_channels) {
						channels = titles_info->titles[f].audio_channels;
					}
				}
			}
			fprintf(stdout,"\tThe main feature has a maximum of %d chapter(s) in on of it's titles\n", chapters);
			fprintf(stdout,"\tThe main feature has a maximum of %d audio channel(s) in on of it's titles\n", channels);
			break;
                }

        }

	fprintf(stdout,"\n\nTitle Sets:");
	for (f=0; f < title_set_info->number_of_title_sets ; f++ ) {
		fprintf(stdout,"\n\n\tTitle set %d\n", f + 1);
		for (i=0; i < titles_info->number_of_titles ; i++ ) {
			if (titles_info->titles[i].title_set == f + 1) {
				if(titles_info->titles[i].aspect_ratio == 3) {
					fprintf(stdout,"\t\tThe aspect ratio of title set %d is 16:9\n", f + 1);
				} else if (titles_info->titles[i].aspect_ratio == 0) {
					fprintf(stdout,"\t\tThe aspect ratio of title set %d is 4:3\n", f + 1);
				} else {
					fprintf(stdout,"\t\tThe aspect ratio of title set %d is unknown\n", f + 1);
				}
				fprintf(stdout,"\t\tTitle set %d has %d angle(s)\n", f + 1, titles_info->titles[i].angles);
				fprintf(stdout,"\t\tTitle set %d has %d audio_track(s)\n", f + 1, titles_info->titles[i].angles);
				fprintf(stdout,"\t\tTitle set %d has %d subpicture channel(s)\n", f + 1, titles_info->titles[i].sub_pictures);
				break;
			}
		}
		fprintf(stdout,"\n\t\tTitles included in title set %d is/are\n", f + 1);
		for (i=0; i < titles_info->number_of_titles ; i++ ) {
			if (titles_info->titles[i].title_set == f + 1) {
				fprintf(stdout,"\t\t\tTitle %d:\n", i + 1);
				fprintf(stdout,"\t\t\t\tTitle %d has %d chapter(s)\n", i + 1, titles_info->titles[i].chapters);
				fprintf(stdout,"\t\t\t\tTitle %d has %d audio channle(s)\n", i + 1, titles_info->titles[i].audio_channels);
			}
		}
	}
	DVDFreeTitlesInfo(titles_info);
	DVDFreeTitleSetInfo(title_set_info);

	return(0);
}

int main(int argc, char *argv[]){

	/* Args */
	int flags;

	/* Switches */
	int title_set = 0;
	int titles;
	int start_chapter;
	int end_chapter;

	int do_mirror = 0;
	int do_title_set = 0;
	int do_chapter = 0;
	int do_titles = 0;
	int do_feature = 0;
	int do_info = 0;



	int return_code;

	/* DVD Video device */
	char * dvd=NULL;

	/* Temp switch helpers */
	char * verbose_temp=NULL;
	char * aspect_temp=NULL;
	char * start_chapter_temp=NULL;
	char * end_chapter_temp=NULL;
	char * titles_temp=NULL;
	char * title_set_temp=NULL;


	/* Title of the DVD */
	char title_name[33]="";
	char * provided_title_name=NULL;

	/* Targer dir */
	char * targetdir=NULL;

	/* Temp filename,dirname */
	char targetname[PATH_MAX];
	struct stat fileinfo;


	/* The DVD main structure */
	dvd_reader_t *	_dvd=NULL;



	/*Todo do isdigit check */

	while ((flags = getopt(argc, argv, "MFI?hi:v:a:o:n:s:e:t:T:")) != -1) {
		switch (flags) {
		case 'i':
      			if(optarg[0]=='-') usage();
      			dvd = optarg;
      			break;
		case 'v':
			if(optarg[0]=='-') usage();
			verbose_temp = optarg;
			break;
		case 'o':
			if(optarg[0]=='-') usage();
			targetdir = optarg;
			break;
		case 'n':
      			if(optarg[0]=='-') usage();
      			provided_title_name = optarg;
      			break;
		case 'a':
			if(optarg[0]=='-') usage();
			aspect_temp = optarg;
			break;
		case 's':
			if(optarg[0]=='-') usage();
			start_chapter_temp = optarg;
			break;
		case 'e':
			if(optarg[0]=='-') usage();
			end_chapter_temp = optarg;
			break;
		case 't':
			if(optarg[0]=='-') usage();
			titles_temp = optarg;
			break;
		case 'T':
			if(optarg[0]=='-') usage();
			title_set_temp = optarg;
			break;
		case 'M':
			do_mirror = 1;
			break;
		case 'F':
			do_feature = 1;
			break;
		case 'I':
			do_info = 1;
			break;

		case '?':
			usage();
			break;
		case 'h':
			usage();
			break;
		default:
			usage();
		}
	}

	if (dvd == NULL) {
		usage();
		exit(1);
	}

	if (targetdir == NULL && do_info == 0) {
		usage();
		exit(1);
	}

	if(verbose_temp == NULL) {
		verbose = 0;
	} else {
		verbose = atoi(verbose_temp);
	}

	if (aspect_temp == NULL) {
		/* Deafult to 16:9 aspect ratio */
		aspect = 3;
	} else {
		aspect = atoi(aspect_temp);
	}

	if((aspect != 0) && (aspect != 3) && (do_info == 0)){
		usage();
		exit(1);
	}

	if ( titles_temp != NULL) {
		titles = atoi(titles_temp);
		if ( titles < 1 ) {
			usage();
			exit(1);
		}
	}

	if ( start_chapter_temp !=NULL) {
		start_chapter = atoi(start_chapter_temp);
		if ( start_chapter < 1 || start_chapter > 99 ) {
			usage();
			exit(1);
		}
	}

	if (end_chapter_temp != NULL) {
		end_chapter = atoi(end_chapter_temp);
		if ( end_chapter < 1 || end_chapter > 99 ) {
			usage();
			exit(1);
		}
	}

	if ( end_chapter_temp != NULL || start_chapter_temp != NULL) {
		if( end_chapter_temp == NULL) {
			end_chapter = 99;
		} else if ( start_chapter_temp == NULL) {
			start_chapter = 1;
		}
		if ( end_chapter < start_chapter ) {
			usage();
			exit(1);
		}
	}

	if ( titles_temp != NULL && ((end_chapter_temp != NULL) || (start_chapter_temp != NULL))) {
		do_chapter = 1;
	} else if ((titles_temp != NULL) && ((end_chapter_temp == NULL) && (start_chapter_temp == NULL))) {
		do_titles=1;
	}
	if (do_chapter && (titles_temp == NULL)) {
		titles = 0;
	}

	if ( title_set_temp != NULL ) {
		title_set = atoi(title_set_temp);
		if ( title_set > 99 || title_set < 0 ) {
			usage();
			exit(1);
		}
		do_title_set = 1;
	}

	if (do_info + do_titles + do_chapter + do_feature + do_title_set  + do_mirror > 1 ) {
		usage();
		exit(1);
	} else if ( do_info + do_titles + do_chapter + do_feature + do_title_set  + do_mirror == 0) {
		usage();
		exit(1);
	}
#ifdef DEBUG
	fprintf(stderr,"After args\n");
#endif


	_dvd = DVDOpen(dvd);
	if(!_dvd) exit(-1);


	if (do_info) {
		DVDDisplayInfo(_dvd, dvd);
		DVDClose(_dvd);
		exit(0);
	}


	if(provided_title_name == NULL) {
		if (DVDGetTitleName(dvd,title_name) != 0) {
			fprintf(stderr,"You must provide a title name when you read your DVD-Video structure direct from the HD\n");
			DVDClose(_dvd);
			exit(1);
		}
		if (strstr(title_name, "DVD_VIDEO") != NULL) {
			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");
			DVDClose(_dvd);
			exit(2);
		}

	} else {
		if (strlen(provided_title_name) > 32) {
			fprintf(stderr,"The title name specified is longer than 32 charachters, truncating the title name\n");
			strncpy(title_name,provided_title_name, 32);
			title_name[32]='\0';
		} else {
			strcpy(title_name,provided_title_name);
		}
	}



	sprintf(targetname,"%s",targetdir);

	if (stat(targetname, &fileinfo) == 0) {
		if (! S_ISDIR(fileinfo.st_mode)) {
			fprintf(stderr,"The target directory is not valid, it may be a ordinary file\n");
		}
	} else {
		if (mkdir(targetname, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
			fprintf(stderr,"Faild creating target directory\n");
			perror("");
			DVDClose(_dvd);
			exit(-1);
		}
	}


	sprintf(targetname,"%s/%s",targetdir, title_name);

	if (stat(targetname, &fileinfo) == 0) {
		if (! S_ISDIR(fileinfo.st_mode)) {
			fprintf(stderr,"The title directory is not valid, it may be a ordinary file\n");
		}
	} else {
		if (mkdir(targetname, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
			fprintf(stderr,"Faild creating title directory\n");
			perror("");
			DVDClose(_dvd);
			exit(-1);
		}
	}

	sprintf(targetname,"%s/%s/VIDEO_TS",targetdir, title_name);

	if (stat(targetname, &fileinfo) == 0) {
		if (! S_ISDIR(fileinfo.st_mode)) {
			fprintf(stderr,"The VIDEO_TS directory is not valid, it may be a ordinary file\n");
		}
	} else {
		if (mkdir(targetname, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
			fprintf(stderr,"Faild creating VIDEO_TS directory\n");
			perror("");
			DVDClose(_dvd);
			exit(-1);
		}
	}


#ifdef DEBUG
	fprintf(stderr,"After dirs\n");
#endif


	if(do_mirror) {
		if ( DVDMirror(_dvd, targetdir, title_name)  != 0 ) {
			fprintf(stderr, "Mirror of DVD faild\n");
			return_code = -1;
		} else {
			return_code = 0;
		}
	}
#ifdef DEBUG
	fprintf(stderr,"After Mirror\n");
#endif


	if (do_title_set) {
		if (DVDMirrorTitleSet(_dvd, targetdir, title_name, title_set) != 0) {
			fprintf(stderr, "Mirror of title set %d faild\n", title_set);
			return_code = -1;
		} else {
			return_code  = 0;
		}

	}
#ifdef DEBUG
	fprintf(stderr,"After Title Set\n");
#endif



	if(do_feature) {
		if ( DVDMirrorMainFeature(_dvd, targetdir, title_name)  != 0 ) {
			fprintf(stderr, "Mirror of main feature film of DVD faild\n");
			return_code = -1;
		} else {
			return_code = 0;
		}
	}

	if(do_titles) {
		if (DVDMirrorTitles(_dvd, targetdir, title_name, titles) != 0) {
			fprintf(stderr, "Mirror of title  %d faild\n", titles);
			return_code = -1;
		} else {
			return_code  = 0;
		}
	}


	if(do_chapter) {
		if (DVDMirrorChapters(_dvd, targetdir, title_name, start_chapter, end_chapter, titles) != 0) {
			fprintf(stderr, "Mirror of chapters %d to %d in title %d faild\n", start_chapter, end_chapter, titles);
			return_code = -1;
		} else {
			return_code  = 0;
		}
	}


	DVDClose(_dvd);
	exit(return_code);
}



-------------- next part --------------

      "Opiates are the religion of the masses." - David Cameron Staples


More information about the freebsd-multimedia mailing list