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; }
/***************************************************************************** * 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 ); }
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 */ }
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 */ }
DVDStream::~DVDStream() { KillReadAheadThread(); rwlock.lockForWrite(); if (m_reader) DVDClose(m_reader); rwlock.unlock(); }
/* 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); }
/*! ****************************************************************************** * \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; }
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); }
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; }
/***************************************************************************** * 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); } } }
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; }
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; }
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; }
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; }
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; }
/*! ****************************************************************************** * \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; }
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; }
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); }
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++; }
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; } } }
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++; }