access: bluray: recycle ES instead of Del/Add
[vlc.git] / modules / access / bluray.c
blob65070b5105e76085336661c3afe36095e35f0a3f
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>
67 //#define DEBUG_BLURAY
68 #ifdef DEBUG_BLURAY
69 # include <libbluray/log_control.h>
70 # define BLURAY_DEBUG_MASK (0xFFFFF & ~DBG_STREAM)
71 static vlc_object_t *p_bluray_DebugObject;
72 static void bluray_DebugHandler(const char *psz)
74 size_t len = strlen(psz);
75 if(len < 1) return;
76 char *psz_log = NULL;
77 if(psz[len - 1] == '\n')
78 psz_log = strndup(psz, len - 1);
79 msg_Dbg(p_bluray_DebugObject, "%s", psz_log ? psz_log : psz);
80 free(psz_log);
82 #endif
84 /*****************************************************************************
85 * Module descriptor
86 *****************************************************************************/
88 #define BD_MENU_TEXT N_("Blu-ray menus")
89 #define BD_MENU_LONGTEXT N_("Use Blu-ray menus. If disabled, "\
90 "the movie will start directly")
91 #define BD_REGION_TEXT N_("Region code")
92 #define BD_REGION_LONGTEXT N_("Blu-Ray player region code. "\
93 "Some discs can be played only with a correct region code.")
95 static const char *const ppsz_region_code[] = {
96 "A", "B", "C" };
97 static const char *const ppsz_region_code_text[] = {
98 "Region A", "Region B", "Region C" };
100 #define REGION_DEFAULT 1 /* Index to region list. Actual region code is (1<<REGION_DEFAULT) */
101 #define LANGUAGE_DEFAULT ("eng")
103 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,0)
104 # define BLURAY_DEMUX
105 #endif
107 #ifndef BD_STREAM_TYPE_VIDEO_HEVC
108 # define BD_STREAM_TYPE_VIDEO_HEVC 0x24
109 #endif
111 /* Callbacks */
112 static int blurayOpen (vlc_object_t *);
113 static void blurayClose(vlc_object_t *);
115 vlc_module_begin ()
116 set_shortname(N_("Blu-ray"))
117 set_description(N_("Blu-ray Disc support (libbluray)"))
119 set_category(CAT_INPUT)
120 set_subcategory(SUBCAT_INPUT_ACCESS)
121 set_capability("access", 500)
122 add_bool("bluray-menu", true, BD_MENU_TEXT, BD_MENU_LONGTEXT, false)
123 add_string("bluray-region", ppsz_region_code[REGION_DEFAULT], BD_REGION_TEXT, BD_REGION_LONGTEXT, false)
124 change_string_list(ppsz_region_code, ppsz_region_code_text)
126 add_shortcut("bluray", "file")
128 set_callbacks(blurayOpen, blurayClose)
130 #ifdef BLURAY_DEMUX
131 /* demux module */
132 add_submodule()
133 set_description( "BluRay demuxer" )
134 set_category( CAT_INPUT )
135 set_subcategory( SUBCAT_INPUT_DEMUX )
136 set_capability( "demux", 5 )
137 set_callbacks( blurayOpen, blurayClose )
138 #endif
140 vlc_module_end ()
142 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
143 #define MAX_OVERLAY 2
145 typedef enum OverlayStatus {
146 Closed = 0,
147 ToDisplay, //Used to mark the overlay to be displayed the first time.
148 Displayed,
149 Outdated //used to update the overlay after it has been sent to the vout
150 } OverlayStatus;
152 typedef struct bluray_spu_updater_sys_t bluray_spu_updater_sys_t;
154 typedef struct bluray_overlay_t
156 vlc_mutex_t lock;
157 int i_channel;
158 OverlayStatus status;
159 subpicture_region_t *p_regions;
160 int width, height;
162 /* pointer to last subpicture updater.
163 * used to disconnect this overlay from vout when:
164 * - the overlay is closed
165 * - vout is changed and this overlay is sent to the new vout
167 bluray_spu_updater_sys_t *p_updater;
168 } bluray_overlay_t;
170 typedef struct
172 BLURAY *bluray;
174 /* Titles */
175 unsigned int i_title;
176 unsigned int i_longest_title;
177 input_title_t **pp_title;
178 unsigned cur_title;
179 unsigned cur_seekpoint;
180 unsigned updates;
182 vlc_mutex_t pl_info_lock;
183 BLURAY_TITLE_INFO *p_pl_info;
184 const BLURAY_CLIP_INFO *p_clip_info;
186 /* Attachments */
187 int i_attachments;
188 input_attachment_t **attachments;
189 int i_cover_idx;
191 /* Meta information */
192 const META_DL *p_meta;
194 /* Menus */
195 bluray_overlay_t *p_overlays[MAX_OVERLAY];
196 bool b_fatal_error;
197 bool b_menu;
198 bool b_menu_open;
199 bool b_popup_available;
200 vlc_tick_t i_still_end_time;
202 vlc_mutex_t bdj_overlay_lock; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
204 /* */
205 vlc_mouse_t oldmouse;
207 es_out_id_t *p_dummy_video;
208 es_out_id_t *p_video_es;
210 /* TS stream */
211 es_out_t *p_tf_out;
212 es_out_t *p_out;
213 bool b_spu_enable; /* enabled / disabled */
214 vlc_demux_chained_t *p_parser;
215 bool b_flushed;
216 bool b_pl_playing; /* true when playing playlist */
218 /* stream input */
219 vlc_mutex_t read_block_lock;
221 /* Used to store bluray disc path */
222 char *psz_bd_path;
223 } demux_sys_t;
226 * Local ES index storage
228 typedef struct
230 es_format_t fmt;
231 es_out_id_t *p_es;
232 int i_next_block_flags;
233 bool b_recyling;
234 } es_pair_t;
236 static bool es_pair_Add(vlc_array_t *p_array, const es_format_t *p_fmt,
237 es_out_id_t *p_es)
239 es_pair_t *p_pair = malloc(sizeof(*p_pair));
240 if (likely(p_pair != NULL))
242 p_pair->p_es = p_es;
243 p_pair->i_next_block_flags = 0;
244 p_pair->b_recyling = false;
245 if(vlc_array_append(p_array, p_pair) != VLC_SUCCESS)
247 free(p_pair);
248 p_pair = NULL;
250 else
252 es_format_Init(&p_pair->fmt, p_fmt->i_cat, p_fmt->i_codec);
253 es_format_Copy(&p_pair->fmt, p_fmt);
256 return p_pair != NULL;
259 static void es_pair_Remove(vlc_array_t *p_array, es_pair_t *p_pair)
261 vlc_array_remove(p_array, vlc_array_index_of_item(p_array, p_pair));
262 es_format_Clean(&p_pair->fmt);
263 free(p_pair);
266 static es_pair_t *getEsPair(vlc_array_t *p_array,
267 bool (*match)(const es_pair_t *, const void *),
268 const void *param)
270 for (size_t i = 0; i < vlc_array_count(p_array); ++i)
272 es_pair_t *p_pair = vlc_array_item_at_index(p_array, i);
273 if(match(p_pair, param))
274 return p_pair;
276 return NULL;
279 static bool es_pair_compare_PID(const es_pair_t *p_pair, const void *p_pid)
281 return p_pair->fmt.i_id == *((const int *)p_pid);
284 static bool es_pair_compare_ES(const es_pair_t *p_pair, const void *p_es)
286 return p_pair->p_es == (const es_out_id_t *)p_es;
289 static bool es_pair_compare_Unused(const es_pair_t *p_pair, const void *priv)
291 VLC_UNUSED(priv);
292 return p_pair->b_recyling;
295 static es_pair_t *getEsPairByPID(vlc_array_t *p_array, int i_pid)
297 return getEsPair(p_array, es_pair_compare_PID, &i_pid);
300 static es_pair_t *getEsPairByES(vlc_array_t *p_array, const es_out_id_t *p_es)
302 return getEsPair(p_array, es_pair_compare_ES, p_es);
305 static es_pair_t *getUnusedEsPair(vlc_array_t *p_array)
307 return getEsPair(p_array, es_pair_compare_Unused, 0);
311 * Subpicture updater
313 struct bluray_spu_updater_sys_t
315 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
316 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
317 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
321 * cut the connection between vout and overlay.
322 * - called when vout is closed or overlay is closed.
323 * - frees bluray_spu_updater_sys_t when both sides have been closed.
325 static void unref_subpicture_updater(bluray_spu_updater_sys_t *p_sys)
327 vlc_mutex_lock(&p_sys->lock);
328 int refs = --p_sys->ref_cnt;
329 p_sys->p_overlay = NULL;
330 vlc_mutex_unlock(&p_sys->lock);
332 if (refs < 1) {
333 vlc_mutex_destroy(&p_sys->lock);
334 free(p_sys);
338 /* Get a 3 char code
339 * FIXME: partiallyy duplicated from src/input/es_out.c
341 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
343 const iso639_lang_t *pl;
344 char *psz_lang;
345 char *p;
347 psz_lang = var_CreateGetString( p_demux, psz_var );
348 if( !psz_lang )
349 return LANGUAGE_DEFAULT;
351 /* XXX: we will use only the first value
352 * (and ignore other ones in case of a list) */
353 if( ( p = strchr( psz_lang, ',' ) ) )
354 *p = '\0';
356 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
358 if( *psz_lang == '\0' )
359 continue;
360 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
361 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
362 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
363 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
364 break;
367 free( psz_lang );
369 if( pl->psz_eng_name != NULL )
370 return pl->psz_iso639_2T;
372 return LANGUAGE_DEFAULT;
375 /*****************************************************************************
376 * Local prototypes
377 *****************************************************************************/
378 static es_out_t *esOutNew(vlc_object_t*, es_out_t *, void *);
380 static int blurayControl(demux_t *, int, va_list);
381 static int blurayDemux(demux_t *);
383 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles);
384 static int bluraySetTitle(demux_t *p_demux, int i_title);
386 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
387 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
389 static void onMouseEvent(const vlc_mouse_t *mouse, void *user_data);
390 static void blurayRestartParser(demux_t *p_demux, bool);
391 static void notifyDiscontinuityToParser( demux_sys_t *p_sys );
393 #define STILL_IMAGE_NOT_SET 0
394 #define STILL_IMAGE_INFINITE -1
396 #define CURRENT_TITLE p_sys->pp_title[p_sys->cur_title]
397 #define CUR_LENGTH CURRENT_TITLE->i_length
399 /* */
400 static void FindMountPoint(char **file)
402 char *device = *file;
403 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
404 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
405 * we look up the real device */
406 char *bd_device = realpath(device, NULL);
407 if (bd_device == NULL)
408 return;
410 struct stat st;
411 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
412 FILE *mtab = setmntent ("/proc/self/mounts", "r");
413 if (mtab) {
414 struct mntent *m, mbuf;
415 char buf [8192];
417 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
418 if (!strcmp (m->mnt_fsname, bd_device)) {
419 free(device);
420 *file = strdup(m->mnt_dir);
421 break;
424 endmntent (mtab);
427 free(bd_device);
429 #elif defined(__APPLE__)
430 struct stat st;
431 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
432 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
433 if (fs_count > 0) {
434 struct statfs mbuf[128];
435 getfsstat (mbuf, fs_count * sizeof(mbuf[0]), MNT_NOWAIT);
436 for (int i = 0; i < fs_count; ++i)
437 if (!strcmp (mbuf[i].f_mntfromname, device)) {
438 free(device);
439 *file = strdup(mbuf[i].f_mntonname);
440 return;
444 #else
445 # warning Disc device to mount point not implemented
446 VLC_UNUSED( device );
447 #endif
450 static void blurayReleaseVideoES(demux_t *p_demux)
452 demux_sys_t *p_sys = p_demux->p_sys;
454 if (p_sys->p_video_es != NULL) {
455 for (int i = 0; i < MAX_OVERLAY; i++) {
456 bluray_overlay_t *p_ov = p_sys->p_overlays[i];
457 if (p_ov) {
458 vlc_mutex_lock(&p_ov->lock);
459 if (p_ov->i_channel != -1) {
460 msg_Err(p_demux, "blurayReleaseVout: subpicture channel exists\n");
461 es_out_Control( p_demux->out, ES_OUT_VOUT_FLUSH_OVERLAY,
462 p_sys->p_video_es, p_ov->i_channel );
464 p_ov->i_channel = -1;
465 p_ov->status = Closed;
466 vlc_mutex_unlock(&p_ov->lock);
468 if (p_ov->p_updater) {
469 unref_subpicture_updater(p_ov->p_updater);
470 p_ov->p_updater = NULL;
474 p_sys->p_video_es = NULL;
478 /*****************************************************************************
479 * BD-J background video
480 *****************************************************************************/
482 static es_out_id_t * blurayCreateBackgroundUnlocked(demux_t *p_demux)
484 demux_sys_t *p_sys = p_demux->p_sys;
486 if (p_sys->p_dummy_video)
487 return p_sys->p_dummy_video;
489 msg_Info(p_demux, "Start background");
491 /* */
492 es_format_t fmt;
493 es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_I420 );
494 video_format_Setup( &fmt.video, VLC_CODEC_I420,
495 1920, 1080, 1920, 1080, 1, 1);
496 fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
497 fmt.i_id = 4115; /* 4113 = main video. 4114 = MVC. 4115 = unused. */
498 fmt.i_group = 1;
499 fmt.psz_description = strdup("Background video");
501 p_sys->p_dummy_video = es_out_Add(p_demux->out, &fmt);
503 if (!p_sys->p_dummy_video) {
504 msg_Err(p_demux, "Error adding background ES");
505 goto out;
508 block_t *p_block = block_Alloc(fmt.video.i_width * fmt.video.i_height *
509 fmt.video.i_bits_per_pixel / 8);
510 if (!p_block) {
511 msg_Err(p_demux, "Error allocating block for background video");
512 goto out;
515 // XXX TODO: what would be correct timestamp ???
516 p_block->i_dts = p_block->i_pts = vlc_tick_now() + VLC_TICK_FROM_MS(40);
518 uint8_t *p = p_block->p_buffer;
519 memset(p, 0, fmt.video.i_width * fmt.video.i_height);
520 p += fmt.video.i_width * fmt.video.i_height;
521 memset(p, 0x80, fmt.video.i_width * fmt.video.i_height / 2);
523 es_out_Send(p_demux->out, p_sys->p_dummy_video, p_block);
525 es_out_Control( p_demux->out, ES_OUT_VOUT_SET_MOUSE_EVENT,
526 p_sys->p_dummy_video, onMouseEvent, p_demux );
528 out:
529 es_format_Clean(&fmt);
530 return p_sys->p_dummy_video;
533 static void stopBackground(demux_t *p_demux)
535 demux_sys_t *p_sys = p_demux->p_sys;
537 if (!p_sys->p_dummy_video) {
538 return;
541 msg_Info(p_demux, "Stop background");
543 es_out_Del(p_demux->out, p_sys->p_dummy_video);
545 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
546 if (p_sys->p_video_es == p_sys->p_dummy_video)
547 blurayReleaseVideoES(p_demux);
548 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
550 p_sys->p_dummy_video = NULL;
553 /*****************************************************************************
554 * cache current playlist (title) information
555 *****************************************************************************/
557 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
559 vlc_mutex_lock(&p_sys->pl_info_lock);
561 if (p_sys->p_pl_info) {
562 bd_free_title_info(p_sys->p_pl_info);
564 p_sys->p_pl_info = info;
565 p_sys->p_clip_info = NULL;
567 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
568 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
571 vlc_mutex_unlock(&p_sys->pl_info_lock);
574 /*****************************************************************************
575 * create input attachment for thumbnail
576 *****************************************************************************/
578 static void attachThumbnail(demux_t *p_demux)
580 demux_sys_t *p_sys = p_demux->p_sys;
582 if (!p_sys->p_meta)
583 return;
585 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
586 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
587 int64_t size;
588 void *data;
589 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
590 char psz_name[64];
591 input_attachment_t *p_attachment;
593 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
595 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
596 if (p_attachment) {
597 p_sys->i_cover_idx = p_sys->i_attachments;
598 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
601 free(data);
603 #endif
606 /*****************************************************************************
607 * stream input
608 *****************************************************************************/
610 static int probeStream(demux_t *p_demux)
612 /* input must be seekable */
613 bool b_canseek = false;
614 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
615 if (!b_canseek) {
616 return VLC_EGENERIC;
619 /* first sector(s) should be filled with zeros */
620 size_t i_peek;
621 const uint8_t *p_peek;
622 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
623 if( i_peek != 2048 ) {
624 return VLC_EGENERIC;
626 while (i_peek > 0) {
627 if (p_peek[ --i_peek ]) {
628 return VLC_EGENERIC;
632 return VLC_SUCCESS;
635 #ifdef BLURAY_DEMUX
636 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
638 demux_t *p_demux = (demux_t*)object;
639 demux_sys_t *p_sys = p_demux->p_sys;
640 int result = -1;
642 assert(p_demux->s != NULL);
644 vlc_mutex_lock(&p_sys->read_block_lock);
646 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
647 size_t req = (size_t)2048 * num_blocks;
648 ssize_t got;
650 got = vlc_stream_Read( p_demux->s, buf, req);
651 if (got < 0) {
652 msg_Err(p_demux, "read from lba %d failed", lba);
653 } else {
654 result = got / 2048;
656 } else {
657 msg_Err(p_demux, "seek to lba %d failed", lba);
660 vlc_mutex_unlock(&p_sys->read_block_lock);
662 return result;
664 #endif
666 /*****************************************************************************
667 * probing of local files
668 *****************************************************************************/
670 /* Descriptor Tag (ECMA 167, 3/7.2) */
671 static int decode_descriptor_tag(const uint8_t *buf)
673 uint16_t id;
674 uint8_t checksum = 0;
675 int i;
677 id = buf[0] | (buf[1] << 8);
679 /* calculate tag checksum */
680 for (i = 0; i < 4; i++) {
681 checksum = (uint8_t)(checksum + buf[i]);
683 for (i = 5; i < 16; i++) {
684 checksum = (uint8_t)(checksum + buf[i]);
687 if (checksum != buf[4]) {
688 return -1;
691 return id;
694 static int probeFile(const char *psz_name)
696 struct stat stat_info;
697 uint8_t peek[2048];
698 unsigned i;
699 int ret = VLC_EGENERIC;
700 int fd;
702 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
703 if (fd == -1) {
704 return VLC_EGENERIC;
707 if (fstat(fd, &stat_info) == -1) {
708 goto bailout;
710 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
711 goto bailout;
714 /* first sector should be filled with zeros */
715 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
716 goto bailout;
718 for (i = 0; i < sizeof(peek); i++) {
719 if (peek[ i ]) {
720 goto bailout;
724 /* Check AVDP tag checksum */
725 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
726 read(fd, peek, 16) != 16 ||
727 decode_descriptor_tag(peek) != 2) {
728 goto bailout;
731 ret = VLC_SUCCESS;
733 bailout:
734 vlc_close(fd);
735 return ret;
738 /*****************************************************************************
739 * blurayOpen: module init function
740 *****************************************************************************/
741 static int blurayOpen(vlc_object_t *object)
743 demux_t *p_demux = (demux_t*)object;
744 demux_sys_t *p_sys;
745 bool forced;
746 uint64_t i_init_pos = 0;
748 const char *error_msg = NULL;
749 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
751 if (p_demux->out == NULL)
752 return VLC_EGENERIC;
754 forced = !strncasecmp(p_demux->psz_url, "bluray:", 7);
756 if (p_demux->s) {
757 if (!strncasecmp(p_demux->psz_url, "file:", 5)) {
758 /* use access_demux for local files */
759 return VLC_EGENERIC;
762 if (probeStream(p_demux) != VLC_SUCCESS) {
763 return VLC_EGENERIC;
766 } else if (!forced) {
767 if (!p_demux->psz_filepath) {
768 return VLC_EGENERIC;
771 if (probeFile(p_demux->psz_filepath) != VLC_SUCCESS) {
772 return VLC_EGENERIC;
776 /* */
777 p_demux->p_sys = p_sys = vlc_obj_calloc(object, 1, sizeof(*p_sys));
778 if (unlikely(!p_sys))
779 return VLC_ENOMEM;
781 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
783 /* init demux info fields */
784 p_sys->updates = 0;
786 TAB_INIT(p_sys->i_title, p_sys->pp_title);
787 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
789 vlc_mouse_Init(&p_sys->oldmouse);
791 vlc_mutex_init(&p_sys->pl_info_lock);
792 vlc_mutex_init(&p_sys->bdj_overlay_lock);
793 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
795 /* request sub demuxers to skip continuity check as some split
796 file concatenation are just resetting counters... */
797 var_Create( p_demux, "ts-cc-check", VLC_VAR_BOOL );
798 var_SetBool( p_demux, "ts-cc-check", false );
800 #ifdef DEBUG_BLURAY
801 p_bluray_DebugObject = VLC_OBJECT(p_demux);
802 bd_set_debug_mask(BLURAY_DEBUG_MASK);
803 bd_set_debug_handler(bluray_DebugHandler);
804 #endif
806 /* Open BluRay */
807 #ifdef BLURAY_DEMUX
808 if (p_demux->s) {
809 i_init_pos = vlc_stream_Tell(p_demux->s);
811 p_sys->bluray = bd_init();
812 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
813 bd_close(p_sys->bluray);
814 p_sys->bluray = NULL;
816 } else
817 #endif
819 if (!p_demux->psz_filepath) {
820 /* no path provided (bluray://). use default DVD device. */
821 p_sys->psz_bd_path = var_InheritString(object, "dvd");
822 } else {
823 /* store current bd path */
824 p_sys->psz_bd_path = strdup(p_demux->psz_filepath);
827 /* If we're passed a block device, try to convert it to the mount point. */
828 FindMountPoint(&p_sys->psz_bd_path);
830 p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
832 if (!p_sys->bluray) {
833 goto error;
836 /* Warning the user about AACS/BD+ */
837 const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
839 /* Is it a bluray? */
840 if (!disc_info->bluray_detected) {
841 if (forced) {
842 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
844 goto error;
847 msg_Info(p_demux, "First play: %i, Top menu: %i\n"
848 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
849 disc_info->first_play_supported, disc_info->top_menu_supported,
850 disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
851 disc_info->num_unsupported_titles);
853 /* AACS */
854 if (disc_info->aacs_detected) {
855 msg_Dbg(p_demux, "Disc is using AACS");
856 if (!disc_info->libaacs_detected)
857 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
858 ", and your system does not have it."));
859 if (!disc_info->aacs_handled) {
860 if (disc_info->aacs_error_code) {
861 switch (disc_info->aacs_error_code) {
862 case BD_AACS_CORRUPTED_DISC:
863 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
864 case BD_AACS_NO_CONFIG:
865 BLURAY_ERROR(_("Missing AACS configuration file!"));
866 case BD_AACS_NO_PK:
867 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
868 case BD_AACS_NO_CERT:
869 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
870 case BD_AACS_CERT_REVOKED:
871 BLURAY_ERROR(_("AACS Host certificate revoked."));
872 case BD_AACS_MMC_FAILED:
873 BLURAY_ERROR(_("AACS MMC failed."));
879 /* BD+ */
880 if (disc_info->bdplus_detected) {
881 msg_Dbg(p_demux, "Disc is using BD+");
882 if (!disc_info->libbdplus_detected)
883 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
884 ", and your system does not have it."));
885 if (!disc_info->bdplus_handled)
886 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
887 "Missing configuration?"));
890 /* set player region code */
891 char *psz_region = var_InheritString(p_demux, "bluray-region");
892 unsigned int region = psz_region ? (psz_region[0] - 'A') : REGION_DEFAULT;
893 free(psz_region);
894 bd_set_player_setting(p_sys->bluray, BLURAY_PLAYER_SETTING_REGION_CODE, 1<<region);
896 /* set preferred languages */
897 const char *psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
898 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG, psz_code);
899 psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
900 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG, psz_code);
901 psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
902 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_MENU_LANG, psz_code);
904 /* Get disc metadata */
905 p_sys->p_meta = bd_get_meta(p_sys->bluray);
906 if (!p_sys->p_meta)
907 msg_Warn(p_demux, "Failed to get meta info.");
909 p_sys->i_cover_idx = -1;
910 attachThumbnail(p_demux);
912 p_sys->b_menu = var_InheritBool(p_demux, "bluray-menu");
914 /* Check BD-J capability */
915 if (p_sys->b_menu && disc_info->bdj_detected && !disc_info->bdj_handled) {
916 msg_Err(p_demux, "BD-J menus not supported. Playing without menus. "
917 "BD-J support: %d, JVM found: %d, JVM usable: %d",
918 disc_info->bdj_supported, disc_info->libjvm_detected, disc_info->bdj_handled);
919 vlc_dialog_display_error(p_demux, _("Java required"),
920 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
921 !disc_info->libjvm_detected ? _("Java was not found on your system.") : "");
922 p_sys->b_menu = false;
925 /* Get titles and chapters */
926 blurayInitTitles(p_demux, disc_info->num_hdmv_titles + disc_info->num_bdj_titles + 1/*Top Menu*/ + 1/*First Play*/);
929 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
931 bd_get_event(p_sys->bluray, NULL);
933 /* Registering overlay event handler */
934 bd_register_overlay_proc(p_sys->bluray, p_demux, blurayOverlayProc);
936 if (p_sys->b_menu) {
938 /* Register ARGB overlay handler for BD-J */
939 if (disc_info->num_bdj_titles)
940 bd_register_argb_overlay_proc(p_sys->bluray, p_demux, blurayArgbOverlayProc, NULL);
942 /* libbluray will start playback from "First-Title" title */
943 if (bd_play(p_sys->bluray) == 0)
944 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
946 } else {
947 /* set start title number */
948 if (bluraySetTitle(p_demux, p_sys->i_longest_title) != VLC_SUCCESS) {
949 msg_Err(p_demux, "Could not set the title %d", p_sys->i_longest_title);
950 goto error;
954 p_sys->p_tf_out = timestamps_filter_es_out_New(p_demux->out);
955 if(unlikely(!p_sys->p_tf_out))
956 goto error;
958 p_sys->p_out = esOutNew(VLC_OBJECT(p_demux), p_sys->p_tf_out, p_demux);
959 if (unlikely(p_sys->p_out == NULL))
960 goto error;
962 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
963 if (!p_sys->p_parser) {
964 msg_Err(p_demux, "Failed to create TS demuxer");
965 goto error;
968 p_demux->pf_control = blurayControl;
969 p_demux->pf_demux = blurayDemux;
971 return VLC_SUCCESS;
973 error:
974 if (error_msg)
975 vlc_dialog_display_error(p_demux, _("Blu-ray error"), "%s", error_msg);
976 blurayClose(object);
978 if (p_demux->s != NULL) {
979 /* restore stream position */
980 if (vlc_stream_Seek(p_demux->s, i_init_pos) != VLC_SUCCESS) {
981 msg_Err(p_demux, "Failed to seek back to stream start");
982 return VLC_ETIMEOUT;
986 return VLC_EGENERIC;
987 #undef BLURAY_ERROR
991 /*****************************************************************************
992 * blurayClose: module destroy function
993 *****************************************************************************/
994 static void blurayClose(vlc_object_t *object)
996 demux_t *p_demux = (demux_t*)object;
997 demux_sys_t *p_sys = p_demux->p_sys;
999 setTitleInfo(p_sys, NULL);
1002 * Close libbluray first.
1003 * This will close all the overlays before we release p_vout
1004 * bd_close(NULL) can crash
1006 if (p_sys->bluray) {
1007 bd_close(p_sys->bluray);
1010 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1011 blurayReleaseVideoES(p_demux);
1012 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1014 if (p_sys->p_parser)
1015 vlc_demux_chained_Delete(p_sys->p_parser);
1017 if (p_sys->p_out != NULL)
1018 es_out_Delete(p_sys->p_out);
1019 if(p_sys->p_tf_out)
1020 timestamps_filter_es_out_Delete(p_sys->p_tf_out);
1022 /* Titles */
1023 for (unsigned int i = 0; i < p_sys->i_title; i++)
1024 vlc_input_title_Delete(p_sys->pp_title[i]);
1025 TAB_CLEAN(p_sys->i_title, p_sys->pp_title);
1027 for (int i = 0; i < p_sys->i_attachments; i++)
1028 vlc_input_attachment_Delete(p_sys->attachments[i]);
1029 TAB_CLEAN(p_sys->i_attachments, p_sys->attachments);
1031 vlc_mutex_destroy(&p_sys->pl_info_lock);
1032 vlc_mutex_destroy(&p_sys->bdj_overlay_lock);
1033 vlc_mutex_destroy(&p_sys->read_block_lock);
1035 free(p_sys->psz_bd_path);
1038 /*****************************************************************************
1039 * Elementary streams handling
1040 *****************************************************************************/
1041 static uint8_t blurayGetStreamsUnlocked(demux_sys_t *p_sys,
1042 int i_stream_type,
1043 BLURAY_STREAM_INFO **pp_streams)
1045 if(!p_sys->p_clip_info)
1046 return 0;
1048 switch(i_stream_type)
1050 case BD_EVENT_AUDIO_STREAM:
1051 *pp_streams = p_sys->p_clip_info->audio_streams;
1052 return p_sys->p_clip_info->audio_stream_count;
1053 case BD_EVENT_PG_TEXTST_STREAM:
1054 *pp_streams = p_sys->p_clip_info->pg_streams;
1055 return p_sys->p_clip_info->pg_stream_count;
1056 default:
1057 return 0;
1061 static BLURAY_STREAM_INFO * blurayGetStreamInfoUnlocked(demux_sys_t *p_sys,
1062 int i_stream_type,
1063 uint8_t i_stream_idx)
1065 BLURAY_STREAM_INFO *p_streams = NULL;
1066 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_stream_type, &p_streams);
1067 if(i_stream_idx < i_streams_count)
1068 return &p_streams[i_stream_idx];
1069 else
1070 return NULL;
1073 static BLURAY_STREAM_INFO * blurayGetStreamInfoByPIDUnlocked(demux_sys_t *p_sys,
1074 int i_pid)
1076 for(int i_type=BD_EVENT_AUDIO_STREAM; i_type<=BD_EVENT_SECONDARY_VIDEO_STREAM; i_type++)
1078 BLURAY_STREAM_INFO *p_streams;
1079 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_type, &p_streams);
1080 for(uint8_t i=0; i<i_streams_count; i++)
1082 if(p_streams[i].pid == i_pid)
1083 return &p_streams[i];
1086 return NULL;
1089 static void setStreamLang(demux_sys_t *p_sys, es_format_t *p_fmt)
1091 vlc_mutex_lock(&p_sys->pl_info_lock);
1093 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoByPIDUnlocked(p_sys, p_fmt->i_id);
1094 if(p_stream)
1096 free(p_fmt->psz_language);
1097 p_fmt->psz_language = strndup((const char *)p_stream->lang, 3);
1100 vlc_mutex_unlock(&p_sys->pl_info_lock);
1103 static int blurayGetStreamPID(demux_sys_t *p_sys, int i_stream_type, uint8_t i_stream_idx)
1105 vlc_mutex_lock(&p_sys->pl_info_lock);
1107 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoUnlocked(p_sys,
1108 i_stream_type,
1109 i_stream_idx);
1110 int i_pid = p_stream ? p_stream->pid : -1;
1112 vlc_mutex_unlock(&p_sys->pl_info_lock);
1114 return i_pid;
1117 /*****************************************************************************
1118 * bluray fake es_out
1119 *****************************************************************************/
1120 typedef struct
1122 es_out_t *p_dst_out;
1123 vlc_object_t *p_obj;
1124 vlc_array_t es; /* es_pair_t */
1125 bool b_entered_recycling;
1126 void *priv;
1127 bool b_discontinuity;
1128 bool b_disable_output;
1129 vlc_mutex_t lock;
1130 struct
1132 int i_audio_pid; /* Selected audio stream. -1 if default */
1133 int i_video_pid;
1134 int i_spu_pid; /* Selected spu stream. -1 if default */
1135 } selected;
1136 es_out_t es_out;
1137 } bluray_esout_priv_t;
1139 enum
1141 BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID = ES_OUT_PRIVATE_START,
1142 BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID,
1143 BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY,
1144 BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT,
1145 BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT,
1148 static es_out_id_t *bluray_esOutAdd(es_out_t *p_out, const es_format_t *p_fmt)
1150 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1151 demux_t *p_demux = esout_priv->priv;
1152 demux_sys_t *p_sys = p_demux->p_sys;
1153 es_format_t fmt;
1154 bool b_select = false;
1156 es_format_Copy(&fmt, p_fmt);
1158 vlc_mutex_lock(&esout_priv->lock);
1160 switch (fmt.i_cat) {
1161 case VIDEO_ES:
1162 if (esout_priv->selected.i_video_pid != -1 && esout_priv->selected.i_video_pid != p_fmt->i_id)
1163 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1164 b_select = (p_fmt->i_id == 0x1011);
1165 break;
1166 case AUDIO_ES:
1167 if (esout_priv->selected.i_audio_pid != -1) {
1168 if (esout_priv->selected.i_audio_pid == p_fmt->i_id)
1169 b_select = true;
1170 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1172 setStreamLang(p_sys, &fmt);
1173 break ;
1174 case SPU_ES:
1175 if (esout_priv->selected.i_spu_pid != -1) {
1176 if (esout_priv->selected.i_spu_pid == p_fmt->i_id)
1177 b_select = p_sys->b_spu_enable;
1178 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1180 setStreamLang(p_sys, &fmt);
1181 break ;
1182 default:
1186 es_out_id_t *p_es = NULL;
1187 if (p_fmt->i_id >= 0) {
1188 /* Ensure we are not overriding anything */
1189 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, p_fmt->i_id);
1190 if (p_pair == NULL)
1192 msg_Info(p_demux, "Adding ES %d select %d", p_fmt->i_id, b_select);
1193 p_es = es_out_Add(esout_priv->p_dst_out, &fmt);
1194 es_pair_Add(&esout_priv->es, &fmt, p_es);
1196 else
1198 msg_Info(p_demux, "Reusing ES %d", p_fmt->i_id);
1199 p_pair->b_recyling = false;
1200 p_es = p_pair->p_es;
1201 if(!es_format_IsSimilar(&fmt, &p_pair->fmt))
1203 es_out_Control(esout_priv->p_dst_out, ES_OUT_SET_ES_FMT, p_pair->p_es, &fmt);
1204 es_format_Clean(&p_pair->fmt);
1205 es_format_Copy(&p_pair->fmt, &fmt);
1208 if (b_select)
1209 es_out_Control(p_demux->out, ES_OUT_SET_ES, p_es);
1211 if (p_es && fmt.i_cat == VIDEO_ES)
1213 es_out_Control( p_demux->out, ES_OUT_VOUT_SET_MOUSE_EVENT, p_es,
1214 onMouseEvent, p_demux );
1215 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1216 p_sys->p_video_es = p_es;
1217 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1219 es_format_Clean(&fmt);
1221 vlc_mutex_unlock(&esout_priv->lock);
1223 return p_es;
1226 static void bluray_esOutDeleteNonReusedESUnlocked(es_out_t *p_out)
1228 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1229 if(!esout_priv->b_entered_recycling)
1230 return;
1231 esout_priv->b_entered_recycling = false;
1233 es_pair_t *p_pair;
1234 while((p_pair = getUnusedEsPair(&esout_priv->es)))
1236 msg_Info(esout_priv->p_obj, "Trashing unused ES %d", p_pair->fmt.i_id);
1237 es_out_Del(esout_priv->p_dst_out, p_pair->p_es);
1238 es_pair_Remove(&esout_priv->es, p_pair);
1242 static int bluray_esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1244 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1245 vlc_mutex_lock(&esout_priv->lock);
1247 bluray_esOutDeleteNonReusedESUnlocked(p_out);
1249 if(esout_priv->b_discontinuity)
1250 esout_priv->b_discontinuity = false;
1252 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1253 if(p_pair && p_pair->i_next_block_flags)
1255 p_block->i_flags |= p_pair->i_next_block_flags;
1256 p_pair->i_next_block_flags = 0;
1258 if(esout_priv->b_disable_output)
1260 block_Release(p_block);
1261 p_block = NULL;
1263 vlc_mutex_unlock(&esout_priv->lock);
1264 return (p_block) ? es_out_Send(esout_priv->p_dst_out, p_es, p_block) : VLC_SUCCESS;
1267 static void bluray_esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1269 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1270 demux_t *p_demux = esout_priv->priv;
1271 demux_sys_t *p_sys = p_demux->p_sys;
1273 vlc_mutex_lock(&esout_priv->lock);
1275 if(esout_priv->b_discontinuity)
1276 esout_priv->b_discontinuity = false;
1278 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1279 if (p_pair)
1281 p_pair->b_recyling = true;
1282 esout_priv->b_entered_recycling = true;
1285 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1286 if (p_es == p_sys->p_video_es)
1287 p_sys->p_video_es = NULL;
1288 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1290 vlc_mutex_unlock(&esout_priv->lock);
1293 static int bluray_esOutControl(es_out_t *p_out, int i_query, va_list args)
1295 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1296 int i_ret;
1297 vlc_mutex_lock(&esout_priv->lock);
1299 if(esout_priv->b_disable_output &&
1300 i_query < ES_OUT_PRIVATE_START)
1302 vlc_mutex_unlock(&esout_priv->lock);
1303 return VLC_EGENERIC;
1306 if(esout_priv->b_discontinuity)
1307 esout_priv->b_discontinuity = false;
1309 switch(i_query)
1311 case BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID:
1312 case BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID:
1314 bool b_select = (i_query == BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID);
1315 const int i_bluray_stream_type = va_arg(args, int);
1316 const int i_pid = va_arg(args, int);
1317 switch(i_bluray_stream_type)
1319 case BD_EVENT_AUDIO_STREAM:
1320 esout_priv->selected.i_audio_pid = i_pid;
1321 break;
1322 case BD_EVENT_PG_TEXTST_STREAM:
1323 esout_priv->selected.i_spu_pid = i_pid;
1324 break;
1325 default:
1326 break;
1329 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, i_pid);
1330 if(unlikely(!p_pair))
1332 vlc_mutex_unlock(&esout_priv->lock);
1333 return VLC_EGENERIC;
1336 i_ret = es_out_Control(esout_priv->p_dst_out,
1337 b_select ? ES_OUT_SET_ES : ES_OUT_UNSET_ES,
1338 p_pair->p_es);
1339 } break;
1341 case BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY:
1343 esout_priv->b_discontinuity = true;
1344 i_ret = VLC_SUCCESS;
1345 } break;
1347 case BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT:
1348 case BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT:
1350 esout_priv->b_disable_output = (i_query == BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
1351 i_ret = VLC_SUCCESS;
1352 } break;
1354 case ES_OUT_SET_ES_DEFAULT:
1355 case ES_OUT_SET_ES:
1356 case ES_OUT_UNSET_ES:
1357 case ES_OUT_SET_ES_STATE:
1358 i_ret = VLC_EGENERIC;
1359 break;
1361 case ES_OUT_GET_ES_STATE:
1362 va_arg(args, es_out_id_t *);
1363 *va_arg(args, bool *) = true;
1364 i_ret = VLC_SUCCESS;
1365 break;
1367 default:
1368 i_ret = es_out_vaControl(esout_priv->p_dst_out, i_query, args);
1369 break;
1371 vlc_mutex_unlock(&esout_priv->lock);
1372 return i_ret;
1375 static void bluray_esOutDestroy(es_out_t *p_out)
1377 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1379 for (size_t i = 0; i < vlc_array_count(&esout_priv->es); ++i)
1380 free(vlc_array_item_at_index(&esout_priv->es, i));
1381 vlc_array_clear(&esout_priv->es);
1382 vlc_mutex_destroy(&esout_priv->lock);
1383 free(esout_priv);
1386 static const struct es_out_callbacks bluray_esOutCallbacks = {
1387 .add = bluray_esOutAdd,
1388 .send = bluray_esOutSend,
1389 .del = bluray_esOutDel,
1390 .control = bluray_esOutControl,
1391 .destroy = bluray_esOutDestroy,
1394 static es_out_t *esOutNew(vlc_object_t *p_obj, es_out_t *p_dst_out, void *priv)
1396 bluray_esout_priv_t *esout_priv = malloc(sizeof(*esout_priv));
1397 if (unlikely(esout_priv == NULL))
1398 return NULL;
1400 vlc_array_init(&esout_priv->es);
1401 esout_priv->p_dst_out = p_dst_out;
1402 esout_priv->p_obj = p_obj;
1403 esout_priv->priv = priv;
1404 esout_priv->es_out.cbs = &bluray_esOutCallbacks;
1405 esout_priv->b_discontinuity = false;
1406 esout_priv->b_disable_output = false;
1407 esout_priv->b_entered_recycling = false;
1408 esout_priv->selected.i_audio_pid = -1;
1409 esout_priv->selected.i_video_pid = -1;
1410 esout_priv->selected.i_spu_pid = -1;
1411 vlc_mutex_init(&esout_priv->lock);
1412 return &esout_priv->es_out;
1415 /*****************************************************************************
1416 * subpicture_updater_t functions:
1417 *****************************************************************************/
1419 static bluray_overlay_t *updater_lock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1421 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1422 vlc_mutex_lock(&p_upd_sys->lock);
1424 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1425 if (ov) {
1426 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1427 vlc_mutex_lock(&ov->lock);
1428 return ov;
1431 /* overlay has been closed */
1432 vlc_mutex_unlock(&p_upd_sys->lock);
1433 return NULL;
1436 static void updater_unlock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1438 assert (p_upd_sys->p_overlay);
1440 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1441 vlc_mutex_unlock(&p_upd_sys->lock);
1444 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1445 bool b_fmt_src, const video_format_t *p_fmt_src,
1446 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1447 vlc_tick_t i_ts)
1449 VLC_UNUSED(b_fmt_src);
1450 VLC_UNUSED(b_fmt_dst);
1451 VLC_UNUSED(p_fmt_src);
1452 VLC_UNUSED(p_fmt_dst);
1453 VLC_UNUSED(i_ts);
1455 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1456 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1458 if (!p_overlay) {
1459 return 1;
1462 int res = p_overlay->status == Outdated;
1464 updater_unlock_overlay(p_upd_sys);
1466 return res;
1469 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1470 const video_format_t *p_fmt_src,
1471 const video_format_t *p_fmt_dst,
1472 vlc_tick_t i_ts)
1474 VLC_UNUSED(p_fmt_src);
1475 VLC_UNUSED(p_fmt_dst);
1476 VLC_UNUSED(i_ts);
1477 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1478 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1480 if (!p_overlay) {
1481 return;
1485 * When this function is called, all p_subpic regions are gone.
1486 * We need to duplicate our regions (stored internaly) to this subpic.
1488 subpicture_region_t *p_src = p_overlay->p_regions;
1489 if (!p_src) {
1490 updater_unlock_overlay(p_upd_sys);
1491 return;
1494 subpicture_region_t **p_dst = &p_subpic->p_region;
1495 while (p_src != NULL) {
1496 *p_dst = subpicture_region_Copy(p_src);
1497 if (*p_dst == NULL)
1498 break;
1499 p_dst = &(*p_dst)->p_next;
1500 p_src = p_src->p_next;
1502 if (*p_dst != NULL)
1503 (*p_dst)->p_next = NULL;
1504 p_overlay->status = Displayed;
1506 updater_unlock_overlay(p_upd_sys);
1509 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1511 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1512 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1514 if (p_overlay) {
1515 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1516 p_overlay->status = ToDisplay;
1517 p_overlay->i_channel = -1;
1518 updater_unlock_overlay(p_upd_sys);
1521 unref_subpicture_updater(p_upd_sys);
1524 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1526 bluray_spu_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1527 if (unlikely(p_upd_sys == NULL)) {
1528 return NULL;
1531 p_upd_sys->p_overlay = p_ov;
1533 subpicture_updater_t updater = {
1534 .pf_validate = subpictureUpdaterValidate,
1535 .pf_update = subpictureUpdaterUpdate,
1536 .pf_destroy = subpictureUpdaterDestroy,
1537 .p_sys = p_upd_sys,
1540 subpicture_t *p_pic = subpicture_New(&updater);
1541 if (p_pic == NULL) {
1542 free(p_upd_sys);
1543 return NULL;
1546 p_pic->i_original_picture_width = p_ov->width;
1547 p_pic->i_original_picture_height = p_ov->height;
1548 p_pic->b_absolute = true;
1550 vlc_mutex_init(&p_upd_sys->lock);
1551 p_upd_sys->ref_cnt = 2;
1553 p_ov->p_updater = p_upd_sys;
1555 return p_pic;
1558 /*****************************************************************************
1559 * User input events:
1560 *****************************************************************************/
1561 static void onMouseEvent(const vlc_mouse_t *newmouse, void *user_data)
1563 demux_t *p_demux = user_data;
1564 demux_sys_t *p_sys = p_demux->p_sys;
1566 if (!newmouse) {
1567 vlc_mouse_Init(&p_sys->oldmouse);
1568 return;
1571 if (vlc_mouse_HasMoved(&p_sys->oldmouse, newmouse))
1572 bd_mouse_select(p_sys->bluray, -1, newmouse->i_x, newmouse->i_y);
1574 if (vlc_mouse_HasPressed( &p_sys->oldmouse, newmouse, MOUSE_BUTTON_LEFT))
1575 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1576 p_sys->oldmouse = *newmouse;
1579 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1581 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1582 return VLC_EGENERIC;
1584 return VLC_SUCCESS;
1587 /*****************************************************************************
1588 * libbluray overlay handling:
1589 *****************************************************************************/
1591 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1593 demux_sys_t *p_sys = p_demux->p_sys;
1594 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1596 if (ov != NULL) {
1598 /* drop overlay from vout */
1599 if (ov->p_updater) {
1600 unref_subpicture_updater(ov->p_updater);
1602 /* no references to this overlay exist in vo anymore */
1603 if (p_sys->p_video_es && ov->i_channel != -1) {
1604 es_out_Control( p_demux->out, ES_OUT_VOUT_FLUSH_OVERLAY,
1605 p_sys->p_video_es, ov->i_channel );
1608 vlc_mutex_destroy(&ov->lock);
1609 subpicture_region_ChainDelete(ov->p_regions);
1610 free(ov);
1612 p_sys->p_overlays[plane] = NULL;
1615 for (int i = 0; i < MAX_OVERLAY; i++)
1616 if (p_sys->p_overlays[i])
1617 return;
1619 /* All overlays have been closed */
1620 blurayReleaseVideoES(p_demux);
1624 * Mark the overlay as "ToDisplay" status.
1625 * This will not send the overlay to the vout instantly, as the vout
1626 * may not be acquired (not acquirable) yet.
1627 * If is has already been acquired, the overlay has already been sent to it,
1628 * therefore, we only flag the overlay as "Outdated"
1630 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1632 demux_sys_t *p_sys = p_demux->p_sys;
1633 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1636 * If the overlay is already displayed, mark the picture as outdated.
1637 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1639 vlc_mutex_lock(&ov->lock);
1640 if (ov->status >= Displayed && p_sys->p_video_es) {
1641 ov->status = Outdated;
1642 vlc_mutex_unlock(&ov->lock);
1643 return;
1647 * Mark the overlay as available, but don't display it right now.
1648 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1649 * the overlay is computed
1651 ov->status = ToDisplay;
1652 vlc_mutex_unlock(&ov->lock);
1655 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1657 demux_sys_t *p_sys = p_demux->p_sys;
1659 assert(p_sys->p_overlays[plane] == NULL);
1661 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1662 if (unlikely(ov == NULL))
1663 return;
1665 ov->width = width;
1666 ov->height = height;
1667 ov->i_channel = -1;
1669 vlc_mutex_init(&ov->lock);
1671 p_sys->p_overlays[plane] = ov;
1675 * Destroy every regions in the subpicture.
1676 * This is done in two steps:
1677 * - Wiping our private regions list
1678 * - Flagging the overlay as outdated, so the changes are replicated from
1679 * the subpicture_updater_t::pf_update
1680 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1682 static void blurayClearOverlay(demux_t *p_demux, int plane)
1684 demux_sys_t *p_sys = p_demux->p_sys;
1685 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1687 vlc_mutex_lock(&ov->lock);
1689 subpicture_region_ChainDelete(ov->p_regions);
1690 ov->p_regions = NULL;
1691 ov->status = Outdated;
1693 vlc_mutex_unlock(&ov->lock);
1697 * This will draw to the overlay by adding a region to our region list
1698 * This will have to be copied to the subpicture used to render the overlay.
1700 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1702 demux_sys_t *p_sys = p_demux->p_sys;
1705 * Compute a subpicture_region_t.
1706 * It will be copied and sent to the vout later.
1708 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1710 /* Find a region to update */
1711 subpicture_region_t **pp_reg = &p_sys->p_overlays[ov->plane]->p_regions;
1712 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1713 subpicture_region_t *p_last = NULL;
1714 while (p_reg != NULL) {
1715 p_last = p_reg;
1716 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1717 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1718 break;
1719 pp_reg = &p_reg->p_next;
1720 p_reg = p_reg->p_next;
1723 if (!ov->img) {
1724 if (p_reg) {
1725 /* drop region */
1726 *pp_reg = p_reg->p_next;
1727 subpicture_region_Delete(p_reg);
1729 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1730 return;
1733 /* If there is no region to update, create a new one. */
1734 if (!p_reg) {
1735 video_format_t fmt;
1736 video_format_Init(&fmt, 0);
1737 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1739 p_reg = subpicture_region_New(&fmt);
1740 p_reg->i_x = ov->x;
1741 p_reg->i_y = ov->y;
1742 /* Append it to our list. */
1743 if (p_last != NULL)
1744 p_last->p_next = p_reg;
1745 else /* If we don't have a last region, then our list empty */
1746 p_sys->p_overlays[ov->plane]->p_regions = p_reg;
1749 /* Now we can update the region, regardless it's an update or an insert */
1750 const BD_PG_RLE_ELEM *img = ov->img;
1751 for (int y = 0; y < ov->h; y++)
1752 for (int x = 0; x < ov->w;) {
1753 plane_t *p = &p_reg->p_picture->p[0];
1754 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1755 x += img->len;
1756 img++;
1759 if (ov->palette) {
1760 p_reg->fmt.p_palette->i_entries = 256;
1761 for (int i = 0; i < 256; ++i) {
1762 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1763 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1764 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1765 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1769 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1771 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1775 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1777 demux_t *p_demux = (demux_t*)ptr;
1778 demux_sys_t *p_sys = p_demux->p_sys;
1780 if (!overlay) {
1781 msg_Info(p_demux, "Closing overlays.");
1782 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1783 if (p_sys->p_video_es)
1784 for (int i = 0; i < MAX_OVERLAY; i++)
1785 blurayCloseOverlay(p_demux, i);
1786 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1787 return;
1790 switch (overlay->cmd) {
1791 case BD_OVERLAY_INIT:
1792 msg_Info(p_demux, "Initializing overlay");
1793 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1794 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1795 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1796 break;
1797 case BD_OVERLAY_CLOSE:
1798 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1799 blurayClearOverlay(p_demux, overlay->plane);
1800 blurayCloseOverlay(p_demux, overlay->plane);
1801 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1802 break;
1803 case BD_OVERLAY_CLEAR:
1804 blurayClearOverlay(p_demux, overlay->plane);
1805 break;
1806 case BD_OVERLAY_FLUSH:
1807 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1808 blurayActivateOverlay(p_demux, overlay->plane);
1809 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1810 break;
1811 case BD_OVERLAY_DRAW:
1812 case BD_OVERLAY_WIPE:
1813 blurayDrawOverlay(p_demux, overlay);
1814 break;
1815 default:
1816 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
1817 break;
1822 * ARGB overlay (BD-J)
1824 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
1826 demux_sys_t *p_sys = p_demux->p_sys;
1828 blurayInitOverlay(p_demux, plane, width, height);
1830 if (!p_sys->p_overlays[plane]->p_regions) {
1831 video_format_t fmt;
1832 video_format_Init(&fmt, 0);
1833 video_format_Setup(&fmt, VLC_CODEC_RGBA, width, height, width, height, 1, 1);
1835 p_sys->p_overlays[plane]->p_regions = subpicture_region_New(&fmt);
1839 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
1841 demux_sys_t *p_sys = p_demux->p_sys;
1843 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1845 /* Find a region to update */
1846 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1847 if (!p_reg) {
1848 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1849 return;
1852 /* Now we can update the region */
1853 const uint32_t *src0 = ov->argb;
1854 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
1855 p_reg->p_picture->p[0].i_pitch * ov->y +
1856 ov->x * 4;
1858 for (int y = 0; y < ov->h; y++) {
1859 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1860 // - or add libbluray option to select the format ?
1861 for (int x = 0; x < ov->w; x++) {
1862 dst0[x*4 ] = src0[x]>>16; /* R */
1863 dst0[x*4+1] = src0[x]>>8; /* G */
1864 dst0[x*4+2] = src0[x]; /* B */
1865 dst0[x*4+3] = src0[x]>>24; /* A */
1868 src0 += ov->stride;
1869 dst0 += p_reg->p_picture->p[0].i_pitch;
1872 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1874 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1878 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
1880 demux_t *p_demux = (demux_t*)ptr;
1881 demux_sys_t *p_sys = p_demux->p_sys;
1883 switch (overlay->cmd) {
1884 case BD_ARGB_OVERLAY_INIT:
1885 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1886 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1887 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1888 break;
1889 case BD_ARGB_OVERLAY_CLOSE:
1890 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1891 blurayClearOverlay(p_demux, overlay->plane);
1892 blurayCloseOverlay(p_demux, overlay->plane);
1893 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1894 break;
1895 case BD_ARGB_OVERLAY_FLUSH:
1896 blurayActivateOverlay(p_demux, overlay->plane);
1897 break;
1898 case BD_ARGB_OVERLAY_DRAW:
1899 blurayDrawArgbOverlay(p_demux, overlay);
1900 break;
1901 default:
1902 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
1903 break;
1907 static void bluraySendOverlayToVout(demux_t *p_demux, bluray_overlay_t *p_ov)
1909 demux_sys_t *p_sys = p_demux->p_sys;
1911 assert(p_ov != NULL);
1912 assert(p_ov->i_channel == -1);
1914 if (p_ov->p_updater) {
1915 unref_subpicture_updater(p_ov->p_updater);
1916 p_ov->p_updater = NULL;
1919 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
1920 if (!p_pic) {
1921 msg_Err(p_demux, "bluraySubpictureCreate() failed");
1922 return;
1926 * After this point, the picture should not be accessed from the demux thread,
1927 * as it is held by the vout thread.
1928 * This must be done only once per subpicture, ie. only once between each
1929 * blurayInitOverlay & blurayCloseOverlay call.
1931 int ret = es_out_Control( p_demux->out, ES_OUT_VOUT_ADD_OVERLAY,
1932 p_sys->p_video_es, p_pic, &p_ov->i_channel);
1933 if (ret != VLC_SUCCESS)
1935 unref_subpicture_updater(p_ov->p_updater);
1936 p_ov->p_updater = NULL;
1937 subpicture_Delete(p_pic);
1938 return;
1942 * Mark the picture as Outdated, as it contains no region for now.
1943 * This will make the subpicture_updater_t call pf_update
1945 p_ov->status = Outdated;
1948 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
1950 t->i_length = FROM_SCALE_NZ(title_info->duration);
1952 for (int i = 0; i < t->i_seekpoint; i++)
1953 vlc_seekpoint_Delete( t->seekpoint[i] );
1954 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
1956 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
1957 seekpoint_t *s = vlc_seekpoint_New();
1958 if (!s) {
1959 break;
1961 s->i_time_offset = FROM_SCALE_NZ(title_info->chapters[j].start);
1963 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
1967 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles)
1969 demux_sys_t *p_sys = p_demux->p_sys;
1970 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
1972 /* get and set the titles */
1973 uint32_t i_title = menu_titles;
1975 if (!p_sys->b_menu) {
1976 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
1977 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
1980 for (uint32_t i = 0; i < i_title; i++) {
1981 input_title_t *t = vlc_input_title_New();
1982 if (!t)
1983 break;
1985 if (!p_sys->b_menu) {
1986 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
1987 blurayUpdateTitleInfo(t, title_info);
1988 bd_free_title_info(title_info);
1990 } else if (i == 0) {
1991 t->psz_name = strdup(_("Top Menu"));
1992 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
1993 } else if (i == i_title - 1) {
1994 t->psz_name = strdup(_("First Play"));
1995 if (di && di->first_play && di->first_play->interactive) {
1996 t->i_flags = INPUT_TITLE_INTERACTIVE;
1998 } else {
1999 /* add possible title name from disc metadata */
2000 if (di && di->titles && i <= di->num_titles) {
2001 if (di->titles[i]->name) {
2002 t->psz_name = strdup(di->titles[i]->name);
2004 if (di->titles[i]->interactive) {
2005 t->i_flags = INPUT_TITLE_INTERACTIVE;
2010 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
2014 static void blurayRestartParser(demux_t *p_demux, bool b_flush)
2017 * This is a hack and will have to be removed.
2018 * The parser should be flushed, and not destroy/created each time
2019 * we are changing title.
2021 demux_sys_t *p_sys = p_demux->p_sys;
2023 if(b_flush)
2024 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
2026 if (p_sys->p_parser)
2027 vlc_demux_chained_Delete(p_sys->p_parser);
2029 if(b_flush)
2030 es_out_Control(p_sys->p_tf_out, ES_OUT_TF_FILTER_RESET);
2032 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
2033 if (!p_sys->p_parser)
2034 msg_Err(p_demux, "Failed to create TS demuxer");
2036 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT);
2039 /*****************************************************************************
2040 * bluraySetTitle: select new BD title
2041 *****************************************************************************/
2042 static int bluraySetTitle(demux_t *p_demux, int i_title)
2044 demux_sys_t *p_sys = p_demux->p_sys;
2046 if (p_sys->b_menu) {
2047 int result;
2048 if (i_title <= 0) {
2049 msg_Dbg(p_demux, "Playing TopMenu Title");
2050 result = bd_menu_call(p_sys->bluray, -1);
2051 } else if (i_title >= (int)p_sys->i_title - 1) {
2052 msg_Dbg(p_demux, "Playing FirstPlay Title");
2053 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
2054 } else {
2055 msg_Dbg(p_demux, "Playing Title %i", i_title);
2056 result = bd_play_title(p_sys->bluray, i_title);
2059 if (result == 0) {
2060 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
2061 return VLC_EGENERIC;
2064 return VLC_SUCCESS;
2067 /* Looking for the main title, ie the longest duration */
2068 if (i_title < 0)
2069 i_title = p_sys->i_longest_title;
2070 else if ((unsigned)i_title > p_sys->i_title)
2071 return VLC_EGENERIC;
2073 msg_Dbg(p_demux, "Selecting Title %i", i_title);
2075 if (bd_select_title(p_sys->bluray, i_title) == 0) {
2076 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
2077 return VLC_EGENERIC;
2080 return VLC_SUCCESS;
2083 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
2084 # define BLURAY_AUDIO_STREAM 0
2085 #endif
2087 static void blurayOnUserStreamSelection(demux_sys_t *p_sys, int i_pid)
2089 vlc_mutex_lock(&p_sys->pl_info_lock);
2091 if (p_sys->p_clip_info) {
2093 if ((i_pid & 0xff00) == 0x1100) {
2094 // audio
2095 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
2096 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
2097 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
2098 if(!p_sys->b_menu)
2099 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG,
2100 (const char *) p_sys->p_clip_info->audio_streams[i_id].lang);
2101 break;
2104 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
2105 // subtitle
2106 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
2107 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
2108 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
2109 if(!p_sys->b_menu)
2110 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG,
2111 (const char *) p_sys->p_clip_info->pg_streams[i_id].lang);
2112 break;
2118 vlc_mutex_unlock(&p_sys->pl_info_lock);
2121 /*****************************************************************************
2122 * blurayControl: handle the controls
2123 *****************************************************************************/
2124 static int blurayControl(demux_t *p_demux, int query, va_list args)
2126 demux_sys_t *p_sys = p_demux->p_sys;
2127 bool *pb_bool;
2129 switch (query) {
2130 case DEMUX_CAN_SEEK:
2131 case DEMUX_CAN_PAUSE:
2132 case DEMUX_CAN_CONTROL_PACE:
2133 pb_bool = va_arg(args, bool *);
2134 *pb_bool = true;
2135 break;
2137 case DEMUX_GET_PTS_DELAY:
2138 *va_arg(args, vlc_tick_t *) =
2139 VLC_TICK_FROM_MS(var_InheritInteger(p_demux, "disc-caching"));
2140 break;
2142 case DEMUX_SET_PAUSE_STATE:
2144 #ifdef BLURAY_RATE_NORMAL
2145 bool b_paused = (bool)va_arg(args, int);
2146 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
2147 return VLC_EGENERIC;
2149 #endif
2150 break;
2152 case DEMUX_SET_ES:
2154 int i_id = va_arg(args, int);
2155 blurayOnUserStreamSelection(p_sys, i_id);
2156 break;
2158 case DEMUX_SET_TITLE:
2160 int i_title = va_arg(args, int);
2161 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
2162 /* make sure GUI restores the old setting in title menu ... */
2163 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2164 return VLC_EGENERIC;
2166 blurayRestartParser(p_demux, true);
2167 notifyDiscontinuityToParser(p_sys);
2168 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2169 break;
2171 case DEMUX_SET_SEEKPOINT:
2173 int i_chapter = va_arg(args, int);
2174 bd_seek_chapter(p_sys->bluray, i_chapter);
2175 blurayRestartParser(p_demux, true);
2176 notifyDiscontinuityToParser(p_sys);
2177 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2178 break;
2180 case DEMUX_TEST_AND_CLEAR_FLAGS:
2182 unsigned *restrict flags = va_arg(args, unsigned *);
2183 *flags &= p_sys->updates;
2184 p_sys->updates &= ~*flags;
2185 break;
2187 case DEMUX_GET_TITLE:
2188 *va_arg(args, int *) = p_sys->cur_title;
2189 break;
2191 case DEMUX_GET_SEEKPOINT:
2192 *va_arg(args, int *) = p_sys->cur_seekpoint;
2193 break;
2195 case DEMUX_GET_TITLE_INFO:
2197 input_title_t ***ppp_title = va_arg(args, input_title_t***);
2198 int *pi_int = va_arg(args, int *);
2199 int *pi_title_offset = va_arg(args, int *);
2200 int *pi_chapter_offset = va_arg(args, int *);
2202 /* */
2203 *pi_title_offset = 0;
2204 *pi_chapter_offset = 0;
2206 /* Duplicate local title infos */
2207 *pi_int = 0;
2208 *ppp_title = vlc_alloc(p_sys->i_title, sizeof(input_title_t *));
2209 if(!*ppp_title)
2210 return VLC_EGENERIC;
2211 for (unsigned int i = 0; i < p_sys->i_title; i++)
2213 input_title_t *p_dup = vlc_input_title_Duplicate(p_sys->pp_title[i]);
2214 if(p_dup)
2215 (*ppp_title)[(*pi_int)++] = p_dup;
2218 return VLC_SUCCESS;
2221 case DEMUX_GET_LENGTH:
2223 if(p_sys->cur_title < p_sys->i_title &&
2224 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2225 return VLC_EGENERIC;
2226 *va_arg(args, vlc_tick_t *) = p_sys->cur_title < p_sys->i_title ? CUR_LENGTH : 0;
2227 return VLC_SUCCESS;
2229 case DEMUX_SET_TIME:
2231 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(va_arg(args, vlc_tick_t)));
2232 blurayRestartParser(p_demux, true);
2233 notifyDiscontinuityToParser(p_sys);
2234 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2235 return VLC_SUCCESS;
2237 case DEMUX_GET_TIME:
2239 vlc_tick_t *pi_time = va_arg(args, vlc_tick_t *);
2240 if(p_sys->cur_title < p_sys->i_title &&
2241 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2242 return VLC_EGENERIC;
2243 *pi_time = FROM_SCALE_NZ(bd_tell_time(p_sys->bluray));
2244 return VLC_SUCCESS;
2247 case DEMUX_GET_POSITION:
2249 double *pf_position = va_arg(args, double *);
2250 if(p_sys->cur_title < p_sys->i_title &&
2251 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2252 return VLC_EGENERIC;
2253 *pf_position = p_sys->cur_title < p_sys->i_title && CUR_LENGTH > 0 ?
2254 (double)FROM_SCALE_NZ(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
2255 return VLC_SUCCESS;
2257 case DEMUX_SET_POSITION:
2259 double f_position = va_arg(args, double);
2260 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(f_position*CUR_LENGTH));
2261 blurayRestartParser(p_demux, true);
2262 notifyDiscontinuityToParser(p_sys);
2263 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2264 return VLC_SUCCESS;
2267 case DEMUX_GET_META:
2269 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
2270 const META_DL *meta = p_sys->p_meta;
2271 if (meta == NULL)
2272 return VLC_EGENERIC;
2274 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
2276 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
2277 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
2278 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
2280 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
2281 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
2283 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
2284 char psz_url[128];
2285 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
2286 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
2287 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
2289 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
2290 char *psz_thumbpath;
2291 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
2292 p_sys->psz_bd_path, meta->thumbnails[0].path) > -1) {
2293 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
2294 free(psz_thumbpath);
2295 if (unlikely(psz_thumburl == NULL))
2296 return VLC_ENOMEM;
2298 vlc_meta_SetArtURL(p_meta, psz_thumburl);
2299 free(psz_thumburl);
2303 return VLC_SUCCESS;
2306 case DEMUX_GET_ATTACHMENTS:
2308 input_attachment_t ***ppp_attach =
2309 va_arg(args, input_attachment_t ***);
2310 int *pi_int = va_arg(args, int *);
2312 if (p_sys->i_attachments <= 0)
2313 return VLC_EGENERIC;
2315 *pi_int = 0;
2316 *ppp_attach = vlc_alloc(p_sys->i_attachments, sizeof(input_attachment_t *));
2317 if(!*ppp_attach)
2318 return VLC_EGENERIC;
2319 for (int i = 0; i < p_sys->i_attachments; i++)
2321 input_attachment_t *p_dup = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
2322 if(p_dup)
2323 (*ppp_attach)[(*pi_int)++] = p_dup;
2325 return VLC_SUCCESS;
2328 case DEMUX_NAV_ACTIVATE:
2329 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
2330 return sendKeyEvent(p_sys, BD_VK_POPUP);
2332 return sendKeyEvent(p_sys, BD_VK_ENTER);
2333 case DEMUX_NAV_UP:
2334 return sendKeyEvent(p_sys, BD_VK_UP);
2335 case DEMUX_NAV_DOWN:
2336 return sendKeyEvent(p_sys, BD_VK_DOWN);
2337 case DEMUX_NAV_LEFT:
2338 return sendKeyEvent(p_sys, BD_VK_LEFT);
2339 case DEMUX_NAV_RIGHT:
2340 return sendKeyEvent(p_sys, BD_VK_RIGHT);
2341 case DEMUX_NAV_POPUP:
2342 return sendKeyEvent(p_sys, BD_VK_POPUP);
2343 case DEMUX_NAV_MENU:
2344 if (p_sys->b_menu) {
2345 if (bd_menu_call(p_sys->bluray, -1) == 1) {
2346 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2347 return VLC_SUCCESS;
2349 msg_Err(p_demux, "Can't select Top Menu title");
2350 return sendKeyEvent(p_sys, BD_VK_POPUP);
2352 return VLC_EGENERIC;
2354 case DEMUX_CAN_RECORD:
2355 case DEMUX_GET_FPS:
2356 case DEMUX_SET_GROUP_DEFAULT:
2357 case DEMUX_SET_GROUP_ALL:
2358 case DEMUX_SET_GROUP_LIST:
2359 case DEMUX_HAS_UNSUPPORTED_META:
2360 default:
2361 return VLC_EGENERIC;
2363 return VLC_SUCCESS;
2366 /*****************************************************************************
2367 * libbluray event handling
2368 *****************************************************************************/
2369 static void writeTsPacketWDiscontinuity( uint8_t *p_buf, uint16_t i_pid,
2370 const uint8_t *p_payload, uint8_t i_payload )
2372 uint8_t ts_header[] = {
2373 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2374 0x47,
2375 0x40 | ((i_pid & 0x1f00) >> 8), i_pid & 0xFF, /* PUSI + PID */
2376 i_payload ? 0x30 : 0x20, /* adaptation field, payload / no payload */
2377 192 - (4 + 5) - i_payload, /* adaptation field length */
2378 0x82, /* af: discontinuity indicator + priv data */
2379 0x0E, /* priv data size */
2380 'V', 'L', 'C', '_',
2381 'D', 'I', 'S', 'C', 'O', 'N', 'T', 'I', 'N', 'U',
2384 memcpy( p_buf, ts_header, sizeof(ts_header) );
2385 memset( &p_buf[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header) - i_payload );
2386 if( i_payload )
2387 memcpy( &p_buf[192 - i_payload], p_payload, i_payload );
2390 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
2391 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
2393 for( size_t i=0; i< i_sinfo; i++ )
2395 const uint16_t i_pid = p_sinfo[i].pid;
2397 block_t *p_block = block_Alloc(192);
2398 if (!p_block)
2399 return;
2401 writeTsPacketWDiscontinuity( p_block->p_buffer, i_pid, NULL, 0 );
2403 vlc_demux_chained_Send(p_parser, p_block);
2407 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2408 p_clip->memb##_stream_count )
2410 static void notifyDiscontinuityToParser( demux_sys_t *p_sys )
2412 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2413 if( p_clip )
2415 DONOTIFY(audio);
2416 DONOTIFY(video);
2417 DONOTIFY(pg);
2418 DONOTIFY(ig);
2419 DONOTIFY(sec_audio);
2420 DONOTIFY(sec_video);
2424 #undef DONOTIFY
2426 static void streamFlush( demux_sys_t *p_sys )
2429 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2430 * Packet is flushed only when TS packet with PUSI flag set is received.
2432 * Fix this by emitting (video) ts packet with PUSI flag set.
2433 * Add video sequence end code to payload so that also video decoder is flushed.
2434 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2437 if (p_sys->b_flushed)
2438 return;
2440 block_t *p_block = block_Alloc(192);
2441 if (!p_block)
2442 return;
2444 bd_stream_type_e i_coding_type;
2446 /* set correct sequence end code */
2447 vlc_mutex_lock(&p_sys->pl_info_lock);
2448 if (p_sys->p_clip_info != NULL)
2449 i_coding_type = p_sys->p_clip_info->video_streams[0].coding_type;
2450 else
2451 i_coding_type = 0;
2452 vlc_mutex_unlock(&p_sys->pl_info_lock);
2454 uint8_t i_eos;
2455 switch( i_coding_type )
2457 case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
2458 case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
2459 default:
2460 i_eos = 0xB7; /* MPEG2 sequence end */
2461 break;
2462 case BLURAY_STREAM_TYPE_VIDEO_VC1:
2463 case BLURAY_STREAM_TYPE_VIDEO_H264:
2464 i_eos = 0x0A; /* VC1 / H.264 sequence end */
2465 break;
2466 case BD_STREAM_TYPE_VIDEO_HEVC:
2467 i_eos = 0x48; /* HEVC sequence end NALU */
2468 break;
2471 uint8_t seq_end_pes[] = {
2472 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2473 0x00, 0x00, 0x01, i_eos, /* PES payload: sequence end */
2474 0x00, /* 2nd byte for HEVC NAL, pads others */
2477 writeTsPacketWDiscontinuity( p_block->p_buffer, 0x1011, seq_end_pes, sizeof(seq_end_pes) );
2479 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2480 p_sys->b_flushed = true;
2483 static void blurayResetStillImage( demux_t *p_demux )
2485 demux_sys_t *p_sys = p_demux->p_sys;
2487 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET) {
2488 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
2490 blurayRestartParser(p_demux, false);
2491 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2495 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2497 demux_sys_t *p_sys = p_demux->p_sys;
2499 /* time period elapsed ? */
2500 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET &&
2501 p_sys->i_still_end_time != STILL_IMAGE_INFINITE &&
2502 p_sys->i_still_end_time <= vlc_tick_now()) {
2503 msg_Dbg(p_demux, "Still image end");
2504 bd_read_skip_still(p_sys->bluray);
2506 blurayResetStillImage(p_demux);
2507 return;
2510 /* show last frame as still image */
2511 if (p_sys->i_still_end_time == STILL_IMAGE_NOT_SET) {
2512 if (i_timeout) {
2513 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2514 p_sys->i_still_end_time = vlc_tick_now() + vlc_tick_from_sec( i_timeout );
2515 } else {
2516 msg_Dbg(p_demux, "Still image (infinite)");
2517 p_sys->i_still_end_time = STILL_IMAGE_INFINITE;
2520 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2521 streamFlush(p_sys);
2523 /* stop buffering */
2524 bool b_empty;
2525 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2528 /* avoid busy loops (read returns no data) */
2529 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2532 static void blurayOnStreamSelectedEvent(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2534 demux_sys_t *p_sys = p_demux->p_sys;
2535 int i_pid = -1;
2537 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2538 i_id--;
2540 if (i_type == BD_EVENT_AUDIO_STREAM) {
2541 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2542 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2543 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2546 if (i_pid > 0)
2548 if (i_type == BD_EVENT_PG_TEXTST_STREAM && !p_sys->b_spu_enable)
2549 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID, (int)i_type, i_pid);
2550 else
2551 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID, (int)i_type, i_pid);
2555 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2557 demux_sys_t *p_sys = p_demux->p_sys;
2559 blurayRestartParser(p_demux, true);
2561 /* read title info and init some values */
2562 if (!p_sys->b_menu)
2563 p_sys->cur_title = bd_get_current_title(p_sys->bluray);
2564 p_sys->cur_seekpoint = 0;
2565 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2567 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2568 if (p_title_info) {
2569 blurayUpdateTitleInfo(p_sys->pp_title[p_sys->cur_title], p_title_info);
2570 if (p_sys->b_menu)
2571 p_sys->updates |= INPUT_UPDATE_TITLE_LIST;
2573 setTitleInfo(p_sys, p_title_info);
2575 blurayResetStillImage(p_demux);
2578 static void blurayUpdateCurrentClip(demux_t *p_demux, uint32_t clip)
2580 demux_sys_t *p_sys = p_demux->p_sys;
2582 vlc_mutex_lock(&p_sys->pl_info_lock);
2584 p_sys->p_clip_info = NULL;
2586 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2588 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2590 /* Let's assume a single video track for now.
2591 * This may brake later, but it's enough for now.
2593 assert(p_sys->p_clip_info->video_stream_count >= 1);
2596 vlc_mutex_unlock(&p_sys->pl_info_lock);
2598 blurayResetStillImage(p_demux);
2601 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e)
2603 demux_sys_t *p_sys = p_demux->p_sys;
2605 switch (e->event) {
2606 case BD_EVENT_TITLE:
2607 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2608 p_sys->cur_title = p_sys->i_title - 1;
2609 else
2610 p_sys->cur_title = e->param;
2611 /* this is feature title, we don't know yet which playlist it will play (if any) */
2612 setTitleInfo(p_sys, NULL);
2613 /* reset title infos here ? */
2614 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2615 /* might be BD-J title with no video */
2616 break;
2617 case BD_EVENT_PLAYLIST:
2618 /* Start of playlist playback (?????.mpls) */
2619 blurayUpdatePlaylist(p_demux, e->param);
2620 if (p_sys->b_pl_playing) {
2621 /* previous playlist was stopped in middle. flush to avoid delay */
2622 msg_Info(p_demux, "Stopping playlist playback");
2623 blurayRestartParser(p_demux, false);
2624 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2626 p_sys->b_pl_playing = true;
2627 break;
2628 case BD_EVENT_PLAYITEM:
2629 notifyDiscontinuityToParser(p_sys);
2630 blurayUpdateCurrentClip(p_demux, e->param);
2631 break;
2632 case BD_EVENT_CHAPTER:
2633 if (e->param && e->param < 0xffff)
2634 p_sys->cur_seekpoint = e->param - 1;
2635 else
2636 p_sys->cur_seekpoint = 0;
2637 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2638 break;
2639 case BD_EVENT_PLAYMARK:
2640 case BD_EVENT_ANGLE:
2641 break;
2642 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2643 case BD_EVENT_UO_MASK_CHANGED:
2644 /* This event could be used to grey out unselectable items in title menu */
2645 break;
2646 #endif
2647 case BD_EVENT_MENU:
2648 p_sys->b_menu_open = e->param;
2649 break;
2650 case BD_EVENT_POPUP:
2651 p_sys->b_popup_available = e->param;
2652 /* TODO: show / hide pop-up menu button in gui ? */
2653 break;
2656 * Errors
2658 case BD_EVENT_ERROR:
2659 /* fatal error (with menus) */
2660 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2661 "Playback with BluRay menus failed");
2662 p_sys->b_fatal_error = true;
2663 break;
2664 case BD_EVENT_ENCRYPTED:
2665 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2666 "This disc seems to be encrypted");
2667 p_sys->b_fatal_error = true;
2668 break;
2669 case BD_EVENT_READ_ERROR:
2670 msg_Err(p_demux, "bluray: read error\n");
2671 break;
2674 * stream selection events
2676 case BD_EVENT_PG_TEXTST:
2677 p_sys->b_spu_enable = e->param;
2678 break;
2679 case BD_EVENT_AUDIO_STREAM:
2680 case BD_EVENT_PG_TEXTST_STREAM:
2681 blurayOnStreamSelectedEvent(p_demux, e->event, e->param);
2682 break;
2683 case BD_EVENT_IG_STREAM:
2684 case BD_EVENT_SECONDARY_AUDIO:
2685 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2686 case BD_EVENT_SECONDARY_VIDEO:
2687 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2688 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2689 break;
2692 * playback control events
2694 case BD_EVENT_STILL_TIME:
2695 blurayStillImage(p_demux, e->param);
2696 break;
2697 case BD_EVENT_DISCONTINUITY:
2698 /* reset demuxer (partially decoded PES packets must be dropped) */
2699 blurayRestartParser(p_demux, false);
2700 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2701 break;
2702 case BD_EVENT_END_OF_TITLE:
2703 p_sys->b_pl_playing = false;
2704 break;
2705 case BD_EVENT_IDLE:
2706 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2707 /* avoid busy loop (bd_read() returns no data) */
2708 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2709 break;
2711 default:
2712 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2713 break;
2717 static bool blurayIsBdjTitle(demux_t *p_demux)
2719 demux_sys_t *p_sys = p_demux->p_sys;
2720 unsigned int i_title = p_sys->cur_title;
2721 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2723 if (di && di->titles) {
2724 if ((i_title <= di->num_titles && di->titles[i_title] && di->titles[i_title]->bdj) ||
2725 (i_title == p_sys->i_title - 1 && di->first_play && di->first_play->bdj)) {
2726 return true;
2730 return false;
2733 static void blurayHandleOverlays(demux_t *p_demux, int nread)
2735 demux_sys_t *p_sys = p_demux->p_sys;
2737 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2739 for (int i = 0; i < MAX_OVERLAY; i++) {
2740 bluray_overlay_t *ov = p_sys->p_overlays[i];
2741 if (!ov) {
2742 continue;
2744 vlc_mutex_lock(&ov->lock);
2745 bool display = ov->status == ToDisplay;
2746 vlc_mutex_unlock(&ov->lock);
2747 if (display) {
2748 /* NOTE: we might want to enable background video always when there's no video stream playing.
2749 Now, with some discs, there are perioids (even seconds) during which the video window
2750 disappears and just playlist is shown.
2751 (sometimes BD-J runs slowly ...)
2753 if (!p_sys->p_video_es && p_sys->b_menu &&
2754 !p_sys->p_pl_info && nread == 0 &&
2755 blurayIsBdjTitle(p_demux)) {
2757 /* Looks like there's no video stream playing.
2758 Emit blank frame so that BD-J overlay can be drawn. */
2759 p_sys->p_video_es = blurayCreateBackgroundUnlocked(p_demux);
2762 if (p_sys->p_video_es != NULL) {
2763 bluraySendOverlayToVout(p_demux, ov);
2768 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2771 #define BD_TS_PACKET_SIZE (192)
2772 #define NB_TS_PACKETS (200)
2773 #define BD_READ_SIZE (NB_TS_PACKETS * BD_TS_PACKET_SIZE)
2775 static int blurayDemux(demux_t *p_demux)
2777 demux_sys_t *p_sys = p_demux->p_sys;
2778 BD_EVENT e;
2780 block_t *p_block = block_Alloc(BD_READ_SIZE);
2781 if (!p_block)
2782 return VLC_DEMUXER_EGENERIC;
2784 int nread;
2786 if (p_sys->b_menu == false) {
2787 nread = bd_read(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE);
2788 while (bd_get_event(p_sys->bluray, &e))
2789 blurayHandleEvent(p_demux, &e);
2790 } else {
2791 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE, &e);
2792 while (e.event != BD_EVENT_NONE) {
2793 blurayHandleEvent(p_demux, &e);
2794 bd_get_event(p_sys->bluray, &e);
2798 blurayHandleOverlays(p_demux, nread);
2800 if (nread <= 0) {
2801 block_Release(p_block);
2802 if (p_sys->b_fatal_error || nread < 0) {
2803 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
2804 return VLC_DEMUXER_EGENERIC;
2806 if (!p_sys->b_menu) {
2807 return VLC_DEMUXER_EOF;
2809 return VLC_DEMUXER_SUCCESS;
2812 p_block->i_buffer = nread;
2814 stopBackground(p_demux);
2816 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2818 p_sys->b_flushed = false;
2820 return VLC_DEMUXER_SUCCESS;