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"
55 #include "../demux/timestamps_filter.h"
57 /* FIXME we should find a better way than including that */
58 #include "../../src/text/iso-639_def.h"
61 #include <libbluray/bluray.h>
62 #include <libbluray/bluray-version.h>
63 #include <libbluray/keys.h>
64 #include <libbluray/meta_data.h>
65 #include <libbluray/overlay.h>
66 #include <libbluray/clpi_data.h>
68 //#define DEBUG_BLURAY
69 //#define DEBUG_BLURAY_EVENTS
72 # include <libbluray/log_control.h>
73 # define BLURAY_DEBUG_MASK (0xFFFFF & ~DBG_STREAM)
74 static vlc_object_t
*p_bluray_DebugObject
;
75 static void bluray_DebugHandler(const char *psz
)
77 size_t len
= strlen(psz
);
80 if(psz
[len
- 1] == '\n')
81 psz_log
= strndup(psz
, len
- 1);
82 msg_Dbg(p_bluray_DebugObject
, "%s", psz_log
? psz_log
: psz
);
87 #ifdef DEBUG_BLURAY_EVENTS
88 # define BD_DEBUG_EVENT_ENTRY(a) [a]=#a
89 static const char * bluray_event_debug_strings
[] =
91 BD_DEBUG_EVENT_ENTRY(BD_EVENT_NONE
),
92 BD_DEBUG_EVENT_ENTRY(BD_EVENT_ERROR
),
93 BD_DEBUG_EVENT_ENTRY(BD_EVENT_READ_ERROR
),
94 BD_DEBUG_EVENT_ENTRY(BD_EVENT_ENCRYPTED
),
95 BD_DEBUG_EVENT_ENTRY(BD_EVENT_ANGLE
),
96 BD_DEBUG_EVENT_ENTRY(BD_EVENT_TITLE
),
97 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PLAYLIST
),
98 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PLAYITEM
),
99 BD_DEBUG_EVENT_ENTRY(BD_EVENT_CHAPTER
),
100 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PLAYMARK
),
101 BD_DEBUG_EVENT_ENTRY(BD_EVENT_END_OF_TITLE
),
102 BD_DEBUG_EVENT_ENTRY(BD_EVENT_AUDIO_STREAM
),
103 BD_DEBUG_EVENT_ENTRY(BD_EVENT_IG_STREAM
),
104 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PG_TEXTST_STREAM
),
105 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PIP_PG_TEXTST_STREAM
),
106 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_AUDIO_STREAM
),
107 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_VIDEO_STREAM
),
108 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PG_TEXTST
),
109 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PIP_PG_TEXTST
),
110 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_AUDIO
),
111 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_VIDEO
),
112 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_VIDEO_SIZE
),
113 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PLAYLIST_STOP
),
114 BD_DEBUG_EVENT_ENTRY(BD_EVENT_DISCONTINUITY
),
115 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SEEK
),
116 BD_DEBUG_EVENT_ENTRY(BD_EVENT_STILL
),
117 BD_DEBUG_EVENT_ENTRY(BD_EVENT_STILL_TIME
),
118 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SOUND_EFFECT
),
119 BD_DEBUG_EVENT_ENTRY(BD_EVENT_IDLE
),
120 BD_DEBUG_EVENT_ENTRY(BD_EVENT_POPUP
),
121 BD_DEBUG_EVENT_ENTRY(BD_EVENT_MENU
),
122 BD_DEBUG_EVENT_ENTRY(BD_EVENT_STEREOSCOPIC_STATUS
),
123 BD_DEBUG_EVENT_ENTRY(BD_EVENT_KEY_INTEREST_TABLE
),
124 BD_DEBUG_EVENT_ENTRY(BD_EVENT_UO_MASK_CHANGED
),
126 # define blurayDebugEvent(e, v) do {\
127 if(e < ARRAY_SIZE(bluray_event_debug_strings))\
128 msg_Dbg(p_demux, "Event %s %x", bluray_event_debug_strings[e], v);\
130 msg_Dbg(p_demux, "Event Unk 0x%x %x", e, v);\
133 # define blurayDebugEvent(e, v)
136 #ifdef BLURAY_HAS_BDJO_DATA_H
137 /* System version check menu freeze. See
138 * https://code.videolan.org/videolan/libbluray/issues/1
139 * To be removed with fix[ed,able] libbluray */
140 # include <libbluray/bdjo_data.h>
141 # include <strings.h>
142 static int BDJO_FileSelect( const char *psz_filename
)
144 int i_len
= strlen( psz_filename
);
148 return ! strcasecmp( &psz_filename
[i_len
- 5], ".bdjo" );
151 static bool BDJO_IsBlacklisted(demux_t
*p_demux
, const char *psz_bd_path
)
153 const char * rgsz_class_blacklist
[] =
155 "com.macrovision.bdplus.Handshake",
160 if(-1 == asprintf(&psz_bdjo_dir
, "%s/BDMV/BDJO", psz_bd_path
))
163 char **ppsz_filenames
= NULL
;
164 int i_files
= vlc_scandir(psz_bdjo_dir
, &ppsz_filenames
, BDJO_FileSelect
, NULL
);
171 for( int i
=0; i
<i_files
&& !b_ret
; i
++ )
174 if(-1 < asprintf(&psz_bdjo_file
, "%s/%s", psz_bdjo_dir
, ppsz_filenames
[i
]))
176 struct bdjo_data
*bdjo
= bd_read_bdjo(psz_bdjo_file
);
179 for(uint8_t j
=0; j
<bdjo
->app_table
.num_app
&& !b_ret
; j
++)
180 for(size_t k
=0; k
<ARRAY_SIZE(rgsz_class_blacklist
) && !b_ret
; k
++)
181 b_ret
= (!strcmp(rgsz_class_blacklist
[k
],
182 bdjo
->app_table
.app
[j
].initial_class
));
185 msg_Warn("Found blacklisted class %s in %s", rgsz_class_blacklist
[k
],
198 for( int i
=0; i
<i_files
; i
++ )
199 free(ppsz_filenames
[i
]);
200 free(ppsz_filenames
);
205 # define BDJO_IsBlacklisted(foo, bar) (0)
208 /*****************************************************************************
210 *****************************************************************************/
212 #define BD_MENU_TEXT N_("Blu-ray menus")
213 #define BD_MENU_LONGTEXT N_("Use Blu-ray menus. If disabled, "\
214 "the movie will start directly")
215 #define BD_REGION_TEXT N_("Region code")
216 #define BD_REGION_LONGTEXT N_("Blu-Ray player region code. "\
217 "Some discs can be played only with a correct region code.")
219 static const char *const ppsz_region_code
[] = {
221 static const char *const ppsz_region_code_text
[] = {
222 "Region A", "Region B", "Region C" };
224 #define REGION_DEFAULT 1 /* Index to region list. Actual region code is (1<<REGION_DEFAULT) */
225 #define LANGUAGE_DEFAULT ("eng")
227 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,0)
228 # define BLURAY_DEMUX
231 #ifndef BD_STREAM_TYPE_VIDEO_HEVC
232 # define BD_STREAM_TYPE_VIDEO_HEVC 0x24
235 #define BD_CLUSTER_SIZE 6144
236 #define BD_READ_SIZE (10 * BD_CLUSTER_SIZE)
239 static int blurayOpen (vlc_object_t
*);
240 static void blurayClose(vlc_object_t
*);
243 set_shortname(N_("Blu-ray"))
244 set_description(N_("Blu-ray Disc support (libbluray)"))
246 set_category(CAT_INPUT
)
247 set_subcategory(SUBCAT_INPUT_ACCESS
)
248 set_capability("access", 500)
249 add_bool("bluray-menu", true, BD_MENU_TEXT
, BD_MENU_LONGTEXT
, false)
250 add_string("bluray-region", ppsz_region_code
[REGION_DEFAULT
], BD_REGION_TEXT
, BD_REGION_LONGTEXT
, false)
251 change_string_list(ppsz_region_code
, ppsz_region_code_text
)
253 add_shortcut("bluray", "file")
255 set_callbacks(blurayOpen
, blurayClose
)
260 set_description( "BluRay demuxer" )
261 set_category( CAT_INPUT
)
262 set_subcategory( SUBCAT_INPUT_DEMUX
)
263 set_capability( "demux", 5 )
264 set_callbacks( blurayOpen
, blurayClose
)
269 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
270 #define MAX_OVERLAY 2
272 typedef enum OverlayStatus
{
274 ToDisplay
, //Used to mark the overlay to be displayed the first time.
276 Outdated
//used to update the overlay after it has been sent to the vout
279 typedef struct bluray_spu_updater_sys_t bluray_spu_updater_sys_t
;
281 typedef struct bluray_overlay_t
285 OverlayStatus status
;
286 subpicture_region_t
*p_regions
;
289 /* pointer to last subpicture updater.
290 * used to disconnect this overlay from vout when:
291 * - the overlay is closed
292 * - vout is changed and this overlay is sent to the new vout
294 bluray_spu_updater_sys_t
*p_updater
;
303 unsigned int i_title
;
304 unsigned int i_longest_title
;
305 input_title_t
**pp_title
;
307 unsigned cur_seekpoint
;
310 vlc_mutex_t pl_info_lock
;
311 BLURAY_TITLE_INFO
*p_pl_info
;
312 const BLURAY_CLIP_INFO
*p_clip_info
;
315 BD_CLIP_APP_TYPE_TS_MAIN_PATH_MOVIE
= 1,
316 BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW
= 2,
317 BD_CLIP_APP_TYPE_TS_MAIN_PATH_BROWSABLE_SLIDESHOW
= 3,
318 BD_CLIP_APP_TYPE_TS_SUB_PATH_BROWSABLE_SLIDESHOW
= 4,
319 BD_CLIP_APP_TYPE_TS_SUB_PATH_INTERACTIVE_MENU
= 5,
320 BD_CLIP_APP_TYPE_TS_SUB_PATH_TEXT_SUBTITLE
= 6,
321 BD_CLIP_APP_TYPE_TS_SUB_PATH_ELEMENTARY_STREAM_PATH
= 7,
322 } clip_application_type
;
326 input_attachment_t
**attachments
;
329 /* Meta information */
330 const META_DL
*p_meta
;
336 bool b_popup_available
;
337 vlc_tick_t i_still_end_time
;
340 bluray_overlay_t
*p_overlays
[MAX_OVERLAY
];
341 vlc_mutex_t lock
; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
345 vlc_mouse_t oldmouse
;
350 bool b_spu_enable
; /* enabled / disabled */
351 vlc_demux_chained_t
*p_parser
;
353 bool b_pl_playing
; /* true when playing playlist */
356 vlc_mutex_t read_block_lock
;
358 /* Used to store bluray disc path */
363 * Local ES index storage
369 int i_next_block_flags
;
371 bool b_restart_decoders_on_reuse
;
374 static bool es_pair_Add(vlc_array_t
*p_array
, const es_format_t
*p_fmt
,
377 es_pair_t
*p_pair
= malloc(sizeof(*p_pair
));
378 if (likely(p_pair
!= NULL
))
381 p_pair
->i_next_block_flags
= 0;
382 p_pair
->b_recyling
= false;
383 p_pair
->b_restart_decoders_on_reuse
= true;
384 if(vlc_array_append(p_array
, p_pair
) != VLC_SUCCESS
)
391 es_format_Init(&p_pair
->fmt
, p_fmt
->i_cat
, p_fmt
->i_codec
);
392 es_format_Copy(&p_pair
->fmt
, p_fmt
);
395 return p_pair
!= NULL
;
398 static void es_pair_Remove(vlc_array_t
*p_array
, es_pair_t
*p_pair
)
400 vlc_array_remove(p_array
, vlc_array_index_of_item(p_array
, p_pair
));
401 es_format_Clean(&p_pair
->fmt
);
405 static es_pair_t
*getEsPair(vlc_array_t
*p_array
,
406 bool (*match
)(const es_pair_t
*, const void *),
409 for (size_t i
= 0; i
< vlc_array_count(p_array
); ++i
)
411 es_pair_t
*p_pair
= vlc_array_item_at_index(p_array
, i
);
412 if(match(p_pair
, param
))
418 static bool es_pair_compare_PID(const es_pair_t
*p_pair
, const void *p_pid
)
420 return p_pair
->fmt
.i_id
== *((const int *)p_pid
);
423 static bool es_pair_compare_ES(const es_pair_t
*p_pair
, const void *p_es
)
425 return p_pair
->p_es
== (const es_out_id_t
*)p_es
;
428 static bool es_pair_compare_Unused(const es_pair_t
*p_pair
, const void *priv
)
431 return p_pair
->b_recyling
;
434 static es_pair_t
*getEsPairByPID(vlc_array_t
*p_array
, int i_pid
)
436 return getEsPair(p_array
, es_pair_compare_PID
, &i_pid
);
439 static es_pair_t
*getEsPairByES(vlc_array_t
*p_array
, const es_out_id_t
*p_es
)
441 return getEsPair(p_array
, es_pair_compare_ES
, p_es
);
444 static es_pair_t
*getUnusedEsPair(vlc_array_t
*p_array
)
446 return getEsPair(p_array
, es_pair_compare_Unused
, 0);
452 struct bluray_spu_updater_sys_t
454 vlc_mutex_t lock
; // protect p_overlay pointer and ref_cnt
455 bluray_overlay_t
*p_overlay
; // NULL if overlay has been closed
456 int ref_cnt
; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
460 * cut the connection between vout and overlay.
461 * - called when vout is closed or overlay is closed.
462 * - frees bluray_spu_updater_sys_t when both sides have been closed.
464 static void unref_subpicture_updater(bluray_spu_updater_sys_t
*p_sys
)
466 vlc_mutex_lock(&p_sys
->lock
);
467 int refs
= --p_sys
->ref_cnt
;
468 p_sys
->p_overlay
= NULL
;
469 vlc_mutex_unlock(&p_sys
->lock
);
472 vlc_mutex_destroy(&p_sys
->lock
);
478 * FIXME: partiallyy duplicated from src/input/es_out.c
480 static const char *DemuxGetLanguageCode( demux_t
*p_demux
, const char *psz_var
)
482 const iso639_lang_t
*pl
;
486 psz_lang
= var_CreateGetString( p_demux
, psz_var
);
488 return LANGUAGE_DEFAULT
;
490 /* XXX: we will use only the first value
491 * (and ignore other ones in case of a list) */
492 if( ( p
= strchr( psz_lang
, ',' ) ) )
495 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
497 if( *psz_lang
== '\0' )
499 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
500 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
501 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
502 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
508 if( pl
->psz_eng_name
!= NULL
)
509 return pl
->psz_iso639_2T
;
511 return LANGUAGE_DEFAULT
;
514 /*****************************************************************************
516 *****************************************************************************/
517 static es_out_t
*esOutNew(vlc_object_t
*, es_out_t
*, void *);
519 static int blurayControl(demux_t
*, int, va_list);
520 static int blurayDemux(demux_t
*);
522 static void blurayInitTitles(demux_t
*p_demux
, uint32_t menu_titles
);
523 static int bluraySetTitle(demux_t
*p_demux
, int i_title
);
525 static void blurayOverlayProc(void *ptr
, const BD_OVERLAY
* const overlay
);
526 static void blurayArgbOverlayProc(void *ptr
, const BD_ARGB_OVERLAY
* const overlay
);
527 static void blurayCloseOverlay(demux_t
*p_demux
, int plane
);
529 static void onMouseEvent(const vlc_mouse_t
*mouse
, void *user_data
);
530 static void blurayRestartParser(demux_t
*p_demux
, bool, bool);
531 static void notifyDiscontinuityToParser( demux_sys_t
*p_sys
);
533 #define STILL_IMAGE_NOT_SET 0
534 #define STILL_IMAGE_INFINITE -1
536 #define CURRENT_TITLE p_sys->pp_title[p_sys->cur_title]
537 #define CUR_LENGTH CURRENT_TITLE->i_length
540 static void FindMountPoint(char **file
)
542 char *device
= *file
;
543 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
544 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
545 * we look up the real device */
546 char *bd_device
= realpath(device
, NULL
);
547 if (bd_device
== NULL
)
551 if (lstat (bd_device
, &st
) == 0 && S_ISBLK (st
.st_mode
)) {
552 FILE *mtab
= setmntent ("/proc/self/mounts", "r");
554 struct mntent
*m
, mbuf
;
557 while ((m
= getmntent_r (mtab
, &mbuf
, buf
, sizeof(buf
))) != NULL
) {
558 if (!strcmp (m
->mnt_fsname
, bd_device
)) {
560 *file
= strdup(m
->mnt_dir
);
569 #elif defined(__APPLE__)
571 if (!stat (device
, &st
) && S_ISBLK (st
.st_mode
)) {
572 int fs_count
= getfsstat (NULL
, 0, MNT_NOWAIT
);
574 struct statfs mbuf
[128];
575 getfsstat (mbuf
, fs_count
* sizeof(mbuf
[0]), MNT_NOWAIT
);
576 for (int i
= 0; i
< fs_count
; ++i
)
577 if (!strcmp (mbuf
[i
].f_mntfromname
, device
)) {
579 *file
= strdup(mbuf
[i
].f_mntonname
);
585 # warning Disc device to mount point not implemented
586 VLC_UNUSED( device
);
590 /*****************************************************************************
591 * BD-J background video
592 *****************************************************************************/
594 static void bluraySendBackgroundImage(vlc_object_t
*p_obj
,
597 const es_format_t
*p_fmt
)
599 msg_Info(p_obj
, "Start background");
601 block_t
*p_block
= block_Alloc(p_fmt
->video
.i_width
* p_fmt
->video
.i_height
*
602 p_fmt
->video
.i_bits_per_pixel
/ 8);
604 msg_Err(p_obj
, "Error allocating block for background video");
608 // XXX TODO: what would be correct timestamp ???
609 p_block
->i_dts
= p_block
->i_pts
= vlc_tick_now() + VLC_TICK_FROM_MS(40);
611 uint8_t *p
= p_block
->p_buffer
;
612 memset(p
, 0, p_fmt
->video
.i_width
* p_fmt
->video
.i_height
);
613 p
+= p_fmt
->video
.i_width
* p_fmt
->video
.i_height
;
614 memset(p
, 0x80, p_fmt
->video
.i_width
* p_fmt
->video
.i_height
/ 2);
616 es_out_SetPCR(p_dst_out
, p_block
->i_dts
- VLC_TICK_FROM_MS(40));
617 es_out_Control(p_dst_out
, ES_OUT_SET_ES
, p_es
);
618 es_out_Send(p_dst_out
, p_es
, p_block
);
619 es_out_Control( p_dst_out
, ES_OUT_VOUT_SET_MOUSE_EVENT
, p_es
, onMouseEvent
, p_obj
);
620 es_out_SetPCR(p_dst_out
, p_block
->i_dts
);
623 /*****************************************************************************
624 * cache current playlist (title) information
625 *****************************************************************************/
627 static void setTitleInfo(demux_sys_t
*p_sys
, BLURAY_TITLE_INFO
*info
)
629 vlc_mutex_lock(&p_sys
->pl_info_lock
);
631 if (p_sys
->p_pl_info
) {
632 bd_free_title_info(p_sys
->p_pl_info
);
634 p_sys
->p_pl_info
= info
;
635 p_sys
->p_clip_info
= NULL
;
637 if (p_sys
->p_pl_info
&& p_sys
->p_pl_info
->clip_count
) {
638 p_sys
->p_clip_info
= &p_sys
->p_pl_info
->clips
[0];
641 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
644 /*****************************************************************************
645 * create input attachment for thumbnail
646 *****************************************************************************/
648 static void attachThumbnail(demux_t
*p_demux
)
650 demux_sys_t
*p_sys
= p_demux
->p_sys
;
655 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
656 if (p_sys
->p_meta
->thumb_count
> 0 && p_sys
->p_meta
->thumbnails
) {
659 if (bd_get_meta_file(p_sys
->bluray
, p_sys
->p_meta
->thumbnails
[0].path
, &data
, &size
) > 0) {
661 input_attachment_t
*p_attachment
;
663 snprintf(psz_name
, sizeof(psz_name
), "picture%d_%s", p_sys
->i_attachments
, p_sys
->p_meta
->thumbnails
[0].path
);
665 p_attachment
= vlc_input_attachment_New(psz_name
, NULL
, "Album art", data
, size
);
667 p_sys
->i_cover_idx
= p_sys
->i_attachments
;
668 TAB_APPEND(p_sys
->i_attachments
, p_sys
->attachments
, p_attachment
);
676 /*****************************************************************************
678 *****************************************************************************/
680 static int probeStream(demux_t
*p_demux
)
682 /* input must be seekable */
683 bool b_canseek
= false;
684 vlc_stream_Control( p_demux
->s
, STREAM_CAN_SEEK
, &b_canseek
);
689 /* first sector(s) should be filled with zeros */
691 const uint8_t *p_peek
;
692 i_peek
= vlc_stream_Peek( p_demux
->s
, &p_peek
, 2048 );
693 if( i_peek
!= 2048 ) {
697 if (p_peek
[ --i_peek
]) {
706 static int blurayReadBlock(void *object
, void *buf
, int lba
, int num_blocks
)
708 demux_t
*p_demux
= (demux_t
*)object
;
709 demux_sys_t
*p_sys
= p_demux
->p_sys
;
712 assert(p_demux
->s
!= NULL
);
714 vlc_mutex_lock(&p_sys
->read_block_lock
);
716 if (vlc_stream_Seek( p_demux
->s
, lba
* INT64_C(2048) ) == VLC_SUCCESS
) {
717 size_t req
= (size_t)2048 * num_blocks
;
720 got
= vlc_stream_Read( p_demux
->s
, buf
, req
);
722 msg_Err(p_demux
, "read from lba %d failed", lba
);
727 msg_Err(p_demux
, "seek to lba %d failed", lba
);
730 vlc_mutex_unlock(&p_sys
->read_block_lock
);
736 /*****************************************************************************
737 * probing of local files
738 *****************************************************************************/
740 /* Descriptor Tag (ECMA 167, 3/7.2) */
741 static int decode_descriptor_tag(const uint8_t *buf
)
744 uint8_t checksum
= 0;
747 id
= buf
[0] | (buf
[1] << 8);
749 /* calculate tag checksum */
750 for (i
= 0; i
< 4; i
++) {
751 checksum
= (uint8_t)(checksum
+ buf
[i
]);
753 for (i
= 5; i
< 16; i
++) {
754 checksum
= (uint8_t)(checksum
+ buf
[i
]);
757 if (checksum
!= buf
[4]) {
764 static int probeFile(const char *psz_name
)
766 struct stat stat_info
;
769 int ret
= VLC_EGENERIC
;
772 fd
= vlc_open(psz_name
, O_RDONLY
| O_NONBLOCK
);
777 if (fstat(fd
, &stat_info
) == -1) {
780 if (!S_ISREG(stat_info
.st_mode
) && !S_ISBLK(stat_info
.st_mode
)) {
784 /* first sector should be filled with zeros */
785 if (read(fd
, peek
, sizeof(peek
)) != sizeof(peek
)) {
788 for (i
= 0; i
< sizeof(peek
); i
++) {
794 /* Check AVDP tag checksum */
795 if (lseek(fd
, 256 * 2048, SEEK_SET
) == -1 ||
796 read(fd
, peek
, 16) != 16 ||
797 decode_descriptor_tag(peek
) != 2) {
808 /*****************************************************************************
809 * blurayOpen: module init function
810 *****************************************************************************/
811 static int blurayOpen(vlc_object_t
*object
)
813 demux_t
*p_demux
= (demux_t
*)object
;
816 uint64_t i_init_pos
= 0;
818 const char *error_msg
= NULL
;
819 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
821 if (p_demux
->out
== NULL
)
824 forced
= !strncasecmp(p_demux
->psz_url
, "bluray:", 7);
827 if (!strncasecmp(p_demux
->psz_url
, "file:", 5)) {
828 /* use access_demux for local files */
832 if (probeStream(p_demux
) != VLC_SUCCESS
) {
836 } else if (!forced
) {
837 if (!p_demux
->psz_filepath
) {
841 if (probeFile(p_demux
->psz_filepath
) != VLC_SUCCESS
) {
847 p_demux
->p_sys
= p_sys
= vlc_obj_calloc(object
, 1, sizeof(*p_sys
));
848 if (unlikely(!p_sys
))
851 p_sys
->i_still_end_time
= STILL_IMAGE_NOT_SET
;
853 /* init demux info fields */
856 TAB_INIT(p_sys
->i_title
, p_sys
->pp_title
);
857 TAB_INIT(p_sys
->i_attachments
, p_sys
->attachments
);
859 vlc_mouse_Init(&p_sys
->oldmouse
);
861 vlc_mutex_init(&p_sys
->pl_info_lock
);
862 vlc_mutex_init(&p_sys
->bdj
.lock
);
863 vlc_mutex_init(&p_sys
->read_block_lock
); /* used during bd_open_stream() */
865 /* request sub demuxers to skip continuity check as some split
866 file concatenation are just resetting counters... */
867 var_Create( p_demux
, "ts-cc-check", VLC_VAR_BOOL
);
868 var_SetBool( p_demux
, "ts-cc-check", false );
869 var_Create( p_demux
, "ts-standard", VLC_VAR_STRING
);
870 var_SetString( p_demux
, "ts-standard", "mpeg" );
871 var_Create( p_demux
, "ts-pmtfix-waitdata", VLC_VAR_BOOL
);
872 var_SetBool( p_demux
, "ts-pmtfix-waitdata", false );
873 var_Create( p_demux
, "ts-patfix", VLC_VAR_BOOL
);
874 var_SetBool( p_demux
, "ts-patfix", false );
875 var_Create( p_demux
, "ts-pcr-offsetfix", VLC_VAR_BOOL
);
876 var_SetBool( p_demux
, "ts-pcr-offsetfix", false );
879 p_bluray_DebugObject
= VLC_OBJECT(p_demux
);
880 bd_set_debug_mask(BLURAY_DEBUG_MASK
);
881 bd_set_debug_handler(bluray_DebugHandler
);
887 i_init_pos
= vlc_stream_Tell(p_demux
->s
);
889 p_sys
->bluray
= bd_init();
890 if (!bd_open_stream(p_sys
->bluray
, p_demux
, blurayReadBlock
)) {
891 bd_close(p_sys
->bluray
);
892 p_sys
->bluray
= NULL
;
897 if (!p_demux
->psz_filepath
) {
898 /* no path provided (bluray://). use default DVD device. */
899 p_sys
->psz_bd_path
= var_InheritString(object
, "dvd");
901 /* store current bd path */
902 p_sys
->psz_bd_path
= strdup(p_demux
->psz_filepath
);
905 /* If we're passed a block device, try to convert it to the mount point. */
906 FindMountPoint(&p_sys
->psz_bd_path
);
908 p_sys
->bluray
= bd_open(p_sys
->psz_bd_path
, NULL
);
910 if (!p_sys
->bluray
) {
914 /* Warning the user about AACS/BD+ */
915 const BLURAY_DISC_INFO
*disc_info
= bd_get_disc_info(p_sys
->bluray
);
917 /* Is it a bluray? */
918 if (!disc_info
->bluray_detected
) {
920 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
925 msg_Info(p_demux
, "First play: %i, Top menu: %i\n"
926 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
927 disc_info
->first_play_supported
, disc_info
->top_menu_supported
,
928 disc_info
->num_hdmv_titles
, disc_info
->num_bdj_titles
,
929 disc_info
->num_unsupported_titles
);
932 if (disc_info
->aacs_detected
) {
933 msg_Dbg(p_demux
, "Disc is using AACS");
934 if (!disc_info
->libaacs_detected
)
935 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
936 ", and your system does not have it."));
937 if (!disc_info
->aacs_handled
) {
938 if (disc_info
->aacs_error_code
) {
939 switch (disc_info
->aacs_error_code
) {
940 case BD_AACS_CORRUPTED_DISC
:
941 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
942 case BD_AACS_NO_CONFIG
:
943 BLURAY_ERROR(_("Missing AACS configuration file!"));
945 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
946 case BD_AACS_NO_CERT
:
947 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
948 case BD_AACS_CERT_REVOKED
:
949 BLURAY_ERROR(_("AACS Host certificate revoked."));
950 case BD_AACS_MMC_FAILED
:
951 BLURAY_ERROR(_("AACS MMC failed."));
958 if (disc_info
->bdplus_detected
) {
959 msg_Dbg(p_demux
, "Disc is using BD+");
960 if (!disc_info
->libbdplus_detected
)
961 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
962 ", and your system does not have it."));
963 if (!disc_info
->bdplus_handled
)
964 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
965 "Missing configuration?"));
968 /* set player region code */
969 char *psz_region
= var_InheritString(p_demux
, "bluray-region");
970 unsigned int region
= psz_region
? (psz_region
[0] - 'A') : REGION_DEFAULT
;
972 bd_set_player_setting(p_sys
->bluray
, BLURAY_PLAYER_SETTING_REGION_CODE
, 1<<region
);
974 /* set preferred languages */
975 const char *psz_code
= DemuxGetLanguageCode( p_demux
, "audio-language" );
976 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_AUDIO_LANG
, psz_code
);
977 psz_code
= DemuxGetLanguageCode( p_demux
, "sub-language" );
978 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_PG_LANG
, psz_code
);
979 psz_code
= DemuxGetLanguageCode( p_demux
, "menu-language" );
980 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_MENU_LANG
, psz_code
);
982 /* Get disc metadata */
983 p_sys
->p_meta
= bd_get_meta(p_sys
->bluray
);
985 msg_Warn(p_demux
, "Failed to get meta info.");
987 p_sys
->i_cover_idx
= -1;
988 attachThumbnail(p_demux
);
990 p_sys
->b_menu
= var_InheritBool(p_demux
, "bluray-menu");
992 /* Check BD-J capability */
993 if (p_sys
->b_menu
&& disc_info
->bdj_detected
&& !disc_info
->bdj_handled
) {
994 msg_Err(p_demux
, "BD-J menus not supported. Playing without menus. "
995 "BD-J support: %d, JVM found: %d, JVM usable: %d",
996 disc_info
->bdj_supported
, disc_info
->libjvm_detected
, disc_info
->bdj_handled
);
997 vlc_dialog_display_error(p_demux
, _("Java required"),
998 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
999 !disc_info
->libjvm_detected
? _("Java was not found on your system.") : "");
1000 p_sys
->b_menu
= false;
1003 if(disc_info
->bdj_detected
&&p_sys
->b_menu
&&
1004 BDJO_IsBlacklisted(p_demux
, p_sys
->psz_bd_path
))
1006 p_sys
->b_menu
= vlc_dialog_wait_question( p_demux
,
1007 VLC_DIALOG_QUESTION_NORMAL
,
1008 _("Play without Menus"),
1011 _("BDJO Menu check"),
1013 _("Incompatible Java Menu detected"));
1016 /* Get titles and chapters */
1017 blurayInitTitles(p_demux
, disc_info
->num_hdmv_titles
+ disc_info
->num_bdj_titles
+ 1/*Top Menu*/ + 1/*First Play*/);
1020 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
1022 bd_get_event(p_sys
->bluray
, NULL
);
1024 /* Registering overlay event handler */
1025 bd_register_overlay_proc(p_sys
->bluray
, p_demux
, blurayOverlayProc
);
1027 if (p_sys
->b_menu
) {
1029 /* Register ARGB overlay handler for BD-J */
1030 if (disc_info
->num_bdj_titles
)
1031 bd_register_argb_overlay_proc(p_sys
->bluray
, p_demux
, blurayArgbOverlayProc
, NULL
);
1033 /* libbluray will start playback from "First-Title" title */
1034 if (bd_play(p_sys
->bluray
) == 0)
1035 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
1038 /* set start title number */
1039 if (bluraySetTitle(p_demux
, p_sys
->i_longest_title
) != VLC_SUCCESS
) {
1040 msg_Err(p_demux
, "Could not set the title %d", p_sys
->i_longest_title
);
1045 p_sys
->p_tf_out
= timestamps_filter_es_out_New(p_demux
->out
);
1046 if(unlikely(!p_sys
->p_tf_out
))
1049 p_sys
->p_out
= esOutNew(VLC_OBJECT(p_demux
), p_sys
->p_tf_out
, p_demux
);
1050 if (unlikely(p_sys
->p_out
== NULL
))
1053 p_sys
->p_parser
= vlc_demux_chained_New(VLC_OBJECT(p_demux
), "ts", p_sys
->p_out
);
1054 if (!p_sys
->p_parser
) {
1055 msg_Err(p_demux
, "Failed to create TS demuxer");
1059 p_demux
->pf_control
= blurayControl
;
1060 p_demux
->pf_demux
= blurayDemux
;
1066 vlc_dialog_display_error(p_demux
, _("Blu-ray error"), "%s", error_msg
);
1067 blurayClose(object
);
1069 if (p_demux
->s
!= NULL
) {
1070 /* restore stream position */
1071 if (vlc_stream_Seek(p_demux
->s
, i_init_pos
) != VLC_SUCCESS
) {
1072 msg_Err(p_demux
, "Failed to seek back to stream start");
1073 return VLC_ETIMEOUT
;
1077 return VLC_EGENERIC
;
1082 /*****************************************************************************
1083 * blurayClose: module destroy function
1084 *****************************************************************************/
1085 static void blurayClose(vlc_object_t
*object
)
1087 demux_t
*p_demux
= (demux_t
*)object
;
1088 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1090 setTitleInfo(p_sys
, NULL
);
1093 * Close libbluray first.
1094 * This will close all the overlays before we release p_vout
1095 * bd_close(NULL) can crash
1097 if (p_sys
->bluray
) {
1098 bd_close(p_sys
->bluray
);
1101 vlc_mutex_lock(&p_sys
->bdj
.lock
);
1102 for(int i
= 0; i
< MAX_OVERLAY
; i
++)
1103 blurayCloseOverlay(p_demux
, i
);
1104 vlc_mutex_unlock(&p_sys
->bdj
.lock
);
1106 if (p_sys
->p_parser
)
1107 vlc_demux_chained_Delete(p_sys
->p_parser
);
1109 if (p_sys
->p_out
!= NULL
)
1110 es_out_Delete(p_sys
->p_out
);
1112 timestamps_filter_es_out_Delete(p_sys
->p_tf_out
);
1115 for (unsigned int i
= 0; i
< p_sys
->i_title
; i
++)
1116 vlc_input_title_Delete(p_sys
->pp_title
[i
]);
1117 TAB_CLEAN(p_sys
->i_title
, p_sys
->pp_title
);
1119 for (int i
= 0; i
< p_sys
->i_attachments
; i
++)
1120 vlc_input_attachment_Delete(p_sys
->attachments
[i
]);
1121 TAB_CLEAN(p_sys
->i_attachments
, p_sys
->attachments
);
1123 vlc_mutex_destroy(&p_sys
->pl_info_lock
);
1124 vlc_mutex_destroy(&p_sys
->bdj
.lock
);
1125 vlc_mutex_destroy(&p_sys
->read_block_lock
);
1127 free(p_sys
->psz_bd_path
);
1130 /*****************************************************************************
1131 * Elementary streams handling
1132 *****************************************************************************/
1133 static uint8_t blurayGetStreamsUnlocked(demux_sys_t
*p_sys
,
1135 BLURAY_STREAM_INFO
**pp_streams
)
1137 if(!p_sys
->p_clip_info
)
1140 switch(i_stream_type
)
1142 case BD_EVENT_AUDIO_STREAM
:
1143 *pp_streams
= p_sys
->p_clip_info
->audio_streams
;
1144 return p_sys
->p_clip_info
->audio_stream_count
;
1145 case BD_EVENT_PG_TEXTST_STREAM
:
1146 *pp_streams
= p_sys
->p_clip_info
->pg_streams
;
1147 return p_sys
->p_clip_info
->pg_stream_count
;
1153 static BLURAY_STREAM_INFO
* blurayGetStreamInfoUnlocked(demux_sys_t
*p_sys
,
1155 uint8_t i_stream_idx
)
1157 BLURAY_STREAM_INFO
*p_streams
= NULL
;
1158 uint8_t i_streams_count
= blurayGetStreamsUnlocked(p_sys
, i_stream_type
, &p_streams
);
1159 if(i_stream_idx
< i_streams_count
)
1160 return &p_streams
[i_stream_idx
];
1165 static BLURAY_STREAM_INFO
* blurayGetStreamInfoByPIDUnlocked(demux_sys_t
*p_sys
,
1168 for(int i_type
=BD_EVENT_AUDIO_STREAM
; i_type
<=BD_EVENT_SECONDARY_VIDEO_STREAM
; i_type
++)
1170 BLURAY_STREAM_INFO
*p_streams
;
1171 uint8_t i_streams_count
= blurayGetStreamsUnlocked(p_sys
, i_type
, &p_streams
);
1172 for(uint8_t i
=0; i
<i_streams_count
; i
++)
1174 if(p_streams
[i
].pid
== i_pid
)
1175 return &p_streams
[i
];
1181 static void setStreamLang(demux_sys_t
*p_sys
, es_format_t
*p_fmt
)
1183 vlc_mutex_lock(&p_sys
->pl_info_lock
);
1185 BLURAY_STREAM_INFO
*p_stream
= blurayGetStreamInfoByPIDUnlocked(p_sys
, p_fmt
->i_id
);
1188 free(p_fmt
->psz_language
);
1189 p_fmt
->psz_language
= strndup((const char *)p_stream
->lang
, 3);
1192 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
1195 static int blurayGetStreamPID(demux_sys_t
*p_sys
, int i_stream_type
, uint8_t i_stream_idx
)
1197 vlc_mutex_lock(&p_sys
->pl_info_lock
);
1199 BLURAY_STREAM_INFO
*p_stream
= blurayGetStreamInfoUnlocked(p_sys
,
1202 int i_pid
= p_stream
? p_stream
->pid
: -1;
1204 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
1209 /*****************************************************************************
1210 * bluray fake es_out
1211 *****************************************************************************/
1214 es_out_t
*p_dst_out
;
1215 vlc_object_t
*p_obj
;
1216 vlc_array_t es
; /* es_pair_t */
1217 bool b_entered_recycling
;
1218 bool b_restart_decoders_on_reuse
;
1220 bool b_discontinuity
;
1221 bool b_disable_output
;
1226 int i_audio_pid
; /* Selected audio stream. -1 if default */
1227 int i_spu_pid
; /* Selected spu stream. -1 if default */
1231 es_out_id_t
*p_video_es
;
1232 int channels
[MAX_OVERLAY
];
1235 } bluray_esout_priv_t
;
1239 BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID
= ES_OUT_PRIVATE_START
,
1240 BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID
,
1241 BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
,
1242 BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT
,
1243 BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT
,
1244 BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY
,
1245 BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY
,
1246 BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY
,
1247 BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY
,
1248 BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS
,
1251 static es_out_id_t
*bluray_esOutAddUnlocked(bluray_esout_priv_t
*esout_priv
,
1252 const es_format_t
*p_fmt
)
1254 demux_t
*p_demux
= esout_priv
->priv
;
1255 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1257 bool b_select
= false;
1259 es_format_Copy(&fmt
, p_fmt
);
1261 switch (fmt
.i_cat
) {
1263 if(esout_priv
->b_lowdelay
)
1265 fmt
.video
.i_frame_rate
= 1; fmt
.video
.i_frame_rate_base
= 1;
1266 fmt
.b_packetized
= true;
1268 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1269 b_select
= (p_fmt
->i_id
== 0x1011);
1272 if (esout_priv
->selected
.i_audio_pid
!= -1) {
1273 if (esout_priv
->selected
.i_audio_pid
== p_fmt
->i_id
)
1275 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1277 setStreamLang(p_sys
, &fmt
);
1280 if (esout_priv
->selected
.i_spu_pid
!= -1) {
1281 if (esout_priv
->selected
.i_spu_pid
== p_fmt
->i_id
)
1282 b_select
= p_sys
->b_spu_enable
;
1283 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1285 setStreamLang(p_sys
, &fmt
);
1291 es_out_id_t
*p_es
= NULL
;
1292 if (p_fmt
->i_id
>= 0) {
1293 /* Ensure we are not overriding anything */
1294 es_pair_t
*p_pair
= getEsPairByPID(&esout_priv
->es
, p_fmt
->i_id
);
1297 msg_Info(p_demux
, "Adding ES %d select %d", p_fmt
->i_id
, b_select
);
1298 p_es
= es_out_Add(esout_priv
->p_dst_out
, &fmt
);
1299 es_pair_Add(&esout_priv
->es
, &fmt
, p_es
);
1303 msg_Info(p_demux
, "Reusing ES %d", p_fmt
->i_id
);
1304 p_pair
->b_recyling
= false;
1305 p_es
= p_pair
->p_es
;
1306 if(!es_format_IsSimilar(p_fmt
, &p_pair
->fmt
) ||
1307 p_fmt
->b_packetized
!= p_pair
->fmt
.b_packetized
||
1308 esout_priv
->b_restart_decoders_on_reuse
)
1309 es_out_Control(esout_priv
->p_dst_out
, ES_OUT_SET_ES_FMT
, p_pair
->p_es
, &fmt
);
1310 es_format_Clean(&p_pair
->fmt
);
1311 es_format_Copy(&p_pair
->fmt
, &fmt
);
1314 es_out_Control(esout_priv
->p_dst_out
, ES_OUT_SET_ES
, p_es
);
1317 if (p_es
&& fmt
.i_cat
== VIDEO_ES
&& b_select
)
1319 es_out_Control(esout_priv
->p_dst_out
, ES_OUT_VOUT_SET_MOUSE_EVENT
, p_es
,
1320 onMouseEvent
, p_demux
);
1321 esout_priv
->overlay
.p_video_es
= p_es
;
1324 es_format_Clean(&fmt
);
1329 static es_out_id_t
*bluray_esOutAdd(es_out_t
*p_out
, const es_format_t
*p_fmt
)
1331 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1333 vlc_mutex_lock(&esout_priv
->lock
);
1334 es_out_id_t
*p_es
= bluray_esOutAddUnlocked(esout_priv
, p_fmt
);
1335 vlc_mutex_unlock(&esout_priv
->lock
);
1340 static void bluray_esOutDeleteNonReusedESUnlocked(es_out_t
*p_out
)
1342 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1344 if(!esout_priv
->b_entered_recycling
)
1346 esout_priv
->b_entered_recycling
= false;
1347 esout_priv
->b_restart_decoders_on_reuse
= true;
1350 while((p_pair
= getUnusedEsPair(&esout_priv
->es
)))
1352 msg_Info(esout_priv
->p_obj
, "Trashing unused ES %d", p_pair
->fmt
.i_id
);
1354 if(esout_priv
->overlay
.p_video_es
== p_pair
->p_es
)
1355 esout_priv
->overlay
.p_video_es
= NULL
;
1357 es_out_Del(esout_priv
->p_dst_out
, p_pair
->p_es
);
1359 es_pair_Remove(&esout_priv
->es
, p_pair
);
1363 static int bluray_esOutSend(es_out_t
*p_out
, es_out_id_t
*p_es
, block_t
*p_block
)
1365 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1366 vlc_mutex_lock(&esout_priv
->lock
);
1368 bluray_esOutDeleteNonReusedESUnlocked(p_out
);
1370 if(esout_priv
->b_discontinuity
)
1371 esout_priv
->b_discontinuity
= false;
1373 es_pair_t
*p_pair
= getEsPairByES(&esout_priv
->es
, p_es
);
1374 if(p_pair
&& p_pair
->i_next_block_flags
)
1376 p_block
->i_flags
|= p_pair
->i_next_block_flags
;
1377 p_pair
->i_next_block_flags
= 0;
1379 if(esout_priv
->b_disable_output
)
1381 block_Release(p_block
);
1384 vlc_mutex_unlock(&esout_priv
->lock
);
1385 return (p_block
) ? es_out_Send(esout_priv
->p_dst_out
, p_es
, p_block
) : VLC_SUCCESS
;
1388 static void bluray_esOutDel(es_out_t
*p_out
, es_out_id_t
*p_es
)
1390 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1391 vlc_mutex_lock(&esout_priv
->lock
);
1393 if(esout_priv
->b_discontinuity
)
1394 esout_priv
->b_discontinuity
= false;
1396 es_pair_t
*p_pair
= getEsPairByES(&esout_priv
->es
, p_es
);
1399 p_pair
->b_recyling
= true;
1400 esout_priv
->b_entered_recycling
= true;
1403 vlc_mutex_unlock(&esout_priv
->lock
);
1406 static int bluray_esOutControl(es_out_t
*p_out
, int i_query
, va_list args
)
1408 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1410 vlc_mutex_lock(&esout_priv
->lock
);
1412 if(esout_priv
->b_disable_output
&&
1413 i_query
< ES_OUT_PRIVATE_START
)
1415 vlc_mutex_unlock(&esout_priv
->lock
);
1416 return VLC_EGENERIC
;
1419 if(esout_priv
->b_discontinuity
)
1420 esout_priv
->b_discontinuity
= false;
1424 case BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID
:
1425 case BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID
:
1427 bool b_select
= (i_query
== BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID
);
1428 const int i_bluray_stream_type
= va_arg(args
, int);
1429 const int i_pid
= va_arg(args
, int);
1430 switch(i_bluray_stream_type
)
1432 case BD_EVENT_AUDIO_STREAM
:
1433 esout_priv
->selected
.i_audio_pid
= i_pid
;
1435 case BD_EVENT_PG_TEXTST_STREAM
:
1436 esout_priv
->selected
.i_spu_pid
= i_pid
;
1442 es_pair_t
*p_pair
= getEsPairByPID(&esout_priv
->es
, i_pid
);
1443 if(unlikely(!p_pair
))
1445 vlc_mutex_unlock(&esout_priv
->lock
);
1446 return VLC_EGENERIC
;
1449 i_ret
= es_out_Control(esout_priv
->p_dst_out
,
1450 b_select
? ES_OUT_SET_ES
: ES_OUT_UNSET_ES
,
1454 case BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
:
1456 esout_priv
->b_discontinuity
= true;
1457 i_ret
= VLC_SUCCESS
;
1460 case BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS
:
1462 esout_priv
->b_restart_decoders_on_reuse
= !va_arg(args
, int);
1463 i_ret
= VLC_SUCCESS
;
1466 case BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT
:
1467 case BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT
:
1469 esout_priv
->b_disable_output
= (i_query
== BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT
);
1470 i_ret
= VLC_SUCCESS
;
1473 case BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY
:
1474 case BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY
:
1476 esout_priv
->b_lowdelay
= (i_query
== BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY
);
1477 i_ret
= VLC_SUCCESS
;
1480 case BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY
:
1482 int i_plane
= va_arg(args
, int);
1483 subpicture_t
*p_pic
= va_arg(args
, subpicture_t
*);
1484 if(!esout_priv
->overlay
.p_video_es
)
1487 es_format_Init(&fmt
, VIDEO_ES
, VLC_CODEC_I420
);
1488 video_format_Setup(&fmt
.video
, VLC_CODEC_I420
,
1489 1920, 1080, 1920, 1080, 1, 1);
1490 fmt
.i_priority
= ES_PRIORITY_NOT_SELECTABLE
;
1493 fmt
.video
.i_frame_rate
= 1; fmt
.video
.i_frame_rate_base
= 1;
1494 fmt
.b_packetized
= true;
1495 esout_priv
->overlay
.p_video_es
= bluray_esOutAddUnlocked(esout_priv
, &fmt
);
1496 if(esout_priv
->overlay
.p_video_es
)
1498 bluraySendBackgroundImage(esout_priv
->p_obj
,
1499 esout_priv
->p_dst_out
,
1500 esout_priv
->overlay
.p_video_es
,
1503 es_format_Clean(&fmt
);
1506 if(esout_priv
->overlay
.p_video_es
&& i_plane
< MAX_OVERLAY
)
1508 i_ret
= es_out_Control(esout_priv
->p_dst_out
, ES_OUT_VOUT_ADD_OVERLAY
,
1509 esout_priv
->overlay
.p_video_es
, p_pic
,
1510 &esout_priv
->overlay
.channels
[i_plane
]);
1514 i_ret
= VLC_EGENERIC
;
1519 case BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY
:
1521 int i_plane
= va_arg(args
, int);
1522 if(esout_priv
->overlay
.p_video_es
&&
1523 i_plane
< MAX_OVERLAY
&&
1524 esout_priv
->overlay
.channels
[i_plane
] != VOUT_SPU_CHANNEL_INVALID
)
1526 i_ret
= es_out_Control(esout_priv
->p_dst_out
, ES_OUT_VOUT_FLUSH_OVERLAY
,
1527 esout_priv
->overlay
.p_video_es
,
1528 esout_priv
->overlay
.channels
[i_plane
]);
1529 esout_priv
->overlay
.channels
[i_plane
] = VOUT_SPU_CHANNEL_INVALID
;
1533 assert(esout_priv
->overlay
.channels
[i_plane
] == VOUT_SPU_CHANNEL_INVALID
);
1534 i_ret
= VLC_EGENERIC
;
1539 case ES_OUT_SET_ES_DEFAULT
:
1541 case ES_OUT_UNSET_ES
:
1542 case ES_OUT_SET_ES_STATE
:
1543 i_ret
= VLC_EGENERIC
;
1546 case ES_OUT_GET_ES_STATE
:
1547 va_arg(args
, es_out_id_t
*);
1548 *va_arg(args
, bool *) = true;
1549 i_ret
= VLC_SUCCESS
;
1553 i_ret
= es_out_vaControl(esout_priv
->p_dst_out
, i_query
, args
);
1556 vlc_mutex_unlock(&esout_priv
->lock
);
1560 static void bluray_esOutDestroy(es_out_t
*p_out
)
1562 bluray_esout_priv_t
*esout_priv
= container_of(p_out
, bluray_esout_priv_t
, es_out
);
1564 for (size_t i
= 0; i
< vlc_array_count(&esout_priv
->es
); ++i
)
1565 free(vlc_array_item_at_index(&esout_priv
->es
, i
));
1566 vlc_array_clear(&esout_priv
->es
);
1567 vlc_mutex_destroy(&esout_priv
->lock
);
1571 static const struct es_out_callbacks bluray_esOutCallbacks
= {
1572 .add
= bluray_esOutAdd
,
1573 .send
= bluray_esOutSend
,
1574 .del
= bluray_esOutDel
,
1575 .control
= bluray_esOutControl
,
1576 .destroy
= bluray_esOutDestroy
,
1579 static es_out_t
*esOutNew(vlc_object_t
*p_obj
, es_out_t
*p_dst_out
, void *priv
)
1581 bluray_esout_priv_t
*esout_priv
= malloc(sizeof(*esout_priv
));
1582 if (unlikely(esout_priv
== NULL
))
1585 vlc_array_init(&esout_priv
->es
);
1586 esout_priv
->p_dst_out
= p_dst_out
;
1587 esout_priv
->p_obj
= p_obj
;
1588 esout_priv
->priv
= priv
;
1589 esout_priv
->es_out
.cbs
= &bluray_esOutCallbacks
;
1590 esout_priv
->b_discontinuity
= false;
1591 esout_priv
->b_disable_output
= false;
1592 esout_priv
->b_entered_recycling
= false;
1593 esout_priv
->b_restart_decoders_on_reuse
= true;
1594 esout_priv
->b_lowdelay
= false;
1595 esout_priv
->selected
.i_audio_pid
= -1;
1596 esout_priv
->selected
.i_spu_pid
= -1;
1597 esout_priv
->overlay
.p_video_es
= NULL
;
1598 for(size_t i
=0; i
<MAX_OVERLAY
; i
++)
1599 esout_priv
->overlay
.channels
[i
] = VOUT_SPU_CHANNEL_INVALID
;
1600 vlc_mutex_init(&esout_priv
->lock
);
1601 return &esout_priv
->es_out
;
1604 /*****************************************************************************
1605 * subpicture_updater_t functions:
1606 *****************************************************************************/
1608 static bluray_overlay_t
*updater_lock_overlay(bluray_spu_updater_sys_t
*p_upd_sys
)
1610 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1611 vlc_mutex_lock(&p_upd_sys
->lock
);
1613 bluray_overlay_t
*ov
= p_upd_sys
->p_overlay
;
1615 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1616 vlc_mutex_lock(&ov
->lock
);
1620 /* overlay has been closed */
1621 vlc_mutex_unlock(&p_upd_sys
->lock
);
1625 static void updater_unlock_overlay(bluray_spu_updater_sys_t
*p_upd_sys
)
1627 assert (p_upd_sys
->p_overlay
);
1629 vlc_mutex_unlock(&p_upd_sys
->p_overlay
->lock
);
1630 vlc_mutex_unlock(&p_upd_sys
->lock
);
1633 static int subpictureUpdaterValidate(subpicture_t
*p_subpic
,
1634 bool b_fmt_src
, const video_format_t
*p_fmt_src
,
1635 bool b_fmt_dst
, const video_format_t
*p_fmt_dst
,
1638 VLC_UNUSED(b_fmt_src
);
1639 VLC_UNUSED(b_fmt_dst
);
1640 VLC_UNUSED(p_fmt_src
);
1641 VLC_UNUSED(p_fmt_dst
);
1644 bluray_spu_updater_sys_t
*p_upd_sys
= p_subpic
->updater
.p_sys
;
1645 bluray_overlay_t
*p_overlay
= updater_lock_overlay(p_upd_sys
);
1651 int res
= p_overlay
->status
== Outdated
;
1653 updater_unlock_overlay(p_upd_sys
);
1658 static void subpictureUpdaterUpdate(subpicture_t
*p_subpic
,
1659 const video_format_t
*p_fmt_src
,
1660 const video_format_t
*p_fmt_dst
,
1663 VLC_UNUSED(p_fmt_src
);
1664 VLC_UNUSED(p_fmt_dst
);
1666 bluray_spu_updater_sys_t
*p_upd_sys
= p_subpic
->updater
.p_sys
;
1667 bluray_overlay_t
*p_overlay
= updater_lock_overlay(p_upd_sys
);
1674 * When this function is called, all p_subpic regions are gone.
1675 * We need to duplicate our regions (stored internaly) to this subpic.
1677 subpicture_region_t
*p_src
= p_overlay
->p_regions
;
1679 updater_unlock_overlay(p_upd_sys
);
1683 subpicture_region_t
**p_dst
= &p_subpic
->p_region
;
1684 while (p_src
!= NULL
) {
1685 *p_dst
= subpicture_region_Copy(p_src
);
1688 p_dst
= &(*p_dst
)->p_next
;
1689 p_src
= p_src
->p_next
;
1692 (*p_dst
)->p_next
= NULL
;
1693 p_overlay
->status
= Displayed
;
1695 updater_unlock_overlay(p_upd_sys
);
1698 static void subpictureUpdaterDestroy(subpicture_t
*p_subpic
)
1700 bluray_spu_updater_sys_t
*p_upd_sys
= p_subpic
->updater
.p_sys
;
1701 bluray_overlay_t
*p_overlay
= updater_lock_overlay(p_upd_sys
);
1704 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1705 p_overlay
->status
= ToDisplay
;
1706 p_overlay
->b_on_vout
= false;
1707 updater_unlock_overlay(p_upd_sys
);
1710 unref_subpicture_updater(p_upd_sys
);
1713 static subpicture_t
*bluraySubpictureCreate(bluray_overlay_t
*p_ov
)
1715 bluray_spu_updater_sys_t
*p_upd_sys
= malloc(sizeof(*p_upd_sys
));
1716 if (unlikely(p_upd_sys
== NULL
)) {
1720 p_upd_sys
->p_overlay
= p_ov
;
1722 subpicture_updater_t updater
= {
1723 .pf_validate
= subpictureUpdaterValidate
,
1724 .pf_update
= subpictureUpdaterUpdate
,
1725 .pf_destroy
= subpictureUpdaterDestroy
,
1729 subpicture_t
*p_pic
= subpicture_New(&updater
);
1730 if (p_pic
== NULL
) {
1735 p_pic
->i_original_picture_width
= p_ov
->width
;
1736 p_pic
->i_original_picture_height
= p_ov
->height
;
1737 p_pic
->b_absolute
= true;
1739 vlc_mutex_init(&p_upd_sys
->lock
);
1740 p_upd_sys
->ref_cnt
= 2;
1742 p_ov
->p_updater
= p_upd_sys
;
1747 /*****************************************************************************
1748 * User input events:
1749 *****************************************************************************/
1750 static void onMouseEvent(const vlc_mouse_t
*newmouse
, void *user_data
)
1752 demux_t
*p_demux
= user_data
;
1753 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1756 vlc_mouse_Init(&p_sys
->oldmouse
);
1760 if (vlc_mouse_HasMoved(&p_sys
->oldmouse
, newmouse
))
1761 bd_mouse_select(p_sys
->bluray
, -1, newmouse
->i_x
, newmouse
->i_y
);
1763 if (vlc_mouse_HasPressed( &p_sys
->oldmouse
, newmouse
, MOUSE_BUTTON_LEFT
))
1764 bd_user_input(p_sys
->bluray
, -1, BD_VK_MOUSE_ACTIVATE
);
1765 p_sys
->oldmouse
= *newmouse
;
1768 static int sendKeyEvent(demux_sys_t
*p_sys
, unsigned int key
)
1770 if (bd_user_input(p_sys
->bluray
, -1, key
) < 0)
1771 return VLC_EGENERIC
;
1776 /*****************************************************************************
1777 * libbluray overlay handling:
1778 *****************************************************************************/
1780 static void blurayCloseOverlay(demux_t
*p_demux
, int plane
)
1782 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1783 bluray_overlay_t
*ov
= p_sys
->bdj
.p_overlays
[plane
];
1787 /* drop overlay from vout */
1788 if (ov
->p_updater
) {
1789 unref_subpicture_updater(ov
->p_updater
);
1792 /* no references to this overlay exist in vo anymore */
1793 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY
, plane
);
1795 vlc_mutex_destroy(&ov
->lock
);
1796 subpicture_region_ChainDelete(ov
->p_regions
);
1799 p_sys
->bdj
.p_overlays
[plane
] = NULL
;
1804 * Mark the overlay as "ToDisplay" status.
1805 * This will not send the overlay to the vout instantly, as the vout
1806 * may not be acquired (not acquirable) yet.
1807 * If is has already been acquired, the overlay has already been sent to it,
1808 * therefore, we only flag the overlay as "Outdated"
1810 static void blurayActivateOverlay(demux_t
*p_demux
, int plane
)
1812 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1813 bluray_overlay_t
*ov
= p_sys
->bdj
.p_overlays
[plane
];
1816 * If the overlay is already displayed, mark the picture as outdated.
1817 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1819 vlc_mutex_lock(&ov
->lock
);
1820 if (ov
->status
>= Displayed
&& ov
->b_on_vout
) {
1821 ov
->status
= Outdated
;
1822 vlc_mutex_unlock(&ov
->lock
);
1827 * Mark the overlay as available, but don't display it right now.
1828 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1829 * the overlay is computed
1831 ov
->status
= ToDisplay
;
1832 vlc_mutex_unlock(&ov
->lock
);
1835 static void blurayInitOverlay(demux_t
*p_demux
, int plane
, int width
, int height
)
1837 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1839 assert(p_sys
->bdj
.p_overlays
[plane
] == NULL
);
1841 bluray_overlay_t
*ov
= calloc(1, sizeof(*ov
));
1842 if (unlikely(ov
== NULL
))
1846 ov
->height
= height
;
1847 ov
->b_on_vout
= false;
1849 vlc_mutex_init(&ov
->lock
);
1851 p_sys
->bdj
.p_overlays
[plane
] = ov
;
1855 * Destroy every regions in the subpicture.
1856 * This is done in two steps:
1857 * - Wiping our private regions list
1858 * - Flagging the overlay as outdated, so the changes are replicated from
1859 * the subpicture_updater_t::pf_update
1860 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1862 static void blurayClearOverlay(demux_t
*p_demux
, int plane
)
1864 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1865 bluray_overlay_t
*ov
= p_sys
->bdj
.p_overlays
[plane
];
1867 vlc_mutex_lock(&ov
->lock
);
1869 subpicture_region_ChainDelete(ov
->p_regions
);
1870 ov
->p_regions
= NULL
;
1871 ov
->status
= Outdated
;
1873 vlc_mutex_unlock(&ov
->lock
);
1877 * This will draw to the overlay by adding a region to our region list
1878 * This will have to be copied to the subpicture used to render the overlay.
1880 static void blurayDrawOverlay(demux_t
*p_demux
, const BD_OVERLAY
* const ov
)
1882 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1885 * Compute a subpicture_region_t.
1886 * It will be copied and sent to the vout later.
1888 vlc_mutex_lock(&p_sys
->bdj
.p_overlays
[ov
->plane
]->lock
);
1890 /* Find a region to update */
1891 subpicture_region_t
**pp_reg
= &p_sys
->bdj
.p_overlays
[ov
->plane
]->p_regions
;
1892 subpicture_region_t
*p_reg
= p_sys
->bdj
.p_overlays
[ov
->plane
]->p_regions
;
1893 subpicture_region_t
*p_last
= NULL
;
1894 while (p_reg
!= NULL
) {
1896 if (p_reg
->i_x
== ov
->x
&& p_reg
->i_y
== ov
->y
&&
1897 p_reg
->fmt
.i_width
== ov
->w
&& p_reg
->fmt
.i_height
== ov
->h
)
1899 pp_reg
= &p_reg
->p_next
;
1900 p_reg
= p_reg
->p_next
;
1906 *pp_reg
= p_reg
->p_next
;
1907 subpicture_region_Delete(p_reg
);
1909 vlc_mutex_unlock(&p_sys
->bdj
.p_overlays
[ov
->plane
]->lock
);
1913 /* If there is no region to update, create a new one. */
1916 video_format_Init(&fmt
, 0);
1917 video_format_Setup(&fmt
, VLC_CODEC_YUVP
, ov
->w
, ov
->h
, ov
->w
, ov
->h
, 1, 1);
1919 p_reg
= subpicture_region_New(&fmt
);
1922 /* Append it to our list. */
1924 p_last
->p_next
= p_reg
;
1925 else /* If we don't have a last region, then our list empty */
1926 p_sys
->bdj
.p_overlays
[ov
->plane
]->p_regions
= p_reg
;
1929 /* Now we can update the region, regardless it's an update or an insert */
1930 const BD_PG_RLE_ELEM
*img
= ov
->img
;
1931 for (int y
= 0; y
< ov
->h
; y
++)
1932 for (int x
= 0; x
< ov
->w
;) {
1933 plane_t
*p
= &p_reg
->p_picture
->p
[0];
1934 memset(&p
->p_pixels
[y
* p
->i_pitch
+ x
], img
->color
, img
->len
);
1940 p_reg
->fmt
.p_palette
->i_entries
= 256;
1941 for (int i
= 0; i
< 256; ++i
) {
1942 p_reg
->fmt
.p_palette
->palette
[i
][0] = ov
->palette
[i
].Y
;
1943 p_reg
->fmt
.p_palette
->palette
[i
][1] = ov
->palette
[i
].Cb
;
1944 p_reg
->fmt
.p_palette
->palette
[i
][2] = ov
->palette
[i
].Cr
;
1945 p_reg
->fmt
.p_palette
->palette
[i
][3] = ov
->palette
[i
].T
;
1949 vlc_mutex_unlock(&p_sys
->bdj
.p_overlays
[ov
->plane
]->lock
);
1951 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1955 static void blurayOverlayProc(void *ptr
, const BD_OVERLAY
*const overlay
)
1957 demux_t
*p_demux
= (demux_t
*)ptr
;
1958 demux_sys_t
*p_sys
= p_demux
->p_sys
;
1960 vlc_mutex_lock(&p_sys
->bdj
.lock
);
1963 msg_Info(p_demux
, "Closing overlays.");
1964 for (int i
= 0; i
< MAX_OVERLAY
; i
++)
1965 blurayCloseOverlay(p_demux
, i
);
1966 vlc_mutex_unlock(&p_sys
->bdj
.lock
);
1970 switch (overlay
->cmd
) {
1971 case BD_OVERLAY_INIT
:
1972 msg_Info(p_demux
, "Initializing overlay");
1973 blurayInitOverlay(p_demux
, overlay
->plane
, overlay
->w
, overlay
->h
);
1975 case BD_OVERLAY_CLOSE
:
1976 blurayClearOverlay(p_demux
, overlay
->plane
);
1977 blurayCloseOverlay(p_demux
, overlay
->plane
);
1979 case BD_OVERLAY_CLEAR
:
1980 blurayClearOverlay(p_demux
, overlay
->plane
);
1982 case BD_OVERLAY_FLUSH
:
1983 blurayActivateOverlay(p_demux
, overlay
->plane
);
1985 case BD_OVERLAY_DRAW
:
1986 case BD_OVERLAY_WIPE
:
1987 blurayDrawOverlay(p_demux
, overlay
);
1990 msg_Warn(p_demux
, "Unknown BD overlay command: %u", overlay
->cmd
);
1994 vlc_mutex_unlock(&p_sys
->bdj
.lock
);
1998 * ARGB overlay (BD-J)
2000 static void blurayInitArgbOverlay(demux_t
*p_demux
, int plane
, int width
, int height
)
2002 blurayInitOverlay(p_demux
, plane
, width
, height
);
2005 static void blurayDrawArgbOverlay(demux_t
*p_demux
, const BD_ARGB_OVERLAY
* const ov
)
2007 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2009 bluray_overlay_t
*bdov
= p_sys
->bdj
.p_overlays
[ov
->plane
];
2010 vlc_mutex_lock(&bdov
->lock
);
2012 if (!bdov
->p_regions
)
2015 video_format_Init(&fmt
, 0);
2016 video_format_Setup(&fmt
,
2017 /* ARGB in word order -> byte order */
2018 #ifdef WORDS_BIG_ENDIAN
2023 ov
->stride
, bdov
->height
,
2024 bdov
->width
, bdov
->height
, 1, 1);
2025 bdov
->p_regions
= subpicture_region_New(&fmt
);
2028 /* Find a region to update */
2029 subpicture_region_t
*p_reg
= bdov
->p_regions
;
2031 vlc_mutex_unlock(&bdov
->lock
);
2035 /* Now we can update the region */
2036 const uint32_t *src0
= ov
->argb
;
2037 uint8_t *dst0
= p_reg
->p_picture
->p
[0].p_pixels
+
2038 p_reg
->p_picture
->p
[0].i_pitch
* ov
->y
+
2041 for (int y
= 0; y
< ov
->h
; y
++)
2043 memcpy(dst0
, src0
, ov
->w
* 4);
2045 dst0
+= p_reg
->p_picture
->p
[0].i_pitch
;
2048 vlc_mutex_unlock(&bdov
->lock
);
2050 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
2054 static void blurayArgbOverlayProc(void *ptr
, const BD_ARGB_OVERLAY
*const overlay
)
2056 demux_t
*p_demux
= (demux_t
*)ptr
;
2057 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2059 switch (overlay
->cmd
) {
2060 case BD_ARGB_OVERLAY_INIT
:
2061 vlc_mutex_lock(&p_sys
->bdj
.lock
);
2062 blurayInitArgbOverlay(p_demux
, overlay
->plane
, overlay
->w
, overlay
->h
);
2063 vlc_mutex_unlock(&p_sys
->bdj
.lock
);
2065 case BD_ARGB_OVERLAY_CLOSE
:
2066 vlc_mutex_lock(&p_sys
->bdj
.lock
);
2067 blurayClearOverlay(p_demux
, overlay
->plane
);
2068 blurayCloseOverlay(p_demux
, overlay
->plane
);
2069 vlc_mutex_unlock(&p_sys
->bdj
.lock
);
2071 case BD_ARGB_OVERLAY_FLUSH
:
2072 blurayActivateOverlay(p_demux
, overlay
->plane
);
2074 case BD_ARGB_OVERLAY_DRAW
:
2075 blurayDrawArgbOverlay(p_demux
, overlay
);
2078 msg_Warn(p_demux
, "Unknown BD ARGB overlay command: %u", overlay
->cmd
);
2083 static void bluraySendOverlayToVout(demux_t
*p_demux
, int plane
, bluray_overlay_t
*p_ov
)
2085 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2087 assert(p_ov
!= NULL
);
2088 assert(!p_ov
->b_on_vout
);
2090 if (p_ov
->p_updater
) {
2091 unref_subpicture_updater(p_ov
->p_updater
);
2092 p_ov
->p_updater
= NULL
;
2095 subpicture_t
*p_pic
= bluraySubpictureCreate(p_ov
);
2097 msg_Err(p_demux
, "bluraySubpictureCreate() failed");
2102 * After this point, the picture should not be accessed from the demux thread,
2103 * as it is held by the vout thread.
2104 * This must be done only once per subpicture, ie. only once between each
2105 * blurayInitOverlay & blurayCloseOverlay call.
2107 int ret
= es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY
,
2109 if (ret
!= VLC_SUCCESS
)
2111 unref_subpicture_updater(p_ov
->p_updater
);
2112 p_ov
->p_updater
= NULL
;
2113 p_ov
->b_on_vout
= false;
2114 subpicture_Delete(p_pic
);
2117 p_ov
->b_on_vout
= true;
2120 * Mark the picture as Outdated, as it contains no region for now.
2121 * This will make the subpicture_updater_t call pf_update
2123 p_ov
->status
= Outdated
;
2126 static bool blurayTitleIsRepeating(BLURAY_TITLE_INFO
*title_info
,
2127 unsigned repeats
, unsigned ratio
)
2129 const BLURAY_CLIP_INFO
*prev
= NULL
;
2130 unsigned maxrepeats
= 0;
2131 unsigned sequence
= 0;
2132 if(!title_info
->chapter_count
)
2135 for (unsigned int j
= 0; j
< title_info
->chapter_count
; j
++)
2137 unsigned i
= title_info
->chapters
[j
].clip_ref
;
2138 if(i
< title_info
->clip_count
)
2141 /* non repeated does not need start time offset */
2142 title_info
->clips
[i
].start_time
== 0 ||
2143 /* repeats occurs on same segment */
2144 memcmp(title_info
->clips
[i
].clip_id
, prev
->clip_id
, 6) ||
2145 prev
->in_time
!= title_info
->clips
[i
].in_time
||
2146 prev
->pkt_count
!= title_info
->clips
[i
].pkt_count
)
2149 prev
= &title_info
->clips
[i
];
2154 if(maxrepeats
< sequence
++)
2155 maxrepeats
= sequence
;
2159 return (maxrepeats
> repeats
&&
2160 (100 * maxrepeats
/ title_info
->chapter_count
) >= ratio
);
2163 static void blurayUpdateTitleInfo(input_title_t
*t
, BLURAY_TITLE_INFO
*title_info
)
2165 t
->i_length
= FROM_SCALE_NZ(title_info
->duration
);
2167 for (int i
= 0; i
< t
->i_seekpoint
; i
++)
2168 vlc_seekpoint_Delete( t
->seekpoint
[i
] );
2169 TAB_CLEAN(t
->i_seekpoint
, t
->seekpoint
);
2171 /* FIXME: have libbluray expose repeating titles */
2172 if(blurayTitleIsRepeating(title_info
, 50, 90))
2175 for (unsigned int j
= 0; j
< title_info
->chapter_count
; j
++) {
2176 seekpoint_t
*s
= vlc_seekpoint_New();
2180 s
->i_time_offset
= FROM_SCALE_NZ(title_info
->chapters
[j
].start
);
2182 TAB_APPEND(t
->i_seekpoint
, t
->seekpoint
, s
);
2186 static void blurayInitTitles(demux_t
*p_demux
, uint32_t menu_titles
)
2188 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2189 const BLURAY_DISC_INFO
*di
= bd_get_disc_info(p_sys
->bluray
);
2191 /* get and set the titles */
2192 uint32_t i_title
= menu_titles
;
2194 if (!p_sys
->b_menu
) {
2195 i_title
= bd_get_titles(p_sys
->bluray
, TITLES_RELEVANT
, 60);
2196 p_sys
->i_longest_title
= bd_get_main_title(p_sys
->bluray
);
2199 for (uint32_t i
= 0; i
< i_title
; i
++) {
2200 input_title_t
*t
= vlc_input_title_New();
2204 if (!p_sys
->b_menu
) {
2205 BLURAY_TITLE_INFO
*title_info
= bd_get_title_info(p_sys
->bluray
, i
, 0);
2206 blurayUpdateTitleInfo(t
, title_info
);
2207 bd_free_title_info(title_info
);
2209 } else if (i
== 0) {
2210 t
->psz_name
= strdup(_("Top Menu"));
2211 t
->i_flags
= INPUT_TITLE_MENU
| INPUT_TITLE_INTERACTIVE
;
2212 } else if (i
== i_title
- 1) {
2213 t
->psz_name
= strdup(_("First Play"));
2214 if (di
&& di
->first_play
&& di
->first_play
->interactive
) {
2215 t
->i_flags
= INPUT_TITLE_INTERACTIVE
;
2218 /* add possible title name from disc metadata */
2219 if (di
&& di
->titles
&& i
<= di
->num_titles
) {
2220 if (di
->titles
[i
]->name
) {
2221 t
->psz_name
= strdup(di
->titles
[i
]->name
);
2223 if (di
->titles
[i
]->interactive
) {
2224 t
->i_flags
= INPUT_TITLE_INTERACTIVE
;
2229 TAB_APPEND(p_sys
->i_title
, p_sys
->pp_title
, t
);
2233 static void blurayRestartParser(demux_t
*p_demux
, bool b_flush
, bool b_random_access
)
2236 * This is a hack and will have to be removed.
2237 * The parser should be flushed, and not destroy/created each time
2238 * we are changing title.
2240 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2243 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT
);
2245 if (p_sys
->p_parser
)
2246 vlc_demux_chained_Delete(p_sys
->p_parser
);
2249 es_out_Control(p_sys
->p_tf_out
, ES_OUT_TF_FILTER_RESET
);
2251 p_sys
->p_parser
= vlc_demux_chained_New(VLC_OBJECT(p_demux
), "ts", p_sys
->p_out
);
2252 if (!p_sys
->p_parser
)
2253 msg_Err(p_demux
, "Failed to create TS demuxer");
2255 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT
);
2257 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS
, b_random_access
);
2260 /*****************************************************************************
2261 * bluraySetTitle: select new BD title
2262 *****************************************************************************/
2263 static int bluraySetTitle(demux_t
*p_demux
, int i_title
)
2265 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2267 if (p_sys
->b_menu
) {
2270 msg_Dbg(p_demux
, "Playing TopMenu Title");
2271 result
= bd_menu_call(p_sys
->bluray
, -1);
2272 } else if (i_title
>= (int)p_sys
->i_title
- 1) {
2273 msg_Dbg(p_demux
, "Playing FirstPlay Title");
2274 result
= bd_play_title(p_sys
->bluray
, BLURAY_TITLE_FIRST_PLAY
);
2276 msg_Dbg(p_demux
, "Playing Title %i", i_title
);
2277 result
= bd_play_title(p_sys
->bluray
, i_title
);
2281 msg_Err(p_demux
, "cannot play bd title '%d'", i_title
);
2282 return VLC_EGENERIC
;
2288 /* Looking for the main title, ie the longest duration */
2290 i_title
= p_sys
->i_longest_title
;
2291 else if ((unsigned)i_title
> p_sys
->i_title
)
2292 return VLC_EGENERIC
;
2294 msg_Dbg(p_demux
, "Selecting Title %i", i_title
);
2296 if (bd_select_title(p_sys
->bluray
, i_title
) == 0) {
2297 msg_Err(p_demux
, "cannot select bd title '%d'", i_title
);
2298 return VLC_EGENERIC
;
2304 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
2305 # define BLURAY_AUDIO_STREAM 0
2308 static void blurayOnUserStreamSelection(demux_sys_t
*p_sys
, int i_pid
)
2310 vlc_mutex_lock(&p_sys
->pl_info_lock
);
2312 if(i_pid
== -AUDIO_ES
)
2313 bd_select_stream(p_sys
->bluray
, BLURAY_AUDIO_STREAM
, 0, 0);
2314 else if(i_pid
== -SPU_ES
)
2315 bd_select_stream(p_sys
->bluray
, BLURAY_PG_TEXTST_STREAM
, 0, 0);
2316 else if (p_sys
->p_clip_info
)
2319 if ((i_pid
& 0xff00) == 0x1100) {
2321 for (int i_id
= 0; i_id
< p_sys
->p_clip_info
->audio_stream_count
; i_id
++) {
2322 if (i_pid
== p_sys
->p_clip_info
->audio_streams
[i_id
].pid
) {
2323 bd_select_stream(p_sys
->bluray
, BLURAY_AUDIO_STREAM
, i_id
+ 1, 1);
2325 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_AUDIO_LANG
,
2326 (const char *) p_sys
->p_clip_info
->audio_streams
[i_id
].lang
);
2330 } else if ((i_pid
& 0xff00) == 0x1400 || i_pid
== 0x1800) {
2332 for (int i_id
= 0; i_id
< p_sys
->p_clip_info
->pg_stream_count
; i_id
++) {
2333 if (i_pid
== p_sys
->p_clip_info
->pg_streams
[i_id
].pid
) {
2334 bd_select_stream(p_sys
->bluray
, BLURAY_PG_TEXTST_STREAM
, i_id
+ 1, 1);
2336 bd_set_player_setting_str(p_sys
->bluray
, BLURAY_PLAYER_SETTING_PG_LANG
,
2337 (const char *) p_sys
->p_clip_info
->pg_streams
[i_id
].lang
);
2344 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
2347 /*****************************************************************************
2348 * blurayControl: handle the controls
2349 *****************************************************************************/
2350 static int blurayControl(demux_t
*p_demux
, int query
, va_list args
)
2352 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2356 case DEMUX_CAN_SEEK
:
2357 case DEMUX_CAN_PAUSE
:
2358 case DEMUX_CAN_CONTROL_PACE
:
2359 pb_bool
= va_arg(args
, bool *);
2363 case DEMUX_GET_PTS_DELAY
:
2364 *va_arg(args
, vlc_tick_t
*) =
2365 VLC_TICK_FROM_MS(var_InheritInteger(p_demux
, "disc-caching"));
2368 case DEMUX_SET_PAUSE_STATE
:
2370 #ifdef BLURAY_RATE_NORMAL
2371 bool b_paused
= (bool)va_arg(args
, int);
2372 if (bd_set_rate(p_sys
->bluray
, BLURAY_RATE_NORMAL
* (!b_paused
)) < 0) {
2373 return VLC_EGENERIC
;
2380 int i_id
= va_arg(args
, int);
2381 blurayOnUserStreamSelection(p_sys
, i_id
);
2384 case DEMUX_SET_TITLE
:
2386 int i_title
= va_arg(args
, int);
2387 if (bluraySetTitle(p_demux
, i_title
) != VLC_SUCCESS
) {
2388 /* make sure GUI restores the old setting in title menu ... */
2389 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2390 return VLC_EGENERIC
;
2392 blurayRestartParser(p_demux
, true, false);
2393 notifyDiscontinuityToParser(p_sys
);
2394 p_sys
->b_draining
= false;
2395 es_out_Control(p_demux
->out
, ES_OUT_RESET_PCR
);
2396 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
);
2399 case DEMUX_SET_SEEKPOINT
:
2401 int i_chapter
= va_arg(args
, int);
2402 bd_seek_chapter(p_sys
->bluray
, i_chapter
);
2403 blurayRestartParser(p_demux
, true, false);
2404 notifyDiscontinuityToParser(p_sys
);
2405 p_sys
->b_draining
= false;
2406 es_out_Control(p_demux
->out
, ES_OUT_RESET_PCR
);
2407 p_sys
->updates
|= INPUT_UPDATE_SEEKPOINT
;
2410 case DEMUX_TEST_AND_CLEAR_FLAGS
:
2412 unsigned *restrict flags
= va_arg(args
, unsigned *);
2413 *flags
&= p_sys
->updates
;
2414 p_sys
->updates
&= ~*flags
;
2417 case DEMUX_GET_TITLE
:
2418 *va_arg(args
, int *) = p_sys
->cur_title
;
2421 case DEMUX_GET_SEEKPOINT
:
2422 *va_arg(args
, int *) = p_sys
->cur_seekpoint
;
2425 case DEMUX_GET_TITLE_INFO
:
2427 input_title_t
***ppp_title
= va_arg(args
, input_title_t
***);
2428 int *pi_int
= va_arg(args
, int *);
2429 int *pi_title_offset
= va_arg(args
, int *);
2430 int *pi_chapter_offset
= va_arg(args
, int *);
2433 *pi_title_offset
= 0;
2434 *pi_chapter_offset
= 0;
2436 /* Duplicate local title infos */
2438 *ppp_title
= vlc_alloc(p_sys
->i_title
, sizeof(input_title_t
*));
2440 return VLC_EGENERIC
;
2441 for (unsigned int i
= 0; i
< p_sys
->i_title
; i
++)
2443 input_title_t
*p_dup
= vlc_input_title_Duplicate(p_sys
->pp_title
[i
]);
2445 (*ppp_title
)[(*pi_int
)++] = p_dup
;
2451 case DEMUX_GET_LENGTH
:
2453 if(p_sys
->cur_title
< p_sys
->i_title
&&
2454 (CURRENT_TITLE
->i_flags
& INPUT_TITLE_INTERACTIVE
))
2455 return VLC_EGENERIC
;
2456 *va_arg(args
, vlc_tick_t
*) = p_sys
->cur_title
< p_sys
->i_title
? CUR_LENGTH
: 0;
2459 case DEMUX_SET_TIME
:
2461 bd_seek_time(p_sys
->bluray
, TO_SCALE_NZ(va_arg(args
, vlc_tick_t
)));
2462 blurayRestartParser(p_demux
, true, true);
2463 notifyDiscontinuityToParser(p_sys
);
2464 p_sys
->b_draining
= false;
2465 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
);
2468 case DEMUX_GET_TIME
:
2470 vlc_tick_t
*pi_time
= va_arg(args
, vlc_tick_t
*);
2471 if(p_sys
->cur_title
< p_sys
->i_title
&&
2472 (CURRENT_TITLE
->i_flags
& INPUT_TITLE_INTERACTIVE
))
2473 return VLC_EGENERIC
;
2474 *pi_time
= FROM_SCALE_NZ(bd_tell_time(p_sys
->bluray
));
2478 case DEMUX_GET_POSITION
:
2480 double *pf_position
= va_arg(args
, double *);
2481 if(p_sys
->cur_title
< p_sys
->i_title
&&
2482 (CURRENT_TITLE
->i_flags
& INPUT_TITLE_INTERACTIVE
))
2483 return VLC_EGENERIC
;
2484 *pf_position
= p_sys
->cur_title
< p_sys
->i_title
&& CUR_LENGTH
> 0 ?
2485 (double)FROM_SCALE_NZ(bd_tell_time(p_sys
->bluray
))/CUR_LENGTH
: 0.0;
2488 case DEMUX_SET_POSITION
:
2490 double f_position
= va_arg(args
, double);
2491 bd_seek_time(p_sys
->bluray
, TO_SCALE_NZ(f_position
*CUR_LENGTH
));
2492 blurayRestartParser(p_demux
, true, true);
2493 notifyDiscontinuityToParser(p_sys
);
2494 p_sys
->b_draining
= false;
2495 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
);
2499 case DEMUX_GET_META
:
2501 vlc_meta_t
*p_meta
= va_arg(args
, vlc_meta_t
*);
2502 const META_DL
*meta
= p_sys
->p_meta
;
2504 return VLC_EGENERIC
;
2506 if (!EMPTY_STR(meta
->di_name
)) vlc_meta_SetTitle(p_meta
, meta
->di_name
);
2508 if (!EMPTY_STR(meta
->language_code
)) vlc_meta_AddExtra(p_meta
, "Language", meta
->language_code
);
2509 if (!EMPTY_STR(meta
->filename
)) vlc_meta_AddExtra(p_meta
, "Filename", meta
->filename
);
2510 if (!EMPTY_STR(meta
->di_alternative
)) vlc_meta_AddExtra(p_meta
, "Alternative", meta
->di_alternative
);
2512 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
2513 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
2515 if (p_sys
->i_cover_idx
>= 0 && p_sys
->i_cover_idx
< p_sys
->i_attachments
) {
2517 snprintf( psz_url
, sizeof(psz_url
), "attachment://%s",
2518 p_sys
->attachments
[p_sys
->i_cover_idx
]->psz_name
);
2519 vlc_meta_Set( p_meta
, vlc_meta_ArtworkURL
, psz_url
);
2521 else if (meta
->thumb_count
> 0 && meta
->thumbnails
&& p_sys
->psz_bd_path
) {
2522 char *psz_thumbpath
;
2523 if (asprintf(&psz_thumbpath
, "%s" DIR_SEP
"BDMV" DIR_SEP
"META" DIR_SEP
"DL" DIR_SEP
"%s",
2524 p_sys
->psz_bd_path
, meta
->thumbnails
[0].path
) > -1) {
2525 char *psz_thumburl
= vlc_path2uri(psz_thumbpath
, "file");
2526 free(psz_thumbpath
);
2527 if (unlikely(psz_thumburl
== NULL
))
2530 vlc_meta_SetArtURL(p_meta
, psz_thumburl
);
2538 case DEMUX_GET_ATTACHMENTS
:
2540 input_attachment_t
***ppp_attach
=
2541 va_arg(args
, input_attachment_t
***);
2542 int *pi_int
= va_arg(args
, int *);
2544 if (p_sys
->i_attachments
<= 0)
2545 return VLC_EGENERIC
;
2548 *ppp_attach
= vlc_alloc(p_sys
->i_attachments
, sizeof(input_attachment_t
*));
2550 return VLC_EGENERIC
;
2551 for (int i
= 0; i
< p_sys
->i_attachments
; i
++)
2553 input_attachment_t
*p_dup
= vlc_input_attachment_Duplicate(p_sys
->attachments
[i
]);
2555 (*ppp_attach
)[(*pi_int
)++] = p_dup
;
2560 case DEMUX_NAV_ACTIVATE
:
2561 if (p_sys
->b_popup_available
&& !p_sys
->b_menu_open
) {
2562 return sendKeyEvent(p_sys
, BD_VK_POPUP
);
2564 return sendKeyEvent(p_sys
, BD_VK_ENTER
);
2566 return sendKeyEvent(p_sys
, BD_VK_UP
);
2567 case DEMUX_NAV_DOWN
:
2568 return sendKeyEvent(p_sys
, BD_VK_DOWN
);
2569 case DEMUX_NAV_LEFT
:
2570 return sendKeyEvent(p_sys
, BD_VK_LEFT
);
2571 case DEMUX_NAV_RIGHT
:
2572 return sendKeyEvent(p_sys
, BD_VK_RIGHT
);
2573 case DEMUX_NAV_POPUP
:
2574 return sendKeyEvent(p_sys
, BD_VK_POPUP
);
2575 case DEMUX_NAV_MENU
:
2576 if (p_sys
->b_menu
) {
2577 if (bd_menu_call(p_sys
->bluray
, -1) == 1) {
2578 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2581 msg_Err(p_demux
, "Can't select Top Menu title");
2582 return sendKeyEvent(p_sys
, BD_VK_POPUP
);
2584 return VLC_EGENERIC
;
2586 case DEMUX_CAN_RECORD
:
2588 case DEMUX_SET_GROUP_DEFAULT
:
2589 case DEMUX_SET_GROUP_ALL
:
2590 case DEMUX_SET_GROUP_LIST
:
2591 case DEMUX_HAS_UNSUPPORTED_META
:
2593 return VLC_EGENERIC
;
2598 /*****************************************************************************
2599 * libbluray event handling
2600 *****************************************************************************/
2601 static void writeTsPacketWDiscontinuity( uint8_t *p_buf
, uint16_t i_pid
,
2602 const uint8_t *p_payload
, uint8_t i_payload
)
2604 uint8_t ts_header
[] = {
2605 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2607 0x40 | ((i_pid
& 0x1f00) >> 8), i_pid
& 0xFF, /* PUSI + PID */
2608 i_payload
? 0x30 : 0x20, /* adaptation field, payload / no payload */
2609 192 - (4 + 5) - i_payload
, /* adaptation field length */
2610 0x82, /* af: discontinuity indicator + priv data */
2611 0x0E, /* priv data size */
2613 'D', 'I', 'S', 'C', 'O', 'N', 'T', 'I', 'N', 'U',
2616 memcpy( p_buf
, ts_header
, sizeof(ts_header
) );
2617 memset( &p_buf
[sizeof(ts_header
)], 0xFF, 192 - sizeof(ts_header
) - i_payload
);
2619 memcpy( &p_buf
[192 - i_payload
], p_payload
, i_payload
);
2622 static void notifyStreamsDiscontinuity( vlc_demux_chained_t
*p_parser
,
2623 const BLURAY_STREAM_INFO
*p_sinfo
, size_t i_sinfo
)
2625 for( size_t i
=0; i
< i_sinfo
; i
++ )
2627 const uint16_t i_pid
= p_sinfo
[i
].pid
;
2629 block_t
*p_block
= block_Alloc(192);
2633 writeTsPacketWDiscontinuity( p_block
->p_buffer
, i_pid
, NULL
, 0 );
2635 vlc_demux_chained_Send(p_parser
, p_block
);
2639 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2640 p_clip->memb##_stream_count )
2642 static void notifyDiscontinuityToParser( demux_sys_t
*p_sys
)
2644 const BLURAY_CLIP_INFO
*p_clip
= p_sys
->p_clip_info
;
2651 DONOTIFY(sec_audio
);
2652 DONOTIFY(sec_video
);
2658 static void streamFlush( demux_sys_t
*p_sys
)
2661 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2662 * Packet is flushed only when TS packet with PUSI flag set is received.
2664 * Fix this by emitting (video) ts packet with PUSI flag set.
2665 * Add video sequence end code to payload so that also video decoder is flushed.
2666 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2669 if (p_sys
->b_flushed
)
2672 block_t
*p_block
= block_Alloc(192);
2676 bd_stream_type_e i_coding_type
;
2678 /* set correct sequence end code */
2679 vlc_mutex_lock(&p_sys
->pl_info_lock
);
2680 if (p_sys
->p_clip_info
!= NULL
)
2681 i_coding_type
= p_sys
->p_clip_info
->video_streams
[0].coding_type
;
2684 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
2687 switch( i_coding_type
)
2689 case BLURAY_STREAM_TYPE_VIDEO_MPEG1
:
2690 case BLURAY_STREAM_TYPE_VIDEO_MPEG2
:
2692 i_eos
= 0xB7; /* MPEG2 sequence end */
2694 case BLURAY_STREAM_TYPE_VIDEO_VC1
:
2695 case BLURAY_STREAM_TYPE_VIDEO_H264
:
2696 i_eos
= 0x0A; /* VC1 / H.264 sequence end */
2698 case BD_STREAM_TYPE_VIDEO_HEVC
:
2699 i_eos
= 0x48; /* HEVC sequence end NALU */
2703 uint8_t seq_end_pes
[] = {
2704 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2705 0x00, 0x00, 0x01, i_eos
, /* PES payload: sequence end */
2706 0x00, /* 2nd byte for HEVC NAL, pads others */
2709 writeTsPacketWDiscontinuity( p_block
->p_buffer
, 0x1011, seq_end_pes
, sizeof(seq_end_pes
) );
2711 vlc_demux_chained_Send(p_sys
->p_parser
, p_block
);
2712 p_sys
->b_flushed
= true;
2715 static void blurayResetStillImage( demux_t
*p_demux
)
2717 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2719 if (p_sys
->i_still_end_time
!= STILL_IMAGE_NOT_SET
) {
2720 p_sys
->i_still_end_time
= STILL_IMAGE_NOT_SET
;
2722 blurayRestartParser(p_demux
, false, false);
2723 es_out_Control( p_demux
->out
, ES_OUT_RESET_PCR
);
2727 static void blurayStillImage( demux_t
*p_demux
, unsigned i_timeout
)
2729 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2731 /* time period elapsed ? */
2732 if (p_sys
->i_still_end_time
!= STILL_IMAGE_NOT_SET
&&
2733 p_sys
->i_still_end_time
!= STILL_IMAGE_INFINITE
&&
2734 p_sys
->i_still_end_time
<= vlc_tick_now()) {
2735 msg_Dbg(p_demux
, "Still image end");
2736 bd_read_skip_still(p_sys
->bluray
);
2738 blurayResetStillImage(p_demux
);
2742 /* show last frame as still image */
2743 if (p_sys
->i_still_end_time
== STILL_IMAGE_NOT_SET
) {
2745 msg_Dbg(p_demux
, "Still image (%d seconds)", i_timeout
);
2746 p_sys
->i_still_end_time
= vlc_tick_now() + vlc_tick_from_sec( i_timeout
);
2748 msg_Dbg(p_demux
, "Still image (infinite)");
2749 p_sys
->i_still_end_time
= STILL_IMAGE_INFINITE
;
2752 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2755 /* stop buffering */
2757 es_out_Control( p_demux
->out
, ES_OUT_GET_EMPTY
, &b_empty
);
2760 /* avoid busy loops (read returns no data) */
2761 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2764 static void blurayOnStreamSelectedEvent(demux_t
*p_demux
, uint32_t i_type
, uint32_t i_id
)
2766 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2769 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2772 if (i_type
== BD_EVENT_AUDIO_STREAM
) {
2773 i_pid
= blurayGetStreamPID(p_sys
, i_type
, i_id
);
2774 } else if (i_type
== BD_EVENT_PG_TEXTST_STREAM
) {
2775 i_pid
= blurayGetStreamPID(p_sys
, i_type
, i_id
);
2780 if (i_type
== BD_EVENT_PG_TEXTST_STREAM
&& !p_sys
->b_spu_enable
)
2781 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID
, (int)i_type
, i_pid
);
2783 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID
, (int)i_type
, i_pid
);
2787 static void blurayUpdatePlaylist(demux_t
*p_demux
, unsigned i_playlist
)
2789 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2791 blurayRestartParser(p_demux
, true, false);
2793 /* read title info and init some values */
2795 p_sys
->cur_title
= bd_get_current_title(p_sys
->bluray
);
2796 p_sys
->cur_seekpoint
= 0;
2797 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2799 BLURAY_TITLE_INFO
*p_title_info
= bd_get_playlist_info(p_sys
->bluray
, i_playlist
, 0);
2801 blurayUpdateTitleInfo(p_sys
->pp_title
[p_sys
->cur_title
], p_title_info
);
2803 p_sys
->updates
|= INPUT_UPDATE_TITLE_LIST
;
2805 setTitleInfo(p_sys
, p_title_info
);
2807 blurayResetStillImage(p_demux
);
2810 static void blurayOnClipUpdate(demux_t
*p_demux
, uint32_t clip
)
2812 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2814 vlc_mutex_lock(&p_sys
->pl_info_lock
);
2816 p_sys
->p_clip_info
= NULL
;
2818 if (p_sys
->p_pl_info
&& clip
< p_sys
->p_pl_info
->clip_count
) {
2820 p_sys
->p_clip_info
= &p_sys
->p_pl_info
->clips
[clip
];
2822 /* Let's assume a single video track for now.
2823 * This may brake later, but it's enough for now.
2825 assert(p_sys
->p_clip_info
->video_stream_count
>= 1);
2828 CLPI_CL
*clpi
= bd_get_clpi(p_sys
->bluray
, clip
);
2829 if(clpi
&& clpi
->clip
.application_type
!= p_sys
->clip_application_type
)
2831 if(p_sys
->clip_application_type
== BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW
||
2832 clpi
->clip
.application_type
== BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW
)
2833 blurayRestartParser(p_demux
, false, false);
2835 if(clpi
->clip
.application_type
== BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW
)
2836 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY
);
2838 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY
);
2842 vlc_mutex_unlock(&p_sys
->pl_info_lock
);
2844 blurayResetStillImage(p_demux
);
2847 static void blurayHandleEvent(demux_t
*p_demux
, const BD_EVENT
*e
)
2849 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2851 blurayDebugEvent(e
->event
, e
->param
);
2854 case BD_EVENT_TITLE
:
2855 if (e
->param
== BLURAY_TITLE_FIRST_PLAY
)
2856 p_sys
->cur_title
= p_sys
->i_title
- 1;
2858 p_sys
->cur_title
= e
->param
;
2859 /* this is feature title, we don't know yet which playlist it will play (if any) */
2860 setTitleInfo(p_sys
, NULL
);
2861 /* reset title infos here ? */
2862 p_sys
->updates
|= INPUT_UPDATE_TITLE
| INPUT_UPDATE_SEEKPOINT
;
2863 /* might be BD-J title with no video */
2865 case BD_EVENT_PLAYLIST
:
2866 /* Start of playlist playback (?????.mpls) */
2867 blurayUpdatePlaylist(p_demux
, e
->param
);
2868 if (p_sys
->b_pl_playing
) {
2869 /* previous playlist was stopped in middle. flush to avoid delay */
2870 msg_Info(p_demux
, "Stopping playlist playback");
2871 blurayRestartParser(p_demux
, false, false);
2872 es_out_Control( p_demux
->out
, ES_OUT_RESET_PCR
);
2874 p_sys
->b_pl_playing
= true;
2876 case BD_EVENT_PLAYITEM
:
2877 notifyDiscontinuityToParser(p_sys
);
2878 blurayOnClipUpdate(p_demux
, e
->param
);
2880 case BD_EVENT_CHAPTER
:
2881 if (e
->param
&& e
->param
< 0xffff)
2882 p_sys
->cur_seekpoint
= e
->param
- 1;
2884 p_sys
->cur_seekpoint
= 0;
2885 p_sys
->updates
|= INPUT_UPDATE_SEEKPOINT
;
2887 case BD_EVENT_PLAYMARK
:
2888 case BD_EVENT_ANGLE
:
2891 /* Seek will happen with any chapter/title or bd_seek(),
2892 but also BD-J initiated. We can't make the difference
2893 between input or vm ones, better double flush/pcr reset
2894 than break the clock by throwing post random access PCR */
2895 blurayRestartParser(p_demux
, true, true);
2896 notifyDiscontinuityToParser(p_sys
);
2897 es_out_Control(p_sys
->p_out
, ES_OUT_RESET_PCR
);
2899 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2900 case BD_EVENT_UO_MASK_CHANGED
:
2901 /* This event could be used to grey out unselectable items in title menu */
2905 p_sys
->b_menu_open
= e
->param
;
2907 case BD_EVENT_POPUP
:
2908 p_sys
->b_popup_available
= e
->param
;
2909 /* TODO: show / hide pop-up menu button in gui ? */
2915 case BD_EVENT_ERROR
:
2916 /* fatal error (with menus) */
2917 vlc_dialog_display_error(p_demux
, _("Blu-ray error"),
2918 "Playback with BluRay menus failed");
2919 p_sys
->b_fatal_error
= true;
2921 case BD_EVENT_ENCRYPTED
:
2922 vlc_dialog_display_error(p_demux
, _("Blu-ray error"),
2923 "This disc seems to be encrypted");
2924 p_sys
->b_fatal_error
= true;
2926 case BD_EVENT_READ_ERROR
:
2927 msg_Err(p_demux
, "bluray: read error\n");
2931 * stream selection events
2933 case BD_EVENT_PG_TEXTST
:
2934 p_sys
->b_spu_enable
= e
->param
;
2936 case BD_EVENT_AUDIO_STREAM
:
2937 case BD_EVENT_PG_TEXTST_STREAM
:
2938 blurayOnStreamSelectedEvent(p_demux
, e
->event
, e
->param
);
2940 case BD_EVENT_IG_STREAM
:
2941 case BD_EVENT_SECONDARY_AUDIO
:
2942 case BD_EVENT_SECONDARY_AUDIO_STREAM
:
2943 case BD_EVENT_SECONDARY_VIDEO
:
2944 case BD_EVENT_SECONDARY_VIDEO_STREAM
:
2945 case BD_EVENT_SECONDARY_VIDEO_SIZE
:
2949 * playback control events
2951 case BD_EVENT_STILL_TIME
:
2952 blurayStillImage(p_demux
, e
->param
);
2954 case BD_EVENT_DISCONTINUITY
:
2955 /* reset demuxer (partially decoded PES packets must be dropped) */
2956 blurayRestartParser(p_demux
, false, true);
2957 es_out_Control(p_sys
->p_out
, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY
);
2959 case BD_EVENT_END_OF_TITLE
:
2960 if(p_sys
->b_pl_playing
)
2962 notifyDiscontinuityToParser(p_sys
);
2963 blurayRestartParser(p_demux
, false, false);
2964 p_sys
->b_draining
= true;
2965 p_sys
->b_pl_playing
= false;
2969 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2970 /* avoid busy loop (bd_read() returns no data) */
2971 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2975 msg_Warn(p_demux
, "event: %d param: %d", e
->event
, e
->param
);
2980 static void blurayHandleOverlays(demux_t
*p_demux
)
2982 demux_sys_t
*p_sys
= p_demux
->p_sys
;
2983 vlc_mutex_lock(&p_sys
->bdj
.lock
);
2985 for (int i
= 0; i
< MAX_OVERLAY
; i
++) {
2986 bluray_overlay_t
*ov
= p_sys
->bdj
.p_overlays
[i
];
2990 vlc_mutex_lock(&ov
->lock
);
2991 bool display
= ov
->status
== ToDisplay
;
2992 vlc_mutex_unlock(&ov
->lock
);
2993 if (display
&& !ov
->b_on_vout
)
2995 /* NOTE: we might want to enable background video always when there's no video stream playing.
2996 Now, with some discs, there are perioids (even seconds) during which the video window
2997 disappears and just playlist is shown.
2998 (sometimes BD-J runs slowly ...)
3000 bluraySendOverlayToVout(p_demux
, i
, ov
);
3004 vlc_mutex_unlock(&p_sys
->bdj
.lock
);
3007 static int blurayDemux(demux_t
*p_demux
)
3009 demux_sys_t
*p_sys
= p_demux
->p_sys
;
3012 if(p_sys
->b_draining
)
3014 bool b_empty
= false;
3015 if(es_out_Control(p_sys
->p_out
, ES_OUT_GET_EMPTY
, &b_empty
) != VLC_SUCCESS
|| b_empty
)
3017 es_out_Control(p_sys
->p_out
, ES_OUT_RESET_PCR
);
3018 p_sys
->b_draining
= false;
3022 msg_Dbg(p_demux
, "Draining...");
3023 vlc_tick_sleep(VLC_TICK_FROM_MS(40));
3024 return VLC_DEMUXER_SUCCESS
;
3028 block_t
*p_block
= block_Alloc(BD_READ_SIZE
);
3030 return VLC_DEMUXER_EGENERIC
;
3034 if (p_sys
->b_menu
== false) {
3035 nread
= bd_read(p_sys
->bluray
, p_block
->p_buffer
, BD_READ_SIZE
);
3036 while (bd_get_event(p_sys
->bluray
, &e
))
3037 blurayHandleEvent(p_demux
, &e
);
3039 nread
= bd_read_ext(p_sys
->bluray
, p_block
->p_buffer
, BD_READ_SIZE
, &e
);
3040 while (e
.event
!= BD_EVENT_NONE
) {
3041 blurayHandleEvent(p_demux
, &e
);
3042 bd_get_event(p_sys
->bluray
, &e
);
3046 blurayHandleOverlays(p_demux
);
3049 block_Release(p_block
);
3050 if (p_sys
->b_fatal_error
|| nread
< 0) {
3051 msg_Err(p_demux
, "bluray: stopping playback after fatal error\n");
3052 return VLC_DEMUXER_EGENERIC
;
3054 if (!p_sys
->b_menu
) {
3055 return VLC_DEMUXER_EOF
;
3057 return VLC_DEMUXER_SUCCESS
;
3060 p_block
->i_buffer
= nread
;
3062 vlc_demux_chained_Send(p_sys
->p_parser
, p_block
);
3064 p_sys
->b_flushed
= false;
3066 return VLC_DEMUXER_SUCCESS
;