/************************************************************************** * Copyright (C) 2005 by Jean-Michel Petit * * jm_petit@laposte.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "k9dvd.h" #include "k9dvdtitle.h" #include "k9dvdtitleset.h" #include "k9cellcopylist.h" #include "k9dvdprogress.h" #include "k9ifo2.h" #include #include #include #include #include "k9dvd.moc" k9DVDTitle* k9DVD::gettitle(int num) { return ((k9DVDTitle*)m_titles.at(num)); } k9DVDTitle* k9DVD::gettitleByNum(int num) { int j=-1; for (uint i=0; i < m_titles.count();i++) { k9DVDTitle *track=(k9DVDTitle*)m_titles.at(i); if (track->getIndexed()) { j++; if (j==num) return track; } } return (NULL); } /** Read property of int longestTitle. */ k9DVDTitle *k9DVD::getlongestTitle() { return m_longestTitle; } /** Read property of TQString title. */ const TQString& k9DVD::getDVDTitle() { return m_title; } void k9DVD::setDVDTitle(const TQString &_newVal) { m_title=_newVal; } /** Read property of int titleCount. */ const int& k9DVD::gettitleCount() { return m_titleCount; } /** Read property of int titlesetCount. */ const int& k9DVD::gettitlesetCount() { return m_titlesetCount; } k9DVDTitleset *k9DVD::gettitleset(int num) { return m_titlesets.at(num); } int k9DVD::getmenuSize() { return m_menuSize; } k9DVD::k9DVD(TQObject *parent, const char *name,const TQStringList args) { m_error=false; m_opened=false; m_titles.setAutoDelete(true); m_titlesets.setAutoDelete(true); m_lvideoFormat.append("NTSC"); m_lvideoFormat.append("PAL"); m_laspectRatio.append("4:3"); m_laspectRatio.append("16:9"); m_laspectRatio.append("?:?"); m_laspectRatio.append("16:9"); m_lquantization.append("16bps"); m_lquantization.append("20bps"); m_lquantization.append("24bps"); m_lquantization.append("drc"); m_lmpegVersion.append("mpeg1"); m_lmpegVersion.append("mpeg2"); m_lvideoHeight.append("480"); m_lvideoHeight.append("576"); m_lvideoHeight.append("???"); m_lvideoHeight.append("576"); m_lvideoWidth.append("720"); m_lvideoWidth.append("704"); m_lvideoWidth.append("352"); m_lvideoWidth.append("352"); m_lpermittedDf.append(""); m_lpermittedDf.append("noletterbox"); m_lpermittedDf.append("nopanscan"); m_lpermittedDf.append("noletterbox & nopanscan"); m_laudioFormat.append("ac3"); m_laudioFormat.append("?"); m_laudioFormat.append("mp2"); m_laudioFormat.append("mp2"); m_laudioFormat.append("pcm"); m_laudioFormat.append("sdds"); m_laudioFormat.append("dts"); m_lsampleFreq.append("48kHz"); m_lsampleFreq.append("48kHz"); m_laudioType.append(""); m_laudioType.append("Normal"); m_laudioType.append(i18n("for visually impaired")); m_laudioType.append(i18n("director's comments")); m_laudioType.append(i18n("alternate director's comments")); m_lsubpType.append(""); m_lsubpType.append("Normal"); m_lsubpType.append(i18n("Large")); m_lsubpType.append(i18n("Children")); m_lsubpType.append(i18n("reserved")); m_lsubpType.append(i18n("Normal captions")); m_lsubpType.append(i18n("Large captions")); m_lsubpType.append(i18n("Children captions")); m_lsubpType.append(""); m_lsubpType.append(i18n("Forced")); m_lsubpType.append(i18n("reserved")); m_lsubpType.append(i18n("reserved")); m_lsubpType.append(i18n("reserved")); m_lsubpType.append(i18n("Director's comments")); m_lsubpType.append(i18n("Large director's comments")); m_lsubpType.append(i18n("Director's comments for children")); m_frames_per_s[0]=-1.0; m_frames_per_s[1]=25.00; m_frames_per_s[2]=-1.0; m_frames_per_s[3]=29.97; m_start=NULL; } k9DVD::~k9DVD() { if (m_dvd.opened()) m_dvd.close(); } int k9DVD::dvdtime2msec(dvd_time_t *dt) { double fps = m_frames_per_s[(dt->frame_u & 0xc0) >> 6]; long ms; ms = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600000; ms += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000; ms += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000; if(fps > 0) ms +=(long)( ((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f) * 1000.0 / fps); return ms; } /* * The following method is based on code from vobcopy, by Robos, with thanks. */ int k9DVD::get_title_name(const char* dvd_device, char* title) { FILE *filehandle = 0; int i; TQString c; if (! (filehandle = fopen(dvd_device, "r"))) { c=i18n("Couldn't open %1 for title\n").arg(dvd_device); // setError(c ); strcpy(title, i18n("unknown").latin1()); return -1; } if ( fseek(filehandle, 32808, SEEK_SET )) { fclose(filehandle); c=i18n("Couldn't seek in %1 for title\n").arg( dvd_device); setError(c); strcpy(title, i18n("unknown").latin1()); return -1; } if ( 32 != (i = fread(title, 1, 32, filehandle)) ) { fclose(filehandle); // c=tr2i18n("Couldn't read enough bytes for title.\n"); // setError(c); strcpy(title, i18n("unknown").latin1()); return 0; } fclose (filehandle); title[32] = '\0'; while(i-- > 2) if(title[i] == ' ') title[i] = '\0'; return 0; } TQString k9DVD::lang_name(const TQString& code,const TQString & name) { TQString c; int i=0; lng arrLng[] = { { " ", i18n("Not Specified") }, { "aa", i18n("Afar") }, { "ab", i18n("Abkhazian") }, { "af", i18n("Afrikaans") }, { "am", i18n("Amharic")}, { "ar", i18n("Arabic") }, { "as", i18n("Assamese") }, { "ay", i18n("Aymara") }, { "az", i18n("Azerbaijani") }, { "ba", i18n("Bashkir") }, { "be", i18n("Byelorussian") }, { "bg", i18n("Bulgarian") }, { "bh", i18n("Bihari") }, { "bi", i18n("Bislama") }, { "bn", i18n("Bengali; Bangla") }, { "bo", i18n("Tibetan") }, { "br", i18n("Breton") }, { "ca", i18n("Catalan") }, { "co", i18n("Corsican") }, { "cs", i18n("Czech") }, { "cy", i18n("Welsh") }, { "da", i18n("Dansk") }, { "de", i18n("Deutsch") }, { "dz", i18n("Bhutani") }, { "el", i18n("Greek") }, { "en", i18n("English") }, { "eo", i18n("Esperanto") }, { "es", i18n("Espanol") }, { "et", i18n("Estonian") }, { "eu", i18n("Basque") }, { "fa", i18n("Persian") }, { "fi", i18n("Suomi") }, { "fj", i18n("Fiji") }, { "fo", i18n("Faroese") }, { "fr", i18n("Francais") }, { "fy", i18n("Frisian") }, { "ga", i18n("Gaelic") }, { "gd", i18n("Scots Gaelic") }, { "gl", i18n("Galician") }, { "gn", i18n("Guarani") }, { "gu", i18n("Gujarati") }, { "ha", i18n("Hausa") }, { "he", i18n("Hebrew") }, { "hi", i18n("Hindi") }, { "hr", i18n("Hrvatski") }, { "hu", i18n("Magyar") }, { "hy", i18n("Armenian") }, { "ia", i18n("Interlingua") }, { "id", i18n("Indonesian") }, { "ie", i18n("Interlingue") }, { "ik", i18n("Inupiak") }, { "in", i18n("Indonesian") }, { "is", i18n("Islenska") }, { "it", i18n("Italiano") }, { "iu", i18n("Inuktitut") }, { "iw", i18n("Hebrew") }, { "ja", i18n("Japanese") }, { "ji", i18n("Yiddish") }, { "jw", i18n("Javanese") }, { "ka", i18n("Georgian") }, { "kk", i18n("Kazakh") }, { "kl", i18n("Greenlandic") }, { "km", i18n("Cambodian") }, { "kn", i18n("Kannada") }, { "ko", i18n("Korean") }, { "ks", i18n("Kashmiri") }, { "ku", i18n("Kurdish") }, { "ky", i18n("Kirghiz") }, { "la", i18n("Latin") }, { "ln", i18n("Lingala") }, { "lo", i18n("Laothian") }, { "lt", i18n("Lithuanian") }, { "lv", i18n("Latvian, Lettish") }, { "mg", i18n("Malagasy") }, { "mi", i18n("Maori") }, { "mk", i18n("Macedonian") }, { "ml", i18n("Malayalam") }, { "mn", i18n("Mongolian") }, { "mo", i18n("Moldavian") }, { "mr", i18n("Marathi") }, { "ms", i18n("Malay") }, { "mt", i18n("Maltese") }, { "my", i18n("Burmese") }, { "na", i18n("Nauru") }, { "ne", i18n("Nepali") }, { "nl", i18n("Nederlands") }, { "no", i18n("Norsk") }, { "oc", i18n("Occitan") }, { "om", i18n("Oromo") }, { "or", i18n("Oriya") }, { "pa", i18n("Punjabi") }, { "pl", i18n("Polish") }, { "ps", i18n("Pashto, Pushto") }, { "pt", i18n("Portugues") }, { "qu", i18n("Quechua") }, { "rm", i18n("Rhaeto-Romance") }, { "rn", i18n("Kirundi") }, { "ro", i18n("Romanian") }, { "ru", i18n("Russian") }, { "rw", i18n("Kinyarwanda") }, { "sa", i18n("Sanskrit") }, { "sd", i18n("Sindhi") }, { "sg", i18n("Sangho") }, { "sh", i18n("Serbo-Croatian") }, { "si", i18n("Sinhalese") }, { "sk", i18n("Slovak") }, { "sl", i18n("Slovenian") }, { "sm",i18n( "Samoan") }, { "sn", i18n("Shona") }, { "so", i18n("Somali") }, { "sq", i18n("Albanian") }, { "sr", i18n("Serbian") }, { "ss", i18n("Siswati") }, { "st", i18n("Sesotho") }, { "su", i18n("Sundanese") }, { "sv", i18n("Svenska") }, { "sw", i18n("Swahili") }, { "ta", i18n("Tamil") }, { "te", i18n("Telugu") }, { "tg", i18n("Tajik") }, { "th", i18n("Thai") }, { "ti", i18n("Tigrinya") }, { "tk", i18n("Turkmen") }, { "tl", i18n("Tagalog") }, { "tn", i18n("Setswana") }, { "to", i18n("Tonga") }, { "tr", i18n("Turkish") }, { "ts", i18n("Tsonga") }, { "tt", i18n("Tatar") }, { "tw", i18n("Twi") }, { "ug", i18n("Uighur") }, { "uk", i18n("Ukrainian") }, { "ur", i18n("Urdu") }, { "uz", i18n("Uzbek") }, { "vi", i18n("Vietnamese") }, { "vo", i18n("Volapuk") }, { "wo", i18n("Wolof") }, { "xh", i18n("Xhosa") }, { "yi", i18n("Yiddish") }, { "yo", i18n("Yoruba") }, { "za", i18n("Zhuang") }, { "zh", i18n("Chinese") }, { "zu", i18n("Zulu") }, { "xx", i18n("Unknown") }, { "\0", i18n("Unknown") } }; c=i18n("Unknown"); for (i=0 ; arrLng[i].code[0]!=0;i++) { lng l =arrLng[i]; if (name=="") { if (strcmp(code.latin1(),l.code)==0) { c = l.name; } } else { if (strcmp(name.latin1(),l.name)==0) { c = l.code; } } } return c; } int k9DVD::calcNumTitle(ifo_handle_t *ifo,int _vts,int _ttn) { for (int i=0; i< ifo->tt_srpt->nr_of_srpts;i++) { if (ifo->tt_srpt->title[i].title_set_nr==_vts && ifo->tt_srpt->title[i].vts_ttn == _ttn) return (i+1); } return 0; } int k9DVD::scandvd (const TQString & device,bool _quickScan) { char ctitle[255]; k9DVDChapter::setcptChapter(0); ifo_handle_t *ifo_zero, *ifo; pgcit_t *vts_pgcit; vtsi_mat_t *vtsi_mat; vmgi_mat_t *vmgi_mat; audio_attr_t *audio_attr; video_attr_t *video_attr; subp_attr_t *subp_attr; pgc_t *pgc; int i, j, ltitles, cell, vts_ttn, title_set_nr; char lang_code[3]; int has_title = 0; int max_length = 0; bool ok; tt_srpt_t *tt_srpt; TQString txt,c; m_start=NULL; int menuSizes[100]; for ( j=0; j<100;j++) menuSizes[j]=0; m_titles.clear(); m_Device=device; m_error=false; m_errMsg=""; if (!_quickScan) { m_progressDlg= new k9DVDProgress(tqApp->mainWidget(),"progress",true); m_progressDlg->setpbTitleStep(0); m_progressDlg->setpbTotalStep(0); connect(this, TQT_SIGNAL(sigVobProgress(unsigned int,unsigned int)), this, TQT_SLOT(slotVobProgress(unsigned int,unsigned int))); connect(this, TQT_SIGNAL(sigTitleProgress(unsigned int,unsigned int)), this, TQT_SLOT(slotTitleProgress(unsigned int,unsigned int))); connect(this, TQT_SIGNAL(sigTitleText(TQString&)), this, TQT_SLOT(slotTitleText(TQString&))); connect(this, TQT_SIGNAL(sigTotalText(TQString&)), this, TQT_SLOT(slotTotalText(TQString&))); m_progressDlg->show(); } else m_progressDlg=NULL; tqApp->processEvents(); k9DVDTitle *l_track; k9DVDAudioStream *l_auds; k9DVDChapter *l_chap; k9DVDSubtitle *l_sub; TQString sh,sm,ss; /* ret = stat(device.latin1(), &dvd_stat); if ( ret < 0 ) { c=i18n("Can't find device %1\n").arg( device); setError(c); return 1; } */ if (m_dvd.opened()) m_dvd.close(); m_dvd.openDevice(device); if( !m_dvd.opened() ) { c=i18n("Can't open disc %1!\n").arg(device); setError(c); return 2; } // k9Ifo2 kifo_zero(&m_dvd),kifo(&m_dvd); // kifo_zero.openIFO( 0); k9Ifo2 *kifo_zero= m_dvd.getIfo(0); k9Ifo2 *kifo; ifo_zero = kifo_zero->getIFO(); if ( !ifo_zero ) { c=tr2i18n("Can't open main ifo!\n"); setError(c); return 3; } ltitles = ifo_zero->tt_srpt->nr_of_srpts; m_titleCount = 0; has_title = get_title_name(device.utf8(), ctitle); vmgi_mat = ifo_zero->vmgi_mat; m_titlesetCount = vmgi_mat->vmg_nr_of_title_sets; menuSizes[0]=vmgi_mat->vmg_last_sector; m_title=( has_title ? tr2i18n("unknown") : ctitle); for (int ts=1;ts <=m_titlesetCount;ts++) { tt_srpt = ifo_zero->tt_srpt; kifo=m_dvd.getIfo(ts); ifo = kifo->getIFO(); if (ifo==NULL) continue; //add the titleset in the titleset list k9DVDTitleset *titleset = new k9DVDTitleset(ts,ifo->vtsi_mat->vts_last_sector -ifo->vtsi_mat->vtstt_vobs-1); m_titlesets.append(titleset); for (j=0; j < ifo->vts_pgcit->nr_of_pgci_srp; j++) { // tt_srpt->title[j].title_set_nr); // GENERAL vtsi_mat = ifo->vtsi_mat; vts_pgcit = ifo->vts_pgcit; pgc = vts_pgcit->pgci_srp[j].pgc; //retrieve the ttn int ttn=(vts_pgcit->pgci_srp[j].entry_id) & 0x7F; bool entryPgc= (vts_pgcit->pgci_srp[j].entry_id & 0x80)==0x80; int numTitle=calcNumTitle(ifo_zero,ts,ttn); //JMP : vérifier la numérotation des titres ...... if (vtsi_mat && (pgc->nr_of_cells >0)) { m_titleCount++; vts_ttn = ttn;//ifo->vts_ptt_srpt->title[j].ptt[0].pgcn; //ifo_zero->tt_srpt->title[j].vts_ttn; //JMPtxt=i18n("Title %1").arg(indexedCount); txt=i18n("Title %1").arg(numTitle); emit sigTotalText (txt); emit sigTitleProgress(numTitle,ltitles); video_attr = &vtsi_mat->vts_video_attr; vmgi_mat = ifo_zero->vmgi_mat; title_set_nr = ts; //ifo_zero->tt_srpt->title[j].title_set_nr; menuSizes[title_set_nr]=vtsi_mat->vtstt_vobs + vtsi_mat->vtsi_last_sector +1; //vts_pgcit->pgci_srp[ifo->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc; int titleStartSector=pgc->cell_playback[0].first_sector; //l_track=addTitle(j+1,title_set_nr,ifo->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1,titleStartSector,isTitleIndex(ifo_zero,ts,vts_ttn)); l_track=addTitle(titleset,m_titleCount, numTitle,title_set_nr,j,titleStartSector, entryPgc); titleset->add (l_track); sh.sprintf("%02x",pgc->playback_time.hour); sm.sprintf("%02x",pgc->playback_time.minute); ss.sprintf("%02x",pgc->playback_time.second); l_track->length.setHMS(sh.toInt(&ok,10),sm.toInt(&ok,10),ss.toInt(&ok,10)); //printf(tr2i18n("Title: %02d, Length: %02x:%02x:%02x "), j+1, pgc->playback_time.hour, pgc->playback_time.minute, pgc->playback_time.second); if (dvdtime2msec(&pgc->playback_time) > max_length && entryPgc) { max_length = dvdtime2msec(&pgc->playback_time); m_longestTitle = l_track; } l_track->chapterCount = pgc->nr_of_programs;// ifo_zero->tt_srpt->title[j].nr_of_ptts; l_track->audioStreamCount = vtsi_mat->nr_of_vts_audio_streams; l_track->subPictureCount = vtsi_mat->nr_of_vts_subp_streams; l_track->VTS = ts;// ifo_zero->tt_srpt->title[j].title_set_nr; l_track->TTN = ttn; // ifo_zero->tt_srpt->title[j].vts_ttn; l_track->FPS = m_frames_per_s[(pgc->playback_time.frame_u & 0xc0) >> 6]; l_track->format= (*m_lvideoFormat.at(video_attr->video_format)); m_format = l_track->format; /* TQStringList::Iterator it; it= videoFormat.at(video_attr->video_format); c= (*it).latin1(); */ l_track->aspectRatio = (*m_laspectRatio.at(video_attr->display_aspect_ratio)); l_track->width = (*m_lvideoWidth.at(video_attr->picture_size)); ; l_track->height = (*m_lvideoHeight.at(video_attr->video_format)); l_track->DF = (*m_lpermittedDf.at(video_attr->permitted_df)); for (i=0; i<16; i++) { TQString pal; pal.sprintf("%08x",pgc->palette[i]); l_track->palette.append(pal); } // ANGLES l_track->angleCount = ifo_zero->tt_srpt->title[j].nr_of_angles; // AUDIO // for (i=0; inr_of_vts_audio_streams; i++) { l_track->audioStreamCount=0; for (i=0; inr_of_vts_audio_streams; i++) { if (pgc->audio_control[i]>>8 !=0) { l_track->audioStreamCount++; l_auds=l_track->addAudioStream(); l_auds->id = 1+ ((pgc->audio_control[i]>>8) & 0x7) ; //this only true for AC3 streams l_auds->m_streamId = (pgc->audio_control[i]>>8); audio_attr = &vtsi_mat->vts_audio_attr[i]; //dts stream starts at 0x88 if (audio_attr->audio_format==6) l_auds->m_streamId +=8; //JMPaudio_attr = &vtsi_mat->vts_audio_attr[l_auds->id-1]; snprintf(lang_code,3, "%c%c", audio_attr->lang_code>>8, audio_attr->lang_code & 0xff); if (!lang_code[0]) { lang_code[0] = 'x'; lang_code[1] = 'x'; } l_auds->langCod=lang_code; l_auds->language=lang_name(l_auds->langCod,""); if (l_auds->language==i18n("Unknown")) l_auds->langCod="xx"; l_auds->format= (*m_laudioFormat.at(audio_attr->audio_format)); l_auds->frequency = (*m_lsampleFreq.at(audio_attr->sample_frequency)); l_auds->quantization = (*m_lquantization.at(audio_attr->quantization)); l_auds->channels = audio_attr->channels+1; l_auds->appMode = audio_attr->application_mode; l_auds->content = (*m_laudioType.at(audio_attr->code_extension)); //if (((pgc->audio_control[i]>>8) & 0x80) ==0x80) { //} else { // l_auds->id=1; //} } } l_track->m_defAudio=NULL; l_track->m_defSubtitle=NULL; // CHAPTERS cell = 0; unsigned long total_sectors = 0; l_track->chapterCount= pgc->nr_of_programs; for (i=0;i < l_track->chapterCount;i++) l_track->addChapter(i+1); k9DVDChapter *l_pchap=NULL; for (i=0; inr_of_programs; i++) { int second=0, minute=0, hour=0, tmp; char hex[3]; int next = pgc->program_map[i+1]; unsigned long sectors = 0; l_chap = l_track->getChapter(i); //first sector l_chap->startSector=pgc->cell_playback[cell].first_sector; ; l_chap->endSector=0; if (i == pgc->nr_of_programs - 1) next = pgc->nr_of_cells + 1; int iangleStart=-1,iangleEnd=-1; while (cell < next - 1) { //using c2 otherwise the value of cell were lost //int c2=cell; //l_chap->cells.append(c2); int startSect=pgc->cell_playback[cell].first_sector; l_chap->startSectors.append(startSect); snprintf(hex,3, "%02x", pgc->cell_playback[cell].playback_time.second); tmp = second + atoi(hex); minute = minute + (tmp / 60); second = tmp % 60; snprintf(hex,3, "%02x", pgc->cell_playback[cell].playback_time.minute); tmp = minute + atoi(hex); hour = hour + (tmp / 60); minute = tmp % 60; l_chap->endSector= pgc->cell_playback[cell].last_sector; //last sector /* Check if we're entering an angle block. (vamp_play-title) */ int cell2=cell; if ( pgc->cell_playback[ cell ].block_type == BLOCK_TYPE_ANGLE_BLOCK && cell>iangleEnd ) { iangleStart=cell; for( int idc = 0;; ++idc ) { k9ChapterCell * chapterCell=new k9ChapterCell(cell2+idc,idc+1); l_chap->cells.append(chapterCell); chapterCell->setstartSector(pgc->cell_playback[cell2+idc].first_sector); chapterCell->setlastSector(pgc->cell_playback[cell2+idc].last_sector); if (idc==0) chapterCell->setangleBlock(angleStart); else chapterCell->setangleBlock(angleInside); if( pgc->cell_playback[ cell2 + idc ].block_mode == BLOCK_MODE_LAST_CELL ) { iangleEnd=cell2+idc; chapterCell->setangleBlock(angleEnd); sectors += pgc->cell_playback[iangleEnd].last_sector - pgc->cell_playback[iangleStart].first_sector + 1; break; } } } else { if (!(cell>=iangleStart && cell <=iangleEnd)) { k9ChapterCell * chapterCell=new k9ChapterCell(cell,1); l_chap->cells.append(chapterCell); chapterCell->setstartSector(pgc->cell_playback[cell].first_sector); chapterCell->setlastSector(pgc->cell_playback[cell].last_sector); sectors += pgc->cell_playback[cell].last_sector - pgc->cell_playback[cell].first_sector + 1; } } cell++; } l_track->vobusize_mb += calcVobuSize(ifo,l_chap); total_sectors += sectors; l_chap->length.setHMS(hour,minute,second); l_chap->sectors=sectors; if (l_pchap!=NULL) { TQTime t; int position; t.setHMS(0,0,0); position=t.secsTo(l_chap->length); t=l_pchap->time.addSecs(position); l_chap->time=t; } l_pchap=l_chap; } l_track->size_mb =((float)total_sectors *2048)/(1024*1024); l_track->m_sectors= total_sectors; // SUBTITLES l_track->subPictureCount=0; for (i=0; inr_of_vts_subp_streams; i++) { if (pgc->subp_control[i]>>24 !=0) { l_sub=l_track->addSubtitle(i+1); unsigned char subpc; subpc=pgc->subp_control[i]>>24; if ((subpc & 0x80)==0x80) { if (l_track->aspectRatio=="4:3") { l_sub->id.append(1+ (subpc & 0x1F)); } else { subpc=(pgc->subp_control[i]>>16) & 0x1F; l_sub->id.append(1+ subpc); subpc=(pgc->subp_control[i]>>8) & 0x1F; if (! l_sub->id.contains(1+ subpc) && ! l_track->DF.contains("noletterbox")) l_sub->id.append(1+ subpc); subpc=pgc->subp_control[i] & 0x1F; if (! l_sub->id.contains(1+ subpc) && ! l_track->DF.contains("nopanscan")) l_sub->id.append(1+ subpc); } kdDebug() << "VTS: " << l_track->VTS << " TTN: " << l_track->TTN << \ " Subtitle " << i+1 << ": " << l_sub->id << " " << l_sub->language << \ " " << l_sub->content << endl; } l_track->subPictureCount++; subp_attr = &vtsi_mat->vts_subp_attr[i]; snprintf(lang_code,3, "%c%c", subp_attr->lang_code>>8, subp_attr->lang_code & 0xff); if (!lang_code[0]) { lang_code[0] = 'x'; lang_code[1] = 'x'; } //JMP : l_sub->setselected(!titleIndexed); l_sub->langCod=lang_code; l_sub->language=lang_name(lang_code,""); l_sub->content= (*m_lsubpType.at(subp_attr->code_extension)); } } if (entryPgc && !_quickScan) calcStreamSize(*l_track); } } //kifo.closeIFO(); } m_menuSize=0; for (j=0;j<100;j++) m_menuSize+=menuSizes[j]; //kifo_zero.closeIFO(); if (!_quickScan) delete m_progressDlg; m_progressDlg=0; m_opened=true; //m_dvd.close(); return 0; } float k9DVD::calcVobuSize(ifo_handle_t *_ifo,k9DVDChapter *_chapter) { vobu_admap_t * vobu_admap = _ifo->vts_vobu_admap; int length = vobu_admap->last_byte + 1 - VOBU_ADMAP_SIZE; float total=0; for(uint32_t i = 0; i < length/sizeof(uint32_t); i++) { if(vobu_admap->vobu_start_sectors[i] >= _chapter->startSector &&vobu_admap->vobu_start_sectors[i] <= _chapter->endSector) total++; } total=total*2048; total=total/(1024*1024); return total; } /** Adds a new track in the titles list the list is sorted by VTS and pgc*/ k9DVDTitle* k9DVD::addTitle(k9DVDTitleset *_titleset,int id,int num,int _VTS,int _pgc,uint32_t _startSector,bool _indexed) { k9DVDTitle *track,*tmp; track = new k9DVDTitle; track->numTitle=num; track->indexed=_indexed; track->id=id; track->m_titleset=_titleset; //JMP : modification track->forceSelection = false; // !_indexed; track->ts_nr=_VTS; track->pgc=_pgc; bool bappend=true; for (uint i=0;igetChapter(0); if (tmp->ts_nr >_VTS) { bappend=false; } else if ( (tmp->ts_nr==_VTS) && ((tmp->pgc >_pgc) || (chap->getstartSector() > _startSector)) ) { bappend=false; } if (!bappend) { m_titles.insert(i,track); break; } } if (bappend) m_titles.append(track); track->name=i18n("Title %1").arg(num); if (!_indexed) { for (uint i=0;inumTitle==num && tmp->indexed) tmp->m_titles.append(track); } } return(track); } void k9DVD::calcStreamSize(k9DVDTitle & track) { struct stream_counter streams[64]; int stream_count; int start = 0; int stop = 0; k9DVDChapter *c_start,*c_stop; struct streamSize streamList[64]; int c, x; TQString pg; for( x=0 ; x<64 ; x++ ) { // init stream usage list streams[x].id = 0; streams[x].count = 0; streams[x].size_mb = 0; streams[x].percent = 0; streamList[x].id=0; streamList[x].percent=0; streamList[x].size_mb=0; } x = 0; c = 0; if( track.chapterCount == 2 ) { // select which chapters to probe for stream sizes start=0; stop=1; } if (track.chapterCount == 1) { start=0; stop=0; } if (track.chapterCount >2) { start=0; stop=(int)(track.chapterCount-1); } c_start=(k9DVDChapter*)track.chapters.at(start); c_stop=(k9DVDChapter*)track.chapters.at(stop); pg=tr2i18n("reading title"); emit sigTitleText(pg); //probe stream usage c = stream_vob( track.ts_nr,c_start->startSector, c_stop->endSector, streams); for( x=0 ; x<64 ; x++ ) { if( streams[x].id == 0 ) break; streams[x].percent = (float)streams[x].count / (float)(c / 100.); // calc usage in percent } // create streamlist with all streams stream_count=0; for( c=0 ; c<64 ; c++ ) { if( streams[c].id == 0 ) break; streamList[stream_count].id = streams[c].id; if( stream_count >= 64 ) break; stream_count++; x++; } // other_streams_mb = 0; // calc size of all selected streams for( x=0 ; xvideosize_mb = streamList[x].size_mb; } for (i=0;iaudioStreamCount;i++) { l_auds=(k9DVDAudioStream*)l_track->audioStreams.at(i); for (x=0;x<64;x++) { if (streamList[x].id==0) break; int id=streamList[x].id; if (( (id >=0x80) && (id <=0x8f)) || ((id >=0xa0) && (id <=0xa7)) || ((id >=0xc0) && (id <=0xdf))) { if ( getVampsID(id) == l_auds->id) { l_auds->size_mb = streamList[x].size_mb; //stop the loop, go to next audio stream break; } } } } for (i=0;isubPictureCount;i++) { l_sub=(k9DVDSubtitle*)l_track->subtitles.at(i); for (x=0;x<64;x++) { if (streamList[x].id==0) break; int id=streamList[x].id; if ( (id >=0x20) && (id <=0x3f)) { if ( l_sub->id.contains(id - 0x20 +1) ) { l_sub->size_mb = streamList[x].size_mb; break; } } } } } int k9DVD::identify_stream( unsigned char *buffer ) { uint8_t packet_type = buffer[17]; if( (packet_type >= 0xE0) && (packet_type <= 0xEF) ) { // video streams ; } else if( packet_type == 0xBB ) { // system header ; } else if( packet_type == 0xBE ) { // padding ; } else if( packet_type == 0xBF ) { // nav pack ; } else if( (packet_type >= 0xC0) && (packet_type <= 0xDF) ) { // mpeg audio ; } else if( packet_type == 0xBD ) { // private stream, check content packet_type = buffer[23+buffer[22]]; } return packet_type; } long k9DVD::stream_vob( int title, unsigned long startblock, unsigned long lastblock, struct stream_counter *sc) { k9DVDFile *dvdfile; //JMP unsigned char buffer[DVD_VIDEO_LB_LEN]; unsigned char buffer[DVD_VIDEO_LB_LEN*800]; unsigned char *ptrbuff; int blocksize=800,y; int step=(int)((lastblock-startblock)/800) / 10;// * 0.05; if (step==0) step=1; unsigned char stream_id; long total=0; unsigned long i, x ,nbread=0; ssize_t size; TQString c; dvdfile =m_dvd.openTitle( title); if( !dvdfile ) { c=i18n("Error opening vobs for title %1\n").arg( title); setError(c); return 0; } i = startblock; while( (i >= startblock) && (i <= lastblock) && (blocksize>0)) { // read blocks size= dvdfile->readBlocks( i,blocksize , buffer); emit sigVobProgress(i-startblock,lastblock-startblock); total+=size; if( !size ) { c=i18n("ERROR reading block %1\n").arg(i); setError(c); break; } ptrbuff=buffer; for (y=0;y lastblock) blocksize=lastblock-i; } dvdfile->close(); return total; } uint64_t k9DVD::getsizeSelected(bool _streams) { uint64_t selstreams=0,vidstreams=0; int i,x; k9DVDTitle *l_track; k9DVDAudioStream *l_auds; k9DVDSubtitle *l_sub; bool withvideo; for (i=0;iisSelected() && l_track->getIndexed(); if ( withvideo) { vidstreams +=l_track->getsectors(); if (_streams) { for (x=0;xaudioStreamCount;x++) { l_auds=l_track->getaudioStream(x); if (!l_auds->selected) selstreams += l_auds->size_mb*512; } for (x=0;xsubPictureCount;x++) { l_sub=l_track->getsubtitle(x); if (!l_sub->selected) selstreams += l_sub->size_mb*512; } } } } vidstreams -=selstreams; return (vidstreams ); } float k9DVD::getfactor(bool _withMenus,bool _streams,bool _useDvdAuthor) { if (!_useDvdAuthor || _withMenus) { //m_dvd.openDevice(Device); k9CellCopyList *cellCopyList =new k9CellCopyList(&m_dvd,this); double factor=cellCopyList->getfactor(_withMenus,_streams); //m_dvd.close(); return (factor); } else { float selstreams=0,vidstreams=0,l_factor; int i,x; k9DVDTitle *l_track; k9DVDAudioStream *l_auds; k9DVDSubtitle *l_sub; bool withvideo; double forced=0,forcedsh=0; for (i=0;iisSelected() && l_track->getIndexed(); if ( withvideo) { //size_mb = size of titles - size of unselected chapters float size_mb=l_track->gettotalsize_mb()-l_track->getChaptersSize_mb( false) ; //gettotalsize_mb does include parts of titles vidstreams +=size_mb ; if (l_track->getforceFactor()) { forced+=size_mb; forcedsh+=(size_mb/l_track->getfactor()); } if (_streams) { for (x=0;xaudioStreamCount;x++) { l_auds=l_track->getaudioStream(x); if (!l_auds->selected) selstreams += l_auds->size_mb; } for (x=0;xsubPictureCount;x++) { l_sub=l_track->getsubtitle(x); if (!l_sub->selected) selstreams += l_sub->size_mb; } } } } vidstreams -=selstreams; l_factor = ((float) vidstreams - forced) / (k9DVDSize::getMaxSize() - forcedsh); l_factor = (int)((l_factor+0.01)*100); l_factor /=100; if (l_factor <1) l_factor=1; return(l_factor); } } void k9DVD::slotVobProgress(unsigned int position,unsigned int total) { m_progressDlg->setpbTitleStep(position); m_progressDlg->setpbTitleTotalSteps(total); tqApp->processEvents(); } void k9DVD::slotTitleProgress(unsigned int position,unsigned int total) { m_progressDlg->setpbTotalStep(position); m_progressDlg->setpbTotalTotalSteps(total); tqApp->processEvents(); } void k9DVD::slotTitleText(TQString& text) { m_progressDlg->setlblTitle(text); tqApp->processEvents(); } void k9DVD::slotTotalText(TQString& text) { m_progressDlg->setlblTotal(text); tqApp->processEvents(); } const TQString& k9DVD::getDevice() { return m_Device; } const bool& k9DVD::geterror() { return m_error; } const TQString& k9DVD::geterrMsg() { return m_errMsg; } void k9DVD::setError(const TQString & err) { m_error=true; m_errMsg=err; if (m_progressDlg !=NULL) m_progressDlg->hide(); } const bool& k9DVD::getopened() { return m_opened; } TQString &k9DVD::getFormat() { return (m_format); } int k9DVD::getVampsID(int type) { int abase = 0; if (type >= 0x80 && type <= 0x87) { // AC3 audio abase = 0x80; } else if (type >= 0x88 && type <= 0x8f) { // DTS audio abase = 0x88; } else if (type >= 0xa0 && type <= 0xbf) { // LPCM audio abase = 0xa0; } else if (type >= 0xc0 && type <= 0xdf) { // MPEG audio abase = 0xc0; } return (type-abase +1); } k9DVDTitle* k9DVD::getstart() { return m_start; } void k9DVD::setstart(k9DVDTitle* title) { m_start=title; } // returns the title number in the reauthored DVD int k9DVD::getnewTitleNum(k9DVDTitle *title) { int num=0; k9DVDTitle *tr; for (int i=0 ;i < m_titleCount;i++) { tr=gettitle(i); if (tr->isSelected() && tr->getIndexed()) { ++num; if (tr->getnumTitle() == title->getnumTitle()) return(num); } } return(-1); } void k9DVD::close() { m_opened=false; if (m_dvd.opened()) m_dvd.close(); m_titles.clear(); m_titlesets.clear(); }