access: bluray: don't restart decoder on seek
[vlc.git] / modules / access / bluray.c
blobcd8f648cfbdd795121a28e5735b80009fe31be19
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 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <assert.h>
29 #include <stdatomic.h>
31 #if defined (HAVE_MNTENT_H) && defined(HAVE_SYS_STAT_H)
32 # include <mntent.h>
33 #endif
34 #include <fcntl.h> /* O_* */
35 #include <unistd.h> /* close() */
36 #include <sys/stat.h>
38 #ifdef __APPLE__
39 # include <sys/param.h>
40 # include <sys/ucred.h>
41 # include <sys/mount.h>
42 #endif
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>
52 #include <vlc_fs.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
71 #ifdef DEBUG_BLURAY
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);
78 if(len < 1) return;
79 char *psz_log = NULL;
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);
83 free(psz_log);
85 #endif
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);\
129 else\
130 msg_Dbg(p_demux, "Event Unk 0x%x %x", e, v);\
131 } while(0)
132 #else
133 # define blurayDebugEvent(e, v)
134 #endif
136 /*****************************************************************************
137 * Module descriptor
138 *****************************************************************************/
140 #define BD_MENU_TEXT N_("Blu-ray menus")
141 #define BD_MENU_LONGTEXT N_("Use Blu-ray menus. If disabled, "\
142 "the movie will start directly")
143 #define BD_REGION_TEXT N_("Region code")
144 #define BD_REGION_LONGTEXT N_("Blu-Ray player region code. "\
145 "Some discs can be played only with a correct region code.")
147 static const char *const ppsz_region_code[] = {
148 "A", "B", "C" };
149 static const char *const ppsz_region_code_text[] = {
150 "Region A", "Region B", "Region C" };
152 #define REGION_DEFAULT 1 /* Index to region list. Actual region code is (1<<REGION_DEFAULT) */
153 #define LANGUAGE_DEFAULT ("eng")
155 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,0)
156 # define BLURAY_DEMUX
157 #endif
159 #ifndef BD_STREAM_TYPE_VIDEO_HEVC
160 # define BD_STREAM_TYPE_VIDEO_HEVC 0x24
161 #endif
163 #define BD_CLUSTER_SIZE 6144
164 #define BD_READ_SIZE (10 * BD_CLUSTER_SIZE)
166 /* Callbacks */
167 static int blurayOpen (vlc_object_t *);
168 static void blurayClose(vlc_object_t *);
170 vlc_module_begin ()
171 set_shortname(N_("Blu-ray"))
172 set_description(N_("Blu-ray Disc support (libbluray)"))
174 set_category(CAT_INPUT)
175 set_subcategory(SUBCAT_INPUT_ACCESS)
176 set_capability("access", 500)
177 add_bool("bluray-menu", true, BD_MENU_TEXT, BD_MENU_LONGTEXT, false)
178 add_string("bluray-region", ppsz_region_code[REGION_DEFAULT], BD_REGION_TEXT, BD_REGION_LONGTEXT, false)
179 change_string_list(ppsz_region_code, ppsz_region_code_text)
181 add_shortcut("bluray", "file")
183 set_callbacks(blurayOpen, blurayClose)
185 #ifdef BLURAY_DEMUX
186 /* demux module */
187 add_submodule()
188 set_description( "BluRay demuxer" )
189 set_category( CAT_INPUT )
190 set_subcategory( SUBCAT_INPUT_DEMUX )
191 set_capability( "demux", 5 )
192 set_callbacks( blurayOpen, blurayClose )
193 #endif
195 vlc_module_end ()
197 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
198 #define MAX_OVERLAY 2
200 typedef enum OverlayStatus {
201 Closed = 0,
202 ToDisplay, //Used to mark the overlay to be displayed the first time.
203 Displayed,
204 Outdated //used to update the overlay after it has been sent to the vout
205 } OverlayStatus;
207 typedef struct bluray_spu_updater_sys_t bluray_spu_updater_sys_t;
209 typedef struct bluray_overlay_t
211 vlc_mutex_t lock;
212 bool b_on_vout;
213 OverlayStatus status;
214 subpicture_region_t *p_regions;
215 int width, height;
217 /* pointer to last subpicture updater.
218 * used to disconnect this overlay from vout when:
219 * - the overlay is closed
220 * - vout is changed and this overlay is sent to the new vout
222 bluray_spu_updater_sys_t *p_updater;
223 } bluray_overlay_t;
225 typedef struct
227 BLURAY *bluray;
228 bool b_draining;
230 /* Titles */
231 unsigned int i_title;
232 unsigned int i_longest_title;
233 input_title_t **pp_title;
234 unsigned cur_title;
235 unsigned cur_seekpoint;
236 unsigned updates;
238 vlc_mutex_t pl_info_lock;
239 BLURAY_TITLE_INFO *p_pl_info;
240 const BLURAY_CLIP_INFO *p_clip_info;
241 enum
243 BD_CLIP_APP_TYPE_TS_MAIN_PATH_MOVIE = 1,
244 BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW = 2,
245 BD_CLIP_APP_TYPE_TS_MAIN_PATH_BROWSABLE_SLIDESHOW = 3,
246 BD_CLIP_APP_TYPE_TS_SUB_PATH_BROWSABLE_SLIDESHOW = 4,
247 BD_CLIP_APP_TYPE_TS_SUB_PATH_INTERACTIVE_MENU = 5,
248 BD_CLIP_APP_TYPE_TS_SUB_PATH_TEXT_SUBTITLE = 6,
249 BD_CLIP_APP_TYPE_TS_SUB_PATH_ELEMENTARY_STREAM_PATH = 7,
250 } clip_application_type;
252 /* Attachments */
253 int i_attachments;
254 input_attachment_t **attachments;
255 int i_cover_idx;
257 /* Meta information */
258 const META_DL *p_meta;
260 /* Menus */
261 bool b_fatal_error;
262 bool b_menu;
263 bool b_menu_open;
264 bool b_popup_available;
265 vlc_tick_t i_still_end_time;
266 struct
268 bluray_overlay_t *p_overlays[MAX_OVERLAY];
269 vlc_mutex_t lock; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
270 } bdj;
272 /* */
273 vlc_mouse_t oldmouse;
275 /* TS stream */
276 es_out_t *p_tf_out;
277 es_out_t *p_out;
278 bool b_spu_enable; /* enabled / disabled */
279 vlc_demux_chained_t *p_parser;
280 bool b_flushed;
281 bool b_pl_playing; /* true when playing playlist */
283 /* stream input */
284 vlc_mutex_t read_block_lock;
286 /* Used to store bluray disc path */
287 char *psz_bd_path;
288 } demux_sys_t;
291 * Local ES index storage
293 typedef struct
295 es_format_t fmt;
296 es_out_id_t *p_es;
297 int i_next_block_flags;
298 bool b_recyling;
299 bool b_restart_decoders_on_reuse;
300 } es_pair_t;
302 static bool es_pair_Add(vlc_array_t *p_array, const es_format_t *p_fmt,
303 es_out_id_t *p_es)
305 es_pair_t *p_pair = malloc(sizeof(*p_pair));
306 if (likely(p_pair != NULL))
308 p_pair->p_es = p_es;
309 p_pair->i_next_block_flags = 0;
310 p_pair->b_recyling = false;
311 p_pair->b_restart_decoders_on_reuse = true;
312 if(vlc_array_append(p_array, p_pair) != VLC_SUCCESS)
314 free(p_pair);
315 p_pair = NULL;
317 else
319 es_format_Init(&p_pair->fmt, p_fmt->i_cat, p_fmt->i_codec);
320 es_format_Copy(&p_pair->fmt, p_fmt);
323 return p_pair != NULL;
326 static void es_pair_Remove(vlc_array_t *p_array, es_pair_t *p_pair)
328 vlc_array_remove(p_array, vlc_array_index_of_item(p_array, p_pair));
329 es_format_Clean(&p_pair->fmt);
330 free(p_pair);
333 static es_pair_t *getEsPair(vlc_array_t *p_array,
334 bool (*match)(const es_pair_t *, const void *),
335 const void *param)
337 for (size_t i = 0; i < vlc_array_count(p_array); ++i)
339 es_pair_t *p_pair = vlc_array_item_at_index(p_array, i);
340 if(match(p_pair, param))
341 return p_pair;
343 return NULL;
346 static bool es_pair_compare_PID(const es_pair_t *p_pair, const void *p_pid)
348 return p_pair->fmt.i_id == *((const int *)p_pid);
351 static bool es_pair_compare_ES(const es_pair_t *p_pair, const void *p_es)
353 return p_pair->p_es == (const es_out_id_t *)p_es;
356 static bool es_pair_compare_Unused(const es_pair_t *p_pair, const void *priv)
358 VLC_UNUSED(priv);
359 return p_pair->b_recyling;
362 static es_pair_t *getEsPairByPID(vlc_array_t *p_array, int i_pid)
364 return getEsPair(p_array, es_pair_compare_PID, &i_pid);
367 static es_pair_t *getEsPairByES(vlc_array_t *p_array, const es_out_id_t *p_es)
369 return getEsPair(p_array, es_pair_compare_ES, p_es);
372 static es_pair_t *getUnusedEsPair(vlc_array_t *p_array)
374 return getEsPair(p_array, es_pair_compare_Unused, 0);
378 * Subpicture updater
380 struct bluray_spu_updater_sys_t
382 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
383 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
384 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
388 * cut the connection between vout and overlay.
389 * - called when vout is closed or overlay is closed.
390 * - frees bluray_spu_updater_sys_t when both sides have been closed.
392 static void unref_subpicture_updater(bluray_spu_updater_sys_t *p_sys)
394 vlc_mutex_lock(&p_sys->lock);
395 int refs = --p_sys->ref_cnt;
396 p_sys->p_overlay = NULL;
397 vlc_mutex_unlock(&p_sys->lock);
399 if (refs < 1) {
400 vlc_mutex_destroy(&p_sys->lock);
401 free(p_sys);
405 /* Get a 3 char code
406 * FIXME: partiallyy duplicated from src/input/es_out.c
408 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
410 const iso639_lang_t *pl;
411 char *psz_lang;
412 char *p;
414 psz_lang = var_CreateGetString( p_demux, psz_var );
415 if( !psz_lang )
416 return LANGUAGE_DEFAULT;
418 /* XXX: we will use only the first value
419 * (and ignore other ones in case of a list) */
420 if( ( p = strchr( psz_lang, ',' ) ) )
421 *p = '\0';
423 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
425 if( *psz_lang == '\0' )
426 continue;
427 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
428 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
429 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
430 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
431 break;
434 free( psz_lang );
436 if( pl->psz_eng_name != NULL )
437 return pl->psz_iso639_2T;
439 return LANGUAGE_DEFAULT;
442 /*****************************************************************************
443 * Local prototypes
444 *****************************************************************************/
445 static es_out_t *esOutNew(vlc_object_t*, es_out_t *, void *);
447 static int blurayControl(demux_t *, int, va_list);
448 static int blurayDemux(demux_t *);
450 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles);
451 static int bluraySetTitle(demux_t *p_demux, int i_title);
453 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
454 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
455 static void blurayCloseOverlay(demux_t *p_demux, int plane);
457 static void onMouseEvent(const vlc_mouse_t *mouse, void *user_data);
458 static void blurayRestartParser(demux_t *p_demux, bool, bool);
459 static void notifyDiscontinuityToParser( demux_sys_t *p_sys );
461 #define STILL_IMAGE_NOT_SET 0
462 #define STILL_IMAGE_INFINITE -1
464 #define CURRENT_TITLE p_sys->pp_title[p_sys->cur_title]
465 #define CUR_LENGTH CURRENT_TITLE->i_length
467 /* */
468 static void FindMountPoint(char **file)
470 char *device = *file;
471 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
472 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
473 * we look up the real device */
474 char *bd_device = realpath(device, NULL);
475 if (bd_device == NULL)
476 return;
478 struct stat st;
479 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
480 FILE *mtab = setmntent ("/proc/self/mounts", "r");
481 if (mtab) {
482 struct mntent *m, mbuf;
483 char buf [8192];
485 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
486 if (!strcmp (m->mnt_fsname, bd_device)) {
487 free(device);
488 *file = strdup(m->mnt_dir);
489 break;
492 endmntent (mtab);
495 free(bd_device);
497 #elif defined(__APPLE__)
498 struct stat st;
499 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
500 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
501 if (fs_count > 0) {
502 struct statfs mbuf[128];
503 getfsstat (mbuf, fs_count * sizeof(mbuf[0]), MNT_NOWAIT);
504 for (int i = 0; i < fs_count; ++i)
505 if (!strcmp (mbuf[i].f_mntfromname, device)) {
506 free(device);
507 *file = strdup(mbuf[i].f_mntonname);
508 return;
512 #else
513 # warning Disc device to mount point not implemented
514 VLC_UNUSED( device );
515 #endif
518 /*****************************************************************************
519 * BD-J background video
520 *****************************************************************************/
522 static void bluraySendBackgroundImage(vlc_object_t *p_obj,
523 es_out_t *p_dst_out,
524 es_out_id_t *p_es,
525 const es_format_t *p_fmt)
527 msg_Info(p_obj, "Start background");
529 block_t *p_block = block_Alloc(p_fmt->video.i_width * p_fmt->video.i_height *
530 p_fmt->video.i_bits_per_pixel / 8);
531 if (!p_block) {
532 msg_Err(p_obj, "Error allocating block for background video");
533 return;
536 // XXX TODO: what would be correct timestamp ???
537 p_block->i_dts = p_block->i_pts = vlc_tick_now() + VLC_TICK_FROM_MS(40);
539 uint8_t *p = p_block->p_buffer;
540 memset(p, 0, p_fmt->video.i_width * p_fmt->video.i_height);
541 p += p_fmt->video.i_width * p_fmt->video.i_height;
542 memset(p, 0x80, p_fmt->video.i_width * p_fmt->video.i_height / 2);
544 es_out_SetPCR(p_dst_out, p_block->i_dts - VLC_TICK_FROM_MS(40));
545 es_out_Control(p_dst_out, ES_OUT_SET_ES, p_es);
546 es_out_Send(p_dst_out, p_es, p_block);
547 es_out_Control( p_dst_out, ES_OUT_VOUT_SET_MOUSE_EVENT, p_es, onMouseEvent, p_obj );
548 es_out_SetPCR(p_dst_out, p_block->i_dts);
551 /*****************************************************************************
552 * cache current playlist (title) information
553 *****************************************************************************/
555 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
557 vlc_mutex_lock(&p_sys->pl_info_lock);
559 if (p_sys->p_pl_info) {
560 bd_free_title_info(p_sys->p_pl_info);
562 p_sys->p_pl_info = info;
563 p_sys->p_clip_info = NULL;
565 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
566 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
569 vlc_mutex_unlock(&p_sys->pl_info_lock);
572 /*****************************************************************************
573 * create input attachment for thumbnail
574 *****************************************************************************/
576 static void attachThumbnail(demux_t *p_demux)
578 demux_sys_t *p_sys = p_demux->p_sys;
580 if (!p_sys->p_meta)
581 return;
583 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
584 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
585 int64_t size;
586 void *data;
587 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
588 char psz_name[64];
589 input_attachment_t *p_attachment;
591 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
593 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
594 if (p_attachment) {
595 p_sys->i_cover_idx = p_sys->i_attachments;
596 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
599 free(data);
601 #endif
604 /*****************************************************************************
605 * stream input
606 *****************************************************************************/
608 static int probeStream(demux_t *p_demux)
610 /* input must be seekable */
611 bool b_canseek = false;
612 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
613 if (!b_canseek) {
614 return VLC_EGENERIC;
617 /* first sector(s) should be filled with zeros */
618 size_t i_peek;
619 const uint8_t *p_peek;
620 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
621 if( i_peek != 2048 ) {
622 return VLC_EGENERIC;
624 while (i_peek > 0) {
625 if (p_peek[ --i_peek ]) {
626 return VLC_EGENERIC;
630 return VLC_SUCCESS;
633 #ifdef BLURAY_DEMUX
634 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
636 demux_t *p_demux = (demux_t*)object;
637 demux_sys_t *p_sys = p_demux->p_sys;
638 int result = -1;
640 assert(p_demux->s != NULL);
642 vlc_mutex_lock(&p_sys->read_block_lock);
644 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
645 size_t req = (size_t)2048 * num_blocks;
646 ssize_t got;
648 got = vlc_stream_Read( p_demux->s, buf, req);
649 if (got < 0) {
650 msg_Err(p_demux, "read from lba %d failed", lba);
651 } else {
652 result = got / 2048;
654 } else {
655 msg_Err(p_demux, "seek to lba %d failed", lba);
658 vlc_mutex_unlock(&p_sys->read_block_lock);
660 return result;
662 #endif
664 /*****************************************************************************
665 * probing of local files
666 *****************************************************************************/
668 /* Descriptor Tag (ECMA 167, 3/7.2) */
669 static int decode_descriptor_tag(const uint8_t *buf)
671 uint16_t id;
672 uint8_t checksum = 0;
673 int i;
675 id = buf[0] | (buf[1] << 8);
677 /* calculate tag checksum */
678 for (i = 0; i < 4; i++) {
679 checksum = (uint8_t)(checksum + buf[i]);
681 for (i = 5; i < 16; i++) {
682 checksum = (uint8_t)(checksum + buf[i]);
685 if (checksum != buf[4]) {
686 return -1;
689 return id;
692 static int probeFile(const char *psz_name)
694 struct stat stat_info;
695 uint8_t peek[2048];
696 unsigned i;
697 int ret = VLC_EGENERIC;
698 int fd;
700 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
701 if (fd == -1) {
702 return VLC_EGENERIC;
705 if (fstat(fd, &stat_info) == -1) {
706 goto bailout;
708 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
709 goto bailout;
712 /* first sector should be filled with zeros */
713 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
714 goto bailout;
716 for (i = 0; i < sizeof(peek); i++) {
717 if (peek[ i ]) {
718 goto bailout;
722 /* Check AVDP tag checksum */
723 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
724 read(fd, peek, 16) != 16 ||
725 decode_descriptor_tag(peek) != 2) {
726 goto bailout;
729 ret = VLC_SUCCESS;
731 bailout:
732 vlc_close(fd);
733 return ret;
736 /*****************************************************************************
737 * blurayOpen: module init function
738 *****************************************************************************/
739 static int blurayOpen(vlc_object_t *object)
741 demux_t *p_demux = (demux_t*)object;
742 demux_sys_t *p_sys;
743 bool forced;
744 uint64_t i_init_pos = 0;
746 const char *error_msg = NULL;
747 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
749 if (p_demux->out == NULL)
750 return VLC_EGENERIC;
752 forced = !strncasecmp(p_demux->psz_url, "bluray:", 7);
754 if (p_demux->s) {
755 if (!strncasecmp(p_demux->psz_url, "file:", 5)) {
756 /* use access_demux for local files */
757 return VLC_EGENERIC;
760 if (probeStream(p_demux) != VLC_SUCCESS) {
761 return VLC_EGENERIC;
764 } else if (!forced) {
765 if (!p_demux->psz_filepath) {
766 return VLC_EGENERIC;
769 if (probeFile(p_demux->psz_filepath) != VLC_SUCCESS) {
770 return VLC_EGENERIC;
774 /* */
775 p_demux->p_sys = p_sys = vlc_obj_calloc(object, 1, sizeof(*p_sys));
776 if (unlikely(!p_sys))
777 return VLC_ENOMEM;
779 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
781 /* init demux info fields */
782 p_sys->updates = 0;
784 TAB_INIT(p_sys->i_title, p_sys->pp_title);
785 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
787 vlc_mouse_Init(&p_sys->oldmouse);
789 vlc_mutex_init(&p_sys->pl_info_lock);
790 vlc_mutex_init(&p_sys->bdj.lock);
791 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
793 /* request sub demuxers to skip continuity check as some split
794 file concatenation are just resetting counters... */
795 var_Create( p_demux, "ts-cc-check", VLC_VAR_BOOL );
796 var_SetBool( p_demux, "ts-cc-check", false );
797 var_Create( p_demux, "ts-standard", VLC_VAR_STRING );
798 var_SetString( p_demux, "ts-standard", "mpeg" );
799 var_Create( p_demux, "ts-pmtfix-waitdata", VLC_VAR_BOOL );
800 var_SetBool( p_demux, "ts-pmtfix-waitdata", false );
801 var_Create( p_demux, "ts-patfix", VLC_VAR_BOOL );
802 var_SetBool( p_demux, "ts-patfix", false );
803 var_Create( p_demux, "ts-pcr-offsetfix", VLC_VAR_BOOL );
804 var_SetBool( p_demux, "ts-pcr-offsetfix", false );
806 #ifdef DEBUG_BLURAY
807 p_bluray_DebugObject = VLC_OBJECT(p_demux);
808 bd_set_debug_mask(BLURAY_DEBUG_MASK);
809 bd_set_debug_handler(bluray_DebugHandler);
810 #endif
812 /* Open BluRay */
813 #ifdef BLURAY_DEMUX
814 if (p_demux->s) {
815 i_init_pos = vlc_stream_Tell(p_demux->s);
817 p_sys->bluray = bd_init();
818 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
819 bd_close(p_sys->bluray);
820 p_sys->bluray = NULL;
822 } else
823 #endif
825 if (!p_demux->psz_filepath) {
826 /* no path provided (bluray://). use default DVD device. */
827 p_sys->psz_bd_path = var_InheritString(object, "dvd");
828 } else {
829 /* store current bd path */
830 p_sys->psz_bd_path = strdup(p_demux->psz_filepath);
833 /* If we're passed a block device, try to convert it to the mount point. */
834 FindMountPoint(&p_sys->psz_bd_path);
836 p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
838 if (!p_sys->bluray) {
839 goto error;
842 /* Warning the user about AACS/BD+ */
843 const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
845 /* Is it a bluray? */
846 if (!disc_info->bluray_detected) {
847 if (forced) {
848 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
850 goto error;
853 msg_Info(p_demux, "First play: %i, Top menu: %i\n"
854 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
855 disc_info->first_play_supported, disc_info->top_menu_supported,
856 disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
857 disc_info->num_unsupported_titles);
859 /* AACS */
860 if (disc_info->aacs_detected) {
861 msg_Dbg(p_demux, "Disc is using AACS");
862 if (!disc_info->libaacs_detected)
863 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
864 ", and your system does not have it."));
865 if (!disc_info->aacs_handled) {
866 if (disc_info->aacs_error_code) {
867 switch (disc_info->aacs_error_code) {
868 case BD_AACS_CORRUPTED_DISC:
869 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
870 case BD_AACS_NO_CONFIG:
871 BLURAY_ERROR(_("Missing AACS configuration file!"));
872 case BD_AACS_NO_PK:
873 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
874 case BD_AACS_NO_CERT:
875 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
876 case BD_AACS_CERT_REVOKED:
877 BLURAY_ERROR(_("AACS Host certificate revoked."));
878 case BD_AACS_MMC_FAILED:
879 BLURAY_ERROR(_("AACS MMC failed."));
885 /* BD+ */
886 if (disc_info->bdplus_detected) {
887 msg_Dbg(p_demux, "Disc is using BD+");
888 if (!disc_info->libbdplus_detected)
889 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
890 ", and your system does not have it."));
891 if (!disc_info->bdplus_handled)
892 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
893 "Missing configuration?"));
896 /* set player region code */
897 char *psz_region = var_InheritString(p_demux, "bluray-region");
898 unsigned int region = psz_region ? (psz_region[0] - 'A') : REGION_DEFAULT;
899 free(psz_region);
900 bd_set_player_setting(p_sys->bluray, BLURAY_PLAYER_SETTING_REGION_CODE, 1<<region);
902 /* set preferred languages */
903 const char *psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
904 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG, psz_code);
905 psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
906 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG, psz_code);
907 psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
908 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_MENU_LANG, psz_code);
910 /* Get disc metadata */
911 p_sys->p_meta = bd_get_meta(p_sys->bluray);
912 if (!p_sys->p_meta)
913 msg_Warn(p_demux, "Failed to get meta info.");
915 p_sys->i_cover_idx = -1;
916 attachThumbnail(p_demux);
918 p_sys->b_menu = var_InheritBool(p_demux, "bluray-menu");
920 /* Check BD-J capability */
921 if (p_sys->b_menu && disc_info->bdj_detected && !disc_info->bdj_handled) {
922 msg_Err(p_demux, "BD-J menus not supported. Playing without menus. "
923 "BD-J support: %d, JVM found: %d, JVM usable: %d",
924 disc_info->bdj_supported, disc_info->libjvm_detected, disc_info->bdj_handled);
925 vlc_dialog_display_error(p_demux, _("Java required"),
926 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
927 !disc_info->libjvm_detected ? _("Java was not found on your system.") : "");
928 p_sys->b_menu = false;
931 /* Get titles and chapters */
932 blurayInitTitles(p_demux, disc_info->num_hdmv_titles + disc_info->num_bdj_titles + 1/*Top Menu*/ + 1/*First Play*/);
935 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
937 bd_get_event(p_sys->bluray, NULL);
939 /* Registering overlay event handler */
940 bd_register_overlay_proc(p_sys->bluray, p_demux, blurayOverlayProc);
942 if (p_sys->b_menu) {
944 /* Register ARGB overlay handler for BD-J */
945 if (disc_info->num_bdj_titles)
946 bd_register_argb_overlay_proc(p_sys->bluray, p_demux, blurayArgbOverlayProc, NULL);
948 /* libbluray will start playback from "First-Title" title */
949 if (bd_play(p_sys->bluray) == 0)
950 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
952 } else {
953 /* set start title number */
954 if (bluraySetTitle(p_demux, p_sys->i_longest_title) != VLC_SUCCESS) {
955 msg_Err(p_demux, "Could not set the title %d", p_sys->i_longest_title);
956 goto error;
960 p_sys->p_tf_out = timestamps_filter_es_out_New(p_demux->out);
961 if(unlikely(!p_sys->p_tf_out))
962 goto error;
964 p_sys->p_out = esOutNew(VLC_OBJECT(p_demux), p_sys->p_tf_out, p_demux);
965 if (unlikely(p_sys->p_out == NULL))
966 goto error;
968 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
969 if (!p_sys->p_parser) {
970 msg_Err(p_demux, "Failed to create TS demuxer");
971 goto error;
974 p_demux->pf_control = blurayControl;
975 p_demux->pf_demux = blurayDemux;
977 return VLC_SUCCESS;
979 error:
980 if (error_msg)
981 vlc_dialog_display_error(p_demux, _("Blu-ray error"), "%s", error_msg);
982 blurayClose(object);
984 if (p_demux->s != NULL) {
985 /* restore stream position */
986 if (vlc_stream_Seek(p_demux->s, i_init_pos) != VLC_SUCCESS) {
987 msg_Err(p_demux, "Failed to seek back to stream start");
988 return VLC_ETIMEOUT;
992 return VLC_EGENERIC;
993 #undef BLURAY_ERROR
997 /*****************************************************************************
998 * blurayClose: module destroy function
999 *****************************************************************************/
1000 static void blurayClose(vlc_object_t *object)
1002 demux_t *p_demux = (demux_t*)object;
1003 demux_sys_t *p_sys = p_demux->p_sys;
1005 setTitleInfo(p_sys, NULL);
1008 * Close libbluray first.
1009 * This will close all the overlays before we release p_vout
1010 * bd_close(NULL) can crash
1012 if (p_sys->bluray) {
1013 bd_close(p_sys->bluray);
1016 vlc_mutex_lock(&p_sys->bdj.lock);
1017 for(int i = 0; i < MAX_OVERLAY; i++)
1018 blurayCloseOverlay(p_demux, i);
1019 vlc_mutex_unlock(&p_sys->bdj.lock);
1021 if (p_sys->p_parser)
1022 vlc_demux_chained_Delete(p_sys->p_parser);
1024 if (p_sys->p_out != NULL)
1025 es_out_Delete(p_sys->p_out);
1026 if(p_sys->p_tf_out)
1027 timestamps_filter_es_out_Delete(p_sys->p_tf_out);
1029 /* Titles */
1030 for (unsigned int i = 0; i < p_sys->i_title; i++)
1031 vlc_input_title_Delete(p_sys->pp_title[i]);
1032 TAB_CLEAN(p_sys->i_title, p_sys->pp_title);
1034 for (int i = 0; i < p_sys->i_attachments; i++)
1035 vlc_input_attachment_Delete(p_sys->attachments[i]);
1036 TAB_CLEAN(p_sys->i_attachments, p_sys->attachments);
1038 vlc_mutex_destroy(&p_sys->pl_info_lock);
1039 vlc_mutex_destroy(&p_sys->bdj.lock);
1040 vlc_mutex_destroy(&p_sys->read_block_lock);
1042 free(p_sys->psz_bd_path);
1045 /*****************************************************************************
1046 * Elementary streams handling
1047 *****************************************************************************/
1048 static uint8_t blurayGetStreamsUnlocked(demux_sys_t *p_sys,
1049 int i_stream_type,
1050 BLURAY_STREAM_INFO **pp_streams)
1052 if(!p_sys->p_clip_info)
1053 return 0;
1055 switch(i_stream_type)
1057 case BD_EVENT_AUDIO_STREAM:
1058 *pp_streams = p_sys->p_clip_info->audio_streams;
1059 return p_sys->p_clip_info->audio_stream_count;
1060 case BD_EVENT_PG_TEXTST_STREAM:
1061 *pp_streams = p_sys->p_clip_info->pg_streams;
1062 return p_sys->p_clip_info->pg_stream_count;
1063 default:
1064 return 0;
1068 static BLURAY_STREAM_INFO * blurayGetStreamInfoUnlocked(demux_sys_t *p_sys,
1069 int i_stream_type,
1070 uint8_t i_stream_idx)
1072 BLURAY_STREAM_INFO *p_streams = NULL;
1073 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_stream_type, &p_streams);
1074 if(i_stream_idx < i_streams_count)
1075 return &p_streams[i_stream_idx];
1076 else
1077 return NULL;
1080 static BLURAY_STREAM_INFO * blurayGetStreamInfoByPIDUnlocked(demux_sys_t *p_sys,
1081 int i_pid)
1083 for(int i_type=BD_EVENT_AUDIO_STREAM; i_type<=BD_EVENT_SECONDARY_VIDEO_STREAM; i_type++)
1085 BLURAY_STREAM_INFO *p_streams;
1086 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_type, &p_streams);
1087 for(uint8_t i=0; i<i_streams_count; i++)
1089 if(p_streams[i].pid == i_pid)
1090 return &p_streams[i];
1093 return NULL;
1096 static void setStreamLang(demux_sys_t *p_sys, es_format_t *p_fmt)
1098 vlc_mutex_lock(&p_sys->pl_info_lock);
1100 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoByPIDUnlocked(p_sys, p_fmt->i_id);
1101 if(p_stream)
1103 free(p_fmt->psz_language);
1104 p_fmt->psz_language = strndup((const char *)p_stream->lang, 3);
1107 vlc_mutex_unlock(&p_sys->pl_info_lock);
1110 static int blurayGetStreamPID(demux_sys_t *p_sys, int i_stream_type, uint8_t i_stream_idx)
1112 vlc_mutex_lock(&p_sys->pl_info_lock);
1114 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoUnlocked(p_sys,
1115 i_stream_type,
1116 i_stream_idx);
1117 int i_pid = p_stream ? p_stream->pid : -1;
1119 vlc_mutex_unlock(&p_sys->pl_info_lock);
1121 return i_pid;
1124 /*****************************************************************************
1125 * bluray fake es_out
1126 *****************************************************************************/
1127 typedef struct
1129 es_out_t *p_dst_out;
1130 vlc_object_t *p_obj;
1131 vlc_array_t es; /* es_pair_t */
1132 bool b_entered_recycling;
1133 bool b_restart_decoders_on_reuse;
1134 void *priv;
1135 bool b_discontinuity;
1136 bool b_disable_output;
1137 bool b_lowdelay;
1138 vlc_mutex_t lock;
1139 struct
1141 int i_audio_pid; /* Selected audio stream. -1 if default */
1142 int i_video_pid;
1143 int i_spu_pid; /* Selected spu stream. -1 if default */
1144 } selected;
1145 struct
1147 es_out_id_t *p_video_es;
1148 int channels[MAX_OVERLAY];
1149 } overlay;
1150 es_out_t es_out;
1151 } bluray_esout_priv_t;
1153 enum
1155 BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID = ES_OUT_PRIVATE_START,
1156 BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID,
1157 BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY,
1158 BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT,
1159 BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT,
1160 BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY,
1161 BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY,
1162 BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY,
1163 BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY,
1164 BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS,
1167 static es_out_id_t *bluray_esOutAddUnlocked(bluray_esout_priv_t *esout_priv,
1168 const es_format_t *p_fmt)
1170 demux_t *p_demux = esout_priv->priv;
1171 demux_sys_t *p_sys = p_demux->p_sys;
1172 es_format_t fmt;
1173 bool b_select = false;
1175 es_format_Copy(&fmt, p_fmt);
1177 switch (fmt.i_cat) {
1178 case VIDEO_ES:
1179 if(esout_priv->b_lowdelay)
1181 fmt.video.i_frame_rate = 1; fmt.video.i_frame_rate_base = 1;
1182 fmt.b_packetized = true;
1184 if (esout_priv->selected.i_video_pid != -1 && esout_priv->selected.i_video_pid != p_fmt->i_id)
1185 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1186 b_select = (p_fmt->i_id == 0x1011);
1187 break;
1188 case AUDIO_ES:
1189 if (esout_priv->selected.i_audio_pid != -1) {
1190 if (esout_priv->selected.i_audio_pid == p_fmt->i_id)
1191 b_select = true;
1192 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1194 setStreamLang(p_sys, &fmt);
1195 break ;
1196 case SPU_ES:
1197 if (esout_priv->selected.i_spu_pid != -1) {
1198 if (esout_priv->selected.i_spu_pid == p_fmt->i_id)
1199 b_select = p_sys->b_spu_enable;
1200 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1202 setStreamLang(p_sys, &fmt);
1203 break ;
1204 default:
1208 es_out_id_t *p_es = NULL;
1209 if (p_fmt->i_id >= 0) {
1210 /* Ensure we are not overriding anything */
1211 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, p_fmt->i_id);
1212 if (p_pair == NULL)
1214 msg_Info(p_demux, "Adding ES %d select %d", p_fmt->i_id, b_select);
1215 p_es = es_out_Add(esout_priv->p_dst_out, &fmt);
1216 es_pair_Add(&esout_priv->es, &fmt, p_es);
1218 else
1220 msg_Info(p_demux, "Reusing ES %d", p_fmt->i_id);
1221 p_pair->b_recyling = false;
1222 p_es = p_pair->p_es;
1223 if(!es_format_IsSimilar(p_fmt, &p_pair->fmt) ||
1224 p_fmt->b_packetized != p_pair->fmt.b_packetized ||
1225 esout_priv->b_restart_decoders_on_reuse)
1226 es_out_Control(esout_priv->p_dst_out, ES_OUT_SET_ES_FMT, p_pair->p_es, &fmt);
1227 es_format_Clean(&p_pair->fmt);
1228 es_format_Copy(&p_pair->fmt, &fmt);
1230 if (b_select)
1231 es_out_Control(esout_priv->p_dst_out, ES_OUT_SET_ES, p_es);
1234 if (p_es && fmt.i_cat == VIDEO_ES && b_select)
1236 es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_SET_MOUSE_EVENT, p_es,
1237 onMouseEvent, p_demux);
1238 esout_priv->overlay.p_video_es = p_es;
1241 es_format_Clean(&fmt);
1243 return p_es;
1246 static es_out_id_t *bluray_esOutAdd(es_out_t *p_out, const es_format_t *p_fmt)
1248 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1250 vlc_mutex_lock(&esout_priv->lock);
1251 es_out_id_t *p_es = bluray_esOutAddUnlocked(esout_priv, p_fmt);
1252 vlc_mutex_unlock(&esout_priv->lock);
1254 return p_es;
1257 static void bluray_esOutDeleteNonReusedESUnlocked(es_out_t *p_out)
1259 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1261 if(!esout_priv->b_entered_recycling)
1262 return;
1263 esout_priv->b_entered_recycling = false;
1264 esout_priv->b_restart_decoders_on_reuse = true;
1266 es_pair_t *p_pair;
1267 while((p_pair = getUnusedEsPair(&esout_priv->es)))
1269 msg_Info(esout_priv->p_obj, "Trashing unused ES %d", p_pair->fmt.i_id);
1271 if(esout_priv->overlay.p_video_es == p_pair->p_es)
1272 esout_priv->overlay.p_video_es = NULL;
1274 es_out_Del(esout_priv->p_dst_out, p_pair->p_es);
1276 es_pair_Remove(&esout_priv->es, p_pair);
1280 static int bluray_esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1282 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1283 vlc_mutex_lock(&esout_priv->lock);
1285 bluray_esOutDeleteNonReusedESUnlocked(p_out);
1287 if(esout_priv->b_discontinuity)
1288 esout_priv->b_discontinuity = false;
1290 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1291 if(p_pair && p_pair->i_next_block_flags)
1293 p_block->i_flags |= p_pair->i_next_block_flags;
1294 p_pair->i_next_block_flags = 0;
1296 if(esout_priv->b_disable_output)
1298 block_Release(p_block);
1299 p_block = NULL;
1301 vlc_mutex_unlock(&esout_priv->lock);
1302 return (p_block) ? es_out_Send(esout_priv->p_dst_out, p_es, p_block) : VLC_SUCCESS;
1305 static void bluray_esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1307 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1308 vlc_mutex_lock(&esout_priv->lock);
1310 if(esout_priv->b_discontinuity)
1311 esout_priv->b_discontinuity = false;
1313 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1314 if (p_pair)
1316 p_pair->b_recyling = true;
1317 esout_priv->b_entered_recycling = true;
1320 vlc_mutex_unlock(&esout_priv->lock);
1323 static int bluray_esOutControl(es_out_t *p_out, int i_query, va_list args)
1325 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1326 int i_ret;
1327 vlc_mutex_lock(&esout_priv->lock);
1329 if(esout_priv->b_disable_output &&
1330 i_query < ES_OUT_PRIVATE_START)
1332 vlc_mutex_unlock(&esout_priv->lock);
1333 return VLC_EGENERIC;
1336 if(esout_priv->b_discontinuity)
1337 esout_priv->b_discontinuity = false;
1339 switch(i_query)
1341 case BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID:
1342 case BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID:
1344 bool b_select = (i_query == BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID);
1345 const int i_bluray_stream_type = va_arg(args, int);
1346 const int i_pid = va_arg(args, int);
1347 switch(i_bluray_stream_type)
1349 case BD_EVENT_AUDIO_STREAM:
1350 esout_priv->selected.i_audio_pid = i_pid;
1351 break;
1352 case BD_EVENT_PG_TEXTST_STREAM:
1353 esout_priv->selected.i_spu_pid = i_pid;
1354 break;
1355 default:
1356 break;
1359 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, i_pid);
1360 if(unlikely(!p_pair))
1362 vlc_mutex_unlock(&esout_priv->lock);
1363 return VLC_EGENERIC;
1366 i_ret = es_out_Control(esout_priv->p_dst_out,
1367 b_select ? ES_OUT_SET_ES : ES_OUT_UNSET_ES,
1368 p_pair->p_es);
1369 } break;
1371 case BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY:
1373 esout_priv->b_discontinuity = true;
1374 i_ret = VLC_SUCCESS;
1375 } break;
1377 case BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS:
1379 esout_priv->b_restart_decoders_on_reuse = !va_arg(args, int);
1380 i_ret = VLC_SUCCESS;
1381 } break;
1383 case BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT:
1384 case BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT:
1386 esout_priv->b_disable_output = (i_query == BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
1387 i_ret = VLC_SUCCESS;
1388 } break;
1390 case BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY:
1391 case BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY:
1393 esout_priv->b_lowdelay = (i_query == BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY);
1394 i_ret = VLC_SUCCESS;
1395 } break;
1397 case BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY:
1399 int i_plane = va_arg(args, int);
1400 subpicture_t *p_pic = va_arg(args, subpicture_t *);
1401 if(!esout_priv->overlay.p_video_es)
1403 es_format_t fmt;
1404 es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_I420);
1405 video_format_Setup(&fmt.video, VLC_CODEC_I420,
1406 1920, 1080, 1920, 1080, 1, 1);
1407 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1408 fmt.i_id = 0x1011;
1409 fmt.i_group = 1;
1410 fmt.video.i_frame_rate = 1; fmt.video.i_frame_rate_base = 1;
1411 fmt.b_packetized = true;
1412 esout_priv->overlay.p_video_es = bluray_esOutAddUnlocked(esout_priv, &fmt);
1413 if(esout_priv->overlay.p_video_es)
1415 bluraySendBackgroundImage(esout_priv->p_obj,
1416 esout_priv->p_dst_out,
1417 esout_priv->overlay.p_video_es,
1418 &fmt);
1420 es_format_Clean(&fmt);
1423 if(esout_priv->overlay.p_video_es && i_plane < MAX_OVERLAY)
1425 i_ret = es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_ADD_OVERLAY,
1426 esout_priv->overlay.p_video_es, p_pic,
1427 &esout_priv->overlay.channels[i_plane]);
1429 else
1431 i_ret = VLC_EGENERIC;
1433 break;
1436 case BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY:
1438 int i_plane = va_arg(args, int);
1439 if(esout_priv->overlay.p_video_es &&
1440 i_plane < MAX_OVERLAY &&
1441 esout_priv->overlay.channels[i_plane] != VOUT_SPU_CHANNEL_INVALID)
1443 i_ret = es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_FLUSH_OVERLAY,
1444 esout_priv->overlay.p_video_es,
1445 esout_priv->overlay.channels[i_plane]);
1446 esout_priv->overlay.channels[i_plane] = VOUT_SPU_CHANNEL_INVALID;
1448 else
1450 assert(esout_priv->overlay.channels[i_plane] == VOUT_SPU_CHANNEL_INVALID);
1451 i_ret = VLC_EGENERIC;
1453 break;
1456 case ES_OUT_SET_ES_DEFAULT:
1457 case ES_OUT_SET_ES:
1458 case ES_OUT_UNSET_ES:
1459 case ES_OUT_SET_ES_STATE:
1460 i_ret = VLC_EGENERIC;
1461 break;
1463 case ES_OUT_GET_ES_STATE:
1464 va_arg(args, es_out_id_t *);
1465 *va_arg(args, bool *) = true;
1466 i_ret = VLC_SUCCESS;
1467 break;
1469 default:
1470 i_ret = es_out_vaControl(esout_priv->p_dst_out, i_query, args);
1471 break;
1473 vlc_mutex_unlock(&esout_priv->lock);
1474 return i_ret;
1477 static void bluray_esOutDestroy(es_out_t *p_out)
1479 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1481 for (size_t i = 0; i < vlc_array_count(&esout_priv->es); ++i)
1482 free(vlc_array_item_at_index(&esout_priv->es, i));
1483 vlc_array_clear(&esout_priv->es);
1484 vlc_mutex_destroy(&esout_priv->lock);
1485 free(esout_priv);
1488 static const struct es_out_callbacks bluray_esOutCallbacks = {
1489 .add = bluray_esOutAdd,
1490 .send = bluray_esOutSend,
1491 .del = bluray_esOutDel,
1492 .control = bluray_esOutControl,
1493 .destroy = bluray_esOutDestroy,
1496 static es_out_t *esOutNew(vlc_object_t *p_obj, es_out_t *p_dst_out, void *priv)
1498 bluray_esout_priv_t *esout_priv = malloc(sizeof(*esout_priv));
1499 if (unlikely(esout_priv == NULL))
1500 return NULL;
1502 vlc_array_init(&esout_priv->es);
1503 esout_priv->p_dst_out = p_dst_out;
1504 esout_priv->p_obj = p_obj;
1505 esout_priv->priv = priv;
1506 esout_priv->es_out.cbs = &bluray_esOutCallbacks;
1507 esout_priv->b_discontinuity = false;
1508 esout_priv->b_disable_output = false;
1509 esout_priv->b_entered_recycling = false;
1510 esout_priv->b_restart_decoders_on_reuse = true;
1511 esout_priv->b_lowdelay = false;
1512 esout_priv->selected.i_audio_pid = -1;
1513 esout_priv->selected.i_video_pid = -1;
1514 esout_priv->selected.i_spu_pid = -1;
1515 esout_priv->overlay.p_video_es = NULL;
1516 for(size_t i=0; i<MAX_OVERLAY; i++)
1517 esout_priv->overlay.channels[i] = VOUT_SPU_CHANNEL_INVALID;
1518 vlc_mutex_init(&esout_priv->lock);
1519 return &esout_priv->es_out;
1522 /*****************************************************************************
1523 * subpicture_updater_t functions:
1524 *****************************************************************************/
1526 static bluray_overlay_t *updater_lock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1528 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1529 vlc_mutex_lock(&p_upd_sys->lock);
1531 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1532 if (ov) {
1533 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1534 vlc_mutex_lock(&ov->lock);
1535 return ov;
1538 /* overlay has been closed */
1539 vlc_mutex_unlock(&p_upd_sys->lock);
1540 return NULL;
1543 static void updater_unlock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1545 assert (p_upd_sys->p_overlay);
1547 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1548 vlc_mutex_unlock(&p_upd_sys->lock);
1551 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1552 bool b_fmt_src, const video_format_t *p_fmt_src,
1553 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1554 vlc_tick_t i_ts)
1556 VLC_UNUSED(b_fmt_src);
1557 VLC_UNUSED(b_fmt_dst);
1558 VLC_UNUSED(p_fmt_src);
1559 VLC_UNUSED(p_fmt_dst);
1560 VLC_UNUSED(i_ts);
1562 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1563 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1565 if (!p_overlay) {
1566 return 1;
1569 int res = p_overlay->status == Outdated;
1571 updater_unlock_overlay(p_upd_sys);
1573 return res;
1576 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1577 const video_format_t *p_fmt_src,
1578 const video_format_t *p_fmt_dst,
1579 vlc_tick_t i_ts)
1581 VLC_UNUSED(p_fmt_src);
1582 VLC_UNUSED(p_fmt_dst);
1583 VLC_UNUSED(i_ts);
1584 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1585 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1587 if (!p_overlay) {
1588 return;
1592 * When this function is called, all p_subpic regions are gone.
1593 * We need to duplicate our regions (stored internaly) to this subpic.
1595 subpicture_region_t *p_src = p_overlay->p_regions;
1596 if (!p_src) {
1597 updater_unlock_overlay(p_upd_sys);
1598 return;
1601 subpicture_region_t **p_dst = &p_subpic->p_region;
1602 while (p_src != NULL) {
1603 *p_dst = subpicture_region_Copy(p_src);
1604 if (*p_dst == NULL)
1605 break;
1606 p_dst = &(*p_dst)->p_next;
1607 p_src = p_src->p_next;
1609 if (*p_dst != NULL)
1610 (*p_dst)->p_next = NULL;
1611 p_overlay->status = Displayed;
1613 updater_unlock_overlay(p_upd_sys);
1616 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1618 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1619 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1621 if (p_overlay) {
1622 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1623 p_overlay->status = ToDisplay;
1624 p_overlay->b_on_vout = false;
1625 updater_unlock_overlay(p_upd_sys);
1628 unref_subpicture_updater(p_upd_sys);
1631 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1633 bluray_spu_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1634 if (unlikely(p_upd_sys == NULL)) {
1635 return NULL;
1638 p_upd_sys->p_overlay = p_ov;
1640 subpicture_updater_t updater = {
1641 .pf_validate = subpictureUpdaterValidate,
1642 .pf_update = subpictureUpdaterUpdate,
1643 .pf_destroy = subpictureUpdaterDestroy,
1644 .p_sys = p_upd_sys,
1647 subpicture_t *p_pic = subpicture_New(&updater);
1648 if (p_pic == NULL) {
1649 free(p_upd_sys);
1650 return NULL;
1653 p_pic->i_original_picture_width = p_ov->width;
1654 p_pic->i_original_picture_height = p_ov->height;
1655 p_pic->b_absolute = true;
1657 vlc_mutex_init(&p_upd_sys->lock);
1658 p_upd_sys->ref_cnt = 2;
1660 p_ov->p_updater = p_upd_sys;
1662 return p_pic;
1665 /*****************************************************************************
1666 * User input events:
1667 *****************************************************************************/
1668 static void onMouseEvent(const vlc_mouse_t *newmouse, void *user_data)
1670 demux_t *p_demux = user_data;
1671 demux_sys_t *p_sys = p_demux->p_sys;
1673 if (!newmouse) {
1674 vlc_mouse_Init(&p_sys->oldmouse);
1675 return;
1678 if (vlc_mouse_HasMoved(&p_sys->oldmouse, newmouse))
1679 bd_mouse_select(p_sys->bluray, -1, newmouse->i_x, newmouse->i_y);
1681 if (vlc_mouse_HasPressed( &p_sys->oldmouse, newmouse, MOUSE_BUTTON_LEFT))
1682 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1683 p_sys->oldmouse = *newmouse;
1686 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1688 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1689 return VLC_EGENERIC;
1691 return VLC_SUCCESS;
1694 /*****************************************************************************
1695 * libbluray overlay handling:
1696 *****************************************************************************/
1698 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1700 demux_sys_t *p_sys = p_demux->p_sys;
1701 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1703 if (ov != NULL) {
1705 /* drop overlay from vout */
1706 if (ov->p_updater) {
1707 unref_subpicture_updater(ov->p_updater);
1710 /* no references to this overlay exist in vo anymore */
1711 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY, plane);
1713 vlc_mutex_destroy(&ov->lock);
1714 subpicture_region_ChainDelete(ov->p_regions);
1715 free(ov);
1717 p_sys->bdj.p_overlays[plane] = NULL;
1722 * Mark the overlay as "ToDisplay" status.
1723 * This will not send the overlay to the vout instantly, as the vout
1724 * may not be acquired (not acquirable) yet.
1725 * If is has already been acquired, the overlay has already been sent to it,
1726 * therefore, we only flag the overlay as "Outdated"
1728 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1730 demux_sys_t *p_sys = p_demux->p_sys;
1731 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1734 * If the overlay is already displayed, mark the picture as outdated.
1735 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1737 vlc_mutex_lock(&ov->lock);
1738 if (ov->status >= Displayed && ov->b_on_vout) {
1739 ov->status = Outdated;
1740 vlc_mutex_unlock(&ov->lock);
1741 return;
1745 * Mark the overlay as available, but don't display it right now.
1746 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1747 * the overlay is computed
1749 ov->status = ToDisplay;
1750 vlc_mutex_unlock(&ov->lock);
1753 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1755 demux_sys_t *p_sys = p_demux->p_sys;
1757 assert(p_sys->bdj.p_overlays[plane] == NULL);
1759 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1760 if (unlikely(ov == NULL))
1761 return;
1763 ov->width = width;
1764 ov->height = height;
1765 ov->b_on_vout = false;
1767 vlc_mutex_init(&ov->lock);
1769 p_sys->bdj.p_overlays[plane] = ov;
1773 * Destroy every regions in the subpicture.
1774 * This is done in two steps:
1775 * - Wiping our private regions list
1776 * - Flagging the overlay as outdated, so the changes are replicated from
1777 * the subpicture_updater_t::pf_update
1778 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1780 static void blurayClearOverlay(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];
1785 vlc_mutex_lock(&ov->lock);
1787 subpicture_region_ChainDelete(ov->p_regions);
1788 ov->p_regions = NULL;
1789 ov->status = Outdated;
1791 vlc_mutex_unlock(&ov->lock);
1795 * This will draw to the overlay by adding a region to our region list
1796 * This will have to be copied to the subpicture used to render the overlay.
1798 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1800 demux_sys_t *p_sys = p_demux->p_sys;
1803 * Compute a subpicture_region_t.
1804 * It will be copied and sent to the vout later.
1806 vlc_mutex_lock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1808 /* Find a region to update */
1809 subpicture_region_t **pp_reg = &p_sys->bdj.p_overlays[ov->plane]->p_regions;
1810 subpicture_region_t *p_reg = p_sys->bdj.p_overlays[ov->plane]->p_regions;
1811 subpicture_region_t *p_last = NULL;
1812 while (p_reg != NULL) {
1813 p_last = p_reg;
1814 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1815 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1816 break;
1817 pp_reg = &p_reg->p_next;
1818 p_reg = p_reg->p_next;
1821 if (!ov->img) {
1822 if (p_reg) {
1823 /* drop region */
1824 *pp_reg = p_reg->p_next;
1825 subpicture_region_Delete(p_reg);
1827 vlc_mutex_unlock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1828 return;
1831 /* If there is no region to update, create a new one. */
1832 if (!p_reg) {
1833 video_format_t fmt;
1834 video_format_Init(&fmt, 0);
1835 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1837 p_reg = subpicture_region_New(&fmt);
1838 p_reg->i_x = ov->x;
1839 p_reg->i_y = ov->y;
1840 /* Append it to our list. */
1841 if (p_last != NULL)
1842 p_last->p_next = p_reg;
1843 else /* If we don't have a last region, then our list empty */
1844 p_sys->bdj.p_overlays[ov->plane]->p_regions = p_reg;
1847 /* Now we can update the region, regardless it's an update or an insert */
1848 const BD_PG_RLE_ELEM *img = ov->img;
1849 for (int y = 0; y < ov->h; y++)
1850 for (int x = 0; x < ov->w;) {
1851 plane_t *p = &p_reg->p_picture->p[0];
1852 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1853 x += img->len;
1854 img++;
1857 if (ov->palette) {
1858 p_reg->fmt.p_palette->i_entries = 256;
1859 for (int i = 0; i < 256; ++i) {
1860 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1861 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1862 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1863 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1867 vlc_mutex_unlock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1869 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1873 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1875 demux_t *p_demux = (demux_t*)ptr;
1876 demux_sys_t *p_sys = p_demux->p_sys;
1878 vlc_mutex_lock(&p_sys->bdj.lock);
1880 if (!overlay) {
1881 msg_Info(p_demux, "Closing overlays.");
1882 for (int i = 0; i < MAX_OVERLAY; i++)
1883 blurayCloseOverlay(p_demux, i);
1884 vlc_mutex_unlock(&p_sys->bdj.lock);
1885 return;
1888 switch (overlay->cmd) {
1889 case BD_OVERLAY_INIT:
1890 msg_Info(p_demux, "Initializing overlay");
1891 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1892 break;
1893 case BD_OVERLAY_CLOSE:
1894 blurayClearOverlay(p_demux, overlay->plane);
1895 blurayCloseOverlay(p_demux, overlay->plane);
1896 break;
1897 case BD_OVERLAY_CLEAR:
1898 blurayClearOverlay(p_demux, overlay->plane);
1899 break;
1900 case BD_OVERLAY_FLUSH:
1901 blurayActivateOverlay(p_demux, overlay->plane);
1902 break;
1903 case BD_OVERLAY_DRAW:
1904 case BD_OVERLAY_WIPE:
1905 blurayDrawOverlay(p_demux, overlay);
1906 break;
1907 default:
1908 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
1909 break;
1912 vlc_mutex_unlock(&p_sys->bdj.lock);
1916 * ARGB overlay (BD-J)
1918 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
1920 demux_sys_t *p_sys = p_demux->p_sys;
1922 blurayInitOverlay(p_demux, plane, width, height);
1924 if (!p_sys->bdj.p_overlays[plane]->p_regions) {
1925 video_format_t fmt;
1926 video_format_Init(&fmt, 0);
1927 video_format_Setup(&fmt, VLC_CODEC_RGBA, width, height, width, height, 1, 1);
1929 p_sys->bdj.p_overlays[plane]->p_regions = subpicture_region_New(&fmt);
1933 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
1935 demux_sys_t *p_sys = p_demux->p_sys;
1937 vlc_mutex_lock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1939 /* Find a region to update */
1940 subpicture_region_t *p_reg = p_sys->bdj.p_overlays[ov->plane]->p_regions;
1941 if (!p_reg) {
1942 vlc_mutex_unlock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1943 return;
1946 /* Now we can update the region */
1947 const uint32_t *src0 = ov->argb;
1948 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
1949 p_reg->p_picture->p[0].i_pitch * ov->y +
1950 ov->x * 4;
1952 for (int y = 0; y < ov->h; y++) {
1953 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1954 // - or add libbluray option to select the format ?
1955 for (int x = 0; x < ov->w; x++) {
1956 dst0[x*4 ] = src0[x]>>16; /* R */
1957 dst0[x*4+1] = src0[x]>>8; /* G */
1958 dst0[x*4+2] = src0[x]; /* B */
1959 dst0[x*4+3] = src0[x]>>24; /* A */
1962 src0 += ov->stride;
1963 dst0 += p_reg->p_picture->p[0].i_pitch;
1966 vlc_mutex_unlock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1968 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1972 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
1974 demux_t *p_demux = (demux_t*)ptr;
1975 demux_sys_t *p_sys = p_demux->p_sys;
1977 switch (overlay->cmd) {
1978 case BD_ARGB_OVERLAY_INIT:
1979 vlc_mutex_lock(&p_sys->bdj.lock);
1980 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1981 vlc_mutex_unlock(&p_sys->bdj.lock);
1982 break;
1983 case BD_ARGB_OVERLAY_CLOSE:
1984 vlc_mutex_lock(&p_sys->bdj.lock);
1985 blurayClearOverlay(p_demux, overlay->plane);
1986 blurayCloseOverlay(p_demux, overlay->plane);
1987 vlc_mutex_unlock(&p_sys->bdj.lock);
1988 break;
1989 case BD_ARGB_OVERLAY_FLUSH:
1990 blurayActivateOverlay(p_demux, overlay->plane);
1991 break;
1992 case BD_ARGB_OVERLAY_DRAW:
1993 blurayDrawArgbOverlay(p_demux, overlay);
1994 break;
1995 default:
1996 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
1997 break;
2001 static void bluraySendOverlayToVout(demux_t *p_demux, int plane, bluray_overlay_t *p_ov)
2003 demux_sys_t *p_sys = p_demux->p_sys;
2005 assert(p_ov != NULL);
2006 assert(!p_ov->b_on_vout);
2008 if (p_ov->p_updater) {
2009 unref_subpicture_updater(p_ov->p_updater);
2010 p_ov->p_updater = NULL;
2013 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
2014 if (!p_pic) {
2015 msg_Err(p_demux, "bluraySubpictureCreate() failed");
2016 return;
2020 * After this point, the picture should not be accessed from the demux thread,
2021 * as it is held by the vout thread.
2022 * This must be done only once per subpicture, ie. only once between each
2023 * blurayInitOverlay & blurayCloseOverlay call.
2025 int ret = es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY,
2026 plane, p_pic);
2027 if (ret != VLC_SUCCESS)
2029 unref_subpicture_updater(p_ov->p_updater);
2030 p_ov->p_updater = NULL;
2031 p_ov->b_on_vout = false;
2032 subpicture_Delete(p_pic);
2033 return;
2035 p_ov->b_on_vout = true;
2038 * Mark the picture as Outdated, as it contains no region for now.
2039 * This will make the subpicture_updater_t call pf_update
2041 p_ov->status = Outdated;
2044 static bool blurayTitleIsRepeating(BLURAY_TITLE_INFO *title_info,
2045 unsigned repeats, unsigned ratio)
2047 const BLURAY_CLIP_INFO *prev = NULL;
2048 unsigned maxrepeats = 0;
2049 unsigned sequence = 0;
2050 if(!title_info->chapter_count)
2051 return false;
2053 for (unsigned int j = 0; j < title_info->chapter_count; j++)
2055 unsigned i = title_info->chapters[j].clip_ref;
2056 if(i < title_info->clip_count)
2058 if(prev == NULL ||
2059 /* non repeated does not need start time offset */
2060 title_info->clips[i].start_time == 0 ||
2061 /* repeats occurs on same segment */
2062 memcmp(title_info->clips[i].clip_id, prev->clip_id, 6) ||
2063 prev->in_time != title_info->clips[i].in_time ||
2064 prev->pkt_count != title_info->clips[i].pkt_count)
2066 sequence = 0;
2067 prev = &title_info->clips[i];
2068 continue;
2070 else
2072 if(maxrepeats < sequence++)
2073 maxrepeats = sequence;
2077 return (maxrepeats > repeats &&
2078 (100 * maxrepeats / title_info->chapter_count) >= ratio);
2081 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
2083 t->i_length = FROM_SCALE_NZ(title_info->duration);
2085 for (int i = 0; i < t->i_seekpoint; i++)
2086 vlc_seekpoint_Delete( t->seekpoint[i] );
2087 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
2089 /* FIXME: have libbluray expose repeating titles */
2090 if(blurayTitleIsRepeating(title_info, 50, 90))
2091 return;
2093 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
2094 seekpoint_t *s = vlc_seekpoint_New();
2095 if (!s) {
2096 break;
2098 s->i_time_offset = FROM_SCALE_NZ(title_info->chapters[j].start);
2100 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
2104 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles)
2106 demux_sys_t *p_sys = p_demux->p_sys;
2107 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2109 /* get and set the titles */
2110 uint32_t i_title = menu_titles;
2112 if (!p_sys->b_menu) {
2113 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
2114 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
2117 for (uint32_t i = 0; i < i_title; i++) {
2118 input_title_t *t = vlc_input_title_New();
2119 if (!t)
2120 break;
2122 if (!p_sys->b_menu) {
2123 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
2124 blurayUpdateTitleInfo(t, title_info);
2125 bd_free_title_info(title_info);
2127 } else if (i == 0) {
2128 t->psz_name = strdup(_("Top Menu"));
2129 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
2130 } else if (i == i_title - 1) {
2131 t->psz_name = strdup(_("First Play"));
2132 if (di && di->first_play && di->first_play->interactive) {
2133 t->i_flags = INPUT_TITLE_INTERACTIVE;
2135 } else {
2136 /* add possible title name from disc metadata */
2137 if (di && di->titles && i <= di->num_titles) {
2138 if (di->titles[i]->name) {
2139 t->psz_name = strdup(di->titles[i]->name);
2141 if (di->titles[i]->interactive) {
2142 t->i_flags = INPUT_TITLE_INTERACTIVE;
2147 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
2151 static void blurayRestartParser(demux_t *p_demux, bool b_flush, bool b_random_access)
2154 * This is a hack and will have to be removed.
2155 * The parser should be flushed, and not destroy/created each time
2156 * we are changing title.
2158 demux_sys_t *p_sys = p_demux->p_sys;
2160 if(b_flush)
2161 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
2163 if (p_sys->p_parser)
2164 vlc_demux_chained_Delete(p_sys->p_parser);
2166 if(b_flush)
2167 es_out_Control(p_sys->p_tf_out, ES_OUT_TF_FILTER_RESET);
2169 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
2170 if (!p_sys->p_parser)
2171 msg_Err(p_demux, "Failed to create TS demuxer");
2173 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT);
2175 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS, b_random_access);
2178 /*****************************************************************************
2179 * bluraySetTitle: select new BD title
2180 *****************************************************************************/
2181 static int bluraySetTitle(demux_t *p_demux, int i_title)
2183 demux_sys_t *p_sys = p_demux->p_sys;
2185 if (p_sys->b_menu) {
2186 int result;
2187 if (i_title <= 0) {
2188 msg_Dbg(p_demux, "Playing TopMenu Title");
2189 result = bd_menu_call(p_sys->bluray, -1);
2190 } else if (i_title >= (int)p_sys->i_title - 1) {
2191 msg_Dbg(p_demux, "Playing FirstPlay Title");
2192 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
2193 } else {
2194 msg_Dbg(p_demux, "Playing Title %i", i_title);
2195 result = bd_play_title(p_sys->bluray, i_title);
2198 if (result == 0) {
2199 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
2200 return VLC_EGENERIC;
2203 return VLC_SUCCESS;
2206 /* Looking for the main title, ie the longest duration */
2207 if (i_title < 0)
2208 i_title = p_sys->i_longest_title;
2209 else if ((unsigned)i_title > p_sys->i_title)
2210 return VLC_EGENERIC;
2212 msg_Dbg(p_demux, "Selecting Title %i", i_title);
2214 if (bd_select_title(p_sys->bluray, i_title) == 0) {
2215 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
2216 return VLC_EGENERIC;
2219 return VLC_SUCCESS;
2222 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
2223 # define BLURAY_AUDIO_STREAM 0
2224 #endif
2226 static void blurayOnUserStreamSelection(demux_sys_t *p_sys, int i_pid)
2228 vlc_mutex_lock(&p_sys->pl_info_lock);
2230 if (p_sys->p_clip_info) {
2232 if ((i_pid & 0xff00) == 0x1100) {
2233 // audio
2234 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
2235 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
2236 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
2237 if(!p_sys->b_menu)
2238 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG,
2239 (const char *) p_sys->p_clip_info->audio_streams[i_id].lang);
2240 break;
2243 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
2244 // subtitle
2245 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
2246 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
2247 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
2248 if(!p_sys->b_menu)
2249 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG,
2250 (const char *) p_sys->p_clip_info->pg_streams[i_id].lang);
2251 break;
2257 vlc_mutex_unlock(&p_sys->pl_info_lock);
2260 /*****************************************************************************
2261 * blurayControl: handle the controls
2262 *****************************************************************************/
2263 static int blurayControl(demux_t *p_demux, int query, va_list args)
2265 demux_sys_t *p_sys = p_demux->p_sys;
2266 bool *pb_bool;
2268 switch (query) {
2269 case DEMUX_CAN_SEEK:
2270 case DEMUX_CAN_PAUSE:
2271 case DEMUX_CAN_CONTROL_PACE:
2272 pb_bool = va_arg(args, bool *);
2273 *pb_bool = true;
2274 break;
2276 case DEMUX_GET_PTS_DELAY:
2277 *va_arg(args, vlc_tick_t *) =
2278 VLC_TICK_FROM_MS(var_InheritInteger(p_demux, "disc-caching"));
2279 break;
2281 case DEMUX_SET_PAUSE_STATE:
2283 #ifdef BLURAY_RATE_NORMAL
2284 bool b_paused = (bool)va_arg(args, int);
2285 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
2286 return VLC_EGENERIC;
2288 #endif
2289 break;
2291 case DEMUX_SET_ES:
2293 int i_id = va_arg(args, int);
2294 blurayOnUserStreamSelection(p_sys, i_id);
2295 break;
2297 case DEMUX_SET_TITLE:
2299 int i_title = va_arg(args, int);
2300 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
2301 /* make sure GUI restores the old setting in title menu ... */
2302 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2303 return VLC_EGENERIC;
2305 blurayRestartParser(p_demux, true, false);
2306 notifyDiscontinuityToParser(p_sys);
2307 p_sys->b_draining = false;
2308 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
2309 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2310 break;
2312 case DEMUX_SET_SEEKPOINT:
2314 int i_chapter = va_arg(args, int);
2315 bd_seek_chapter(p_sys->bluray, i_chapter);
2316 blurayRestartParser(p_demux, true, false);
2317 notifyDiscontinuityToParser(p_sys);
2318 p_sys->b_draining = false;
2319 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
2320 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2321 break;
2323 case DEMUX_TEST_AND_CLEAR_FLAGS:
2325 unsigned *restrict flags = va_arg(args, unsigned *);
2326 *flags &= p_sys->updates;
2327 p_sys->updates &= ~*flags;
2328 break;
2330 case DEMUX_GET_TITLE:
2331 *va_arg(args, int *) = p_sys->cur_title;
2332 break;
2334 case DEMUX_GET_SEEKPOINT:
2335 *va_arg(args, int *) = p_sys->cur_seekpoint;
2336 break;
2338 case DEMUX_GET_TITLE_INFO:
2340 input_title_t ***ppp_title = va_arg(args, input_title_t***);
2341 int *pi_int = va_arg(args, int *);
2342 int *pi_title_offset = va_arg(args, int *);
2343 int *pi_chapter_offset = va_arg(args, int *);
2345 /* */
2346 *pi_title_offset = 0;
2347 *pi_chapter_offset = 0;
2349 /* Duplicate local title infos */
2350 *pi_int = 0;
2351 *ppp_title = vlc_alloc(p_sys->i_title, sizeof(input_title_t *));
2352 if(!*ppp_title)
2353 return VLC_EGENERIC;
2354 for (unsigned int i = 0; i < p_sys->i_title; i++)
2356 input_title_t *p_dup = vlc_input_title_Duplicate(p_sys->pp_title[i]);
2357 if(p_dup)
2358 (*ppp_title)[(*pi_int)++] = p_dup;
2361 return VLC_SUCCESS;
2364 case DEMUX_GET_LENGTH:
2366 if(p_sys->cur_title < p_sys->i_title &&
2367 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2368 return VLC_EGENERIC;
2369 *va_arg(args, vlc_tick_t *) = p_sys->cur_title < p_sys->i_title ? CUR_LENGTH : 0;
2370 return VLC_SUCCESS;
2372 case DEMUX_SET_TIME:
2374 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(va_arg(args, vlc_tick_t)));
2375 blurayRestartParser(p_demux, true, true);
2376 notifyDiscontinuityToParser(p_sys);
2377 p_sys->b_draining = false;
2378 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2379 return VLC_SUCCESS;
2381 case DEMUX_GET_TIME:
2383 vlc_tick_t *pi_time = va_arg(args, vlc_tick_t *);
2384 if(p_sys->cur_title < p_sys->i_title &&
2385 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2386 return VLC_EGENERIC;
2387 *pi_time = FROM_SCALE_NZ(bd_tell_time(p_sys->bluray));
2388 return VLC_SUCCESS;
2391 case DEMUX_GET_POSITION:
2393 double *pf_position = va_arg(args, double *);
2394 if(p_sys->cur_title < p_sys->i_title &&
2395 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2396 return VLC_EGENERIC;
2397 *pf_position = p_sys->cur_title < p_sys->i_title && CUR_LENGTH > 0 ?
2398 (double)FROM_SCALE_NZ(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
2399 return VLC_SUCCESS;
2401 case DEMUX_SET_POSITION:
2403 double f_position = va_arg(args, double);
2404 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(f_position*CUR_LENGTH));
2405 blurayRestartParser(p_demux, true, true);
2406 notifyDiscontinuityToParser(p_sys);
2407 p_sys->b_draining = false;
2408 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2409 return VLC_SUCCESS;
2412 case DEMUX_GET_META:
2414 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
2415 const META_DL *meta = p_sys->p_meta;
2416 if (meta == NULL)
2417 return VLC_EGENERIC;
2419 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
2421 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
2422 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
2423 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
2425 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
2426 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
2428 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
2429 char psz_url[128];
2430 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
2431 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
2432 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
2434 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
2435 char *psz_thumbpath;
2436 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
2437 p_sys->psz_bd_path, meta->thumbnails[0].path) > -1) {
2438 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
2439 free(psz_thumbpath);
2440 if (unlikely(psz_thumburl == NULL))
2441 return VLC_ENOMEM;
2443 vlc_meta_SetArtURL(p_meta, psz_thumburl);
2444 free(psz_thumburl);
2448 return VLC_SUCCESS;
2451 case DEMUX_GET_ATTACHMENTS:
2453 input_attachment_t ***ppp_attach =
2454 va_arg(args, input_attachment_t ***);
2455 int *pi_int = va_arg(args, int *);
2457 if (p_sys->i_attachments <= 0)
2458 return VLC_EGENERIC;
2460 *pi_int = 0;
2461 *ppp_attach = vlc_alloc(p_sys->i_attachments, sizeof(input_attachment_t *));
2462 if(!*ppp_attach)
2463 return VLC_EGENERIC;
2464 for (int i = 0; i < p_sys->i_attachments; i++)
2466 input_attachment_t *p_dup = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
2467 if(p_dup)
2468 (*ppp_attach)[(*pi_int)++] = p_dup;
2470 return VLC_SUCCESS;
2473 case DEMUX_NAV_ACTIVATE:
2474 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
2475 return sendKeyEvent(p_sys, BD_VK_POPUP);
2477 return sendKeyEvent(p_sys, BD_VK_ENTER);
2478 case DEMUX_NAV_UP:
2479 return sendKeyEvent(p_sys, BD_VK_UP);
2480 case DEMUX_NAV_DOWN:
2481 return sendKeyEvent(p_sys, BD_VK_DOWN);
2482 case DEMUX_NAV_LEFT:
2483 return sendKeyEvent(p_sys, BD_VK_LEFT);
2484 case DEMUX_NAV_RIGHT:
2485 return sendKeyEvent(p_sys, BD_VK_RIGHT);
2486 case DEMUX_NAV_POPUP:
2487 return sendKeyEvent(p_sys, BD_VK_POPUP);
2488 case DEMUX_NAV_MENU:
2489 if (p_sys->b_menu) {
2490 if (bd_menu_call(p_sys->bluray, -1) == 1) {
2491 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2492 return VLC_SUCCESS;
2494 msg_Err(p_demux, "Can't select Top Menu title");
2495 return sendKeyEvent(p_sys, BD_VK_POPUP);
2497 return VLC_EGENERIC;
2499 case DEMUX_CAN_RECORD:
2500 case DEMUX_GET_FPS:
2501 case DEMUX_SET_GROUP_DEFAULT:
2502 case DEMUX_SET_GROUP_ALL:
2503 case DEMUX_SET_GROUP_LIST:
2504 case DEMUX_HAS_UNSUPPORTED_META:
2505 default:
2506 return VLC_EGENERIC;
2508 return VLC_SUCCESS;
2511 /*****************************************************************************
2512 * libbluray event handling
2513 *****************************************************************************/
2514 static void writeTsPacketWDiscontinuity( uint8_t *p_buf, uint16_t i_pid,
2515 const uint8_t *p_payload, uint8_t i_payload )
2517 uint8_t ts_header[] = {
2518 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2519 0x47,
2520 0x40 | ((i_pid & 0x1f00) >> 8), i_pid & 0xFF, /* PUSI + PID */
2521 i_payload ? 0x30 : 0x20, /* adaptation field, payload / no payload */
2522 192 - (4 + 5) - i_payload, /* adaptation field length */
2523 0x82, /* af: discontinuity indicator + priv data */
2524 0x0E, /* priv data size */
2525 'V', 'L', 'C', '_',
2526 'D', 'I', 'S', 'C', 'O', 'N', 'T', 'I', 'N', 'U',
2529 memcpy( p_buf, ts_header, sizeof(ts_header) );
2530 memset( &p_buf[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header) - i_payload );
2531 if( i_payload )
2532 memcpy( &p_buf[192 - i_payload], p_payload, i_payload );
2535 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
2536 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
2538 for( size_t i=0; i< i_sinfo; i++ )
2540 const uint16_t i_pid = p_sinfo[i].pid;
2542 block_t *p_block = block_Alloc(192);
2543 if (!p_block)
2544 return;
2546 writeTsPacketWDiscontinuity( p_block->p_buffer, i_pid, NULL, 0 );
2548 vlc_demux_chained_Send(p_parser, p_block);
2552 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2553 p_clip->memb##_stream_count )
2555 static void notifyDiscontinuityToParser( demux_sys_t *p_sys )
2557 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2558 if( p_clip )
2560 DONOTIFY(audio);
2561 DONOTIFY(video);
2562 DONOTIFY(pg);
2563 DONOTIFY(ig);
2564 DONOTIFY(sec_audio);
2565 DONOTIFY(sec_video);
2569 #undef DONOTIFY
2571 static void streamFlush( demux_sys_t *p_sys )
2574 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2575 * Packet is flushed only when TS packet with PUSI flag set is received.
2577 * Fix this by emitting (video) ts packet with PUSI flag set.
2578 * Add video sequence end code to payload so that also video decoder is flushed.
2579 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2582 if (p_sys->b_flushed)
2583 return;
2585 block_t *p_block = block_Alloc(192);
2586 if (!p_block)
2587 return;
2589 bd_stream_type_e i_coding_type;
2591 /* set correct sequence end code */
2592 vlc_mutex_lock(&p_sys->pl_info_lock);
2593 if (p_sys->p_clip_info != NULL)
2594 i_coding_type = p_sys->p_clip_info->video_streams[0].coding_type;
2595 else
2596 i_coding_type = 0;
2597 vlc_mutex_unlock(&p_sys->pl_info_lock);
2599 uint8_t i_eos;
2600 switch( i_coding_type )
2602 case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
2603 case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
2604 default:
2605 i_eos = 0xB7; /* MPEG2 sequence end */
2606 break;
2607 case BLURAY_STREAM_TYPE_VIDEO_VC1:
2608 case BLURAY_STREAM_TYPE_VIDEO_H264:
2609 i_eos = 0x0A; /* VC1 / H.264 sequence end */
2610 break;
2611 case BD_STREAM_TYPE_VIDEO_HEVC:
2612 i_eos = 0x48; /* HEVC sequence end NALU */
2613 break;
2616 uint8_t seq_end_pes[] = {
2617 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2618 0x00, 0x00, 0x01, i_eos, /* PES payload: sequence end */
2619 0x00, /* 2nd byte for HEVC NAL, pads others */
2622 writeTsPacketWDiscontinuity( p_block->p_buffer, 0x1011, seq_end_pes, sizeof(seq_end_pes) );
2624 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2625 p_sys->b_flushed = true;
2628 static void blurayResetStillImage( demux_t *p_demux )
2630 demux_sys_t *p_sys = p_demux->p_sys;
2632 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET) {
2633 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
2635 blurayRestartParser(p_demux, false, false);
2636 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2640 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2642 demux_sys_t *p_sys = p_demux->p_sys;
2644 /* time period elapsed ? */
2645 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET &&
2646 p_sys->i_still_end_time != STILL_IMAGE_INFINITE &&
2647 p_sys->i_still_end_time <= vlc_tick_now()) {
2648 msg_Dbg(p_demux, "Still image end");
2649 bd_read_skip_still(p_sys->bluray);
2651 blurayResetStillImage(p_demux);
2652 return;
2655 /* show last frame as still image */
2656 if (p_sys->i_still_end_time == STILL_IMAGE_NOT_SET) {
2657 if (i_timeout) {
2658 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2659 p_sys->i_still_end_time = vlc_tick_now() + vlc_tick_from_sec( i_timeout );
2660 } else {
2661 msg_Dbg(p_demux, "Still image (infinite)");
2662 p_sys->i_still_end_time = STILL_IMAGE_INFINITE;
2665 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2666 streamFlush(p_sys);
2668 /* stop buffering */
2669 bool b_empty;
2670 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2673 /* avoid busy loops (read returns no data) */
2674 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2677 static void blurayOnStreamSelectedEvent(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2679 demux_sys_t *p_sys = p_demux->p_sys;
2680 int i_pid = -1;
2682 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2683 i_id--;
2685 if (i_type == BD_EVENT_AUDIO_STREAM) {
2686 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2687 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2688 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2691 if (i_pid > 0)
2693 if (i_type == BD_EVENT_PG_TEXTST_STREAM && !p_sys->b_spu_enable)
2694 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID, (int)i_type, i_pid);
2695 else
2696 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID, (int)i_type, i_pid);
2700 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2702 demux_sys_t *p_sys = p_demux->p_sys;
2704 blurayRestartParser(p_demux, true, false);
2706 /* read title info and init some values */
2707 if (!p_sys->b_menu)
2708 p_sys->cur_title = bd_get_current_title(p_sys->bluray);
2709 p_sys->cur_seekpoint = 0;
2710 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2712 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2713 if (p_title_info) {
2714 blurayUpdateTitleInfo(p_sys->pp_title[p_sys->cur_title], p_title_info);
2715 if (p_sys->b_menu)
2716 p_sys->updates |= INPUT_UPDATE_TITLE_LIST;
2718 setTitleInfo(p_sys, p_title_info);
2720 blurayResetStillImage(p_demux);
2723 static void blurayOnClipUpdate(demux_t *p_demux, uint32_t clip)
2725 demux_sys_t *p_sys = p_demux->p_sys;
2727 vlc_mutex_lock(&p_sys->pl_info_lock);
2729 p_sys->p_clip_info = NULL;
2731 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2733 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2735 /* Let's assume a single video track for now.
2736 * This may brake later, but it's enough for now.
2738 assert(p_sys->p_clip_info->video_stream_count >= 1);
2741 CLPI_CL *clpi = bd_get_clpi(p_sys->bluray, clip);
2742 if(clpi && clpi->clip.application_type != p_sys->clip_application_type)
2744 if(p_sys->clip_application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW ||
2745 clpi->clip.application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW)
2746 blurayRestartParser(p_demux, false, false);
2748 if(clpi->clip.application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW)
2749 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY);
2750 else
2751 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY);
2752 bd_free_clpi(clpi);
2755 vlc_mutex_unlock(&p_sys->pl_info_lock);
2757 blurayResetStillImage(p_demux);
2760 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e)
2762 demux_sys_t *p_sys = p_demux->p_sys;
2764 blurayDebugEvent(e->event, e->param);
2766 switch (e->event) {
2767 case BD_EVENT_TITLE:
2768 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2769 p_sys->cur_title = p_sys->i_title - 1;
2770 else
2771 p_sys->cur_title = e->param;
2772 /* this is feature title, we don't know yet which playlist it will play (if any) */
2773 setTitleInfo(p_sys, NULL);
2774 /* reset title infos here ? */
2775 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2776 /* might be BD-J title with no video */
2777 break;
2778 case BD_EVENT_PLAYLIST:
2779 /* Start of playlist playback (?????.mpls) */
2780 blurayUpdatePlaylist(p_demux, e->param);
2781 if (p_sys->b_pl_playing) {
2782 /* previous playlist was stopped in middle. flush to avoid delay */
2783 msg_Info(p_demux, "Stopping playlist playback");
2784 blurayRestartParser(p_demux, false, false);
2785 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2787 p_sys->b_pl_playing = true;
2788 break;
2789 case BD_EVENT_PLAYITEM:
2790 notifyDiscontinuityToParser(p_sys);
2791 blurayOnClipUpdate(p_demux, e->param);
2792 break;
2793 case BD_EVENT_CHAPTER:
2794 if (e->param && e->param < 0xffff)
2795 p_sys->cur_seekpoint = e->param - 1;
2796 else
2797 p_sys->cur_seekpoint = 0;
2798 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2799 break;
2800 case BD_EVENT_PLAYMARK:
2801 case BD_EVENT_ANGLE:
2802 break;
2803 case BD_EVENT_SEEK:
2804 /* Seek will happen with any chapter/title or bd_seek(),
2805 but also BD-J initiated. We can't make the difference
2806 between input or vm ones, better double flush/pcr reset
2807 than break the clock by throwing post random access PCR */
2808 blurayRestartParser(p_demux, true, true);
2809 notifyDiscontinuityToParser(p_sys);
2810 es_out_Control(p_sys->p_out, ES_OUT_RESET_PCR);
2811 break;
2812 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2813 case BD_EVENT_UO_MASK_CHANGED:
2814 /* This event could be used to grey out unselectable items in title menu */
2815 break;
2816 #endif
2817 case BD_EVENT_MENU:
2818 p_sys->b_menu_open = e->param;
2819 break;
2820 case BD_EVENT_POPUP:
2821 p_sys->b_popup_available = e->param;
2822 /* TODO: show / hide pop-up menu button in gui ? */
2823 break;
2826 * Errors
2828 case BD_EVENT_ERROR:
2829 /* fatal error (with menus) */
2830 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2831 "Playback with BluRay menus failed");
2832 p_sys->b_fatal_error = true;
2833 break;
2834 case BD_EVENT_ENCRYPTED:
2835 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2836 "This disc seems to be encrypted");
2837 p_sys->b_fatal_error = true;
2838 break;
2839 case BD_EVENT_READ_ERROR:
2840 msg_Err(p_demux, "bluray: read error\n");
2841 break;
2844 * stream selection events
2846 case BD_EVENT_PG_TEXTST:
2847 p_sys->b_spu_enable = e->param;
2848 break;
2849 case BD_EVENT_AUDIO_STREAM:
2850 case BD_EVENT_PG_TEXTST_STREAM:
2851 blurayOnStreamSelectedEvent(p_demux, e->event, e->param);
2852 break;
2853 case BD_EVENT_IG_STREAM:
2854 case BD_EVENT_SECONDARY_AUDIO:
2855 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2856 case BD_EVENT_SECONDARY_VIDEO:
2857 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2858 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2859 break;
2862 * playback control events
2864 case BD_EVENT_STILL_TIME:
2865 blurayStillImage(p_demux, e->param);
2866 break;
2867 case BD_EVENT_DISCONTINUITY:
2868 /* reset demuxer (partially decoded PES packets must be dropped) */
2869 blurayRestartParser(p_demux, false, true);
2870 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2871 break;
2872 case BD_EVENT_END_OF_TITLE:
2873 if(p_sys->b_pl_playing)
2875 notifyDiscontinuityToParser(p_sys);
2876 blurayRestartParser(p_demux, false, false);
2877 p_sys->b_draining = true;
2878 p_sys->b_pl_playing = false;
2880 break;
2881 case BD_EVENT_IDLE:
2882 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2883 /* avoid busy loop (bd_read() returns no data) */
2884 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2885 break;
2887 default:
2888 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2889 break;
2893 static void blurayHandleOverlays(demux_t *p_demux)
2895 demux_sys_t *p_sys = p_demux->p_sys;
2896 vlc_mutex_lock(&p_sys->bdj.lock);
2898 for (int i = 0; i < MAX_OVERLAY; i++) {
2899 bluray_overlay_t *ov = p_sys->bdj.p_overlays[i];
2900 if (!ov) {
2901 continue;
2903 vlc_mutex_lock(&ov->lock);
2904 bool display = ov->status == ToDisplay;
2905 vlc_mutex_unlock(&ov->lock);
2906 if (display && !ov->b_on_vout)
2908 /* NOTE: we might want to enable background video always when there's no video stream playing.
2909 Now, with some discs, there are perioids (even seconds) during which the video window
2910 disappears and just playlist is shown.
2911 (sometimes BD-J runs slowly ...)
2913 bluraySendOverlayToVout(p_demux, i, ov);
2917 vlc_mutex_unlock(&p_sys->bdj.lock);
2920 static int blurayDemux(demux_t *p_demux)
2922 demux_sys_t *p_sys = p_demux->p_sys;
2923 BD_EVENT e;
2925 if(p_sys->b_draining)
2927 bool b_empty = false;
2928 if(es_out_Control(p_sys->p_out, ES_OUT_GET_EMPTY, &b_empty) != VLC_SUCCESS || b_empty)
2930 es_out_Control(p_sys->p_out, ES_OUT_RESET_PCR);
2931 p_sys->b_draining = false;
2933 else
2935 msg_Dbg(p_demux, "Draining...");
2936 vlc_tick_sleep(VLC_TICK_FROM_MS(40));
2937 return VLC_DEMUXER_SUCCESS;
2941 block_t *p_block = block_Alloc(BD_READ_SIZE);
2942 if (!p_block)
2943 return VLC_DEMUXER_EGENERIC;
2945 int nread;
2947 if (p_sys->b_menu == false) {
2948 nread = bd_read(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE);
2949 while (bd_get_event(p_sys->bluray, &e))
2950 blurayHandleEvent(p_demux, &e);
2951 } else {
2952 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE, &e);
2953 while (e.event != BD_EVENT_NONE) {
2954 blurayHandleEvent(p_demux, &e);
2955 bd_get_event(p_sys->bluray, &e);
2959 blurayHandleOverlays(p_demux);
2961 if (nread <= 0) {
2962 block_Release(p_block);
2963 if (p_sys->b_fatal_error || nread < 0) {
2964 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
2965 return VLC_DEMUXER_EGENERIC;
2967 if (!p_sys->b_menu) {
2968 return VLC_DEMUXER_EOF;
2970 return VLC_DEMUXER_SUCCESS;
2973 p_block->i_buffer = nread;
2975 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2977 p_sys->b_flushed = false;
2979 return VLC_DEMUXER_SUCCESS;