00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00042
00043
00044 #ifdef HAVE_CONFIG_H
00045 #include "autoconfig.h"
00046 #endif
00047
00048 #ifdef HAVE_LIBDVDNAV
00049
00050 #include "dvdnav_read.h"
00051 #include <assert.h>
00052
00053 #include "tools.h"
00054
00055 using namespace zmm;
00056
00057 static double frames_per_s[4] = {-1.0, 25.00, -1.0, 29.97};
00058
00059 static struct { char code[3]; char name[20]; }
00060
00061 language[] = {
00062 { " ", "Not Specified" }, { "aa", "Afar" },
00063 { "ab", "Abkhazian" }, { "af", "Afrikaans" },
00064 { "am", "Amharic" }, { "ar", "Arabic" },
00065 { "as", "Assamese" }, { "ay", "Aymara" },
00066 { "az", "Azerbaijani" }, { "ba", "Bashkir" },
00067 { "be", "Byelorussian" }, { "bg", "Bulgarian" },
00068 { "bh", "Bihari" }, { "bi", "Bislama" },
00069 { "bn", "Bengali; Bangla" }, { "bo", "Tibetan" },
00070 { "br", "Breton" }, { "ca", "Catalan" },
00071 { "co", "Corsican" }, { "cs", "Czech" },
00072 { "cy", "Welsh" }, { "da", "Dansk" },
00073 { "de", "Deutsch" }, { "dz", "Bhutani" },
00074 { "el", "Greek" }, { "en", "English" },
00075 { "eo", "Esperanto" }, { "es", "Espanol" },
00076 { "et", "Estonian" }, { "eu", "Basque" },
00077 { "fa", "Persian" }, { "fi", "Suomi" },
00078 { "fj", "Fiji" }, { "fo", "Faroese" },
00079 { "fr", "Francais" }, { "fy", "Frisian" },
00080 { "ga", "Gaelic" }, { "gd", "Scots Gaelic" },
00081 { "gl", "Galician" }, { "gn", "Guarani" },
00082 { "gu", "Gujarati" }, { "ha", "Hausa" },
00083 { "he", "Hebrew" }, { "hi", "Hindi" },
00084 { "hr", "Hrvatski" }, { "hu", "Magyar" },
00085 { "hy", "Armenian" }, { "ia", "Interlingua" },
00086 { "id", "Indonesian" }, { "ie", "Interlingue" },
00087 { "ik", "Inupiak" }, { "in", "Indonesian" },
00088 { "is", "Islenska" }, { "it", "Italiano" },
00089 { "iu", "Inuktitut" }, { "iw", "Hebrew" },
00090 { "ja", "Japanese" }, { "ji", "Yiddish" },
00091 { "jw", "Javanese" }, { "ka", "Georgian" },
00092 { "kk", "Kazakh" }, { "kl", "Greenlandic" },
00093 { "km", "Cambodian" }, { "kn", "Kannada" },
00094 { "ko", "Korean" }, { "ks", "Kashmiri" },
00095 { "ku", "Kurdish" }, { "ky", "Kirghiz" },
00096 { "la", "Latin" }, { "ln", "Lingala" },
00097 { "lo", "Laothian" }, { "lt", "Lithuanian" },
00098 { "lv", "Latvian, Lettish" }, { "mg", "Malagasy" },
00099 { "mi", "Maori" }, { "mk", "Macedonian" },
00100 { "ml", "Malayalam" }, { "mn", "Mongolian" },
00101 { "mo", "Moldavian" }, { "mr", "Marathi" },
00102 { "ms", "Malay" }, { "mt", "Maltese" },
00103 { "my", "Burmese" }, { "na", "Nauru" },
00104 { "ne", "Nepali" }, { "nl", "Nederlands" },
00105 { "no", "Norsk" }, { "oc", "Occitan" },
00106 { "om", "Oromo" }, { "or", "Oriya" },
00107 { "pa", "Punjabi" }, { "pl", "Polish" },
00108 { "ps", "Pashto, Pushto" }, { "pt", "Portugues" },
00109 { "qu", "Quechua" }, { "rm", "Rhaeto-Romance" },
00110 { "rn", "Kirundi" }, { "ro", "Romanian" },
00111 { "ru", "Russian" }, { "rw", "Kinyarwanda" },
00112 { "sa", "Sanskrit" }, { "sd", "Sindhi" },
00113 { "sg", "Sangho" }, { "sh", "Serbo-Croatian" },
00114 { "si", "Sinhalese" }, { "sk", "Slovak" },
00115 { "sl", "Slovenian" }, { "sm", "Samoan" },
00116 { "sn", "Shona" }, { "so", "Somali" },
00117 { "sq", "Albanian" }, { "sr", "Serbian" },
00118 { "ss", "Siswati" }, { "st", "Sesotho" },
00119 { "su", "Sundanese" }, { "sv", "Svenska" },
00120 { "sw", "Swahili" }, { "ta", "Tamil" },
00121 { "te", "Telugu" }, { "tg", "Tajik" },
00122 { "th", "Thai" }, { "ti", "Tigrinya" },
00123 { "tk", "Turkmen" }, { "tl", "Tagalog" },
00124 { "tn", "Setswana" }, { "to", "Tonga" },
00125 { "tr", "Turkish" }, { "ts", "Tsonga" },
00126 { "tt", "Tatar" }, { "tw", "Twi" },
00127 { "ug", "Uighur" }, { "uk", "Ukrainian" },
00128 { "ur", "Urdu" }, { "uz", "Uzbek" },
00129 { "vi", "Vietnamese" }, { "vo", "Volapuk" },
00130 { "wo", "Wolof" }, { "xh", "Xhosa" },
00131 { "yi", "Yiddish" }, { "yo", "Yoruba" },
00132 { "za", "Zhuang" }, { "zh", "Chinese" },
00133 { "zu", "Zulu" }, { "xx", "Unknown" },
00134 { "\0", "Unknown" }
00135 };
00136
00137 static const char *audio_format[7] =
00138 {"ac3", "?", "mpeg1", "mpeg2", "lpcm ", "sdds ", "dts"};
00139 static int audio_id[7] = {0x80, 0, 0xC0, 0xC0, 0xA0, 0, 0x88};
00140
00141 DVDNavReader::DVDNavReader(String path)
00142 {
00143
00144
00145
00146
00147
00150 if (dvdnav_open(&dvd, path.c_str()) != DVDNAV_STATUS_OK)
00151 {
00152 throw _Exception(_("Could not open DVD ") + path);
00153 }
00154
00155 dvd_path = path;
00156
00157
00158
00159 if (dvdnav_set_PGC_positioning_flag(dvd, 1) != DVDNAV_STATUS_OK)
00160 {
00161 throw _Exception(_("Failed to set PGC positioning flag on DVD ") +
00162 path);
00163 }
00164
00165 log_debug("Opened DVD %s\n", dvd_path.c_str());
00166
00167 mutex = Ref<Mutex>(new Mutex(true));
00168
00169 EOT = true;
00170 }
00171
00172 DVDNavReader::~DVDNavReader()
00173 {
00174 if (dvd)
00175 dvdnav_close(dvd);
00176 log_debug("Closing DVD %s\n", dvd_path.c_str());
00177 }
00178
00179 int DVDNavReader::titleCount()
00180 {
00181 int32_t t;
00182 if (dvdnav_get_number_of_titles(dvd, &t) != DVDNAV_STATUS_OK)
00183 throw _Exception(_("Failed to get title count for DVD ") + dvd_path +
00184 " : " + dvdnav_err_to_string(dvd));
00185
00186 return t;
00187 }
00188
00189 int DVDNavReader::chapterCount(int title_idx)
00190 {
00191 int32_t c;
00192
00193 title_idx++;
00194
00195 if ((title_idx < 1) || (title_idx > titleCount()))
00196 throw _Exception(_("Requested title number exceeds available titles "
00197 "for DVD ") + dvd_path);
00198
00199 if (dvdnav_get_number_of_parts(dvd, title_idx, &c) != DVDNAV_STATUS_OK)
00200 throw _Exception(_("Failed to get chapter count for title ")
00201 + title_idx + " DVD " + dvd_path);
00202
00203 return c;
00204 }
00205
00206 void DVDNavReader::selectPGC(int title_idx, int chapter_idx)
00207 {
00208 title_idx++;
00209 chapter_idx++;
00210
00211 if ((title_idx < 1) || (title_idx > titleCount()))
00212 throw _Exception(_("Attmpted to select invalid title!"));
00213
00214 if ((chapter_idx < 1) || (chapter_idx > chapterCount(title_idx-1)))
00215 throw _Exception(_("Attempted to select invalid chapter!"));
00216
00217 AUTOLOCK(mutex);
00218
00219 if (dvdnav_part_play(dvd, title_idx, chapter_idx) != DVDNAV_STATUS_OK)
00220 {
00221 throw _Exception(_("Failed to select PGC for DVD ") + dvd_path + " : " +
00222 dvdnav_err_to_string(dvd));
00223 }
00224
00225 EOT = false;
00226 }
00227
00228 size_t DVDNavReader::readSector(unsigned char *buffer, size_t length)
00229 {
00230 AUTOLOCK(mutex);
00231
00232 unsigned char *p = buffer;
00233 size_t consumed = 0;
00234
00235 if (length < DVD_VIDEO_LB_LEN)
00236 throw _Exception(_("Buffer must be at least ") + DVD_VIDEO_LB_LEN);
00237
00238 while (!EOT)
00239 {
00240 int result, event, len;
00241
00242 result = dvdnav_get_next_block(dvd, (uint8_t *)p, &event, &len);
00243 if (result == DVDNAV_STATUS_ERR)
00244 {
00245 throw _Exception(_("Error getting next block for DVD ") + dvd_path +
00246 " : " + dvdnav_err_to_string(dvd));
00247 }
00248
00249 switch (event)
00250 {
00251 case DVDNAV_BLOCK_OK:
00252 consumed = consumed + len;
00253 if ((consumed + DVD_VIDEO_LB_LEN) > length)
00254 return consumed;
00255
00256 p = p + len;
00257 break;
00258 case DVDNAV_STILL_FRAME:
00259 {
00260 dvdnav_still_event_t *still_event;
00261 still_event = (dvdnav_still_event_t *)p;
00262 if (still_event->length == 0xff)
00263 dvdnav_still_skip(dvd);
00264 }
00265 break;
00266 case DVDNAV_WAIT:
00267 dvdnav_wait_skip(dvd);
00268 break;
00269 case DVDNAV_CELL_CHANGE:
00270 {
00271 int32_t tt = 0, ptt = 0;
00272 dvdnav_current_title_info(dvd, &tt, &ptt);
00273 if (tt == 0)
00274 {
00275 log_warning("Reached DVD menu, aborting.\n");
00276 EOT = true;
00277 return consumed;
00278 }
00279 }
00280 break;
00281 case DVDNAV_STOP:
00282 EOT = true;
00283 return consumed;
00284 break;
00285 case DVDNAV_NAV_PACKET:
00286 case DVDNAV_NOP:
00287 case DVDNAV_SPU_CLUT_CHANGE:
00288 case DVDNAV_SPU_STREAM_CHANGE:
00289 case DVDNAV_AUDIO_STREAM_CHANGE:
00290 case DVDNAV_HIGHLIGHT:
00291 case DVDNAV_VTS_CHANGE:
00292 case DVDNAV_HOP_CHANNEL:
00293 break;
00294 default:
00295 log_error("Uknown event when playing DVD %s\n", dvd_path.c_str());
00296 EOT = true;
00297 return -1;
00298 break;
00299 }
00300 }
00301 return 0;
00302 }
00303
00304 int DVDNavReader::audioTrackCount()
00305 {
00306 AUTOLOCK(mutex);
00307
00308 uint8_t count = 0;
00309 while (true)
00310 {
00311 if(dvdnav_get_audio_logical_stream(dvd, count) < 0)
00312 break;
00313
00314
00315
00316 if (count > 10)
00317 break;
00318
00319 count++;
00320 }
00321
00322 return (int)count;
00323 }
00324
00325
00326 String DVDNavReader::getLanguage(char *code)
00327 {
00328 int k = 0;
00329 while (memcmp(language[k].code, code, 2) && language[k].name[0] ) { k++; }
00330 return _(language[k].name);
00331 }
00332
00333 String DVDNavReader::audioLanguage(int stream_idx)
00334 {
00335 char code[3];
00336 audio_attr_t audio_attr;
00337
00338 AUTOLOCK(mutex);
00339
00340 if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
00341 throw _Exception(_("Error error retrieving audio language from DVD ") +
00342 dvd_path + " : " +
00343 dvdnav_err_to_string(dvd));
00344
00345 sprintf(code, "%c%c", audio_attr.lang_code >> 8,
00346 audio_attr.lang_code & 0xff);
00347
00348 if (!code[0])
00349 {
00350 code[0] = 'x';
00351 code[1] = 'x';
00352 }
00353
00354 return getLanguage(code);
00355 }
00356
00357 int DVDNavReader::audioSampleFrequency(int stream_idx)
00358 {
00359 audio_attr_t audio_attr;
00360
00361 AUTOLOCK(mutex);
00362
00363 if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
00364 throw _Exception(_("Error error retrieving audio language from DVD ") +
00365 dvd_path + " : " +
00366 dvdnav_err_to_string(dvd));
00367
00368 if (audio_attr.sample_frequency == 0)
00369 return 48000;
00370 else
00371 return 96000;
00372 }
00373
00374 int DVDNavReader::audioChannels(int stream_idx)
00375 {
00376 audio_attr_t audio_attr;
00377
00378 AUTOLOCK(mutex);
00379
00380 if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
00381 throw _Exception(_("Error error retrieving audio language from DVD ") +
00382 dvd_path + " : " +
00383 dvdnav_err_to_string(dvd));
00384
00385 return audio_attr.channels + 1;
00386 }
00387
00388 String DVDNavReader::audioFormat(int stream_idx)
00389 {
00390 audio_attr_t audio_attr;
00391
00392 AUTOLOCK(mutex);
00393
00394 if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
00395 throw _Exception(_("Error error retrieving audio language from DVD ") +
00396 dvd_path + " : " +
00397 dvdnav_err_to_string(dvd));
00398 return _(audio_format[audio_attr.audio_format]);
00399 }
00400
00401 int DVDNavReader::audioStreamID(int stream_idx)
00402 {
00403 audio_attr_t audio_attr;
00404
00405 AUTOLOCK(mutex);
00406
00407 if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
00408 throw _Exception(_("Error error retrieving audio language from DVD ") +
00409 dvd_path + " : " +
00410 dvdnav_err_to_string(dvd));
00411
00412 return audio_id[audio_attr.audio_format]+stream_idx;
00413 }
00414
00415 #endif//HAVE_LIBDVDNAV