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