~vanvugt/ubuntu/oneiric/mediatomb/fix-770964-784431

« back to all changes in this revision

Viewing changes to src/dvdnav_read.cc

  • Committer: Bazaar Package Importer
  • Author(s): Andres Mejia
  • Date: 2009-04-22 21:39:19 UTC
  • mto: (4.2.1 sid)
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20090422213919-52m015y6gcpv1m1g
Tags: upstream-0.12.0~svn2018
ImportĀ upstreamĀ versionĀ 0.12.0~svn2018

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*MT*
 
2
    
 
3
    MediaTomb - http://www.mediatomb.cc/
 
4
    
 
5
    dvdnav_read.cc - this file is part of MediaTomb.
 
6
    
 
7
    Copyright (C) 2005 Gena Batyan <bgeradz@mediatomb.cc>,
 
8
                       Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>
 
9
    
 
10
    Copyright (C) 2006-2009 Gena Batyan <bgeradz@mediatomb.cc>,
 
11
                            Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>,
 
12
                            Leonhard Wimmer <leo@mediatomb.cc>
 
13
    
 
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.
 
17
    
 
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.
 
22
    
 
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.
 
26
    
 
27
    $Id$
 
28
*/
 
29
 
 
30
/*
 
31
    Significant amounts of code were derived from the menus.c example
 
32
    program which is part of libdvdnav.
 
33
 
 
34
    menus.c is (C) 2003 by the libdvdnav project under GPLv2 or later.
 
35
 
 
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.
 
39
 */
 
40
 
 
41
/// \file dvdnav_read.cc
 
42
 
 
43
 
 
44
#ifdef HAVE_CONFIG_H
 
45
    #include "autoconfig.h"
 
46
#endif
 
47
 
 
48
#ifdef HAVE_LIBDVDNAV
 
49
 
 
50
#include "dvdnav_read.h"
 
51
#include <assert.h>
 
52
 
 
53
#include "tools.h"
 
54
 
 
55
using namespace zmm;
 
56
 
 
57
static double frames_per_s[4] = {-1.0, 25.00, -1.0, 29.97};
 
58
 
 
59
static struct { char code[3]; char name[20]; }
 
60
// from lsdvd, ISO-639
 
61
language[] = {
 
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"        }, 
 
134
    { "\0", "Unknown" } 
 
135
};
 
136
 
 
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};
 
140
 
 
141
DVDNavReader::DVDNavReader(String path)
 
142
{
 
143
    /*
 
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.
 
147
     */
 
148
    /// \todo check the implications of the above comment, do we use chdir()
 
149
    /// somewhere?
 
150
    if (dvdnav_open(&dvd, path.c_str()) != DVDNAV_STATUS_OK)
 
151
    {
 
152
        throw _Exception(_("Could not open DVD ") + path);
 
153
    }
 
154
 
 
155
    dvd_path = path;
 
156
 
 
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)
 
160
    {
 
161
        throw _Exception(_("Failed to set PGC positioning flag on DVD ") + 
 
162
                          path);
 
163
    }
 
164
 
 
165
    log_debug("Opened DVD %s\n", dvd_path.c_str());
 
166
 
 
167
    mutex = Ref<Mutex>(new Mutex(true));
 
168
 
 
169
    EOT = true;
 
170
}
 
171
 
 
172
DVDNavReader::~DVDNavReader()
 
173
{
 
174
    if (dvd)
 
175
        dvdnav_close(dvd);
 
176
    log_debug("Closing DVD %s\n", dvd_path.c_str());
 
177
}
 
178
 
 
179
int DVDNavReader::titleCount()
 
180
{
 
181
   int32_t t;
 
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)));
 
185
 
 
186
    return t;
 
187
}
 
188
 
 
189
int DVDNavReader::chapterCount(int title_idx)
 
190
{
 
191
    int32_t c;
 
192
 
 
193
    title_idx++;
 
194
 
 
195
    if ((title_idx < 1) || (title_idx > titleCount()))
 
196
        throw _Exception(_("Requested title number exceeds available titles "
 
197
                    "for DVD ") + dvd_path);
 
198
 
 
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);
 
