Exemple #1
0
u32 DumpFile( char *FileName, u64 Offset, u32 Size )
{
	DVDLowRead( DVDBuffer, Offset, (Size+31) & (~31) ); // align reads by 32 bytes, doesn't effect final filesize!
					
	s32 fd = DVDOpen( FileName );
	if( fd < 0 )
	{
		DVDError = DI_FATAL|(0x20<<16);
		return 2;

	} else {

		if( DVDWrite( fd, DVDBuffer, Size ) != Size )
		{
			DVDError = DI_FATAL|(0x21<<16);

			DVDClose( fd );
			return 2;
		}

		DVDWrote += Size;

		DVDClose( fd );
	}

	return 1;
}
Exemple #2
0
/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;
    int i;

    for( i = 0; i < PS_TK_COUNT; i++ )
    {
        ps_track_t *tk = &p_sys->tk[i];
        if( tk->b_seen )
        {
            es_format_Clean( &tk->fmt );
            if( tk->es ) es_out_Del( p_demux->out, tk->es );
        }
    }

    /* Free the array of titles */
    for( int i = 0; i < p_sys->i_titles; i++ )
        vlc_input_title_Delete( p_sys->titles[i] );
    TAB_CLEAN( p_sys->i_titles, p_sys->titles );

    /* Close libdvdread */
    if( p_sys->p_title ) DVDCloseFile( p_sys->p_title );
    if( p_sys->p_vts_file ) ifoClose( p_sys->p_vts_file );
    if( p_sys->p_vmg_file ) ifoClose( p_sys->p_vmg_file );
    DVDClose( p_sys->p_dvdread );

    free( p_sys );
}
Exemple #3
0
static void dvd_close(dvd_priv_t *d)
{
  ifoClose(d->vts_file);
  ifoClose(d->vmg_file);
  DVDCloseFile(d->title);
  DVDClose(d->dvd);
  dvd_set_speed(dvd_device_current, -1); /* -1 => restore default */
}
Exemple #4
0
static void stream_dvd_close(stream_t *s) {
  dvd_priv_t *d = s->priv;
  ifoClose(d->vts_file);
  ifoClose(d->vmg_file);
  DVDCloseFile(d->title);
  DVDClose(d->dvd);
  dvd_set_speed(s,dvd_device_current, -1); /* -1 => restore default */
}
Exemple #5
0
DVDStream::~DVDStream()
{
    KillReadAheadThread();

    rwlock.lockForWrite();

    if (m_reader)
        DVDClose(m_reader);

    rwlock.unlock();
}
Exemple #6
0
/* Close a dvd
 */
static inline void close_dvd(struct mount_info *mi) {
    int title, domain;

    for (title = 0; title <= mi->num_title; ++title) {
	for (domain = MIN_DOMAIN; domain <= MAX_DOMAIN; ++domain) {
	    dvd_file_t *fd = mi->file[domain][title].fd;;
	    if (fd)
		    DVDCloseFile(fd);
	}
    }
    DVDClose(mi->dvd);
    fprintf(stderr, "dvdclose\n");
}
/* ---------------------------------------------------------------------------------*/
void TrackClose( DVD_TRACK_INFO* stTrack )
{
	if( stTrack->file )
		DVDCloseFile( stTrack->file );
	if( stTrack->ifo_file )
		ifoClose( stTrack->ifo_file );
	if( stTrack->dvd )
		DVDClose( stTrack->dvd );
	if( stTrack->sBuf )
		free( stTrack->sBuf );

	stTrack->file= NULL;
	stTrack->dvd= NULL;
	stTrack->ifo_file= NULL;
	stTrack->sBuf= NULL;
	stTrack->iVobuNo= -1;
}
int main(void) {

	int return_code = 0;

	/* DVD Video device */
	char* dvd = (char*)"/dev/dvd";

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

	/* Targer dir */
	char* targetdir = (char*)".";

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

	/* TODO: do isdigit check */

	progress = 1;
	dvd = (char*)"/dev/rdisk1";
	targetdir = (char*)"./test/post";

	aspect = 0;

	_dvd = DVDOpen(dvd);
	if (!_dvd) {
		fprintf(stderr, "Cannot open specified device %s - check your DVD device\n", dvd);
		exit(-1);
	}

	read_title_name(_dvd, dvd, title_name, targetdir);

	if ( DVDMirror(_dvd, targetdir, title_name, STRATEGY_SKIP_MULTIBLOCK) != 0 ) {
		fprintf(stderr,  "Mirror of DVD failed\n");
		return_code = -1;
	} else {
		return_code = 0;
	}

	DVDClose(_dvd);
	exit(return_code);
}
Exemple #9
0
/*!
 ******************************************************************************
 * \brief
 *		Close open video file
 *
 * \return
 *		TRUE if file is closed sucessfully.
 *
 ******************************************************************************
 */
BOOL AUDSimpleClose(void)
	{
	if (audio_player.open)
		{
		if (audio_player.preFetchState == FALSE)
			{
			if (!audio_player.asyncDvdRunning)
				{
				audio_player.open = FALSE;
				DVDClose(&audio_player.fileHandle);
				if(audio_player.audioHeaderChunk != NULL)
					{
					(*audio_player.cbFree)(audio_player.audioHeaderChunk);
					audio_player.audioHeaderChunk = NULL;
					}
				return TRUE;
				}
			}
		}
	return FALSE;
	}
