static int mp_describe_titleset(stream_t *stream, dvd_reader_t *dvd, tt_srpt_t *tt_srpt, int vts_no) { ifo_handle_t *vts_file; int title_no, msec=0; vts_file = ifoOpen(dvd, vts_no); if(!vts_file) return 0; if(!vts_file->vtsi_mat || !vts_file->vts_pgcit) { ifoClose(vts_file); return 0; } for(title_no = 0; title_no < tt_srpt->nr_of_srpts; title_no++) { if (tt_srpt->title[title_no].title_set_nr != vts_no) continue; msec = mp_get_titleset_length(vts_file, tt_srpt, title_no); MP_SMODE(stream, "ID_DVD_TITLE_%d_LENGTH=%d.%03d\n", title_no, msec / 1000, msec % 1000); } ifoClose(vts_file); return 1; }
static int control(stream_t *stream,int cmd,void* arg) { dvd_priv_t *d = stream->priv; switch(cmd) { case STREAM_CTRL_GET_TIME_LENGTH: { *((double *)arg) = (double) mp_get_titleset_length(d->vts_file, d->tt_srpt, d->cur_title)/1000.0; return 1; } case STREAM_CTRL_GET_START_TIME: { *((double *)arg) = 0; return 1; } case STREAM_CTRL_GET_NUM_TITLES: { *((unsigned int *)arg) = d->vmg_file->tt_srpt->nr_of_srpts; return 1; } case STREAM_CTRL_GET_NUM_CHAPTERS: { int r; r = get_num_chapter(d->vts_file, d->tt_srpt, d->cur_title); if(! r) return STREAM_UNSUPPORTED; *((unsigned int *)arg) = r; return 1; } case STREAM_CTRL_GET_CHAPTER_TIME: { int r; r = get_chapter_time(d->vts_file, d->tt_srpt, d->cur_title, (double *)arg); if(! r) return STREAM_UNSUPPORTED; return 1; } case STREAM_CTRL_GET_CURRENT_TITLE: { *((unsigned int *)arg) = d->cur_title; return 1; } case STREAM_CTRL_GET_CURRENT_TIME: { double tm; tm = dvd_get_current_time(stream, -1); if(tm != -1) { *((double *)arg) = tm; return 1; } break; } case STREAM_CTRL_SEEK_TO_TIME: { if(dvd_seek_to_time(stream, d->vts_file, *((double*)arg))) return 1; break; } case STREAM_CTRL_GET_ASPECT_RATIO: { *((double *)arg) = !d->vts_file->vtsi_mat->vts_video_attr.display_aspect_ratio ? 4.0/3.0 : 16.0/9.0; return 1; } case STREAM_CTRL_GET_NUM_ANGLES: { *((int *)arg) = d->vmg_file->tt_srpt->title[d->dvd_title].nr_of_angles; return 1; } case STREAM_CTRL_GET_ANGLE: { *((int *)arg) = d->dvd_angle; return 1; } case STREAM_CTRL_SET_ANGLE: { int ang = *((int *)arg); if(ang>d->vmg_file->tt_srpt->title[d->dvd_title].nr_of_angles || ang<=0) break; d->dvd_angle = ang; d->angle_seek = 1; return 1; } case STREAM_CTRL_GET_LANG: { struct stream_lang_req *req = arg; int lang = 0; switch(req->type) { case STREAM_AUDIO: lang = dvd_lang_from_aid(stream, req->id); break; case STREAM_SUB: lang = dvd_lang_from_sid(stream, req->id); break; } if (!lang) break; snprintf(req->name, sizeof(req->name), "%c%c", lang >> 8, lang); return STREAM_OK; } case STREAM_CTRL_GET_DVD_INFO: { struct stream_dvd_info_req *req = arg; memset(req, 0, sizeof(*req)); req->num_subs = dvd_number_of_subs(stream); memcpy(req->palette, d->cur_pgc->palette, sizeof(req->palette)); return STREAM_OK; } case STREAM_CTRL_GET_DISC_NAME: { char buffer[128]; if (DVDUDFVolumeInfo(d->dvd, buffer, sizeof(buffer), NULL, 0) < 0 && DVDISOVolumeInfo(d->dvd, buffer, sizeof(buffer), NULL, 0) < 0) break; if (!buffer[0]) break; *(char**)arg = talloc_strdup(NULL, buffer); return STREAM_OK; } } return STREAM_UNSUPPORTED; }
static int dvd_seek_to_time(stream_t *stream, ifo_handle_t *vts_file, double sec) { unsigned int i, j, k, timeunit, ac_time, tmap_sector=0, cell_sector=0, vobu_sector=0; int t=0; double tm, duration; int64_t pos = -1; dvd_priv_t *d = stream->priv; vts_tmapt_t *vts_tmapt = vts_file->vts_tmapt; if(!vts_file->vts_tmapt || sec < 0) return 0; duration = (double) mp_get_titleset_length(d->vts_file, d->tt_srpt, d->cur_title) / 1000.0f; if(sec > duration) return 0; i=d->cur_pgc_idx; timeunit = vts_tmapt->tmap[i].tmu; for(j = 0; j < vts_tmapt->tmap[i].nr_of_entries; j++) { ac_time = timeunit * (j + 1); if(ac_time >= sec) break; tmap_sector = vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff; } //search enclosing cell for(i=0; i<d->cur_pgc->nr_of_cells; i++) { if(tmap_sector >= d->cur_pgc->cell_playback[i].first_sector && tmap_sector <= d->cur_pgc->cell_playback[i].last_sector) { cell_sector = d->cur_pgc->cell_playback[i].first_sector; break; } } pos = ((int64_t)cell_sector)<<11; do_seek(stream, pos); do { char buf[2048]; if (dvd_read_sector(stream, stream->priv, buf) < 0) // skip break; t = mp_dvdtimetomsec(&d->dsi_pack.dsi_gi.c_eltm); } while(!t); tm = dvd_get_current_time(stream, -1); pos = ((int64_t)tmap_sector)<<11; do_seek(stream, pos); //now get current time in terms of the cell+cell time offset memset(&d->dsi_pack.dsi_gi.c_eltm, 0, sizeof(dvd_time_t)); while(tm <= sec) { char buf[2048]; if (dvd_read_sector(stream, stream->priv, buf) < 0) // skip break; pos += 2048; tm = dvd_get_current_time(stream, -1); }; tmap_sector = pos >> 11; //search closest VOBU sector k=(vts_file->vts_vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE)/4; //entries in the vobu admap for(i=1; i<k; i++) { if(vts_file->vts_vobu_admap->vobu_start_sectors[i] > tmap_sector) break; } vobu_sector = vts_file->vts_vobu_admap->vobu_start_sectors[i-1]; pos = ((int64_t)vobu_sector) << 11; do_seek(stream, pos); return 1; }
static int control(stream_t *stream,int cmd,void* arg) { dvd_priv_t *d = stream->priv; switch(cmd) { case STREAM_CTRL_GET_TIME_LENGTH: { *((double *)arg) = (double) mp_get_titleset_length(d->vts_file, d->tt_srpt, d->cur_title-1)/1000.0; return 1; } case STREAM_CTRL_GET_NUM_CHAPTERS: { int r; r = get_num_chapter(d->vts_file, d->tt_srpt, d->cur_title-1); if(! r) return STREAM_UNSUPPORTED; *((unsigned int *)arg) = r; return 1; } case STREAM_CTRL_SEEK_TO_CHAPTER: { int r; r = seek_to_chapter(stream, d->vts_file, d->tt_srpt, d->cur_title-1, *((unsigned int *)arg)); if(! r) return STREAM_UNSUPPORTED; return 1; } case STREAM_CTRL_GET_CURRENT_CHAPTER: { *((unsigned int *)arg) = dvd_chapter_from_cell(d, d->cur_title-1, d->cur_cell); return 1; } case STREAM_CTRL_GET_CURRENT_TIME: { double tm; tm = dvd_get_current_time(stream, 0); if(tm != -1) { *((double *)arg) = tm; return 1; } break; } case STREAM_CTRL_SEEK_TO_TIME: { if(dvd_seek_to_time(stream, d->vts_file, *((double*)arg))) return 1; break; } case STREAM_CTRL_GET_ASPECT_RATIO: { *((double *)arg) = !d->vts_file->vtsi_mat->vts_video_attr.display_aspect_ratio ? 4.0/3.0 : 16.0/9.0; return 1; } case STREAM_CTRL_GET_NUM_ANGLES: { *((int *)arg) = d->vmg_file->tt_srpt->title[dvd_title].nr_of_angles; return 1; } case STREAM_CTRL_GET_ANGLE: { *((int *)arg) = dvd_angle+1; return 1; } case STREAM_CTRL_SET_ANGLE: { int ang = *((int *)arg); if(ang>d->vmg_file->tt_srpt->title[dvd_title].nr_of_angles || ang<=0) break; dvd_angle = ang - 1; d->angle_seek = 1; return 1; } } return STREAM_UNSUPPORTED; }
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); } #ifdef GEKKO /** * Try to autodetect main title if title number not specified. */ if (dvd_title == 0) { int longest_len = 0; int longest_title = 0; int vts_no; for (vts_no = 1; vts_no <= vmg_file->vts_atrt->nr_of_vtss; vts_no++) { ifo_handle_t *temp_vts_file = ifoOpen(dvd, vts_no); // ignore failed titles if (temp_vts_file) { int title_no; for (title_no = 0; title_no < tt_srpt->nr_of_srpts; title_no++) { int len; if (tt_srpt->title[title_no].title_set_nr != vts_no) continue; len = mp_get_titleset_length(temp_vts_file, tt_srpt, title_no); if (len > longest_len) { longest_len = len; longest_title = title_no; } } ifoClose(temp_vts_file); } } dvd_title = longest_title + 1; // remap +1 for the validation } if(dvd_angle < 1) dvd_angle = 1; #endif /** * 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++; }