202
 
 
203
    return c;
 
204
}
 
205
 
 
206
void DVDNavReader::selectPGC(int title_idx, int chapter_idx)
 
207
{
 
208
    title_idx++;
 
209
    chapter_idx++;
 
210
 
 
211
    if ((title_idx < 1) || (title_idx > titleCount()))
 
212
        throw _Exception(_("Attmpted to select invalid title!"));
 
213
 
 
214
    if ((chapter_idx < 1) || (chapter_idx > chapterCount(title_idx-1)))
 
215
        throw _Exception(_("Attempted to select invalid chapter!"));
 
216
 
 
217
    AUTOLOCK(mutex);
 
218
 
 
219
   if (dvdnav_part_play(dvd, title_idx, chapter_idx) != DVDNAV_STATUS_OK)
 
220
   {
 
221
       throw _Exception(_("Failed to select PGC for DVD ") + dvd_path + " : " +
 
222
                         String(dvdnav_err_to_string(dvd)));
 
223
   }
 
224
 
 
225
   EOT = false;
 
226
}
 
227
 
 
228
size_t DVDNavReader::readSector(unsigned char *buffer, size_t length)
 
229
{
 
230
    AUTOLOCK(mutex);
 
231
 
 
232
    unsigned char *p = buffer;
 
233
    size_t consumed = 0;
 
234
 
 
235
    if (length < DVD_VIDEO_LB_LEN)
 
236
        throw _Exception(_("Buffer must be at least ") + DVD_VIDEO_LB_LEN);
 
237
 
 
238
    while (!EOT)
 
239
    {
 
240
        int result, event, len;
 
241
 
 
242
        result = dvdnav_get_next_block(dvd, (uint8_t *)p, &event, &len);
 
243
        if (result == DVDNAV_STATUS_ERR)
 
244
        {
 
245
            throw _Exception(_("Error getting next block for DVD ") + dvd_path +
 
246
                               " : " + String(dvdnav_err_to_string(dvd)));
 
247
        }
 
248
 
 
249
        switch (event)
 
250
        {
 
251
            case DVDNAV_BLOCK_OK:
 
252
                consumed = consumed + len;
 
253
                if ((consumed + DVD_VIDEO_LB_LEN) > length)
 
254
                    return consumed;
 
255
                    
 
256
                p = p + len;
 
257
                break;
 
258
            case DVDNAV_STILL_FRAME:
 
259
                {
 
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);
 
264
                }
 
265
                break;
 
266
            case DVDNAV_WAIT:
 
267
                dvdnav_wait_skip(dvd);
 
268
                break;
 
269
            case DVDNAV_CELL_CHANGE:
 
270
                {
 
271
                    int32_t tt = 0, ptt = 0;
 
272
                    dvdnav_current_title_info(dvd, &tt, &ptt);
 
273
                    if (tt == 0)
 
274
                    {
 
275
                        log_warning("Reached DVD menu, aborting.\n");
 
276
                        EOT = true;
 
277
                        return consumed;
 
278
                    }
 
279
                }
 
280
                break;
 
281
            case DVDNAV_STOP:
 
282
                EOT = true;
 
283
                return consumed;
 
284
                break;
 
285
            case DVDNAV_NAV_PACKET:
 
286
            case DVDNAV_NOP:
 
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:
 
293
                break;
 
294
            default:
 
295
                log_error("Uknown event when playing DVD %s\n", dvd_path.c_str());
 
296
                EOT = true;
 
297
                return -1;
 
298
                break;
 
299
        }
 
300
    }
 
301
    return 0;
 
302
}
 
303
 
 
304
int DVDNavReader::audioTrackCount()
 
