]> git.sesse.net Git - vlc/blob - modules/access/bluray.c
bluray: fix compilation according to last libbluray commits. (the values can be tuned).
[vlc] / modules / access / bluray.c
1 /*****************************************************************************
2  * bluray.c: Blu-ray disc support plugin
3  *****************************************************************************
4  * Copyright (C) 2010 VideoLAN, VLC authors and libbluray AUTHORS
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #ifdef HAVE_SYS_STAT_H
26 #   include <sys/stat.h>
27 #endif
28
29 #include <assert.h>
30 #include <limits.h>
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_access.h>
35 #include <vlc_messages.h>
36 #include <vlc_input.h>
37 #include <vlc_dialog.h>
38
39 #include <libbluray/bluray.h>
40
41 /*****************************************************************************
42  * Module descriptor
43  *****************************************************************************/
44 #define CACHING_TEXT N_("Caching value in ms")
45 #define CACHING_LONGTEXT N_( "Caching value for BDs. This "\
46                              "value should be set in milliseconds." )
47
48 /* Callbacks */
49 static int  blurayOpen ( vlc_object_t * );
50 static void blurayClose( vlc_object_t * );
51
52 vlc_module_begin ()
53     set_shortname( N_("BluRay") )
54     set_description( N_("Blu-Ray Disc support (libbluray)") )
55
56     set_category( CAT_INPUT )
57     set_subcategory( SUBCAT_INPUT_ACCESS )
58     set_capability( "access", 60 )
59
60     add_integer( "bluray-caching", 1000,
61         CACHING_TEXT, CACHING_LONGTEXT, true )
62
63     add_shortcut( "bluray" )
64     add_shortcut( "file" )
65
66     set_callbacks( blurayOpen, blurayClose )
67 vlc_module_end ()
68
69 /*****************************************************************************
70  * Local prototypes
71  *****************************************************************************/
72
73 struct access_sys_t
74 {
75     BLURAY *bluray; /* */
76
77     /* Titles */
78     unsigned int i_title;
79     unsigned int i_longest_title;
80     input_title_t   **pp_title;
81
82     int i_bd_delay;
83 };
84
85 static ssize_t blurayRead   (access_t *, uint8_t *, size_t);
86 static int     bluraySeek   (access_t *, uint64_t);
87 static int     blurayControl(access_t *, int, va_list);
88 static int     blurayInitTitles(access_t *p_access );
89 static int     bluraySetTitle(access_t *p_access, int i_title);
90
91 /*****************************************************************************
92  * blurayOpen: module init function
93  *****************************************************************************/
94 static int blurayOpen( vlc_object_t *object )
95 {
96     access_t *p_access = (access_t*)object;
97
98     access_sys_t *p_sys;
99     char *pos_title;
100     int i_title = -1;
101     char bd_path[PATH_MAX];
102
103     if( strcmp( p_access->psz_access, "bluray" ) ) {
104         // TODO BDMV support, once we figure out what to do in libbluray
105         return VLC_EGENERIC;
106     }
107
108     /* init access fields */
109     access_InitFields(p_access);
110
111     /* register callback function for communication */
112     ACCESS_SET_CALLBACKS(blurayRead, NULL, blurayControl, bluraySeek);
113
114     p_access->p_sys = p_sys = malloc(sizeof(access_sys_t));
115     if (unlikely(!p_sys)) {
116         return VLC_ENOMEM;
117     }
118
119     TAB_INIT( p_sys->i_title, p_sys->pp_title );
120
121     /* store current bd_path */
122     strncpy(bd_path, p_access->psz_location, sizeof(bd_path));
123     bd_path[PATH_MAX - 1] = '\0';
124
125     p_sys->bluray = bd_open(bd_path, NULL);
126     if ( !p_sys->bluray ) {
127         free(p_sys);
128         return VLC_EGENERIC;
129     }
130
131     /* Warning the user about AACS/BD+ */
132     const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
133     msg_Dbg (p_access, "First play: %i, Top menu: %i\n"
134                        "HDMV Titles: %i, BDJ Titles: %i, Other: %i",
135              disc_info->first_play_supported, disc_info->top_menu_supported,
136              disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
137              disc_info->num_unsupported_titles);
138
139     /* AACS */
140     if (disc_info->aacs_detected) {
141         if (!disc_info->libaacs_detected) {
142             dialog_Fatal (p_access, _("Blu-Ray error"),
143                     _("This Blu-Ray Disc needs a library for AACS decoding, "
144                       "and your system does not have it."));
145             blurayClose(object);
146             return VLC_EGENERIC;
147         }
148         if (!disc_info->aacs_handled) {
149             dialog_Fatal (p_access, _("Blu-Ray error"),
150                     _("Your system AACS decoding library does not work. "
151                       "Missing keys?"));
152             blurayClose(object);
153             return VLC_EGENERIC;
154         }
155     }
156
157     /* BD+ */
158     if (disc_info->bdplus_detected) {
159         if (!disc_info->libbdplus_detected) {
160             dialog_Fatal (p_access, _("Blu-Ray error"),
161                     _("This Blu-Ray Disc needs a library for BD+ decoding, "
162                       "and your system does not have it."));
163             blurayClose(object);
164             return VLC_EGENERIC;
165         }
166         if (!disc_info->bdplus_handled) {
167             dialog_Fatal (p_access, _("Blu-Ray error"),
168                     _("Your system BD+ decoding library does not work. "
169                       "Missing configuration?"));
170             blurayClose(object);
171             return VLC_EGENERIC;
172         }
173     }
174
175     /* Get titles and chapters */
176     if (blurayInitTitles(p_access) != VLC_SUCCESS) {
177         blurayClose(object);
178         return VLC_EGENERIC;
179     }
180
181     /* get title request */
182     if ( (pos_title = strrchr(bd_path, ':')) ) {
183         /* found character ':' for title information */
184         *(pos_title++) = '\0';
185         i_title = atoi(pos_title);
186     }
187
188     /* set start title number */
189     if ( bluraySetTitle(p_access, i_title) != VLC_SUCCESS ) {
190         msg_Err( p_access, "Could not set the title %d", i_title );
191         blurayClose(object);
192         return VLC_EGENERIC;
193     }
194
195     p_sys->i_bd_delay = var_InheritInteger(p_access, "bluray-caching");
196
197     return VLC_SUCCESS;
198 }
199
200
201 /*****************************************************************************
202  * blurayClose: module destroy function
203  *****************************************************************************/
204 static void blurayClose( vlc_object_t *object )
205 {
206     access_t *p_access = (access_t*)object;
207     access_sys_t *p_sys = p_access->p_sys;
208
209     /* Titles */
210     for (unsigned int i = 0; i < p_sys->i_title; i++)
211         vlc_input_title_Delete(p_sys->pp_title[i]);
212     TAB_CLEAN( p_sys->i_title, p_sys->pp_title );
213
214     /* bd_close( NULL ) can crash */
215     assert(p_sys->bluray);
216     bd_close(p_sys->bluray);
217     free(p_sys);
218 }
219
220 static int blurayInitTitles(access_t *p_access )
221 {
222     access_sys_t *p_sys = p_access->p_sys;
223
224     /* get and set the titles */
225     unsigned i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 0);
226     int64_t duration = 0;
227
228     for (unsigned int i = 0; i < i_title; i++) {
229         input_title_t *t = vlc_input_title_New();
230         if (!t)
231             break;
232
233         BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
234         if (!title_info)
235             break;
236         t->i_length = title_info->duration * CLOCK_FREQ / INT64_C(90000);
237
238         if (t->i_length > duration) {
239             duration = t->i_length;
240             p_sys->i_longest_title = i;
241         }
242
243         for ( unsigned int j = 0; j < title_info->chapter_count; j++) {
244             seekpoint_t *s = vlc_seekpoint_New();
245             if( !s )
246                 break;
247             s->i_time_offset = title_info->chapters[j].offset;
248
249             TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
250         }
251         TAB_APPEND( p_sys->i_title, p_sys->pp_title, t );
252         bd_free_title_info(title_info);
253     }
254     return VLC_SUCCESS;
255 }
256
257 /*****************************************************************************
258  * bluraySetTitle: select new BD title
259  *****************************************************************************/
260 static int bluraySetTitle(access_t *p_access, int i_title)
261 {
262     access_sys_t *p_sys = p_access->p_sys;
263
264     /* Looking for the main title, ie the longest duration */
265     if (i_title == -1)
266         i_title = p_sys->i_longest_title;
267
268     msg_Dbg( p_access, "Selecting Title %i", i_title);
269
270     /* Select Blu-Ray title */
271     if ( bd_select_title(p_access->p_sys->bluray, i_title) == 0 ) {
272         msg_Err( p_access, "cannot select bd title '%d'", p_access->info.i_title);
273         return VLC_EGENERIC;
274     }
275
276     /* read title length and init some values */
277     p_access->info.i_title = i_title;
278     p_access->info.i_size  = bd_get_title_size(p_sys->bluray);
279     p_access->info.i_pos   = 0;
280     p_access->info.b_eof   = false;
281     p_access->info.i_seekpoint = 0;
282     p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
283
284     return VLC_SUCCESS;
285 }
286
287
288 /*****************************************************************************
289  * blurayControl: handle the controls
290  *****************************************************************************/
291 static int blurayControl(access_t *p_access, int query, va_list args)
292 {
293     access_sys_t *p_sys = p_access->p_sys;
294     bool     *pb_bool;
295     int64_t  *pi_64;
296
297     switch (query) {
298         case ACCESS_CAN_SEEK:
299         case ACCESS_CAN_FASTSEEK:
300         case ACCESS_CAN_PAUSE:
301         case ACCESS_CAN_CONTROL_PACE:
302              pb_bool = (bool*)va_arg( args, bool * );
303              *pb_bool = true;
304              break;
305
306         case ACCESS_GET_PTS_DELAY:
307             pi_64 = (int64_t*)va_arg( args, int64_t * );
308             *pi_64 = p_sys->i_bd_delay;
309             break;
310
311         case ACCESS_SET_PAUSE_STATE:
312             /* Nothing to do */
313             break;
314
315         case ACCESS_SET_TITLE:
316         {
317             int i_title = (int)va_arg( args, int );
318             if( bluraySetTitle( p_access, i_title ) != VLC_SUCCESS )
319                 return VLC_EGENERIC;
320             break;
321         }
322         case ACCESS_SET_SEEKPOINT:
323         {
324             int i_chapter = (int)va_arg( args, int );
325             bd_seek_chapter( p_sys->bluray, i_chapter );
326             p_access->info.i_update = INPUT_UPDATE_SEEKPOINT;
327             break;
328         }
329
330         case ACCESS_GET_TITLE_INFO:
331         {
332             input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
333             int *pi_int             = (int*)va_arg( args, int* );
334             int *pi_title_offset    = (int*)va_arg( args, int* );
335             int *pi_chapter_offset  = (int*)va_arg( args, int* );
336
337             /* */
338             *pi_title_offset   = 0;
339             *pi_chapter_offset = 0;
340
341             /* Duplicate local title infos */
342             *pi_int = p_sys->i_title;
343             *ppp_title = calloc( p_sys->i_title, sizeof(input_title_t **) );
344             for( unsigned int i = 0; i < p_sys->i_title; i++ )
345                 (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->pp_title[i]);
346
347             return VLC_SUCCESS;
348         }
349         case ACCESS_SET_PRIVATE_ID_STATE:
350         case ACCESS_GET_CONTENT_TYPE:
351         case ACCESS_GET_META:
352             return VLC_EGENERIC;
353
354         default:
355             msg_Warn( p_access, "unimplemented query (%d) in control", query );
356             return VLC_EGENERIC;
357     }
358
359     return VLC_SUCCESS;
360 }
361
362
363 /*****************************************************************************
364  * bluraySeek: seek to the given position
365  *****************************************************************************/
366 static int bluraySeek(access_t *p_access, uint64_t position)
367 {
368     access_sys_t *p_sys = p_access->p_sys;
369
370     p_access->info.i_pos = bd_seek(p_sys->bluray, position);
371     p_access->info.b_eof = false;
372
373     return VLC_SUCCESS;
374 }
375
376
377 /*****************************************************************************
378  * blurayRead: read BD data into buffer
379  *****************************************************************************/
380 static ssize_t blurayRead(access_t *p_access, uint8_t *data, size_t size)
381 {
382     access_sys_t *p_sys = p_access->p_sys;
383     int nread;
384
385     if (p_access->info.b_eof) {
386         return 0;
387     }
388
389     /* read data into buffer with given length */
390     nread = bd_read(p_sys->bluray, data, size);
391
392     if( nread == 0 ) {
393         p_access->info.b_eof = true;
394     }
395     else if( nread > 0 ) {
396         p_access->info.i_pos += nread;
397     }
398
399     return nread;
400 }
401