Exemple #10
0
int main (int argc, const char *argv[])
{
    dvd_reader_t *dvd;
    ifo_handle_t *ifohandle;
    tt_srpt_t *tt_srpt;    
    int number, i;
    
    if( argc != 2 )
	{
        fprintf( stderr, "Usage: %s <dvd path>\n", argv[ 0 ] );
        return -1;
    }
    
    dvd = DVDOpen(argv[1]);
    
    if( !dvd )
		return 0;
		
	ifohandle = ifoOpen(dvd, 0);
	number = ifohandle->vmgi_mat->vmg_nr_of_title_sets;
    tt_srpt = ifohandle->tt_srpt;
	
	for( i = 0; i < tt_srpt->nr_of_srpts; ++i )
	{
    	ifo_handle_t *ifo2;
			
		ifo2 = ifoOpen(dvd, tt_srpt->title[ i ].title_set_nr);
		if(!ifo2)
			return 0;

		printf("%02x:%02x:%02x\n",
			   ifo2->vts_pgcit->pgci_srp->pgc->playback_time.hour,
			   ifo2->vts_pgcit->pgci_srp->pgc->playback_time.minute,
			   ifo2->vts_pgcit->pgci_srp->pgc->playback_time.second);
		
		ifoClose(ifo2);		
	}
	ifoClose(ifohandle);
    DVDClose(dvd);
}
Exemple #11
0
int main(int argc, char *argv[])
{
  dvd_reader_t *dvd;
  program_name = argv[0];
  
  if(argc != 3) {
    usage();
    return 1;
  }

  dvd = DVDOpen( argv[ 1 ] );
  if( !dvd ) {
    fprintf( stderr, "Can't open disc %s!\n", argv[ 1 ] );
    return -1;
  }

  ifo_print( dvd, atoi( argv[ 2 ] ) );
  DVDClose(dvd);

  DVDFinish(); //to keep memory checkers from complaining 
  return 0;  
}
Exemple #12
0
/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;
    int i;

    for( i = 0; i < PS_TK_COUNT; i++ )
    {
        ps_track_t *tk = &p_sys->tk[i];
        if( tk->b_seen )
        {
            es_format_Clean( &tk->fmt );
            if( tk->es ) es_out_Del( p_demux->out, tk->es );
        }
    }

    /* Close libdvdread */
    if( p_sys->p_title ) DVDCloseFile( p_sys->p_title );
    if( p_sys->p_vts_file ) ifoClose( p_sys->p_vts_file );
    if( p_sys->p_vmg_file ) ifoClose( p_sys->p_vmg_file );
    DVDClose( p_sys->p_dvdread );

    free( p_sys );
}
void read_title_name(dvd_reader_t* _dvd, char* dvd, char* title_name, char* targetdir) {
	/* Temp filename,dirname */
	char targetname[PATH_MAX];
	struct stat fileinfo;

	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 too generic; please provide a title with the -n switch\n");
		DVDClose(_dvd);
		exit(2);
	}

	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 an ordinary file.\n");
		}
	} else {
		if (mkdir(targetname, 0777) != 0) {
			fprintf(stderr, "Failed creating target directory %s\n", targetname);
			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 an ordinary file.\n");
		}
	} else {
		if (mkdir(targetname, 0777) != 0) {
			fprintf(stderr, "Failed 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 an ordinary file.\n");
		}
	} else {
		if (mkdir(targetname, 0777) != 0) {
			fprintf(stderr, "Failed creating VIDEO_TS directory\n");
			perror("");
			DVDClose(_dvd);
			exit(-1);
		}
	}
}
Exemple #14
0
int main( int argc, char **argv )
{
    dvd_reader_t *dvd;
    ifo_handle_t *ifo_file;
    tt_srpt_t *tt_srpt;
    int i, j;

    /**
     * Usage.
     */
    if( argc != 2 ) {
        fprintf( stderr, "Usage: %s <dvd path>\n", argv[ 0 ] );
        return -1;
    }

    dvd = DVDOpen( argv[ 1 ] );
    if( !dvd ) {
        fprintf( stderr, "Couldn't open DVD: %s\n", argv[ 1 ] );
        return -1;
    }

    ifo_file = ifoOpen( dvd, 0 );
    if( !ifo_file ) {
        fprintf( stderr, "Can't open VMG info.\n" );
        DVDClose( dvd );
        return -1;
    }
    tt_srpt = ifo_file->tt_srpt;

    //printf( "There are %d titles.\n", tt_srpt->nr_of_srpts );
	
	// let's see if we can make this spit out JSON...
	printf("[\n");

    for( i = 0; i < tt_srpt->nr_of_srpts; ++i ) {
        ifo_handle_t *vts_file;
        vts_ptt_srpt_t *vts_ptt_srpt;
        pgc_t *cur_pgc;
        int vtsnum, ttnnum, pgcnum, chapts;
	
        vtsnum = tt_srpt->title[ i ].title_set_nr;
        ttnnum = tt_srpt->title[ i ].vts_ttn;
        chapts = tt_srpt->title[ i ].nr_of_ptts;

		printf("{\"title\":\"%d\",\n", i + 1);
		printf("\"vts\":\"%d\",\n", vtsnum);
		printf("\"ttn\":\"%d\",\n", ttnnum);
		printf("\"chapters\":[\n");
	
        //printf( "\nTitle %d:\n", i + 1 );
        //printf( "\tIn VTS: %d [TTN %d]\n", vtsnum, ttnnum );
        //printf( "\n" );
        //printf( "\tTitle has %d chapters and %d angles\n", chapts,
        //        tt_srpt->title[ i ].nr_of_angles );

        vts_file = ifoOpen( dvd, vtsnum );
        if( !vts_file ) {
            fprintf( stderr, "Can't open info file for title %d.\n", vtsnum );
            DVDClose( dvd );
            return -1;
        }

        vts_ptt_srpt = vts_file->vts_ptt_srpt;
        for( j = 0; j < chapts; ++j ) {
            int start_cell;
            int pgn;

            pgcnum = vts_ptt_srpt->title[ ttnnum - 1 ].ptt[ j ].pgcn;
            pgn = vts_ptt_srpt->title[ ttnnum - 1 ].ptt[ j ].pgn;
            cur_pgc = vts_file->vts_pgcit->pgci_srp[ pgcnum - 1 ].pgc;
            start_cell = cur_pgc->program_map[ pgn - 1 ] - 1;

			printf("{\"chapter\":\"%d\"}", j + 1);

			if(j < chapts - 1){
				printf(",");
			}
 
			printf("\n");
			

			/*	
            printf( "\tChapter %3d [PGC %2d, PG %2d] starts at Cell %2d [sector %x-%x]\n",
                    j, pgcnum, pgn, start_cell,
                    cur_pgc->cell_playback[ start_cell ].first_sector,
                    cur_pgc->cell_playback[ start_cell ].last_sector );
			*/
        }

		printf("]}");

		if(i < tt_srpt->nr_of_srpts - 1){
			printf(",");
		}

		printf("\n");

        ifoClose( vts_file );
    }

	printf("]");

    ifoClose( ifo_file );
    DVDClose( dvd );
    DVDFinish();
    return 0;
}
Exemple #15
0
int main(int argc, char **argv) {

	if(argc == 2 || argc > 3 || (argc > 1 && strncmp(&argv[0][0], "-", 1) == 0)) {
		printf("dvd_drive_status [dvd_device dvd_raw_device]\n");
		printf("Default devices: %s %s\n", DEFAULT_DVD_DEVICE, DEFAULT_DVD_RAW_DEVICE);
		return 1;
	}

	const char *device_filename = NULL;
	const char *raw_device_filename = NULL;

	if(argc > 2) {
		device_filename = argv[1];
		raw_device_filename = argv[2];
	} else {
		device_filename = DEFAULT_DVD_DEVICE;
		raw_device_filename = DEFAULT_DVD_RAW_DEVICE;
	}

	int fd = -1;

	fd = open(raw_device_filename, O_RDONLY);

	if(fd < 0) {
		if(errno == EACCES)
			fprintf(stderr, "could not open device %s permission denied\n", raw_device_filename);
		else
			fprintf(stderr, "could not open device %s (errno: %i)\n", raw_device_filename, errno);
		return 1;
	}
	
	close(fd);

	fd = open(device_filename, O_RDONLY);

	if(fd < 0) {
#ifdef __NetBSD__
		if(errno == ENODEV)
#else
		if(errno == EIO)
#endif
		{
			printf("drive is closed with no disc or drive is open\n");
			return 2;
		} else {
			fprintf(stderr, "could not detect drive status (errno: %i)\n", errno);
			return 1;
		}

	}

	/**
	 * Look to see if the disc in the drive is a DVD or not.
	 * libdvdread will open any disc just fine, so scan it to see if there
	 * is a VMG IFO as well as an additional check.
	 */
	dvd_reader_t *dvdread_dvd = NULL;
	
	// FreeBSD and NetBSD will throw syslog messages if there's a disc in the drive that's
	// not a DVD.
	dvdread_dvd = DVDOpen(device_filename);
	if(dvdread_dvd) {

		ifo_handle_t *vmg_ifo = NULL;
		
		// OpenBSD will throw a syslog error here if the tray is open
		vmg_ifo = ifoOpen(dvdread_dvd, 0);

		if(vmg_ifo == NULL) {
			ifoClose(vmg_ifo);
			DVDClose(dvdread_dvd);
			close(fd);
#ifdef __OpenBSD__
			printf("drive is closed with no disc or non-DVD or drive is open\n");
			return 2;
#else
			printf("drive is closed with a disc that is not a DVD\n");
			return 4;
#endif
		} else {
			printf("drive is closed with a DVD\n");
			DVDClose(dvdread_dvd);
			close(fd);
			return 3;
		}

	}

	close(fd);

	return 0;

}
Exemple #16
0
int main(int argc, char **argv) {

	/**
	 * Parse options
	 */

	bool verbose = false;
	bool debug = false;
	bool opt_track_number = false;
	bool opt_chapter_number = false;
	bool opt_filename = false;
	bool valid_preset = false;
	uint16_t arg_track_number = 0;
	int long_index = 0;
	int opt = 0;
	opterr = 1;
	uint8_t arg_first_chapter = 1;
	uint8_t arg_last_chapter = 99;
	char *token = NULL;
	char *token_filename = NULL;
	char tmp_filename[5] = {'\0'};
	char dvd_mpv_args[13] = {'\0'};
	char dvd_mpv_first_chapter[5] = {'\0'};
	char dvd_mpv_last_chapter[5] = {'\0'};
	mpv_handle *dvd_mpv = NULL;
	mpv_event *dvd_mpv_event = NULL;
	struct mpv_event_log_message *dvd_mpv_log_message = NULL;

	// Video Title Set
	struct dvd_vts dvd_vts[99];

	const char str_options[] = "Ac:dehl:o:p:t:Vvz";
	struct option long_options[] = {

		{ "chapters", required_argument, 0, 'c' },
		{ "track", required_argument, 0, 't' },
		{ "alang", required_argument, 0, 'l' },
		{ "aid", required_argument, 0, 'A' },

		{ "deinterlace", no_argument, 0, 'd' },
		{ "detelecine", no_argument, 0, 'e' },
		{ "preset", required_argument, 0, 'p' },

		{ "output", required_argument, 0, 'o' },

		{ "help", no_argument, 0, 'h' },
		{ "version", no_argument, 0, 'V' },

		{ "verbose", no_argument, 0, 'v' },
		{ "debug", no_argument, 0, 'z' },
		{ 0, 0, 0, 0 }

	};

	struct dvd_trip dvd_trip;

	dvd_trip.track = 1;
	dvd_trip.first_chapter = 1;
	dvd_trip.last_chapter = 99;

	memset(dvd_mpv_first_chapter, '\0', sizeof(dvd_mpv_first_chapter));
	memset(dvd_mpv_last_chapter, '\0', sizeof(dvd_mpv_last_chapter));

	memset(dvd_trip.filename, '\0', sizeof(dvd_trip.filename));
	memset(dvd_trip.container, '\0', sizeof(dvd_trip.container));
	strcpy(dvd_trip.container, "mkv");
	memset(dvd_trip.preset, '\0', sizeof(dvd_trip.preset));
	strcpy(dvd_trip.preset, "medium");
	memset(dvd_trip.vcodec, '\0', sizeof(dvd_trip.vcodec));
	memset(dvd_trip.vcodec_preset, '\0', sizeof(dvd_trip.vcodec_preset));
	memset(dvd_trip.vcodec_opts, '\0', sizeof(dvd_trip.vcodec_opts));
	memset(dvd_trip.vcodec_log_level, '\0', sizeof(dvd_trip.vcodec_log_level));
	memset(dvd_trip.color_opts, '\0', sizeof(dvd_trip.color_opts));
	memset(dvd_trip.acodec, '\0', sizeof(dvd_trip.acodec));
	memset(dvd_trip.acodec_opts, '\0', sizeof(dvd_trip.acodec_opts));
	memset(dvd_trip.audio_lang, '\0', sizeof(dvd_trip.audio_lang));
	memset(dvd_trip.audio_aid, '\0', sizeof(dvd_trip.audio_aid));
	memset(dvd_trip.vf_opts, '\0', sizeof(dvd_trip.vf_opts));
	dvd_trip.crf = 28;
	memset(dvd_trip.fps, '\0', sizeof(dvd_trip.fps));
	dvd_trip.deinterlace = false;
	dvd_trip.detelecine = false;
	dvd_trip.pass = 1;

	while((opt = getopt_long(argc, argv, str_options, long_options, &long_index )) != -1) {

		switch(opt) {

			case 'A':
				strncpy(dvd_trip.audio_aid, optarg, 3);
				break;

			case 'c':
				opt_chapter_number = true;
				token = strtok(optarg, "-"); {
					if(strlen(token) > 2) {
						fprintf(stderr, "Chapter range must be between 1 and 99\n");
						return 1;
					}
					arg_first_chapter = (uint8_t)strtoumax(token, NULL, 0);
				}

				token = strtok(NULL, "-");
				if(token != NULL) {
					if(strlen(token) > 2) {
						fprintf(stderr, "Chapter range must be between 1 and 99\n");
						return 1;
					}
					arg_last_chapter = (uint8_t)strtoumax(token, NULL, 0);
				}

				if(arg_first_chapter == 0)
					arg_first_chapter = 1;
				if(arg_last_chapter < arg_first_chapter)
					arg_last_chapter = arg_first_chapter;

				break;

			case 'd':
				dvd_trip.deinterlace = true;
				break;

			case 'e':
				dvd_trip.detelecine = true;
				break;

			case 'h':
				print_usage(DVD_INFO_PROGRAM);
				return 0;

			case 'l':
				strncpy(dvd_trip.audio_lang, optarg, 2);
				break;

			case 'p':
				if(strncmp(optarg, "low", 3) == 0) {
					strcpy(dvd_trip.preset, "low");
				} else if(strncmp(optarg, "medium", 6) == 0) {
					strcpy(dvd_trip.preset, "medium");
				} else if(strncmp(optarg, "high", 4) == 0) {
					strcpy(dvd_trip.preset, "high");
				} else if(strncmp(optarg, "insane", 6) == 0) {
					strcpy(dvd_trip.preset, "insane");
				} else {
					printf("dvd_trip [error]: valid presets - low medium high insane\n");
					return 1;
				}
				break;

			case 'o':
				opt_filename = true;
				strncpy(dvd_trip.filename, optarg, PATH_MAX - 1);
				token_filename = strtok(optarg, ".");

				// Choose preset from file extension
				while(token_filename != NULL) {

					snprintf(tmp_filename, 5, "%s", token_filename);
					token_filename = strtok(NULL, ".");

					if(token_filename == NULL && strlen(tmp_filename) == 3 && strncmp(tmp_filename, "mkv", 3) == 0) {
						strncpy(dvd_trip.container, "mkv", 4);
						valid_preset = true;
					} else if(token_filename == NULL && strlen(tmp_filename) == 3 && strncmp(tmp_filename, "mp4", 3) == 0) {
						strncpy(dvd_trip.container, "mp4", 4);
						valid_preset = true;
					} else if(token_filename == NULL && strlen(tmp_filename) == 4 && strncmp(tmp_filename, "webm", 4) == 0) {
						strncpy(dvd_trip.container, "webm", 5);
						valid_preset = true;
					}

				}

				if(!valid_preset) {
					printf("dvd_trip [error]: output filename extension must be one of: .mkv, .mp4, .webm\n");
					return 1;
				}

				break;

			case 't':
				opt_track_number = true;
				arg_track_number = (uint16_t)strtoumax(optarg, NULL, 0);
				break;

			case 'V':
				print_version("dvd_trip");
				return 0;

			case 'v':
				verbose = true;
				break;

			case 'z':
				verbose = true;
				debug = true;
				break;

			// ignore unknown arguments
			case '?':
				print_usage("dvd_trip");
				return 1;

			// let getopt_long set the variable
			case 0:
			default:
				break;

		}

	}

	const char *device_filename = DEFAULT_DVD_DEVICE;

	if (argv[optind])
		device_filename = argv[optind];

	if(access(device_filename, F_OK) != 0) {
		fprintf(stderr, "cannot access %s\n", device_filename);
		return 1;
	}

	// Check to see if device can be opened
	int dvd_fd = 0;
	dvd_fd = dvd_device_open(device_filename);
	if(dvd_fd < 0) {
		fprintf(stderr, "dvd_trip: error opening %s\n", device_filename);
		return 1;
	}
	dvd_device_close(dvd_fd);


#ifdef __linux__

	// Poll drive status if it is hardware
	if(dvd_device_is_hardware(device_filename)) {

		// Wait for the drive to become ready
		if(!dvd_drive_has_media(device_filename)) {

			fprintf(stderr, "drive status: ");
			dvd_drive_display_status(device_filename);

			return 1;

		}

	}

#endif

	dvd_reader_t *dvdread_dvd = NULL;
	dvdread_dvd = DVDOpen(device_filename);

	if(!dvdread_dvd) {
		fprintf(stderr, "* dvdread could not open %s\n", device_filename);
		return 1;
	}

	ifo_handle_t *vmg_ifo = NULL;
	vmg_ifo = ifoOpen(dvdread_dvd, 0);

	if(vmg_ifo == NULL) {
		fprintf(stderr, "* Could not open IFO zero\n");
		DVDClose(dvdread_dvd);
		return 1;
	}

	// DVD
	struct dvd_info dvd_info;
	memset(dvd_info.dvdread_id, '\0', sizeof(dvd_info.dvdread_id));
	dvd_info.video_title_sets = dvd_video_title_sets(vmg_ifo);
	dvd_info.side = 1;
	memset(dvd_info.title, '\0', sizeof(dvd_info.title));
	memset(dvd_info.provider_id, '\0', sizeof(dvd_info.provider_id));
	memset(dvd_info.vmg_id, '\0', sizeof(dvd_info.vmg_id));
	dvd_info.tracks = dvd_tracks(vmg_ifo);
	dvd_info.longest_track = 1;

	dvd_title(dvd_info.title, device_filename);
	printf("Disc title: %s\n", dvd_info.title);

	uint16_t num_ifos = 1;
	num_ifos = vmg_ifo->vts_atrt->nr_of_vtss;

	if(num_ifos < 1) {
		fprintf(stderr, "* DVD has no title IFOs?!\n");
		fprintf(stderr, "* Most likely a bug in libdvdread or a bad master or problems reading the disc\n");
		ifoClose(vmg_ifo);
		DVDClose(dvdread_dvd);
		return 1;
	}


	// Track
	struct dvd_track dvd_track;
	memset(&dvd_track, 0, sizeof(dvd_track));

	struct dvd_track dvd_tracks[DVD_MAX_TRACKS];
	memset(&dvd_tracks, 0, sizeof(dvd_track) * dvd_info.tracks);

	// Cells
	struct dvd_cell dvd_cell;
	dvd_cell.cell = 1;
	memset(dvd_cell.length, '\0', sizeof(dvd_cell.length));
	snprintf(dvd_cell.length, DVD_CELL_LENGTH + 1, "00:00:00.000");
	dvd_cell.msecs = 0;

	// Open first IFO
	uint16_t vts = 1;
	ifo_handle_t *vts_ifo = NULL;

	vts_ifo = ifoOpen(dvdread_dvd, vts);
	if(vts_ifo == NULL) {
		fprintf(stderr, "* Could not open VTS_IFO for track %u\n", 1);
		return 1;
	}
	ifoClose(vts_ifo);
	vts_ifo = NULL;

	// Create an array of all the IFOs
	ifo_handle_t *vts_ifos[DVD_MAX_VTS_IFOS];
	vts_ifos[0] = NULL;

	for(vts = 1; vts < dvd_info.video_title_sets + 1; vts++) {

		dvd_vts[vts].vts = vts;
		dvd_vts[vts].valid = false;
		dvd_vts[vts].blocks = 0;
		dvd_vts[vts].filesize = 0;
		dvd_vts[vts].vobs = 0;
		dvd_vts[vts].tracks = 0;
		dvd_vts[vts].valid_tracks = 0;
		dvd_vts[vts].invalid_tracks = 0;

		vts_ifos[vts] = ifoOpen(dvdread_dvd, vts);

		if(vts_ifos[vts] == NULL) {
			dvd_vts[vts].valid = false;
			vts_ifos[vts] = NULL;
		} else if(!ifo_is_vts(vts_ifos[vts])) {
			dvd_vts[vts].valid = false;
			ifoClose(vts_ifos[vts]);
			vts_ifos[vts] = NULL;
		} else {
			dvd_vts[vts].valid = true;
		}

	}
	
	// Exit if track number requested does not exist
	if(opt_track_number && (arg_track_number > dvd_info.tracks)) {
		fprintf(stderr, "dvd_trip: Invalid track number %d\n", arg_track_number);
		fprintf(stderr, "dvd_trip: Valid track numbers: 1 to %u\n", dvd_info.tracks);
		ifoClose(vmg_ifo);
		DVDClose(dvdread_dvd);
		return 1;
	} else if(opt_track_number) {
		dvd_trip.track = arg_track_number;
	}

	uint16_t ix = 0;
	uint16_t track = 1;
	
	uint32_t longest_msecs = 0;
	
	for(ix = 0, track = 1; ix < dvd_info.tracks; ix++, track++) {
 
		vts = dvd_vts_ifo_number(vmg_ifo, ix + 1);
		vts_ifo = vts_ifos[vts];
		dvd_track_info(&dvd_tracks[ix], track, vmg_ifo, vts_ifo);
		dvd_tracks[ix].valid = true;

		if(dvd_tracks[ix].msecs > longest_msecs) {
			dvd_info.longest_track = track;
			longest_msecs = dvd_tracks[ix].msecs;
		}

	}

	// Set the track number to rip if none is passed as an argument
	if(!opt_track_number)
		dvd_trip.track = dvd_info.longest_track;
	
	dvd_track = dvd_tracks[dvd_trip.track - 1];

	// Set the proper chapter range
	if(opt_chapter_number) {
		if(arg_first_chapter > dvd_track.chapters) {
			dvd_trip.first_chapter = dvd_track.chapters;
			fprintf(stderr, "Resetting first chapter to %u\n", dvd_trip.first_chapter);
		} else
			dvd_trip.first_chapter = arg_first_chapter;
		
		if(arg_last_chapter > dvd_track.chapters) {
			dvd_trip.last_chapter = dvd_track.chapters;
			fprintf(stderr, "Resetting last chapter to %u\n", dvd_trip.last_chapter);
		} else
			dvd_trip.last_chapter = arg_last_chapter;
	} else {
		dvd_trip.first_chapter = 1;
		dvd_trip.last_chapter = dvd_track.chapters;
	}
	
	/**
	 * File descriptors and filenames
	 */
	dvd_file_t *dvdread_vts_file = NULL;

	vts = dvd_vts_ifo_number(vmg_ifo, dvd_trip.track);
	vts_ifo = vts_ifos[vts];

	// Open the VTS VOB
	dvdread_vts_file = DVDOpenFile(dvdread_dvd, vts, DVD_READ_TITLE_VOBS);

	printf("Track: %02u, Length: %s, Chapters: %02u, Cells: %02u, Audio streams: %02u, Subpictures: %02u, Filesize: %lu, Blocks: %lu\n", dvd_track.track, dvd_track.length, dvd_track.chapters, dvd_track.cells, dvd_track.audio_tracks, dvd_track.subtitles, dvd_track.filesize, dvd_track.blocks);

	// Check for track issues
	dvd_track.valid = true;

	if(dvd_vts[vts].valid == false) {
		dvd_track.valid = false;
	}

	if(dvd_track.msecs == 0) {
		printf("	Error: track has zero length\n");
		dvd_track.valid = false;
	}

	if(dvd_track.chapters == 0) {
		printf("	Error: track has zero chapters\n");
		dvd_track.valid = false;
	}

	if(dvd_track.cells == 0) {
		printf("	Error: track has zero cells\n");
		dvd_track.valid = false;
	}

	if(dvd_track.valid == false) {

		printf("Track has been marked as invalid, quitting\n");

		DVDCloseFile(dvdread_vts_file);

		if(vts_ifo)
			ifoClose(vts_ifo);

		if(vmg_ifo)
			ifoClose(vmg_ifo);

		if(dvdread_dvd)
			DVDClose(dvdread_dvd);

		return 1;

	}

	// MPV zero-indexes tracks
	sprintf(dvd_mpv_args, "dvdread://%u", dvd_trip.track - 1);

	const char *dvd_mpv_commands[] = { "loadfile", dvd_mpv_args, NULL };


	// DVD playback using libmpv
	dvd_mpv = mpv_create();

	// Terminal output
	mpv_set_option_string(dvd_mpv, "terminal", "yes");
	if(!debug)
		mpv_set_option_string(dvd_mpv, "term-osd-bar", "yes");

	if (debug) {
		mpv_request_log_messages(dvd_mpv, "debug");
		strcpy(dvd_trip.vcodec_log_level, "full");
	} else if(verbose) {
		mpv_request_log_messages(dvd_mpv, "v");
		strcpy(dvd_trip.vcodec_log_level, "info");
	} else {
		mpv_request_log_messages(dvd_mpv, "info");
		strcpy(dvd_trip.vcodec_log_level, "info");
	}

	/** Video **/

	// Set output frames per second and color spaces based on source (NTSC or PAL)
	if(dvd_track_pal_video(vts_ifo)) {
		strcpy(dvd_trip.fps, "25");
		strcpy(dvd_trip.color_opts, "color_primaries=bt470bg,color_trc=gamma28,colorspace=bt470bg");
	} else {
		strcpy(dvd_trip.fps, "30000/1001");
		strcpy(dvd_trip.color_opts, "color_primaries=smpte170m,color_trc=smpte170m,colorspace=smpte170m");
	}

	/** Containers and Presets **/

	// Set preset defaults
	if(strncmp(dvd_trip.container, "mkv", 3) == 0) {

		if(!opt_filename)
			strcpy(dvd_trip.filename, "trip_encode.mkv");

		strcpy(dvd_trip.vcodec, "libx265");
		strcpy(dvd_trip.vcodec_preset, "medium");
		strcpy(dvd_trip.acodec, "libfdk_aac");


		if(strncmp(dvd_trip.preset, "low", 3) == 0) {
			strcpy(dvd_trip.vcodec_preset, "fast");
			dvd_trip.crf = 28;
		} else if(strncmp(dvd_trip.preset, "medium", 6) == 0) {
			strcpy(dvd_trip.vcodec_preset, "medium");
			dvd_trip.crf = 24;
		} else if(strncmp(dvd_trip.preset, "high", 4) == 0) {
			strcpy(dvd_trip.vcodec_preset, "slow");
			strcpy(dvd_trip.acodec_opts, "b=192k");
			dvd_trip.crf = 20;
		} else if(strncmp(dvd_trip.preset, "insane", 6) == 0) {
			strcpy(dvd_trip.vcodec_preset, "slower");
			strcpy(dvd_trip.acodec_opts, "b=256k");
			dvd_trip.crf = 14;
		}

		sprintf(dvd_trip.vcodec_opts, "%s,preset=%s,crf=%u,x265-params=log-level=%s", dvd_trip.color_opts, dvd_trip.vcodec_preset, dvd_trip.crf, dvd_trip.vcodec_log_level);

	}

	if(strncmp(dvd_trip.container, "mp4", 3) == 0) {

		if(!opt_filename)
			strcpy(dvd_trip.filename, "trip_encode.mp4");

		strcpy(dvd_trip.vcodec, "libx264");
		strcpy(dvd_trip.vcodec_preset, "medium");
		strcpy(dvd_trip.acodec, "libfdk_aac");
		strcpy(dvd_trip.acodec_opts, "");


		if(strncmp(dvd_trip.preset, "low", 3) == 0) {
			strcpy(dvd_trip.vcodec_preset, "fast");
			dvd_trip.crf = 28;
		} else if(strncmp(dvd_trip.preset, "medium", 6) == 0) {
			strcpy(dvd_trip.vcodec_preset, "medium");
			dvd_trip.crf = 22;
		} else if(strncmp(dvd_trip.preset, "high", 4) == 0) {
			strcpy(dvd_trip.vcodec_preset, "slow");
			strcpy(dvd_trip.acodec_opts, "b=192k");
			dvd_trip.crf = 20;
		} else if(strncmp(dvd_trip.preset, "insane", 6) == 0) {
			strcpy(dvd_trip.vcodec_preset, "slower");
			strcpy(dvd_trip.acodec_opts, "b=256k");
			dvd_trip.crf = 16;
		}

		// x264 doesn't allow passing log level (that I can see)
		sprintf(dvd_trip.vcodec_opts, "%s,preset=%s,crf=%u", dvd_trip.color_opts, dvd_trip.vcodec_preset, dvd_trip.crf);

	}

	if(strncmp(dvd_trip.container, "webm", 4) == 0) {

		if(!opt_filename)
			strcpy(dvd_trip.filename, "trip_encode.webm");

		strcpy(dvd_trip.vcodec, "libvpx-vp9");
		strcpy(dvd_trip.acodec, "libopus");
		strcpy(dvd_trip.acodec_opts, "application=audio");

		if(strncmp(dvd_trip.preset, "low", 3) == 0) {
			dvd_trip.crf = 34;
			sprintf(dvd_trip.vcodec_opts, "%s,b=0,crf=%u,keyint_min=0,g=360", dvd_trip.color_opts, dvd_trip.crf);
			strcpy(dvd_trip.acodec_opts, "application=audio,b=96000");
		}

		if(strncmp(dvd_trip.preset, "medium", 6) == 0) {
			dvd_trip.crf = 32;
			sprintf(dvd_trip.vcodec_opts, "%s,b=0,crf=%u,keyint_min=0,g=360", dvd_trip.color_opts, dvd_trip.crf);
			strcpy(dvd_trip.acodec_opts, "application=audio,b=144000");
		}

		if(strncmp(dvd_trip.preset, "high", 4) == 0) {
			dvd_trip.crf = 22;
			sprintf(dvd_trip.vcodec_opts, "%s,b=0,crf=%u,keyint_min=0,g=360", dvd_trip.color_opts, dvd_trip.crf);
			strcpy(dvd_trip.acodec_opts, "application=audio,b=192000");
		}

		if(strncmp(dvd_trip.preset, "insane", 6) == 0) {
			dvd_trip.crf = 16;
			sprintf(dvd_trip.vcodec_opts, "%s,b=0,crf=%u,keyint_min=0,g=360", dvd_trip.color_opts, dvd_trip.crf);
			strcpy(dvd_trip.acodec_opts, "application=audio,b=256000");
		}

	}

	mpv_set_option_string(dvd_mpv, "o", dvd_trip.filename);
	mpv_set_option_string(dvd_mpv, "ovc", dvd_trip.vcodec);
	mpv_set_option_string(dvd_mpv, "ovcopts", dvd_trip.vcodec_opts);
	mpv_set_option_string(dvd_mpv, "oac", dvd_trip.acodec);
	if(strlen(dvd_trip.acodec_opts) > 0)
		mpv_set_option_string(dvd_mpv, "oacopts", dvd_trip.acodec_opts);
	mpv_set_option_string(dvd_mpv, "dvd-device", device_filename);
	mpv_set_option_string(dvd_mpv, "track-auto-selection", "yes");
	mpv_set_option_string(dvd_mpv, "input-default-bindings", "yes");
	mpv_set_option_string(dvd_mpv, "input-vo-keyboard", "yes");
	mpv_set_option_string(dvd_mpv, "resume-playback", "no");

	// MPV's chapter range starts at the first one, and ends at the last one plus one
	// fex: to play chapter 1 only, mpv --start '#1' --end '#2'
	sprintf(dvd_mpv_first_chapter, "#%u", dvd_trip.first_chapter);
	sprintf(dvd_mpv_last_chapter, "#%u", dvd_trip.last_chapter + 1);
	mpv_set_option_string(dvd_mpv, "start", dvd_mpv_first_chapter);
	mpv_set_option_string(dvd_mpv, "end", dvd_mpv_last_chapter);

	if(strlen(dvd_trip.audio_aid) > 0)
		mpv_set_option_string(dvd_mpv, "aid", dvd_trip.audio_aid);
	else if(strlen(dvd_trip.audio_lang) > 0)
		mpv_set_option_string(dvd_mpv, "alang", dvd_trip.audio_lang);

	/** Video Filters **/

	if(mpv_client_api_version() <= MPV_MAKE_VERSION(1, 25)) {

		// Syntax up to 0.27.2
		mpv_set_option_string(dvd_mpv, "ofps", dvd_trip.fps);

		if(dvd_trip.detelecine && dvd_trip.deinterlace)
			sprintf(dvd_trip.vf_opts, "lavfi=yadif,lavfi=pullup,lavfi=dejudder");
		else if(dvd_trip.deinterlace)
			sprintf(dvd_trip.vf_opts, "lavfi=yadif");
		else if(dvd_trip.detelecine)
			sprintf(dvd_trip.vf_opts, "lavfi=pullup,lavfi=dejudder");

	} else {

		// Syntax starting in 0.29.1
		if(dvd_trip.detelecine && dvd_trip.deinterlace)
			sprintf(dvd_trip.vf_opts, "lavfi-yadif,lavfi-pullup,lavfi-dejudder,fps=%s", dvd_trip.fps);
		else if(dvd_trip.deinterlace)
			sprintf(dvd_trip.vf_opts, "lavfi-yadif,fps=%s", dvd_trip.fps);
		else if(dvd_trip.detelecine)
			sprintf(dvd_trip.vf_opts, "lavfi-pullup,lavfi-dejudder,fps=%s", dvd_trip.fps);
		else
			sprintf(dvd_trip.vf_opts, "fps=%s", dvd_trip.fps);

	}

	mpv_set_option_string(dvd_mpv, "vf", dvd_trip.vf_opts);

	if(dvd_trip.pass == 1) {
		fprintf(stderr, "dvd_trip [info]: dvd track %u\n", dvd_trip.track);
		fprintf(stderr, "dvd_trip [info]: chapters %u to %u\n", dvd_trip.first_chapter, dvd_trip.last_chapter);
		fprintf(stderr, "dvd_trip [info]: saving to %s\n", dvd_trip.filename);
		fprintf(stderr, "dvd_trip [info]: vcodec %s\n", dvd_trip.vcodec);
		fprintf(stderr, "dvd_trip [info]: acodec %s\n", dvd_trip.acodec);
		fprintf(stderr, "dvd_trip [info]: ovcopts %s\n", dvd_trip.vcodec_opts);
		fprintf(stderr, "dvd_trip [info]: oacopts %s\n", dvd_trip.acodec_opts);
		if(strlen(dvd_trip.vf_opts))
			fprintf(stderr, "dvd_trip [info]: vf %s\n", dvd_trip.vf_opts);
		fprintf(stderr, "dvd_trip [info]: output fps %s\n", dvd_trip.fps);
		if(dvd_trip.deinterlace)
			fprintf(stderr, "dvd_trip [info]: deinterlacing video\n");
		if(dvd_trip.detelecine)
			fprintf(stderr, "dvd_trip [info]: detelecining video\n");
	}

	mpv_initialize(dvd_mpv);
	mpv_command(dvd_mpv, dvd_mpv_commands);

	while(true) {

		dvd_mpv_event = mpv_wait_event(dvd_mpv, -1);

		if(dvd_mpv_event->event_id == MPV_EVENT_SHUTDOWN || dvd_mpv_event->event_id == MPV_EVENT_END_FILE)
			break;

		// Logging output
		if((verbose || debug) && dvd_mpv_event->event_id == MPV_EVENT_LOG_MESSAGE) {
			dvd_mpv_log_message = (struct mpv_event_log_message *)dvd_mpv_event->data;
			printf("mpv [%s]: %s", dvd_mpv_log_message->level, dvd_mpv_log_message->text);
		}

	}

	mpv_terminate_destroy(dvd_mpv);

	DVDCloseFile(dvdread_vts_file);

	if(vts_ifo)
		ifoClose(vts_ifo);
	
	if(vmg_ifo)
		ifoClose(vmg_ifo);

	if(dvdread_dvd)
		DVDClose(dvdread_dvd);
	
	return 0;

}
Exemple #17
0
dvd_reader_t *DVDOpen( const char *ppath )
{
    struct stat fileinfo;
    int ret;
    int have_css;
	dvd_reader_t *ret_val = NULL;
    char *dev_name = 0;
	char *path;

#ifdef _MSC_VER
	int len;
#endif

    if( ppath == NULL )
      return 0;

	path = strdup(ppath);
	
    /* Try to open libdvdcss or fall back to standard functions */
    have_css = dvdinput_setup();

#ifdef _MSC_VER
	/* Strip off the trailing \ if it is not a drive */
	len = strlen(path);
	if ((len > 1) && 
		(path[len - 1] == '\\')  && 
		(path[len - 2] != ':'))
	{
		path[len-1] = '\0';
	}
#endif
    
    ret = stat( path, &fileinfo );

    if( ret < 0 ) {

        /* maybe "host:port" url? try opening it with acCeSS library */
        if( strchr(path,':') ) {
			ret_val = DVDOpenImageFile( path, have_css );
			free(path);
	        return ret_val;
        }
      
	/* If we can't stat the file, give up */
	fprintf( stderr, "libdvdread: Can't stat %s\n", path );
	perror("");
	free(path);
	return 0;
    }

    /* First check if this is a block/char device or a file*/
    if( S_ISBLK( fileinfo.st_mode ) || 
	S_ISCHR( fileinfo.st_mode ) || 
	S_ISREG( fileinfo.st_mode ) ) {

	/**
	 * Block devices and regular files are assumed to be DVD-Video images.
	 */
#if defined(__sun)
	ret_val = DVDOpenImageFile( sun_block2char( path ), have_css );
#elif defined(SYS_BSD)
	ret_val = DVDOpenImageFile( bsd_block2char( path ), have_css );
#else
	ret_val = DVDOpenImageFile( path, have_css );
#endif

	free(path);
	return ret_val;

    } else if( S_ISDIR( fileinfo.st_mode ) ) {
	dvd_reader_t *auth_drive = 0;
	char *path_copy;
#if defined(SYS_BSD)
	struct fstab* fe;
#elif defined(__sun) || defined(__linux__)
	FILE *mntfile;
#endif

	/* XXX: We should scream real loud here. */
	if( !(path_copy = strdup( path ) ) ) {
		free(path);	
		return 0;
	}

#ifndef WIN32 /* don't have fchdir, and getcwd( NULL, ... ) is strange */
              /* Also WIN32 does not have symlinks, so we don't need this bit of code. */

	/* Resolve any symlinks and get the absolut dir name. */
	{
	    char *new_path;
	    int cdir = open( ".", O_RDONLY );
	    
	    if( cdir >= 0 ) {
		chdir( path_copy );
		new_path = getcwd( NULL, XINE_PATH_MAX );
		fchdir( cdir );
		close( cdir );
		if( new_path ) {
		    free( path_copy );
		    path_copy = new_path;
		}
	    }
	}
#endif	
	/**
	 * If we're being asked to open a directory, check if that directory
	 * is the mountpoint for a DVD-ROM which we can use instead.
	 */

	if( strlen( path_copy ) > 1 ) {
	    if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) 
		path_copy[ strlen( path_copy ) - 1 ] = '\0';
	}

	if( strlen( path_copy ) > 9 ) {
	    if( !strcasecmp( &(path_copy[ strlen( path_copy ) - 9 ]), 
			     "/video_ts" ) ) {
	      path_copy[ strlen( path_copy ) - 9 ] = '\0';
	    }
	}

#if defined(SYS_BSD)
	if( ( fe = getfsfile( path_copy ) ) ) {
	    dev_name = bsd_block2char( fe->fs_spec );
	    fprintf( stderr,
		     "libdvdread: Attempting to use device %s"
		     " mounted on %s for CSS authentication\n",
		     dev_name,
		     fe->fs_file );
	    auth_drive = DVDOpenImageFile( dev_name, have_css );
	}
#elif defined(__sun)
	mntfile = fopen( MNTTAB, "r" );
	if( mntfile ) {
	    struct mnttab mp;
	    int res;

	    while( ( res = getmntent( mntfile, &mp ) ) != -1 ) {
		if( res == 0 && !strcmp( mp.mnt_mountp, path_copy ) ) {
		    dev_name = sun_block2char( mp.mnt_special );
		    fprintf( stderr, 
			     "libdvdread: Attempting to use device %s"
			     " mounted on %s for CSS authentication\n",
			     dev_name,
			     mp.mnt_mountp );
		    auth_drive = DVDOpenImageFile( dev_name, have_css );
		    break;
		}
	    }
	    fclose( mntfile );
	}
#elif defined(__linux__)
        mntfile = fopen( MOUNTED, "r" );
        if( mntfile ) {
            struct mntent *me;
 
            while( ( me = getmntent( mntfile ) ) ) {
                if( !strcmp( me->mnt_dir, path_copy ) ) {
		    fprintf( stderr, 
			     "libdvdread: Attempting to use device %s"
			     " mounted on %s for CSS authentication\n",
			     me->mnt_fsname,
			     me->mnt_dir );
                    auth_drive = DVDOpenImageFile( me->mnt_fsname, have_css );
		    /* If the device is not encrypted, don't access the device
		     * directly as it would fail for non-UDF DVDs */
		    if ( auth_drive && dvdinput_is_encrypted( auth_drive->dev ) == 0) {
		      DVDClose( auth_drive );
		      auth_drive = NULL;
		      break;
		    }
		    dev_name = strdup(me->mnt_fsname);
                    break;
                }
            }
            fclose( mntfile );
	}
#elif defined(_MSC_VER)
    auth_drive = DVDOpenImageFile( path, have_css );
#endif

#ifndef _MSC_VER
	if( !dev_name ) {
	  fprintf( stderr, "libdvdread: Couldn't find device name.\n" );
	} else if( !auth_drive ) {
	    fprintf( stderr, "libdvdread: Device %s inaccessible, "
		     "CSS authentication not available.\n", dev_name );
	}
#else
	if( !auth_drive ) {
	    fprintf( stderr, "libdvdread: Device %s inaccessible, "
		     "CSS authentication not available.\n", dev_name );
	}
#endif

	free( dev_name );
	free( path_copy );

        /**
         * If we've opened a drive, just use that.
         */
	if( auth_drive ) {
		free(path);
		return auth_drive;
	}

        /**
         * Otherwise, we now try to open the directory tree instead.
         */
        ret_val = DVDOpenPath( path );
		free( path );
		return ret_val;
    }

    /* If it's none of the above, screw it. */
    fprintf( stderr, "libdvdread: Could not open %s\n", path );
	free( path );
    return 0;
}
Exemple #18
0
int main(int argc, char **argv) {

	/**
	 * Parse options
	 */

	bool verbose = false;
	bool debug = false;
	bool opt_track_number = false;
	bool opt_chapter_number = false;
	bool opt_widescreen = false;
	bool opt_pan_scan = false;
	bool opt_no_video = false;
	bool opt_no_audio = false;
	uint16_t arg_track_number = 0;
	uint8_t arg_first_chapter = 1;
	uint8_t arg_last_chapter = 99;
	struct dvd_player dvd_player;
	struct dvd_playback dvd_playback;
	char dvd_mpv_args[13] = {'\0'};
	mpv_handle *dvd_mpv = NULL;
	mpv_event *dvd_mpv_event = NULL;
	struct mpv_event_log_message *dvd_mpv_log_message = NULL;
	const char *home_dir = getenv("HOME");
	const char *lang = getenv("LANG");

	// Video Title Set
	struct dvd_vts dvd_vts[99];

	// DVD player default options
	snprintf(dvd_player.config_dir, 20, "/.config/dvd_player");
	memset(dvd_player.mpv_config_dir, '\0', sizeof(dvd_player.mpv_config_dir));
	if(home_dir != NULL)
		snprintf(dvd_player.mpv_config_dir, PATH_MAX - 1, "%s%s", home_dir, dvd_player.config_dir);

	// DVD playback default options
	dvd_playback.track = 1;
	dvd_playback.first_chapter = 1;
	dvd_playback.last_chapter = 99;
	dvd_playback.fullscreen = false;
	dvd_playback.deinterlace = false;
	dvd_playback.subtitles = false;
	snprintf(dvd_playback.mpv_chapters_range, 8, "%u-%u", 1, 99);
	memset(dvd_playback.audio_lang, '\0', sizeof(dvd_playback.audio_lang));
	if(strlen(lang) >= 2)
		snprintf(dvd_playback.audio_lang, 3, "%s", strndup(lang, 2));
	memset(dvd_playback.audio_aid, '\0', sizeof(dvd_playback.audio_aid));
	memset(dvd_playback.subtitles_lang, '\0', sizeof(dvd_playback.subtitles_lang));
	if(strlen(lang) >= 2)
		snprintf(dvd_playback.subtitles_lang, 3, "%s", strndup(lang, 2));
	memset(dvd_playback.subtitles_sid, '\0', sizeof(dvd_playback.subtitles_sid));

	const char str_options[] = "Aa:c:dfhpSs:t:Vvwz";
	struct option long_options[] = {

		{ "track", required_argument, 0, 't' },
		{ "chapters", required_argument, 0, 'c' },
		{ "fullscreen", no_argument, 0, 'f' },
		{ "deinterlace", no_argument, 0, 'd' },
		{ "alang", required_argument, 0, 'a' },
		{ "slang", required_argument, 0, 's' },
		{ "aid", required_argument, 0, 'A' },
		{ "sid", required_argument, 0, 'S' },
		{ "help", no_argument, 0, 'h' },
		{ "version", no_argument, 0, 'V' },
		{ "widescreen", no_argument, 0, 'w' },
		{ "pan-scan", no_argument, 0, 'p' },
		{ "verbose", no_argument, 0, 'v' },
		{ "debug", no_argument, 0, 'z' },
		{ 0, 0, 0, 0 }

	};

	int long_index = 0;
	int opt = 0;
	opterr = 1;
	char *token = NULL;

	while((opt = getopt_long(argc, argv, str_options, long_options, &long_index )) != -1) {

		switch(opt) {

			case 'A':
				strncpy(dvd_playback.audio_aid, optarg, 3);
				break;

			case 'a':
				strncpy(dvd_playback.audio_lang, optarg, 2);
				break;

			case 'c':
				opt_chapter_number = true;
				token = strtok(optarg, "-"); {
					if(strlen(token) > 2) {
						fprintf(stderr, "Chapter range must be between 1 and 99\n");
						return 1;
					}
					arg_first_chapter = (uint8_t)strtoumax(token, NULL, 0);
				}

				token = strtok(NULL, "-");
				if(token != NULL) {
					if(strlen(token) > 2) {
						fprintf(stderr, "Chapter range must be between 1 and 99\n");
						return 1;
					}
					arg_last_chapter = (uint8_t)strtoumax(token, NULL, 0);
				}

				if(arg_first_chapter == 0)
					arg_first_chapter = 1;
				if(arg_last_chapter < arg_first_chapter)
					arg_last_chapter = arg_first_chapter;
				if(arg_first_chapter > arg_last_chapter)
					arg_first_chapter = arg_last_chapter;

				break;

			case 'd':
				dvd_playback.deinterlace = true;
				break;

			case 'f':
				dvd_playback.fullscreen = true;
				break;

			case 'h':
				print_usage(DVD_INFO_PROGRAM);
				return 0;

			case 'p':
				opt_pan_scan = true;
				break;

			case 's':
				strncpy(dvd_playback.subtitles_lang, optarg, 2);
				dvd_playback.subtitles = true;
				break;

			case 'S':
				strncpy(dvd_playback.subtitles_sid, optarg, 3);
				dvd_playback.subtitles = true;
				break;

			case 't':
				opt_track_number = true;
				arg_track_number = (uint16_t)strtoumax(optarg, NULL, 0);
				break;

			case 'V':
				print_version("dvd_player");
				return 0;

			case 'v':
				verbose = true;
				break;

			case 'w':
				opt_widescreen = true;
				break;

			case 'z':
				verbose = true;
				debug = true;
				break;

			// ignore unknown arguments
			case '?':
				print_usage("dvd_player");
				return 1;

			// let getopt_long set the variable
			case 0:
			default:
				break;

		}

	}

	if(opt_pan_scan && opt_widescreen)
		opt_pan_scan = false;
	
	const char *device_filename = DEFAULT_DVD_DEVICE;

	if (argv[optind])
		device_filename = argv[optind];

	if(access(device_filename, F_OK) != 0) {
		fprintf(stderr, "cannot access %s\n", device_filename);
		return 1;
	}

	// Check to see if device can be opened
	int dvd_fd = 0;
	dvd_fd = dvd_device_open(device_filename);
	if(dvd_fd < 0) {
		fprintf(stderr, "dvd_player: error opening %s\n", device_filename);
		return 1;
	}
	dvd_device_close(dvd_fd);


#ifdef __linux__

	// Poll drive status if it is hardware
	if(dvd_device_is_hardware(device_filename)) {

		// Wait for the drive to become ready
		if(!dvd_drive_has_media(device_filename)) {

			fprintf(stderr, "drive status: ");
			dvd_drive_display_status(device_filename);

			return 1;

		}

	}

#endif

	dvd_reader_t *dvdread_dvd = NULL;
	dvdread_dvd = DVDOpen(device_filename);

	if(!dvdread_dvd) {
		fprintf(stderr, "* dvdread could not open %s\n", device_filename);
		return 1;
	}

	ifo_handle_t *vmg_ifo = NULL;
	vmg_ifo = ifoOpen(dvdread_dvd, 0);

	if(vmg_ifo == NULL) {
		fprintf(stderr, "* Could not open IFO zero\n");
		DVDClose(dvdread_dvd);
		return 1;
	}

	// DVD
	struct dvd_info dvd_info;
	memset(dvd_info.dvdread_id, '\0', sizeof(dvd_info.dvdread_id));
	dvd_info.video_title_sets = dvd_video_title_sets(vmg_ifo);
	dvd_info.side = 1;
	memset(dvd_info.title, '\0', sizeof(dvd_info.title));
	memset(dvd_info.provider_id, '\0', sizeof(dvd_info.provider_id));
	memset(dvd_info.vmg_id, '\0', sizeof(dvd_info.vmg_id));
	dvd_info.tracks = dvd_tracks(vmg_ifo);
	dvd_info.longest_track = 1;

	dvd_title(dvd_info.title, device_filename);
	printf("Disc title: %s\n", dvd_info.title);

	uint16_t num_ifos = 1;
	num_ifos = vmg_ifo->vts_atrt->nr_of_vtss;

	if(num_ifos < 1) {
		fprintf(stderr, "* DVD has no title IFOs?!\n");
		fprintf(stderr, "* Most likely a bug in libdvdread or a bad master or problems reading the disc\n");
		ifoClose(vmg_ifo);
		DVDClose(dvdread_dvd);
		return 1;
	}


	// Track
	struct dvd_track dvd_track;
	memset(&dvd_track, 0, sizeof(dvd_track));

	struct dvd_track dvd_tracks[DVD_MAX_TRACKS];
	memset(&dvd_tracks, 0, sizeof(dvd_track) * dvd_info.tracks);

	// Open first IFO
	uint16_t vts = 1;
	ifo_handle_t *vts_ifo = NULL;

	vts_ifo = ifoOpen(dvdread_dvd, vts);
	if(vts_ifo == NULL) {
		fprintf(stderr, "* Could not open VTS_IFO for track %u\n", 1);
		return 1;
	}
	ifoClose(vts_ifo);
	vts_ifo = NULL;

	// Create an array of all the IFOs
	ifo_handle_t *vts_ifos[DVD_MAX_VTS_IFOS];
	vts_ifos[0] = NULL;

	for(vts = 1; vts < dvd_info.video_title_sets + 1; vts++) {

		dvd_vts[vts].vts = vts;
		dvd_vts[vts].valid = false;
		dvd_vts[vts].blocks = 0;
		dvd_vts[vts].filesize = 0;
		dvd_vts[vts].vobs = 0;
		dvd_vts[vts].tracks = 0;
		dvd_vts[vts].valid_tracks = 0;
		dvd_vts[vts].invalid_tracks = 0;

		vts_ifos[vts] = ifoOpen(dvdread_dvd, vts);

		if(vts_ifos[vts] == NULL) {
			dvd_vts[vts].valid = false;
			vts_ifos[vts] = NULL;
		} else if(!ifo_is_vts(vts_ifos[vts])) {
			dvd_vts[vts].valid = false;
			ifoClose(vts_ifos[vts]);
			vts_ifos[vts] = NULL;
		} else {
			dvd_vts[vts].valid = true;
		}

	}
	
	// Exit if track number requested does not exist
	if(opt_track_number && (arg_track_number > dvd_info.tracks)) {
		fprintf(stderr, "dvd_player: Invalid track number %d\n", arg_track_number);
		fprintf(stderr, "dvd_player: Valid track numbers: 1 to %u\n", dvd_info.tracks);
		ifoClose(vmg_ifo);
		DVDClose(dvdread_dvd);
		return 1;
	} else if(opt_track_number) {
		dvd_playback.track = arg_track_number;
	}

	uint16_t ix = 0;
	uint16_t track = 1;
	
	uint32_t longest_msecs = 0;
	uint16_t longest_widescreen_track = 0;
	uint32_t longest_widescreen_msecs = 0;
	uint16_t longest_pan_scan_track = 0;
	uint32_t longest_pan_scan_msecs = 0;
	
	for(ix = 0, track = 1; ix < dvd_info.tracks; ix++, track++) {
 
		vts = dvd_vts_ifo_number(vmg_ifo, ix + 1);
		vts_ifo = vts_ifos[vts];
		dvd_track_info(&dvd_tracks[ix], track, vmg_ifo, vts_ifo);

		if(dvd_tracks[ix].msecs > longest_msecs) {
			dvd_info.longest_track = track;
			longest_msecs = dvd_tracks[ix].msecs;
		}

		if(dvd_track_aspect_ratio_16x9(vts_ifo) && dvd_tracks[ix].msecs > longest_widescreen_msecs) {
			longest_widescreen_msecs = dvd_tracks[ix].msecs;
			longest_widescreen_track = track;
		}

		else if(dvd_track_aspect_ratio_4x3(vts_ifo) && dvd_tracks[ix].msecs > longest_pan_scan_msecs) {
			longest_pan_scan_msecs = dvd_tracks[ix].msecs;
			longest_pan_scan_track = track;
		}

	}

	if(opt_widescreen && longest_widescreen_track != 0)
		dvd_info.longest_track = longest_widescreen_track;
	else if(opt_pan_scan && longest_pan_scan_track != 0)
		dvd_info.longest_track = longest_pan_scan_track;

	// TODO if there is another track that is active, within ~1 seconds of longest track, and
	// the first is pan & scan, and the second is widescreen, switch to the widescreen one.
	// A more intelligent search might also see if the second one has audio tracks. Need to
	// find a reference DVD.

	// Set the track number to play if none is passed as an argument
	if(!opt_track_number)
		dvd_playback.track = dvd_info.longest_track;
	
	dvd_track = dvd_tracks[dvd_playback.track - 1];

	// Set the proper chapter range
	if(opt_chapter_number) {
		if(arg_first_chapter > dvd_track.chapters) {
			dvd_playback.first_chapter = dvd_track.chapters;
		} else
			dvd_playback.first_chapter = arg_first_chapter;
		
		if(arg_last_chapter > dvd_track.chapters) {
			dvd_playback.last_chapter = dvd_track.chapters;
		} else
			dvd_playback.last_chapter = arg_last_chapter;
	} else {
		dvd_playback.first_chapter = 1;
		dvd_playback.last_chapter = dvd_track.chapters;
	}
	
	/**
	 * File descriptors and filenames
	 */
	dvd_file_t *dvdread_vts_file = NULL;

	vts = dvd_vts_ifo_number(vmg_ifo, dvd_playback.track);
	vts_ifo = vts_ifos[vts];

	// Open the VTS VOB
	dvdread_vts_file = DVDOpenFile(dvdread_dvd, vts, DVD_READ_TITLE_VOBS);

	printf("Track: %02u, Length: %s, Chapters: %02u, Cells: %02u, Audio streams: %02u, Subpictures: %02u, Filesize: %lu, Blocks: %lu\n", dvd_track.track, dvd_track.length, dvd_track.chapters, dvd_track.cells, dvd_track.audio_tracks, dvd_track.subtitles, dvd_track.filesize, dvd_track.blocks);

	// Check for track issues
	dvd_track.valid = true;

	if(dvd_vts[vts].valid == false) {
		dvd_track.valid = false;
	}

	if(dvd_track.msecs == 0) {
		printf("	Error: track has zero length\n");
		dvd_track.valid = false;
	}

	if(dvd_track.chapters == 0) {
		printf("	Error: track has zero chapters\n");
		dvd_track.valid = false;
	}

	if(dvd_track.cells == 0) {
		printf("	Error: track has zero cells\n");
		dvd_track.valid = false;
	}

	if(dvd_track.valid == false) {

		printf("Track has been marked as invalid, quitting\n");

		DVDCloseFile(dvdread_vts_file);

		if(vts_ifo)
			ifoClose(vts_ifo);

		if(vmg_ifo)
			ifoClose(vmg_ifo);

		if(dvdread_dvd)
			DVDClose(dvdread_dvd);

		return 1;

	}

	// DVD playback using libmpv
	dvd_mpv = mpv_create();

	// Terminal output
	mpv_set_option_string(dvd_mpv, "terminal", "yes");
	mpv_set_option_string(dvd_mpv, "term-osd-bar", "yes");
	if(debug) {
		mpv_request_log_messages(dvd_mpv, "debug");
	} else if(verbose) {
		mpv_request_log_messages(dvd_mpv, "v");
	} else {
		mpv_request_log_messages(dvd_mpv, "none");
		// Skip "[ffmpeg/audio] ac3: frame sync error" which are normal when seeking on DVDs
		mpv_set_option_string(dvd_mpv, "msg-level", "ffmpeg/audio=none");
	}

	// mpv zero-indexes tracks
	snprintf(dvd_mpv_args, 13, "dvdread://%u", dvd_playback.track - 1);

	// MPV uses zero-indexing for tracks, dvd_info uses one instead
	const char *dvd_mpv_commands[] = { "loadfile", dvd_mpv_args, NULL };

	// Load user's mpv configuration in ~/.config/dvd_player/mpv.conf (and friends)
	if(strlen(dvd_player.mpv_config_dir) > 0) {
		mpv_set_option_string(dvd_mpv, "config-dir", dvd_player.mpv_config_dir);
		mpv_set_option_string(dvd_mpv, "config", "yes");
	}

	// When choosing a chapter range, mpv will add 1 to the last one requested
	snprintf(dvd_playback.mpv_chapters_range, 8, "%u-%u", dvd_playback.first_chapter, dvd_playback.last_chapter + 1);

	// Playback options and default configuration
	mpv_set_option_string(dvd_mpv, "dvd-device", device_filename);
	if(strlen(dvd_info.title) > 0)
		mpv_set_option_string(dvd_mpv, "title", dvd_info.title);
	else
		mpv_set_option_string(dvd_mpv, "title", "dvd_player");
	mpv_set_option_string(dvd_mpv, "chapter", dvd_playback.mpv_chapters_range);
	mpv_set_option_string(dvd_mpv, "input-default-bindings", "yes");
	mpv_set_option_string(dvd_mpv, "input-vo-keyboard", "yes");
	if(strlen(dvd_playback.audio_aid) > 0)
		mpv_set_option_string(dvd_mpv, "aid", dvd_playback.audio_aid);
	else if(strlen(dvd_playback.audio_lang) > 0)
		mpv_set_option_string(dvd_mpv, "alang", dvd_playback.audio_lang);
	if(dvd_playback.subtitles && strlen(dvd_playback.subtitles_sid) > 0)
		mpv_set_option_string(dvd_mpv, "sid", dvd_playback.subtitles_sid);
	else if(dvd_playback.subtitles && strlen(dvd_playback.subtitles_lang) > 0)
		mpv_set_option_string(dvd_mpv, "slang", dvd_playback.subtitles_lang);
	if(dvd_playback.fullscreen)
		mpv_set_option_string(dvd_mpv, "fullscreen", NULL);
	if(dvd_playback.deinterlace)
		mpv_set_option_string(dvd_mpv, "deinterlace", "yes");
	if(opt_no_video)
		mpv_set_option_string(dvd_mpv, "video", "no");
	if(opt_no_audio)
		mpv_set_option_string(dvd_mpv, "audio", "no");

	// start mpv
	mpv_initialize(dvd_mpv);
	mpv_command(dvd_mpv, dvd_mpv_commands);

	while(true) {

		dvd_mpv_event = mpv_wait_event(dvd_mpv, -1);

		// Goodbye :)
		if(dvd_mpv_event->event_id == MPV_EVENT_SHUTDOWN || dvd_mpv_event->event_id == MPV_EVENT_END_FILE)
			break;

		if(debug && dvd_mpv_event->event_id != MPV_EVENT_LOG_MESSAGE)
			printf("dvd_player [mpv_event_name]: %s\n", mpv_event_name(dvd_mpv_event->event_id));

		// Logging output
		if((verbose || debug) && dvd_mpv_event->event_id == MPV_EVENT_LOG_MESSAGE) {
			dvd_mpv_log_message = (struct mpv_event_log_message *)dvd_mpv_event->data;
			printf("mpv [%s]: %s", dvd_mpv_log_message->level, dvd_mpv_log_message->text);
		}

	}

	mpv_terminate_destroy(dvd_mpv);

	DVDCloseFile(dvdread_vts_file);

	if(vts_ifo)
		ifoClose(vts_ifo);
	
	if(vmg_ifo)
		ifoClose(vmg_ifo);

	if(dvdread_dvd)
		DVDClose(dvdread_dvd);
	
	return 0;

}
Exemple #19
0
/*!
 ******************************************************************************
 * \brief
 *		Open video file.
 *
 *		This functions opens a video file and parses some basic file
 *		information.
 *
 * \param fileName
 *		Name of file to open
 *
 * \return
 *		TRUE if file could be opened and is in valid format!
 *
 ******************************************************************************
 */
