contrib: soxr: enable by default
[vlc.git] / modules / access / bluray.c
blob126acb7d442ebf83318a56238ca3a4b0cc7075bd
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_plugin.h>
46 #include <vlc_demux.h> /* demux_t */
47 #include <vlc_input.h> /* Seekpoints, chapters */
48 #include <vlc_dialog.h> /* BD+/AACS warnings */
49 #include <vlc_vout.h> /* vout_PutSubpicture / subpicture_t */
50 #include <vlc_url.h> /* vlc_path2uri */
51 #include <vlc_iso_lang.h>
52 #include <vlc_fs.h>
54 /* FIXME we should find a better way than including that */
55 #include "../../src/text/iso-639_def.h"
58 #include <libbluray/bluray.h>
59 #include <libbluray/bluray-version.h>
60 #include <libbluray/keys.h>
61 #include <libbluray/meta_data.h>
62 #include <libbluray/overlay.h>
64 /*****************************************************************************
65 * Module descriptor
66 *****************************************************************************/
68 #define BD_MENU_TEXT N_("Blu-ray menus")
69 #define BD_MENU_LONGTEXT N_("Use Blu-ray menus. If disabled, "\
70 "the movie will start directly")
71 #define BD_REGION_TEXT N_("Region code")
72 #define BD_REGION_LONGTEXT N_("Blu-Ray player region code. "\
73 "Some discs can be played only with a correct region code.")
75 static const char *const ppsz_region_code[] = {
76 "A", "B", "C" };
77 static const char *const ppsz_region_code_text[] = {
78 "Region A", "Region B", "Region C" };
80 #define REGION_DEFAULT 1 /* Index to region list. Actual region code is (1<<REGION_DEFAULT) */
81 #define LANGUAGE_DEFAULT ("eng")
83 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,0)
84 # define BLURAY_DEMUX
85 #endif
87 /* Callbacks */
88 static int blurayOpen (vlc_object_t *);
89 static void blurayClose(vlc_object_t *);
91 vlc_module_begin ()
92 set_shortname(N_("Blu-ray"))
93 set_description(N_("Blu-ray Disc support (libbluray)"))
95 set_category(CAT_INPUT)
96 set_subcategory(SUBCAT_INPUT_ACCESS)
97 set_capability("access_demux", 500)
98 add_bool("bluray-menu", true, BD_MENU_TEXT, BD_MENU_LONGTEXT, false)
99 add_string("bluray-region", ppsz_region_code[REGION_DEFAULT], BD_REGION_TEXT, BD_REGION_LONGTEXT, false)
100 change_string_list(ppsz_region_code, ppsz_region_code_text)
102 add_shortcut("bluray", "file")
104 set_callbacks(blurayOpen, blurayClose)
106 #ifdef BLURAY_DEMUX
107 /* demux module */
108 add_submodule()
109 set_description( "BluRay demuxer" )
110 set_category( CAT_INPUT )
111 set_subcategory( SUBCAT_INPUT_DEMUX )
112 set_capability( "demux", 5 )
113 set_callbacks( blurayOpen, blurayClose )
114 #endif
116 vlc_module_end ()
118 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
119 #define MAX_OVERLAY 2
121 typedef enum OverlayStatus {
122 Closed = 0,
123 ToDisplay, //Used to mark the overlay to be displayed the first time.
124 Displayed,
125 Outdated //used to update the overlay after it has been sent to the vout
126 } OverlayStatus;
128 typedef struct bluray_overlay_t
130 vlc_mutex_t lock;
131 int i_channel;
132 OverlayStatus status;
133 subpicture_region_t *p_regions;
134 int width, height;
136 /* pointer to last subpicture updater.
137 * used to disconnect this overlay from vout when:
138 * - the overlay is closed
139 * - vout is changed and this overlay is sent to the new vout
141 struct subpicture_updater_sys_t *p_updater;
142 } bluray_overlay_t;
144 struct demux_sys_t
146 BLURAY *bluray;
148 /* Titles */
149 unsigned int i_title;
150 unsigned int i_longest_title;
151 input_title_t **pp_title;
152 unsigned cur_title;
153 unsigned cur_seekpoint;
154 unsigned updates;
156 vlc_mutex_t pl_info_lock;
157 BLURAY_TITLE_INFO *p_pl_info;
158 const BLURAY_CLIP_INFO *p_clip_info;
160 /* Attachments */
161 int i_attachments;
162 input_attachment_t **attachments;
163 int i_cover_idx;
165 /* Meta information */
166 const META_DL *p_meta;
168 /* Menus */
169 bluray_overlay_t *p_overlays[MAX_OVERLAY];
170 bool b_fatal_error;
171 bool b_menu;
172 bool b_menu_open;
173 bool b_popup_available;
174 mtime_t i_still_end_time;
176 vlc_mutex_t bdj_overlay_lock; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
178 /* */
179 vout_thread_t *p_vout;
181 es_out_id_t *p_dummy_video;
183 /* TS stream */
184 es_out_t *p_out;
185 vlc_array_t es;
186 int i_audio_stream_idx; /* Selected audio stream. -1 if default */
187 int i_spu_stream_idx; /* Selected subtitle stream. -1 if default */
188 bool b_spu_enable; /* enabled / disabled */
189 int i_video_stream;
190 vlc_demux_chained_t *p_parser;
191 bool b_flushed;
192 bool b_pl_playing; /* true when playing playlist */
194 /* stream input */
195 vlc_mutex_t read_block_lock;
197 /* Used to store bluray disc path */
198 char *psz_bd_path;
201 struct subpicture_updater_sys_t
203 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
204 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
205 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
209 * cut the connection between vout and overlay.
210 * - called when vout is closed or overlay is closed.
211 * - frees subpicture_updater_sys_t when both sides have been closed.
213 static void unref_subpicture_updater(subpicture_updater_sys_t *p_sys)
215 vlc_mutex_lock(&p_sys->lock);
216 int refs = --p_sys->ref_cnt;
217 p_sys->p_overlay = NULL;
218 vlc_mutex_unlock(&p_sys->lock);
220 if (refs < 1) {
221 vlc_mutex_destroy(&p_sys->lock);
222 free(p_sys);
226 /* Get a 3 char code
227 * FIXME: partiallyy duplicated from src/input/es_out.c
229 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
231 const iso639_lang_t *pl;
232 char *psz_lang;
233 char *p;
235 psz_lang = var_CreateGetString( p_demux, psz_var );
236 if( !psz_lang )
237 return LANGUAGE_DEFAULT;
239 /* XXX: we will use only the first value
240 * (and ignore other ones in case of a list) */
241 if( ( p = strchr( psz_lang, ',' ) ) )
242 *p = '\0';
244 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
246 if( *psz_lang == '\0' )
247 continue;
248 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
249 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
250 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
251 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
252 break;
255 free( psz_lang );
257 if( pl->psz_eng_name != NULL )
258 return pl->psz_iso639_2T;
260 return LANGUAGE_DEFAULT;
263 /*****************************************************************************
264 * Local prototypes
265 *****************************************************************************/
266 static es_out_t *esOutNew(demux_t *p_demux);
268 static int blurayControl(demux_t *, int, va_list);
269 static int blurayDemux(demux_t *);
271 static void blurayInitTitles(demux_t *p_demux, int menu_titles);
272 static int bluraySetTitle(demux_t *p_demux, int i_title);
274 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
275 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
277 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var,
278 vlc_value_t old, vlc_value_t val, void *p_data);
279 static int onIntfEvent(vlc_object_t *, char const *,
280 vlc_value_t, vlc_value_t, void *);
282 static void blurayResetParser(demux_t *p_demux);
283 static void notifyDiscontinuity( demux_sys_t *p_sys );
285 #define FROM_TICKS(a) ((a)*CLOCK_FREQ / INT64_C(90000))
286 #define TO_TICKS(a) ((a)*INT64_C(90000)/CLOCK_FREQ)
287 #define CUR_LENGTH p_sys->pp_title[p_sys->cur_title]->i_length
289 /* */
290 static void FindMountPoint(char **file)
292 char *device = *file;
293 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
294 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
295 * we look up the real device */
296 char *bd_device = realpath(device, NULL);
297 if (bd_device == NULL)
298 return;
300 struct stat st;
301 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
302 FILE *mtab = setmntent ("/proc/self/mounts", "r");
303 if (mtab) {
304 struct mntent *m, mbuf;
305 char buf [8192];
307 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
308 if (!strcmp (m->mnt_fsname, bd_device)) {
309 free(device);
310 *file = strdup(m->mnt_dir);
311 break;
314 endmntent (mtab);
317 free(bd_device);
319 #elif defined(__APPLE__)
320 struct stat st;
321 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
322 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
323 if (fs_count > 0) {
324 struct statfs mbuf[128];
325 getfsstat (mbuf, fs_count * sizeof(mbuf[0]), MNT_NOWAIT);
326 for (int i = 0; i < fs_count; ++i)
327 if (!strcmp (mbuf[i].f_mntfromname, device)) {
328 free(device);
329 *file = strdup(mbuf[i].f_mntonname);
330 return;
334 #else
335 # warning Disc device to mount point not implemented
336 VLC_UNUSED( device );
337 #endif
340 static void blurayReleaseVout(demux_t *p_demux)
342 demux_sys_t *p_sys = p_demux->p_sys;
344 if (p_sys->p_vout != NULL) {
345 var_DelCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
346 var_DelCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
348 for (int i = 0; i < MAX_OVERLAY; i++) {
349 bluray_overlay_t *p_ov = p_sys->p_overlays[i];
350 if (p_ov) {
351 vlc_mutex_lock(&p_ov->lock);
352 if (p_ov->i_channel != -1) {
353 msg_Err(p_demux, "blurayReleaseVout: subpicture channel exists\n");
354 vout_FlushSubpictureChannel(p_sys->p_vout, p_ov->i_channel);
356 p_ov->i_channel = -1;
357 p_ov->status = ToDisplay;
358 vlc_mutex_unlock(&p_ov->lock);
360 if (p_ov->p_updater) {
361 unref_subpicture_updater(p_ov->p_updater);
362 p_ov->p_updater = NULL;
367 vlc_object_release(p_sys->p_vout);
368 p_sys->p_vout = NULL;
372 /*****************************************************************************
373 * BD-J background video
374 *****************************************************************************/
376 static void startBackground(demux_t *p_demux)
378 demux_sys_t *p_sys = p_demux->p_sys;
380 if (p_sys->p_dummy_video) {
381 return;
384 msg_Info(p_demux, "Start background");
386 /* */
387 es_format_t fmt;
388 es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_I420 );
389 video_format_Setup( &fmt.video, VLC_CODEC_I420,
390 1920, 1080, 1920, 1080, 1, 1);
391 fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
392 fmt.i_id = 4115; /* 4113 = main video. 4114 = MVC. 4115 = unused. */
393 fmt.i_group = 1;
395 p_sys->p_dummy_video = es_out_Add(p_demux->out, &fmt);
397 if (!p_sys->p_dummy_video) {
398 msg_Err(p_demux, "Error adding background ES");
399 goto out;
402 block_t *p_block = block_Alloc(fmt.video.i_width * fmt.video.i_height *
403 fmt.video.i_bits_per_pixel / 8);
404 if (!p_block) {
405 msg_Err(p_demux, "Error allocating block for background video");
406 goto out;
409 // XXX TODO: what would be correct timestamp ???
410 p_block->i_dts = p_block->i_pts = mdate() + CLOCK_FREQ/25;
412 uint8_t *p = p_block->p_buffer;
413 memset(p, 0, fmt.video.i_width * fmt.video.i_height);
414 p += fmt.video.i_width * fmt.video.i_height;
415 memset(p, 0x80, fmt.video.i_width * fmt.video.i_height / 2);
417 es_out_Send(p_demux->out, p_sys->p_dummy_video, p_block);
419 out:
420 es_format_Clean(&fmt);
423 static void stopBackground(demux_t *p_demux)
425 demux_sys_t *p_sys = p_demux->p_sys;
427 if (!p_sys->p_dummy_video) {
428 return;
431 msg_Info(p_demux, "Stop background");
433 es_out_Del(p_demux->out, p_sys->p_dummy_video);
434 p_sys->p_dummy_video = NULL;
437 /*****************************************************************************
438 * cache current playlist (title) information
439 *****************************************************************************/
441 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
443 vlc_mutex_lock(&p_sys->pl_info_lock);
445 if (p_sys->p_pl_info) {
446 bd_free_title_info(p_sys->p_pl_info);
448 p_sys->p_pl_info = info;
449 p_sys->p_clip_info = NULL;
451 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
452 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
455 vlc_mutex_unlock(&p_sys->pl_info_lock);
458 /*****************************************************************************
459 * create input attachment for thumbnail
460 *****************************************************************************/
462 static void attachThumbnail(demux_t *p_demux)
464 demux_sys_t *p_sys = p_demux->p_sys;
466 if (!p_sys->p_meta)
467 return;
469 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
470 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
471 int64_t size;
472 void *data;
473 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
474 char psz_name[64];
475 input_attachment_t *p_attachment;
477 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
479 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
480 if (p_attachment) {
481 p_sys->i_cover_idx = p_sys->i_attachments;
482 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
485 free(data);
487 #endif
490 /*****************************************************************************
491 * stream input
492 *****************************************************************************/
494 static int probeStream(demux_t *p_demux)
496 /* input must be seekable */
497 bool b_canseek = false;
498 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
499 if (!b_canseek) {
500 return VLC_EGENERIC;
503 /* first sector(s) should be filled with zeros */
504 size_t i_peek;
505 const uint8_t *p_peek;
506 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
507 if( i_peek != 2048 ) {
508 return VLC_EGENERIC;
510 while (i_peek > 0) {
511 if (p_peek[ --i_peek ]) {
512 return VLC_EGENERIC;
516 return VLC_SUCCESS;
519 #ifdef BLURAY_DEMUX
520 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
522 demux_t *p_demux = (demux_t*)object;
523 demux_sys_t *p_sys = p_demux->p_sys;
524 int result = -1;
526 assert(p_demux->s != NULL);
528 vlc_mutex_lock(&p_sys->read_block_lock);
530 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
531 size_t req = (size_t)2048 * num_blocks;
532 ssize_t got;
534 got = vlc_stream_Read( p_demux->s, buf, req);
535 if (got < 0) {
536 msg_Err(p_demux, "read from lba %d failed", lba);
537 } else {
538 result = got / 2048;
540 } else {
541 msg_Err(p_demux, "seek to lba %d failed", lba);
544 vlc_mutex_unlock(&p_sys->read_block_lock);
546 return result;
548 #endif
550 /*****************************************************************************
551 * probing of local files
552 *****************************************************************************/
554 /* Descriptor Tag (ECMA 167, 3/7.2) */
555 static int decode_descriptor_tag(const uint8_t *buf)
557 uint16_t id;
558 uint8_t checksum = 0;
559 int i;
561 id = buf[0] | (buf[1] << 8);
563 /* calculate tag checksum */
564 for (i = 0; i < 4; i++) {
565 checksum = (uint8_t)(checksum + buf[i]);
567 for (i = 5; i < 16; i++) {
568 checksum = (uint8_t)(checksum + buf[i]);
571 if (checksum != buf[4]) {
572 return -1;
575 return id;
578 static int probeFile(const char *psz_name)
580 struct stat stat_info;
581 uint8_t peek[2048];
582 unsigned i;
583 int ret = VLC_EGENERIC;
584 int fd;
586 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
587 if (fd == -1) {
588 return VLC_EGENERIC;
591 if (fstat(fd, &stat_info) == -1) {
592 goto bailout;
594 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
595 goto bailout;
598 /* first sector should be filled with zeros */
599 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
600 goto bailout;
602 for (i = 0; i < sizeof(peek); i++) {
603 if (peek[ i ]) {
604 goto bailout;
608 /* Check AVDP tag checksum */
609 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
610 read(fd, peek, 16) != 16 ||
611 decode_descriptor_tag(peek) != 2) {
612 goto bailout;
615 ret = VLC_SUCCESS;
617 bailout:
618 vlc_close(fd);
619 return ret;
622 /*****************************************************************************
623 * blurayOpen: module init function
624 *****************************************************************************/
625 static int blurayOpen(vlc_object_t *object)
627 demux_t *p_demux = (demux_t*)object;
628 demux_sys_t *p_sys;
629 bool forced;
630 uint64_t i_init_pos = 0;
632 const char *error_msg = NULL;
633 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
635 if (unlikely(!p_demux->p_input))
636 return VLC_EGENERIC;
638 forced = !strncasecmp(p_demux->psz_url, "bluray:", 7);
640 if (p_demux->s) {
641 if (!strncasecmp(p_demux->psz_url, "file:", 5)) {
642 /* use access_demux for local files */
643 return VLC_EGENERIC;
646 if (probeStream(p_demux) != VLC_SUCCESS) {
647 return VLC_EGENERIC;
650 } else if (!forced) {
651 if (!p_demux->psz_filepath) {
652 return VLC_EGENERIC;
655 if (probeFile(p_demux->psz_filepath) != VLC_SUCCESS) {
656 return VLC_EGENERIC;
660 /* */
661 p_demux->p_sys = p_sys = vlc_obj_calloc(object, 1, sizeof(*p_sys));
662 if (unlikely(!p_sys))
663 return VLC_ENOMEM;
665 p_sys->i_audio_stream_idx = -1;
666 p_sys->i_spu_stream_idx = -1;
667 p_sys->i_video_stream = -1;
668 p_sys->i_still_end_time = 0;
670 /* init demux info fields */
671 p_sys->updates = 0;
673 TAB_INIT(p_sys->i_title, p_sys->pp_title);
674 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
676 vlc_mutex_init(&p_sys->pl_info_lock);
677 vlc_mutex_init(&p_sys->bdj_overlay_lock);
678 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
680 /* request sub demuxers to skip continuity check as some split
681 file concatenation are just resetting counters... */
682 var_Create( p_demux, "ts-cc-check", VLC_VAR_BOOL );
683 var_SetBool( p_demux, "ts-cc-check", false );
685 var_AddCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
687 /* Open BluRay */
688 #ifdef BLURAY_DEMUX
689 if (p_demux->s) {
690 i_init_pos = vlc_stream_Tell(p_demux->s);
692 p_sys->bluray = bd_init();
693 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
694 bd_close(p_sys->bluray);
695 p_sys->bluray = NULL;
697 } else
698 #endif
700 if (!p_demux->psz_filepath) {
701 /* no path provided (bluray://). use default DVD device. */
702 p_sys->psz_bd_path = var_InheritString(object, "dvd");
703 } else {
704 /* store current bd path */
705 p_sys->psz_bd_path = strdup(p_demux->psz_filepath);
708 /* If we're passed a block device, try to convert it to the mount point. */
709 FindMountPoint(&p_sys->psz_bd_path);
711 p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
713 if (!p_sys->bluray) {
714 goto error;
717 /* Warning the user about AACS/BD+ */
718 const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
720 /* Is it a bluray? */
721 if (!disc_info->bluray_detected) {
722 if (forced) {
723 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
725 goto error;
728 msg_Info(p_demux, "First play: %i, Top menu: %i\n"
729 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
730 disc_info->first_play_supported, disc_info->top_menu_supported,
731 disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
732 disc_info->num_unsupported_titles);
734 /* AACS */
735 if (disc_info->aacs_detected) {
736 msg_Dbg(p_demux, "Disc is using AACS");
737 if (!disc_info->libaacs_detected)
738 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
739 ", and your system does not have it."));
740 if (!disc_info->aacs_handled) {
741 if (disc_info->aacs_error_code) {
742 switch (disc_info->aacs_error_code) {
743 case BD_AACS_CORRUPTED_DISC:
744 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
745 case BD_AACS_NO_CONFIG:
746 BLURAY_ERROR(_("Missing AACS configuration file!"));
747 case BD_AACS_NO_PK:
748 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
749 case BD_AACS_NO_CERT:
750 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
751 case BD_AACS_CERT_REVOKED:
752 BLURAY_ERROR(_("AACS Host certificate revoked."));
753 case BD_AACS_MMC_FAILED:
754 BLURAY_ERROR(_("AACS MMC failed."));
760 /* BD+ */
761 if (disc_info->bdplus_detected) {
762 msg_Dbg(p_demux, "Disc is using BD+");
763 if (!disc_info->libbdplus_detected)
764 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
765 ", and your system does not have it."));
766 if (!disc_info->bdplus_handled)
767 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
768 "Missing configuration?"));
771 /* set player region code */
772 char *psz_region = var_InheritString(p_demux, "bluray-region");
773 unsigned int region = psz_region ? (psz_region[0] - 'A') : REGION_DEFAULT;
774 free(psz_region);
775 bd_set_player_setting(p_sys->bluray, BLURAY_PLAYER_SETTING_REGION_CODE, 1<<region);
777 /* set preferred languages */
778 const char *psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
779 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG, psz_code);
780 psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
781 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG, psz_code);
782 psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
783 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_MENU_LANG, psz_code);
785 /* Get disc metadata */
786 p_sys->p_meta = bd_get_meta(p_sys->bluray);
787 if (!p_sys->p_meta)
788 msg_Warn(p_demux, "Failed to get meta info.");
790 p_sys->i_cover_idx = -1;
791 attachThumbnail(p_demux);
793 p_sys->b_menu = var_InheritBool(p_demux, "bluray-menu");
795 /* Check BD-J capability */
796 if (p_sys->b_menu && disc_info->bdj_detected && !disc_info->bdj_handled) {
797 msg_Err(p_demux, "BD-J menus not supported. Playing without menus. "
798 "BD-J support: %d, JVM found: %d, JVM usable: %d",
799 disc_info->bdj_supported, disc_info->libjvm_detected, disc_info->bdj_handled);
800 vlc_dialog_display_error(p_demux, _("Java required"),
801 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
802 !disc_info->libjvm_detected ? _("Java was not found on your system.") : "");
803 p_sys->b_menu = false;
806 /* Get titles and chapters */
807 blurayInitTitles(p_demux, disc_info->num_hdmv_titles + disc_info->num_bdj_titles + 1/*Top Menu*/ + 1/*First Play*/);
810 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
812 bd_get_event(p_sys->bluray, NULL);
814 /* Registering overlay event handler */
815 bd_register_overlay_proc(p_sys->bluray, p_demux, blurayOverlayProc);
817 if (p_sys->b_menu) {
819 /* Register ARGB overlay handler for BD-J */
820 if (disc_info->num_bdj_titles)
821 bd_register_argb_overlay_proc(p_sys->bluray, p_demux, blurayArgbOverlayProc, NULL);
823 /* libbluray will start playback from "First-Title" title */
824 if (bd_play(p_sys->bluray) == 0)
825 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
827 } else {
828 /* set start title number */
829 if (bluraySetTitle(p_demux, p_sys->i_longest_title) != VLC_SUCCESS) {
830 msg_Err(p_demux, "Could not set the title %d", p_sys->i_longest_title);
831 goto error;
835 vlc_array_init(&p_sys->es);
836 p_sys->p_out = esOutNew(p_demux);
837 if (unlikely(p_sys->p_out == NULL))
838 goto error;
840 blurayResetParser(p_demux);
841 if (!p_sys->p_parser) {
842 msg_Err(p_demux, "Failed to create TS demuxer");
843 goto error;
846 p_demux->pf_control = blurayControl;
847 p_demux->pf_demux = blurayDemux;
849 return VLC_SUCCESS;
851 error:
852 if (error_msg)
853 vlc_dialog_display_error(p_demux, _("Blu-ray error"), "%s", error_msg);
854 blurayClose(object);
856 if (p_demux->s != NULL) {
857 /* restore stream position */
858 if (vlc_stream_Seek(p_demux->s, i_init_pos) != VLC_SUCCESS) {
859 msg_Err(p_demux, "Failed to seek back to stream start");
860 return VLC_ETIMEOUT;
864 return VLC_EGENERIC;
865 #undef BLURAY_ERROR
869 /*****************************************************************************
870 * blurayClose: module destroy function
871 *****************************************************************************/
872 static void blurayClose(vlc_object_t *object)
874 demux_t *p_demux = (demux_t*)object;
875 demux_sys_t *p_sys = p_demux->p_sys;
877 var_DelCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
879 setTitleInfo(p_sys, NULL);
882 * Close libbluray first.
883 * This will close all the overlays before we release p_vout
884 * bd_close(NULL) can crash
886 if (p_sys->bluray) {
887 bd_close(p_sys->bluray);
890 blurayReleaseVout(p_demux);
892 if (p_sys->p_parser)
893 vlc_demux_chained_Delete(p_sys->p_parser);
894 if (p_sys->p_out != NULL)
895 es_out_Delete(p_sys->p_out);
896 assert(vlc_array_count(&p_sys->es) == 0);
897 vlc_array_clear(&p_sys->es);
899 /* Titles */
900 for (unsigned int i = 0; i < p_sys->i_title; i++)
901 vlc_input_title_Delete(p_sys->pp_title[i]);
902 TAB_CLEAN(p_sys->i_title, p_sys->pp_title);
904 for (int i = 0; i < p_sys->i_attachments; i++)
905 vlc_input_attachment_Delete(p_sys->attachments[i]);
906 TAB_CLEAN(p_sys->i_attachments, p_sys->attachments);
908 vlc_mutex_destroy(&p_sys->pl_info_lock);
909 vlc_mutex_destroy(&p_sys->bdj_overlay_lock);
910 vlc_mutex_destroy(&p_sys->read_block_lock);
912 free(p_sys->psz_bd_path);
915 /*****************************************************************************
916 * Elementary streams handling
917 *****************************************************************************/
919 struct es_out_sys_t {
920 demux_t *p_demux;
923 typedef struct fmt_es_pair {
924 int i_id;
925 es_out_id_t *p_es;
926 } fmt_es_pair_t;
928 static int findEsPairIndex(demux_sys_t *p_sys, int i_id)
930 for (size_t i = 0; i < vlc_array_count(&p_sys->es); ++i)
931 if (((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->i_id == i_id)
932 return i;
934 return -1;
937 static int findEsPairIndexByEs(demux_sys_t *p_sys, es_out_id_t *p_es)
939 for (size_t i = 0; i < vlc_array_count(&p_sys->es); ++i)
940 if (((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->p_es == p_es)
941 return i;
943 return -1;
946 static void setStreamLang(demux_sys_t *p_sys, es_format_t *p_fmt)
948 const BLURAY_STREAM_INFO *p_streams;
949 int i_stream_count = 0;
951 vlc_mutex_lock(&p_sys->pl_info_lock);
953 if (p_sys->p_clip_info) {
954 if (p_fmt->i_cat == AUDIO_ES) {
955 p_streams = p_sys->p_clip_info->audio_streams;
956 i_stream_count = p_sys->p_clip_info->audio_stream_count;
957 } else if (p_fmt->i_cat == SPU_ES) {
958 p_streams = p_sys->p_clip_info->pg_streams;
959 i_stream_count = p_sys->p_clip_info->pg_stream_count;
963 for (int i = 0; i < i_stream_count; i++) {
964 if (p_fmt->i_id == p_streams[i].pid) {
965 free(p_fmt->psz_language);
966 p_fmt->psz_language = strndup((const char *)p_streams[i].lang, 3);
967 break;
971 vlc_mutex_unlock(&p_sys->pl_info_lock);
974 static int blurayEsPid(demux_sys_t *p_sys, int es_type, int i_es_idx)
976 int i_pid = -1;
978 vlc_mutex_lock(&p_sys->pl_info_lock);
980 if (p_sys->p_clip_info) {
981 if (es_type == AUDIO_ES) {
982 if (i_es_idx >= 0 && i_es_idx < p_sys->p_clip_info->audio_stream_count) {
983 i_pid = p_sys->p_clip_info->audio_streams[i_es_idx].pid;
985 } else if (es_type == SPU_ES) {
986 if (i_es_idx >= 0 && i_es_idx < p_sys->p_clip_info->pg_stream_count) {
987 i_pid = p_sys->p_clip_info->pg_streams[i_es_idx].pid;
992 vlc_mutex_unlock(&p_sys->pl_info_lock);
994 return i_pid;
997 static es_out_id_t *esOutAdd(es_out_t *p_out, const es_format_t *p_fmt)
999 demux_t *p_demux = p_out->p_sys->p_demux;
1000 demux_sys_t *p_sys = p_demux->p_sys;
1001 es_format_t fmt;
1002 bool b_select = false;
1004 es_format_Copy(&fmt, p_fmt);
1006 switch (fmt.i_cat) {
1007 case VIDEO_ES:
1008 if (p_sys->i_video_stream != -1 && p_sys->i_video_stream != p_fmt->i_id)
1009 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1010 break ;
1011 case AUDIO_ES:
1012 if (p_sys->i_audio_stream_idx != -1) {
1013 if (blurayEsPid(p_sys, AUDIO_ES, p_sys->i_audio_stream_idx) == p_fmt->i_id)
1014 b_select = true;
1015 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1017 setStreamLang(p_sys, &fmt);
1018 break ;
1019 case SPU_ES:
1020 if (p_sys->i_spu_stream_idx != -1) {
1021 if (blurayEsPid(p_sys, SPU_ES, p_sys->i_spu_stream_idx) == p_fmt->i_id)
1022 b_select = true;
1023 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1025 setStreamLang(p_sys, &fmt);
1026 break ;
1027 default:
1031 es_out_id_t *p_es = es_out_Add(p_demux->out, &fmt);
1032 if (p_fmt->i_id >= 0) {
1033 /* Ensure we are not overriding anything */
1034 int idx = findEsPairIndex(p_sys, p_fmt->i_id);
1035 if (idx == -1) {
1036 fmt_es_pair_t *p_pair = malloc(sizeof(*p_pair));
1037 if (likely(p_pair != NULL)) {
1038 p_pair->i_id = p_fmt->i_id;
1039 p_pair->p_es = p_es;
1040 msg_Info(p_demux, "Adding ES %d", p_fmt->i_id);
1041 vlc_array_append_or_abort(&p_sys->es, p_pair);
1043 if (b_select) {
1044 if (fmt.i_cat == AUDIO_ES) {
1045 var_SetInteger( p_demux->p_input, "audio-es", p_fmt->i_id );
1046 } else if (fmt.i_cat == SPU_ES) {
1047 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? p_fmt->i_id : -1 );
1053 es_format_Clean(&fmt);
1054 return p_es;
1057 static int esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1059 demux_t *p_demux = p_out->p_sys->p_demux;
1061 return es_out_Send(p_demux->out, p_es, p_block);
1064 static void esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1066 demux_t *p_demux = p_out->p_sys->p_demux;
1067 demux_sys_t *p_sys = p_demux->p_sys;
1069 int idx = findEsPairIndexByEs(p_sys, p_es);
1070 if (idx >= 0) {
1071 free(vlc_array_item_at_index(&p_sys->es, idx));
1072 vlc_array_remove(&p_sys->es, idx);
1074 es_out_Del(p_demux->out, p_es);
1077 static int esOutControl(es_out_t *p_out, int i_query, va_list args)
1079 demux_t *p_demux = p_out->p_sys->p_demux;
1081 return es_out_vaControl(p_demux->out, i_query, args);
1084 static void esOutDestroy(es_out_t *p_out)
1086 demux_t *p_demux = p_out->p_sys->p_demux;
1087 demux_sys_t *p_sys = p_demux->p_sys;
1089 for (size_t i = 0; i < vlc_array_count(&p_sys->es); ++i)
1090 free(vlc_array_item_at_index(&p_sys->es, i));
1091 vlc_array_clear(&p_sys->es);
1092 free(p_out->p_sys);
1093 free(p_out);
1096 static es_out_t *esOutNew(demux_t *p_demux)
1098 #ifndef NDEBUG
1099 demux_sys_t *p_sys = p_demux->p_sys;
1100 assert(vlc_array_count(&p_sys->es) == 0);
1101 #endif
1102 es_out_t *p_out = malloc(sizeof(*p_out));
1103 if (unlikely(p_out == NULL))
1104 return NULL;
1106 p_out->pf_add = esOutAdd;
1107 p_out->pf_control = esOutControl;
1108 p_out->pf_del = esOutDel;
1109 p_out->pf_destroy = esOutDestroy;
1110 p_out->pf_send = esOutSend;
1112 p_out->p_sys = malloc(sizeof(*p_out->p_sys));
1113 if (unlikely(p_out->p_sys == NULL)) {
1114 free(p_out);
1115 return NULL;
1117 p_out->p_sys->p_demux = p_demux;
1118 return p_out;
1121 /*****************************************************************************
1122 * subpicture_updater_t functions:
1123 *****************************************************************************/
1125 static bluray_overlay_t *updater_lock_overlay(subpicture_updater_sys_t *p_upd_sys)
1127 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1128 vlc_mutex_lock(&p_upd_sys->lock);
1130 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1131 if (ov) {
1132 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1133 vlc_mutex_lock(&ov->lock);
1134 return ov;
1137 /* overlay has been closed */
1138 vlc_mutex_unlock(&p_upd_sys->lock);
1139 return NULL;
1142 static void updater_unlock_overlay(subpicture_updater_sys_t *p_upd_sys)
1144 assert (p_upd_sys->p_overlay);
1146 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1147 vlc_mutex_unlock(&p_upd_sys->lock);
1150 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1151 bool b_fmt_src, const video_format_t *p_fmt_src,
1152 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1153 mtime_t i_ts)
1155 VLC_UNUSED(b_fmt_src);
1156 VLC_UNUSED(b_fmt_dst);
1157 VLC_UNUSED(p_fmt_src);
1158 VLC_UNUSED(p_fmt_dst);
1159 VLC_UNUSED(i_ts);
1161 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1162 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1164 if (!p_overlay) {
1165 return 1;
1168 int res = p_overlay->status == Outdated;
1170 updater_unlock_overlay(p_upd_sys);
1172 return res;
1175 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1176 const video_format_t *p_fmt_src,
1177 const video_format_t *p_fmt_dst,
1178 mtime_t i_ts)
1180 VLC_UNUSED(p_fmt_src);
1181 VLC_UNUSED(p_fmt_dst);
1182 VLC_UNUSED(i_ts);
1183 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1184 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1186 if (!p_overlay) {
1187 return;
1191 * When this function is called, all p_subpic regions are gone.
1192 * We need to duplicate our regions (stored internaly) to this subpic.
1194 subpicture_region_t *p_src = p_overlay->p_regions;
1195 if (!p_src) {
1196 updater_unlock_overlay(p_upd_sys);
1197 return;
1200 subpicture_region_t **p_dst = &p_subpic->p_region;
1201 while (p_src != NULL) {
1202 *p_dst = subpicture_region_Copy(p_src);
1203 if (*p_dst == NULL)
1204 break;
1205 p_dst = &(*p_dst)->p_next;
1206 p_src = p_src->p_next;
1208 if (*p_dst != NULL)
1209 (*p_dst)->p_next = NULL;
1210 p_overlay->status = Displayed;
1212 updater_unlock_overlay(p_upd_sys);
1215 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1217 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1218 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1220 if (p_overlay) {
1221 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1222 p_overlay->status = ToDisplay;
1223 p_overlay->i_channel = -1;
1224 updater_unlock_overlay(p_upd_sys);
1227 unref_subpicture_updater(p_upd_sys);
1230 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1232 subpicture_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1233 if (unlikely(p_upd_sys == NULL)) {
1234 return NULL;
1237 p_upd_sys->p_overlay = p_ov;
1239 subpicture_updater_t updater = {
1240 .pf_validate = subpictureUpdaterValidate,
1241 .pf_update = subpictureUpdaterUpdate,
1242 .pf_destroy = subpictureUpdaterDestroy,
1243 .p_sys = p_upd_sys,
1246 subpicture_t *p_pic = subpicture_New(&updater);
1247 if (p_pic == NULL) {
1248 free(p_upd_sys);
1249 return NULL;
1252 p_pic->i_original_picture_width = p_ov->width;
1253 p_pic->i_original_picture_height = p_ov->height;
1254 p_pic->b_ephemer = true;
1255 p_pic->b_absolute = true;
1257 vlc_mutex_init(&p_upd_sys->lock);
1258 p_upd_sys->ref_cnt = 2;
1260 p_ov->p_updater = p_upd_sys;
1262 return p_pic;
1265 /*****************************************************************************
1266 * User input events:
1267 *****************************************************************************/
1268 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var, vlc_value_t old,
1269 vlc_value_t val, void *p_data)
1271 demux_t *p_demux = (demux_t*)p_data;
1272 demux_sys_t *p_sys = p_demux->p_sys;
1273 VLC_UNUSED(old);
1274 VLC_UNUSED(p_vout);
1276 if (psz_var[6] == 'm') //Mouse moved
1277 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1278 else if (psz_var[6] == 'c') {
1279 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1280 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1281 } else {
1282 vlc_assert_unreachable();
1284 return VLC_SUCCESS;
1287 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1289 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1290 return VLC_EGENERIC;
1292 return VLC_SUCCESS;
1295 /*****************************************************************************
1296 * libbluray overlay handling:
1297 *****************************************************************************/
1299 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1301 demux_sys_t *p_sys = p_demux->p_sys;
1302 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1304 if (ov != NULL) {
1306 /* drop overlay from vout */
1307 if (ov->p_updater) {
1308 unref_subpicture_updater(ov->p_updater);
1310 /* no references to this overlay exist in vo anymore */
1311 if (p_sys->p_vout && ov->i_channel != -1) {
1312 vout_FlushSubpictureChannel(p_sys->p_vout, ov->i_channel);
1315 vlc_mutex_destroy(&ov->lock);
1316 subpicture_region_ChainDelete(ov->p_regions);
1317 free(ov);
1319 p_sys->p_overlays[plane] = NULL;
1322 for (int i = 0; i < MAX_OVERLAY; i++)
1323 if (p_sys->p_overlays[i])
1324 return;
1326 /* All overlays have been closed */
1327 blurayReleaseVout(p_demux);
1331 * Mark the overlay as "ToDisplay" status.
1332 * This will not send the overlay to the vout instantly, as the vout
1333 * may not be acquired (not acquirable) yet.
1334 * If is has already been acquired, the overlay has already been sent to it,
1335 * therefore, we only flag the overlay as "Outdated"
1337 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1339 demux_sys_t *p_sys = p_demux->p_sys;
1340 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1343 * If the overlay is already displayed, mark the picture as outdated.
1344 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1346 vlc_mutex_lock(&ov->lock);
1347 if (ov->status >= Displayed && p_sys->p_vout) {
1348 ov->status = Outdated;
1349 vlc_mutex_unlock(&ov->lock);
1350 return;
1354 * Mark the overlay as available, but don't display it right now.
1355 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1356 * the overlay is computed
1358 ov->status = ToDisplay;
1359 vlc_mutex_unlock(&ov->lock);
1362 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1364 demux_sys_t *p_sys = p_demux->p_sys;
1366 assert(p_sys->p_overlays[plane] == NULL);
1368 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1369 if (unlikely(ov == NULL))
1370 return;
1372 ov->width = width;
1373 ov->height = height;
1374 ov->i_channel = -1;
1376 vlc_mutex_init(&ov->lock);
1378 p_sys->p_overlays[plane] = ov;
1382 * Destroy every regions in the subpicture.
1383 * This is done in two steps:
1384 * - Wiping our private regions list
1385 * - Flagging the overlay as outdated, so the changes are replicated from
1386 * the subpicture_updater_t::pf_update
1387 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1389 static void blurayClearOverlay(demux_t *p_demux, int plane)
1391 demux_sys_t *p_sys = p_demux->p_sys;
1392 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1394 vlc_mutex_lock(&ov->lock);
1396 subpicture_region_ChainDelete(ov->p_regions);
1397 ov->p_regions = NULL;
1398 ov->status = Outdated;
1400 vlc_mutex_unlock(&ov->lock);
1404 * This will draw to the overlay by adding a region to our region list
1405 * This will have to be copied to the subpicture used to render the overlay.
1407 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1409 demux_sys_t *p_sys = p_demux->p_sys;
1412 * Compute a subpicture_region_t.
1413 * It will be copied and sent to the vout later.
1415 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1417 /* Find a region to update */
1418 subpicture_region_t **pp_reg = &p_sys->p_overlays[ov->plane]->p_regions;
1419 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1420 subpicture_region_t *p_last = NULL;
1421 while (p_reg != NULL) {
1422 p_last = p_reg;
1423 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1424 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1425 break;
1426 pp_reg = &p_reg->p_next;
1427 p_reg = p_reg->p_next;
1430 if (!ov->img) {
1431 if (p_reg) {
1432 /* drop region */
1433 *pp_reg = p_reg->p_next;
1434 subpicture_region_Delete(p_reg);
1436 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1437 return;
1440 /* If there is no region to update, create a new one. */
1441 if (!p_reg) {
1442 video_format_t fmt;
1443 video_format_Init(&fmt, 0);
1444 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1446 p_reg = subpicture_region_New(&fmt);
1447 p_reg->i_x = ov->x;
1448 p_reg->i_y = ov->y;
1449 /* Append it to our list. */
1450 if (p_last != NULL)
1451 p_last->p_next = p_reg;
1452 else /* If we don't have a last region, then our list empty */
1453 p_sys->p_overlays[ov->plane]->p_regions = p_reg;
1456 /* Now we can update the region, regardless it's an update or an insert */
1457 const BD_PG_RLE_ELEM *img = ov->img;
1458 for (int y = 0; y < ov->h; y++)
1459 for (int x = 0; x < ov->w;) {
1460 plane_t *p = &p_reg->p_picture->p[0];
1461 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1462 x += img->len;
1463 img++;
1466 if (ov->palette) {
1467 p_reg->fmt.p_palette->i_entries = 256;
1468 for (int i = 0; i < 256; ++i) {
1469 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1470 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1471 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1472 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1476 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1478 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1482 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1484 demux_t *p_demux = (demux_t*)ptr;
1485 demux_sys_t *p_sys = p_demux->p_sys;
1487 if (!overlay) {
1488 msg_Info(p_demux, "Closing overlays.");
1489 if (p_sys->p_vout)
1490 for (int i = 0; i < MAX_OVERLAY; i++)
1491 blurayCloseOverlay(p_demux, i);
1492 return;
1495 switch (overlay->cmd) {
1496 case BD_OVERLAY_INIT:
1497 msg_Info(p_demux, "Initializing overlay");
1498 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1499 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1500 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1501 break;
1502 case BD_OVERLAY_CLOSE:
1503 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1504 blurayClearOverlay(p_demux, overlay->plane);
1505 blurayCloseOverlay(p_demux, overlay->plane);
1506 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1507 break;
1508 case BD_OVERLAY_CLEAR:
1509 blurayClearOverlay(p_demux, overlay->plane);
1510 break;
1511 case BD_OVERLAY_FLUSH:
1512 blurayActivateOverlay(p_demux, overlay->plane);
1513 break;
1514 case BD_OVERLAY_DRAW:
1515 case BD_OVERLAY_WIPE:
1516 blurayDrawOverlay(p_demux, overlay);
1517 break;
1518 default:
1519 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
1520 break;
1525 * ARGB overlay (BD-J)
1527 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
1529 demux_sys_t *p_sys = p_demux->p_sys;
1531 blurayInitOverlay(p_demux, plane, width, height);
1533 if (!p_sys->p_overlays[plane]->p_regions) {
1534 video_format_t fmt;
1535 video_format_Init(&fmt, 0);
1536 video_format_Setup(&fmt, VLC_CODEC_RGBA, width, height, width, height, 1, 1);
1538 p_sys->p_overlays[plane]->p_regions = subpicture_region_New(&fmt);
1542 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
1544 demux_sys_t *p_sys = p_demux->p_sys;
1546 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1548 /* Find a region to update */
1549 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1550 if (!p_reg) {
1551 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1552 return;
1555 /* Now we can update the region */
1556 const uint32_t *src0 = ov->argb;
1557 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
1558 p_reg->p_picture->p[0].i_pitch * ov->y +
1559 ov->x * 4;
1561 for (int y = 0; y < ov->h; y++) {
1562 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1563 // - or add libbluray option to select the format ?
1564 for (int x = 0; x < ov->w; x++) {
1565 dst0[x*4 ] = src0[x]>>16; /* R */
1566 dst0[x*4+1] = src0[x]>>8; /* G */
1567 dst0[x*4+2] = src0[x]; /* B */
1568 dst0[x*4+3] = src0[x]>>24; /* A */
1571 src0 += ov->stride;
1572 dst0 += p_reg->p_picture->p[0].i_pitch;
1575 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1577 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1581 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
1583 demux_t *p_demux = (demux_t*)ptr;
1584 demux_sys_t *p_sys = p_demux->p_sys;
1586 switch (overlay->cmd) {
1587 case BD_ARGB_OVERLAY_INIT:
1588 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1589 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1590 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1591 break;
1592 case BD_ARGB_OVERLAY_CLOSE:
1593 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1594 blurayClearOverlay(p_demux, overlay->plane);
1595 blurayCloseOverlay(p_demux, overlay->plane);
1596 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1597 break;
1598 case BD_ARGB_OVERLAY_FLUSH:
1599 blurayActivateOverlay(p_demux, overlay->plane);
1600 break;
1601 case BD_ARGB_OVERLAY_DRAW:
1602 blurayDrawArgbOverlay(p_demux, overlay);
1603 break;
1604 default:
1605 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
1606 break;
1610 static void bluraySendOverlayToVout(demux_t *p_demux, bluray_overlay_t *p_ov)
1612 demux_sys_t *p_sys = p_demux->p_sys;
1614 assert(p_ov != NULL);
1615 assert(p_ov->i_channel == -1);
1617 if (p_ov->p_updater) {
1618 unref_subpicture_updater(p_ov->p_updater);
1619 p_ov->p_updater = NULL;
1622 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
1623 if (!p_pic) {
1624 msg_Err(p_demux, "bluraySubpictureCreate() failed");
1625 return;
1628 p_pic->i_start = p_pic->i_stop = mdate();
1629 p_pic->i_channel = vout_RegisterSubpictureChannel(p_sys->p_vout);
1630 p_ov->i_channel = p_pic->i_channel;
1633 * After this point, the picture should not be accessed from the demux thread,
1634 * as it is held by the vout thread.
1635 * This must be done only once per subpicture, ie. only once between each
1636 * blurayInitOverlay & blurayCloseOverlay call.
1638 vout_PutSubpicture(p_sys->p_vout, p_pic);
1641 * Mark the picture as Outdated, as it contains no region for now.
1642 * This will make the subpicture_updater_t call pf_update
1644 p_ov->status = Outdated;
1647 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
1649 t->i_length = FROM_TICKS(title_info->duration);
1651 for (int i = 0; i < t->i_seekpoint; i++)
1652 vlc_seekpoint_Delete( t->seekpoint[i] );
1653 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
1655 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
1656 seekpoint_t *s = vlc_seekpoint_New();
1657 if (!s) {
1658 break;
1660 s->i_time_offset = FROM_TICKS(title_info->chapters[j].start);
1662 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
1666 static void blurayInitTitles(demux_t *p_demux, int menu_titles)
1668 demux_sys_t *p_sys = p_demux->p_sys;
1669 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
1671 /* get and set the titles */
1672 unsigned i_title = menu_titles;
1674 if (!p_sys->b_menu) {
1675 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
1676 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
1679 for (unsigned int i = 0; i < i_title; i++) {
1680 input_title_t *t = vlc_input_title_New();
1681 if (!t)
1682 break;
1684 if (!p_sys->b_menu) {
1685 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
1686 blurayUpdateTitleInfo(t, title_info);
1687 bd_free_title_info(title_info);
1689 } else if (i == 0) {
1690 t->psz_name = strdup(_("Top Menu"));
1691 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
1692 } else if (i == i_title - 1) {
1693 t->psz_name = strdup(_("First Play"));
1694 if (di && di->first_play && di->first_play->interactive) {
1695 t->i_flags = INPUT_TITLE_INTERACTIVE;
1697 } else {
1698 /* add possible title name from disc metadata */
1699 if (di && di->titles && i <= di->num_titles) {
1700 if (di->titles[i]->name) {
1701 t->psz_name = strdup(di->titles[i]->name);
1703 if (di->titles[i]->interactive) {
1704 t->i_flags = INPUT_TITLE_INTERACTIVE;
1709 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
1713 static void blurayResetParser(demux_t *p_demux)
1716 * This is a hack and will have to be removed.
1717 * The parser should be flushed, and not destroy/created each time
1718 * we are changing title.
1720 demux_sys_t *p_sys = p_demux->p_sys;
1721 if (p_sys->p_parser)
1722 vlc_demux_chained_Delete(p_sys->p_parser);
1724 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
1726 if (!p_sys->p_parser)
1727 msg_Err(p_demux, "Failed to create TS demuxer");
1730 /*****************************************************************************
1731 * bluraySetTitle: select new BD title
1732 *****************************************************************************/
1733 static int bluraySetTitle(demux_t *p_demux, int i_title)
1735 demux_sys_t *p_sys = p_demux->p_sys;
1737 if (p_sys->b_menu) {
1738 int result;
1739 if (i_title <= 0) {
1740 msg_Dbg(p_demux, "Playing TopMenu Title");
1741 result = bd_menu_call(p_sys->bluray, -1);
1742 } else if (i_title >= (int)p_sys->i_title - 1) {
1743 msg_Dbg(p_demux, "Playing FirstPlay Title");
1744 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
1745 } else {
1746 msg_Dbg(p_demux, "Playing Title %i", i_title);
1747 result = bd_play_title(p_sys->bluray, i_title);
1750 if (result == 0) {
1751 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
1752 return VLC_EGENERIC;
1755 return VLC_SUCCESS;
1758 /* Looking for the main title, ie the longest duration */
1759 if (i_title < 0)
1760 i_title = p_sys->i_longest_title;
1761 else if ((unsigned)i_title > p_sys->i_title)
1762 return VLC_EGENERIC;
1764 msg_Dbg(p_demux, "Selecting Title %i", i_title);
1766 if (bd_select_title(p_sys->bluray, i_title) == 0) {
1767 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
1768 return VLC_EGENERIC;
1771 return VLC_SUCCESS;
1774 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
1775 # define BLURAY_AUDIO_STREAM 0
1776 #endif
1778 static void blurayStreamSelected(demux_sys_t *p_sys, int i_pid)
1780 vlc_mutex_lock(&p_sys->pl_info_lock);
1782 if (p_sys->p_clip_info) {
1783 if ((i_pid & 0xff00) == 0x1100) {
1784 // audio
1785 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
1786 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
1787 p_sys->i_audio_stream_idx = i_id;
1788 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
1789 break;
1792 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
1793 // subtitle
1794 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
1795 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
1796 p_sys->i_spu_stream_idx = i_id;
1797 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
1798 break;
1804 vlc_mutex_unlock(&p_sys->pl_info_lock);
1807 /*****************************************************************************
1808 * blurayControl: handle the controls
1809 *****************************************************************************/
1810 static int blurayControl(demux_t *p_demux, int query, va_list args)
1812 demux_sys_t *p_sys = p_demux->p_sys;
1813 bool *pb_bool;
1814 int64_t *pi_64;
1816 switch (query) {
1817 case DEMUX_CAN_SEEK:
1818 case DEMUX_CAN_PAUSE:
1819 case DEMUX_CAN_CONTROL_PACE:
1820 pb_bool = va_arg(args, bool *);
1821 *pb_bool = true;
1822 break;
1824 case DEMUX_GET_PTS_DELAY:
1825 pi_64 = va_arg(args, int64_t *);
1826 *pi_64 = INT64_C(1000) * var_InheritInteger(p_demux, "disc-caching");
1827 break;
1829 case DEMUX_SET_PAUSE_STATE:
1831 #ifdef BLURAY_RATE_NORMAL
1832 bool b_paused = (bool)va_arg(args, int);
1833 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
1834 return VLC_EGENERIC;
1836 #endif
1837 break;
1839 case DEMUX_SET_ES:
1841 int i_id = va_arg(args, int);
1842 blurayStreamSelected(p_sys, i_id);
1843 break;
1845 case DEMUX_SET_TITLE:
1847 int i_title = va_arg(args, int);
1848 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
1849 /* make sure GUI restores the old setting in title menu ... */
1850 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1851 return VLC_EGENERIC;
1853 blurayResetParser( p_demux );
1854 notifyDiscontinuity( p_sys );
1855 break;
1857 case DEMUX_SET_SEEKPOINT:
1859 int i_chapter = va_arg(args, int);
1860 bd_seek_chapter(p_sys->bluray, i_chapter);
1861 notifyDiscontinuity( p_sys );
1862 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
1863 break;
1865 case DEMUX_TEST_AND_CLEAR_FLAGS:
1867 unsigned *restrict flags = va_arg(args, unsigned *);
1868 *flags &= p_sys->updates;
1869 p_sys->updates &= ~*flags;
1870 break;
1872 case DEMUX_GET_TITLE:
1873 *va_arg(args, int *) = p_sys->cur_title;
1874 break;
1876 case DEMUX_GET_SEEKPOINT:
1877 *va_arg(args, int *) = p_sys->cur_seekpoint;
1878 break;
1880 case DEMUX_GET_TITLE_INFO:
1882 input_title_t ***ppp_title = va_arg(args, input_title_t***);
1883 int *pi_int = va_arg(args, int *);
1884 int *pi_title_offset = va_arg(args, int *);
1885 int *pi_chapter_offset = va_arg(args, int *);
1887 /* */
1888 *pi_title_offset = 0;
1889 *pi_chapter_offset = 0;
1891 /* Duplicate local title infos */
1892 *pi_int = 0;
1893 *ppp_title = vlc_alloc(p_sys->i_title, sizeof(input_title_t *));
1894 if(!*ppp_title)
1895 return VLC_EGENERIC;
1896 for (unsigned int i = 0; i < p_sys->i_title; i++)
1898 input_title_t *p_dup = vlc_input_title_Duplicate(p_sys->pp_title[i]);
1899 if(p_dup)
1900 (*ppp_title)[(*pi_int)++] = p_dup;
1903 return VLC_SUCCESS;
1906 case DEMUX_GET_LENGTH:
1908 int64_t *pi_length = va_arg(args, int64_t *);
1909 *pi_length = p_sys->cur_title < p_sys->i_title ? CUR_LENGTH : 0;
1910 return VLC_SUCCESS;
1912 case DEMUX_SET_TIME:
1914 int64_t i_time = va_arg(args, int64_t);
1915 bd_seek_time(p_sys->bluray, TO_TICKS(i_time));
1916 notifyDiscontinuity( p_sys );
1917 return VLC_SUCCESS;
1919 case DEMUX_GET_TIME:
1921 int64_t *pi_time = va_arg(args, int64_t *);
1922 *pi_time = (int64_t)FROM_TICKS(bd_tell_time(p_sys->bluray));
1923 return VLC_SUCCESS;
1926 case DEMUX_GET_POSITION:
1928 double *pf_position = va_arg(args, double *);
1929 *pf_position = p_sys->cur_title < p_sys->i_title && CUR_LENGTH > 0 ?
1930 (double)FROM_TICKS(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
1931 return VLC_SUCCESS;
1933 case DEMUX_SET_POSITION:
1935 double f_position = va_arg(args, double);
1936 bd_seek_time(p_sys->bluray, TO_TICKS(f_position*CUR_LENGTH));
1937 notifyDiscontinuity( p_sys );
1938 return VLC_SUCCESS;
1941 case DEMUX_GET_META:
1943 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
1944 const META_DL *meta = p_sys->p_meta;
1945 if (meta == NULL)
1946 return VLC_EGENERIC;
1948 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
1950 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
1951 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
1952 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
1954 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
1955 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
1957 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
1958 char psz_url[128];
1959 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
1960 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
1961 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
1963 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
1964 char *psz_thumbpath;
1965 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
1966 p_sys->psz_bd_path, meta->thumbnails[0].path) > -1) {
1967 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
1968 free(psz_thumbpath);
1969 if (unlikely(psz_thumburl == NULL))
1970 return VLC_ENOMEM;
1972 vlc_meta_SetArtURL(p_meta, psz_thumburl);
1973 free(psz_thumburl);
1977 return VLC_SUCCESS;
1980 case DEMUX_GET_ATTACHMENTS:
1982 input_attachment_t ***ppp_attach =
1983 va_arg(args, input_attachment_t ***);
1984 int *pi_int = va_arg(args, int *);
1986 if (p_sys->i_attachments <= 0)
1987 return VLC_EGENERIC;
1989 *pi_int = 0;
1990 *ppp_attach = vlc_alloc(p_sys->i_attachments, sizeof(input_attachment_t *));
1991 if(!*ppp_attach)
1992 return VLC_EGENERIC;
1993 for (int i = 0; i < p_sys->i_attachments; i++)
1995 input_attachment_t *p_dup = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
1996 if(p_dup)
1997 (*ppp_attach)[(*pi_int)++] = p_dup;
1999 return VLC_SUCCESS;
2002 case DEMUX_NAV_ACTIVATE:
2003 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
2004 return sendKeyEvent(p_sys, BD_VK_POPUP);
2006 return sendKeyEvent(p_sys, BD_VK_ENTER);
2007 case DEMUX_NAV_UP:
2008 return sendKeyEvent(p_sys, BD_VK_UP);
2009 case DEMUX_NAV_DOWN:
2010 return sendKeyEvent(p_sys, BD_VK_DOWN);
2011 case DEMUX_NAV_LEFT:
2012 return sendKeyEvent(p_sys, BD_VK_LEFT);
2013 case DEMUX_NAV_RIGHT:
2014 return sendKeyEvent(p_sys, BD_VK_RIGHT);
2015 case DEMUX_NAV_POPUP:
2016 return sendKeyEvent(p_sys, BD_VK_POPUP);
2017 case DEMUX_NAV_MENU:
2018 if (p_sys->b_menu) {
2019 if (bd_menu_call(p_sys->bluray, -1) == 1) {
2020 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2021 return VLC_SUCCESS;
2023 msg_Err(p_demux, "Can't select Top Menu title");
2024 return sendKeyEvent(p_sys, BD_VK_POPUP);
2026 return VLC_EGENERIC;
2028 case DEMUX_CAN_RECORD:
2029 case DEMUX_GET_FPS:
2030 case DEMUX_SET_GROUP:
2031 case DEMUX_HAS_UNSUPPORTED_META:
2032 default:
2033 return VLC_EGENERIC;
2035 return VLC_SUCCESS;
2038 /*****************************************************************************
2039 * libbluray event handling
2040 *****************************************************************************/
2041 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
2042 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
2044 for( size_t i=0; i< i_sinfo; i++ )
2046 const uint16_t i_pid = p_sinfo[i].pid;
2048 block_t *p_block = block_Alloc(192);
2049 if (!p_block)
2050 return;
2052 uint8_t ts_header[] = {
2053 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2054 0x47,
2055 (i_pid & 0x1f00) >> 8, i_pid & 0xFF, /* PID */
2056 0x20, /* adaptation field, no payload */
2057 183, /* adaptation field length */
2058 0x80, /* adaptation field: discontinuity indicator */
2061 memcpy(p_block->p_buffer, ts_header, sizeof(ts_header));
2062 memset(&p_block->p_buffer[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header));
2063 p_block->i_buffer = 192;
2065 vlc_demux_chained_Send(p_parser, p_block);
2069 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2070 p_clip->memb##_stream_count )
2072 static void notifyDiscontinuity( demux_sys_t *p_sys )
2074 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2075 if( p_clip )
2077 DONOTIFY(audio);
2078 DONOTIFY(video);
2079 DONOTIFY(pg);
2080 DONOTIFY(ig);
2081 DONOTIFY(sec_audio);
2082 DONOTIFY(sec_video);
2086 #undef DONOTIFY
2088 static void streamFlush( demux_sys_t *p_sys )
2091 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2092 * Packet is flushed only when TS packet with PUSI flag set is received.
2094 * Fix this by emitting (video) ts packet with PUSI flag set.
2095 * Add video sequence end code to payload so that also video decoder is flushed.
2096 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2099 if (p_sys->b_flushed)
2100 return;
2102 block_t *p_block = block_Alloc(192);
2103 if (!p_block)
2104 return;
2106 static const uint8_t seq_end_pes[] = {
2107 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2108 0x00, 0x00, 0x01, 0xb7, /* PES payload: sequence end */
2110 static const uint8_t vid_pusi_ts[] = {
2111 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2112 0x47, 0x50, 0x11, 0x30, /* TP header */
2113 (192 - (4 + 5) - sizeof(seq_end_pes)), /* adaptation field length */
2114 0x82, /* af: discontinuity indicator + priv data */
2115 0x0E, /* priv data size */
2116 'V', 'L', 'C', '_',
2117 'S', 'T', 'I', 'L', 'L', 'F', 'R', 'A', 'M', 'E',
2120 memset(p_block->p_buffer, 0, 192);
2121 memcpy(p_block->p_buffer, vid_pusi_ts, sizeof(vid_pusi_ts));
2122 memcpy(p_block->p_buffer + 192 - sizeof(seq_end_pes), seq_end_pes, sizeof(seq_end_pes));
2123 p_block->i_buffer = 192;
2125 /* set correct sequence end code */
2126 vlc_mutex_lock(&p_sys->pl_info_lock);
2127 if (p_sys->p_clip_info != NULL) {
2128 if (p_sys->p_clip_info->video_streams[0].coding_type > 2) {
2129 /* VC1 / H.264 sequence end */
2130 p_block->p_buffer[191] = 0x0a;
2133 vlc_mutex_unlock(&p_sys->pl_info_lock);
2135 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2136 p_sys->b_flushed = true;
2139 static void blurayResetStillImage( demux_t *p_demux )
2141 demux_sys_t *p_sys = p_demux->p_sys;
2143 if (p_sys->i_still_end_time) {
2144 p_sys->i_still_end_time = 0;
2146 blurayResetParser(p_demux);
2147 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2151 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2153 demux_sys_t *p_sys = p_demux->p_sys;
2155 /* time period elapsed ? */
2156 if (p_sys->i_still_end_time > 0 && p_sys->i_still_end_time <= mdate()) {
2157 msg_Dbg(p_demux, "Still image end");
2158 bd_read_skip_still(p_sys->bluray);
2160 blurayResetStillImage(p_demux);
2161 return;
2164 /* show last frame as still image */
2165 if (!p_sys->i_still_end_time) {
2166 if (i_timeout) {
2167 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2168 p_sys->i_still_end_time = mdate() + i_timeout * CLOCK_FREQ;
2169 } else {
2170 msg_Dbg(p_demux, "Still image (infinite)");
2171 p_sys->i_still_end_time = -1;
2174 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2175 streamFlush(p_sys);
2177 /* stop buffering */
2178 bool b_empty;
2179 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2182 /* avoid busy loops (read returns no data) */
2183 msleep( 40000 );
2186 static void blurayStreamSelect(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2188 demux_sys_t *p_sys = p_demux->p_sys;
2189 int i_pid = -1;
2191 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2192 i_id--;
2194 if (i_type == BD_EVENT_AUDIO_STREAM) {
2195 p_sys->i_audio_stream_idx = i_id;
2196 i_pid = blurayEsPid(p_sys, AUDIO_ES, i_id);
2197 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2198 p_sys->i_spu_stream_idx = i_id;
2199 i_pid = blurayEsPid(p_sys, SPU_ES, i_id);
2202 if (i_pid > 0) {
2203 int i_idx = findEsPairIndex(p_sys, i_pid);
2204 if (i_idx >= 0) {
2205 if (i_type == BD_EVENT_AUDIO_STREAM) {
2206 var_SetInteger( p_demux->p_input, "audio-es", i_pid );
2207 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2208 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? i_pid : -1 );
2214 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2216 demux_sys_t *p_sys = p_demux->p_sys;
2218 blurayResetParser(p_demux);
2220 /* read title info and init some values */
2221 if (!p_sys->b_menu)
2222 p_sys->cur_title = bd_get_current_title(p_sys->bluray);
2223 p_sys->cur_seekpoint = 0;
2224 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2226 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2227 if (p_title_info) {
2228 blurayUpdateTitleInfo(p_sys->pp_title[p_sys->cur_title], p_title_info);
2229 if (p_sys->b_menu)
2230 p_sys->updates |= INPUT_UPDATE_TITLE_LIST;
2232 setTitleInfo(p_sys, p_title_info);
2234 blurayResetStillImage(p_demux);
2237 static void blurayUpdateCurrentClip(demux_t *p_demux, uint32_t clip)
2239 demux_sys_t *p_sys = p_demux->p_sys;
2241 vlc_mutex_lock(&p_sys->pl_info_lock);
2243 p_sys->p_clip_info = NULL;
2244 p_sys->i_video_stream = -1;
2246 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2248 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2250 /* Let's assume a single video track for now.
2251 * This may brake later, but it's enough for now.
2253 assert(p_sys->p_clip_info->video_stream_count >= 1);
2254 p_sys->i_video_stream = p_sys->p_clip_info->video_streams[0].pid;
2257 vlc_mutex_unlock(&p_sys->pl_info_lock);
2259 blurayResetStillImage(p_demux);
2262 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e)
2264 demux_sys_t *p_sys = p_demux->p_sys;
2266 switch (e->event) {
2267 case BD_EVENT_TITLE:
2268 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2269 p_sys->cur_title = p_sys->i_title - 1;
2270 else
2271 p_sys->cur_title = e->param;
2272 /* this is feature title, we don't know yet which playlist it will play (if any) */
2273 setTitleInfo(p_sys, NULL);
2274 /* reset title infos here ? */
2275 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2276 /* might be BD-J title with no video */
2277 break;
2278 case BD_EVENT_PLAYLIST:
2279 /* Start of playlist playback (?????.mpls) */
2280 blurayUpdatePlaylist(p_demux, e->param);
2281 if (p_sys->b_pl_playing) {
2282 /* previous playlist was stopped in middle. flush to avoid delay */
2283 msg_Info(p_demux, "Stopping playlist playback");
2284 blurayResetParser(p_demux);
2285 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2287 p_sys->b_pl_playing = true;
2288 break;
2289 case BD_EVENT_PLAYITEM:
2290 blurayUpdateCurrentClip(p_demux, e->param);
2291 break;
2292 case BD_EVENT_CHAPTER:
2293 if (e->param && e->param < 0xffff)
2294 p_sys->cur_seekpoint = e->param - 1;
2295 else
2296 p_sys->cur_seekpoint = 0;
2297 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2298 break;
2299 case BD_EVENT_PLAYMARK:
2300 case BD_EVENT_ANGLE:
2301 break;
2302 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2303 case BD_EVENT_UO_MASK_CHANGED:
2304 /* This event could be used to grey out unselectable items in title menu */
2305 break;
2306 #endif
2307 case BD_EVENT_MENU:
2308 p_sys->b_menu_open = e->param;
2309 break;
2310 case BD_EVENT_POPUP:
2311 p_sys->b_popup_available = e->param;
2312 /* TODO: show / hide pop-up menu button in gui ? */
2313 break;
2316 * Errors
2318 case BD_EVENT_ERROR:
2319 /* fatal error (with menus) */
2320 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2321 "Playback with BluRay menus failed");
2322 p_sys->b_fatal_error = true;
2323 break;
2324 case BD_EVENT_ENCRYPTED:
2325 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2326 "This disc seems to be encrypted");
2327 p_sys->b_fatal_error = true;
2328 break;
2329 case BD_EVENT_READ_ERROR:
2330 msg_Err(p_demux, "bluray: read error\n");
2331 break;
2334 * stream selection events
2336 case BD_EVENT_PG_TEXTST:
2337 p_sys->b_spu_enable = e->param;
2338 break;
2339 case BD_EVENT_AUDIO_STREAM:
2340 case BD_EVENT_PG_TEXTST_STREAM:
2341 blurayStreamSelect(p_demux, e->event, e->param);
2342 break;
2343 case BD_EVENT_IG_STREAM:
2344 case BD_EVENT_SECONDARY_AUDIO:
2345 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2346 case BD_EVENT_SECONDARY_VIDEO:
2347 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2348 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2349 break;
2352 * playback control events
2354 case BD_EVENT_STILL_TIME:
2355 blurayStillImage(p_demux, e->param);
2356 break;
2357 case BD_EVENT_DISCONTINUITY:
2358 /* reset demuxer (partially decoded PES packets must be dropped) */
2359 blurayResetParser(p_demux);
2360 break;
2361 case BD_EVENT_END_OF_TITLE:
2362 p_sys->b_pl_playing = false;
2363 break;
2364 case BD_EVENT_IDLE:
2365 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2366 /* avoid busy loop (bd_read() returns no data) */
2367 msleep( 40000 );
2368 break;
2370 default:
2371 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2372 break;
2376 static bool blurayIsBdjTitle(demux_t *p_demux)
2378 demux_sys_t *p_sys = p_demux->p_sys;
2379 unsigned int i_title = p_sys->cur_title;
2380 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2382 if (di && di->titles) {
2383 if ((i_title <= di->num_titles && di->titles[i_title] && di->titles[i_title]->bdj) ||
2384 (i_title == p_sys->i_title - 1 && di->first_play && di->first_play->bdj)) {
2385 return true;
2389 return false;
2392 static void blurayHandleOverlays(demux_t *p_demux, int nread)
2394 demux_sys_t *p_sys = p_demux->p_sys;
2396 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2398 for (int i = 0; i < MAX_OVERLAY; i++) {
2399 bluray_overlay_t *ov = p_sys->p_overlays[i];
2400 if (!ov) {
2401 continue;
2403 vlc_mutex_lock(&ov->lock);
2404 bool display = ov->status == ToDisplay;
2405 vlc_mutex_unlock(&ov->lock);
2406 if (display) {
2407 if (p_sys->p_vout == NULL) {
2408 p_sys->p_vout = input_GetVout(p_demux->p_input);
2409 if (p_sys->p_vout != NULL) {
2410 var_AddCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
2411 var_AddCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
2415 /* NOTE: we might want to enable background video always when there's no video stream playing.
2416 Now, with some discs, there are perioids (even seconds) during which the video window
2417 disappears and just playlist is shown.
2418 (sometimes BD-J runs slowly ...)
2420 if (!p_sys->p_vout && !p_sys->p_dummy_video && p_sys->b_menu &&
2421 !p_sys->p_pl_info && nread == 0 &&
2422 blurayIsBdjTitle(p_demux)) {
2424 /* Looks like there's no video stream playing.
2425 Emit blank frame so that BD-J overlay can be drawn. */
2426 startBackground(p_demux);
2429 if (p_sys->p_vout != NULL) {
2430 bluraySendOverlayToVout(p_demux, ov);
2435 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2438 static int onIntfEvent( vlc_object_t *p_input, char const *psz_var,
2439 vlc_value_t oldval, vlc_value_t val, void *p_data )
2441 (void)p_input; (void) psz_var; (void) oldval;
2442 demux_t *p_demux = p_data;
2443 demux_sys_t *p_sys = p_demux->p_sys;
2445 if (val.i_int == INPUT_EVENT_VOUT) {
2447 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2448 if( p_sys->p_vout != NULL ) {
2449 blurayReleaseVout(p_demux);
2451 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2453 blurayHandleOverlays(p_demux, 1);
2456 return VLC_SUCCESS;
2459 #define BD_TS_PACKET_SIZE (192)
2460 #define NB_TS_PACKETS (200)
2462 static int blurayDemux(demux_t *p_demux)
2464 demux_sys_t *p_sys = p_demux->p_sys;
2465 BD_EVENT e;
2467 block_t *p_block = block_Alloc(NB_TS_PACKETS * (int64_t)BD_TS_PACKET_SIZE);
2468 if (!p_block)
2469 return VLC_DEMUXER_EGENERIC;
2471 int nread;
2473 if (p_sys->b_menu == false) {
2474 while (bd_get_event(p_sys->bluray, &e))
2475 blurayHandleEvent(p_demux, &e);
2477 nread = bd_read(p_sys->bluray, p_block->p_buffer,
2478 NB_TS_PACKETS * BD_TS_PACKET_SIZE);
2479 } else {
2480 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer,
2481 NB_TS_PACKETS * BD_TS_PACKET_SIZE, &e);
2482 while (e.event != BD_EVENT_NONE) {
2483 blurayHandleEvent(p_demux, &e);
2484 bd_get_event(p_sys->bluray, &e);
2488 blurayHandleOverlays(p_demux, nread);
2490 if (nread <= 0) {
2491 block_Release(p_block);
2492 if (p_sys->b_fatal_error || nread < 0) {
2493 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
2494 return VLC_DEMUXER_EGENERIC;
2496 if (!p_sys->b_menu) {
2497 return VLC_DEMUXER_EOF;
2499 return VLC_DEMUXER_SUCCESS;
2502 p_block->i_buffer = nread;
2504 stopBackground(p_demux);
2506 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2508 p_sys->b_flushed = false;
2510 return VLC_DEMUXER_SUCCESS;