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_mouse.h>
46 #include <vlc_plugin.h>
47 #include <vlc_demux.h> /* demux_t */
48 #include <vlc_input.h> /* Seekpoints, chapters */
49 #include <vlc_dialog.h> /* BD+/AACS warnings */
50 #include <vlc_url.h> /* vlc_path2uri */
51 #include <vlc_iso_lang.h>
54 #include "../demux/mpeg/timestamps.h"
56 /* FIXME we should find a better way than including that */
57 #include "../../src/text/iso-639_def.h"
60 #include <libbluray/bluray.h>
61 #include <libbluray/bluray-version.h>
62 #include <libbluray/keys.h>
63 #include <libbluray/meta_data.h>
64 #include <libbluray/overlay.h>
66 //#define DEBUG_BLURAY
68 # include <libbluray/log_control.h>
69 # define BLURAY_DEBUG_MASK (0xFFFFF & ~DBG_STREAM)
70 static vlc_object_t
*p_bluray_DebugObject
;
71 static void bluray_DebugHandler(const char *psz
)
73 size_t len
= strlen(psz
);
76 if(psz
[len
- 1] == '\n')
77 psz_log
= strndup(psz
, len
- 1);
78 msg_Dbg(p_bluray_DebugObject
, "%s", psz_log
? psz_log
: psz
);
83 /*****************************************************************************
85 *****************************************************************************/
87 #define BD_MENU_TEXT N_("Blu-ray menus")
88 #define BD_MENU_LONGTEXT N_("Use Blu-ray menus. If disabled, "\
89 "the movie will start directly")
90 #define BD_REGION_TEXT N_("Region code")
91 #define BD_REGION_LONGTEXT N_("Blu-Ray player region code. "\
92 "Some discs can be played only with a correct region code.")
94 static const char *const ppsz_region_code
[] = {
96 static const char *const ppsz_region_code_text
[] = {
97 "Region A", "Region B", "Region C" };
99 #define REGION_DEFAULT 1 /* Index to region list. Actual region code is (1<<REGION_DEFAULT) */
100 #define LANGUAGE_DEFAULT ("eng")
102 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,0)
103 # define BLURAY_DEMUX
106 #ifndef BD_STREAM_TYPE_VIDEO_HEVC
107 # define BD_STREAM_TYPE_VIDEO_HEVC 0x24
111 static int blurayOpen (vlc_object_t
*);
112 static void blurayClose(vlc_object_t
*);
115 set_shortname(N_("Blu-ray"))
116 set_description(N_("Blu-ray Disc support (libbluray)"))
118 set_category(CAT_INPUT
)
119 set_subcategory(SUBCAT_INPUT_ACCESS
)
120 set_capability("access", 500)
121 add_bool("bluray-menu", true, BD_MENU_TEXT
, BD_MENU_LONGTEXT
, false)
122 add_string("bluray-region", ppsz_region_code
[REGION_DEFAULT
], BD_REGION_TEXT
, BD_REGION_LONGTEXT
, false)
123 change_string_list(ppsz_region_code
, ppsz_region_code_text
)
125 add_shortcut("bluray", "file")
127 set_callbacks(blurayOpen
, blurayClose
)
132 set_description( "BluRay demuxer" )
133 set_category( CAT_INPUT
)
134 set_subcategory( SUBCAT_INPUT_DEMUX
)
135 set_capability( "demux", 5 )
136 set_callbacks( blurayOpen
, blurayClose
)
141 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
142 #define MAX_OVERLAY 2
144 typedef enum OverlayStatus
{
146 ToDisplay
, //Used to mark the overlay to be displayed the first time.
148 Outdated
//used to update the overlay after it has been sent to the vout
151 typedef struct bluray_spu_updater_sys_t bluray_spu_updater_sys_t
;
153 typedef struct bluray_overlay_t
157 OverlayStatus status
;
158 subpicture_region_t
*p_regions
;
161 /* pointer to last subpicture updater.
162 * used to disconnect this overlay from vout when:
163 * - the overlay is closed
164 * - vout is changed and this overlay is sent to the new vout
166 bluray_spu_updater_sys_t
*p_updater
;
174 unsigned int i_title
;
175 unsigned int i_longest_title
;
176 input_title_t
**pp_title
;
178 unsigned cur_seekpoint
;
181 vlc_mutex_t pl_info_lock
;
182 BLURAY_TITLE_INFO
*p_pl_info
;
183 const BLURAY_CLIP_INFO
*p_clip_info
;
187 input_attachment_t
**attachments
;
190 /* Meta information */
191 const META_DL
*p_meta
;
194 bluray_overlay_t
*p_overlays
[MAX_OVERLAY
];
198 bool b_popup_available
;
199 vlc_tick_t i_still_end_time
;
201 vlc_mutex_t bdj_overlay_lock
; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
204 vlc_mouse_t oldmouse
;
206 es_out_id_t
*p_dummy_video
;
207 es_out_id_t
*p_video_es
;
211 bool b_spu_enable
; /* enabled / disabled */
212 vlc_demux_chained_t
*p_parser
;
214 bool b_pl_playing
; /* true when playing playlist */
217 vlc_mutex_t read_block_lock
;
219 /* Used to store bluray disc path */
224 * Local ES index storage
230 int i_next_block_flags
;
233 static bool es_pair_Add(vlc_array_t
*p_array
, const es_format_t
*p_fmt
,
236 es_pair_t
*p_pair
= malloc(sizeof(*p_pair
));
237 if (likely(p_pair
!= NULL
))
240 p_pair
->i_next_block_flags
= 0;
241 if(vlc_array_append(p_array
, p_pair
) != VLC_SUCCESS
)
248 es_format_Init(&p_pair
->fmt
, p_fmt
->i_cat
, p_fmt
->i_codec
);
249 es_format_Copy(&p_pair
->fmt
, p_fmt
);
252 return p_pair
!= NULL
;
255 static void es_pair_Remove(vlc_array_t
*p_array
, es_pair_t
*p_pair
)
257 vlc_array_remove(p_array
, vlc_array_index_of_item(p_array
, p_pair
));
258 es_format_Clean(&p_pair
->fmt
);
262 static es_pair_t
*getEsPair(vlc_array_t
*p_array
,
263 bool (*match
)(const es_pair_t
*, const void *),
266 for (size_t i
= 0; i
< vlc_array_count(p_array
); ++i
)
268 es_pair_t
*p_pair
= vlc_array_item_at_index(p_array
, i
);
269 if(match(p_pair
, param
))
275 static bool es_pair_compare_PID(const es_pair_t
*p_pair
, const void *p_pid
)
277 return p_pair
->fmt
.i_id
== *((const int *)p_pid
);
280 static bool es_pair_compare_ES(const es_pair_t
*p_pair
, const void *p_es
)
282 return p_pair
->p_es
== (const es_out_id_t
*)p_es
;
285 static es_pair_t
*getEsPairByPID(vlc_array_t
*p_array
, int i_pid
)
287 return getEsPair(p_array
, es_pair_compare_PID
, &i_pid
);
290 static es_pair_t
*getEsPairByES(vlc_array_t
*p_array
, const es_out_id_t
*p_es
)
292 return getEsPair(p_array
, es_pair_compare_ES
, p_es
);
298 struct bluray_spu_updater_sys_t
300 vlc_mutex_t lock
; // protect p_overlay pointer and ref_cnt
301 bluray_overlay_t
*p_overlay
; // NULL if overlay has been closed
302 int ref_cnt
; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
306 * cut the connection between vout and overlay.
307 * - called when vout is closed or overlay is closed.
308 * - frees bluray_spu_updater_sys_t when both sides have been closed.
310 static void unref_subpicture_updater(bluray_spu_updater_sys_t
*p_sys
)
312 vlc_mutex_lock(&p_sys
->lock
);
313 int refs
= --p_sys
->ref_cnt
;
314 p_sys
->p_overlay
= NULL
;
315 vlc_mutex_unlock(&p_sys
->lock
);
318 vlc_mutex_destroy(&p_sys
->lock
);
324 * FIXME: partiallyy duplicated from src/input/es_out.c
326 static const char *DemuxGetLanguageCode( demux_t
*p_demux
, const char *psz_var
)
328 const iso639_lang_t
*pl
;
332 psz_lang
= var_CreateGetString( p_demux
, psz_var
);
334 return LANGUAGE_DEFAULT
;
336 /* XXX: we will use only the first value
337 * (and ignore other ones in case of a list) */
338 if( ( p
= strchr( psz_lang
, ',' ) ) )
341 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
343 if( *psz_lang
== '\0' )
345 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
346 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
347 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
348 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
354 if( pl
->psz_eng_name
!= NULL
)
355 return pl
->psz_iso639_2T
;
357 return LANGUAGE_DEFAULT
;
360 /*****************************************************************************
362 *****************************************************************************/
363 static es_out_t
*esOutNew(vlc_object_t
*, es_out_t
*, void *);
365 static int blurayControl(demux_t
*, int, va_list);
366 static int blurayDemux(demux_t
*);
368 static void blurayInitTitles(demux_t
*p_demux
, uint32_t menu_titles
);
369 static int bluraySetTitle(demux_t
*p_demux
, int i_title
);
371 static void blurayOverlayProc(void *ptr
, const BD_OVERLAY
* const overlay
);
372 static void blurayArgbOverlayProc(void *ptr
, const BD_ARGB_OVERLAY
* const overlay
);
374 static void onMouseEvent(const vlc_mouse_t
*mouse
, void *user_data
);
375 static void blurayRestartParser(demux_t
*p_demux
, bool);
376 static void notifyDiscontinuityToParser( demux_sys_t
*p_sys
);
378 #define STILL_IMAGE_NOT_SET 0
379 #define STILL_IMAGE_INFINITE -1
381 #define CURRENT_TITLE p_sys->pp_title[p_sys->cur_title]
382 #define CUR_LENGTH CURRENT_TITLE->i_length
385 static void FindMountPoint(char **file
)
387 char *device
= *file
;
388 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
389 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
390 * we look up the real device */
391 char *bd_device
= realpath(device
, NULL
);
392 if (bd_device
== NULL
)
396 if (lstat (bd_device
, &st
) == 0 && S_ISBLK (st
.st_mode
)) {
397 FILE *mtab
= setmntent ("/proc/self/mounts", "r");
399 struct mntent
*m
, mbuf
;
402 while ((m
= getmntent_r (mtab
, &mbuf
, buf
, sizeof(buf
))) != NULL
) {
403 if (!strcmp (m
->mnt_fsname
, bd_device
)) {
405 *file
= strdup(m
->mnt_dir
);
414 #elif defined(__APPLE__)
416 if (!stat (device
, &st
) && S_ISBLK (st
.st_mode
)) {
417 int fs_count
= getfsstat (NULL
, 0, MNT_NOWAIT
);
419 struct statfs mbuf
[128];
420 getfsstat (mbuf
, fs_count
* sizeof(mbuf
[0]), MNT_NOWAIT
);
421 for (int i
= 0; i
< fs_count
; ++i
)
422 if (!strcmp (mbuf
[i
].f_mntfromname
, device
)) {
424 *file
= strdup(mbuf
[i
].f_mntonname
);
430 # warning Disc device to mount point not implemented
431 VLC_UNUSED( device
);
435 static void blurayReleaseVideoES(demux_t
*p_demux
)
437 demux_sys_t
*p_sys
= p_demux
->p_sys
;
439 if (p_sys
->p_video_es
!= NULL
) {
440 for (int i
= 0; i
< MAX_OVERLAY
; i
++) {
441 bluray_overlay_t
*p_ov
= p_sys
->p_overlays
[i
];
443 vlc_mutex_lock(&p_ov
->lock
);
444 if (p_ov
->i_channel
!= -1) {
445 msg_Err(p_demux
, "blurayReleaseVout: subpicture channel exists\n");
446 es_out_Control( p_demux
->out
, ES_OUT_VOUT_FLUSH_OVERLAY
,
447 p_sys
->p_video_es
, p_ov
->i_channel
);
449 p_ov
->i_channel
= -1;
450 p_ov
->status
= Closed
;
451 vlc_mutex_unlock(&p_ov
->lock
);
453 if (p_ov
->p_updater
) {
454 unref_subpicture_updater(p_ov
->p_updater
);
455 p_ov
->p_updater
= NULL
;
459 p_sys
->p_video_es
= NULL
;
463 /*****************************************************************************
464 * BD-J background video
465 *****************************************************************************/
467 static es_out_id_t
* blurayCreateBackgroundUnlocked(demux_t
*p_demux
)
469 demux_sys_t
*p_sys
= p_demux
->p_sys
;
471 if (p_sys
->p_dummy_video
)
472 return p_sys
->p_dummy_video
;
474 msg_Info(p_demux
, "Start background");
478 es_format_Init( &fmt
, VIDEO_ES
, VLC_CODEC_I420
);
479 video_format_Setup( &fmt
.video
, VLC_CODEC_I420
,
480 1920, 1080, 1920, 1080, 1, 1);
481 fmt
.i_priority
= ES_PRIORITY_SELECTABLE_MIN
;
482 fmt
.i_id
= 4115; /* 4113 = main video. 4114 = MVC. 4115 = unused. */
485 p_sys
->p_dummy_video
= es_out_Add(p_demux
->out
, &fmt
);
487 if (!p_sys
->p_dummy_video
) {
488 msg_Err(p_demux
, "Error adding background ES");
492 block_t
*p_block
= block_Alloc(fmt
.video
.i_width
* fmt
.video
.i_height
*
493 fmt
.video
.i_bits_per_pixel
/ 8);
495 msg_Err(p_demux
, "Error allocating block for background video");
499 // XXX TODO: what would be correct timestamp ???
500 p_block
->i_dts
= p_block
->i_pts
= vlc_tick_now() + VLC_TICK_FROM_MS(40);
502 uint8_t *p
= p_block
->p_buffer
;
503 memset(p
, 0, fmt
.video
.i_width
* fmt
.video
.i_height
);
504 p
+= fmt
.video
.i_width
* fmt
.video
.i_height
;
505 memset(p
, 0x80, fmt
.video
.i_width
* fmt
.video
.i_height
/ 2);
507 es_out_Send(p_demux
->out
, p_sys
->p_dummy_video
, p_block
);
509 es_out_Control( p_demux
->out
, ES_OUT_VOUT_SET_MOUSE_EVENT
,
510 p_sys
->p_dummy_video
, onMouseEvent
, p_demux
);
513 es_format_Clean(&fmt
);
514 return p_sys
->p_dummy_video
;
517 static void stopBackground(demux_t
*p_demux
)
519 demux_sys_t
*p_sys
= p_demux
->p_sys
;
521 if (!p_sys
->p_dummy_video
) {
525 msg_Info(p_demux
, "Stop background");
527 es_out_Del(p_demux
->out
, p_sys
->p_dummy_video
);
529 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
530 if (p_sys
->p_video_es
== p_sys
->p_dummy_video
)
531 blurayReleaseVideoES(p_demux
);
532 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
534 p_sys
->p_dummy_video
= NULL
;
537 /*****************************************************************************
538 * cache current playlist (title) information
539 *****************************************************************************/
541 static void setTitleInfo(demux_sys_t
*p_sys
, BLURAY_TITLE_INFO
*info
)
543 vlc_mutex_lock(&p_sys
->pl_info_lock
);
545 if (p_sys
->p_pl_info
) {
546 bd_free_title_info(p_sys
->p_pl_info
);
548 p_sys
->p_pl_info
= info
;
549 p_sys
->p_clip_info
= NULL
;
551 if (p_sys
->p_pl_info
&& p_sys
->p_pl_info
->clip_count
) {
552 p_sys
->p_clip_info
= &p_sys
->p_pl_info
->clips
[0];
555 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
558 /*****************************************************************************
559 * create input attachment for thumbnail
560 *****************************************************************************/
562 static void attachThumbnail(demux_t
*p_demux
)
564 demux_sys_t
*p_sys
= p_demux
->p_sys
;
569 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
570 if (p_sys
->p_meta
->thumb_count
> 0 && p_sys
->p_meta
->thumbnails
) {
573 if (bd_get_meta_file(p_sys
->bluray
, p_sys
->p_meta
->thumbnails
[0].path
, &data
, &size
) > 0) {
575 input_attachment_t
*p_attachment
;
577 snprintf(psz_name
, sizeof(psz_name
), "picture%d_%s", p_sys
->i_attachments
, p_sys
->p_meta
->thumbnails
[0].path
);
579 p_attachment
= vlc_input_attachment_New(psz_name
, NULL
, "Album art", data
, size
);
581 p_sys
->i_cover_idx
= p_sys
->i_attachments
;
582 TAB_APPEND(p_sys
->i_attachments
, p_sys
->attachments
, p_attachment
);
590 /*****************************************************************************
592 *****************************************************************************/
594 static int probeStream(demux_t
*p_demux
)
596 /* input must be seekable */
597 bool b_canseek
= false;
598 vlc_stream_Control( p_demux
->s
, STREAM_CAN_SEEK
, &b_canseek
);
603 /* first sector(s) should be filled with zeros */
605 const uint8_t *p_peek
;
606 i_peek
= vlc_stream_Peek( p_demux
->s
, &p_peek
, 2048 );
607 if( i_peek
!= 2048 ) {
611 if (p_peek
[ --i_peek
]) {
620 static int blurayReadBlock(void *object
, void *buf
, int lba
, int num_blocks
)
622 demux_t
*p_demux
= (demux_t
*)object
;
623 demux_sys_t
*p_sys
= p_demux
->p_sys
;
626 assert(p_demux
->s
!= NULL
);
628 vlc_mutex_lock(&p_sys
->read_block_lock
);
630 if (vlc_stream_Seek( p_demux
->s
, lba
* INT64_C(2048) ) == VLC_SUCCESS
) {
631 size_t req
= (size_t)2048 * num_blocks
;
634 got
= vlc_stream_Read( p_demux
->s
, buf
, req
);
636 msg_Err(p_demux
, "read from lba %d failed", lba
);
641 msg_Err(p_demux
, "seek to lba %d failed", lba
);
644 vlc_mutex_unlock(&p_sys
->read_block_lock
);
650 /*****************************************************************************
651 * probing of local files
652 *****************************************************************************/
654 /* Descriptor Tag (ECMA 167, 3/7.2) */
655 static int decode_descriptor_tag(const uint8_t *buf
)
658 uint8_t checksum
= 0;
661 id
= buf
[0] | (buf
[1] << 8);
663 /* calculate tag checksum */
664 for (i
= 0; i
< 4; i
++) {
665 checksum
= (uint8_t)(checksum
+ buf
[i
]);
667 for (i
= 5; i
< 16; i
++) {
668 checksum
= (uint8_t)(checksum
+ buf
[i
]);
671 if (checksum
!= buf
[4]) {
678 static int probeFile(const char *psz_name
)
680 struct stat stat_info
;
683 int ret
= VLC_EGENERIC
;
686 fd
= vlc_open(psz_name
, O_RDONLY
| O_NONBLOCK
);
691 if (fstat(fd
, &stat_info
) == -1) {
694 if (!S_ISREG(stat_info
.st_mode
) && !S_ISBLK(stat_info
.st_mode
)) {
698 /* first sector should be filled with zeros */
699 if (read(fd
, peek
, sizeof(peek
)) != sizeof(peek
)) {
702 for (i
= 0; i
< sizeof(peek
); i
++) {
708 /* Check AVDP tag checksum */
709 if (lseek(fd
, 256 * 2048, SEEK_SET
) == -1 ||
710 read(fd
, peek
, 16) != 16 ||
711 decode_descriptor_tag(peek
) != 2) {
722 /*****************************************************************************
723 * blurayOpen: module init function
724 *****************************************************************************/
725 static int blurayOpen(vlc_object_t
*object
)
727 demux_t
*p_demux
= (demux_t
*)object
;
730 uint64_t i_init_pos
= 0;
732 const char *error_msg
= NULL
;
733 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
735 if (p_demux
->out
== NULL
)
738 forced
= !strncasecmp(p_demux
->psz_url
, "bluray:", 7);
741 if (!strncasecmp(p_demux
->psz_url
, "file:", 5)) {
742 /* use access_demux for local files */
746 if (probeStream(p_demux
) != VLC_SUCCESS
) {
750 } else if (!forced
) {
751 if (!p_demux
->psz_filepath
) {
755 if (probeFile(p_demux
->psz_filepath
) != VLC_SUCCESS
) {
761 p_demux
->p_sys
= p_sys
= vlc_obj_calloc(object
, 1, sizeof(*p_sys
));
762 if (unlikely(!p_sys
))
765 p_sys
->i_still_end_time
= STILL_IMAGE_NOT_SET
;
767 /* init demux info fields */
770 TAB_INIT(p_sys
->i_title
, p_sys
->pp_title
);
771 TAB_INIT(p_sys
->i_attachments
, p_sys
->attachments
);
773 vlc_mouse_Init(&p_sys
->oldmouse
);
775 vlc_mutex_init(&p_sys
->pl_info_lock
);
776 vlc_mutex_init(&p_sys
->bdj_overlay_lock
);
777 vlc_mutex_init(&p_sys
->read_block_lock
); /* used during bd_open_stream() */
779 /* request sub demuxers to skip continuity check as some split
780 file concatenation are just resetting counters... */
781 var_Create( p_demux
, "ts-cc-check", VLC_VAR_BOOL
);
782 var_SetBool( p_demux
, "ts-cc-check", false );
785 p_bluray_DebugObject
= VLC_OBJECT(p_demux
);
786 bd_set_debug_mask(BLURAY_DEBUG_MASK
);
787 bd_set_debug_handler(bluray_DebugHandler
);
793 i_init_pos
= vlc_stream_Tell(p_demux
->s
);
795 p_sys
->bluray
= bd_init();
796 if (!bd_open_stream(p_sys
->bluray
, p_demux
, blurayReadBlock
)) {
797 bd_close(p_sys
->bluray
);
798 p_sys
->bluray
= NULL
;
803 if (!p_demux
->psz_filepath
) {
804 /* no path provided (bluray://). use default DVD device. */
805 p_sys
->psz_bd_path
= var_InheritString(object
, "dvd");
807 /* store current bd path */
808 p_sys
->psz_bd_path
= strdup(p_demux
->psz_filepath
);
811 /* If we're passed a block device, try to convert it to the mount point. */
812 FindMountPoint(&p_sys
->psz_bd_path
);
814 p_sys
->bluray
= bd_open(p_sys
->psz_bd_path
, NULL
);
816 if (!p_sys
->bluray
) {
820 /* Warning the user about AACS/BD+ */
821 const BLURAY_DISC_INFO
*disc_info
= bd_get_disc_info(p_sys
->bluray
);
823 /* Is it a bluray? */
824 if (!disc_info
->bluray_detected
) {
826 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
831 msg_Info(p_demux
, "First play: %i, Top menu: %i\n"
832 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
833 disc_info
->first_play_supported
, disc_info
->top_menu_supported
,
834 disc_info
->num_hdmv_titles
, disc_info
->num_bdj_titles
,
835 disc_info
->num_unsupported_titles
);
838 if (disc_info
->aacs_detected
) {
839 msg_Dbg(p_demux
, "Disc is using AACS");
840 if (!disc_info
->libaacs_detected
)
841 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
842 ", and your system does not have it."));
843 if (!disc_info
->aacs_handled
) {
844 if (disc_info
->aacs_error_code
) {
845 switch (disc_info
->aacs_error_code
) {
846 case BD_AACS_CORRUPTED_DISC
:
847 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
848 case BD_AACS_NO_CONFIG
:
849 BLURAY_ERROR(_("Missing AACS configuration file!"));
851 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
852 case BD_AACS_NO_CERT
:
853 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
854 case BD_AACS_CERT_REVOKED
:
855 BLURAY_ERROR(_("AACS Host certificate revoked."));
856 case BD_AACS_MMC_FAILED
:
857 BLURAY_ERROR(_("AACS MMC failed."));
864 if (disc_info
->bdplus_detected
) {
865 msg_Dbg(p_demux
, "Disc is using BD+");
866 if (!disc_info
->libbdplus_detected
)
867 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
868 ", and your system does not have it."));
869 if (!disc_info
->bdplus_handled
)
870 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
871 "Missing configuration?"));
874 /* set player region code */
875 char *psz_region
= var_InheritString(p_demux
, "bluray-region");
876 unsigned int region
= psz_region
? (psz_region
[0] - 'A') : REGION_DEFAULT
;
878 bd_set_player_setting(p_sys
->bluray
, BLURAY_PLAYER_SETTING_REGION_CODE
, 1<<region
);
880 /* set preferred languages */
881 const char *psz_code
= DemuxGetLanguageCode( p_demux
, "audio-language" );
882 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_AUDIO_LANG
, psz_code
);
883 psz_code
= DemuxGetLanguageCode( p_demux
, "sub-language" );
884 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_PG_LANG
, psz_code
);
885 psz_code
= DemuxGetLanguageCode( p_demux
, "menu-language" );
886 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_MENU_LANG
, psz_code
);
888 /* Get disc metadata */
889 p_sys
->p_meta
= bd_get_meta(p_sys
->bluray
);
891 msg_Warn(p_demux
, "Failed to get meta info.");
893 p_sys
->i_cover_idx
= -1;
894 attachThumbnail(p_demux
);
896 p_sys
->b_menu
= var_InheritBool(p_demux
, "bluray-menu");
898 /* Check BD-J capability */
899 if (p_sys
->b_menu
&& disc_info
->bdj_detected
&& !disc_info
->bdj_handled
) {
900 msg_Err(p_demux
, "BD-J menus not supported. Playing without menus. "
901 "BD-J support: %d, JVM found: %d, JVM usable: %d",
902 disc_info
->bdj_supported
, disc_info
->libjvm_detected
, disc_info
->bdj_handled
);
903 vlc_dialog_display_error(p_demux
, _("Java required"),
904 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
905 !disc_info
->libjvm_detected
? _("Java was not found on your system.") : "");
906 p_sys
->b_menu
= false;
909 /* Get titles and chapters */
910 blurayInitTitles(p_demux
, disc_info
->num_hdmv_titles
+ disc_info
->num_bdj_titles
+ 1/*Top Menu*/ + 1/*First Play*/);
913 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
915 bd_get_event(p_sys
->bluray
, NULL
);
917 /* Registering overlay event handler */
918 bd_register_overlay_proc(p_sys
->bluray
, p_demux
, blurayOverlayProc
);
922 /* Register ARGB overlay handler for BD-J */
923 if (disc_info
->num_bdj_titles
)
924 bd_register_argb_overlay_proc(p_sys
->bluray
, p_demux
, blurayArgbOverlayProc
, NULL
);
926 /* libbluray will start playback from "First-Title" title */
927 if (bd_play(p_sys
->bluray
) == 0)
928 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
931 /* set start title number */
932 if (bluraySetTitle(p_demux
, p_sys
->i_longest_title
) != VLC_SUCCESS
) {
933 msg_Err(p_demux
, "Could not set the title %d", p_sys
->i_longest_title
);
938 p_sys
->p_out
= esOutNew(VLC_OBJECT(p_demux
), p_demux
->out
, p_demux
);
939 if (unlikely(p_sys
->p_out
== NULL
))
942 p_sys
->p_parser
= vlc_demux_chained_New(VLC_OBJECT(p_demux
), "ts", p_sys
->p_out
);
943 if (!p_sys
->p_parser
) {
944 msg_Err(p_demux
, "Failed to create TS demuxer");
948 p_demux
->pf_control
= blurayControl
;
949 p_demux
->pf_demux
= blurayDemux
;
955 vlc_dialog_display_error(p_demux
, _("Blu-ray error"), "%s", error_msg
);
958 if (p_demux
->s
!= NULL
) {
959 /* restore stream position */
960 if (vlc_stream_Seek(p_demux
->s
, i_init_pos
) != VLC_SUCCESS
) {
961 msg_Err(p_demux
, "Failed to seek back to stream start");
971 /*****************************************************************************
972 * blurayClose: module destroy function
973 *****************************************************************************/
974 static void blurayClose(vlc_object_t
*object
)
976 demux_t
*p_demux
= (demux_t
*)object
;
977 demux_sys_t
*p_sys
= p_demux
->p_sys
;
979 setTitleInfo(p_sys
, NULL
);
982 * Close libbluray first.
983 * This will close all the overlays before we release p_vout
984 * bd_close(NULL) can crash
987 bd_close(p_sys
->bluray
);
990 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
991 blurayReleaseVideoES(p_demux
);
992 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
995 vlc_demux_chained_Delete(p_sys
->p_parser
);
996 es_out_Delete(p_sys
->p_out
);
999 for (unsigned int i
= 0; i
< p_sys
->i_title
; i
++)
1000 vlc_input_title_Delete(p_sys
->pp_title
[i
]);
1001 TAB_CLEAN(p_sys
->i_title
, p_sys
->pp_title
);
1003 for (int i
= 0; i
< p_sys
->i_attachments
; i
++)
1004 vlc_input_attachment_Delete(p_sys
->attachments
[i
]);
1005 TAB_CLEAN(p_sys
->i_attachments
, p_sys
->attachments
);
1007 vlc_mutex_destroy(&p_sys
->pl_info_lock
);
1008 vlc_mutex_destroy(&p_sys
->bdj_overlay_lock
);
1009 vlc_mutex_destroy(&p_sys
->read_block_lock
);
1011 free(p_sys
->psz_bd_path
);
1014 /*****************************************************************************
1015 * Elementary streams handling
1016 *****************************************************************************/
1017 static uint8_t blurayGetStreamsUnlocked(demux_sys_t
*p_sys
,
1019 BLURAY_STREAM_INFO
**pp_streams
)
1021 if(!p_sys
->p_clip_info
)
1024 switch(i_stream_type
)
1026 case BD_EVENT_AUDIO_STREAM
:
1027 *pp_streams
= p_sys
->p_clip_info
->audio_streams
;
1028 return p_sys
->p_clip_info
->audio_stream_count
;
1029 case BD_EVENT_PG_TEXTST_STREAM
:
1030 *pp_streams
= p_sys
->p_clip_info
->pg_streams
;
1031 return p_sys
->p_clip_info
->pg_stream_count
;
1037 static BLURAY_STREAM_INFO
* blurayGetStreamInfoUnlocked(demux_sys_t
*p_sys
,
1039 uint8_t i_stream_idx
)
1041 BLURAY_STREAM_INFO
*p_streams
= NULL
;
1042 uint8_t i_streams_count
= blurayGetStreamsUnlocked(p_sys
, i_stream_type
, &p_streams
);
1043 if(i_stream_idx
< i_streams_count
)
1044 return &p_streams
[i_stream_idx
];
1049 static BLURAY_STREAM_INFO
* blurayGetStreamInfoByPIDUnlocked(demux_sys_t
*p_sys
,
1052 for(int i_type
=BD_EVENT_AUDIO_STREAM
; i_type
<=BD_EVENT_SECONDARY_VIDEO_STREAM
; i_type
++)
1054 BLURAY_STREAM_INFO
*p_streams
;
1055 uint8_t i_streams_count
= blurayGetStreamsUnlocked(p_sys
, i_type
, &p_streams
);
1056 for(uint8_t i
=0; i
<i_streams_count
; i
++)
1058 if(p_streams
[i
].pid
== i_pid
)
1059 return &p_streams
[i
];
1065 static void setStreamLang(demux_sys_t
*p_sys
, es_format_t
*p_fmt
)
1067 vlc_mutex_lock(&p_sys
->pl_info_lock
);
1069 BLURAY_STREAM_INFO
*p_stream
= blurayGetStreamInfoByPIDUnlocked(p_sys
, p_fmt
->i_id
);
1072 free(p_fmt
->psz_language
);
1073 p_fmt
->psz_language
= strndup((const char *)p_stream
->lang
, 3);
1076 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
1079 static int blurayGetStreamPID(demux_sys_t
*p_sys
, int i_stream_type
, uint8_t i_stream_idx
)
1081 vlc_mutex_lock(&p_sys
->pl_info_lock
);
1083 BLURAY_STREAM_INFO
*p_stream
= blurayGetStreamInfoUnlocked(p_sys
,
1086 int i_pid
= p_stream
? p_stream
->pid
: -1;
1088 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
1093 /*****************************************************************************
1094 * bluray fake es_out
1095 *****************************************************************************/
1098 es_out_t
*p_dst_out
;
1099 vlc_object_t
*p_obj
;
1100 vlc_array_t es
; /* es_pair_t */
1102 bool b_discontinuity
;
1103 bool b_disable_output
;
1107 int i_audio_pid
; /* Selected audio stream. -1 if default */
1109 int i_spu_pid
; /* Selected spu stream. -1 if default */
1112 } bluray_esout_priv_t
;
1116 BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID
= ES_OUT_PRIVATE_START
,
1117 BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID
,
1118 BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
,
1119 BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT
,
1120 BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT
,
1123 static es_out_id_t
*bluray_esOutAdd(es_out_t
*p_out
, const es_format_t
*p_fmt
)
1125 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1126 demux_t
*p_demux
= esout_priv
->priv
;
1127 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1129 bool b_select
= false;
1131 es_format_Copy(&fmt
, p_fmt
);
1133 vlc_mutex_lock(&esout_priv
->lock
);
1135 switch (fmt
.i_cat
) {
1137 if (esout_priv
->selected
.i_video_pid
!= -1 && esout_priv
->selected
.i_video_pid
!= p_fmt
->i_id
)
1138 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1141 if (esout_priv
->selected
.i_audio_pid
!= -1) {
1142 if (esout_priv
->selected
.i_audio_pid
== p_fmt
->i_id
)
1144 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1146 setStreamLang(p_sys
, &fmt
);
1149 if (esout_priv
->selected
.i_spu_pid
!= -1) {
1150 if (esout_priv
->selected
.i_spu_pid
== p_fmt
->i_id
)
1151 b_select
= p_sys
->b_spu_enable
;
1152 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1154 setStreamLang(p_sys
, &fmt
);
1160 es_out_id_t
*p_es
= es_out_Add(esout_priv
->p_dst_out
, &fmt
);
1161 if (p_fmt
->i_id
>= 0) {
1162 /* Ensure we are not overriding anything */
1163 es_pair_t
*p_pair
= getEsPairByPID(&esout_priv
->es
, p_fmt
->i_id
);
1166 msg_Info(p_demux
, "Adding ES %d", p_fmt
->i_id
);
1167 if (es_pair_Add(&esout_priv
->es
, &fmt
, p_es
) && b_select
)
1168 es_out_Control(p_demux
->out
, ES_OUT_SET_ES
, p_es
);
1171 if (p_es
&& fmt
.i_cat
== VIDEO_ES
)
1173 es_out_Control( p_demux
->out
, ES_OUT_VOUT_SET_MOUSE_EVENT
, p_es
,
1174 onMouseEvent
, p_demux
);
1175 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1176 p_sys
->p_video_es
= p_es
;
1177 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1179 es_format_Clean(&fmt
);
1181 vlc_mutex_unlock(&esout_priv
->lock
);
1186 static int bluray_esOutSend(es_out_t
*p_out
, es_out_id_t
*p_es
, block_t
*p_block
)
1188 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1190 vlc_mutex_lock(&esout_priv
->lock
);
1192 if(esout_priv
->b_discontinuity
)
1193 esout_priv
->b_discontinuity
= false;
1195 es_pair_t
*p_pair
= getEsPairByES(&esout_priv
->es
, p_es
);
1196 if(p_pair
&& p_pair
->i_next_block_flags
)
1198 p_block
->i_flags
|= p_pair
->i_next_block_flags
;
1199 p_pair
->i_next_block_flags
= 0;
1201 if(esout_priv
->b_disable_output
)
1203 block_Release(p_block
);
1206 vlc_mutex_unlock(&esout_priv
->lock
);
1207 return (p_block
) ? es_out_Send(esout_priv
->p_dst_out
, p_es
, p_block
) : VLC_SUCCESS
;
1210 static void bluray_esOutDel(es_out_t
*p_out
, es_out_id_t
*p_es
)
1212 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1213 demux_t
*p_demux
= esout_priv
->priv
;
1214 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1216 vlc_mutex_lock(&esout_priv
->lock
);
1218 if(esout_priv
->b_discontinuity
)
1219 esout_priv
->b_discontinuity
= false;
1221 es_pair_t
*p_pair
= getEsPairByES(&esout_priv
->es
, p_es
);
1223 es_pair_Remove(&esout_priv
->es
, p_pair
);
1225 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1226 if (p_es
== p_sys
->p_video_es
)
1227 p_sys
->p_video_es
= NULL
;
1228 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1230 es_out_Del(esout_priv
->p_dst_out
, p_es
);
1232 vlc_mutex_unlock(&esout_priv
->lock
);
1235 static int bluray_esOutControl(es_out_t
*p_out
, int i_query
, va_list args
)
1237 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1239 vlc_mutex_lock(&esout_priv
->lock
);
1241 if(esout_priv
->b_disable_output
&&
1242 i_query
< ES_OUT_PRIVATE_START
)
1244 vlc_mutex_unlock(&esout_priv
->lock
);
1245 return VLC_EGENERIC
;
1248 if(esout_priv
->b_discontinuity
)
1249 esout_priv
->b_discontinuity
= false;
1253 case BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID
:
1254 case BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID
:
1256 bool b_select
= (i_query
== BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID
);
1257 const int i_bluray_stream_type
= va_arg(args
, int);
1258 const int i_pid
= va_arg(args
, int);
1259 switch(i_bluray_stream_type
)
1261 case BD_EVENT_AUDIO_STREAM
:
1262 esout_priv
->selected
.i_audio_pid
= i_pid
;
1264 case BD_EVENT_PG_TEXTST_STREAM
:
1265 esout_priv
->selected
.i_spu_pid
= i_pid
;
1271 es_pair_t
*p_pair
= getEsPairByPID(&esout_priv
->es
, i_pid
);
1272 if(unlikely(!p_pair
))
1274 vlc_mutex_unlock(&esout_priv
->lock
);
1275 return VLC_EGENERIC
;
1278 i_ret
= es_out_Control(esout_priv
->p_dst_out
,
1279 b_select
? ES_OUT_SET_ES
: ES_OUT_UNSET_ES
,
1283 case BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
:
1285 esout_priv
->b_discontinuity
= true;
1286 i_ret
= VLC_SUCCESS
;
1289 case BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT
:
1290 case BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT
:
1292 esout_priv
->b_disable_output
= (i_query
== BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT
);
1293 i_ret
= VLC_SUCCESS
;
1296 case ES_OUT_SET_ES_DEFAULT
:
1298 case ES_OUT_UNSET_ES
:
1299 case ES_OUT_SET_ES_STATE
:
1300 i_ret
= VLC_EGENERIC
;
1303 case ES_OUT_GET_ES_STATE
:
1304 va_arg(args
, es_out_id_t
*);
1305 *va_arg(args
, bool *) = true;
1306 i_ret
= VLC_SUCCESS
;
1310 i_ret
= es_out_vaControl(esout_priv
->p_dst_out
, i_query
, args
);
1313 vlc_mutex_unlock(&esout_priv
->lock
);
1317 static void bluray_esOutDestroy(es_out_t
*p_out
)
1319 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1321 for (size_t i
= 0; i
< vlc_array_count(&esout_priv
->es
); ++i
)
1322 free(vlc_array_item_at_index(&esout_priv
->es
, i
));
1323 vlc_array_clear(&esout_priv
->es
);
1324 vlc_mutex_destroy(&esout_priv
->lock
);
1328 static const struct es_out_callbacks bluray_esOutCallbacks
= {
1329 .add
= bluray_esOutAdd
,
1330 .send
= bluray_esOutSend
,
1331 .del
= bluray_esOutDel
,
1332 .control
= bluray_esOutControl
,
1333 .destroy
= bluray_esOutDestroy
,
1336 static es_out_t
*esOutNew(vlc_object_t
*p_obj
, es_out_t
*p_dst_out
, void *priv
)
1338 bluray_esout_priv_t
*esout_priv
= malloc(sizeof(*esout_priv
));
1339 if (unlikely(esout_priv
== NULL
))
1342 vlc_array_init(&esout_priv
->es
);
1343 esout_priv
->p_dst_out
= p_dst_out
;
1344 esout_priv
->p_obj
= p_obj
;
1345 esout_priv
->priv
= priv
;
1346 esout_priv
->es_out
.cbs
= &bluray_esOutCallbacks
;
1347 esout_priv
->b_discontinuity
= false;
1348 esout_priv
->b_disable_output
= false;
1349 esout_priv
->selected
.i_audio_pid
= -1;
1350 esout_priv
->selected
.i_video_pid
= -1;
1351 esout_priv
->selected
.i_spu_pid
= -1;
1352 vlc_mutex_init(&esout_priv
->lock
);
1353 return &esout_priv
->es_out
;
1356 /*****************************************************************************
1357 * subpicture_updater_t functions:
1358 *****************************************************************************/
1360 static bluray_overlay_t
*updater_lock_overlay(bluray_spu_updater_sys_t
*p_upd_sys
)
1362 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1363 vlc_mutex_lock(&p_upd_sys
->lock
);
1365 bluray_overlay_t
*ov
= p_upd_sys
->p_overlay
;
1367 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1368 vlc_mutex_lock(&ov
->lock
);
1372 /* overlay has been closed */
1373 vlc_mutex_unlock(&p_upd_sys
->lock
);
1377 static void updater_unlock_overlay(bluray_spu_updater_sys_t
*p_upd_sys
)
1379 assert (p_upd_sys
->p_overlay
);
1381 vlc_mutex_unlock(&p_upd_sys
->p_overlay
->lock
);
1382 vlc_mutex_unlock(&p_upd_sys
->lock
);
1385 static int subpictureUpdaterValidate(subpicture_t
*p_subpic
,
1386 bool b_fmt_src
, const video_format_t
*p_fmt_src
,
1387 bool b_fmt_dst
, const video_format_t
*p_fmt_dst
,
1390 VLC_UNUSED(b_fmt_src
);
1391 VLC_UNUSED(b_fmt_dst
);
1392 VLC_UNUSED(p_fmt_src
);
1393 VLC_UNUSED(p_fmt_dst
);
1396 bluray_spu_updater_sys_t
*p_upd_sys
= p_subpic
->updater
.p_sys
;
1397 bluray_overlay_t
*p_overlay
= updater_lock_overlay(p_upd_sys
);
1403 int res
= p_overlay
->status
== Outdated
;
1405 updater_unlock_overlay(p_upd_sys
);
1410 static void subpictureUpdaterUpdate(subpicture_t
*p_subpic
,
1411 const video_format_t
*p_fmt_src
,
1412 const video_format_t
*p_fmt_dst
,
1415 VLC_UNUSED(p_fmt_src
);
1416 VLC_UNUSED(p_fmt_dst
);
1418 bluray_spu_updater_sys_t
*p_upd_sys
= p_subpic
->updater
.p_sys
;
1419 bluray_overlay_t
*p_overlay
= updater_lock_overlay(p_upd_sys
);
1426 * When this function is called, all p_subpic regions are gone.
1427 * We need to duplicate our regions (stored internaly) to this subpic.
1429 subpicture_region_t
*p_src
= p_overlay
->p_regions
;
1431 updater_unlock_overlay(p_upd_sys
);
1435 subpicture_region_t
**p_dst
= &p_subpic
->p_region
;
1436 while (p_src
!= NULL
) {
1437 *p_dst
= subpicture_region_Copy(p_src
);
1440 p_dst
= &(*p_dst
)->p_next
;
1441 p_src
= p_src
->p_next
;
1444 (*p_dst
)->p_next
= NULL
;
1445 p_overlay
->status
= Displayed
;
1447 updater_unlock_overlay(p_upd_sys
);
1450 static void subpictureUpdaterDestroy(subpicture_t
*p_subpic
)
1452 bluray_spu_updater_sys_t
*p_upd_sys
= p_subpic
->updater
.p_sys
;
1453 bluray_overlay_t
*p_overlay
= updater_lock_overlay(p_upd_sys
);
1456 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1457 p_overlay
->status
= ToDisplay
;
1458 p_overlay
->i_channel
= -1;
1459 updater_unlock_overlay(p_upd_sys
);
1462 unref_subpicture_updater(p_upd_sys
);
1465 static subpicture_t
*bluraySubpictureCreate(bluray_overlay_t
*p_ov
)
1467 bluray_spu_updater_sys_t
*p_upd_sys
= malloc(sizeof(*p_upd_sys
));
1468 if (unlikely(p_upd_sys
== NULL
)) {
1472 p_upd_sys
->p_overlay
= p_ov
;
1474 subpicture_updater_t updater
= {
1475 .pf_validate
= subpictureUpdaterValidate
,
1476 .pf_update
= subpictureUpdaterUpdate
,
1477 .pf_destroy
= subpictureUpdaterDestroy
,
1481 subpicture_t
*p_pic
= subpicture_New(&updater
);
1482 if (p_pic
== NULL
) {
1487 p_pic
->i_original_picture_width
= p_ov
->width
;
1488 p_pic
->i_original_picture_height
= p_ov
->height
;
1489 p_pic
->b_absolute
= true;
1491 vlc_mutex_init(&p_upd_sys
->lock
);
1492 p_upd_sys
->ref_cnt
= 2;
1494 p_ov
->p_updater
= p_upd_sys
;
1499 /*****************************************************************************
1500 * User input events:
1501 *****************************************************************************/
1502 static void onMouseEvent(const vlc_mouse_t
*newmouse
, void *user_data
)
1504 demux_t
*p_demux
= user_data
;
1505 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1508 vlc_mouse_Init(&p_sys
->oldmouse
);
1512 if (vlc_mouse_HasMoved(&p_sys
->oldmouse
, newmouse
))
1513 bd_mouse_select(p_sys
->bluray
, -1, newmouse
->i_x
, newmouse
->i_y
);
1515 if (vlc_mouse_HasPressed( &p_sys
->oldmouse
, newmouse
, MOUSE_BUTTON_LEFT
))
1516 bd_user_input(p_sys
->bluray
, -1, BD_VK_MOUSE_ACTIVATE
);
1517 p_sys
->oldmouse
= *newmouse
;
1520 static int sendKeyEvent(demux_sys_t
*p_sys
, unsigned int key
)
1522 if (bd_user_input(p_sys
->bluray
, -1, key
) < 0)
1523 return VLC_EGENERIC
;
1528 /*****************************************************************************
1529 * libbluray overlay handling:
1530 *****************************************************************************/
1532 static void blurayCloseOverlay(demux_t
*p_demux
, int plane
)
1534 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1535 bluray_overlay_t
*ov
= p_sys
->p_overlays
[plane
];
1539 /* drop overlay from vout */
1540 if (ov
->p_updater
) {
1541 unref_subpicture_updater(ov
->p_updater
);
1543 /* no references to this overlay exist in vo anymore */
1544 if (p_sys
->p_video_es
&& ov
->i_channel
!= -1) {
1545 es_out_Control( p_demux
->out
, ES_OUT_VOUT_FLUSH_OVERLAY
,
1546 p_sys
->p_video_es
, ov
->i_channel
);
1549 vlc_mutex_destroy(&ov
->lock
);
1550 subpicture_region_ChainDelete(ov
->p_regions
);
1553 p_sys
->p_overlays
[plane
] = NULL
;
1556 for (int i
= 0; i
< MAX_OVERLAY
; i
++)
1557 if (p_sys
->p_overlays
[i
])
1560 /* All overlays have been closed */
1561 blurayReleaseVideoES(p_demux
);
1565 * Mark the overlay as "ToDisplay" status.
1566 * This will not send the overlay to the vout instantly, as the vout
1567 * may not be acquired (not acquirable) yet.
1568 * If is has already been acquired, the overlay has already been sent to it,
1569 * therefore, we only flag the overlay as "Outdated"
1571 static void blurayActivateOverlay(demux_t
*p_demux
, int plane
)
1573 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1574 bluray_overlay_t
*ov
= p_sys
->p_overlays
[plane
];
1577 * If the overlay is already displayed, mark the picture as outdated.
1578 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1580 vlc_mutex_lock(&ov
->lock
);
1581 if (ov
->status
>= Displayed
&& p_sys
->p_video_es
) {
1582 ov
->status
= Outdated
;
1583 vlc_mutex_unlock(&ov
->lock
);
1588 * Mark the overlay as available, but don't display it right now.
1589 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1590 * the overlay is computed
1592 ov
->status
= ToDisplay
;
1593 vlc_mutex_unlock(&ov
->lock
);
1596 static void blurayInitOverlay(demux_t
*p_demux
, int plane
, int width
, int height
)
1598 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1600 assert(p_sys
->p_overlays
[plane
] == NULL
);
1602 bluray_overlay_t
*ov
= calloc(1, sizeof(*ov
));
1603 if (unlikely(ov
== NULL
))
1607 ov
->height
= height
;
1610 vlc_mutex_init(&ov
->lock
);
1612 p_sys
->p_overlays
[plane
] = ov
;
1616 * Destroy every regions in the subpicture.
1617 * This is done in two steps:
1618 * - Wiping our private regions list
1619 * - Flagging the overlay as outdated, so the changes are replicated from
1620 * the subpicture_updater_t::pf_update
1621 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1623 static void blurayClearOverlay(demux_t
*p_demux
, int plane
)
1625 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1626 bluray_overlay_t
*ov
= p_sys
->p_overlays
[plane
];
1628 vlc_mutex_lock(&ov
->lock
);
1630 subpicture_region_ChainDelete(ov
->p_regions
);
1631 ov
->p_regions
= NULL
;
1632 ov
->status
= Outdated
;
1634 vlc_mutex_unlock(&ov
->lock
);
1638 * This will draw to the overlay by adding a region to our region list
1639 * This will have to be copied to the subpicture used to render the overlay.
1641 static void blurayDrawOverlay(demux_t
*p_demux
, const BD_OVERLAY
* const ov
)
1643 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1646 * Compute a subpicture_region_t.
1647 * It will be copied and sent to the vout later.
1649 vlc_mutex_lock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1651 /* Find a region to update */
1652 subpicture_region_t
**pp_reg
= &p_sys
->p_overlays
[ov
->plane
]->p_regions
;
1653 subpicture_region_t
*p_reg
= p_sys
->p_overlays
[ov
->plane
]->p_regions
;
1654 subpicture_region_t
*p_last
= NULL
;
1655 while (p_reg
!= NULL
) {
1657 if (p_reg
->i_x
== ov
->x
&& p_reg
->i_y
== ov
->y
&&
1658 p_reg
->fmt
.i_width
== ov
->w
&& p_reg
->fmt
.i_height
== ov
->h
)
1660 pp_reg
= &p_reg
->p_next
;
1661 p_reg
= p_reg
->p_next
;
1667 *pp_reg
= p_reg
->p_next
;
1668 subpicture_region_Delete(p_reg
);
1670 vlc_mutex_unlock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1674 /* If there is no region to update, create a new one. */
1677 video_format_Init(&fmt
, 0);
1678 video_format_Setup(&fmt
, VLC_CODEC_YUVP
, ov
->w
, ov
->h
, ov
->w
, ov
->h
, 1, 1);
1680 p_reg
= subpicture_region_New(&fmt
);
1683 /* Append it to our list. */
1685 p_last
->p_next
= p_reg
;
1686 else /* If we don't have a last region, then our list empty */
1687 p_sys
->p_overlays
[ov
->plane
]->p_regions
= p_reg
;
1690 /* Now we can update the region, regardless it's an update or an insert */
1691 const BD_PG_RLE_ELEM
*img
= ov
->img
;
1692 for (int y
= 0; y
< ov
->h
; y
++)
1693 for (int x
= 0; x
< ov
->w
;) {
1694 plane_t
*p
= &p_reg
->p_picture
->p
[0];
1695 memset(&p
->p_pixels
[y
* p
->i_pitch
+ x
], img
->color
, img
->len
);
1701 p_reg
->fmt
.p_palette
->i_entries
= 256;
1702 for (int i
= 0; i
< 256; ++i
) {
1703 p_reg
->fmt
.p_palette
->palette
[i
][0] = ov
->palette
[i
].Y
;
1704 p_reg
->fmt
.p_palette
->palette
[i
][1] = ov
->palette
[i
].Cb
;
1705 p_reg
->fmt
.p_palette
->palette
[i
][2] = ov
->palette
[i
].Cr
;
1706 p_reg
->fmt
.p_palette
->palette
[i
][3] = ov
->palette
[i
].T
;
1710 vlc_mutex_unlock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1712 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1716 static void blurayOverlayProc(void *ptr
, const BD_OVERLAY
*const overlay
)
1718 demux_t
*p_demux
= (demux_t
*)ptr
;
1719 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1722 msg_Info(p_demux
, "Closing overlays.");
1723 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1724 if (p_sys
->p_video_es
)
1725 for (int i
= 0; i
< MAX_OVERLAY
; i
++)
1726 blurayCloseOverlay(p_demux
, i
);
1727 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1731 switch (overlay
->cmd
) {
1732 case BD_OVERLAY_INIT
:
1733 msg_Info(p_demux
, "Initializing overlay");
1734 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1735 blurayInitOverlay(p_demux
, overlay
->plane
, overlay
->w
, overlay
->h
);
1736 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1738 case BD_OVERLAY_CLOSE
:
1739 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1740 blurayClearOverlay(p_demux
, overlay
->plane
);
1741 blurayCloseOverlay(p_demux
, overlay
->plane
);
1742 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1744 case BD_OVERLAY_CLEAR
:
1745 blurayClearOverlay(p_demux
, overlay
->plane
);
1747 case BD_OVERLAY_FLUSH
:
1748 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1749 blurayActivateOverlay(p_demux
, overlay
->plane
);
1750 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1752 case BD_OVERLAY_DRAW
:
1753 case BD_OVERLAY_WIPE
:
1754 blurayDrawOverlay(p_demux
, overlay
);
1757 msg_Warn(p_demux
, "Unknown BD overlay command: %u", overlay
->cmd
);
1763 * ARGB overlay (BD-J)
1765 static void blurayInitArgbOverlay(demux_t
*p_demux
, int plane
, int width
, int height
)
1767 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1769 blurayInitOverlay(p_demux
, plane
, width
, height
);
1771 if (!p_sys
->p_overlays
[plane
]->p_regions
) {
1773 video_format_Init(&fmt
, 0);
1774 video_format_Setup(&fmt
, VLC_CODEC_RGBA
, width
, height
, width
, height
, 1, 1);
1776 p_sys
->p_overlays
[plane
]->p_regions
= subpicture_region_New(&fmt
);
1780 static void blurayDrawArgbOverlay(demux_t
*p_demux
, const BD_ARGB_OVERLAY
* const ov
)
1782 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1784 vlc_mutex_lock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1786 /* Find a region to update */
1787 subpicture_region_t
*p_reg
= p_sys
->p_overlays
[ov
->plane
]->p_regions
;
1789 vlc_mutex_unlock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1793 /* Now we can update the region */
1794 const uint32_t *src0
= ov
->argb
;
1795 uint8_t *dst0
= p_reg
->p_picture
->p
[0].p_pixels
+
1796 p_reg
->p_picture
->p
[0].i_pitch
* ov
->y
+
1799 for (int y
= 0; y
< ov
->h
; y
++) {
1800 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1801 // - or add libbluray option to select the format ?
1802 for (int x
= 0; x
< ov
->w
; x
++) {
1803 dst0
[x
*4 ] = src0
[x
]>>16; /* R */
1804 dst0
[x
*4+1] = src0
[x
]>>8; /* G */
1805 dst0
[x
*4+2] = src0
[x
]; /* B */
1806 dst0
[x
*4+3] = src0
[x
]>>24; /* A */
1810 dst0
+= p_reg
->p_picture
->p
[0].i_pitch
;
1813 vlc_mutex_unlock(&p_sys
->p_overlays
[ov
->plane
]->lock
);
1815 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1819 static void blurayArgbOverlayProc(void *ptr
, const BD_ARGB_OVERLAY
*const overlay
)
1821 demux_t
*p_demux
= (demux_t
*)ptr
;
1822 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1824 switch (overlay
->cmd
) {
1825 case BD_ARGB_OVERLAY_INIT
:
1826 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1827 blurayInitArgbOverlay(p_demux
, overlay
->plane
, overlay
->w
, overlay
->h
);
1828 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1830 case BD_ARGB_OVERLAY_CLOSE
:
1831 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
1832 blurayClearOverlay(p_demux
, overlay
->plane
);
1833 blurayCloseOverlay(p_demux
, overlay
->plane
);
1834 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
1836 case BD_ARGB_OVERLAY_FLUSH
:
1837 blurayActivateOverlay(p_demux
, overlay
->plane
);
1839 case BD_ARGB_OVERLAY_DRAW
:
1840 blurayDrawArgbOverlay(p_demux
, overlay
);
1843 msg_Warn(p_demux
, "Unknown BD ARGB overlay command: %u", overlay
->cmd
);
1848 static void bluraySendOverlayToVout(demux_t
*p_demux
, bluray_overlay_t
*p_ov
)
1850 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1852 assert(p_ov
!= NULL
);
1853 assert(p_ov
->i_channel
== -1);
1855 if (p_ov
->p_updater
) {
1856 unref_subpicture_updater(p_ov
->p_updater
);
1857 p_ov
->p_updater
= NULL
;
1860 subpicture_t
*p_pic
= bluraySubpictureCreate(p_ov
);
1862 msg_Err(p_demux
, "bluraySubpictureCreate() failed");
1867 * After this point, the picture should not be accessed from the demux thread,
1868 * as it is held by the vout thread.
1869 * This must be done only once per subpicture, ie. only once between each
1870 * blurayInitOverlay & blurayCloseOverlay call.
1872 int ret
= es_out_Control( p_demux
->out
, ES_OUT_VOUT_ADD_OVERLAY
,
1873 p_sys
->p_video_es
, p_pic
, &p_ov
->i_channel
);
1874 if (ret
!= VLC_SUCCESS
)
1876 unref_subpicture_updater(p_ov
->p_updater
);
1877 p_ov
->p_updater
= NULL
;
1878 subpicture_Delete(p_pic
);
1883 * Mark the picture as Outdated, as it contains no region for now.
1884 * This will make the subpicture_updater_t call pf_update
1886 p_ov
->status
= Outdated
;
1889 static void blurayUpdateTitleInfo(input_title_t
*t
, BLURAY_TITLE_INFO
*title_info
)
1891 t
->i_length
= FROM_SCALE_NZ(title_info
->duration
);
1893 for (int i
= 0; i
< t
->i_seekpoint
; i
++)
1894 vlc_seekpoint_Delete( t
->seekpoint
[i
] );
1895 TAB_CLEAN(t
->i_seekpoint
, t
->seekpoint
);
1897 for (unsigned int j
= 0; j
< title_info
->chapter_count
; j
++) {
1898 seekpoint_t
*s
= vlc_seekpoint_New();
1902 s
->i_time_offset
= FROM_SCALE_NZ(title_info
->chapters
[j
].start
);
1904 TAB_APPEND(t
->i_seekpoint
, t
->seekpoint
, s
);
1908 static void blurayInitTitles(demux_t
*p_demux
, uint32_t menu_titles
)
1910 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1911 const BLURAY_DISC_INFO
*di
= bd_get_disc_info(p_sys
->bluray
);
1913 /* get and set the titles */
1914 uint32_t i_title
= menu_titles
;
1916 if (!p_sys
->b_menu
) {
1917 i_title
= bd_get_titles(p_sys
->bluray
, TITLES_RELEVANT
, 60);
1918 p_sys
->i_longest_title
= bd_get_main_title(p_sys
->bluray
);
1921 for (uint32_t i
= 0; i
< i_title
; i
++) {
1922 input_title_t
*t
= vlc_input_title_New();
1926 if (!p_sys
->b_menu
) {
1927 BLURAY_TITLE_INFO
*title_info
= bd_get_title_info(p_sys
->bluray
, i
, 0);
1928 blurayUpdateTitleInfo(t
, title_info
);
1929 bd_free_title_info(title_info
);
1931 } else if (i
== 0) {
1932 t
->psz_name
= strdup(_("Top Menu"));
1933 t
->i_flags
= INPUT_TITLE_MENU
| INPUT_TITLE_INTERACTIVE
;
1934 } else if (i
== i_title
- 1) {
1935 t
->psz_name
= strdup(_("First Play"));
1936 if (di
&& di
->first_play
&& di
->first_play
->interactive
) {
1937 t
->i_flags
= INPUT_TITLE_INTERACTIVE
;
1940 /* add possible title name from disc metadata */
1941 if (di
&& di
->titles
&& i
<= di
->num_titles
) {
1942 if (di
->titles
[i
]->name
) {
1943 t
->psz_name
= strdup(di
->titles
[i
]->name
);
1945 if (di
->titles
[i
]->interactive
) {
1946 t
->i_flags
= INPUT_TITLE_INTERACTIVE
;
1951 TAB_APPEND(p_sys
->i_title
, p_sys
->pp_title
, t
);
1955 static void blurayRestartParser(demux_t
*p_demux
, bool b_flush
)
1958 * This is a hack and will have to be removed.
1959 * The parser should be flushed, and not destroy/created each time
1960 * we are changing title.
1962 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1965 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT
);
1967 if (p_sys
->p_parser
)
1968 vlc_demux_chained_Delete(p_sys
->p_parser
);
1970 p_sys
->p_parser
= vlc_demux_chained_New(VLC_OBJECT(p_demux
), "ts", p_sys
->p_out
);
1971 if (!p_sys
->p_parser
)
1972 msg_Err(p_demux
, "Failed to create TS demuxer");
1974 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT
);
1977 /*****************************************************************************
1978 * bluraySetTitle: select new BD title
1979 *****************************************************************************/
1980 static int bluraySetTitle(demux_t
*p_demux
, int i_title
)
1982 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1984 if (p_sys
->b_menu
) {
1987 msg_Dbg(p_demux
, "Playing TopMenu Title");
1988 result
= bd_menu_call(p_sys
->bluray
, -1);
1989 } else if (i_title
>= (int)p_sys
->i_title
- 1) {
1990 msg_Dbg(p_demux
, "Playing FirstPlay Title");
1991 result
= bd_play_title(p_sys
->bluray
, BLURAY_TITLE_FIRST_PLAY
);
1993 msg_Dbg(p_demux
, "Playing Title %i", i_title
);
1994 result
= bd_play_title(p_sys
->bluray
, i_title
);
1998 msg_Err(p_demux
, "cannot play bd title '%d'", i_title
);
1999 return VLC_EGENERIC
;
2005 /* Looking for the main title, ie the longest duration */
2007 i_title
= p_sys
->i_longest_title
;
2008 else if ((unsigned)i_title
> p_sys
->i_title
)
2009 return VLC_EGENERIC
;
2011 msg_Dbg(p_demux
, "Selecting Title %i", i_title
);
2013 if (bd_select_title(p_sys
->bluray
, i_title
) == 0) {
2014 msg_Err(p_demux
, "cannot select bd title '%d'", i_title
);
2015 return VLC_EGENERIC
;
2021 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
2022 # define BLURAY_AUDIO_STREAM 0
2025 static void blurayOnUserStreamSelection(demux_sys_t
*p_sys
, int i_pid
)
2027 vlc_mutex_lock(&p_sys
->pl_info_lock
);
2029 if (p_sys
->p_clip_info
) {
2031 if ((i_pid
& 0xff00) == 0x1100) {
2033 for (int i_id
= 0; i_id
< p_sys
->p_clip_info
->audio_stream_count
; i_id
++) {
2034 if (i_pid
== p_sys
->p_clip_info
->audio_streams
[i_id
].pid
) {
2035 bd_select_stream(p_sys
->bluray
, BLURAY_AUDIO_STREAM
, i_id
+ 1, 1);
2037 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_AUDIO_LANG
,
2038 (const char *) p_sys
->p_clip_info
->audio_streams
[i_id
].lang
);
2042 } else if ((i_pid
& 0xff00) == 0x1400 || i_pid
== 0x1800) {
2044 for (int i_id
= 0; i_id
< p_sys
->p_clip_info
->pg_stream_count
; i_id
++) {
2045 if (i_pid
== p_sys
->p_clip_info
->pg_streams
[i_id
].pid
) {
2046 bd_select_stream(p_sys
->bluray
, BLURAY_PG_TEXTST_STREAM
, i_id
+ 1, 1);
2048 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_PG_LANG
,
2049 (const char *) p_sys
->p_clip_info
->pg_streams
[i_id
].lang
);
2056 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
2059 /*****************************************************************************
2060 * blurayControl: handle the controls
2061 *****************************************************************************/
2062 static int blurayControl(demux_t
*p_demux
, int query
, va_list args
)
2064 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2068 case DEMUX_CAN_SEEK
:
2069 case DEMUX_CAN_PAUSE
:
2070 case DEMUX_CAN_CONTROL_PACE
:
2071 pb_bool
= va_arg(args
, bool *);
2075 case DEMUX_GET_PTS_DELAY
:
2076 *va_arg(args
, vlc_tick_t
*) =
2077 VLC_TICK_FROM_MS(var_InheritInteger(p_demux
, "disc-caching"));
2080 case DEMUX_SET_PAUSE_STATE
:
2082 #ifdef BLURAY_RATE_NORMAL
2083 bool b_paused
= (bool)va_arg(args
, int);
2084 if (bd_set_rate(p_sys
->bluray
, BLURAY_RATE_NORMAL
* (!b_paused
)) < 0) {
2085 return VLC_EGENERIC
;
2092 int i_id
= va_arg(args
, int);
2093 blurayOnUserStreamSelection(p_sys
, i_id
);
2096 case DEMUX_SET_TITLE
:
2098 int i_title
= va_arg(args
, int);
2099 if (bluraySetTitle(p_demux
, i_title
) != VLC_SUCCESS
) {
2100 /* make sure GUI restores the old setting in title menu ... */
2101 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2102 return VLC_EGENERIC
;
2104 blurayRestartParser(p_demux
, true);
2105 notifyDiscontinuityToParser(p_sys
);
2106 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
);
2109 case DEMUX_SET_SEEKPOINT
:
2111 int i_chapter
= va_arg(args
, int);
2112 bd_seek_chapter(p_sys
->bluray
, i_chapter
);
2113 blurayRestartParser(p_demux
, true);
2114 notifyDiscontinuityToParser(p_sys
);
2115 p_sys
->updates
|= INPUT_UPDATE_SEEKPOINT
;
2118 case DEMUX_TEST_AND_CLEAR_FLAGS
:
2120 unsigned *restrict flags
= va_arg(args
, unsigned *);
2121 *flags
&= p_sys
->updates
;
2122 p_sys
->updates
&= ~*flags
;
2125 case DEMUX_GET_TITLE
:
2126 *va_arg(args
, int *) = p_sys
->cur_title
;
2129 case DEMUX_GET_SEEKPOINT
:
2130 *va_arg(args
, int *) = p_sys
->cur_seekpoint
;
2133 case DEMUX_GET_TITLE_INFO
:
2135 input_title_t
***ppp_title
= va_arg(args
, input_title_t
***);
2136 int *pi_int
= va_arg(args
, int *);
2137 int *pi_title_offset
= va_arg(args
, int *);
2138 int *pi_chapter_offset
= va_arg(args
, int *);
2141 *pi_title_offset
= 0;
2142 *pi_chapter_offset
= 0;
2144 /* Duplicate local title infos */
2146 *ppp_title
= vlc_alloc(p_sys
->i_title
, sizeof(input_title_t
*));
2148 return VLC_EGENERIC
;
2149 for (unsigned int i
= 0; i
< p_sys
->i_title
; i
++)
2151 input_title_t
*p_dup
= vlc_input_title_Duplicate(p_sys
->pp_title
[i
]);
2153 (*ppp_title
)[(*pi_int
)++] = p_dup
;
2159 case DEMUX_GET_LENGTH
:
2161 if(p_sys
->cur_title
< p_sys
->i_title
&&
2162 (CURRENT_TITLE
->i_flags
& INPUT_TITLE_INTERACTIVE
))
2163 return VLC_EGENERIC
;
2164 *va_arg(args
, vlc_tick_t
*) = p_sys
->cur_title
< p_sys
->i_title
? CUR_LENGTH
: 0;
2167 case DEMUX_SET_TIME
:
2169 bd_seek_time(p_sys
->bluray
, TO_SCALE_NZ(va_arg(args
, vlc_tick_t
)));
2170 blurayRestartParser(p_demux
, true);
2171 notifyDiscontinuityToParser(p_sys
);
2172 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
);
2175 case DEMUX_GET_TIME
:
2177 vlc_tick_t
*pi_time
= va_arg(args
, vlc_tick_t
*);
2178 if(p_sys
->cur_title
< p_sys
->i_title
&&
2179 (CURRENT_TITLE
->i_flags
& INPUT_TITLE_INTERACTIVE
))
2180 return VLC_EGENERIC
;
2181 *pi_time
= FROM_SCALE_NZ(bd_tell_time(p_sys
->bluray
));
2185 case DEMUX_GET_POSITION
:
2187 double *pf_position
= va_arg(args
, double *);
2188 if(p_sys
->cur_title
< p_sys
->i_title
&&
2189 (CURRENT_TITLE
->i_flags
& INPUT_TITLE_INTERACTIVE
))
2190 return VLC_EGENERIC
;
2191 *pf_position
= p_sys
->cur_title
< p_sys
->i_title
&& CUR_LENGTH
> 0 ?
2192 (double)FROM_SCALE_NZ(bd_tell_time(p_sys
->bluray
))/CUR_LENGTH
: 0.0;
2195 case DEMUX_SET_POSITION
:
2197 double f_position
= va_arg(args
, double);
2198 bd_seek_time(p_sys
->bluray
, TO_SCALE_NZ(f_position
*CUR_LENGTH
));
2199 blurayRestartParser(p_demux
, true);
2200 notifyDiscontinuityToParser(p_sys
);
2201 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
);
2205 case DEMUX_GET_META
:
2207 vlc_meta_t
*p_meta
= va_arg(args
, vlc_meta_t
*);
2208 const META_DL
*meta
= p_sys
->p_meta
;
2210 return VLC_EGENERIC
;
2212 if (!EMPTY_STR(meta
->di_name
)) vlc_meta_SetTitle(p_meta
, meta
->di_name
);
2214 if (!EMPTY_STR(meta
->language_code
)) vlc_meta_AddExtra(p_meta
, "Language", meta
->language_code
);
2215 if (!EMPTY_STR(meta
->filename
)) vlc_meta_AddExtra(p_meta
, "Filename", meta
->filename
);
2216 if (!EMPTY_STR(meta
->di_alternative
)) vlc_meta_AddExtra(p_meta
, "Alternative", meta
->di_alternative
);
2218 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
2219 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
2221 if (p_sys
->i_cover_idx
>= 0 && p_sys
->i_cover_idx
< p_sys
->i_attachments
) {
2223 snprintf( psz_url
, sizeof(psz_url
), "attachment://%s",
2224 p_sys
->attachments
[p_sys
->i_cover_idx
]->psz_name
);
2225 vlc_meta_Set( p_meta
, vlc_meta_ArtworkURL
, psz_url
);
2227 else if (meta
->thumb_count
> 0 && meta
->thumbnails
&& p_sys
->psz_bd_path
) {
2228 char *psz_thumbpath
;
2229 if (asprintf(&psz_thumbpath
, "%s" DIR_SEP
"BDMV" DIR_SEP
"META" DIR_SEP
"DL" DIR_SEP
"%s",
2230 p_sys
->psz_bd_path
, meta
->thumbnails
[0].path
) > -1) {
2231 char *psz_thumburl
= vlc_path2uri(psz_thumbpath
, "file");
2232 free(psz_thumbpath
);
2233 if (unlikely(psz_thumburl
== NULL
))
2236 vlc_meta_SetArtURL(p_meta
, psz_thumburl
);
2244 case DEMUX_GET_ATTACHMENTS
:
2246 input_attachment_t
***ppp_attach
=
2247 va_arg(args
, input_attachment_t
***);
2248 int *pi_int
= va_arg(args
, int *);
2250 if (p_sys
->i_attachments
<= 0)
2251 return VLC_EGENERIC
;
2254 *ppp_attach
= vlc_alloc(p_sys
->i_attachments
, sizeof(input_attachment_t
*));
2256 return VLC_EGENERIC
;
2257 for (int i
= 0; i
< p_sys
->i_attachments
; i
++)
2259 input_attachment_t
*p_dup
= vlc_input_attachment_Duplicate(p_sys
->attachments
[i
]);
2261 (*ppp_attach
)[(*pi_int
)++] = p_dup
;
2266 case DEMUX_NAV_ACTIVATE
:
2267 if (p_sys
->b_popup_available
&& !p_sys
->b_menu_open
) {
2268 return sendKeyEvent(p_sys
, BD_VK_POPUP
);
2270 return sendKeyEvent(p_sys
, BD_VK_ENTER
);
2272 return sendKeyEvent(p_sys
, BD_VK_UP
);
2273 case DEMUX_NAV_DOWN
:
2274 return sendKeyEvent(p_sys
, BD_VK_DOWN
);
2275 case DEMUX_NAV_LEFT
:
2276 return sendKeyEvent(p_sys
, BD_VK_LEFT
);
2277 case DEMUX_NAV_RIGHT
:
2278 return sendKeyEvent(p_sys
, BD_VK_RIGHT
);
2279 case DEMUX_NAV_POPUP
:
2280 return sendKeyEvent(p_sys
, BD_VK_POPUP
);
2281 case DEMUX_NAV_MENU
:
2282 if (p_sys
->b_menu
) {
2283 if (bd_menu_call(p_sys
->bluray
, -1) == 1) {
2284 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2287 msg_Err(p_demux
, "Can't select Top Menu title");
2288 return sendKeyEvent(p_sys
, BD_VK_POPUP
);
2290 return VLC_EGENERIC
;
2292 case DEMUX_CAN_RECORD
:
2294 case DEMUX_SET_GROUP_DEFAULT
:
2295 case DEMUX_SET_GROUP_ALL
:
2296 case DEMUX_SET_GROUP_LIST
:
2297 case DEMUX_HAS_UNSUPPORTED_META
:
2299 return VLC_EGENERIC
;
2304 /*****************************************************************************
2305 * libbluray event handling
2306 *****************************************************************************/
2307 static void writeTsPacketWDiscontinuity( uint8_t *p_buf
, uint16_t i_pid
,
2308 const uint8_t *p_payload
, uint8_t i_payload
)
2310 uint8_t ts_header
[] = {
2311 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2313 0x40 | ((i_pid
& 0x1f00) >> 8), i_pid
& 0xFF, /* PUSI + PID */
2314 i_payload
? 0x30 : 0x20, /* adaptation field, payload / no payload */
2315 192 - (4 + 5) - i_payload
, /* adaptation field length */
2316 0x82, /* af: discontinuity indicator + priv data */
2317 0x0E, /* priv data size */
2319 'D', 'I', 'S', 'C', 'O', 'N', 'T', 'I', 'N', 'U',
2322 memcpy( p_buf
, ts_header
, sizeof(ts_header
) );
2323 memset( &p_buf
[sizeof(ts_header
)], 0xFF, 192 - sizeof(ts_header
) - i_payload
);
2325 memcpy( &p_buf
[192 - i_payload
], p_payload
, i_payload
);
2328 static void notifyStreamsDiscontinuity( vlc_demux_chained_t
*p_parser
,
2329 const BLURAY_STREAM_INFO
*p_sinfo
, size_t i_sinfo
)
2331 for( size_t i
=0; i
< i_sinfo
; i
++ )
2333 const uint16_t i_pid
= p_sinfo
[i
].pid
;
2335 block_t
*p_block
= block_Alloc(192);
2339 writeTsPacketWDiscontinuity( p_block
->p_buffer
, i_pid
, NULL
, 0 );
2341 vlc_demux_chained_Send(p_parser
, p_block
);
2345 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2346 p_clip->memb##_stream_count )
2348 static void notifyDiscontinuityToParser( demux_sys_t
*p_sys
)
2350 const BLURAY_CLIP_INFO
*p_clip
= p_sys
->p_clip_info
;
2357 DONOTIFY(sec_audio
);
2358 DONOTIFY(sec_video
);
2364 static void streamFlush( demux_sys_t
*p_sys
)
2367 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2368 * Packet is flushed only when TS packet with PUSI flag set is received.
2370 * Fix this by emitting (video) ts packet with PUSI flag set.
2371 * Add video sequence end code to payload so that also video decoder is flushed.
2372 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2375 if (p_sys
->b_flushed
)
2378 block_t
*p_block
= block_Alloc(192);
2382 bd_stream_type_e i_coding_type
;
2384 /* set correct sequence end code */
2385 vlc_mutex_lock(&p_sys
->pl_info_lock
);
2386 if (p_sys
->p_clip_info
!= NULL
)
2387 i_coding_type
= p_sys
->p_clip_info
->video_streams
[0].coding_type
;
2390 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
2393 switch( i_coding_type
)
2395 case BLURAY_STREAM_TYPE_VIDEO_MPEG1
:
2396 case BLURAY_STREAM_TYPE_VIDEO_MPEG2
:
2398 i_eos
= 0xB7; /* MPEG2 sequence end */
2400 case BLURAY_STREAM_TYPE_VIDEO_VC1
:
2401 case BLURAY_STREAM_TYPE_VIDEO_H264
:
2402 i_eos
= 0x0A; /* VC1 / H.264 sequence end */
2404 case BD_STREAM_TYPE_VIDEO_HEVC
:
2405 i_eos
= 0x48; /* HEVC sequence end NALU */
2409 uint8_t seq_end_pes
[] = {
2410 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2411 0x00, 0x00, 0x01, i_eos
, /* PES payload: sequence end */
2412 0x00, /* 2nd byte for HEVC NAL, pads others */
2415 writeTsPacketWDiscontinuity( p_block
->p_buffer
, 0x1011, seq_end_pes
, sizeof(seq_end_pes
) );
2417 vlc_demux_chained_Send(p_sys
->p_parser
, p_block
);
2418 p_sys
->b_flushed
= true;
2421 static void blurayResetStillImage( demux_t
*p_demux
)
2423 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2425 if (p_sys
->i_still_end_time
!= STILL_IMAGE_NOT_SET
) {
2426 p_sys
->i_still_end_time
= STILL_IMAGE_NOT_SET
;
2428 blurayRestartParser(p_demux
, false);
2429 es_out_Control( p_demux
->out
, ES_OUT_RESET_PCR
);
2433 static void blurayStillImage( demux_t
*p_demux
, unsigned i_timeout
)
2435 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2437 /* time period elapsed ? */
2438 if (p_sys
->i_still_end_time
!= STILL_IMAGE_NOT_SET
&&
2439 p_sys
->i_still_end_time
!= STILL_IMAGE_INFINITE
&&
2440 p_sys
->i_still_end_time
<= vlc_tick_now()) {
2441 msg_Dbg(p_demux
, "Still image end");
2442 bd_read_skip_still(p_sys
->bluray
);
2444 blurayResetStillImage(p_demux
);
2448 /* show last frame as still image */
2449 if (p_sys
->i_still_end_time
== STILL_IMAGE_NOT_SET
) {
2451 msg_Dbg(p_demux
, "Still image (%d seconds)", i_timeout
);
2452 p_sys
->i_still_end_time
= vlc_tick_now() + vlc_tick_from_sec( i_timeout
);
2454 msg_Dbg(p_demux
, "Still image (infinite)");
2455 p_sys
->i_still_end_time
= STILL_IMAGE_INFINITE
;
2458 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2461 /* stop buffering */
2463 es_out_Control( p_demux
->out
, ES_OUT_GET_EMPTY
, &b_empty
);
2466 /* avoid busy loops (read returns no data) */
2467 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2470 static void blurayOnStreamSelectedEvent(demux_t
*p_demux
, uint32_t i_type
, uint32_t i_id
)
2472 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2475 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2478 if (i_type
== BD_EVENT_AUDIO_STREAM
) {
2479 i_pid
= blurayGetStreamPID(p_sys
, i_type
, i_id
);
2480 } else if (i_type
== BD_EVENT_PG_TEXTST_STREAM
) {
2481 i_pid
= blurayGetStreamPID(p_sys
, i_type
, i_id
);
2486 if (i_type
== BD_EVENT_PG_TEXTST_STREAM
&& !p_sys
->b_spu_enable
)
2487 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID
, (int)i_type
, i_pid
);
2489 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID
, (int)i_type
, i_pid
);
2493 static void blurayUpdatePlaylist(demux_t
*p_demux
, unsigned i_playlist
)
2495 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2497 blurayRestartParser(p_demux
, true);
2499 /* read title info and init some values */
2501 p_sys
->cur_title
= bd_get_current_title(p_sys
->bluray
);
2502 p_sys
->cur_seekpoint
= 0;
2503 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2505 BLURAY_TITLE_INFO
*p_title_info
= bd_get_playlist_info(p_sys
->bluray
, i_playlist
, 0);
2507 blurayUpdateTitleInfo(p_sys
->pp_title
[p_sys
->cur_title
], p_title_info
);
2509 p_sys
->updates
|= INPUT_UPDATE_TITLE_LIST
;
2511 setTitleInfo(p_sys
, p_title_info
);
2513 blurayResetStillImage(p_demux
);
2516 static void blurayUpdateCurrentClip(demux_t
*p_demux
, uint32_t clip
)
2518 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2520 vlc_mutex_lock(&p_sys
->pl_info_lock
);
2522 p_sys
->p_clip_info
= NULL
;
2524 if (p_sys
->p_pl_info
&& clip
< p_sys
->p_pl_info
->clip_count
) {
2526 p_sys
->p_clip_info
= &p_sys
->p_pl_info
->clips
[clip
];
2528 /* Let's assume a single video track for now.
2529 * This may brake later, but it's enough for now.
2531 assert(p_sys
->p_clip_info
->video_stream_count
>= 1);
2534 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
2536 blurayResetStillImage(p_demux
);
2539 static void blurayHandleEvent(demux_t
*p_demux
, const BD_EVENT
*e
)
2541 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2544 case BD_EVENT_TITLE
:
2545 if (e
->param
== BLURAY_TITLE_FIRST_PLAY
)
2546 p_sys
->cur_title
= p_sys
->i_title
- 1;
2548 p_sys
->cur_title
= e
->param
;
2549 /* this is feature title, we don't know yet which playlist it will play (if any) */
2550 setTitleInfo(p_sys
, NULL
);
2551 /* reset title infos here ? */
2552 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2553 /* might be BD-J title with no video */
2555 case BD_EVENT_PLAYLIST
:
2556 /* Start of playlist playback (?????.mpls) */
2557 blurayUpdatePlaylist(p_demux
, e
->param
);
2558 if (p_sys
->b_pl_playing
) {
2559 /* previous playlist was stopped in middle. flush to avoid delay */
2560 msg_Info(p_demux
, "Stopping playlist playback");
2561 blurayRestartParser(p_demux
, false);
2562 es_out_Control( p_demux
->out
, ES_OUT_RESET_PCR
);
2564 p_sys
->b_pl_playing
= true;
2566 case BD_EVENT_PLAYITEM
:
2567 blurayUpdateCurrentClip(p_demux
, e
->param
);
2569 case BD_EVENT_CHAPTER
:
2570 if (e
->param
&& e
->param
< 0xffff)
2571 p_sys
->cur_seekpoint
= e
->param
- 1;
2573 p_sys
->cur_seekpoint
= 0;
2574 p_sys
->updates
|= INPUT_UPDATE_SEEKPOINT
;
2576 case BD_EVENT_PLAYMARK
:
2577 case BD_EVENT_ANGLE
:
2579 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2580 case BD_EVENT_UO_MASK_CHANGED
:
2581 /* This event could be used to grey out unselectable items in title menu */
2585 p_sys
->b_menu_open
= e
->param
;
2587 case BD_EVENT_POPUP
:
2588 p_sys
->b_popup_available
= e
->param
;
2589 /* TODO: show / hide pop-up menu button in gui ? */
2595 case BD_EVENT_ERROR
:
2596 /* fatal error (with menus) */
2597 vlc_dialog_display_error(p_demux
, _("Blu-ray error"),
2598 "Playback with BluRay menus failed");
2599 p_sys
->b_fatal_error
= true;
2601 case BD_EVENT_ENCRYPTED
:
2602 vlc_dialog_display_error(p_demux
, _("Blu-ray error"),
2603 "This disc seems to be encrypted");
2604 p_sys
->b_fatal_error
= true;
2606 case BD_EVENT_READ_ERROR
:
2607 msg_Err(p_demux
, "bluray: read error\n");
2611 * stream selection events
2613 case BD_EVENT_PG_TEXTST
:
2614 p_sys
->b_spu_enable
= e
->param
;
2616 case BD_EVENT_AUDIO_STREAM
:
2617 case BD_EVENT_PG_TEXTST_STREAM
:
2618 blurayOnStreamSelectedEvent(p_demux
, e
->event
, e
->param
);
2620 case BD_EVENT_IG_STREAM
:
2621 case BD_EVENT_SECONDARY_AUDIO
:
2622 case BD_EVENT_SECONDARY_AUDIO_STREAM
:
2623 case BD_EVENT_SECONDARY_VIDEO
:
2624 case BD_EVENT_SECONDARY_VIDEO_STREAM
:
2625 case BD_EVENT_SECONDARY_VIDEO_SIZE
:
2629 * playback control events
2631 case BD_EVENT_STILL_TIME
:
2632 blurayStillImage(p_demux
, e
->param
);
2634 case BD_EVENT_DISCONTINUITY
:
2635 /* reset demuxer (partially decoded PES packets must be dropped) */
2636 blurayRestartParser(p_demux
, false);
2637 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
);
2639 case BD_EVENT_END_OF_TITLE
:
2640 p_sys
->b_pl_playing
= false;
2643 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2644 /* avoid busy loop (bd_read() returns no data) */
2645 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2649 msg_Warn(p_demux
, "event: %d param: %d", e
->event
, e
->param
);
2654 static bool blurayIsBdjTitle(demux_t
*p_demux
)
2656 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2657 unsigned int i_title
= p_sys
->cur_title
;
2658 const BLURAY_DISC_INFO
*di
= bd_get_disc_info(p_sys
->bluray
);
2660 if (di
&& di
->titles
) {
2661 if ((i_title
<= di
->num_titles
&& di
->titles
[i_title
] && di
->titles
[i_title
]->bdj
) ||
2662 (i_title
== p_sys
->i_title
- 1 && di
->first_play
&& di
->first_play
->bdj
)) {
2670 static void blurayHandleOverlays(demux_t
*p_demux
, int nread
)
2672 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2674 vlc_mutex_lock(&p_sys
->bdj_overlay_lock
);
2676 for (int i
= 0; i
< MAX_OVERLAY
; i
++) {
2677 bluray_overlay_t
*ov
= p_sys
->p_overlays
[i
];
2681 vlc_mutex_lock(&ov
->lock
);
2682 bool display
= ov
->status
== ToDisplay
;
2683 vlc_mutex_unlock(&ov
->lock
);
2685 /* NOTE: we might want to enable background video always when there's no video stream playing.
2686 Now, with some discs, there are perioids (even seconds) during which the video window
2687 disappears and just playlist is shown.
2688 (sometimes BD-J runs slowly ...)
2690 if (!p_sys
->p_video_es
&& p_sys
->b_menu
&&
2691 !p_sys
->p_pl_info
&& nread
== 0 &&
2692 blurayIsBdjTitle(p_demux
)) {
2694 /* Looks like there's no video stream playing.
2695 Emit blank frame so that BD-J overlay can be drawn. */
2696 p_sys
->p_video_es
= blurayCreateBackgroundUnlocked(p_demux
);
2699 if (p_sys
->p_video_es
!= NULL
) {
2700 bluraySendOverlayToVout(p_demux
, ov
);
2705 vlc_mutex_unlock(&p_sys
->bdj_overlay_lock
);
2708 #define BD_TS_PACKET_SIZE (192)
2709 #define NB_TS_PACKETS (200)
2710 #define BD_READ_SIZE (NB_TS_PACKETS * BD_TS_PACKET_SIZE)
2712 static int blurayDemux(demux_t
*p_demux
)
2714 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2717 block_t
*p_block
= block_Alloc(BD_READ_SIZE
);
2719 return VLC_DEMUXER_EGENERIC
;
2723 if (p_sys
->b_menu
== false) {
2724 nread
= bd_read(p_sys
->bluray
, p_block
->p_buffer
, BD_READ_SIZE
);
2725 while (bd_get_event(p_sys
->bluray
, &e
))
2726 blurayHandleEvent(p_demux
, &e
);
2728 nread
= bd_read_ext(p_sys
->bluray
, p_block
->p_buffer
, BD_READ_SIZE
, &e
);
2729 while (e
.event
!= BD_EVENT_NONE
) {
2730 blurayHandleEvent(p_demux
, &e
);
2731 bd_get_event(p_sys
->bluray
, &e
);
2735 blurayHandleOverlays(p_demux
, nread
);
2738 block_Release(p_block
);
2739 if (p_sys
->b_fatal_error
|| nread
< 0) {
2740 msg_Err(p_demux
, "bluray: stopping playback after fatal error\n");
2741 return VLC_DEMUXER_EGENERIC
;
2743 if (!p_sys
->b_menu
) {
2744 return VLC_DEMUXER_EOF
;
2746 return VLC_DEMUXER_SUCCESS
;
2749 p_block
->i_buffer
= nread
;
2751 stopBackground(p_demux
);
2753 vlc_demux_chained_Send(p_sys
->p_parser
, p_block
);
2755 p_sys
->b_flushed
= false;
2757 return VLC_DEMUXER_SUCCESS
;