BOOL AUDSimpleOpen( char* fileName )
{
//	u32 fileOffset = 0;
//	u32 headSize;
//	u32 audioInfoSize;
	
	if( audio_player.open )
	{
#		ifdef _DEBUG
		OSReport( "*** Cannot open '%s' because audio_player already open.\n", fileName );
#		endif
		return FALSE;
	}

	// Initialise the callback status.
	audio_player.asyncOpenCallbackStatus = 0;
	
	s32 entry_num = DVDConvertPathToEntrynum( fileName );
	if( entry_num == -1 )
	{
#		ifdef _DEBUG
		OSReport( "*** Cannot find '%s'\n", filename );
#		endif
		return FALSE;
	}
	if( DVDFastOpen( entry_num, &audio_player.fileHandle ) == FALSE )
	{
#		ifdef _DEBUG
		OSReport( "*** Cannot open: '%s'\n", fileName );
#		endif
		return FALSE;
	}
		
	// Set callback status to indicate file is now open.
	audio_player.asyncOpenCallbackStatus = 1;
	
	// Read 'VID1' chunk from file and check for correct version.
//	if( DVDRead( &audio_player.fileHandle, &workChunk, 32, 0 ) < 0 )
	if( DVDReadAsync( &audio_player.fileHandle, &workChunk, 32, 0, AUDSimpleOpenDVDCallback ) < 0 )
	{
#		ifdef _DEBUG
		OSReport( "*** Failed to read the header for %s.\n", fileName );
#		endif
		DVDClose( &audio_player.fileHandle );
		return FALSE;
	}

	strncpy( audio_player.fileName, fileName, 64 );
	audio_player.fileName[63]				= 0;

	// Nothing more to do here.
	return TRUE;
		
//	fileOffset += 32;
	
	// Check file id	
//	if( workChunk.id != VID_FCC('V','I','D','1' ))
//	{
//#		ifdef _DEBUG
//		OSReport("*** No VID1 file: '%s'\n", fileName);
//#		endif
//		DVDClose( &audio_player.fileHandle );
//		return FALSE;
//	}
	
	// Check for correct version of vid chunk.
	// If we find this version we assume a 'special' alignment and chunk ordering which may be invalid
	// in another version of the file format.
//	if( workChunk.vid.versionMajor != 1 || workChunk.vid.versionMinor != 0 )
//	{
//#		ifdef _DEBUG
//		OSReport("*** Unsupported file version: major: %d, minor: %d\n", workChunk.vid.versionMajor, workChunk.vid.versionMajor);
//#		endif
//		DVDClose(&audio_player.fileHandle);
//		return FALSE;
//	}
	
//#	ifdef _DEBUG
	// Sometimes, it's required to check for a special build of the VidConv converter.
//	{
//		u32 version = VID_VERSION(workChunk.vid.vidConvMajor, workChunk.vid.vidConvMinor, workChunk.vid.vidConvBuild);
//		if(version < VID_VERSION(1,0,1))
//		OSReport("*** WARNING: Vid file created using an unsupported converter version: %d.%d.%d\n", (u32)workChunk.vid.vidConvMajor, (u32)workChunk.vid.vidConvMinor, (u32)workChunk.vid.vidConvBuild);
//	}
//#	endif

	// Check types of chunks we have in this file.
	// !!! Note that we assume start of 'HEAD' chunk at byte offset 32 from file start !!!
//	if( DVDRead( &audio_player.fileHandle, &workChunk, 32, (s32)fileOffset ) < 0 )
//	{
//#		ifdef _DEBUG
//		OSReport("*** Failed to read 'HEAD' chunk.\n");
//#		endif
//		DVDClose( &audio_player.fileHandle );
//		return FALSE;
//	}
	
//	if( workChunk.id != VID_FCC('H','E','A','D' ))
//	{
//#		ifdef _DEBUG
//		OSReport("*** No HEAD chunk found at expected offset\n");
//#		endif
//		DVDClose(&audio_player.fileHandle);
//		return FALSE;
//	}
	
	// Calculate the start of the first frame chunk
	// (we know the header chunk starts at offset 32)
//	audio_player.nextFrameOffset = workChunk.len + 32;

	// Skip 'HEAD' chunk id, len and version fields
//	fileOffset += VID_CHUNK_HEADER_SIZE;
	
	// The header chunk contains one or more header chunks for the different data types contained
	// in the stream. Parse them all...
//	headSize = workChunk.len - VID_CHUNK_HEADER_SIZE;
//	while( headSize >= 32 )
//	{
//		if( DVDRead( &audio_player.fileHandle, &workChunk, 32, (s32)fileOffset ) < 0 )
//		{
//#			ifdef _DEBUG
//			OSReport("*** Error reading file at offset %d\n", fileOffset);
//#			endif
//			DVDClose(&audio_player.fileHandle);
//			return FALSE;
//		}
		
//		fileOffset += 32;
//		headSize -= 32;

		// We analyze the 1st 32 bytes of the chunk for a known header format
//		if(workChunk.id == VID_FCC('A','U','D','H'))
//		{
			// Allocate memory for audio header chunk
//			audio_player.audioHeaderChunk = (u8*)((*audio_player.cbAlloc)(workChunk.len));
//			audioInfoSize = workChunk.len - VID_CHUNK_HEADER_SIZE;
			
			// Copy the already loaded part
//			memcpy(audio_player.audioHeaderChunk, &workChunk, 32);
//			workChunk.len -= 32;
			
			// Read additional audio header bytes if the audio header is greater that 32 bytes
//			if(workChunk.len >= 32)
//			{
//				ASSERT((workChunk.len&31)==0);
//				if( DVDRead( &audio_player.fileHandle, audio_player.audioHeaderChunk + 32, workChunk.len, (s32)fileOffset ) < 0 )
//				{
//#					ifdef _DEBUG
//					OSReport("*** Error reading file at offset %d\n", fileOffset);
//#					endif
//					DVDClose(&audio_player.fileHandle);
//					return FALSE;
//				}
//				fileOffset += workChunk.len;
//				headSize -= workChunk.len;
//			}

			// Setup and calc the number of bytes which we are allowed to copy into the audioInfo struct
//			memcpy(&audio_player.audioInfo, audio_player.audioHeaderChunk+VID_CHUNK_HEADER_SIZE, MIN(audioInfoSize, sizeof(audio_player.audioInfo)));
//		}
//		else
//		{
//			// Skip unknown chunks. We already read 32 bytes for the header which we must subtract here.
//			fileOffset += workChunk.len - 32;
///			headSize -= workChunk.len - 32;
//		}
//	}
	
	// check if we have the correct vaud file version (>0)
//	if(audio_player.audioInfo.vaudex.version == 0)
//	{
//#		ifdef _DEBUG
//		OSReport("*** Invalid version in vaud file.");
//#		endif
//		DVDClose(&audio_player.fileHandle);
//		return FALSE;
//	}

	// we can only play audio files which have the following fiels set.
	// Note that in case of VIDEO files this fields are allowed to be 0.
//	ASSERT(audio_player.audioInfo.vaudex.maxBufferSize > 0);
//	ASSERT(audio_player.audioInfo.vaudex.frameCount > 0);
//	ASSERT(audio_player.audioInfo.vaudex.frameTimeMs > 0);
	
	// read beginning of 1st frame chunk to get required size information
//	if( DVDRead( &audio_player.fileHandle, &workChunk, 32 , (s32)audio_player.nextFrameOffset ) < 0 )
//	{
//#		ifdef _DEBUG
//		OSReport("*** Failed to read 'FRAM' chunk.\n");
//#		endif
//		DVDClose(&audio_player.fileHandle);
//		return FALSE;
//	}

//	if( workChunk.id != VID_FCC('F','R','A','M') )
//	{
//#		ifdef _DEBUG
//		OSReport("*** No FRAM chunk found.");
//#		endif
//		DVDClose(&audio_player.fileHandle);
//		return FALSE;
//	}

//	audio_player.nextFrameSize = workChunk.len; 		// 32 bytes of this chunk are already consumed, but we want to 'preload' the NEXT chunk's FRAM header
//	audio_player.nextFrameOffset += 32;
	
//	audio_player.firstFrameOffset = audio_player.nextFrameOffset;
//	audio_player.firstFrameSize   = audio_player.nextFrameSize;

//	strncpy(audio_player.fileName, fileName, 64);
//	audio_player.fileName[63] = 0;
	
//	audio_player.open 			 	= TRUE;

//	audio_player.readIndex 			= 0;
//	audio_player.decodeIndex 			= 0;
//	audio_player.lastDecodedFrame		= 0;
//	audio_player.error 			 	= FALSE;
//	audio_player.preFetchState 	 	= FALSE;
//	audio_player.loopMode			 	= FALSE;
//	audio_player.asyncDvdRunning		= FALSE;
//	audio_player.currentFrameCount 	= 0;
//	audio_player.readBufferBaseMem	= 0;

//	return TRUE;
} 	
Exemple #20
0
bool DVDStream::OpenFile(const QString &filename, uint /*retry_ms*/)
{
    rwlock.lockForWrite();

    const QString root = filename.section("/VIDEO_TS/", 0, 0);
    const QString path = filename.section(root, 1);

    if (m_reader)
        DVDClose(m_reader);

    m_reader = DVDOpen(qPrintable(root));
    if (!m_reader)
    {
        LOG(VB_GENERAL, LOG_ERR, QString("DVDStream DVDOpen(%1) failed").arg(filename));
        rwlock.unlock();
        return false;
    }

    if (!path.isEmpty())
    {
        // Locate the start block of the requested title
        uint32_t len;
        m_start = UDFFindFile(m_reader, const_cast<char*>(qPrintable(path)), &len);
        if (m_start == 0)
        {
            LOG(VB_GENERAL, LOG_ERR, QString("DVDStream(%1) UDFFindFile(%2) failed").
                arg(root).arg(path));
            DVDClose(m_reader);
            m_reader = 0;
            rwlock.unlock();
            return false;
        }
        else
        {
            m_list.append(BlockRange(0, Len2Blocks(len), 0));
        }
    }
    else
    {
        // Create a list of the possibly encrypted files
        uint32_t len, start;

        // Root menu
        char name[64] = "VIDEO_TS/VIDEO_TS.VOB";
        start = UDFFindFile(m_reader, name, &len);
        if( start != 0 && len != 0 )
            m_list.append(BlockRange(start, Len2Blocks(len), 0));

        const int kTitles = 100;
        for ( int title = 1; title < kTitles; ++title)
        {
            // Menu
            snprintf(name, sizeof name, "/VIDEO_TS/VTS_%02d_0.VOB", title);
            start = UDFFindFile(m_reader, name, &len);
            if( start != 0 && len != 0 )
                m_list.append(BlockRange(start, Len2Blocks(len), title));

            for ( int part = 1; part < 10; ++part)
            {
                // A/V track
                snprintf(name, sizeof name, "/VIDEO_TS/VTS_%02d_%d.VOB", title, part);
                start = UDFFindFile(m_reader, name, &len);
                if( start != 0 && len != 0 )
                    m_list.append(BlockRange(start, Len2Blocks(len), title + part * kTitles));
            }
        }

        qSort( m_list);

        // Open the root menu so that CSS keys are generated now
        dvd_file_t *file = DVDOpenFile(m_reader, 0, DVD_READ_MENU_VOBS);
        if (file)
            DVDCloseFile(file);
        else
            LOG(VB_GENERAL, LOG_ERR, "DVDStream DVDOpenFile(VOBS_1) failed");
    }

    rwlock.unlock();
    return true;
}
Exemple #21
0
title_set_info_t *
DVDGetFileSet(char *dvd)
{
	/*
	 * TODO  Fix close of files if
	 *	we error out
	 *	We also assume that all
	 *	DVD files are of valid
	 *	size i.e. file%2048 == 0
	 */

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

	/* DVD file structures */
	dvd_reader_t *	_dvd = NULL;

	ifo_handle_t *	vmg_ifo = NULL;
	ifo_handle_t *	vts_ifo = NULL;

	dvd_file_t   *	vmg_vob_file = NULL;
	dvd_file_t   *	vmg_ifo_file = NULL;

	dvd_file_t   *	vts_ifo_file = NULL;
	dvd_file_t   *	vts_menu_file = NULL;
	dvd_file_t   * 	vts_title_file = NULL;

	/* The sizes it self of each file */
	int		ifo;
	int		bup;
	int		menu_vob;
	int		title_vob;

	/* Arrays keeping the title - filset relationship */
	int		* sector;
	int		* title;
	int		* title_sets_array;
	int		* sector_sets_array;

	/* DVD Video files */
	struct stat	fileinfo;
	char		temppoint[PATH_MAX + 1];

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

	/* Temporary mount point - to be used later */
	char		mountpoint[PATH_MAX + 1];

	strncpy(mountpoint, dvd, sizeof (mountpoint));
	mountpoint[sizeof (mountpoint)-1] = '\0';


	_dvd = DVDOpen(dvd);
	if (!_dvd) {
#ifdef	USE_LIBSCHILY
		errmsgno(EX_BAD, "Can't open device '%s'\n", dvd);
#else
		fprintf(stderr, "Can't open device\n");
#endif
		return (0);
	}
	vmg_ifo = ifoOpen(_dvd, 0);
	if (!vmg_ifo) {
#ifdef	USE_LIBSCHILY
		errmsgno(EX_BAD, "Can't open VMG info for '%s'.\n", dvd);
#else
		fprintf(stderr, "Can't open VMG info.\n");
#endif
		return (0);
	}

	/* Check mount point */

	snprintf(temppoint, sizeof (temppoint),
				"%s/VIDEO_TS/VIDEO_TS.IFO", mountpoint);


	if (stat(temppoint, &fileinfo) < 0) {
		/* If we can't stat the file, give up */
#ifdef	USE_LIBSCHILY
		errmsg("Can't stat %s\n", temppoint);
#else
		fprintf(stderr, "Can't stat %s\n", temppoint);
		perror("");
#endif
		return (0);
	}



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

	sector = e_malloc(titles * sizeof (int));
	memset(sector, 0, titles * sizeof (int));
	title = e_malloc(titles * sizeof (int));
	title_sets_array = e_malloc(title_sets * sizeof (int));
	sector_sets_array = e_malloc(title_sets * sizeof (int));
	title_set_info = (title_set_info_t *)e_malloc(sizeof (title_set_info_t));
	title_set_info->title_set = (title_set_t *)e_malloc((title_sets + 1) *
							sizeof (title_set_t));

	title_set_info->num_titles = title_sets;


	/* Fill and sort the arrays for titles*/

	if (titles >= 1) {
		for (counter = 0; counter < titles; counter++) {
			sector[counter] = vmg_ifo->tt_srpt->title[counter].title_set_sector;
			title[counter]  = counter + 1;
		}
	}

	/* Yes, we should probably do a better sort than B - but what the heck*/
	bsort(sector, title, titles);


	/*
	 * Since title sets and titles are not the same we will need to sort
	 * out "bogus" titles
	 */

	uniq(sector, title, title_sets_array, sector_sets_array, titles);


	/* Open VIDEO_TS.VOB is present */

	vmg_vob_file = DVDOpenFile(_dvd, 0, DVD_READ_MENU_VOBS);

	/* Check VIDEO_TS title set */

	vmg_ifo_file = DVDOpenFile(_dvd, 0, DVD_READ_INFO_FILE);

	if ((vmg_vob_file == 0) && vmg_ifo->vmgi_mat->vmg_last_sector + 1
			< 2 * DVDFileSize(vmg_ifo_file)) {
#ifdef	USE_LIBSCHILY
		errmsgno(EX_BAD, "IFO is not of correct size aborting\n");
#else
		fprintf(stderr, "IFO is not of correct size aborting\n");
#endif
		DVDFreeFileSetArrays(sector, title, title_sets_array,
					sector_sets_array);
		DVDFreeFileSet(title_set_info);
		return (0);
	} else if ((vmg_vob_file != 0) && (vmg_ifo->vmgi_mat->vmg_last_sector
		    + 1  < 2 * DVDFileSize(vmg_ifo_file) +
		    DVDFileSize(vmg_vob_file))) {
#ifdef	USE_LIBSCHILY
		errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
#else
		fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
#endif
		DVDFreeFileSetArrays(sector, title, title_sets_array,
					sector_sets_array);
		DVDFreeFileSet(title_set_info);
		return (0);
	}

	/* Find the actuall right size of VIDEO_TS.IFO */
	if (vmg_vob_file == 0) {
		if (vmg_ifo->vmgi_mat->vmg_last_sector + 1 > 2
				*  DVDFileSize(vmg_ifo_file)) {
			ifo = vmg_ifo->vmgi_mat->vmg_last_sector
				- DVDFileSize(vmg_ifo_file) + 1;
		} else {
			ifo = vmg_ifo->vmgi_mat->vmgi_last_sector + 1;
		}
	} else {
		if (vmg_ifo->vmgi_mat->vmgi_last_sector + 1
				< vmg_ifo->vmgi_mat->vmgm_vobs) {
			ifo = vmg_ifo->vmgi_mat->vmgm_vobs;
		} else {
			ifo = vmg_ifo->vmgi_mat->vmgi_last_sector + 1;
		}
	}

	title_set_info->title_set[0].size_ifo = ifo * 2048;
	title_set_info->title_set[0].realsize_ifo = fileinfo.st_size;
	title_set_info->title_set[0].pad_ifo = ifo - DVDFileSize(vmg_ifo_file);

	/* Find the actuall right size of VIDEO_TS.VOB */
	if (vmg_vob_file != 0) {
		if (ifo + DVDFileSize(vmg_ifo_file) +
		    DVDFileSize(vmg_vob_file) - 1 <
		    vmg_ifo->vmgi_mat->vmg_last_sector) {
				menu_vob = vmg_ifo->vmgi_mat->vmg_last_sector -
						ifo - DVDFileSize(vmg_ifo_file) + 1;
		} else {
			menu_vob = vmg_ifo->vmgi_mat->vmg_last_sector
			- ifo - DVDFileSize(vmg_ifo_file) + 1;
		}

		snprintf(temppoint, sizeof (temppoint),
				"%s/VIDEO_TS/VIDEO_TS.VOB", mountpoint);
		if (stat(temppoint, &fileinfo) < 0) {
#ifdef	USE_LIBSCHILY
			errmsg("calc: Can't stat %s\n", temppoint);
#else
			fprintf(stderr, "calc: Can't stat %s\n", temppoint);
			perror("");
#endif
			DVDFreeFileSetArrays(sector, title, title_sets_array,
						sector_sets_array);
			DVDFreeFileSet(title_set_info);
			return (0);
		}

		title_set_info->title_set[0].realsize_menu = fileinfo.st_size;
		title_set_info->title_set[0].pad_menu = menu_vob -
						DVDFileSize(vmg_vob_file);
		title_set_info->title_set[0].size_menu = menu_vob * 2048;
		DVDCloseFile(vmg_vob_file);
	} else {
		title_set_info->title_set[0].size_menu = 0;
		title_set_info->title_set[0].realsize_menu = 0;
		title_set_info->title_set[0].pad_menu = 0;
		menu_vob = 0;
	}


	/* Finding the actuall right size of VIDEO_TS.BUP */
	if (title_sets >= 1) {
		bup = sector_sets_array[0] - menu_vob - ifo;
	} else {
		/* Just in case we burn a DVD-Video without any title_sets */
		bup = vmg_ifo->vmgi_mat->vmg_last_sector + 1 - menu_vob - ifo;
	}

	/* Never trust the BUP file - use a copy of the IFO */
	snprintf(temppoint, sizeof (temppoint),
				"%s/VIDEO_TS/VIDEO_TS.IFO", mountpoint);

	if (stat(temppoint, &fileinfo) < 0) {
#ifdef	USE_LIBSCHILY
		errmsg("calc: Can't stat %s\n", temppoint);
#else
		fprintf(stderr, "calc: Can't stat %s\n", temppoint);
		perror("");
#endif
		DVDFreeFileSetArrays(sector, title, title_sets_array,
					sector_sets_array);
		DVDFreeFileSet(title_set_info);
		return (0);
	}

	title_set_info->title_set[0].realsize_bup = fileinfo.st_size;
	title_set_info->title_set[0].size_bup = bup * 2048;
	title_set_info->title_set[0].pad_bup = bup - DVDFileSize(vmg_ifo_file);

	/* 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].realsize_vob[0] = 0;
	title_set_info->title_set[0].pad_title = 0;

	DVDCloseFile(vmg_ifo_file);

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

			vts_ifo = ifoOpen(_dvd, counter + 1);

			if (!vts_ifo) {
#ifdef	USE_LIBSCHILY
				errmsgno(EX_BAD, "Can't open VTS info.\n");
#else
				fprintf(stderr, "Can't open VTS info.\n");
#endif
				DVDFreeFileSetArrays(sector, title,
					title_sets_array, sector_sets_array);
				DVDFreeFileSet(title_set_info);
				return (0);
			}

			snprintf(temppoint, sizeof (temppoint),
				"%s/VIDEO_TS/VTS_%02i_0.IFO",
				mountpoint, counter + 1);

			if (stat(temppoint, &fileinfo) < 0) {
#ifdef	USE_LIBSCHILY
				errmsg("calc: Can't stat %s\n", temppoint);
#else
				fprintf(stderr, "calc: Can't stat %s\n",
					temppoint);
				perror("");
#endif
				DVDFreeFileSetArrays(sector, title,
					title_sets_array, sector_sets_array);
				DVDFreeFileSet(title_set_info);
				return (0);
			}


			/* Test if VTS_XX_0.VOB is present */

			vts_menu_file = DVDOpenFile(_dvd, counter + 1,
					DVD_READ_MENU_VOBS);

			/* Test if VTS_XX_X.VOB are present */

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

			/* Check VIDEO_TS.IFO */

			vts_ifo_file = DVDOpenFile(_dvd, counter + 1,
							DVD_READ_INFO_FILE);

			/*
			 * Checking that title will fit in the
			 * space given by the ifo file
			 */


			if (vts_ifo->vtsi_mat->vts_last_sector + 1
				< 2 * DVDFileSize(vts_ifo_file)) {
#ifdef	USE_LIBSCHILY
				errmsgno(EX_BAD, "IFO is not of correct size aborting.\n");
#else
				fprintf(stderr, "IFO is not of correct size aborting\n");
#endif
				DVDFreeFileSetArrays(sector, title,
					title_sets_array, sector_sets_array);
				DVDFreeFileSet(title_set_info);
				return (0);
			} else if ((vts_title_file != 0) &&
				    (vts_menu_file != 0) &&
				    (vts_ifo->vtsi_mat->vts_last_sector + 1
				    < 2 * DVDFileSize(vts_ifo_file) +
				    DVDFileSize(vts_title_file) +
				    DVDFileSize(vts_menu_file))) {
#ifdef	USE_LIBSCHILY
				errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size.\n");
#else
				fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
#endif
				DVDFreeFileSetArrays(sector, title,
					title_sets_array, sector_sets_array);
				DVDFreeFileSet(title_set_info);
				return (0);
			} else if ((vts_title_file != 0) &&
				    (vts_menu_file == 0) &&
				    (vts_ifo->vtsi_mat->vts_last_sector + 1
				    < 2 * DVDFileSize(vts_ifo_file) +
				    DVDFileSize(vts_title_file))) {
#ifdef	USE_LIBSCHILY
				errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size.\n");
#else
				fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
#endif
				DVDFreeFileSetArrays(sector, title,
					title_sets_array, sector_sets_array);
				DVDFreeFileSet(title_set_info);
				return (0);
			} else if ((vts_menu_file != 0) &&
				    (vts_title_file == 0) &&
				    (vts_ifo->vtsi_mat->vts_last_sector + 1
				    < 2 * DVDFileSize(vts_ifo_file) +
				    DVDFileSize(vts_menu_file))) {
#ifdef	USE_LIBSCHILY
				errmsgno(EX_BAD, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size.\n");
#else
				fprintf(stderr, "Either VIDEO_TS.IFO or VIDEO_TS.VOB is not of correct size");
#endif
				DVDFreeFileSetArrays(sector, title,
					title_sets_array, sector_sets_array);
				DVDFreeFileSet(title_set_info);
				return (0);
			}


			/* Find the actuall right size of VTS_XX_0.IFO */
			if ((vts_title_file == 0) && (vts_menu_file == 0)) {
				if (vts_ifo->vtsi_mat->vts_last_sector + 1 >
				    2 * DVDFileSize(vts_ifo_file)) {
					ifo = vts_ifo->vtsi_mat->vts_last_sector
						- DVDFileSize(vts_ifo_file) + 1;
				} else {
					ifo = vts_ifo->vtsi_mat->vts_last_sector
						- DVDFileSize(vts_ifo_file) + 1;
				}
			} else if (vts_title_file == 0) {
				if (vts_ifo->vtsi_mat->vtsi_last_sector + 1 <
				    vts_ifo->vtsi_mat->vtstt_vobs) {
					ifo = vmg_ifo->vtsi_mat->vtstt_vobs;
				} else {
					ifo = vmg_ifo->vtsi_mat->vtstt_vobs;
				}
			} else {
				if (vts_ifo->vtsi_mat->vtsi_last_sector + 1 <
				    vts_ifo->vtsi_mat->vtsm_vobs) {
					ifo = vts_ifo->vtsi_mat->vtsm_vobs;
				} else {
					ifo = vts_ifo->vtsi_mat->vtsi_last_sector + 1;
				}
			}
			title_set_info->title_set[counter + 1].size_ifo =
						ifo * 2048;
			title_set_info->title_set[counter + 1].realsize_ifo =
						fileinfo.st_size;
			title_set_info->title_set[counter + 1].pad_ifo =
						ifo - DVDFileSize(vts_ifo_file);


			/* Find the actuall right size of VTS_XX_0.VOB */
			if (vts_menu_file != 0) {
				if (vts_ifo->vtsi_mat->vtsm_vobs == 0)  {
					/*
					 * Apparently start sector 0 means that
					 * VTS_XX_0.VOB is empty after all...
					 */
					menu_vob = 0;
					if (DVDFileSize(vts_menu_file) != 0) {
						/*
						 * Paranoia: we most likely never
						 * come here...
						 */
#ifdef	USE_LIBSCHILY
						errmsgno(EX_BAD,
							"%s/VIDEO_TS/VTS_%02i_0.IFO appears to be corrupted.\n",
							mountpoint, counter+1);
#else
						fprintf(stderr,
							"%s/VIDEO_TS/VTS_%02i_0.IFO appears to be corrupted.\n",
							mountpoint, counter+1);
#endif
						return (0);
					}
				} else if ((vts_title_file != 0) &&
					(vts_ifo->vtsi_mat->vtstt_vobs -
					vts_ifo->vtsi_mat->vtsm_vobs >
						DVDFileSize(vts_menu_file))) {
					menu_vob = vts_ifo->vtsi_mat->vtstt_vobs -
							vts_ifo->vtsi_mat->vtsm_vobs;
				} else if ((vts_title_file == 0) &&
					    (vts_ifo->vtsi_mat->vtsm_vobs +
					    DVDFileSize(vts_menu_file) +
					    DVDFileSize(vts_ifo_file) - 1 <
					    vts_ifo->vtsi_mat->vts_last_sector)) {
					menu_vob = vts_ifo->vtsi_mat->vts_last_sector
						- DVDFileSize(vts_ifo_file)
						- vts_ifo->vtsi_mat->vtsm_vobs + 1;
				} else {
					menu_vob = vts_ifo->vtsi_mat->vtstt_vobs -
							vts_ifo->vtsi_mat->vtsm_vobs;
				}

				snprintf(temppoint, sizeof (temppoint),
					"%s/VIDEO_TS/VTS_%02i_0.VOB", mountpoint, counter + 1);

				if (stat(temppoint, &fileinfo)  < 0) {
#ifdef	USE_LIBSCHILY
					errmsg("calc: Can't stat %s\n", temppoint);
#else
					fprintf(stderr, "calc: Can't stat %s\n",
						temppoint);
					perror("");
#endif
					DVDFreeFileSetArrays(sector, title,
						title_sets_array, sector_sets_array);
					DVDFreeFileSet(title_set_info);
					return (0);
				}

				title_set_info->title_set[counter + 1].realsize_menu = fileinfo.st_size;
				title_set_info->title_set[counter + 1].size_menu = menu_vob * 2048;
				title_set_info->title_set[counter + 1].pad_menu = menu_vob - DVDFileSize(vts_menu_file);

			} else {
				title_set_info->title_set[counter + 1].size_menu = 0;
				title_set_info->title_set[counter + 1].realsize_menu = 0;
				title_set_info->title_set[counter + 1].pad_menu = 0;
				menu_vob = 0;
			}


			/* Find the actuall total size of VTS_XX_[1 to 9].VOB */

			if (vts_title_file != 0) {
				if (ifo + menu_vob + DVDFileSize(vts_ifo_file) -
				    1 < vts_ifo->vtsi_mat->vts_last_sector) {
				    title_vob = vts_ifo->vtsi_mat->vts_last_sector
						+ 1 - ifo - menu_vob -
						DVDFileSize(vts_ifo_file);
				} else {
					title_vob = vts_ifo->vtsi_mat->vts_last_sector +
						1 - ifo - menu_vob -
						DVDFileSize(vts_ifo_file);
				}
				/*
				 * Find out how many vob files
				 * and the size of them
				 */
				for (i = 0; i < 9; ++i) {
					snprintf(temppoint, sizeof (temppoint),
						"%s/VIDEO_TS/VTS_%02i_%i.VOB",
						mountpoint, counter + 1, i + 1);
					if (stat(temppoint, &fileinfo) < 0) {
						break;
					}
					title_set_info->title_set[counter + 1].realsize_vob[i] = fileinfo.st_size;
				}
				title_set_info->title_set[counter + 1].number_of_vob_files = i;
				title_set_info->title_set[counter + 1].size_title = title_vob * 2048;
				title_set_info->title_set[counter + 1].pad_title = title_vob - DVDFileSize(vts_title_file);
			} else {
				title_set_info->title_set[counter + 1].number_of_vob_files = 0;
				title_set_info->title_set[counter + 1].realsize_vob[0] = 0;
				title_set_info->title_set[counter + 1].size_title = 0;
				title_set_info->title_set[counter + 1].pad_title = 0;
				title_vob = 0;

			}


			/* Find the actuall total size of VTS_XX_0.BUP */
			if (title_sets - 1 > counter) {
				bup = sector_sets_array[counter+1]
					- sector_sets_array[counter]
					- title_vob - menu_vob - ifo;
			} else {
				bup = vts_ifo->vtsi_mat->vts_last_sector + 1
					- title_vob - menu_vob - ifo;
			}

			/* Never trust the BUP use a copy of the IFO */
			snprintf(temppoint, sizeof (temppoint),
				"%s/VIDEO_TS/VTS_%02i_0.IFO",
				mountpoint, counter + 1);

			if (stat(temppoint, &fileinfo) < 0) {
#ifdef	USE_LIBSCHILY
				errmsg("calc: Can't stat %s\n", temppoint);
#else
				fprintf(stderr, "calc: Can't stat %s\n",
					temppoint);
				perror("");
#endif
				DVDFreeFileSetArrays(sector, title,
					title_sets_array, sector_sets_array);
				DVDFreeFileSet(title_set_info);
				return (0);
			}

			title_set_info->title_set[counter + 1].size_bup =
						bup * 2048;
			title_set_info->title_set[counter + 1].realsize_bup =
						fileinfo.st_size;
			title_set_info->title_set[counter + 1].pad_bup =
						bup - DVDFileSize(vts_ifo_file);


			/* Closing files */

			if (vts_menu_file != 0) {
				DVDCloseFile(vts_menu_file);
			}

			if (vts_title_file != 0) {
				DVDCloseFile(vts_title_file);
			}


			if (vts_ifo_file != 0) {
				DVDCloseFile(vts_ifo_file);
			}

			ifoClose(vts_ifo);

		}

	}

	DVDFreeFileSetArrays(sector, title, title_sets_array, sector_sets_array);

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


	/* Close the DVD */
	DVDClose(_dvd);

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


}
Exemple #22
0
static int open_s(stream_t *stream)
{
  int k;
  dvd_priv_t *d = stream->priv;

  d->dvd_angle = stream->opts->dvd_angle;

  MP_VERBOSE(stream, "URL: %s\n", stream->url);
  d->dvd_title = d->cfg_title + 1;
  if(1){
    //int ret,ret2;
    int ttn,pgc_id,pgn;
    dvd_reader_t *dvd;
    dvd_file_t *title;
    ifo_handle_t *vmg_file;
    tt_srpt_t *tt_srpt;
    ifo_handle_t *vts_file;
    pgc_t *pgc;
    /**
     * Open the disc.
     */
    if(d->cfg_device && d->cfg_device[0])
      d->dvd_device_current = d->cfg_device;
    else if(stream->opts->dvd_device && stream->opts->dvd_device[0])
      d->dvd_device_current = talloc_strdup(stream, stream->opts->dvd_device);
    else
      d->dvd_device_current = DEFAULT_DVD_DEVICE;
    d->dvd_speed = stream->opts->dvd_speed;
    dvd_set_speed(stream,d->dvd_device_current, d->dvd_speed);
#if defined(__APPLE__) || defined(__DARWIN__)
    /* Dynamic DVD drive selection on Darwin */
    if(!strcmp(d->dvd_device_current, "/dev/rdiskN")) {
      int i;
      size_t len = strlen(d->dvd_device_current)+1;
      char *temp_device = malloc(len);

      for (i = 1; i < 10; i++) {
        snprintf(temp_device, len, "/dev/rdisk%d", i);
        dvd = DVDOpen(temp_device);
        if(!dvd) {
          MP_ERR(stream, "Couldn't open DVD device: %s (%s)\n",temp_device, strerror(errno));
        } else {
#if DVDREAD_VERSION <= LIBDVDREAD_VERSION(0,9,4)
          dvd_file_t *dvdfile = DVDOpenFile(dvd,d->dvd_title,DVD_READ_INFO_FILE);
          if(!dvdfile) {
            MP_ERR(stream, "Couldn't open DVD device: %s (%s)\n",temp_device, strerror(errno));
            DVDClose(dvd);
            continue;
          }
          DVDCloseFile(dvdfile);
#endif
          break;
        }
      }
      free(temp_device);

      if(!dvd) {
        return STREAM_UNSUPPORTED;
      }
    } else
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
    {
        dvd = DVDOpen(d->dvd_device_current);
        if(!dvd) {
          MP_ERR(stream, "Couldn't open DVD device: %s (%s)\n",d->dvd_device_current, strerror(errno));
          return STREAM_UNSUPPORTED;
        }
    }

    MP_VERBOSE(stream, "Reading disc structure, please wait...\n");

    /**
     * Load the video manager to find out the information about the titles on
     * this disc.
     */
    vmg_file = ifoOpen(dvd, 0);
    if(!vmg_file) {
      MP_ERR(stream, "Can't open VMG info!\n");
      DVDClose( dvd );
      return STREAM_UNSUPPORTED;
    }
    tt_srpt = vmg_file->tt_srpt;
    /**
     * Make sure our title number is valid.
     */
    MP_INFO(stream, "There are %d titles on this DVD.\n", tt_srpt->nr_of_srpts );
    if(d->dvd_title < 1 || d->dvd_title > tt_srpt->nr_of_srpts) {
      MP_ERR(stream, "Invalid DVD title number: %d\n", d->dvd_title);
      ifoClose( vmg_file );
      DVDClose( dvd );
      return STREAM_UNSUPPORTED;
    }
    --(d->dvd_title); // remap 1.. -> 0..
    /**
     * Make sure the angle number is valid for this title.
     */
    MP_INFO(stream, "There are %d angles in this DVD title.\n", tt_srpt->title[d->dvd_title].nr_of_angles);
    if(d->dvd_angle<1 || d->dvd_angle>tt_srpt->title[d->dvd_title].nr_of_angles) {
      MP_ERR(stream, "Invalid DVD angle number: %d\n", d->dvd_angle);
      goto fail;
    }

    ttn = tt_srpt->title[d->dvd_title].vts_ttn - 1;
    /**
     * Load the VTS information for the title set our title is in.
     */
    vts_file = ifoOpen( dvd, tt_srpt->title[d->dvd_title].title_set_nr );
    if(!vts_file) {
      MP_ERR(stream, "Cannot open the IFO file for DVD title %d.\n", tt_srpt->title[d->dvd_title].title_set_nr );
      goto fail;
    }
    /**
     * We've got enough info, time to open the title set data.
     */
    title = DVDOpenFile(dvd, tt_srpt->title[d->dvd_title].title_set_nr, DVD_READ_TITLE_VOBS);
    if(!title) {
      MP_ERR(stream, "Cannot open title VOBS (VTS_%02d_1.VOB).\n", tt_srpt->title[d->dvd_title].title_set_nr);
      ifoClose( vts_file );
      goto fail;
    }

    MP_VERBOSE(stream, "DVD successfully opened.\n");
    // store data
    d->dvd=dvd;
    d->title=title;
    d->vmg_file=vmg_file;
    d->tt_srpt=tt_srpt;
    d->vts_file=vts_file;
    d->cur_title = d->dvd_title;

    pgc = vts_file->vts_pgcit ? vts_file->vts_pgcit->pgci_srp[ttn].pgc : NULL;
    /**
     * Check number of audio channels and types
     */
    {
      d->nr_of_channels=0;
      if(vts_file->vts_pgcit) {
        int i;
        for(i=0;i<8;i++)
          if(pgc->audio_control[i] & 0x8000) {
            audio_attr_t * audio = &vts_file->vtsi_mat->vts_audio_attr[i];
            int language = 0;
            char tmp[] = "unknown";
            stream_language_t *audio_stream = &d->audio_streams[d->nr_of_channels];

            if(audio->lang_type == 1) {
              language=audio->lang_code;
              tmp[0]=language>>8;
              tmp[1]=language&0xff;
              tmp[2]=0;
            }

            audio_stream->language=language;
            audio_stream->id=pgc->audio_control[i] >> 8 & 7;
            switch(audio->audio_format) {
              case 0: // ac3
                audio_stream->id+=FIRST_AC3_AID;
                break;
              case 6: // dts
                audio_stream->id+=FIRST_DTS_AID;
                break;
              case 2: // mpeg layer 1/2/3
              case 3: // mpeg2 ext
                audio_stream->id+=FIRST_MPG_AID;
                break;
              case 4: // lpcm
                audio_stream->id+=FIRST_PCM_AID;
                break;
           }

           audio_stream->type=audio->audio_format;
           // Pontscho: to my mind, tha channels:
           //  1 - stereo
           //  5 - 5.1
           audio_stream->channels=audio->channels;
           MP_INFO(stream, "audio stream: %d format: %s (%s) language: %s aid: %d.\n",
             d->nr_of_channels,
             dvd_audio_stream_types[ audio->audio_format ],
             dvd_audio_stream_channels[ audio->channels ],
             tmp,
             audio_stream->id
           );

           d->nr_of_channels++;
         }
Exemple #23
0
static void AUDSimpleOpenDVDCallback( s32 result, DVDFileInfo* fileInfo )
{
	static u32	fileOffset		= 0;
	static u32	headSize		= 0;
	static u32	audioInfoSize	= 0;
	
	// Deal with errors, possibly flagged as an indication to shut down immediately.
	if( audio_player.error )
	{
		// Set this back to zero so the player will be regarded as 'free' again.
		audio_player.asyncOpenCallbackStatus = 0;
		return;
	}
	
	switch( audio_player.asyncOpenCallbackStatus )
	{
		case 1:
		{
			// The read of the 'VID1' chunk has completed.
			fileOffset = 32;
	
			// Check file id.
			if( workChunk.id != VID_FCC('V','I','D','1' ))
			{
#				ifdef _DEBUG
				OSReport("*** No VID1 file: '%s'\n", fileName);
#				endif
				DVDClose( &audio_player.fileHandle );
				audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
				return;
			}
	
			// Check for correct version of vid chunk.
			// If we find this version we assume a 'special' alignment and chunk ordering which may be invalid
			// in another version of the file format.
			if( workChunk.vid.versionMajor != 1 || workChunk.vid.versionMinor != 0 )
			{
#				ifdef _DEBUG
				OSReport("*** Unsupported file version: major: %d, minor: %d\n", workChunk.vid.versionMajor, workChunk.vid.versionMajor);
#				endif
				DVDClose( &audio_player.fileHandle );
				audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
				return;
			}
	
#			ifdef _DEBUG
			// Sometimes, it's required to check for a special build of the VidConv converter.
			{
				u32 version = VID_VERSION(workChunk.vid.vidConvMajor, workChunk.vid.vidConvMinor, workChunk.vid.vidConvBuild);
				if( version < VID_VERSION( 1, 0, 1 ))
					OSReport("*** WARNING: Vid file created using an unsupported converter version: %d.%d.%d\n", (u32)workChunk.vid.vidConvMajor, (u32)workChunk.vid.vidConvMinor, (u32)workChunk.vid.vidConvBuild);
			}
#			endif

			// Set callback status to indicate 'VID1' chunk is read.
			audio_player.asyncOpenCallbackStatus = 2;
			
			// Check types of chunks we have in this file.
			// !!! Note that we assume start of 'HEAD' chunk at byte offset 32 from file start !!!
			if( DVDReadAsync( &audio_player.fileHandle, &workChunk, 32, (s32)fileOffset, AUDSimpleOpenDVDCallback ) < 0 )
			{
#				ifdef _DEBUG
				OSReport("*** Failed to read 'HEAD' chunk.\n");
#				endif
				DVDClose( &audio_player.fileHandle );
				audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
				return;
			}
			break;
		}
	
		case 2:
		{
			// The read of the chunk type info has completed.
			if( workChunk.id != VID_FCC('H','E','A','D' ))
			{
#				ifdef _DEBUG
				OSReport("*** No HEAD chunk found at expected offset\n");
#				endif
				DVDClose( &audio_player.fileHandle );
				audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
				return;
			}

			// Calculate the start of the first frame chunk (we know the header chunk starts at offset 32).
			audio_player.nextFrameOffset = workChunk.len + 32;

			// Skip 'HEAD' chunk id, len and version fields.
			fileOffset += VID_CHUNK_HEADER_SIZE;

			// The header chunk contains one or more header chunks for the different data types contained
			// in the stream. Parse them all...

			headSize = workChunk.len - VID_CHUNK_HEADER_SIZE;
			
			audio_player.asyncOpenCallbackStatus = 3;
			if( DVDReadAsync( &audio_player.fileHandle, &workChunk, 32, (s32)fileOffset, AUDSimpleOpenDVDCallback ) < 0 )
			{
#				ifdef _DEBUG
				OSReport("*** Error reading file at offset %d\n", fileOffset);
#				endif
				DVDClose( &audio_player.fileHandle );
				audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
				return;
			}
			break;
		}
	
		case 3:
		{
			fileOffset	+= 32;
			headSize	-= 32;

			// We analyze the 1st 32 bytes of the chunk for a known header format.
			if( workChunk.id == VID_FCC( 'A','U','D','H' ))
			{
				// Allocate memory for audio header chunk.
				audio_player.audioHeaderChunk	= (u8*)((*audio_player.cbAlloc)(workChunk.len));
				audioInfoSize					= workChunk.len - VID_CHUNK_HEADER_SIZE;

				// Copy the already loaded part.
				memcpy( audio_player.audioHeaderChunk, &workChunk, 32 );
				workChunk.len -= 32;

				// Read additional audio header bytes if the audio header is greater that 32 bytes
				if( workChunk.len >= 32 )
				{
					ASSERT(( workChunk.len & 31 ) == 0 );
					audio_player.asyncOpenCallbackStatus = 4;
					if( DVDReadAsync( &audio_player.fileHandle, audio_player.audioHeaderChunk + 32, workChunk.len, (s32)fileOffset, AUDSimpleOpenDVDCallback ) < 0 )
					{
#						ifdef _DEBUG
						OSReport("*** Error reading file at offset %d\n", fileOffset);
#						endif
						DVDClose( &audio_player.fileHandle );
						audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
						return;
					}
				}
				else
				{
					ASSERT( 0 );
				}
			}
			else
			{
				ASSERT( 0 );
			}
			break;
		}
					
		case 4:
		{
			fileOffset	+= workChunk.len;
			headSize	-= workChunk.len;

			// Setup and calc the number of bytes which we are allowed to copy into the audioInfo struct
			memcpy( &audio_player.audioInfo, audio_player.audioHeaderChunk + VID_CHUNK_HEADER_SIZE, MIN( audioInfoSize, sizeof( audio_player.audioInfo )));
			
			// Check if we have the correct vaud file version (>0).
			if( audio_player.audioInfo.vaudex.version == 0 )
			{
#				ifdef _DEBUG
				OSReport("*** Invalid version in vaud file.");
#				endif
				DVDClose( &audio_player.fileHandle );
				audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
				return;
			}

			// We can only play audio files which have the following fields set.
			// Note that in case of VIDEO files this fields are allowed to be 0.
			ASSERT( audio_player.audioInfo.vaudex.maxBufferSize > 0 );
			ASSERT( audio_player.audioInfo.vaudex.frameCount > 0 );
			ASSERT( audio_player.audioInfo.vaudex.frameTimeMs > 0 );

			// Read beginning of 1st frame chunk to get required size information.
			audio_player.asyncOpenCallbackStatus = 5;
			if( DVDReadAsync( &audio_player.fileHandle, &workChunk, 32 , (s32)audio_player.nextFrameOffset, AUDSimpleOpenDVDCallback ) < 0 )
			{
#				ifdef _DEBUG
				OSReport("*** Failed to read 'FRAM' chunk.\n");
#				endif
				DVDClose( &audio_player.fileHandle );
				audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
				return;
			}
			break;
		}
			
		case 5:
		{
			if( workChunk.id != VID_FCC('F','R','A','M') )
			{
#				ifdef _DEBUG
				OSReport("*** No FRAM chunk found.");
#				endif
				audio_player.asyncOpenCallbackStatus = ASYNC_OPEN_FAIL;
				DVDClose( &audio_player.fileHandle );
				return;
			}

			// 32 bytes of this chunk are already consumed, but we want to 'preload' the NEXT chunk's FRAM header.
			audio_player.nextFrameSize				= workChunk.len; 		
			audio_player.nextFrameOffset			+= 32;

			audio_player.firstFrameOffset			= audio_player.nextFrameOffset;
			audio_player.firstFrameSize				= audio_player.nextFrameSize;

//			strncpy( audio_player.fileName, fileName, 64 );
//			audio_player.fileName[63]				= 0;

			audio_player.open 			 			= TRUE;

			audio_player.asyncOpenCallbackStatus	= ASYNC_OPEN_SUCCESS;
			audio_player.readIndex 					= 0;
			audio_player.decodeIndex 				= 0;
			audio_player.lastDecodedFrame			= 0;
			audio_player.error 			 			= FALSE;
			audio_player.preFetchState 	 			= FALSE;
			audio_player.loopMode		 			= FALSE;
			audio_player.asyncDvdRunning			= FALSE;
			audio_player.currentFrameCount 			= 0;
			audio_player.readBufferBaseMem			= 0;
			break;
		}
	
		default:
		{
			ASSERT( 0 );
			break;
		}
	}
}
Exemple #24
0
static int open_s(stream_t *stream,int mode, void* opts, int* file_format) {
  struct stream_priv_s* p = (struct stream_priv_s*)opts;
  int k;

  mp_msg(MSGT_OPEN,MSGL_V,"URL: %s\n", stream->url);
  dvd_title = p->title;
  if(1){
    //int ret,ret2;
    dvd_priv_t *d;
    int ttn,pgc_id,pgn;
    dvd_reader_t *dvd;
    dvd_file_t *title;
    ifo_handle_t *vmg_file;
    tt_srpt_t *tt_srpt;
    ifo_handle_t *vts_file;
    pgc_t *pgc;
    /**
     * Open the disc.
     */
    if(p->device)
      dvd_device_current = p->device;
    else if(dvd_device)
      dvd_device_current = dvd_device;
    else
      dvd_device_current = DEFAULT_DVD_DEVICE;
    dvd_set_speed(dvd_device_current, dvd_speed);
#if defined(__APPLE__) || defined(__DARWIN__)
    /* Dynamic DVD drive selection on Darwin */
    if(!strcmp(dvd_device_current, "/dev/rdiskN")) {
      int i;
      size_t len = strlen(dvd_device_current)+1;
      char *temp_device = malloc(len);

      for (i = 1; i < 10; i++) {
        snprintf(temp_device, len, "/dev/rdisk%d", i);
        dvd = DVDOpen(temp_device);
        if(!dvd) {
          mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,temp_device, strerror(errno));
        } else {
#if DVDREAD_VERSION <= LIBDVDREAD_VERSION(0,9,4)
          dvd_file_t *dvdfile = DVDOpenFile(dvd,dvd_title,DVD_READ_INFO_FILE);
          if(!dvdfile) {
            mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,temp_device, strerror(errno));
            DVDClose(dvd);
            continue;
          }
          DVDCloseFile(dvdfile);
#endif
          break;
        }
      }
      free(temp_device);

      if(!dvd) {
        m_struct_free(&stream_opts,opts);
        return STREAM_UNSUPPORTED;
      }
    } else
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
    {
        dvd = DVDOpen(dvd_device_current);
        if(!dvd) {
          mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,dvd_device_current, strerror(errno));
          m_struct_free(&stream_opts,opts);
          return STREAM_UNSUPPORTED;
        }
    }

    mp_msg(MSGT_OPEN,MSGL_V,"Reading disc structure, please wait...\n");

    /**
     * Load the video manager to find out the information about the titles on
     * this disc.
     */
    vmg_file = ifoOpen(dvd, 0);
    if(!vmg_file) {
      mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoVMG);
      DVDClose( dvd );
      m_struct_free(&stream_opts,opts);
      return STREAM_UNSUPPORTED;
    }
    tt_srpt = vmg_file->tt_srpt;
    if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO))
    {
      int title_no; ///< title number
      mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLES=%d\n", tt_srpt->nr_of_srpts);
      for (title_no = 0; title_no < tt_srpt->nr_of_srpts; title_no++)
      {
        mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLE_%d_CHAPTERS=%d\n", title_no + 1, tt_srpt->title[title_no].nr_of_ptts);
        mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLE_%d_ANGLES=%d\n", title_no + 1, tt_srpt->title[title_no].nr_of_angles);
      }
    }
    if (mp_msg_test(MSGT_IDENTIFY, MSGL_V))
    {
      char volid[32];
      unsigned char discid [16]; ///< disk ID, a 128 bit MD5 sum
      int vts_no;   ///< video title set number
      for (vts_no = 1; vts_no <= vmg_file->vts_atrt->nr_of_vtss; vts_no++)
        mp_describe_titleset(dvd, tt_srpt, vts_no);
      if (DVDDiscID(dvd, discid) >= 0)
      {
        int i;
        mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_DVD_DISC_ID=");
        for (i = 0; i < 16; i ++)
          mp_msg(MSGT_IDENTIFY, MSGL_V, "%02X", discid[i]);
        mp_msg(MSGT_IDENTIFY, MSGL_V, "\n");
      }
      if (DVDUDFVolumeInfo(dvd, volid, sizeof(volid), NULL, 0) >= 0 || DVDISOVolumeInfo(dvd, volid, sizeof(volid), NULL, 0) >= 0)
        mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_DVD_VOLUME_ID=%s\n", volid);
    }
    /**
     * Make sure our title number is valid.
     */
    mp_msg(MSGT_OPEN,MSGL_STATUS, MSGTR_DVDnumTitles, tt_srpt->nr_of_srpts );
    if(dvd_title < 1 || dvd_title > tt_srpt->nr_of_srpts) {
      mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidTitle, dvd_title);
      ifoClose( vmg_file );
      DVDClose( dvd );
      m_struct_free(&stream_opts,opts);
      return STREAM_UNSUPPORTED;
    }
    mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_CURRENT_TITLE=%d\n", dvd_title);
    --dvd_title; // remap 1.. -> 0..
    /**
     * Make sure the angle number is valid for this title.
     */
    mp_msg(MSGT_OPEN,MSGL_STATUS, MSGTR_DVDnumAngles, tt_srpt->title[dvd_title].nr_of_angles);
    if(dvd_angle<1 || dvd_angle>tt_srpt->title[dvd_title].nr_of_angles) {
      mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidAngle, dvd_angle);
      goto fail;
    }
    --dvd_angle; // remap 1.. -> 0..

    ttn = tt_srpt->title[dvd_title].vts_ttn - 1;
    /**
     * Load the VTS information for the title set our title is in.
     */
    vts_file = ifoOpen( dvd, tt_srpt->title[dvd_title].title_set_nr );
    if(!vts_file) {
      mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoIFO, tt_srpt->title[dvd_title].title_set_nr );
      goto fail;
    }
    /**
     * We've got enough info, time to open the title set data.
     */
    title = DVDOpenFile(dvd, tt_srpt->title[dvd_title].title_set_nr, DVD_READ_TITLE_VOBS);
    if(!title) {
      mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoVOBs, tt_srpt->title[dvd_title].title_set_nr);
      ifoClose( vts_file );
      goto fail;
    }

    mp_msg(MSGT_OPEN,MSGL_V, "DVD successfully opened.\n");
    // store data
    d=malloc(sizeof(dvd_priv_t)); memset(d,0,sizeof(dvd_priv_t));
    d->dvd=dvd;
    d->title=title;
    d->vmg_file=vmg_file;
    d->tt_srpt=tt_srpt;
    d->vts_file=vts_file;
    d->cur_title = dvd_title+1;

    pgc = vts_file->vts_pgcit ? vts_file->vts_pgcit->pgci_srp[ttn].pgc : NULL;
    /**
     * Check number of audio channels and types
     */
    {
      d->nr_of_channels=0;
      if(vts_file->vts_pgcit) {
        int i;
        for(i=0;i<8;i++)
          if(pgc->audio_control[i] & 0x8000) {
            audio_attr_t * audio = &vts_file->vtsi_mat->vts_audio_attr[i];
            int language = 0;
            char tmp[] = "unknown";
            stream_language_t *audio_stream = &d->audio_streams[d->nr_of_channels];

            if(audio->lang_type == 1) {
              language=audio->lang_code;
              tmp[0]=language>>8;
              tmp[1]=language&0xff;
              tmp[2]=0;
            }

            audio_stream->language=language;
            audio_stream->id=pgc->audio_control[i] >> 8 & 7;
            switch(audio->audio_format) {
              case 0: // ac3
                audio_stream->id+=FIRST_AC3_AID;
                break;
              case 6: // dts
                audio_stream->id+=FIRST_DTS_AID;
                break;
              case 2: // mpeg layer 1/2/3
              case 3: // mpeg2 ext
                audio_stream->id+=FIRST_MPG_AID;
                break;
              case 4: // lpcm
                audio_stream->id+=FIRST_PCM_AID;
                break;
           }

           audio_stream->type=audio->audio_format;
           // Pontscho: to my mind, tha channels:
           //  1 - stereo
           //  5 - 5.1
           audio_stream->channels=audio->channels;
           mp_msg(MSGT_OPEN,MSGL_STATUS,MSGTR_DVDaudioStreamInfo,
             d->nr_of_channels,
             dvd_audio_stream_types[ audio->audio_format ],
             dvd_audio_stream_channels[ audio->channels ],
             tmp,
             audio_stream->id
           );
           mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_ID=%d\n", audio_stream->id);
           if(language && tmp[0])
             mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", audio_stream->id, tmp);

           d->nr_of_channels++;
         }