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
];
99 if (strcmp(p_demux
->psz_access
, "bluray")) {
100 // TODO BDMV support, once we figure out what to do in libbluray
105 p_demux
->p_sys
= p_sys
= malloc(sizeof(*p_sys
));
106 if (unlikely(!p_sys
)) {
109 p_sys
->p_parser
= NULL
;
111 /* init demux info fields */
112 p_demux
->info
.i_update
= 0;
113 p_demux
->info
.i_title
= 0;
114 p_demux
->info
.i_seekpoint
= 0;
116 TAB_INIT( p_sys
->i_title
, p_sys
->pp_title
);
118 /* store current bd_path */
119 strncpy(bd_path
, p_demux
->psz_file
, sizeof(bd_path
));
120 bd_path
[PATH_MAX
- 1] = '\0';
122 p_sys
->bluray
= bd_open(bd_path
, NULL
);
123 if (!p_sys
->bluray
) {
128 /* Warning the user about AACS/BD+ */
129 const BLURAY_DISC_INFO
*disc_info
= bd_get_disc_info(p_sys
->bluray
);
130 msg_Info(p_demux
, "First play: %i, Top menu: %i\n"
131 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
132 disc_info
->first_play_supported
, disc_info
->top_menu_supported
,
133 disc_info
->num_hdmv_titles
, disc_info
->num_bdj_titles
,
134 disc_info
->num_unsupported_titles
);
137 if (disc_info
->aacs_detected
) {
138 if (!disc_info
->libaacs_detected
) {
139 dialog_Fatal (p_demux
, _("Blu-Ray error"),
140 _("This Blu-Ray Disc needs a library for AACS decoding, "
141 "and your system does not have it."));
145 if (!disc_info
->aacs_handled
) {
146 dialog_Fatal (p_demux
, _("Blu-Ray error"),
147 _("Your system AACS decoding library does not work. "
155 if (disc_info
->bdplus_detected
) {
156 if (!disc_info
->libbdplus_detected
) {
157 dialog_Fatal (p_demux
, _("Blu-Ray error"),
158 _("This Blu-Ray Disc needs a library for BD+ decoding, "
159 "and your system does not have it."));
163 if (!disc_info
->bdplus_handled
) {
164 dialog_Fatal (p_demux
, _("Blu-Ray error"),
165 _("Your system BD+ decoding library does not work. "
166 "Missing configuration?"));
172 /* Get titles and chapters */
173 if (blurayInitTitles(p_demux
) != VLC_SUCCESS
) {
178 /* get title request */
179 if ((pos_title
= strrchr(bd_path
, ':'))) {
180 /* found character ':' for title information */
181 *(pos_title
++) = '\0';
182 i_title
= atoi(pos_title
);
185 /* set start title number */
186 if (bluraySetTitle(p_demux
, i_title
) != VLC_SUCCESS
) {
187 msg_Err( p_demux
, "Could not set the title %d", i_title
);
192 p_sys
->p_parser
= stream_DemuxNew(p_demux
, "ts", p_demux
->out
);
193 if (!p_sys
->p_parser
) {
194 msg_Err(p_demux
, "Failed to create TS demuxer");
199 p_demux
->pf_control
= blurayControl
;
200 p_demux
->pf_demux
= blurayDemux
;
206 /*****************************************************************************
207 * blurayClose: module destroy function
208 *****************************************************************************/
209 static void blurayClose( vlc_object_t
*object
)
211 demux_t
*p_demux
= (demux_t
*)object
;
212 demux_sys_t
*p_sys
= p_demux
->p_sys
;
215 stream_Delete(p_sys
->p_parser
);
218 for (unsigned int i
= 0; i
< p_sys
->i_title
; i
++)
219 vlc_input_title_Delete(p_sys
->pp_title
[i
]);
220 TAB_CLEAN( p_sys
->i_title
, p_sys
->pp_title
);
222 /* bd_close( NULL ) can crash */
223 assert(p_sys
->bluray
);
224 bd_close(p_sys
->bluray
);
229 static int blurayInitTitles(demux_t
*p_demux
)
231 demux_sys_t
*p_sys
= p_demux
->p_sys
;
233 /* get and set the titles */
234 unsigned i_title
= bd_get_titles(p_sys
->bluray
, TITLES_RELEVANT
, 60);
235 int64_t duration
= 0;
237 for (unsigned int i
= 0; i
< i_title
; i
++) {
238 input_title_t
*t
= vlc_input_title_New();
242 BLURAY_TITLE_INFO
*title_info
= bd_get_title_info(p_sys
->bluray
, i
, 0);
245 t
->i_length
= FROM_TICKS(title_info
->duration
);
247 if (t
->i_length
> duration
) {
248 duration
= t
->i_length
;
249 p_sys
->i_longest_title
= i
;
252 for ( unsigned int j
= 0; j
< title_info
->chapter_count
; j
++) {
253 seekpoint_t
*s
= vlc_seekpoint_New();
256 s
->i_time_offset
= title_info
->chapters
[j
].offset
;
258 TAB_APPEND( t
->i_seekpoint
, t
->seekpoint
, s
);
260 TAB_APPEND( p_sys
->i_title
, p_sys
->pp_title
, t
);
261 bd_free_title_info(title_info
);
267 /*****************************************************************************
268 * bluraySetTitle: select new BD title
269 *****************************************************************************/
270 static int bluraySetTitle(demux_t
*p_demux
, int i_title
)
272 demux_sys_t
*p_sys
= p_demux
->p_sys
;
274 /* Looking for the main title, ie the longest duration */
276 i_title
= p_sys
->i_longest_title
;
277 else if ((unsigned)i_title
> p_sys
->i_title
)
280 msg_Dbg( p_demux
, "Selecting Title %i", i_title
);
282 /* Select Blu-Ray title */
283 if (bd_select_title(p_demux
->p_sys
->bluray
, i_title
) == 0 ) {
284 msg_Err(p_demux
, "cannot select bd title '%d'", p_demux
->info
.i_title
);
288 /* read title info and init some values */
289 p_demux
->info
.i_title
= i_title
;
290 p_demux
->info
.i_seekpoint
= 0;
291 p_demux
->info
.i_update
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
297 /*****************************************************************************
298 * blurayControl: handle the controls
299 *****************************************************************************/
300 static int blurayControl(demux_t
*p_demux
, int query
, va_list args
)
302 demux_sys_t
*p_sys
= p_demux
->p_sys
;
308 case DEMUX_CAN_PAUSE
:
309 case DEMUX_CAN_CONTROL_PACE
:
310 pb_bool
= (bool*)va_arg( args
, bool * );
314 case DEMUX_GET_PTS_DELAY
:
315 pi_64
= (int64_t*)va_arg( args
, int64_t * );
317 INT64_C(1000) * var_InheritInteger( p_demux
, "disc-caching" );
320 case DEMUX_SET_PAUSE_STATE
:
324 case DEMUX_SET_TITLE
:
326 int i_title
= (int)va_arg( args
, int );
327 if (bluraySetTitle(p_demux
, i_title
) != VLC_SUCCESS
)
331 case DEMUX_SET_SEEKPOINT
:
333 int i_chapter
= (int)va_arg( args
, int );
334 bd_seek_chapter( p_sys
->bluray
, i_chapter
);
335 p_demux
->info
.i_update
= INPUT_UPDATE_SEEKPOINT
;
339 case DEMUX_GET_TITLE_INFO
:
341 input_title_t
***ppp_title
= (input_title_t
***)va_arg( args
, input_title_t
*** );
342 int *pi_int
= (int*)va_arg( args
, int* );
343 int *pi_title_offset
= (int*)va_arg( args
, int* );
344 int *pi_chapter_offset
= (int*)va_arg( args
, int* );
347 *pi_title_offset
= 0;
348 *pi_chapter_offset
= 0;
350 /* Duplicate local title infos */
351 *pi_int
= p_sys
->i_title
;
352 *ppp_title
= calloc( p_sys
->i_title
, sizeof(input_title_t
**) );
353 for( unsigned int i
= 0; i
< p_sys
->i_title
; i
++ )
354 (*ppp_title
)[i
] = vlc_input_title_Duplicate( p_sys
->pp_title
[i
]);
359 case DEMUX_GET_LENGTH
:
361 int64_t *pi_length
= (int64_t*)va_arg(args
, int64_t *);
362 *pi_length
= CUR_LENGTH
;
367 int64_t i_time
= (int64_t)va_arg(args
, int64_t);
368 bd_seek_time(p_sys
->bluray
, TO_TICKS(i_time
));
373 int64_t *pi_time
= (int64_t*)va_arg(args
, int64_t *);
374 *pi_time
= (int64_t)FROM_TICKS(bd_tell_time(p_sys
->bluray
));
378 case DEMUX_GET_POSITION
:
380 double *pf_position
= (double*)va_arg( args
, double * );
381 *pf_position
= (double)FROM_TICKS(bd_tell_time(p_sys
->bluray
))/CUR_LENGTH
;
384 case DEMUX_SET_POSITION
:
386 double f_position
= (double)va_arg(args
, double);
387 bd_seek_time(p_sys
->bluray
, TO_TICKS(f_position
*CUR_LENGTH
));
393 struct meta_dl
*meta
= bd_get_meta(p_sys
->bluray
);
394 vlc_meta_t
*p_meta
= (vlc_meta_t
*) va_arg (args
, vlc_meta_t
*);
396 if (!EMPTY_STR(meta
->di_name
)) vlc_meta_SetTitle(p_meta
, meta
->di_name
);
398 if (!EMPTY_STR(meta
->language_code
)) vlc_meta_AddExtra(p_meta
, "Language", meta
->language_code
);
399 if (!EMPTY_STR(meta
->filename
)) vlc_meta_AddExtra(p_meta
, "Filename", meta
->filename
);
400 if (!EMPTY_STR(meta
->di_alternative
)) vlc_meta_AddExtra(p_meta
, "Alternative", meta
->di_alternative
);
402 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
403 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
405 if (meta
->thumb_count
> 0 && meta
->thumbnails
) {
406 vlc_meta_SetArtURL(p_meta
, meta
->thumbnails
[0].path
);
412 case DEMUX_CAN_RECORD
:
414 case DEMUX_SET_GROUP
:
415 case DEMUX_HAS_UNSUPPORTED_META
:
416 case DEMUX_GET_ATTACHMENTS
:
419 msg_Warn( p_demux
, "unimplemented query (%d) in control", query
);
426 #define BD_TS_PACKET_SIZE (192)
427 #define NB_TS_PACKETS (200)
429 static int blurayDemux(demux_t
*p_demux
)
431 demux_sys_t
*p_sys
= p_demux
->p_sys
;
433 block_t
*p_block
= block_New(p_demux
, NB_TS_PACKETS
* (int64_t)BD_TS_PACKET_SIZE
);
438 int nread
= bd_read(p_sys
->bluray
, p_block
->p_buffer
,
439 NB_TS_PACKETS
* BD_TS_PACKET_SIZE
);
441 block_Release(p_block
);
445 p_block
->i_buffer
= nread
;
447 stream_DemuxSend( p_sys
->p_parser
, p_block
);