3
MediaTomb - http://www.mediatomb.cc/
5
dvdnav_read.cc - this file is part of MediaTomb.
7
Copyright (C) 2005 Gena Batyan <bgeradz@mediatomb.cc>,
8
Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>
10
Copyright (C) 2006-2009 Gena Batyan <bgeradz@mediatomb.cc>,
11
Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>,
12
Leonhard Wimmer <leo@mediatomb.cc>
14
MediaTomb is free software; you can redistribute it and/or modify
15
it under the terms of the GNU General Public License version 2
16
as published by the Free Software Foundation.
18
MediaTomb is distributed in the hope that it will be useful,
19
but WITHOUT ANY WARRANTY; without even the implied warranty of
20
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
GNU General Public License for more details.
23
You should have received a copy of the GNU General Public License
24
version 2 along with MediaTomb; if not, write to the Free Software
25
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
31
Significant amounts of code were derived from the menus.c example
32
program which is part of libdvdnav.
34
menus.c is (C) 2003 by the libdvdnav project under GPLv2 or later.
36
The dvdtime2msec() function as well as some other parts which are marked
37
by comments were taken from lsdvd, (C) 2003 by Chris Phillips,
38
Henk Vergonet, licensed under GPL version 2.
41
/// \file dvdnav_read.cc
45
#include "autoconfig.h"
50
#include "dvdnav_read.h"
57
static double frames_per_s[4] = {-1.0, 25.00, -1.0, 29.97};
59
static struct { char code[3]; char name[20]; }
60
// from lsdvd, ISO-639
62
{ " ", "Not Specified" }, { "aa", "Afar" },
63
{ "ab", "Abkhazian" }, { "af", "Afrikaans" },
64
{ "am", "Amharic" }, { "ar", "Arabic" },
65
{ "as", "Assamese" }, { "ay", "Aymara" },
66
{ "az", "Azerbaijani" }, { "ba", "Bashkir" },
67
{ "be", "Byelorussian" }, { "bg", "Bulgarian" },
68
{ "bh", "Bihari" }, { "bi", "Bislama" },
69
{ "bn", "Bengali; Bangla" }, { "bo", "Tibetan" },
70
{ "br", "Breton" }, { "ca", "Catalan" },
71
{ "co", "Corsican" }, { "cs", "Czech" },
72
{ "cy", "Welsh" }, { "da", "Dansk" },
73
{ "de", "Deutsch" }, { "dz", "Bhutani" },
74
{ "el", "Greek" }, { "en", "English" },
75
{ "eo", "Esperanto" }, { "es", "Espanol" },
76
{ "et", "Estonian" }, { "eu", "Basque" },
77
{ "fa", "Persian" }, { "fi", "Suomi" },
78
{ "fj", "Fiji" }, { "fo", "Faroese" },
79
{ "fr", "Francais" }, { "fy", "Frisian" },
80
{ "ga", "Gaelic" }, { "gd", "Scots Gaelic" },
81
{ "gl", "Galician" }, { "gn", "Guarani" },
82
{ "gu", "Gujarati" }, { "ha", "Hausa" },
83
{ "he", "Hebrew" }, { "hi", "Hindi" },
84
{ "hr", "Hrvatski" }, { "hu", "Magyar" },
85
{ "hy", "Armenian" }, { "ia", "Interlingua" },
86
{ "id", "Indonesian" }, { "ie", "Interlingue" },
87
{ "ik", "Inupiak" }, { "in", "Indonesian" },
88
{ "is", "Islenska" }, { "it", "Italiano" },
89
{ "iu", "Inuktitut" }, { "iw", "Hebrew" },
90
{ "ja", "Japanese" }, { "ji", "Yiddish" },
91
{ "jw", "Javanese" }, { "ka", "Georgian" },
92
{ "kk", "Kazakh" }, { "kl", "Greenlandic" },
93
{ "km", "Cambodian" }, { "kn", "Kannada" },
94
{ "ko", "Korean" }, { "ks", "Kashmiri" },
95
{ "ku", "Kurdish" }, { "ky", "Kirghiz" },
96
{ "la", "Latin" }, { "ln", "Lingala" },
97
{ "lo", "Laothian" }, { "lt", "Lithuanian" },
98
{ "lv", "Latvian, Lettish" }, { "mg", "Malagasy" },
99
{ "mi", "Maori" }, { "mk", "Macedonian" },
100
{ "ml", "Malayalam" }, { "mn", "Mongolian" },
101
{ "mo", "Moldavian" }, { "mr", "Marathi" },
102
{ "ms", "Malay" }, { "mt", "Maltese" },
103
{ "my", "Burmese" }, { "na", "Nauru" },
104
{ "ne", "Nepali" }, { "nl", "Nederlands" },
105
{ "no", "Norsk" }, { "oc", "Occitan" },
106
{ "om", "Oromo" }, { "or", "Oriya" },
107
{ "pa", "Punjabi" }, { "pl", "Polish" },
108
{ "ps", "Pashto, Pushto" }, { "pt", "Portugues" },
109
{ "qu", "Quechua" }, { "rm", "Rhaeto-Romance" },
110
{ "rn", "Kirundi" }, { "ro", "Romanian" },
111
{ "ru", "Russian" }, { "rw", "Kinyarwanda" },
112
{ "sa", "Sanskrit" }, { "sd", "Sindhi" },
113
{ "sg", "Sangho" }, { "sh", "Serbo-Croatian" },
114
{ "si", "Sinhalese" }, { "sk", "Slovak" },
115
{ "sl", "Slovenian" }, { "sm", "Samoan" },
116
{ "sn", "Shona" }, { "so", "Somali" },
117
{ "sq", "Albanian" }, { "sr", "Serbian" },
118
{ "ss", "Siswati" }, { "st", "Sesotho" },
119
{ "su", "Sundanese" }, { "sv", "Svenska" },
120
{ "sw", "Swahili" }, { "ta", "Tamil" },
121
{ "te", "Telugu" }, { "tg", "Tajik" },
122
{ "th", "Thai" }, { "ti", "Tigrinya" },
123
{ "tk", "Turkmen" }, { "tl", "Tagalog" },
124
{ "tn", "Setswana" }, { "to", "Tonga" },
125
{ "tr", "Turkish" }, { "ts", "Tsonga" },
126
{ "tt", "Tatar" }, { "tw", "Twi" },
127
{ "ug", "Uighur" }, { "uk", "Ukrainian" },
128
{ "ur", "Urdu" }, { "uz", "Uzbek" },
129
{ "vi", "Vietnamese" }, { "vo", "Volapuk" },
130
{ "wo", "Wolof" }, { "xh", "Xhosa" },
131
{ "yi", "Yiddish" }, { "yo", "Yoruba" },
132
{ "za", "Zhuang" }, { "zh", "Chinese" },
133
{ "zu", "Zulu" }, { "xx", "Unknown" },
137
static const char *audio_format[7] =
138
{"ac3", "?", "mpeg1", "mpeg2", "lpcm ", "sdds ", "dts"};
139
static int audio_id[7] = {0x80, 0, 0xC0, 0xC0, 0xA0, 0, 0x88};
141
DVDNavReader::DVDNavReader(String path)
144
* Threads: this function uses chdir() and getcwd().
145
* The current working directory is global to all threads,
146
* so using chdir/getcwd in another thread could give unexpected results.
148
/// \todo check the implications of the above comment, do we use chdir()
150
if (dvdnav_open(&dvd, path.c_str()) != DVDNAV_STATUS_OK)
152
throw _Exception(_("Could not open DVD ") + path);
157
// set the PGC positioning flag to have position information relatively to
158
// the whole feature instead of just relatively to the current chapter
159
if (dvdnav_set_PGC_positioning_flag(dvd, 1) != DVDNAV_STATUS_OK)
161
throw _Exception(_("Failed to set PGC positioning flag on DVD ") +
165
log_debug("Opened DVD %s\n", dvd_path.c_str());
167
mutex = Ref<Mutex>(new Mutex(true));
172
DVDNavReader::~DVDNavReader()
176
log_debug("Closing DVD %s\n", dvd_path.c_str());
179
int DVDNavReader::titleCount()
182
if (dvdnav_get_number_of_titles(dvd, &t) != DVDNAV_STATUS_OK)
183
throw _Exception(_("Failed to get title count for DVD ") + dvd_path +
184
" : " + String(dvdnav_err_to_string(dvd)));
189
int DVDNavReader::chapterCount(int title_idx)
195
if ((title_idx < 1) || (title_idx > titleCount()))
196
throw _Exception(_("Requested title number exceeds available titles "
197
"for DVD ") + dvd_path);
199
if (dvdnav_get_number_of_parts(dvd, title_idx, &c) != DVDNAV_STATUS_OK)
200
throw _Exception(_("Failed to get chapter count for title ")
201
+ title_idx + " DVD " + dvd_path);
206
void DVDNavReader::selectPGC(int title_idx, int chapter_idx)
211
if ((title_idx < 1) || (title_idx > titleCount()))
212
throw _Exception(_("Attmpted to select invalid title!"));
214
if ((chapter_idx < 1) || (chapter_idx > chapterCount(title_idx-1)))
215
throw _Exception(_("Attempted to select invalid chapter!"));
219
if (dvdnav_part_play(dvd, title_idx, chapter_idx) != DVDNAV_STATUS_OK)
221
throw _Exception(_("Failed to select PGC for DVD ") + dvd_path + " : " +
222
String(dvdnav_err_to_string(dvd)));
228
size_t DVDNavReader::readSector(unsigned char *buffer, size_t length)
232
unsigned char *p = buffer;
235
if (length < DVD_VIDEO_LB_LEN)
236
throw _Exception(_("Buffer must be at least ") + DVD_VIDEO_LB_LEN);
240
int result, event, len;
242
result = dvdnav_get_next_block(dvd, (uint8_t *)p, &event, &len);
243
if (result == DVDNAV_STATUS_ERR)
245
throw _Exception(_("Error getting next block for DVD ") + dvd_path +
246
" : " + String(dvdnav_err_to_string(dvd)));
251
case DVDNAV_BLOCK_OK:
252
consumed = consumed + len;
253
if ((consumed + DVD_VIDEO_LB_LEN) > length)
258
case DVDNAV_STILL_FRAME:
260
dvdnav_still_event_t *still_event;
261
still_event = (dvdnav_still_event_t *)p;
262
if (still_event->length == 0xff)
263
dvdnav_still_skip(dvd);
267
dvdnav_wait_skip(dvd);
269
case DVDNAV_CELL_CHANGE:
271
int32_t tt = 0, ptt = 0;
272
dvdnav_current_title_info(dvd, &tt, &ptt);
275
log_warning("Reached DVD menu, aborting.\n");
285
case DVDNAV_NAV_PACKET:
287
case DVDNAV_SPU_CLUT_CHANGE:
288
case DVDNAV_SPU_STREAM_CHANGE:
289
case DVDNAV_AUDIO_STREAM_CHANGE:
290
case DVDNAV_HIGHLIGHT:
291
case DVDNAV_VTS_CHANGE:
292
case DVDNAV_HOP_CHANNEL:
295
log_error("Uknown event when playing DVD %s\n", dvd_path.c_str());
304
int DVDNavReader::audioTrackCount()
311
if(dvdnav_get_audio_logical_stream(dvd, count) < 0)
314
// afaik only 8 streams are supported?
315
// \todo check the exact amount of supported audio streams in the DVD
326
String DVDNavReader::getLanguage(char *code)
329
while (memcmp(language[k].code, code, 2) && language[k].name[0] ) { k++; }
330
return _(language[k].name);
333
String DVDNavReader::audioLanguage(int stream_idx)
336
audio_attr_t audio_attr;
340
if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
341
throw _Exception(_("Error error retrieving audio language from DVD ") +
343
String(dvdnav_err_to_string(dvd)));
345
sprintf(code, "%c%c", audio_attr.lang_code >> 8,
346
audio_attr.lang_code & 0xff);
354
return getLanguage(code);
357
int DVDNavReader::audioSampleFrequency(int stream_idx)
359
audio_attr_t audio_attr;
363
if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
364
throw _Exception(_("Error error retrieving audio language from DVD ") +
366
String(dvdnav_err_to_string(dvd)));
368
if (audio_attr.sample_frequency == 0)
374
int DVDNavReader::audioChannels(int stream_idx)
376
audio_attr_t audio_attr;
380
if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
381
throw _Exception(_("Error error retrieving audio language from DVD ") +
383
String(dvdnav_err_to_string(dvd)));
385
return audio_attr.channels + 1;
388
String DVDNavReader::audioFormat(int stream_idx)
390
audio_attr_t audio_attr;
394
if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
395
throw _Exception(_("Error error retrieving audio language from DVD ") +
397
String(dvdnav_err_to_string(dvd)));
398
return _(audio_format[audio_attr.audio_format]);
401
int DVDNavReader::audioStreamID(int stream_idx)
403
audio_attr_t audio_attr;
407
if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
408
throw _Exception(_("Error error retrieving audio language from DVD ") +
410
String(dvdnav_err_to_string(dvd)));
412
return audio_id[audio_attr.audio_format]+stream_idx;
415
#endif//HAVE_LIBDVDNAV