305
{
 
306
    AUTOLOCK(mutex);
 
307
 
 
308
    uint8_t count = 0;
 
309
    while (true)
 
310
    {
 
311
        if(dvdnav_get_audio_logical_stream(dvd, count) < 0)
 
312
            break;
 
313
 
 
314
        // afaik only 8 streams are supported?
 
315
        // \todo check the exact amount of supported audio streams in the DVD
 
316
        if (count > 10)
 
317
            break;
 
318
 
 
319
        count++;
 
320
    }
 
321
 
 
322
    return (int)count;
 
323
}
 
324
 
 
325
// from lsdvd
 
326
String DVDNavReader::getLanguage(char *code)
 
327
{
 
328
    int k = 0;
 
329
    while (memcmp(language[k].code, code, 2) && language[k].name[0] ) { k++; }
 
330
    return _(language[k].name);
 
331
}
 
332
 
 
333
String DVDNavReader::audioLanguage(int stream_idx)
 
334
{
 
335
    char code[3];
 
336
    audio_attr_t audio_attr;
 
337
    
 
338
    AUTOLOCK(mutex);
 
339
 
 
340
    if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
 
341
        throw _Exception(_("Error error retrieving audio language from DVD ") +
 
342
                           dvd_path + " : " + 
 
343
                           String(dvdnav_err_to_string(dvd)));
 
344
 
 
345
    sprintf(code, "%c%c", audio_attr.lang_code >> 8, 
 
346
                          audio_attr.lang_code & 0xff);
 
347
    
 
348
    if (!code[0])
 
349
    { 
 
350
        code[0] = 'x'; 
 
351
        code[1] = 'x'; 
 
352
    }
 
353
 
 
354
    return getLanguage(code);
 
355
}
 
356
 
 
357
int DVDNavReader::audioSampleFrequency(int stream_idx)
 
358
{
 
359
    audio_attr_t audio_attr;
 
360
    
 
361
    AUTOLOCK(mutex);
 
362
    
 
363
    if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
 
364
        throw _Exception(_("Error error retrieving audio language from DVD ") +
 
365
                           dvd_path + " : " + 
 
366
                           String(dvdnav_err_to_string(dvd)));
 
367
 
 
368
    if (audio_attr.sample_frequency == 0)
 
369
        return 48000;
 
370
    else
 
371
        return 96000;
 
372
}
 
373
 
 
374
int DVDNavReader::audioChannels(int stream_idx)
 
375
{
 
376
    audio_attr_t audio_attr;
 
377
   
 
378
    AUTOLOCK(mutex);
 
379
 
 
380
    if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
 
381
        throw _Exception(_("Error error retrieving audio language from DVD ") +
 
382
                           dvd_path + " : " + 
 
383
                           String(dvdnav_err_to_string(dvd)));
 
384
 
 
385
    return audio_attr.channels + 1;
 
386
}
 
387
 
 
388
String DVDNavReader::audioFormat(int stream_idx)
 
389
{
 
390
    audio_attr_t audio_attr;
 
391
    
 
392
    AUTOLOCK(mutex);
 
393
    
 
394
    if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
 
395
        throw _Exception(_("Error error retrieving audio language from DVD ") +
 
396
                           dvd_path + " : " +
 
397
                           String(dvdnav_err_to_string(dvd)));
 
398
    return _(audio_format[audio_attr.audio_format]);
 
399
}
 
400
 
 
401
int DVDNavReader::audioStreamID(int stream_idx)
 
402
{
 
403
    audio_attr_t audio_attr;
 
404
 
 
405
    AUTOLOCK(mutex);
 
406
    
 
407
    if (dvdnav_get_audio_attr(dvd, stream_idx, &audio_attr) != DVDNAV_STATUS_OK)
 
408
        throw _Exception(_("Error error retrieving audio language from DVD ") +
 
409
                           dvd_path + " : " +
 
410
                           String(dvdnav_err_to_string(dvd)));
 
411
 
 
412
    return audio_id[audio_attr.audio_format]+stream_idx;
 
413
}
 
414
 
 
415
#endif//HAVE_LIBDVDNAV
 
416