1 /*****************************************************************************
2 * bluray.c: Blu-ray disc support plugin
3 *****************************************************************************
4 * Copyright © 2010-2012 VideoLAN, VLC authors and libbluray AUTHORS
6 * Authors: Jean-Baptiste Kempf <jb@videolan.org>
7 * Hugo Beauzée-Luyssen <hugo@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
29 #include <stdatomic.h>
31 #if defined (HAVE_MNTENT_H) && defined(HAVE_SYS_STAT_H)
34 #include <fcntl.h> /* O_* */
35 #include <unistd.h> /* close() */
39 # include <sys/param.h>
40 # include <sys/ucred.h>
41 # include <sys/mount.h>
44 #include <vlc_common.h>
45 #include <vlc_plugin.h>
46 #include <vlc_demux.h> /* demux_t */
47 #include <vlc_input.h> /* Seekpoints, chapters */
48 #include <vlc_dialog.h> /* BD+/AACS warnings */
49 #include <vlc_vout.h> /* vout_PutSubpicture / subpicture_t */
50 #include <vlc_url.h> /* vlc_path2uri */
51 #include <vlc_iso_lang.h>
54 /* FIXME we should find a better way than including that */
55 #include "../../src/text/iso-639_def.h"
58 #include <libbluray/bluray.h>
59 #include <libbluray/bluray-version.h>
60 #include <libbluray/keys.h>
61 #include <libbluray/meta_data.h>
62 #include <libbluray/overlay.h>
64 /*****************************************************************************
66 *****************************************************************************/
68 #define BD_MENU_TEXT N_("Blu-ray menus")
69 #define BD_MENU_LONGTEXT N_("Use Blu-ray menus. If disabled, "\
70 "the movie will start directly")
71 #define BD_REGION_TEXT N_("Region code")
72 #define BD_REGION_LONGTEXT N_("Blu-Ray player region code. "\
73 "Some discs can be played only with a correct region code.")
75 static const char *const ppsz_region_code
[] = {
77 static const char *const ppsz_region_code_text
[] = {
78 "Region A", "Region B", "Region C" };
80 #define REGION_DEFAULT 1 /* Index to region list. Actual region code is (1<<REGION_DEFAULT) */
81 #define LANGUAGE_DEFAULT ("eng")
83 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,0)
88 static int blurayOpen (vlc_object_t
*);
89 static void blurayClose(vlc_object_t
*);
92 set_shortname(N_("Blu-ray"))
93 set_description(N_("Blu-ray Disc support (libbluray)"))
95 set_category(CAT_INPUT
)
96 set_subcategory(SUBCAT_INPUT_ACCESS
)
97 set_capability("access_demux", 500)
98 add_bool("bluray-menu", true, BD_MENU_TEXT
, BD_MENU_LONGTEXT
, false)
99 add_string("bluray-region", ppsz_region_code
[REGION_DEFAULT
], BD_REGION_TEXT
, BD_REGION_LONGTEXT
, false)
100 change_string_list(ppsz_region_code
, ppsz_region_code_text
)
102 add_shortcut("bluray", "file")
104 set_callbacks(blurayOpen
, blurayClose
)
109 set_description( "BluRay demuxer" )
110 set_category( CAT_INPUT
)
111 set_subcategory( SUBCAT_INPUT_DEMUX
)
112 set_capability( "demux", 5 )
113 set_callbacks( blurayOpen
, blurayClose
)
118 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
119 #define MAX_OVERLAY 2
121 typedef enum OverlayStatus
{
123 ToDisplay
, //Used to mark the overlay to be displayed the first time.
125 Outdated
//used to update the overlay after it has been sent to the vout
128 typedef struct bluray_overlay_t
132 OverlayStatus status
;
133 subpicture_region_t
*p_regions
;
136 /* pointer to last subpicture updater.
137 * used to disconnect this overlay from vout when:
138 * - the overlay is closed
139 * - vout is changed and this overlay is sent to the new vout
141 struct subpicture_updater_sys_t
*p_updater
;
149 unsigned int i_title
;
150 unsigned int i_longest_title
;
151 input_title_t
**pp_title
;
153 unsigned cur_seekpoint
;
156 vlc_mutex_t pl_info_lock
;
157 BLURAY_TITLE_INFO
*p_pl_info
;
158 const BLURAY_CLIP_INFO
*p_clip_info
;
162 input_attachment_t
**attachments
;
165 /* Meta information */
166 const META_DL
*p_meta
;
169 bluray_overlay_t
*p_overlays
[MAX_OVERLAY
];
173 bool b_popup_available
;
174 mtime_t i_still_end_time
;
176 vlc_mutex_t bdj_overlay_lock
; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
179 vout_thread_t
*p_vout
;
181 es_out_id_t
*p_dummy_video
;
186 int i_audio_stream_idx
; /* Selected audio stream. -1 if default */
187 int i_spu_stream_idx
; /* Selected subtitle stream. -1 if default */
188 bool b_spu_enable
; /* enabled / disabled */
190 vlc_demux_chained_t
*p_parser
;
192 bool b_pl_playing
; /* true when playing playlist */
195 vlc_mutex_t read_block_lock
;
197 /* Used to store bluray disc path */
201 struct subpicture_updater_sys_t
203 vlc_mutex_t lock
; // protect p_overlay pointer and ref_cnt
204 bluray_overlay_t
*p_overlay
; // NULL if overlay has been closed
205 int ref_cnt
; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
209 * cut the connection between vout and overlay.
210 * - called when vout is closed or overlay is closed.
211 * - frees subpicture_updater_sys_t when both sides have been closed.
213 static void unref_subpicture_updater(subpicture_updater_sys_t
*p_sys
)
215 vlc_mutex_lock(&p_sys
->lock
);
216 int refs
= --p_sys
->ref_cnt
;
217 p_sys
->p_overlay
= NULL
;
218 vlc_mutex_unlock(&p_sys
->lock
);
221 vlc_mutex_destroy(&p_sys
->lock
);
227 * FIXME: partiallyy duplicated from src/input/es_out.c
229 static const char *DemuxGetLanguageCode( demux_t
*p_demux
, const char *psz_var
)
231 const iso639_lang_t
*pl
;
235 psz_lang
= var_CreateGetString( p_demux
, psz_var
);
237 return LANGUAGE_DEFAULT
;
239 /* XXX: we will use only the first value
240 * (and ignore other ones in case of a list) */
241 if( ( p
= strchr( psz_lang
, ',' ) ) )
244 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
246 if( *psz_lang
== '\0' )
248 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
249 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
250 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
251 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
257 if( pl
->psz_eng_name
!= NULL
)
258 return pl
->psz_iso639_2T
;
260 return LANGUAGE_DEFAULT
;
263 /*****************************************************************************
265 *****************************************************************************/
266 static es_out_t
*esOutNew(demux_t
*p_demux
);
268 static int blurayControl(demux_t
*, int, va_list);
269 static int blurayDemux(demux_t
*);
271 static void blurayInitTitles(demux_t
*p_demux
, int menu_titles
);
272 static int bluraySetTitle(demux_t
*p_demux
, int i_title
);
274 static void blurayOverlayProc(void *ptr
, const BD_OVERLAY
* const overlay
);
275 static void blurayArgbOverlayProc(void *ptr
, const BD_ARGB_OVERLAY
* const overlay
);
277 static int onMouseEvent(vlc_object_t
*p_vout
, const char *psz_var
,
278 vlc_value_t old
, vlc_value_t val
, void *p_data
);
279 static int onIntfEvent(vlc_object_t
*, char const *,
280 vlc_value_t
, vlc_value_t
, void *);
282 static void blurayResetParser(demux_t
*p_demux
);
283 static void notifyDiscontinuity( demux_sys_t
*p_sys
);
285 #define FROM_TICKS(a) ((a)*CLOCK_FREQ / INT64_C(90000))
286 #define TO_TICKS(a) ((a)*INT64_C(90000)/CLOCK_FREQ)
287 #define CUR_LENGTH p_sys->pp_title[p_sys->cur_title]->i_length
290 static void FindMountPoint(char **file
)
292 char *device
= *file
;
293 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
294 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
295 * we look up the real device */
296 char *bd_device
= realpath(device
, NULL
);
297 if (bd_device
== NULL
)
301 if (lstat (bd_device
, &st
) == 0 && S_ISBLK (st
.st_mode
)) {
302 FILE *mtab
= setmntent ("/proc/self/mounts", "r");
304 struct mntent
*m
, mbuf
;
307 while ((m
= getmntent_r (mtab
, &mbuf
, buf
, sizeof(buf
))) != NULL
) {
308 if (!strcmp (m
->mnt_fsname
, bd_device
)) {
310 *file
= strdup(m
->mnt_dir
);
319 #elif defined(__APPLE__)
321 if (!stat (device
, &st
) && S_ISBLK (st
.st_mode
)) {
322 int fs_count
= getfsstat (NULL
, 0, MNT_NOWAIT
);
324 struct statfs mbuf
[128];
325 getfsstat (mbuf
, fs_count
* sizeof(mbuf
[0]), MNT_NOWAIT
);
326 for (int i
= 0; i
< fs_count
; ++i
)
327 if (!strcmp (mbuf
[i
].f_mntfromname
, device
)) {
329 *file
= strdup(mbuf
[i
].f_mntonname
);
335 # warning Disc device to mount point not implemented
336 VLC_UNUSED( device
);
340 static void blurayReleaseVout(demux_t
*p_demux
)
342 demux_sys_t
*p_sys
= p_demux
->p_sys
;
344 if (p_sys
->p_vout
!= NULL
) {
345 var_DelCallback(p_sys
->p_vout
, "mouse-moved", onMouseEvent
, p_demux
);
346 var_DelCallback(p_sys
->p_vout
, "mouse-clicked", onMouseEvent
, p_demux
);
348 for (int i
= 0; i
< MAX_OVERLAY
; i
++) {
349 bluray_overlay_t
*p_ov
= p_sys
->p_overlays
[i
];
351 vlc_mutex_lock(&p_ov
->lock
);
352 if (p_ov
->i_channel
!= -1) {
353 msg_Err(p_demux
, "blurayReleaseVout: subpicture channel exists\n");
354 vout_FlushSubpictureChannel(p_sys
->p_vout
, p_ov
->i_channel
);
356 p_ov
->i_channel
= -1;
357 p_ov
->status
= ToDisplay
;
358 vlc_mutex_unlock(&p_ov
->lock
);
360 if (p_ov
->p_updater
) {
361 unref_subpicture_updater(p_ov
->p_updater
);
362 p_ov
->p_updater
= NULL
;
367 vlc_object_release(p_sys
->p_vout
);
368 p_sys
->p_vout
= NULL
;
372 /*****************************************************************************
373 * BD-J background video
374 *****************************************************************************/
376 static void startBackground(demux_t
*p_demux
)
378 demux_sys_t
*p_sys
= p_demux
->p_sys
;
380 if (p_sys
->p_dummy_video
) {
384 msg_Info(p_demux
, "Start background");
388 es_format_Init( &fmt
, VIDEO_ES
, VLC_CODEC_I420
);
389 video_format_Setup( &fmt
.video
, VLC_CODEC_I420
,
390 1920, 1080, 1920, 1080, 1, 1);
391 fmt
.i_priority
= ES_PRIORITY_SELECTABLE_MIN
;
392 fmt
.i_id
= 4115; /* 4113 = main video. 4114 = MVC. 4115 = unused. */
395 p_sys
->p_dummy_video
= es_out_Add(p_demux
->out
, &fmt
);
397 if (!p_sys
->p_dummy_video
) {
398 msg_Err(p_demux
, "Error adding background ES");
402 block_t
*p_block
= block_Alloc(fmt
.video
.i_width
* fmt
.video
.i_height
*
403 fmt
.video
.i_bits_per_pixel
/ 8);
405 msg_Err(p_demux
, "Error allocating block for background video");
409 // XXX TODO: what would be correct timestamp ???
410 p_block
->i_dts
= p_block
->i_pts
= mdate() + CLOCK_FREQ
/25;
412 uint8_t *p
= p_block
->p_buffer
;
413 memset(p
, 0, fmt
.video
.i_width
* fmt
.video
.i_height
);
414 p
+= fmt
.video
.i_width
* fmt
.video
.i_height
;
415 memset(p
, 0x80, fmt
.video
.i_width
* fmt
.video
.i_height
/ 2);
417 es_out_Send(p_demux
->out
, p_sys
->p_dummy_video
, p_block
);
420 es_format_Clean(&fmt
);
423 static void stopBackground(demux_t
*p_demux
)
425 demux_sys_t
*p_sys
= p_demux
->p_sys
;
427 if (!p_sys
->p_dummy_video
) {
431 msg_Info(p_demux
, "Stop background");
433 es_out_Del(p_demux
->out
, p_sys
->p_dummy_video
);
434 p_sys
->p_dummy_video
= NULL
;
437 /*****************************************************************************
438 * cache current playlist (title) information
439 *****************************************************************************/
441 static void setTitleInfo(demux_sys_t
*p_sys
, BLURAY_TITLE_INFO
*info
)
443 vlc_mutex_lock(&p_sys
->pl_info_lock
);
445 if (p_sys
->p_pl_info
) {
446 bd_free_title_info(p_sys
->p_pl_info
);
448 p_sys
->p_pl_info
= info
;
449 p_sys
->p_clip_info
= NULL
;
451 if (p_sys
->p_pl_info
&& p_sys
->p_pl_info
->clip_count
) {
452 p_sys
->p_clip_info
= &p_sys
->p_pl_info
->clips
[0];
455 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
458 /*****************************************************************************
459 * create input attachment for thumbnail
460 *****************************************************************************/
462 static void attachThumbnail(demux_t
*p_demux
)
464 demux_sys_t
*p_sys
= p_demux
->p_sys
;
469 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
470 if (p_sys
->p_meta
->thumb_count
> 0 && p_sys
->p_meta
->thumbnails
) {
473 if (bd_get_meta_file(p_sys
->bluray
, p_sys
->p_meta
->thumbnails
[0].path
, &data
, &size
) > 0) {
475 input_attachment_t
*p_attachment
;
477 snprintf(psz_name
, sizeof(psz_name
), "picture%d_%s", p_sys
->i_attachments
, p_sys
->p_meta
->thumbnails
[0].path
);
479 p_attachment
= vlc_input_attachment_New(psz_name
, NULL
, "Album art", data
, size
);
481 p_sys
->i_cover_idx
= p_sys
->i_attachments
;
482 TAB_APPEND(p_sys
->i_attachments
, p_sys
->attachments
, p_attachment
);
490 /*****************************************************************************
492 *****************************************************************************/
494 static int probeStream(demux_t
*p_demux
)
496 /* input must be seekable */
497 bool b_canseek
= false;
498 vlc_stream_Control( p_demux
->s
, STREAM_CAN_SEEK
, &b_canseek
);
503 /* first sector(s) should be filled with zeros */
505 const uint8_t *p_peek
;
506 i_peek
= vlc_stream_Peek( p_demux
->s
, &p_peek
, 2048 );
507 if( i_peek
!= 2048 ) {
511 if (p_peek
[ --i_peek
]) {
520 static int blurayReadBlock(void *object
, void *buf
, int lba
, int num_blocks
)
522 demux_t
*p_demux
= (demux_t
*)object
;
523 demux_sys_t
*p_sys
= p_demux
->p_sys
;
526 assert(p_demux
->s
!= NULL
);
528 vlc_mutex_lock(&p_sys
->read_block_lock
);
530 if (vlc_stream_Seek( p_demux
->s
, lba
* INT64_C(2048) ) == VLC_SUCCESS
) {
531 size_t req
= (size_t)2048 * num_blocks
;
534 got
= vlc_stream_Read( p_demux
->s
, buf
, req
);
536 msg_Err(p_demux
, "read from lba %d failed", lba
);
541 msg_Err(p_demux
, "seek to lba %d failed", lba
);
544 vlc_mutex_unlock(&p_sys
->read_block_lock
);
550 /*****************************************************************************
551 * probing of local files
552 *****************************************************************************/
554 /* Descriptor Tag (ECMA 167, 3/7.2) */
555 static int decode_descriptor_tag(const uint8_t *buf
)
558 uint8_t checksum
= 0;
561 id
= buf
[0] | (buf
[1] << 8);
563 /* calculate tag checksum */
564 for (i
= 0; i
< 4; i
++) {
565 checksum
= (uint8_t)(checksum
+ buf
[i
]);
567 for (i
= 5; i
< 16; i
++) {
568 checksum
= (uint8_t)(checksum
+ buf
[i
]);
571 if (checksum
!= buf
[4]) {
578 static int probeFile(const char *psz_name
)
580 struct stat stat_info
;
583 int ret
= VLC_EGENERIC
;
586 fd
= vlc_open(psz_name
, O_RDONLY
| O_NONBLOCK
);
591 if (fstat(fd
, &stat_info
) == -1) {
594 if (!S_ISREG(stat_info
.st_mode
) && !S_ISBLK(stat_info
.st_mode
)) {
598 /* first sector should be filled with zeros */
599 if (read(fd
, peek
, sizeof(peek
)) != sizeof(peek
)) {
602 for (i
= 0; i
< sizeof(peek
); i
++) {
608 /* Check AVDP tag checksum */
609 if (lseek(fd
, 256 * 2048, SEEK_SET
) == -1 ||
610 read(fd
, peek
, 16) != 16 ||
611 decode_descriptor_tag(peek
) != 2) {
622 /*****************************************************************************
623 * blurayOpen: module init function
624 *****************************************************************************/
625 static int blurayOpen(vlc_object_t
*object
)
627 demux_t
*p_demux
= (demux_t
*)object
;
630 uint64_t i_init_pos
= 0;
632 const char *error_msg
= NULL
;
633 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
635 if (unlikely(!p_demux
->p_input
))
638 forced
= !strncasecmp(p_demux
->psz_url
, "bluray:", 7);
641 if (!strncasecmp(p_demux
->psz_url
, "file:", 5)) {
642 /* use access_demux for local files */
646 if (probeStream(p_demux
) != VLC_SUCCESS
) {
650 } else if (!forced
) {
651 if (!p_demux
->psz_filepath
) {
655 if (probeFile(p_demux
->psz_filepath
) != VLC_SUCCESS
) {
661 p_demux
->p_sys
= p_sys
= vlc_obj_calloc(object
, 1, sizeof(*p_sys
));
662 if (unlikely(!p_sys
))
665 p_sys
->i_audio_stream_idx
= -1;
666 p_sys
->i_spu_stream_idx
= -1;
667 p_sys
->i_video_stream
= -1;
668 p_sys
->i_still_end_time
= 0;
670 /* init demux info fields */
673 TAB_INIT(p_sys
->i_title
, p_sys
->pp_title
);
674 TAB_INIT(p_sys
->i_attachments
, p_sys
->attachments
);
676 vlc_mutex_init(&p_sys
->pl_info_lock
);
677 vlc_mutex_init(&p_sys
->bdj_overlay_lock
);
678 vlc_mutex_init(&p_sys
->read_block_lock
); /* used during bd_open_stream() */
680 /* request sub demuxers to skip continuity check as some split
681 file concatenation are just resetting counters... */
682 var_Create( p_demux
, "ts-cc-check", VLC_VAR_BOOL
);
683 var_SetBool( p_demux
, "ts-cc-check", false );
685 var_AddCallback( p_demux
->p_input
, "intf-event", onIntfEvent
, p_demux
);
690 i_init_pos
= vlc_stream_Tell(p_demux
->s
);
692 p_sys
->bluray
= bd_init();
693 if (!bd_open_stream(p_sys
->bluray
, p_demux
, blurayReadBlock
)) {
694 bd_close(p_sys
->bluray
);
695 p_sys
->bluray
= NULL
;
700 if (!p_demux
->psz_filepath
) {
701 /* no path provided (bluray://). use default DVD device. */
702 p_sys
->psz_bd_path
= var_InheritString(object
, "dvd");
704 /* store current bd path */
705 p_sys
->psz_bd_path
= strdup(p_demux
->psz_filepath
);
708 /* If we're passed a block device, try to convert it to the mount point. */
709 FindMountPoint(&p_sys
->psz_bd_path
);
711 p_sys
->bluray
= bd_open(p_sys
->psz_bd_path
, NULL
);
713 if (!p_sys
->bluray
) {
717 /* Warning the user about AACS/BD+ */
718 const BLURAY_DISC_INFO
*disc_info
= bd_get_disc_info(p_sys
->bluray
);
720 /* Is it a bluray? */
721 if (!disc_info
->bluray_detected
) {
723 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
728 msg_Info(p_demux
, "First play: %i, Top menu: %i\n"
729 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
730 disc_info
->first_play_supported
, disc_info
->top_menu_supported
,
731 disc_info
->num_hdmv_titles
, disc_info
->num_bdj_titles
,
732 disc_info
->num_unsupported_titles
);
735 if (disc_info
->aacs_detected
) {
736 msg_Dbg(p_demux
, "Disc is using AACS");
737 if (!disc_info
->libaacs_detected
)
738 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
739 ", and your system does not have it."));
740 if (!disc_info
->aacs_handled
) {
741 if (disc_info
->aacs_error_code
) {
742 switch (disc_info
->aacs_error_code
) {
743 case BD_AACS_CORRUPTED_DISC
:
744 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
745 case BD_AACS_NO_CONFIG
:
746 BLURAY_ERROR(_("Missing AACS configuration file!"));
748 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
749 case BD_AACS_NO_CERT
:
750 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
751 case BD_AACS_CERT_REVOKED
:
752 BLURAY_ERROR(_("AACS Host certificate revoked."));
753 case BD_AACS_MMC_FAILED
:
754 BLURAY_ERROR(_("AACS MMC failed."));
761 if (disc_info
->bdplus_detected
) {
762 msg_Dbg(p_demux
, "Disc is using BD+");
763 if (!disc_info
->libbdplus_detected
)
764 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
765 ", and your system does not have it."));
766 if (!disc_info
->bdplus_handled
)
767 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
768 "Missing configuration?"));
771 /* set player region code */
772 char *psz_region
= var_InheritString(p_demux
, "bluray-region");
773 unsigned int region
= psz_region
? (psz_region
[0] - 'A') : REGION_DEFAULT
;
775 bd_set_player_setting(p_sys
->bluray
, BLURAY_PLAYER_SETTING_REGION_CODE
, 1<<region
);
777 /* set preferred languages */
778 const char *psz_code
= DemuxGetLanguageCode( p_demux
, "audio-language" );
779 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_AUDIO_LANG
, psz_code
);
780 psz_code
= DemuxGetLanguageCode( p_demux
, "sub-language" );
781 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_PG_LANG
, psz_code
);
782 psz_code
= DemuxGetLanguageCode( p_demux
, "menu-language" );
783 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_MENU_LANG
, psz_code
);
785 /* Get disc metadata */
786 p_sys
->p_meta
= bd_get_meta(p_sys
->bluray
);
788 msg_Warn(p_demux
, "Failed to get meta info.");
790 p_sys
->i_cover_idx
= -1;
791 attachThumbnail(p_demux
);
793 p_sys
->b_menu
= var_InheritBool(p_demux
, "bluray-menu");
795 /* Check BD-J capability */
796 if (p_sys
->b_menu
&& disc_info
->bdj_detected
&& !disc_info
->bdj_handled
) {
797 msg_Err(p_demux
, "BD-J menus not supported. Playing without menus. "
798 "BD-J support: %d, JVM found: %d, JVM usable: %d",
799 disc_info
->bdj_supported
, disc_info
->libjvm_detected
, disc_info
->bdj_handled
);
800 vlc_dialog_display_error(p_demux
, _("Java required"),
801 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
802 !disc_info
->libjvm_detected
? _("Java was not found on your system.") : "");
803 p_sys
->b_menu
= false;
806 /* Get titles and chapters */
807 blurayInitTitles(p_demux
, disc_info
->num_hdmv_titles
+ disc_info
->num_bdj_titles
+ 1/*Top Menu*/ + 1/*First Play*/);
810 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
812 bd_get_event(p_sys
->bluray
, NULL
);
814 /* Registering overlay event handler */
815 bd_register_overlay_proc(p_sys
->bluray
, p_demux
, blurayOverlayProc
);
819 /* Register ARGB overlay handler for BD-J */
820 if (disc_info
->num_bdj_titles
)
821 bd_register_argb_overlay_proc(p_sys
->bluray
, p_demux
, blurayArgbOverlayProc
, NULL
);
823 /* libbluray will start playback from "First-Title" title */
824 if (bd_play(p_sys
->bluray
) == 0)
825 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
828 /* set start title number */
829 if (bluraySetTitle(p_demux
, p_sys
->i_longest_title
) != VLC_SUCCESS
) {
830 msg_Err(p_demux
, "Could not set the title %d", p_sys
->i_longest_title
);
835 vlc_array_init(&p_sys
->es
);
836 p_sys
->p_out
= esOutNew(p_demux
);
837 if (unlikely(p_sys
->p_out
== NULL
))
840 blurayResetParser(p_demux
);
841 if (!p_sys
->p_parser
) {
842 msg_Err(p_demux
, "Failed to create TS demuxer");
846 p_demux
->pf_control
= blurayControl
;
847 p_demux
->pf_demux
= blurayDemux
;
853 vlc_dialog_display_error(p_demux
, _("Blu-ray error"), "%s", error_msg
);
856 if (p_demux
->s
!= NULL
) {
857 /* restore stream position */
858 if (vlc_stream_Seek(p_demux
->s
, i_init_pos
) != VLC_SUCCESS
) {
859 msg_Err(p_demux
, "Failed to seek back to stream start");
869 /*****************************************************************************
870 * blurayClose: module destroy function
871 *****************************************************************************/
872 static void blurayClose(vlc_object_t
*object
)
874 demux_t
*p_demux
= (demux_t
*)object
;
875 demux_sys_t
*p_sys
= p_demux
->p_sys
;
877 var_DelCallback( p_demux
->p_input
, "intf-event", onIntfEvent
, p_demux
);
879 setTitleInfo(p_sys
, NULL
);
882 * Close libbluray first.
883 * This will close all the overlays before we release p_vout
884 * bd_close(NULL) can crash
887 bd_close(p_sys
->bluray
);
890 blurayReleaseVout(p_demux
);
893 vlc_demux_chained_Delete(p_sys
->p_parser
);
894 if (p_sys
->p_out
!= NULL
)
895 es_out_Delete(p_sys
->p_out
);
896 assert(vlc_array_count(&p_sys
->es
) == 0);
897 vlc_array_clear(&p_sys
->es
);
900 for (unsigned int i
= 0; i
< p_sys
->i_title
; i
++)
901 vlc_input_title_Delete(p_sys
->pp_title
[i
]);
902 TAB_CLEAN(p_sys
->i_title
, p_sys
->pp_title
);
904 for (int i
= 0; i
< p_sys
->i_attachments
; i
++)
905 vlc_input_attachment_Delete(p_sys
->attachments
[i
]);
906 TAB_CLEAN(p_sys
->i_attachments
, p_sys
->attachments
);
908 vlc_mutex_destroy(&p_sys
->pl_info_lock
);
909 vlc_mutex_destroy(&p_sys
->bdj_overlay_lock
);
910 vlc_mutex_destroy(&p_sys
->read_block_lock
);
912 free(p_sys
->psz_bd_path
);
915 /*****************************************************************************
916 * Elementary streams handling
917 *****************************************************************************/
919 struct es_out_sys_t
{
923 typedef struct fmt_es_pair
{
928 static int findEsPairIndex(demux_sys_t
*p_sys
, int i_id
)
930 for (size_t i
= 0; i
< vlc_array_count(&p_sys
->es
); ++i
)
931 if (((fmt_es_pair_t
*)vlc_array_item_at_index(&p_sys
->es
, i
))->i_id
== i_id
)
937 static int findEsPairIndexByEs(demux_sys_t
*p_sys
, es_out_id_t
*p_es
)
939 for (size_t i
= 0; i
< vlc_array_count(&p_sys
->es
); ++i
)
940 if (((fmt_es_pair_t
*)vlc_array_item_at_index(&p_sys
->es
, i
))->p_es
== p_es
)
946 static void setStreamLang(demux_sys_t
*p_sys
, es_format_t
*p_fmt
)
948 const BLURAY_STREAM_INFO
*p_streams
;
949 int i_stream_count
= 0;
951 vlc_mutex_lock(&p_sys
->pl_info_lock
);
953 if (p_sys
->p_clip_info
) {
954 if (p_fmt
->i_cat
== AUDIO_ES
) {
955 p_streams
= p_sys
->p_clip_info
->audio_streams
;
956 i_stream_count
= p_sys
->p_clip_info
->audio_stream_count
;
957 } else if (p_fmt
->i_cat
== SPU_ES
) {
958 p_streams
= p_sys
->p_clip_info
->pg_streams
;
959 i_stream_count
= p_sys
->p_clip_info
->pg_stream_count
;
963 for (int i
= 0; i
< i_stream_count
; i
++) {
964 if (p_fmt
->i_id
== p_streams
[i
].pid
) {
965 free(p_fmt
->psz_language
);
966 p_fmt
->psz_language
= strndup((const char *)p_streams
[i
].lang
, 3);
971 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
974 static int blurayEsPid(demux_sys_t
*p_sys
, int es_type
, int i_es_idx
)
978 vlc_mutex_lock(&p_sys
->pl_info_lock
);
980 if (p_sys
->p_clip_info
) {
981 if (es_type
== AUDIO_ES
) {
982 if (i_es_idx
>= 0 && i_es_idx
< p_sys
->p_clip_info
->audio_stream_count
) {
983 i_pid
= p_sys
->p_clip_info
->audio_streams
[i_es_idx
].pid
;
985 } else if (es_type
== SPU_ES
) {
986 if (i_es_idx
>= 0 && i_es_idx
< p_sys
->p_clip_info
->pg_stream_count
) {
987 i_pid
= p_sys
->p_clip_info
->pg_streams
[i_es_idx
].pid
;
992 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
997 static es_out_id_t
*esOutAdd(es_out_t
*p_out
, const es_format_t
*p_fmt
)
999 demux_t
*p_demux
= p_out
->p_sys
->p_demux
;
1000 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1002 bool b_select
= false;
1004 es_format_Copy(&fmt
, p_fmt
);
1006 switch (fmt
.i_cat
) {
1008 if (p_sys
->i_video_stream
!= -1 && p_sys
->i_video_stream
!= p_fmt
->i_id
)
1009 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1012 if (p_sys
->i_audio_stream_idx
!= -1) {
1013 if (blurayEsPid(p_sys
, AUDIO_ES
, p_sys
->i_audio_stream_idx
) == p_fmt
->i_id
)
1015 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1017 setStreamLang(p_sys
, &fmt
);
1020 if (p_sys
->i_spu_stream_idx
!= -1) {
1021 if (blurayEsPid(p_sys
, SPU_ES
, p_sys
->i_spu_stream_idx
) == p_fmt
->i_id
)
1023 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1025 setStreamLang(p_sys
, &fmt
);
1031 es_out_id_t
*p_es
= es_out_Add(p_demux
->out
, &fmt
);
1032 if (p_fmt
->i_id
>= 0) {
1033 /* Ensure we are not overriding anything */
1034 int idx
= findEsPairIndex(p_sys
, p_fmt
->i_id
);
1036 fmt_es_pair_t
*p_pair
= malloc(sizeof(*p_pair
));
1037 if (likely(p_pair
!= NULL
)) {
1038 p_pair
->i_id
= p_fmt
->i_id
;
1039 p_pair
->p_es
= p_es
;
1040 msg_Info(p_demux
, "Adding ES %d", p_fmt
->i_id
);
1041 vlc_array_append_or_abort(&p_sys
->es
, p_pair
);
1044 if (fmt
.i_cat
== AUDIO_ES
) {
1045 var_SetInteger( p_demux
->p_input
, "audio-es", p_fmt
->i_id
);
1046 } else if (fmt
.i_cat
== SPU_ES
) {
1047 var_SetInteger( p_demux
->p_input
, "spu-es", p_sys
->b_spu_enable
? p_fmt
->i_id
: -1 );
1053 es_format_Clean(&fmt
);
1057 static int esOutSend(es_out_t
*p_out
, es_out_id_t
*p_es
, block_t
*p_block
)
1059 demux_t
*p_demux
= p_out
->p_sys
->p_demux
;
1061 return es_out_Send(p_demux
->out
, p_es
, p_block
);
1064 static void esOutDel(es_out_t
*p_out
, es_out_id_t
*p_es
)
1066 demux_t
*p_demux
= p_out
->p_sys
->p_demux
;
1067 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1069 int idx
= findEsPairIndexByEs(p_sys
, p_es
);
1071 free(vlc_array_item_at_index(&p_sys
->es
, idx
));
1072 vlc_array_remove(&p_sys
->es
, idx
);
1074 es_out_Del(p_demux
->out
, p_es
);
1077 static int esOutControl(es_out_t
*p_out
, int i_query
, va_list args
)
1079 demux_t
*p_demux
= p_out
->p_sys
->p_demux
;
1081 return es_out_vaControl(p_demux
->out
, i_query
, args
);
1084 static void esOutDestroy(es_out_t
*p_out
)
1086 demux_t
*p_demux
= p_out
->p_sys
->p_demux
;
1087 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1089 for (size_t i
= 0; i
< vlc_array_count(&p_sys
->es
); ++i
)
1090 free(vlc_array_item_at_index(&p_sys
->es
, i
));
1091 vlc_array_clear(&p_sys
->es
);
1096 static es_out_t
*esOutNew(demux_t
*p_demux
)
1099 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1100 assert(vlc_array_count(&p_sys
->es
) == 0);
1102 es_out_t
*p_out
= malloc(sizeof(*p_out
));
1103 if (unlikely(p_out
== NULL
))
1106 p_out
->pf_add
= esOutAdd
;
1107 p_out
->pf_control
= esOutControl
;
1108 p_out
->pf_del
= esOutDel
;
1109 p_out
->pf_destroy
= esOutDestroy
;
1110 p_out
->pf_send
= esOutSend
;
1112 p_out
->p_sys
= malloc(sizeof(*p_out
->p_sys
));
1113 if (unlikely(p_out
->p_sys
== NULL
)) {
1117 p_out
->p_sys
->p_demux
= p_demux
;
1121 /*****************************************************************************
1122 * subpicture_updater_t functions:
1123 *****************************************************************************/
1125 static bluray_overlay_t
*updater_lock_overlay(subpicture_updater_sys_t
*p_upd_sys
)
1127 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1128 vlc_mutex_lock(&p_upd_sys
->lock
);
1130 bluray_overlay_t
*ov
= p_upd_sys
->p_overlay
;
1132 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1133 vlc_mutex_lock(&ov
->lock
);
1137 /* overlay has been closed */
1138 vlc_mutex_unlock(&p_upd_sys
->lock
);
1142 static void updater_unlock_overlay(subpicture_updater_sys_t
*p_upd_sys
)
1144 assert (p_upd_sys
->p_overlay
);
1146 vlc_mutex_unlock(&p_upd_sys
->p_overlay
->lock
);
1147 vlc_mutex_unlock(&p_upd_sys
->lock
);
1150 static int subpictureUpdaterValidate(subpicture_t
*p_subpic
,
1151 bool b_fmt_src
, const video_format_t
*p_fmt_src
,
1152 bool b_fmt_dst
, const video_format_t
*p_fmt_dst
,
1155 VLC_UNUSED(b_fmt_src
);
1156 VLC_UNUSED(b_fmt_dst
);
1157 VLC_UNUSED(p_fmt_src
);
1158 VLC_UNUSED(p_fmt_dst
);
1161 subpicture_updater_sys_t
*p_upd_sys
= p_subpic
->updater
.p_sys
;
1162 bluray_overlay_t
*p_overlay
= updater_lock_overlay(p_upd_sys
);
1168 int res
= p_overlay
->status
== Outdated
;
1170 updater_unlock_overlay(p_upd_sys
);
1175 static void subpictureUpdaterUpdate(subpicture_t
*p_subpic
,
1176 const video_format_t
*p_fmt_src
,
1177 const video_format_t
*p_fmt_dst
,
1180 VLC_UNUSED(p_fmt_src
);
1181 VLC_UNUSED(p_fmt_dst
);
1183 subpicture_updater_sys_t
*p_upd_sys
= p_subpic
->updater
.p_sys
;
1184 bluray_overlay_t
*p_overlay
= updater_lock_overlay(p_upd_sys
);
1191 * When this function is called, all p_subpic regions are gone.
1192 * We need to duplicate our regions (stored internaly) to this subpic.
1194 subpicture_region_t
*p_src
= p_overlay
->p_regions
;
1196 updater_unlock_overlay(p_upd_sys
);
1200 subpicture_region_t
**p_dst
= &p_subpic
->p_region
;
1201 while (p_src
!= NULL
) {
1202 *p_dst
= subpicture_region_Copy(p_src
);
1205 p_dst
= &(*p_dst
)->p_next
;
1206 p_src
= p_src
->p_next
;
1209 (*p_dst
)->p_next
= NULL
;
1210 p_overlay
->status
= Displayed
;
1212 updater_unlock_overlay(p_upd_sys
);
1215 static void subpictureUpdaterDestroy(subpicture_t
*p_subpic
)
1217 subpicture_updater_sys_t
*p_upd_sys
= p_subpic
->updater
.p_sys
;
1218 bluray_overlay_t
*p_overlay
= updater_lock_overlay(p_upd_sys
);
1221 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1222 p_overlay
->status
= ToDisplay
;
1223 p_overlay
->i_channel
= -1;
1224 updater_unlock_overlay(p_upd_sys
);
1227 unref_subpicture_updater(p_upd_sys
);
1230 static subpicture_t
*bluraySubpictureCreate(bluray_overlay_t
*p_ov
)
1232 subpicture_updater_sys_t
*p_upd_sys
= malloc(sizeof(*p_upd_sys
));
1233 if (unlikely(p_upd_sys
== NULL
)) {
1237 p_upd_sys
->p_overlay
= p_ov
;
1239 subpicture_updater_t updater
= {
1240 .pf_validate
= subpictureUpdaterValidate
,
1241 .pf_update
= subpictureUpdaterUpdate
,
1242 .pf_destroy
= subpictureUpdaterDestroy
,
1246 subpicture_t
*p_pic
= subpicture_New(&updater
);
1247 if (p_pic
== NULL
) {
1252 p_pic
->i_original_picture_width
= p_ov
->width
;
1253 p_pic
->i_original_picture_height
= p_ov
->height
;
1254 p_pic
->b_ephemer
= true;
1255 p_pic
->b_absolute
= true;
1257 vlc_mutex_init(&p_upd_sys
->lock
);
1258 p_upd_sys
->ref_cnt
= 2;
1260 p_ov
->p_updater
= p_upd_sys
;
1265 /*****************************************************************************
1266 * User input events:
1267 *****************************************************************************/
1268 static int onMouseEvent(vlc_object_t
*p_vout
, const char *psz_var
, vlc_value_t old
,
1269 vlc_value_t val
, void *p_data
)
1271 demux_t
*p_demux
= (demux_t
*)p_data
;
1272 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1276 if (psz_var
[6] == 'm') //Mouse moved
1277 bd_mouse_select(p_sys
->bluray
, -1, val
.coords
.x
, val
.coords
.y
);
1278 else if (psz_var
[6] == 'c') {
1279 bd_mouse_select(p_sys
->bluray
, -1, val
.coords
.x
, val
.coords
.y
);
1280 bd_user_input(p_sys
->bluray
, -1, BD_VK_MOUSE_ACTIVATE
);
1282 vlc_assert_unreachable();
1287 static int sendKeyEvent(demux_sys_t
*p_sys
, unsigned int key
)
1289 if (bd_user_input(p_sys
->bluray
, -1, key
) < 0)
1290 return VLC_EGENERIC
;
1295 /*****************************************************************************
1296 * libbluray overlay handling:
1297 *****************************************************************************/
1299 static void blurayCloseOverlay(demux_t
*p_demux
, int plane
)
1301 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1302 bluray_overlay_t
*ov
= p_sys
->p_overlays
[plane
];
1306 /* drop overlay from vout */
1307 if (ov
->p_updater
) {
1308 unref_subpicture_updater(ov
->p_updater
);
1310 /* no references to this overlay exist in vo anymore */
1311 if (p_sys
->p_vout
&& ov
->i_channel
!= -1) {
1312 vout_FlushSubpictureChannel(p_sys
->p_vout
, ov
->i_channel
);
1315 vlc_mutex_destroy(&ov
->lock
);
1316 subpicture_region_ChainDelete(ov
->p_regions
);
1319 p_sys
->p_overlays
[plane
] = NULL
;
1322 for (int i
= 0; i
< MAX_OVERLAY
; i
++)
1323 if (p_sys
->p_overlays
[i
])
1326 /* All overlays have been closed */
1327 blurayReleaseVout(p_demux
);
1331 * Mark the overlay as "ToDisplay" status.
1332 * This will not send the overlay to the vout instantly, as the vout
1333 * may not be acquired (not acquirable) yet.
1334 * If is has already been acquired, the overlay has already been sent to it,
1335 * therefore, we only flag the overlay as "Outdated"
1337 static void blurayActivateOverlay(demux_t
*p_demux
, int plane
)
1339 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1340 bluray_overlay_t
*ov
= p_sys
->p_overlays
[plane
];
1343 * If the overlay is already displayed, mark the picture as outdated.
1344 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1346 vlc_mutex_lock(&ov
->lock
);
1347 if (ov
->status
>= Displayed
&& p_sys
->p_vout
) {
1348 ov
->status
= Outdated
;
1349 vlc_mutex_unlock(&ov
->lock
);
1354 * Mark the overlay as available, but don't display it right now.
1355 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1356 * the overlay is computed
1358 ov
->status
= ToDisplay
;
1359 vlc_mutex_unlock(&ov
->lock
);
1362 static void blurayInitOverlay(demux_t
*p_demux
, int plane
, int width
, int height
)
1364 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1366 assert(p_sys
->p_overlays
[plane
] == NULL
);
1368 bluray_overlay_t
*ov
= calloc(1, sizeof(*ov
));
1369 if (unlikely(ov
== NULL
))
1373 ov
->height
= height
;
1376 vlc_mutex_init(&ov
->lock
);
1378 p_sys
->p_overlays
[plane
] = ov
;
1382 * Destroy every regions in the subpicture.
1383 * This is done in two steps:
1384 * - Wiping our private regions list
1385 * - Flagging the overlay as outdated, so the changes are replicated from
1386 * the subpicture_updater_t::pf_update
1387 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1389 static void blurayClearOverlay(demux_t
*p_demux
, int plane
)
1391 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1392 bluray_overlay_t
*ov
= p_sys
->p_overlays
[plane
];
1394 vlc_mutex_lock(&ov
->lock
);
1396 subpicture_region_ChainDelete(ov
->p_regions
);
1397 ov
->p_regions
= NULL
;
1398 ov
->status
= Outdated
;
1400 vlc_mutex_unlock(&ov
->lock
);
1404 * This will draw to the overlay by adding a region to our region list
1405 * This will have to be copied to the subpicture used to render the overlay.
1407 static void blurayDrawOverlay(demux_t
*p_demux
, const BD_OVERLAY
* const ov
)
1409 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1412 * Compute a subpicture_region_t.
1413 * It will be copied and sent to the vout later.
1415 vlc_mutex_lock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1417 /* Find a region to update */
1418 subpicture_region_t
**pp_reg
= &p_sys
->p_overlays
[ov
->plane
]->p_regions
;
1419 subpicture_region_t
*p_reg
= p_sys
->p_overlays
[ov
->plane
]->p_regions
;
1420 subpicture_region_t
*p_last
= NULL
;
1421 while (p_reg
!= NULL
) {
1423 if (p_reg
->i_x
== ov
->x
&& p_reg
->i_y
== ov
->y
&&
1424 p_reg
->fmt
.i_width
== ov
->w
&& p_reg
->fmt
.i_height
== ov
->h
)
1426 pp_reg
= &p_reg
->p_next
;
1427 p_reg
= p_reg
->p_next
;
1433 *pp_reg
= p_reg
->p_next
;
1434 subpicture_region_Delete(p_reg
);
1436 vlc_mutex_unlock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1440 /* If there is no region to update, create a new one. */
1443 video_format_Init(&fmt
, 0);
1444 video_format_Setup(&fmt
, VLC_CODEC_YUVP
, ov
->w
, ov
->h
, ov
->w
, ov
->h
, 1, 1);
1446 p_reg
= subpicture_region_New(&fmt
);
1449 /* Append it to our list. */
1451 p_last
->p_next
= p_reg
;
1452 else /* If we don't have a last region, then our list empty */
1453 p_sys
->p_overlays
[ov
->plane
]->p_regions
= p_reg
;
1456 /* Now we can update the region, regardless it's an update or an insert */
1457 const BD_PG_RLE_ELEM
*img
= ov
->img
;
1458 for (int y
= 0; y
< ov
->h
; y
++)
1459 for (int x
= 0; x
< ov
->w
;) {
1460 plane_t
*p
= &p_reg
->p_picture
->p
[0];
1461 memset(&p
->p_pixels
[y
* p
->i_pitch
+ x
], img
->color
, img
->len
);
1467 p_reg
->fmt
.p_palette
->i_entries
= 256;
1468 for (int i
= 0; i
< 256; ++i
) {
1469 p_reg
->fmt
.p_palette
->palette
[i
][0] = ov
->palette
[i
].Y
;
1470 p_reg
->fmt
.p_palette
->palette
[i
][1] = ov
->palette
[i
].Cb
;
1471 p_reg
->fmt
.p_palette
->palette
[i
][2] = ov
->palette
[i
].Cr
;
1472 p_reg
->fmt
.p_palette
->palette
[i
][3] = ov
->palette
[i
].T
;
1476 vlc_mutex_unlock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1478 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1482 static void blurayOverlayProc(void *ptr
, const BD_OVERLAY
*const overlay
)
1484 demux_t
*p_demux
= (demux_t
*)ptr
;
1485 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1488 msg_Info(p_demux
, "Closing overlays.");
1490 for (int i
= 0; i
< MAX_OVERLAY
; i
++)
1491 blurayCloseOverlay(p_demux
, i
);
1495 switch (overlay
->cmd
) {
1496 case BD_OVERLAY_INIT
:
1497 msg_Info(p_demux
, "Initializing overlay");
1498 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1499 blurayInitOverlay(p_demux
, overlay
->plane
, overlay
->w
, overlay
->h
);
1500 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1502 case BD_OVERLAY_CLOSE
:
1503 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1504 blurayClearOverlay(p_demux
, overlay
->plane
);
1505 blurayCloseOverlay(p_demux
, overlay
->plane
);
1506 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1508 case BD_OVERLAY_CLEAR
:
1509 blurayClearOverlay(p_demux
, overlay
->plane
);
1511 case BD_OVERLAY_FLUSH
:
1512 blurayActivateOverlay(p_demux
, overlay
->plane
);
1514 case BD_OVERLAY_DRAW
:
1515 case BD_OVERLAY_WIPE
:
1516 blurayDrawOverlay(p_demux
, overlay
);
1519 msg_Warn(p_demux
, "Unknown BD overlay command: %u", overlay
->cmd
);
1525 * ARGB overlay (BD-J)
1527 static void blurayInitArgbOverlay(demux_t
*p_demux
, int plane
, int width
, int height
)
1529 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1531 blurayInitOverlay(p_demux
, plane
, width
, height
);
1533 if (!p_sys
->p_overlays
[plane
]->p_regions
) {
1535 video_format_Init(&fmt
, 0);
1536 video_format_Setup(&fmt
, VLC_CODEC_RGBA
, width
, height
, width
, height
, 1, 1);
1538 p_sys
->p_overlays
[plane
]->p_regions
= subpicture_region_New(&fmt
);
1542 static void blurayDrawArgbOverlay(demux_t
*p_demux
, const BD_ARGB_OVERLAY
* const ov
)
1544 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1546 vlc_mutex_lock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1548 /* Find a region to update */
1549 subpicture_region_t
*p_reg
= p_sys
->p_overlays
[ov
->plane
]->p_regions
;
1551 vlc_mutex_unlock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1555 /* Now we can update the region */
1556 const uint32_t *src0
= ov
->argb
;
1557 uint8_t *dst0
= p_reg
->p_picture
->p
[0].p_pixels
+
1558 p_reg
->p_picture
->p
[0].i_pitch
* ov
->y
+
1561 for (int y
= 0; y
< ov
->h
; y
++) {
1562 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1563 // - or add libbluray option to select the format ?
1564 for (int x
= 0; x
< ov
->w
; x
++) {
1565 dst0
[x
*4 ] = src0
[x
]>>16; /* R */
1566 dst0
[x
*4+1] = src0
[x
]>>8; /* G */
1567 dst0
[x
*4+2] = src0
[x
]; /* B */
1568 dst0
[x
*4+3] = src0
[x
]>>24; /* A */
1572 dst0
+= p_reg
->p_picture
->p
[0].i_pitch
;
1575 vlc_mutex_unlock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1577 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1581 static void blurayArgbOverlayProc(void *ptr
, const BD_ARGB_OVERLAY
*const overlay
)
1583 demux_t
*p_demux
= (demux_t
*)ptr
;
1584 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1586 switch (overlay
->cmd
) {
1587 case BD_ARGB_OVERLAY_INIT
:
1588 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1589 blurayInitArgbOverlay(p_demux
, overlay
->plane
, overlay
->w
, overlay
->h
);
1590 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1592 case BD_ARGB_OVERLAY_CLOSE
:
1593 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1594 blurayClearOverlay(p_demux
, overlay
->plane
);
1595 blurayCloseOverlay(p_demux
, overlay
->plane
);
1596 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1598 case BD_ARGB_OVERLAY_FLUSH
:
1599 blurayActivateOverlay(p_demux
, overlay
->plane
);
1601 case BD_ARGB_OVERLAY_DRAW
:
1602 blurayDrawArgbOverlay(p_demux
, overlay
);
1605 msg_Warn(p_demux
, "Unknown BD ARGB overlay command: %u", overlay
->cmd
);
1610 static void bluraySendOverlayToVout(demux_t
*p_demux
, bluray_overlay_t
*p_ov
)
1612 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1614 assert(p_ov
!= NULL
);
1615 assert(p_ov
->i_channel
== -1);
1617 if (p_ov
->p_updater
) {
1618 unref_subpicture_updater(p_ov
->p_updater
);
1619 p_ov
->p_updater
= NULL
;
1622 subpicture_t
*p_pic
= bluraySubpictureCreate(p_ov
);
1624 msg_Err(p_demux
, "bluraySubpictureCreate() failed");
1628 p_pic
->i_start
= p_pic
->i_stop
= mdate();
1629 p_pic
->i_channel
= vout_RegisterSubpictureChannel(p_sys
->p_vout
);
1630 p_ov
->i_channel
= p_pic
->i_channel
;
1633 * After this point, the picture should not be accessed from the demux thread,
1634 * as it is held by the vout thread.
1635 * This must be done only once per subpicture, ie. only once between each
1636 * blurayInitOverlay & blurayCloseOverlay call.
1638 vout_PutSubpicture(p_sys
->p_vout
, p_pic
);
1641 * Mark the picture as Outdated, as it contains no region for now.
1642 * This will make the subpicture_updater_t call pf_update
1644 p_ov
->status
= Outdated
;
1647 static void blurayUpdateTitleInfo(input_title_t
*t
, BLURAY_TITLE_INFO
*title_info
)
1649 t
->i_length
= FROM_TICKS(title_info
->duration
);
1651 for (int i
= 0; i
< t
->i_seekpoint
; i
++)
1652 vlc_seekpoint_Delete( t
->seekpoint
[i
] );
1653 TAB_CLEAN(t
->i_seekpoint
, t
->seekpoint
);
1655 for (unsigned int j
= 0; j
< title_info
->chapter_count
; j
++) {
1656 seekpoint_t
*s
= vlc_seekpoint_New();
1660 s
->i_time_offset
= FROM_TICKS(title_info
->chapters
[j
].start
);
1662 TAB_APPEND(t
->i_seekpoint
, t
->seekpoint
, s
);
1666 static void blurayInitTitles(demux_t
*p_demux
, int menu_titles
)
1668 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1669 const BLURAY_DISC_INFO
*di
= bd_get_disc_info(p_sys
->bluray
);
1671 /* get and set the titles */
1672 unsigned i_title
= menu_titles
;
1674 if (!p_sys
->b_menu
) {
1675 i_title
= bd_get_titles(p_sys
->bluray
, TITLES_RELEVANT
, 60);
1676 p_sys
->i_longest_title
= bd_get_main_title(p_sys
->bluray
);
1679 for (unsigned int i
= 0; i
< i_title
; i
++) {
1680 input_title_t
*t
= vlc_input_title_New();
1684 if (!p_sys
->b_menu
) {
1685 BLURAY_TITLE_INFO
*title_info
= bd_get_title_info(p_sys
->bluray
, i
, 0);
1686 blurayUpdateTitleInfo(t
, title_info
);
1687 bd_free_title_info(title_info
);
1689 } else if (i
== 0) {
1690 t
->psz_name
= strdup(_("Top Menu"));
1691 t
->i_flags
= INPUT_TITLE_MENU
| INPUT_TITLE_INTERACTIVE
;
1692 } else if (i
== i_title
- 1) {
1693 t
->psz_name
= strdup(_("First Play"));
1694 if (di
&& di
->first_play
&& di
->first_play
->interactive
) {
1695 t
->i_flags
= INPUT_TITLE_INTERACTIVE
;
1698 /* add possible title name from disc metadata */
1699 if (di
&& di
->titles
&& i
<= di
->num_titles
) {
1700 if (di
->titles
[i
]->name
) {
1701 t
->psz_name
= strdup(di
->titles
[i
]->name
);
1703 if (di
->titles
[i
]->interactive
) {
1704 t
->i_flags
= INPUT_TITLE_INTERACTIVE
;
1709 TAB_APPEND(p_sys
->i_title
, p_sys
->pp_title
, t
);
1713 static void blurayResetParser(demux_t
*p_demux
)
1716 * This is a hack and will have to be removed.
1717 * The parser should be flushed, and not destroy/created each time
1718 * we are changing title.
1720 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1721 if (p_sys
->p_parser
)
1722 vlc_demux_chained_Delete(p_sys
->p_parser
);
1724 p_sys
->p_parser
= vlc_demux_chained_New(VLC_OBJECT(p_demux
), "ts", p_sys
->p_out
);
1726 if (!p_sys
->p_parser
)
1727 msg_Err(p_demux
, "Failed to create TS demuxer");
1730 /*****************************************************************************
1731 * bluraySetTitle: select new BD title
1732 *****************************************************************************/
1733 static int bluraySetTitle(demux_t
*p_demux
, int i_title
)
1735 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1737 if (p_sys
->b_menu
) {
1740 msg_Dbg(p_demux
, "Playing TopMenu Title");
1741 result
= bd_menu_call(p_sys
->bluray
, -1);
1742 } else if (i_title
>= (int)p_sys
->i_title
- 1) {
1743 msg_Dbg(p_demux
, "Playing FirstPlay Title");
1744 result
= bd_play_title(p_sys
->bluray
, BLURAY_TITLE_FIRST_PLAY
);
1746 msg_Dbg(p_demux
, "Playing Title %i", i_title
);
1747 result
= bd_play_title(p_sys
->bluray
, i_title
);
1751 msg_Err(p_demux
, "cannot play bd title '%d'", i_title
);
1752 return VLC_EGENERIC
;
1758 /* Looking for the main title, ie the longest duration */
1760 i_title
= p_sys
->i_longest_title
;
1761 else if ((unsigned)i_title
> p_sys
->i_title
)
1762 return VLC_EGENERIC
;
1764 msg_Dbg(p_demux
, "Selecting Title %i", i_title
);
1766 if (bd_select_title(p_sys
->bluray
, i_title
) == 0) {
1767 msg_Err(p_demux
, "cannot select bd title '%d'", i_title
);
1768 return VLC_EGENERIC
;
1774 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
1775 # define BLURAY_AUDIO_STREAM 0
1778 static void blurayStreamSelected(demux_sys_t
*p_sys
, int i_pid
)
1780 vlc_mutex_lock(&p_sys
->pl_info_lock
);
1782 if (p_sys
->p_clip_info
) {
1783 if ((i_pid
& 0xff00) == 0x1100) {
1785 for (int i_id
= 0; i_id
< p_sys
->p_clip_info
->audio_stream_count
; i_id
++) {
1786 if (i_pid
== p_sys
->p_clip_info
->audio_streams
[i_id
].pid
) {
1787 p_sys
->i_audio_stream_idx
= i_id
;
1788 bd_select_stream(p_sys
->bluray
, BLURAY_AUDIO_STREAM
, i_id
+ 1, 1);
1792 } else if ((i_pid
& 0xff00) == 0x1400 || i_pid
== 0x1800) {
1794 for (int i_id
= 0; i_id
< p_sys
->p_clip_info
->pg_stream_count
; i_id
++) {
1795 if (i_pid
== p_sys
->p_clip_info
->pg_streams
[i_id
].pid
) {
1796 p_sys
->i_spu_stream_idx
= i_id
;
1797 bd_select_stream(p_sys
->bluray
, BLURAY_PG_TEXTST_STREAM
, i_id
+ 1, 1);
1804 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
1807 /*****************************************************************************
1808 * blurayControl: handle the controls
1809 *****************************************************************************/
1810 static int blurayControl(demux_t
*p_demux
, int query
, va_list args
)
1812 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1817 case DEMUX_CAN_SEEK
:
1818 case DEMUX_CAN_PAUSE
:
1819 case DEMUX_CAN_CONTROL_PACE
:
1820 pb_bool
= va_arg(args
, bool *);
1824 case DEMUX_GET_PTS_DELAY
:
1825 pi_64
= va_arg(args
, int64_t *);
1826 *pi_64
= INT64_C(1000) * var_InheritInteger(p_demux
, "disc-caching");
1829 case DEMUX_SET_PAUSE_STATE
:
1831 #ifdef BLURAY_RATE_NORMAL
1832 bool b_paused
= (bool)va_arg(args
, int);
1833 if (bd_set_rate(p_sys
->bluray
, BLURAY_RATE_NORMAL
* (!b_paused
)) < 0) {
1834 return VLC_EGENERIC
;
1841 int i_id
= va_arg(args
, int);
1842 blurayStreamSelected(p_sys
, i_id
);
1845 case DEMUX_SET_TITLE
:
1847 int i_title
= va_arg(args
, int);
1848 if (bluraySetTitle(p_demux
, i_title
) != VLC_SUCCESS
) {
1849 /* make sure GUI restores the old setting in title menu ... */
1850 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
1851 return VLC_EGENERIC
;
1853 blurayResetParser( p_demux
);
1854 notifyDiscontinuity( p_sys
);
1857 case DEMUX_SET_SEEKPOINT
:
1859 int i_chapter
= va_arg(args
, int);
1860 bd_seek_chapter(p_sys
->bluray
, i_chapter
);
1861 notifyDiscontinuity( p_sys
);
1862 p_sys
->updates
|= INPUT_UPDATE_SEEKPOINT
;
1865 case DEMUX_TEST_AND_CLEAR_FLAGS
:
1867 unsigned *restrict flags
= va_arg(args
, unsigned *);
1868 *flags
&= p_sys
->updates
;
1869 p_sys
->updates
&= ~*flags
;
1872 case DEMUX_GET_TITLE
:
1873 *va_arg(args
, int *) = p_sys
->cur_title
;
1876 case DEMUX_GET_SEEKPOINT
:
1877 *va_arg(args
, int *) = p_sys
->cur_seekpoint
;
1880 case DEMUX_GET_TITLE_INFO
:
1882 input_title_t
***ppp_title
= va_arg(args
, input_title_t
***);
1883 int *pi_int
= va_arg(args
, int *);
1884 int *pi_title_offset
= va_arg(args
, int *);
1885 int *pi_chapter_offset
= va_arg(args
, int *);
1888 *pi_title_offset
= 0;
1889 *pi_chapter_offset
= 0;
1891 /* Duplicate local title infos */
1893 *ppp_title
= vlc_alloc(p_sys
->i_title
, sizeof(input_title_t
*));
1895 return VLC_EGENERIC
;
1896 for (unsigned int i
= 0; i
< p_sys
->i_title
; i
++)
1898 input_title_t
*p_dup
= vlc_input_title_Duplicate(p_sys
->pp_title
[i
]);
1900 (*ppp_title
)[(*pi_int
)++] = p_dup
;
1906 case DEMUX_GET_LENGTH
:
1908 int64_t *pi_length
= va_arg(args
, int64_t *);
1909 *pi_length
= p_sys
->cur_title
< p_sys
->i_title
? CUR_LENGTH
: 0;
1912 case DEMUX_SET_TIME
:
1914 int64_t i_time
= va_arg(args
, int64_t);
1915 bd_seek_time(p_sys
->bluray
, TO_TICKS(i_time
));
1916 notifyDiscontinuity( p_sys
);
1919 case DEMUX_GET_TIME
:
1921 int64_t *pi_time
= va_arg(args
, int64_t *);
1922 *pi_time
= (int64_t)FROM_TICKS(bd_tell_time(p_sys
->bluray
));
1926 case DEMUX_GET_POSITION
:
1928 double *pf_position
= va_arg(args
, double *);
1929 *pf_position
= p_sys
->cur_title
< p_sys
->i_title
&& CUR_LENGTH
> 0 ?
1930 (double)FROM_TICKS(bd_tell_time(p_sys
->bluray
))/CUR_LENGTH
: 0.0;
1933 case DEMUX_SET_POSITION
:
1935 double f_position
= va_arg(args
, double);
1936 bd_seek_time(p_sys
->bluray
, TO_TICKS(f_position
*CUR_LENGTH
));
1937 notifyDiscontinuity( p_sys
);
1941 case DEMUX_GET_META
:
1943 vlc_meta_t
*p_meta
= va_arg(args
, vlc_meta_t
*);
1944 const META_DL
*meta
= p_sys
->p_meta
;
1946 return VLC_EGENERIC
;
1948 if (!EMPTY_STR(meta
->di_name
)) vlc_meta_SetTitle(p_meta
, meta
->di_name
);
1950 if (!EMPTY_STR(meta
->language_code
)) vlc_meta_AddExtra(p_meta
, "Language", meta
->language_code
);
1951 if (!EMPTY_STR(meta
->filename
)) vlc_meta_AddExtra(p_meta
, "Filename", meta
->filename
);
1952 if (!EMPTY_STR(meta
->di_alternative
)) vlc_meta_AddExtra(p_meta
, "Alternative", meta
->di_alternative
);
1954 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
1955 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
1957 if (p_sys
->i_cover_idx
>= 0 && p_sys
->i_cover_idx
< p_sys
->i_attachments
) {
1959 snprintf( psz_url
, sizeof(psz_url
), "attachment://%s",
1960 p_sys
->attachments
[p_sys
->i_cover_idx
]->psz_name
);
1961 vlc_meta_Set( p_meta
, vlc_meta_ArtworkURL
, psz_url
);
1963 else if (meta
->thumb_count
> 0 && meta
->thumbnails
&& p_sys
->psz_bd_path
) {
1964 char *psz_thumbpath
;
1965 if (asprintf(&psz_thumbpath
, "%s" DIR_SEP
"BDMV" DIR_SEP
"META" DIR_SEP
"DL" DIR_SEP
"%s",
1966 p_sys
->psz_bd_path
, meta
->thumbnails
[0].path
) > -1) {
1967 char *psz_thumburl
= vlc_path2uri(psz_thumbpath
, "file");
1968 free(psz_thumbpath
);
1969 if (unlikely(psz_thumburl
== NULL
))
1972 vlc_meta_SetArtURL(p_meta
, psz_thumburl
);
1980 case DEMUX_GET_ATTACHMENTS
:
1982 input_attachment_t
***ppp_attach
=
1983 va_arg(args
, input_attachment_t
***);
1984 int *pi_int
= va_arg(args
, int *);
1986 if (p_sys
->i_attachments
<= 0)
1987 return VLC_EGENERIC
;
1990 *ppp_attach
= vlc_alloc(p_sys
->i_attachments
, sizeof(input_attachment_t
*));
1992 return VLC_EGENERIC
;
1993 for (int i
= 0; i
< p_sys
->i_attachments
; i
++)
1995 input_attachment_t
*p_dup
= vlc_input_attachment_Duplicate(p_sys
->attachments
[i
]);
1997 (*ppp_attach
)[(*pi_int
)++] = p_dup
;
2002 case DEMUX_NAV_ACTIVATE
:
2003 if (p_sys
->b_popup_available
&& !p_sys
->b_menu_open
) {
2004 return sendKeyEvent(p_sys
, BD_VK_POPUP
);
2006 return sendKeyEvent(p_sys
, BD_VK_ENTER
);
2008 return sendKeyEvent(p_sys
, BD_VK_UP
);
2009 case DEMUX_NAV_DOWN
:
2010 return sendKeyEvent(p_sys
, BD_VK_DOWN
);
2011 case DEMUX_NAV_LEFT
:
2012 return sendKeyEvent(p_sys
, BD_VK_LEFT
);
2013 case DEMUX_NAV_RIGHT
:
2014 return sendKeyEvent(p_sys
, BD_VK_RIGHT
);
2015 case DEMUX_NAV_POPUP
:
2016 return sendKeyEvent(p_sys
, BD_VK_POPUP
);
2017 case DEMUX_NAV_MENU
:
2018 if (p_sys
->b_menu
) {
2019 if (bd_menu_call(p_sys
->bluray
, -1) == 1) {
2020 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2023 msg_Err(p_demux
, "Can't select Top Menu title");
2024 return sendKeyEvent(p_sys
, BD_VK_POPUP
);
2026 return VLC_EGENERIC
;
2028 case DEMUX_CAN_RECORD
:
2030 case DEMUX_SET_GROUP
:
2031 case DEMUX_HAS_UNSUPPORTED_META
:
2033 return VLC_EGENERIC
;
2038 /*****************************************************************************
2039 * libbluray event handling
2040 *****************************************************************************/
2041 static void notifyStreamsDiscontinuity( vlc_demux_chained_t
*p_parser
,
2042 const BLURAY_STREAM_INFO
*p_sinfo
, size_t i_sinfo
)
2044 for( size_t i
=0; i
< i_sinfo
; i
++ )
2046 const uint16_t i_pid
= p_sinfo
[i
].pid
;
2048 block_t
*p_block
= block_Alloc(192);
2052 uint8_t ts_header
[] = {
2053 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2055 (i_pid
& 0x1f00) >> 8, i_pid
& 0xFF, /* PID */
2056 0x20, /* adaptation field, no payload */
2057 183, /* adaptation field length */
2058 0x80, /* adaptation field: discontinuity indicator */
2061 memcpy(p_block
->p_buffer
, ts_header
, sizeof(ts_header
));
2062 memset(&p_block
->p_buffer
[sizeof(ts_header
)], 0xFF, 192 - sizeof(ts_header
));
2063 p_block
->i_buffer
= 192;
2065 vlc_demux_chained_Send(p_parser
, p_block
);
2069 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2070 p_clip->memb##_stream_count )
2072 static void notifyDiscontinuity( demux_sys_t
*p_sys
)
2074 const BLURAY_CLIP_INFO
*p_clip
= p_sys
->p_clip_info
;
2081 DONOTIFY(sec_audio
);
2082 DONOTIFY(sec_video
);
2088 static void streamFlush( demux_sys_t
*p_sys
)
2091 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2092 * Packet is flushed only when TS packet with PUSI flag set is received.
2094 * Fix this by emitting (video) ts packet with PUSI flag set.
2095 * Add video sequence end code to payload so that also video decoder is flushed.
2096 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2099 if (p_sys
->b_flushed
)
2102 block_t
*p_block
= block_Alloc(192);
2106 static const uint8_t seq_end_pes
[] = {
2107 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2108 0x00, 0x00, 0x01, 0xb7, /* PES payload: sequence end */
2110 static const uint8_t vid_pusi_ts
[] = {
2111 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2112 0x47, 0x50, 0x11, 0x30, /* TP header */
2113 (192 - (4 + 5) - sizeof(seq_end_pes
)), /* adaptation field length */
2114 0x82, /* af: discontinuity indicator + priv data */
2115 0x0E, /* priv data size */
2117 'S', 'T', 'I', 'L', 'L', 'F', 'R', 'A', 'M', 'E',
2120 memset(p_block
->p_buffer
, 0, 192);
2121 memcpy(p_block
->p_buffer
, vid_pusi_ts
, sizeof(vid_pusi_ts
));
2122 memcpy(p_block
->p_buffer
+ 192 - sizeof(seq_end_pes
), seq_end_pes
, sizeof(seq_end_pes
));
2123 p_block
->i_buffer
= 192;
2125 /* set correct sequence end code */
2126 vlc_mutex_lock(&p_sys
->pl_info_lock
);
2127 if (p_sys
->p_clip_info
!= NULL
) {
2128 if (p_sys
->p_clip_info
->video_streams
[0].coding_type
> 2) {
2129 /* VC1 / H.264 sequence end */
2130 p_block
->p_buffer
[191] = 0x0a;
2133 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
2135 vlc_demux_chained_Send(p_sys
->p_parser
, p_block
);
2136 p_sys
->b_flushed
= true;
2139 static void blurayResetStillImage( demux_t
*p_demux
)
2141 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2143 if (p_sys
->i_still_end_time
) {
2144 p_sys
->i_still_end_time
= 0;
2146 blurayResetParser(p_demux
);
2147 es_out_Control( p_demux
->out
, ES_OUT_RESET_PCR
);
2151 static void blurayStillImage( demux_t
*p_demux
, unsigned i_timeout
)
2153 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2155 /* time period elapsed ? */
2156 if (p_sys
->i_still_end_time
> 0 && p_sys
->i_still_end_time
<= mdate()) {
2157 msg_Dbg(p_demux
, "Still image end");
2158 bd_read_skip_still(p_sys
->bluray
);
2160 blurayResetStillImage(p_demux
);
2164 /* show last frame as still image */
2165 if (!p_sys
->i_still_end_time
) {
2167 msg_Dbg(p_demux
, "Still image (%d seconds)", i_timeout
);
2168 p_sys
->i_still_end_time
= mdate() + i_timeout
* CLOCK_FREQ
;
2170 msg_Dbg(p_demux
, "Still image (infinite)");
2171 p_sys
->i_still_end_time
= -1;
2174 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2177 /* stop buffering */
2179 es_out_Control( p_demux
->out
, ES_OUT_GET_EMPTY
, &b_empty
);
2182 /* avoid busy loops (read returns no data) */
2186 static void blurayStreamSelect(demux_t
*p_demux
, uint32_t i_type
, uint32_t i_id
)
2188 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2191 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2194 if (i_type
== BD_EVENT_AUDIO_STREAM
) {
2195 p_sys
->i_audio_stream_idx
= i_id
;
2196 i_pid
= blurayEsPid(p_sys
, AUDIO_ES
, i_id
);
2197 } else if (i_type
== BD_EVENT_PG_TEXTST_STREAM
) {
2198 p_sys
->i_spu_stream_idx
= i_id
;
2199 i_pid
= blurayEsPid(p_sys
, SPU_ES
, i_id
);
2203 int i_idx
= findEsPairIndex(p_sys
, i_pid
);
2205 if (i_type
== BD_EVENT_AUDIO_STREAM
) {
2206 var_SetInteger( p_demux
->p_input
, "audio-es", i_pid
);
2207 } else if (i_type
== BD_EVENT_PG_TEXTST_STREAM
) {
2208 var_SetInteger( p_demux
->p_input
, "spu-es", p_sys
->b_spu_enable
? i_pid
: -1 );
2214 static void blurayUpdatePlaylist(demux_t
*p_demux
, unsigned i_playlist
)
2216 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2218 blurayResetParser(p_demux
);
2220 /* read title info and init some values */
2222 p_sys
->cur_title
= bd_get_current_title(p_sys
->bluray
);
2223 p_sys
->cur_seekpoint
= 0;
2224 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2226 BLURAY_TITLE_INFO
*p_title_info
= bd_get_playlist_info(p_sys
->bluray
, i_playlist
, 0);
2228 blurayUpdateTitleInfo(p_sys
->pp_title
[p_sys
->cur_title
], p_title_info
);
2230 p_sys
->updates
|= INPUT_UPDATE_TITLE_LIST
;
2232 setTitleInfo(p_sys
, p_title_info
);
2234 blurayResetStillImage(p_demux
);
2237 static void blurayUpdateCurrentClip(demux_t
*p_demux
, uint32_t clip
)
2239 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2241 vlc_mutex_lock(&p_sys
->pl_info_lock
);
2243 p_sys
->p_clip_info
= NULL
;
2244 p_sys
->i_video_stream
= -1;
2246 if (p_sys
->p_pl_info
&& clip
< p_sys
->p_pl_info
->clip_count
) {
2248 p_sys
->p_clip_info
= &p_sys
->p_pl_info
->clips
[clip
];
2250 /* Let's assume a single video track for now.
2251 * This may brake later, but it's enough for now.
2253 assert(p_sys
->p_clip_info
->video_stream_count
>= 1);
2254 p_sys
->i_video_stream
= p_sys
->p_clip_info
->video_streams
[0].pid
;
2257 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
2259 blurayResetStillImage(p_demux
);
2262 static void blurayHandleEvent(demux_t
*p_demux
, const BD_EVENT
*e
)
2264 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2267 case BD_EVENT_TITLE
:
2268 if (e
->param
== BLURAY_TITLE_FIRST_PLAY
)
2269 p_sys
->cur_title
= p_sys
->i_title
- 1;
2271 p_sys
->cur_title
= e
->param
;
2272 /* this is feature title, we don't know yet which playlist it will play (if any) */
2273 setTitleInfo(p_sys
, NULL
);
2274 /* reset title infos here ? */
2275 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2276 /* might be BD-J title with no video */
2278 case BD_EVENT_PLAYLIST
:
2279 /* Start of playlist playback (?????.mpls) */
2280 blurayUpdatePlaylist(p_demux
, e
->param
);
2281 if (p_sys
->b_pl_playing
) {
2282 /* previous playlist was stopped in middle. flush to avoid delay */
2283 msg_Info(p_demux
, "Stopping playlist playback");
2284 blurayResetParser(p_demux
);
2285 es_out_Control( p_demux
->out
, ES_OUT_RESET_PCR
);
2287 p_sys
->b_pl_playing
= true;
2289 case BD_EVENT_PLAYITEM
:
2290 blurayUpdateCurrentClip(p_demux
, e
->param
);
2292 case BD_EVENT_CHAPTER
:
2293 if (e
->param
&& e
->param
< 0xffff)
2294 p_sys
->cur_seekpoint
= e
->param
- 1;
2296 p_sys
->cur_seekpoint
= 0;
2297 p_sys
->updates
|= INPUT_UPDATE_SEEKPOINT
;
2299 case BD_EVENT_PLAYMARK
:
2300 case BD_EVENT_ANGLE
:
2302 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2303 case BD_EVENT_UO_MASK_CHANGED
:
2304 /* This event could be used to grey out unselectable items in title menu */
2308 p_sys
->b_menu_open
= e
->param
;
2310 case BD_EVENT_POPUP
:
2311 p_sys
->b_popup_available
= e
->param
;
2312 /* TODO: show / hide pop-up menu button in gui ? */
2318 case BD_EVENT_ERROR
:
2319 /* fatal error (with menus) */
2320 vlc_dialog_display_error(p_demux
, _("Blu-ray error"),
2321 "Playback with BluRay menus failed");
2322 p_sys
->b_fatal_error
= true;
2324 case BD_EVENT_ENCRYPTED
:
2325 vlc_dialog_display_error(p_demux
, _("Blu-ray error"),
2326 "This disc seems to be encrypted");
2327 p_sys
->b_fatal_error
= true;
2329 case BD_EVENT_READ_ERROR
:
2330 msg_Err(p_demux
, "bluray: read error\n");
2334 * stream selection events
2336 case BD_EVENT_PG_TEXTST
:
2337 p_sys
->b_spu_enable
= e
->param
;
2339 case BD_EVENT_AUDIO_STREAM
:
2340 case BD_EVENT_PG_TEXTST_STREAM
:
2341 blurayStreamSelect(p_demux
, e
->event
, e
->param
);
2343 case BD_EVENT_IG_STREAM
:
2344 case BD_EVENT_SECONDARY_AUDIO
:
2345 case BD_EVENT_SECONDARY_AUDIO_STREAM
:
2346 case BD_EVENT_SECONDARY_VIDEO
:
2347 case BD_EVENT_SECONDARY_VIDEO_STREAM
:
2348 case BD_EVENT_SECONDARY_VIDEO_SIZE
:
2352 * playback control events
2354 case BD_EVENT_STILL_TIME
:
2355 blurayStillImage(p_demux
, e
->param
);
2357 case BD_EVENT_DISCONTINUITY
:
2358 /* reset demuxer (partially decoded PES packets must be dropped) */
2359 blurayResetParser(p_demux
);
2361 case BD_EVENT_END_OF_TITLE
:
2362 p_sys
->b_pl_playing
= false;
2365 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2366 /* avoid busy loop (bd_read() returns no data) */
2371 msg_Warn(p_demux
, "event: %d param: %d", e
->event
, e
->param
);
2376 static bool blurayIsBdjTitle(demux_t
*p_demux
)
2378 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2379 unsigned int i_title
= p_sys
->cur_title
;
2380 const BLURAY_DISC_INFO
*di
= bd_get_disc_info(p_sys
->bluray
);
2382 if (di
&& di
->titles
) {
2383 if ((i_title
<= di
->num_titles
&& di
->titles
[i_title
] && di
->titles
[i_title
]->bdj
) ||
2384 (i_title
== p_sys
->i_title
- 1 && di
->first_play
&& di
->first_play
->bdj
)) {
2392 static void blurayHandleOverlays(demux_t
*p_demux
, int nread
)
2394 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2396 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
2398 for (int i
= 0; i
< MAX_OVERLAY
; i
++) {
2399 bluray_overlay_t
*ov
= p_sys
->p_overlays
[i
];
2403 vlc_mutex_lock(&ov
->lock
);
2404 bool display
= ov
->status
== ToDisplay
;
2405 vlc_mutex_unlock(&ov
->lock
);
2407 if (p_sys
->p_vout
== NULL
) {
2408 p_sys
->p_vout
= input_GetVout(p_demux
->p_input
);
2409 if (p_sys
->p_vout
!= NULL
) {
2410 var_AddCallback(p_sys
->p_vout
, "mouse-moved", onMouseEvent
, p_demux
);
2411 var_AddCallback(p_sys
->p_vout
, "mouse-clicked", onMouseEvent
, p_demux
);
2415 /* NOTE: we might want to enable background video always when there's no video stream playing.
2416 Now, with some discs, there are perioids (even seconds) during which the video window
2417 disappears and just playlist is shown.
2418 (sometimes BD-J runs slowly ...)
2420 if (!p_sys
->p_vout
&& !p_sys
->p_dummy_video
&& p_sys
->b_menu
&&
2421 !p_sys
->p_pl_info
&& nread
== 0 &&
2422 blurayIsBdjTitle(p_demux
)) {
2424 /* Looks like there's no video stream playing.
2425 Emit blank frame so that BD-J overlay can be drawn. */
2426 startBackground(p_demux
);
2429 if (p_sys
->p_vout
!= NULL
) {
2430 bluraySendOverlayToVout(p_demux
, ov
);
2435 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
2438 static int onIntfEvent( vlc_object_t
*p_input
, char const *psz_var
,
2439 vlc_value_t oldval
, vlc_value_t val
, void *p_data
)
2441 (void)p_input
; (void) psz_var
; (void) oldval
;
2442 demux_t
*p_demux
= p_data
;
2443 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2445 if (val
.i_int
== INPUT_EVENT_VOUT
) {
2447 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
2448 if( p_sys
->p_vout
!= NULL
) {
2449 blurayReleaseVout(p_demux
);
2451 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
2453 blurayHandleOverlays(p_demux
, 1);
2459 #define BD_TS_PACKET_SIZE (192)
2460 #define NB_TS_PACKETS (200)
2462 static int blurayDemux(demux_t
*p_demux
)
2464 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2467 block_t
*p_block
= block_Alloc(NB_TS_PACKETS
* (int64_t)BD_TS_PACKET_SIZE
);
2469 return VLC_DEMUXER_EGENERIC
;
2473 if (p_sys
->b_menu
== false) {
2474 while (bd_get_event(p_sys
->bluray
, &e
))
2475 blurayHandleEvent(p_demux
, &e
);
2477 nread
= bd_read(p_sys
->bluray
, p_block
->p_buffer
,
2478 NB_TS_PACKETS
* BD_TS_PACKET_SIZE
);
2480 nread
= bd_read_ext(p_sys
->bluray
, p_block
->p_buffer
,
2481 NB_TS_PACKETS
* BD_TS_PACKET_SIZE
, &e
);
2482 while (e
.event
!= BD_EVENT_NONE
) {
2483 blurayHandleEvent(p_demux
, &e
);
2484 bd_get_event(p_sys
->bluray
, &e
);
2488 blurayHandleOverlays(p_demux
, nread
);
2491 block_Release(p_block
);
2492 if (p_sys
->b_fatal_error
|| nread
< 0) {
2493 msg_Err(p_demux
, "bluray: stopping playback after fatal error\n");
2494 return VLC_DEMUXER_EGENERIC
;
2496 if (!p_sys
->b_menu
) {
2497 return VLC_DEMUXER_EOF
;
2499 return VLC_DEMUXER_SUCCESS
;
2502 p_block
->i_buffer
= nread
;
2504 stopBackground(p_demux
);
2506 vlc_demux_chained_Send(p_sys
->p_parser
, p_block
);
2508 p_sys
->b_flushed
= false;
2510 return VLC_DEMUXER_SUCCESS
;