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 *****************************************************************************/
30 #if defined (HAVE_MNTENT_H) && defined(HAVE_SYS_STAT_H)
33 #include <fcntl.h> /* O_* */
34 #include <unistd.h> /* close() */
38 # include <sys/param.h>
39 # include <sys/ucred.h>
40 # include <sys/mount.h>
43 #include <vlc_common.h>
44 #include <vlc_plugin.h>
45 #include <vlc_demux.h> /* demux_t */
46 #include <vlc_input.h> /* Seekpoints, chapters */
47 #include <vlc_atomic.h>
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", 200)
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 vlc_mutex_t pl_info_lock;
154 BLURAY_TITLE_INFO *p_pl_info;
155 const BLURAY_CLIP_INFO *p_clip_info;
159 input_attachment_t **attachments;
162 /* Meta information */
163 const META_DL *p_meta;
166 bluray_overlay_t *p_overlays[MAX_OVERLAY];
170 bool b_popup_available;
171 mtime_t i_still_end_time;
173 vlc_mutex_t bdj_overlay_lock; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
176 vout_thread_t *p_vout;
178 es_out_id_t *p_dummy_video;
183 int i_audio_stream_idx; /* Selected audio stream. -1 if default */
184 int i_spu_stream_idx; /* Selected subtitle stream. -1 if default */
185 bool b_spu_enable; /* enabled / disabled */
187 vlc_demux_chained_t *p_parser;
189 bool b_pl_playing; /* true when playing playlist */
192 vlc_mutex_t read_block_lock;
194 /* Used to store bluray disc path */
198 struct subpicture_updater_sys_t
200 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
201 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
202 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
206 * cut the connection between vout and overlay.
207 * - called when vout is closed or overlay is closed.
208 * - frees subpicture_updater_sys_t when both sides have been closed.
210 static void unref_subpicture_updater(subpicture_updater_sys_t *p_sys)
212 vlc_mutex_lock(&p_sys->lock);
213 int refs = --p_sys->ref_cnt;
214 p_sys->p_overlay = NULL;
215 vlc_mutex_unlock(&p_sys->lock);
218 vlc_mutex_destroy(&p_sys->lock);
224 * FIXME: partiallyy duplicated from src/input/es_out.c
226 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
228 const iso639_lang_t *pl;
232 psz_lang = var_CreateGetString( p_demux, psz_var );
234 return LANGUAGE_DEFAULT;
236 /* XXX: we will use only the first value
237 * (and ignore other ones in case of a list) */
238 if( ( p = strchr( psz_lang, ',' ) ) )
241 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
243 if( *psz_lang == '\0' )
245 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
246 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
247 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
248 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
254 if( pl->psz_eng_name != NULL )
255 return pl->psz_iso639_2T;
257 return LANGUAGE_DEFAULT;
260 /*****************************************************************************
262 *****************************************************************************/
263 static es_out_t *esOutNew(demux_t *p_demux);
265 static int blurayControl(demux_t *, int, va_list);
266 static int blurayDemux(demux_t *);
268 static void blurayInitTitles(demux_t *p_demux, int menu_titles);
269 static int bluraySetTitle(demux_t *p_demux, int i_title);
271 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
272 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
274 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var,
275 vlc_value_t old, vlc_value_t val, void *p_data);
276 static int onIntfEvent(vlc_object_t *, char const *,
277 vlc_value_t, vlc_value_t, void *);
279 static void blurayResetParser(demux_t *p_demux);
281 #define FROM_TICKS(a) ((a)*CLOCK_FREQ / INT64_C(90000))
282 #define TO_TICKS(a) ((a)*INT64_C(90000)/CLOCK_FREQ)
283 #define CUR_LENGTH p_sys->pp_title[p_demux->info.i_title]->i_length
286 static void FindMountPoint(char **file)
288 char *device = *file;
289 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
290 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
291 * we look up the real device */
292 char *bd_device = realpath(device, NULL);
293 if (bd_device == NULL)
297 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
298 FILE *mtab = setmntent ("/proc/self/mounts", "r");
299 struct mntent *m, mbuf;
302 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
303 if (!strcmp (m->mnt_fsname, bd_device)) {
305 *file = strdup(m->mnt_dir);
313 #elif defined(__APPLE__)
315 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
316 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
318 struct statfs mbuf[128];
319 getfsstat (mbuf, fs_count * sizeof(mbuf[0]), MNT_NOWAIT);
320 for (int i = 0; i < fs_count; ++i)
321 if (!strcmp (mbuf[i].f_mntfromname, device)) {
323 *file = strdup(mbuf[i].f_mntonname);
329 # warning Disc device to mount point not implemented
330 VLC_UNUSED( device );
334 static void blurayReleaseVout(demux_t *p_demux)
336 demux_sys_t *p_sys = p_demux->p_sys;
338 if (p_sys->p_vout != NULL) {
339 var_DelCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
340 var_DelCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
342 for (int i = 0; i < MAX_OVERLAY; i++) {
343 bluray_overlay_t *p_ov = p_sys->p_overlays[i];
345 vlc_mutex_lock(&p_ov->lock);
346 if (p_ov->i_channel != -1) {
347 msg_Err(p_demux, "blurayReleaseVout: subpicture channel exists\n");
348 vout_FlushSubpictureChannel(p_sys->p_vout, p_ov->i_channel);
350 p_ov->i_channel = -1;
351 p_ov->status = ToDisplay;
352 vlc_mutex_unlock(&p_ov->lock);
354 if (p_ov->p_updater) {
355 unref_subpicture_updater(p_ov->p_updater);
356 p_ov->p_updater = NULL;
361 vlc_object_release(p_sys->p_vout);
362 p_sys->p_vout = NULL;
366 /*****************************************************************************
367 * BD-J background video
368 *****************************************************************************/
370 static void startBackground(demux_t *p_demux)
372 demux_sys_t *p_sys = p_demux->p_sys;
374 if (p_sys->p_dummy_video) {
378 msg_Info(p_demux, "Start background");
382 es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_I420 );
383 video_format_Setup( &fmt.video, VLC_CODEC_I420,
384 1920, 1080, 1920, 1080, 1, 1);
385 fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
386 fmt.i_id = 4115; /* 4113 = main video. 4114 = MVC. 4115 = unused. */
389 p_sys->p_dummy_video = es_out_Add(p_demux->out, &fmt);
391 if (!p_sys->p_dummy_video) {
392 msg_Err(p_demux, "Error adding background ES");
396 block_t *p_block = block_Alloc(fmt.video.i_width * fmt.video.i_height *
397 fmt.video.i_bits_per_pixel / 8);
399 msg_Err(p_demux, "Error allocating block for background video");
403 // XXX TODO: what would be correct timestamp ???
404 p_block->i_dts = p_block->i_pts = mdate() + CLOCK_FREQ/25;
406 uint8_t *p = p_block->p_buffer;
407 memset(p, 0, fmt.video.i_width * fmt.video.i_height);
408 p += fmt.video.i_width * fmt.video.i_height;
409 memset(p, 0x80, fmt.video.i_width * fmt.video.i_height / 2);
411 es_out_Send(p_demux->out, p_sys->p_dummy_video, p_block);
414 es_format_Clean(&fmt);
417 static void stopBackground(demux_t *p_demux)
419 demux_sys_t *p_sys = p_demux->p_sys;
421 if (!p_sys->p_dummy_video) {
425 msg_Info(p_demux, "Stop background");
427 es_out_Del(p_demux->out, p_sys->p_dummy_video);
428 p_sys->p_dummy_video = NULL;
431 /*****************************************************************************
432 * cache current playlist (title) information
433 *****************************************************************************/
435 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
437 vlc_mutex_lock(&p_sys->pl_info_lock);
439 if (p_sys->p_pl_info) {
440 bd_free_title_info(p_sys->p_pl_info);
442 p_sys->p_pl_info = info;
443 p_sys->p_clip_info = NULL;
445 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
446 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
449 vlc_mutex_unlock(&p_sys->pl_info_lock);
452 /*****************************************************************************
453 * create input attachment for thumbnail
454 *****************************************************************************/
456 static void attachThumbnail(demux_t *p_demux)
458 demux_sys_t *p_sys = p_demux->p_sys;
463 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
464 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
467 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
469 input_attachment_t *p_attachment;
471 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
473 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
475 p_sys->i_cover_idx = p_sys->i_attachments;
476 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
484 /*****************************************************************************
486 *****************************************************************************/
488 static int probeStream(demux_t *p_demux)
490 /* input must be seekable */
491 bool b_canseek = false;
492 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
497 /* first sector(s) should be filled with zeros */
499 const uint8_t *p_peek;
500 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
501 if( i_peek != 2048 ) {
505 if (p_peek[ --i_peek ]) {
514 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
516 demux_t *p_demux = (demux_t*)object;
517 demux_sys_t *p_sys = p_demux->p_sys;
520 assert(p_demux->s != NULL);
522 vlc_mutex_lock(&p_sys->read_block_lock);
524 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
525 size_t req = (size_t)2048 * num_blocks;
528 got = vlc_stream_Read( p_demux->s, buf, req);
530 msg_Err(p_demux, "read from lba %d failed", lba);
535 msg_Err(p_demux, "seek to lba %d failed", lba);
538 vlc_mutex_unlock(&p_sys->read_block_lock);
544 /*****************************************************************************
545 * probing of local files
546 *****************************************************************************/
548 /* Descriptor Tag (ECMA 167, 3/7.2) */
549 static int decode_descriptor_tag(const uint8_t *buf)
552 uint8_t checksum = 0;
555 id = buf[0] | (buf[1] << 8);
557 /* calculate tag checksum */
558 for (i = 0; i < 4; i++) {
559 checksum = (uint8_t)(checksum + buf[i]);
561 for (i = 5; i < 16; i++) {
562 checksum = (uint8_t)(checksum + buf[i]);
565 if (checksum != buf[4]) {
572 static int probeFile(const char *psz_name)
574 struct stat stat_info;
577 int ret = VLC_EGENERIC;
580 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
585 if (fstat(fd, &stat_info) == -1) {
588 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
592 /* first sector should be filled with zeros */
593 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
596 for (i = 0; i < sizeof(peek); i++) {
602 /* Check AVDP tag checksum */
603 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
604 read(fd, peek, 16) != 16 ||
605 decode_descriptor_tag(peek) != 2) {
616 /*****************************************************************************
617 * blurayOpen: module init function
618 *****************************************************************************/
619 static int blurayOpen(vlc_object_t *object)
621 demux_t *p_demux = (demux_t*)object;
624 uint64_t i_init_pos = 0;
626 const char *error_msg = NULL;
627 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
629 forced = !strcasecmp(p_demux->psz_access, "bluray");
632 if (p_demux->psz_access == NULL || !strcasecmp(p_demux->psz_access, "file")) {
633 /* use access_demux for local files */
637 if (probeStream(p_demux) != VLC_SUCCESS) {
641 } else if (!forced) {
642 if (!p_demux->psz_file) {
646 if (probeFile(p_demux->psz_file) != VLC_SUCCESS) {
652 p_demux->p_sys = p_sys = calloc(1, sizeof(*p_sys));
653 if (unlikely(!p_sys))
656 p_sys->i_audio_stream_idx = -1;
657 p_sys->i_spu_stream_idx = -1;
658 p_sys->i_video_stream = -1;
659 p_sys->i_still_end_time = 0;
661 /* init demux info fields */
662 p_demux->info.i_update = 0;
663 p_demux->info.i_title = 0;
664 p_demux->info.i_seekpoint = 0;
666 TAB_INIT(p_sys->i_title, p_sys->pp_title);
667 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
669 vlc_mutex_init(&p_sys->pl_info_lock);
670 vlc_mutex_init(&p_sys->bdj_overlay_lock);
671 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
673 var_AddCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
678 i_init_pos = vlc_stream_Tell(p_demux->s);
680 p_sys->bluray = bd_init();
681 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
682 bd_close(p_sys->bluray);
683 p_sys->bluray = NULL;
688 if (!p_demux->psz_file) {
689 /* no path provided (bluray://). use default DVD device. */
690 p_sys->psz_bd_path = var_InheritString(object, "dvd");
692 /* store current bd path */
693 p_sys->psz_bd_path = strdup(p_demux->psz_file);
696 /* If we're passed a block device, try to convert it to the mount point. */
697 FindMountPoint(&p_sys->psz_bd_path);
699 p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
701 if (!p_sys->bluray) {
705 /* Warning the user about AACS/BD+ */
706 const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
708 /* Is it a bluray? */
709 if (!disc_info->bluray_detected) {
711 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
716 msg_Info(p_demux, "First play: %i, Top menu: %i\n"
717 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
718 disc_info->first_play_supported, disc_info->top_menu_supported,
719 disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
720 disc_info->num_unsupported_titles);
723 if (disc_info->aacs_detected) {
724 msg_Dbg(p_demux, "Disc is using AACS");
725 if (!disc_info->libaacs_detected)
726 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
727 ", and your system does not have it."));
728 if (!disc_info->aacs_handled) {
729 if (disc_info->aacs_error_code) {
730 switch (disc_info->aacs_error_code) {
731 case BD_AACS_CORRUPTED_DISC:
732 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
733 case BD_AACS_NO_CONFIG:
734 BLURAY_ERROR(_("Missing AACS configuration file!"));
736 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
737 case BD_AACS_NO_CERT:
738 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
739 case BD_AACS_CERT_REVOKED:
740 BLURAY_ERROR(_("AACS Host certificate revoked."));
741 case BD_AACS_MMC_FAILED:
742 BLURAY_ERROR(_("AACS MMC failed."));
749 if (disc_info->bdplus_detected) {
750 msg_Dbg(p_demux, "Disc is using BD+");
751 if (!disc_info->libbdplus_detected)
752 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
753 ", and your system does not have it."));
754 if (!disc_info->bdplus_handled)
755 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
756 "Missing configuration?"));
759 /* set player region code */
760 char *psz_region = var_InheritString(p_demux, "bluray-region");
761 unsigned int region = psz_region ? (psz_region[0] - 'A') : REGION_DEFAULT;
763 bd_set_player_setting(p_sys->bluray, BLURAY_PLAYER_SETTING_REGION_CODE, 1<<region);
765 /* set preferred languages */
766 const char *psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
767 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG, psz_code);
768 psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
769 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG, psz_code);
770 psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
771 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_MENU_LANG, psz_code);
773 /* Get disc metadata */
774 p_sys->p_meta = bd_get_meta(p_sys->bluray);
776 msg_Warn(p_demux, "Failed to get meta info.");
778 p_sys->i_cover_idx = -1;
779 attachThumbnail(p_demux);
781 p_sys->b_menu = var_InheritBool(p_demux, "bluray-menu");
783 /* Check BD-J capability */
784 if (p_sys->b_menu && disc_info->bdj_detected && !disc_info->bdj_handled) {
785 msg_Err(p_demux, "BD-J menus not supported. Playing without menus. "
786 "BD-J support: %d, JVM found: %d, JVM usable: %d",
787 disc_info->bdj_supported, disc_info->libjvm_detected, disc_info->bdj_handled);
788 vlc_dialog_display_error(p_demux, _("Java required"),
789 _("This Blu-ray disc needs Java for menus.%s\nDisc is played without menus."),
790 !disc_info->libjvm_detected ? _(" Java was not found from your system.") : "");
791 p_sys->b_menu = false;
794 /* Get titles and chapters */
795 blurayInitTitles(p_demux, disc_info->num_hdmv_titles + disc_info->num_bdj_titles + 1/*Top Menu*/ + 1/*First Play*/);
798 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
800 bd_get_event(p_sys->bluray, NULL);
802 /* Registering overlay event handler */
803 bd_register_overlay_proc(p_sys->bluray, p_demux, blurayOverlayProc);
804 if (unlikely(!p_demux->p_input)) {
805 msg_Err(p_demux, "Could not get parent input");
811 /* Register ARGB overlay handler for BD-J */
812 if (disc_info->num_bdj_titles)
813 bd_register_argb_overlay_proc(p_sys->bluray, p_demux, blurayArgbOverlayProc, NULL);
815 /* libbluray will start playback from "First-Title" title */
816 if (bd_play(p_sys->bluray) == 0)
817 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
820 /* set start title number */
821 if (bluraySetTitle(p_demux, p_sys->i_longest_title) != VLC_SUCCESS) {
822 msg_Err(p_demux, "Could not set the title %d", p_sys->i_longest_title);
827 vlc_array_init(&p_sys->es);
828 p_sys->p_out = esOutNew(p_demux);
829 if (unlikely(p_sys->p_out == NULL))
832 blurayResetParser(p_demux);
833 if (!p_sys->p_parser) {
834 msg_Err(p_demux, "Failed to create TS demuxer");
838 p_demux->pf_control = blurayControl;
839 p_demux->pf_demux = blurayDemux;
845 vlc_dialog_display_error(p_demux, _("Blu-ray error"), "%s", error_msg);
848 if (p_demux->s != NULL) {
849 /* restore stream position */
850 if (vlc_stream_Seek(p_demux->s, i_init_pos) != VLC_SUCCESS) {
851 msg_Err(p_demux, "Failed to seek back to stream start");
861 /*****************************************************************************
862 * blurayClose: module destroy function
863 *****************************************************************************/
864 static void blurayClose(vlc_object_t *object)
866 demux_t *p_demux = (demux_t*)object;
867 demux_sys_t *p_sys = p_demux->p_sys;
869 var_DelCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
871 setTitleInfo(p_sys, NULL);
874 * Close libbluray first.
875 * This will close all the overlays before we release p_vout
876 * bd_close(NULL) can crash
879 bd_close(p_sys->bluray);
882 blurayReleaseVout(p_demux);
885 vlc_demux_chained_Delete(p_sys->p_parser);
886 if (p_sys->p_out != NULL)
887 es_out_Delete(p_sys->p_out);
888 assert(vlc_array_count(&p_sys->es) == 0);
889 vlc_array_clear(&p_sys->es);
892 for (unsigned int i = 0; i < p_sys->i_title; i++)
893 vlc_input_title_Delete(p_sys->pp_title[i]);
894 TAB_CLEAN(p_sys->i_title, p_sys->pp_title);
896 for (int i = 0; i < p_sys->i_attachments; i++)
897 vlc_input_attachment_Delete(p_sys->attachments[i]);
898 TAB_CLEAN(p_sys->i_attachments, p_sys->attachments);
900 vlc_mutex_destroy(&p_sys->pl_info_lock);
901 vlc_mutex_destroy(&p_sys->bdj_overlay_lock);
902 vlc_mutex_destroy(&p_sys->read_block_lock);
904 free(p_sys->psz_bd_path);
908 /*****************************************************************************
909 * Elementary streams handling
910 *****************************************************************************/
912 struct es_out_sys_t {
916 typedef struct fmt_es_pair {
921 static int findEsPairIndex(demux_sys_t *p_sys, int i_id)
923 for (int i = 0; i < vlc_array_count(&p_sys->es); ++i)
924 if (((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->i_id == i_id)
930 static int findEsPairIndexByEs(demux_sys_t *p_sys, es_out_id_t *p_es)
932 for (int i = 0; i < vlc_array_count(&p_sys->es); ++i)
933 if (((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->p_es == p_es)
939 static void setStreamLang(demux_sys_t *p_sys, es_format_t *p_fmt)
941 const BLURAY_STREAM_INFO *p_streams;
942 int i_stream_count = 0;
944 vlc_mutex_lock(&p_sys->pl_info_lock);
946 if (p_sys->p_clip_info) {
947 if (p_fmt->i_cat == AUDIO_ES) {
948 p_streams = p_sys->p_clip_info->audio_streams;
949 i_stream_count = p_sys->p_clip_info->audio_stream_count;
950 } else if (p_fmt->i_cat == SPU_ES) {
951 p_streams = p_sys->p_clip_info->pg_streams;
952 i_stream_count = p_sys->p_clip_info->pg_stream_count;
956 for (int i = 0; i < i_stream_count; i++) {
957 if (p_fmt->i_id == p_streams[i].pid) {
958 free(p_fmt->psz_language);
959 p_fmt->psz_language = strndup((const char *)p_streams[i].lang, 3);
964 vlc_mutex_unlock(&p_sys->pl_info_lock);
967 static int blurayEsPid(demux_sys_t *p_sys, int es_type, int i_es_idx)
971 vlc_mutex_lock(&p_sys->pl_info_lock);
973 if (p_sys->p_clip_info) {
974 if (es_type == AUDIO_ES) {
975 if (i_es_idx >= 0 && i_es_idx < p_sys->p_clip_info->audio_stream_count) {
976 i_pid = p_sys->p_clip_info->audio_streams[i_es_idx].pid;
978 } else if (es_type == SPU_ES) {
979 if (i_es_idx >= 0 && i_es_idx < p_sys->p_clip_info->pg_stream_count) {
980 i_pid = p_sys->p_clip_info->pg_streams[i_es_idx].pid;
985 vlc_mutex_unlock(&p_sys->pl_info_lock);
990 static es_out_id_t *esOutAdd(es_out_t *p_out, const es_format_t *p_fmt)
992 demux_t *p_demux = p_out->p_sys->p_demux;
993 demux_sys_t *p_sys = p_demux->p_sys;
995 bool b_select = false;
997 es_format_Copy(&fmt, p_fmt);
1001 if (p_sys->i_video_stream != -1 && p_sys->i_video_stream != p_fmt->i_id)
1002 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1005 if (p_sys->i_audio_stream_idx != -1) {
1006 if (blurayEsPid(p_sys, AUDIO_ES, p_sys->i_audio_stream_idx) == p_fmt->i_id)
1008 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1010 setStreamLang(p_sys, &fmt);
1013 if (p_sys->i_spu_stream_idx != -1) {
1014 if (blurayEsPid(p_sys, SPU_ES, p_sys->i_spu_stream_idx) == p_fmt->i_id)
1016 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1018 setStreamLang(p_sys, &fmt);
1022 es_out_id_t *p_es = es_out_Add(p_demux->out, &fmt);
1023 if (p_fmt->i_id >= 0) {
1024 /* Ensure we are not overriding anything */
1025 int idx = findEsPairIndex(p_sys, p_fmt->i_id);
1027 fmt_es_pair_t *p_pair = malloc(sizeof(*p_pair));
1028 if (likely(p_pair != NULL)) {
1029 p_pair->i_id = p_fmt->i_id;
1030 p_pair->p_es = p_es;
1031 msg_Info(p_demux, "Adding ES %d", p_fmt->i_id);
1032 vlc_array_append(&p_sys->es, p_pair);
1035 if (fmt.i_cat == AUDIO_ES) {
1036 var_SetInteger( p_demux->p_input, "audio-es", p_fmt->i_id );
1037 } else if (fmt.i_cat == SPU_ES) {
1038 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? p_fmt->i_id : -1 );
1044 es_format_Clean(&fmt);
1048 static int esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1050 return es_out_Send(p_out->p_sys->p_demux->out, p_es, p_block);
1053 static void esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1055 int idx = findEsPairIndexByEs(p_out->p_sys->p_demux->p_sys, p_es);
1057 free(vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, idx));
1058 vlc_array_remove(&p_out->p_sys->p_demux->p_sys->es, idx);
1060 es_out_Del(p_out->p_sys->p_demux->out, p_es);
1063 static int esOutControl(es_out_t *p_out, int i_query, va_list args)
1065 return es_out_vaControl(p_out->p_sys->p_demux->out, i_query, args);
1068 static void esOutDestroy(es_out_t *p_out)
1070 for (int i = 0; i < vlc_array_count(&p_out->p_sys->p_demux->p_sys->es); ++i)
1071 free(vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, i));
1072 vlc_array_clear(&p_out->p_sys->p_demux->p_sys->es);
1077 static es_out_t *esOutNew(demux_t *p_demux)
1079 assert(vlc_array_count(&p_demux->p_sys->es) == 0);
1080 es_out_t *p_out = malloc(sizeof(*p_out));
1081 if (unlikely(p_out == NULL))
1084 p_out->pf_add = esOutAdd;
1085 p_out->pf_control = esOutControl;
1086 p_out->pf_del = esOutDel;
1087 p_out->pf_destroy = esOutDestroy;
1088 p_out->pf_send = esOutSend;
1090 p_out->p_sys = malloc(sizeof(*p_out->p_sys));
1091 if (unlikely(p_out->p_sys == NULL)) {
1095 p_out->p_sys->p_demux = p_demux;
1099 /*****************************************************************************
1100 * subpicture_updater_t functions:
1101 *****************************************************************************/
1103 static bluray_overlay_t *updater_lock_overlay(subpicture_updater_sys_t *p_upd_sys)
1105 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1106 vlc_mutex_lock(&p_upd_sys->lock);
1108 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1110 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1111 vlc_mutex_lock(&ov->lock);
1115 /* overlay has been closed */
1116 vlc_mutex_unlock(&p_upd_sys->lock);
1120 static void updater_unlock_overlay(subpicture_updater_sys_t *p_upd_sys)
1122 assert (p_upd_sys->p_overlay);
1124 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1125 vlc_mutex_unlock(&p_upd_sys->lock);
1128 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1129 bool b_fmt_src, const video_format_t *p_fmt_src,
1130 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1133 VLC_UNUSED(b_fmt_src);
1134 VLC_UNUSED(b_fmt_dst);
1135 VLC_UNUSED(p_fmt_src);
1136 VLC_UNUSED(p_fmt_dst);
1139 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1140 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1146 int res = p_overlay->status == Outdated;
1148 updater_unlock_overlay(p_upd_sys);
1153 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1154 const video_format_t *p_fmt_src,
1155 const video_format_t *p_fmt_dst,
1158 VLC_UNUSED(p_fmt_src);
1159 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);
1169 * When this function is called, all p_subpic regions are gone.
1170 * We need to duplicate our regions (stored internaly) to this subpic.
1172 subpicture_region_t *p_src = p_overlay->p_regions;
1174 updater_unlock_overlay(p_upd_sys);
1178 subpicture_region_t **p_dst = &p_subpic->p_region;
1179 while (p_src != NULL) {
1180 *p_dst = subpicture_region_Copy(p_src);
1183 p_dst = &(*p_dst)->p_next;
1184 p_src = p_src->p_next;
1187 (*p_dst)->p_next = NULL;
1188 p_overlay->status = Displayed;
1190 updater_unlock_overlay(p_upd_sys);
1193 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1195 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1196 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1199 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1200 p_overlay->status = ToDisplay;
1201 p_overlay->i_channel = -1;
1202 updater_unlock_overlay(p_upd_sys);
1205 unref_subpicture_updater(p_upd_sys);
1208 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1210 subpicture_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1211 if (unlikely(p_upd_sys == NULL)) {
1215 p_upd_sys->p_overlay = p_ov;
1217 subpicture_updater_t updater = {
1218 .pf_validate = subpictureUpdaterValidate,
1219 .pf_update = subpictureUpdaterUpdate,
1220 .pf_destroy = subpictureUpdaterDestroy,
1224 subpicture_t *p_pic = subpicture_New(&updater);
1225 if (p_pic == NULL) {
1230 p_pic->i_original_picture_width = p_ov->width;
1231 p_pic->i_original_picture_height = p_ov->height;
1232 p_pic->b_ephemer = true;
1233 p_pic->b_absolute = true;
1235 vlc_mutex_init(&p_upd_sys->lock);
1236 p_upd_sys->ref_cnt = 2;
1238 p_ov->p_updater = p_upd_sys;
1243 /*****************************************************************************
1244 * User input events:
1245 *****************************************************************************/
1246 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var, vlc_value_t old,
1247 vlc_value_t val, void *p_data)
1249 demux_t *p_demux = (demux_t*)p_data;
1250 demux_sys_t *p_sys = p_demux->p_sys;
1254 if (psz_var[6] == 'm') //Mouse moved
1255 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1256 else if (psz_var[6] == 'c') {
1257 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1258 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1260 vlc_assert_unreachable();
1265 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1267 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1268 return VLC_EGENERIC;
1273 /*****************************************************************************
1274 * libbluray overlay handling:
1275 *****************************************************************************/
1277 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1279 demux_sys_t *p_sys = p_demux->p_sys;
1280 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1284 /* drop overlay from vout */
1285 if (ov->p_updater) {
1286 unref_subpicture_updater(ov->p_updater);
1288 /* no references to this overlay exist in vo anymore */
1289 if (p_sys->p_vout && ov->i_channel != -1) {
1290 vout_FlushSubpictureChannel(p_sys->p_vout, ov->i_channel);
1293 vlc_mutex_destroy(&ov->lock);
1294 subpicture_region_ChainDelete(ov->p_regions);
1297 p_sys->p_overlays[plane] = NULL;
1300 for (int i = 0; i < MAX_OVERLAY; i++)
1301 if (p_sys->p_overlays[i])
1304 /* All overlays have been closed */
1305 blurayReleaseVout(p_demux);
1309 * Mark the overlay as "ToDisplay" status.
1310 * This will not send the overlay to the vout instantly, as the vout
1311 * may not be acquired (not acquirable) yet.
1312 * If is has already been acquired, the overlay has already been sent to it,
1313 * therefore, we only flag the overlay as "Outdated"
1315 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1317 demux_sys_t *p_sys = p_demux->p_sys;
1318 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1321 * If the overlay is already displayed, mark the picture as outdated.
1322 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1324 vlc_mutex_lock(&ov->lock);
1325 if (ov->status >= Displayed && p_sys->p_vout) {
1326 ov->status = Outdated;
1327 vlc_mutex_unlock(&ov->lock);
1332 * Mark the overlay as available, but don't display it right now.
1333 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1334 * the overlay is computed
1336 ov->status = ToDisplay;
1337 vlc_mutex_unlock(&ov->lock);
1340 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1342 demux_sys_t *p_sys = p_demux->p_sys;
1344 assert(p_sys->p_overlays[plane] == NULL);
1346 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1347 if (unlikely(ov == NULL))
1351 ov->height = height;
1354 vlc_mutex_init(&ov->lock);
1356 p_sys->p_overlays[plane] = ov;
1360 * Destroy every regions in the subpicture.
1361 * This is done in two steps:
1362 * - Wiping our private regions list
1363 * - Flagging the overlay as outdated, so the changes are replicated from
1364 * the subpicture_updater_t::pf_update
1365 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1367 static void blurayClearOverlay(demux_t *p_demux, int plane)
1369 demux_sys_t *p_sys = p_demux->p_sys;
1370 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1372 vlc_mutex_lock(&ov->lock);
1374 subpicture_region_ChainDelete(ov->p_regions);
1375 ov->p_regions = NULL;
1376 ov->status = Outdated;
1378 vlc_mutex_unlock(&ov->lock);
1382 * This will draw to the overlay by adding a region to our region list
1383 * This will have to be copied to the subpicture used to render the overlay.
1385 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1387 demux_sys_t *p_sys = p_demux->p_sys;
1390 * Compute a subpicture_region_t.
1391 * It will be copied and sent to the vout later.
1393 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1395 /* Find a region to update */
1396 subpicture_region_t **pp_reg = &p_sys->p_overlays[ov->plane]->p_regions;
1397 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1398 subpicture_region_t *p_last = NULL;
1399 while (p_reg != NULL) {
1401 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1402 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1404 pp_reg = &p_reg->p_next;
1405 p_reg = p_reg->p_next;
1411 *pp_reg = p_reg->p_next;
1412 subpicture_region_Delete(p_reg);
1414 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1418 /* If there is no region to update, create a new one. */
1421 video_format_Init(&fmt, 0);
1422 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1424 p_reg = subpicture_region_New(&fmt);
1427 /* Append it to our list. */
1429 p_last->p_next = p_reg;
1430 else /* If we don't have a last region, then our list empty */
1431 p_sys->p_overlays[ov->plane]->p_regions = p_reg;
1434 /* Now we can update the region, regardless it's an update or an insert */
1435 const BD_PG_RLE_ELEM *img = ov->img;
1436 for (int y = 0; y < ov->h; y++)
1437 for (int x = 0; x < ov->w;) {
1438 plane_t *p = &p_reg->p_picture->p[0];
1439 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1445 p_reg->fmt.p_palette->i_entries = 256;
1446 for (int i = 0; i < 256; ++i) {
1447 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1448 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1449 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1450 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1454 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1456 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1460 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1462 demux_t *p_demux = (demux_t*)ptr;
1463 demux_sys_t *p_sys = p_demux->p_sys;
1466 msg_Info(p_demux, "Closing overlays.");
1468 for (int i = 0; i < MAX_OVERLAY; i++)
1469 blurayCloseOverlay(p_demux, i);
1473 switch (overlay->cmd) {
1474 case BD_OVERLAY_INIT:
1475 msg_Info(p_demux, "Initializing overlay");
1476 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1477 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1478 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1480 case BD_OVERLAY_CLOSE:
1481 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1482 blurayClearOverlay(p_demux, overlay->plane);
1483 blurayCloseOverlay(p_demux, overlay->plane);
1484 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1486 case BD_OVERLAY_CLEAR:
1487 blurayClearOverlay(p_demux, overlay->plane);
1489 case BD_OVERLAY_FLUSH:
1490 blurayActivateOverlay(p_demux, overlay->plane);
1492 case BD_OVERLAY_DRAW:
1493 case BD_OVERLAY_WIPE:
1494 blurayDrawOverlay(p_demux, overlay);
1497 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
1503 * ARGB overlay (BD-J)
1505 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
1507 demux_sys_t *p_sys = p_demux->p_sys;
1509 blurayInitOverlay(p_demux, plane, width, height);
1511 if (!p_sys->p_overlays[plane]->p_regions) {
1513 video_format_Init(&fmt, 0);
1514 video_format_Setup(&fmt, VLC_CODEC_RGBA, width, height, width, height, 1, 1);
1516 p_sys->p_overlays[plane]->p_regions = subpicture_region_New(&fmt);
1520 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
1522 demux_sys_t *p_sys = p_demux->p_sys;
1524 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1526 /* Find a region to update */
1527 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1529 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1533 /* Now we can update the region */
1534 const uint32_t *src0 = ov->argb;
1535 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
1536 p_reg->p_picture->p[0].i_pitch * ov->y +
1539 for (int y = 0; y < ov->h; y++) {
1540 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1541 // - or add libbluray option to select the format ?
1542 for (int x = 0; x < ov->w; x++) {
1543 dst0[x*4 ] = src0[x]>>16; /* R */
1544 dst0[x*4+1] = src0[x]>>8; /* G */
1545 dst0[x*4+2] = src0[x]; /* B */
1546 dst0[x*4+3] = src0[x]>>24; /* A */
1550 dst0 += p_reg->p_picture->p[0].i_pitch;
1553 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1555 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1559 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
1561 demux_t *p_demux = (demux_t*)ptr;
1562 demux_sys_t *p_sys = p_demux->p_sys;
1564 switch (overlay->cmd) {
1565 case BD_ARGB_OVERLAY_INIT:
1566 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1567 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1568 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1570 case BD_ARGB_OVERLAY_CLOSE:
1571 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1572 blurayClearOverlay(p_demux, overlay->plane);
1573 blurayCloseOverlay(p_demux, overlay->plane);
1574 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1576 case BD_ARGB_OVERLAY_FLUSH:
1577 blurayActivateOverlay(p_demux, overlay->plane);
1579 case BD_ARGB_OVERLAY_DRAW:
1580 blurayDrawArgbOverlay(p_demux, overlay);
1583 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
1588 static void bluraySendOverlayToVout(demux_t *p_demux, bluray_overlay_t *p_ov)
1590 demux_sys_t *p_sys = p_demux->p_sys;
1592 assert(p_ov != NULL);
1593 assert(p_ov->i_channel == -1);
1595 if (p_ov->p_updater) {
1596 unref_subpicture_updater(p_ov->p_updater);
1597 p_ov->p_updater = NULL;
1600 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
1602 msg_Err(p_demux, "bluraySubpictureCreate() failed");
1606 p_pic->i_start = p_pic->i_stop = mdate();
1607 p_pic->i_channel = vout_RegisterSubpictureChannel(p_sys->p_vout);
1608 p_ov->i_channel = p_pic->i_channel;
1611 * After this point, the picture should not be accessed from the demux thread,
1612 * as it is held by the vout thread.
1613 * This must be done only once per subpicture, ie. only once between each
1614 * blurayInitOverlay & blurayCloseOverlay call.
1616 vout_PutSubpicture(p_sys->p_vout, p_pic);
1619 * Mark the picture as Outdated, as it contains no region for now.
1620 * This will make the subpicture_updater_t call pf_update
1622 p_ov->status = Outdated;
1625 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
1627 t->i_length = FROM_TICKS(title_info->duration);
1629 for (int i = 0; i < t->i_seekpoint; i++)
1630 vlc_seekpoint_Delete( t->seekpoint[i] );
1631 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
1633 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
1634 seekpoint_t *s = vlc_seekpoint_New();
1638 s->i_time_offset = FROM_TICKS(title_info->chapters[j].start);
1640 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
1644 static void blurayInitTitles(demux_t *p_demux, int menu_titles)
1646 demux_sys_t *p_sys = p_demux->p_sys;
1647 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
1649 /* get and set the titles */
1650 unsigned i_title = menu_titles;
1652 if (!p_sys->b_menu) {
1653 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
1654 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
1657 for (unsigned int i = 0; i < i_title; i++) {
1658 input_title_t *t = vlc_input_title_New();
1662 if (!p_sys->b_menu) {
1663 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
1664 blurayUpdateTitleInfo(t, title_info);
1665 bd_free_title_info(title_info);
1667 } else if (i == 0) {
1668 t->psz_name = strdup(_("Top Menu"));
1669 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
1670 } else if (i == i_title - 1) {
1671 t->psz_name = strdup(_("First Play"));
1672 if (di && di->first_play && di->first_play->interactive) {
1673 t->i_flags = INPUT_TITLE_INTERACTIVE;
1676 /* add possible title name from disc metadata */
1677 if (di && di->titles && i <= di->num_titles) {
1678 if (di->titles[i]->name) {
1679 t->psz_name = strdup(di->titles[i]->name);
1681 if (di->titles[i]->interactive) {
1682 t->i_flags = INPUT_TITLE_INTERACTIVE;
1687 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
1691 static void blurayResetParser(demux_t *p_demux)
1694 * This is a hack and will have to be removed.
1695 * The parser should be flushed, and not destroy/created each time
1696 * we are changing title.
1698 demux_sys_t *p_sys = p_demux->p_sys;
1699 if (p_sys->p_parser)
1700 vlc_demux_chained_Delete(p_sys->p_parser);
1702 p_sys->p_parser = vlc_demux_chained_New(p_demux, "ts", p_sys->p_out);
1704 if (!p_sys->p_parser)
1705 msg_Err(p_demux, "Failed to create TS demuxer");
1708 /*****************************************************************************
1709 * bluraySetTitle: select new BD title
1710 *****************************************************************************/
1711 static int bluraySetTitle(demux_t *p_demux, int i_title)
1713 demux_sys_t *p_sys = p_demux->p_sys;
1715 if (p_sys->b_menu) {
1718 msg_Dbg(p_demux, "Playing TopMenu Title");
1719 result = bd_menu_call(p_sys->bluray, -1);
1720 } else if (i_title >= (int)p_sys->i_title - 1) {
1721 msg_Dbg(p_demux, "Playing FirstPlay Title");
1722 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
1724 msg_Dbg(p_demux, "Playing Title %i", i_title);
1725 result = bd_play_title(p_sys->bluray, i_title);
1729 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
1730 return VLC_EGENERIC;
1736 /* Looking for the main title, ie the longest duration */
1738 i_title = p_sys->i_longest_title;
1739 else if ((unsigned)i_title > p_sys->i_title)
1740 return VLC_EGENERIC;
1742 msg_Dbg(p_demux, "Selecting Title %i", i_title);
1744 if (bd_select_title(p_sys->bluray, i_title) == 0) {
1745 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
1746 return VLC_EGENERIC;
1749 blurayResetParser(p_demux);
1754 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
1755 # define BLURAY_AUDIO_STREAM 0
1758 static void blurayStreamSelected(demux_sys_t *p_sys, int i_pid)
1760 vlc_mutex_lock(&p_sys->pl_info_lock);
1762 if (p_sys->p_clip_info) {
1763 if ((i_pid & 0xff00) == 0x1100) {
1765 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
1766 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
1767 p_sys->i_audio_stream_idx = i_id;
1768 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
1772 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
1774 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
1775 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
1776 p_sys->i_spu_stream_idx = i_id;
1777 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
1784 vlc_mutex_unlock(&p_sys->pl_info_lock);
1787 /*****************************************************************************
1788 * blurayControl: handle the controls
1789 *****************************************************************************/
1790 static int blurayControl(demux_t *p_demux, int query, va_list args)
1792 demux_sys_t *p_sys = p_demux->p_sys;
1797 case DEMUX_CAN_SEEK:
1798 case DEMUX_CAN_PAUSE:
1799 case DEMUX_CAN_CONTROL_PACE:
1800 pb_bool = (bool*)va_arg(args, bool *);
1804 case DEMUX_GET_PTS_DELAY:
1805 pi_64 = (int64_t*)va_arg(args, int64_t *);
1806 *pi_64 = INT64_C(1000) * var_InheritInteger(p_demux, "disc-caching");
1809 case DEMUX_SET_PAUSE_STATE:
1811 #ifdef BLURAY_RATE_NORMAL
1812 bool b_paused = (bool)va_arg(args, int);
1813 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
1814 return VLC_EGENERIC;
1821 int i_id = (int)va_arg(args, int);
1822 blurayStreamSelected(p_sys, i_id);
1825 case DEMUX_SET_TITLE:
1827 int i_title = (int)va_arg(args, int);
1828 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
1829 /* make sure GUI restores the old setting in title menu ... */
1830 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1831 return VLC_EGENERIC;
1835 case DEMUX_SET_SEEKPOINT:
1837 int i_chapter = (int)va_arg(args, int);
1838 bd_seek_chapter(p_sys->bluray, i_chapter);
1839 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
1843 case DEMUX_GET_TITLE_INFO:
1845 input_title_t ***ppp_title = (input_title_t***)va_arg(args, input_title_t***);
1846 int *pi_int = (int*)va_arg(args, int*);
1847 int *pi_title_offset = (int*)va_arg(args, int*);
1848 int *pi_chapter_offset = (int*)va_arg(args, int*);
1851 *pi_title_offset = 0;
1852 *pi_chapter_offset = 0;
1854 /* Duplicate local title infos */
1855 *pi_int = p_sys->i_title;
1856 *ppp_title = malloc(p_sys->i_title * sizeof(input_title_t *));
1857 for (unsigned int i = 0; i < p_sys->i_title; i++)
1858 (*ppp_title)[i] = vlc_input_title_Duplicate(p_sys->pp_title[i]);
1863 case DEMUX_GET_LENGTH:
1865 int64_t *pi_length = (int64_t*)va_arg(args, int64_t *);
1866 *pi_length = p_demux->info.i_title < (int)p_sys->i_title ? CUR_LENGTH : 0;
1869 case DEMUX_SET_TIME:
1871 int64_t i_time = (int64_t)va_arg(args, int64_t);
1872 bd_seek_time(p_sys->bluray, TO_TICKS(i_time));
1875 case DEMUX_GET_TIME:
1877 int64_t *pi_time = (int64_t*)va_arg(args, int64_t *);
1878 *pi_time = (int64_t)FROM_TICKS(bd_tell_time(p_sys->bluray));
1882 case DEMUX_GET_POSITION:
1884 double *pf_position = (double*)va_arg(args, double *);
1885 *pf_position = p_demux->info.i_title < (int)p_sys->i_title && CUR_LENGTH > 0 ?
1886 (double)FROM_TICKS(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
1889 case DEMUX_SET_POSITION:
1891 double f_position = (double)va_arg(args, double);
1892 bd_seek_time(p_sys->bluray, TO_TICKS(f_position*CUR_LENGTH));
1896 case DEMUX_GET_META:
1898 vlc_meta_t *p_meta = (vlc_meta_t *) va_arg (args, vlc_meta_t*);
1899 const META_DL *meta = p_sys->p_meta;
1901 return VLC_EGENERIC;
1903 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
1905 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
1906 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
1907 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
1909 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
1910 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
1912 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
1914 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
1915 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
1916 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
1918 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
1919 char *psz_thumbpath;
1920 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
1921 p_sys->psz_bd_path, meta->thumbnails[0].path) > 0) {
1922 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
1923 if (unlikely(psz_thumburl == NULL)) {
1924 free(psz_thumbpath);
1928 vlc_meta_SetArtURL(p_meta, psz_thumburl);
1931 free(psz_thumbpath);
1937 case DEMUX_GET_ATTACHMENTS:
1939 input_attachment_t ***ppp_attach =
1940 (input_attachment_t ***)va_arg(args, input_attachment_t ***);
1941 int *pi_int = (int *)va_arg(args, int *);
1943 if (p_sys->i_attachments <= 0)
1944 return VLC_EGENERIC;
1946 *pi_int = p_sys->i_attachments;
1947 *ppp_attach = xmalloc(sizeof(input_attachment_t *) * p_sys->i_attachments);
1948 for (int i = 0; i < p_sys->i_attachments; i++)
1949 (*ppp_attach)[i] = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
1953 case DEMUX_NAV_ACTIVATE:
1954 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
1955 return sendKeyEvent(p_sys, BD_VK_POPUP);
1957 return sendKeyEvent(p_sys, BD_VK_ENTER);
1959 return sendKeyEvent(p_sys, BD_VK_UP);
1960 case DEMUX_NAV_DOWN:
1961 return sendKeyEvent(p_sys, BD_VK_DOWN);
1962 case DEMUX_NAV_LEFT:
1963 return sendKeyEvent(p_sys, BD_VK_LEFT);
1964 case DEMUX_NAV_RIGHT:
1965 return sendKeyEvent(p_sys, BD_VK_RIGHT);
1966 case DEMUX_NAV_POPUP:
1967 return sendKeyEvent(p_sys, BD_VK_POPUP);
1968 case DEMUX_NAV_MENU:
1969 if (p_sys->b_menu) {
1970 if (bd_menu_call(p_sys->bluray, -1) == 1) {
1971 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1974 msg_Err(p_demux, "Can't select Top Menu title");
1975 return sendKeyEvent(p_sys, BD_VK_POPUP);
1977 return VLC_EGENERIC;
1979 case DEMUX_CAN_RECORD:
1981 case DEMUX_SET_GROUP:
1982 case DEMUX_HAS_UNSUPPORTED_META:
1983 return VLC_EGENERIC;
1985 msg_Warn(p_demux, "unimplemented query (%d) in control", query);
1986 return VLC_EGENERIC;
1991 /*****************************************************************************
1992 * libbluray event handling
1993 *****************************************************************************/
1995 static void streamFlush( demux_sys_t *p_sys )
1998 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
1999 * Packet is flushed only when TS packet with PUSI flag set is received.
2001 * Fix this by emitting (video) ts packet with PUSI flag set.
2002 * Add video sequence end code to payload so that also video decoder is flushed.
2003 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2006 if (p_sys->b_flushed)
2009 block_t *p_block = block_Alloc(192);
2013 static const uint8_t seq_end_pes[] = {
2014 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2015 0x00, 0x00, 0x01, 0xb7, /* PES payload: sequence end */
2017 static const uint8_t vid_pusi_ts[] = {
2018 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2019 0x47, 0x50, 0x11, 0x30, /* TP header */
2020 (192 - (4 + 5) - sizeof(seq_end_pes)), /* adaptation field length */
2021 0x80, /* adaptation field: discontinuity indicator */
2024 memset(p_block->p_buffer, 0, 192);
2025 memcpy(p_block->p_buffer, vid_pusi_ts, sizeof(vid_pusi_ts));
2026 memcpy(p_block->p_buffer + 192 - sizeof(seq_end_pes), seq_end_pes, sizeof(seq_end_pes));
2027 p_block->i_buffer = 192;
2029 /* set correct sequence end code */
2030 vlc_mutex_lock(&p_sys->pl_info_lock);
2031 if (p_sys->p_clip_info != NULL) {
2032 if (p_sys->p_clip_info->video_streams[0].coding_type > 2) {
2033 /* VC1 / H.264 sequence end */
2034 p_block->p_buffer[191] = 0x0a;
2037 vlc_mutex_unlock(&p_sys->pl_info_lock);
2039 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2040 p_sys->b_flushed = true;
2043 static void blurayResetStillImage( demux_t *p_demux )
2045 demux_sys_t *p_sys = p_demux->p_sys;
2047 if (p_sys->i_still_end_time) {
2048 p_sys->i_still_end_time = 0;
2050 blurayResetParser(p_demux);
2051 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2055 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2057 demux_sys_t *p_sys = p_demux->p_sys;
2059 /* time period elapsed ? */
2060 if (p_sys->i_still_end_time > 0 && p_sys->i_still_end_time <= mdate()) {
2061 msg_Dbg(p_demux, "Still image end");
2062 bd_read_skip_still(p_sys->bluray);
2064 blurayResetStillImage(p_demux);
2068 /* show last frame as still image */
2069 if (!p_sys->i_still_end_time) {
2071 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2072 p_sys->i_still_end_time = mdate() + i_timeout * CLOCK_FREQ;
2074 msg_Dbg(p_demux, "Still image (infinite)");
2075 p_sys->i_still_end_time = -1;
2078 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2081 /* stop buffering */
2083 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2086 /* avoid busy loops (read returns no data) */
2090 static void blurayStreamSelect(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2092 demux_sys_t *p_sys = p_demux->p_sys;
2095 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2098 if (i_type == BD_EVENT_AUDIO_STREAM) {
2099 p_sys->i_audio_stream_idx = i_id;
2100 i_pid = blurayEsPid(p_sys, AUDIO_ES, i_id);
2101 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2102 p_sys->i_spu_stream_idx = i_id;
2103 i_pid = blurayEsPid(p_sys, SPU_ES, i_id);
2107 int i_idx = findEsPairIndex(p_sys, i_pid);
2109 if (i_type == BD_EVENT_AUDIO_STREAM) {
2110 var_SetInteger( p_demux->p_input, "audio-es", i_pid );
2111 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2112 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? i_pid : -1 );
2118 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2120 demux_sys_t *p_sys = p_demux->p_sys;
2122 blurayResetParser(p_demux);
2124 /* read title info and init some values */
2126 p_demux->info.i_title = bd_get_current_title(p_sys->bluray);
2127 p_demux->info.i_seekpoint = 0;
2128 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2130 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2132 blurayUpdateTitleInfo(p_sys->pp_title[p_demux->info.i_title], p_title_info);
2134 p_demux->info.i_update |= INPUT_UPDATE_TITLE_LIST;
2136 setTitleInfo(p_sys, p_title_info);
2138 blurayResetStillImage(p_demux);
2141 static void blurayUpdateCurrentClip(demux_t *p_demux, uint32_t clip)
2143 demux_sys_t *p_sys = p_demux->p_sys;
2145 vlc_mutex_lock(&p_sys->pl_info_lock);
2147 p_sys->p_clip_info = NULL;
2148 p_sys->i_video_stream = -1;
2150 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2152 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2154 /* Let's assume a single video track for now.
2155 * This may brake later, but it's enough for now.
2157 assert(p_sys->p_clip_info->video_stream_count >= 1);
2158 p_sys->i_video_stream = p_sys->p_clip_info->video_streams[0].pid;
2161 vlc_mutex_unlock(&p_sys->pl_info_lock);
2163 blurayResetStillImage(p_demux);
2166 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e)
2168 demux_sys_t *p_sys = p_demux->p_sys;
2171 case BD_EVENT_TITLE:
2172 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2173 p_demux->info.i_title = p_sys->i_title - 1;
2175 p_demux->info.i_title = e->param;
2176 /* this is feature title, we don't know yet which playlist it will play (if any) */
2177 setTitleInfo(p_sys, NULL);
2178 /* reset title infos here ? */
2179 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT; /* might be BD-J title with no video */
2181 case BD_EVENT_PLAYLIST:
2182 /* Start of playlist playback (?????.mpls) */
2183 blurayUpdatePlaylist(p_demux, e->param);
2184 if (p_sys->b_pl_playing) {
2185 /* previous playlist was stopped in middle. flush to avoid delay */
2186 msg_Info(p_demux, "Stopping playlist playback");
2187 blurayResetParser(p_demux);
2188 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2190 p_sys->b_pl_playing = true;
2192 case BD_EVENT_PLAYITEM:
2193 blurayUpdateCurrentClip(p_demux, e->param);
2195 case BD_EVENT_CHAPTER:
2196 if (e->param && e->param < 0xffff)
2197 p_demux->info.i_seekpoint = e->param - 1;
2199 p_demux->info.i_seekpoint = 0;
2200 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
2202 case BD_EVENT_PLAYMARK:
2203 case BD_EVENT_ANGLE:
2205 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2206 case BD_EVENT_UO_MASK_CHANGED:
2207 /* This event could be used to grey out unselectable items in title menu */
2211 p_sys->b_menu_open = e->param;
2213 case BD_EVENT_POPUP:
2214 p_sys->b_popup_available = e->param;
2215 /* TODO: show / hide pop-up menu button in gui ? */
2221 case BD_EVENT_ERROR:
2222 /* fatal error (with menus) */
2223 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2224 "Playback with BluRay menus failed");
2225 p_sys->b_fatal_error = true;
2227 case BD_EVENT_ENCRYPTED:
2228 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2229 "This disc seems to be encrypted");
2230 p_sys->b_fatal_error = true;
2232 case BD_EVENT_READ_ERROR:
2233 msg_Err(p_demux, "bluray: read error\n");
2237 * stream selection events
2239 case BD_EVENT_PG_TEXTST:
2240 p_sys->b_spu_enable = e->param;
2242 case BD_EVENT_AUDIO_STREAM:
2243 case BD_EVENT_PG_TEXTST_STREAM:
2244 blurayStreamSelect(p_demux, e->event, e->param);
2246 case BD_EVENT_IG_STREAM:
2247 case BD_EVENT_SECONDARY_AUDIO:
2248 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2249 case BD_EVENT_SECONDARY_VIDEO:
2250 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2251 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2255 * playback control events
2257 case BD_EVENT_STILL_TIME:
2258 blurayStillImage(p_demux, e->param);
2260 case BD_EVENT_DISCONTINUITY:
2261 /* reset demuxer (partially decoded PES packets must be dropped) */
2262 blurayResetParser(p_demux);
2264 case BD_EVENT_END_OF_TITLE:
2265 p_sys->b_pl_playing = false;
2268 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2269 /* avoid busy loop (bd_read() returns no data) */
2274 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2279 static bool blurayIsBdjTitle(demux_t *p_demux)
2281 demux_sys_t *p_sys = p_demux->p_sys;
2282 unsigned int i_title = p_demux->info.i_title;
2283 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2285 if (di && di->titles) {
2286 if ((i_title <= di->num_titles && di->titles[i_title] && di->titles[i_title]->bdj) ||
2287 (i_title == p_sys->i_title - 1 && di->first_play && di->first_play->bdj)) {
2295 static void blurayHandleOverlays(demux_t *p_demux, int nread)
2297 demux_sys_t *p_sys = p_demux->p_sys;
2299 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2301 for (int i = 0; i < MAX_OVERLAY; i++) {
2302 bluray_overlay_t *ov = p_sys->p_overlays[i];
2306 vlc_mutex_lock(&ov->lock);
2307 bool display = ov->status == ToDisplay;
2308 vlc_mutex_unlock(&ov->lock);
2310 if (p_sys->p_vout == NULL) {
2311 p_sys->p_vout = input_GetVout(p_demux->p_input);
2312 if (p_sys->p_vout != NULL) {
2313 var_AddCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
2314 var_AddCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
2318 /* NOTE: we might want to enable background video always when there's no video stream playing.
2319 Now, with some discs, there are perioids (even seconds) during which the video window
2320 disappears and just playlist is shown.
2321 (sometimes BD-J runs slowly ...)
2323 if (!p_sys->p_vout && !p_sys->p_dummy_video && p_sys->b_menu &&
2324 !p_sys->p_pl_info && nread == 0 &&
2325 blurayIsBdjTitle(p_demux)) {
2327 /* Looks like there's no video stream playing.
2328 Emit blank frame so that BD-J overlay can be drawn. */
2329 startBackground(p_demux);
2332 if (p_sys->p_vout != NULL) {
2333 bluraySendOverlayToVout(p_demux, ov);
2338 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2341 static int onIntfEvent( vlc_object_t *p_input, char const *psz_var,
2342 vlc_value_t oldval, vlc_value_t val, void *p_data )
2344 (void)p_input; (void) psz_var; (void) oldval;
2345 demux_t *p_demux = p_data;
2346 demux_sys_t *p_sys = p_demux->p_sys;
2348 if (val.i_int == INPUT_EVENT_VOUT) {
2350 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2351 if( p_sys->p_vout != NULL ) {
2352 blurayReleaseVout(p_demux);
2354 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2356 blurayHandleOverlays(p_demux, 1);
2362 #define BD_TS_PACKET_SIZE (192)
2363 #define NB_TS_PACKETS (200)
2365 static int blurayDemux(demux_t *p_demux)
2367 demux_sys_t *p_sys = p_demux->p_sys;
2370 block_t *p_block = block_Alloc(NB_TS_PACKETS * (int64_t)BD_TS_PACKET_SIZE);
2372 return VLC_DEMUXER_EGENERIC;
2376 if (p_sys->b_menu == false) {
2377 while (bd_get_event(p_sys->bluray, &e))
2378 blurayHandleEvent(p_demux, &e);
2380 nread = bd_read(p_sys->bluray, p_block->p_buffer,
2381 NB_TS_PACKETS * BD_TS_PACKET_SIZE);
2383 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer,
2384 NB_TS_PACKETS * BD_TS_PACKET_SIZE, &e);
2385 while (e.event != BD_EVENT_NONE) {
2386 blurayHandleEvent(p_demux, &e);
2387 bd_get_event(p_sys->bluray, &e);
2391 blurayHandleOverlays(p_demux, nread);
2394 block_Release(p_block);
2395 if (p_sys->b_fatal_error || nread < 0) {
2396 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
2397 return VLC_DEMUXER_EGENERIC;
2399 if (!p_sys->b_menu) {
2400 return VLC_DEMUXER_EOF;
2402 return VLC_DEMUXER_SUCCESS;
2405 p_block->i_buffer = nread;
2407 stopBackground(p_demux);
2409 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2411 p_sys->b_flushed = false;
2413 return VLC_DEMUXER_SUCCESS;