1 /*****************************************************************************
2 * bluray.c: Blu-ray disc support plugin
3 *****************************************************************************
4 * Copyright © 2010-2011 VideoLAN, VLC authors and libbluray AUTHORS
6 * Authors: Jean-Baptiste Kempf <jb@videolan.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
28 #include <limits.h> /* PATH_MAX */
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_demux.h> /* demux_t */
33 #include <vlc_input.h> /* Seekpoints, chapters */
34 #include <vlc_dialog.h> /* BD+/AACS warnings */
36 #include <libbluray/bluray.h>
37 #include <libbluray/meta_data.h>
39 /*****************************************************************************
41 *****************************************************************************/
44 static int blurayOpen ( vlc_object_t
* );
45 static void blurayClose( vlc_object_t
* );
48 set_shortname( N_("BluRay") )
49 set_description( N_("Blu-Ray Disc support (libbluray)") )
51 set_category( CAT_INPUT
)
52 set_subcategory( SUBCAT_INPUT_ACCESS
)
53 set_capability( "access_demux", 200)
55 add_shortcut( "bluray", "file" )
57 set_callbacks( blurayOpen
, blurayClose
)
67 unsigned int i_longest_title
;
68 input_title_t
**pp_title
;
74 /*****************************************************************************
76 *****************************************************************************/
77 static int blurayControl(demux_t
*, int, va_list);
78 static int blurayDemux (demux_t
*);
80 static int blurayInitTitles(demux_t
*p_demux
);
81 static int bluraySetTitle(demux_t
*p_demux
, int i_title
);
83 #define FROM_TICKS(a) (a*CLOCK_FREQ / INT64_C(90000))
84 #define TO_TICKS(a) (a*INT64_C(90000)/CLOCK_FREQ)
85 #define CUR_LENGTH p_sys->pp_title[p_demux->info.i_title]->i_length
87 /*****************************************************************************
88 * blurayOpen: module init function
89 *****************************************************************************/
90 static int blurayOpen( vlc_object_t
*object
)
92 demux_t
*p_demux
= (demux_t
*)object
;
97 char bd_path
[PATH_MAX
];
98 const char *error_msg
= NULL
;
100 if (strcmp(p_demux
->psz_access
, "bluray")) {
101 // TODO BDMV support, once we figure out what to do in libbluray
106 p_demux
->p_sys
= p_sys
= malloc(sizeof(*p_sys
));
107 if (unlikely(!p_sys
)) {
110 p_sys
->p_parser
= NULL
;
112 /* init demux info fields */
113 p_demux
->info
.i_update
= 0;
114 p_demux
->info
.i_title
= 0;
115 p_demux
->info
.i_seekpoint
= 0;
117 TAB_INIT( p_sys
->i_title
, p_sys
->pp_title
);
119 /* store current bd_path */
120 strncpy(bd_path
, p_demux
->psz_file
, sizeof(bd_path
));
121 bd_path
[PATH_MAX
- 1] = '\0';
123 p_sys
->bluray
= bd_open(bd_path
, NULL
);
124 if (!p_sys
->bluray
) {
129 /* Warning the user about AACS/BD+ */
130 const BLURAY_DISC_INFO
*disc_info
= bd_get_disc_info(p_sys
->bluray
);
131 msg_Info(p_demux
, "First play: %i, Top menu: %i\n"
132 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
133 disc_info
->first_play_supported
, disc_info
->top_menu_supported
,
134 disc_info
->num_hdmv_titles
, disc_info
->num_bdj_titles
,
135 disc_info
->num_unsupported_titles
);
138 if (disc_info
->aacs_detected
) {
139 if (!disc_info
->libaacs_detected
) {
140 error_msg
= _("This Blu-Ray Disc needs a library for AACS decoding, "
141 "and your system does not have it.");
144 if (!disc_info
->aacs_handled
) {
145 error_msg
= _("Your system AACS decoding library does not work. "
152 if (disc_info
->bdplus_detected
) {
153 if (!disc_info
->libbdplus_detected
) {
154 error_msg
= _("This Blu-Ray Disc needs a library for BD+ decoding, "
155 "and your system does not have it.");
158 if (!disc_info
->bdplus_handled
) {
159 error_msg
= _("Your system BD+ decoding library does not work. "
160 "Missing configuration?");
165 /* Get titles and chapters */
166 if (blurayInitTitles(p_demux
) != VLC_SUCCESS
) {
170 /* get title request */
171 if ((pos_title
= strrchr(bd_path
, ':'))) {
172 /* found character ':' for title information */
173 *(pos_title
++) = '\0';
174 i_title
= atoi(pos_title
);
177 /* set start title number */
178 if (bluraySetTitle(p_demux
, i_title
) != VLC_SUCCESS
) {
179 msg_Err( p_demux
, "Could not set the title %d", i_title
);
183 p_sys
->p_parser
= stream_DemuxNew(p_demux
, "ts", p_demux
->out
);
184 if (!p_sys
->p_parser
) {
185 msg_Err(p_demux
, "Failed to create TS demuxer");
189 p_demux
->pf_control
= blurayControl
;
190 p_demux
->pf_demux
= blurayDemux
;
196 dialog_Fatal(p_demux
, _("Blu-Ray error"), "%s", error_msg
);
202 /*****************************************************************************
203 * blurayClose: module destroy function
204 *****************************************************************************/
205 static void blurayClose( vlc_object_t
*object
)
207 demux_t
*p_demux
= (demux_t
*)object
;
208 demux_sys_t
*p_sys
= p_demux
->p_sys
;
211 stream_Delete(p_sys
->p_parser
);
214 for (unsigned int i
= 0; i
< p_sys
->i_title
; i
++)
215 vlc_input_title_Delete(p_sys
->pp_title
[i
]);
216 TAB_CLEAN( p_sys
->i_title
, p_sys
->pp_title
);
218 /* bd_close( NULL ) can crash */
219 assert(p_sys
->bluray
);
220 bd_close(p_sys
->bluray
);
225 static int blurayInitTitles(demux_t
*p_demux
)
227 demux_sys_t
*p_sys
= p_demux
->p_sys
;
229 /* get and set the titles */
230 unsigned i_title
= bd_get_titles(p_sys
->bluray
, TITLES_RELEVANT
, 60);
231 int64_t duration
= 0;
233 for (unsigned int i
= 0; i
< i_title
; i
++) {
234 input_title_t
*t
= vlc_input_title_New();
238 BLURAY_TITLE_INFO
*title_info
= bd_get_title_info(p_sys
->bluray
, i
, 0);
241 t
->i_length
= FROM_TICKS(title_info
->duration
);
243 if (t
->i_length
> duration
) {
244 duration
= t
->i_length
;
245 p_sys
->i_longest_title
= i
;
248 for ( unsigned int j
= 0; j
< title_info
->chapter_count
; j
++) {
249 seekpoint_t
*s
= vlc_seekpoint_New();
252 s
->i_time_offset
= title_info
->chapters
[j
].offset
;
254 TAB_APPEND( t
->i_seekpoint
, t
->seekpoint
, s
);
256 TAB_APPEND( p_sys
->i_title
, p_sys
->pp_title
, t
);
257 bd_free_title_info(title_info
);
263 /*****************************************************************************
264 * bluraySetTitle: select new BD title
265 *****************************************************************************/
266 static int bluraySetTitle(demux_t
*p_demux
, int i_title
)
268 demux_sys_t
*p_sys
= p_demux
->p_sys
;
270 /* Looking for the main title, ie the longest duration */
272 i_title
= p_sys
->i_longest_title
;
273 else if ((unsigned)i_title
> p_sys
->i_title
)
276 msg_Dbg( p_demux
, "Selecting Title %i", i_title
);
278 /* Select Blu-Ray title */
279 if (bd_select_title(p_demux
->p_sys
->bluray
, i_title
) == 0 ) {
280 msg_Err(p_demux
, "cannot select bd title '%d'", p_demux
->info
.i_title
);
284 /* read title info and init some values */
285 p_demux
->info
.i_title
= i_title
;
286 p_demux
->info
.i_seekpoint
= 0;
287 p_demux
->info
.i_update
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
293 /*****************************************************************************
294 * blurayControl: handle the controls
295 *****************************************************************************/
296 static int blurayControl(demux_t
*p_demux
, int query
, va_list args
)
298 demux_sys_t
*p_sys
= p_demux
->p_sys
;
304 case DEMUX_CAN_PAUSE
:
305 case DEMUX_CAN_CONTROL_PACE
:
306 pb_bool
= (bool*)va_arg( args
, bool * );
310 case DEMUX_GET_PTS_DELAY
:
311 pi_64
= (int64_t*)va_arg( args
, int64_t * );
313 INT64_C(1000) * var_InheritInteger( p_demux
, "disc-caching" );
316 case DEMUX_SET_PAUSE_STATE
:
320 case DEMUX_SET_TITLE
:
322 int i_title
= (int)va_arg( args
, int );
323 if (bluraySetTitle(p_demux
, i_title
) != VLC_SUCCESS
)
327 case DEMUX_SET_SEEKPOINT
:
329 int i_chapter
= (int)va_arg( args
, int );
330 bd_seek_chapter( p_sys
->bluray
, i_chapter
);
331 p_demux
->info
.i_update
= INPUT_UPDATE_SEEKPOINT
;
335 case DEMUX_GET_TITLE_INFO
:
337 input_title_t
***ppp_title
= (input_title_t
***)va_arg( args
, input_title_t
*** );
338 int *pi_int
= (int*)va_arg( args
, int* );
339 int *pi_title_offset
= (int*)va_arg( args
, int* );
340 int *pi_chapter_offset
= (int*)va_arg( args
, int* );
343 *pi_title_offset
= 0;
344 *pi_chapter_offset
= 0;
346 /* Duplicate local title infos */
347 *pi_int
= p_sys
->i_title
;
348 *ppp_title
= calloc( p_sys
->i_title
, sizeof(input_title_t
**) );
349 for( unsigned int i
= 0; i
< p_sys
->i_title
; i
++ )
350 (*ppp_title
)[i
] = vlc_input_title_Duplicate( p_sys
->pp_title
[i
]);
355 case DEMUX_GET_LENGTH
:
357 int64_t *pi_length
= (int64_t*)va_arg(args
, int64_t *);
358 *pi_length
= CUR_LENGTH
;
363 int64_t i_time
= (int64_t)va_arg(args
, int64_t);
364 bd_seek_time(p_sys
->bluray
, TO_TICKS(i_time
));
369 int64_t *pi_time
= (int64_t*)va_arg(args
, int64_t *);
370 *pi_time
= (int64_t)FROM_TICKS(bd_tell_time(p_sys
->bluray
));
374 case DEMUX_GET_POSITION
:
376 double *pf_position
= (double*)va_arg( args
, double * );
377 *pf_position
= (double)FROM_TICKS(bd_tell_time(p_sys
->bluray
))/CUR_LENGTH
;
380 case DEMUX_SET_POSITION
:
382 double f_position
= (double)va_arg(args
, double);
383 bd_seek_time(p_sys
->bluray
, TO_TICKS(f_position
*CUR_LENGTH
));
389 struct meta_dl
*meta
= bd_get_meta(p_sys
->bluray
);
390 vlc_meta_t
*p_meta
= (vlc_meta_t
*) va_arg (args
, vlc_meta_t
*);
392 if (!EMPTY_STR(meta
->di_name
)) vlc_meta_SetTitle(p_meta
, meta
->di_name
);
394 if (!EMPTY_STR(meta
->language_code
)) vlc_meta_AddExtra(p_meta
, "Language", meta
->language_code
);
395 if (!EMPTY_STR(meta
->filename
)) vlc_meta_AddExtra(p_meta
, "Filename", meta
->filename
);
396 if (!EMPTY_STR(meta
->di_alternative
)) vlc_meta_AddExtra(p_meta
, "Alternative", meta
->di_alternative
);
398 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
399 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
401 if (meta
->thumb_count
> 0 && meta
->thumbnails
) {
402 vlc_meta_SetArtURL(p_meta
, meta
->thumbnails
[0].path
);
408 case DEMUX_CAN_RECORD
:
410 case DEMUX_SET_GROUP
:
411 case DEMUX_HAS_UNSUPPORTED_META
:
412 case DEMUX_GET_ATTACHMENTS
:
415 msg_Warn( p_demux
, "unimplemented query (%d) in control", query
);
422 #define BD_TS_PACKET_SIZE (192)
423 #define NB_TS_PACKETS (200)
425 static int blurayDemux(demux_t
*p_demux
)
427 demux_sys_t
*p_sys
= p_demux
->p_sys
;
429 block_t
*p_block
= block_New(p_demux
, NB_TS_PACKETS
* (int64_t)BD_TS_PACKET_SIZE
);
434 int nread
= bd_read(p_sys
->bluray
, p_block
->p_buffer
,
435 NB_TS_PACKETS
* BD_TS_PACKET_SIZE
);
437 block_Release(p_block
);
441 p_block
->i_buffer
= nread
;
443 stream_DemuxSend( p_sys
->p_parser
, p_block
);