demux: provide full URL instead of access name (refs #18504)
[vlc.git] / modules / access / bluray.c
blob010a169d4404d42a36d40227fd2cb10f4aebf46a
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>
30 #if defined (HAVE_MNTENT_H) && defined(HAVE_SYS_STAT_H)
31 # include <mntent.h>
32 #endif
33 #include <fcntl.h> /* O_* */
34 #include <unistd.h> /* close() */
35 #include <sys/stat.h>
37 #ifdef __APPLE__
38 # include <sys/param.h>
39 # include <sys/ucred.h>
40 # include <sys/mount.h>
41 #endif
43 #include <vlc_common.h>
44 #include <vlc_plugin.h>
45 #include <vlc_demux.h> /* demux_t */
46 #include <vlc_input.h> /* Seekpoints, chapters */
47 #include <vlc_atomic.h>
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", 200)
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;
153 vlc_mutex_t pl_info_lock;
154 BLURAY_TITLE_INFO *p_pl_info;
155 const BLURAY_CLIP_INFO *p_clip_info;
157 /* Attachments */
158 int i_attachments;
159 input_attachment_t **attachments;
160 int i_cover_idx;
162 /* Meta information */
163 const META_DL *p_meta;
165 /* Menus */
166 bluray_overlay_t *p_overlays[MAX_OVERLAY];
167 bool b_fatal_error;
168 bool b_menu;
169 bool b_menu_open;
170 bool b_popup_available;
171 mtime_t i_still_end_time;
173 vlc_mutex_t bdj_overlay_lock; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
175 /* */
176 vout_thread_t *p_vout;
178 es_out_id_t *p_dummy_video;
180 /* TS stream */
181 es_out_t *p_out;
182 vlc_array_t es;
183 int i_audio_stream_idx; /* Selected audio stream. -1 if default */
184 int i_spu_stream_idx; /* Selected subtitle stream. -1 if default */
185 bool b_spu_enable; /* enabled / disabled */
186 int i_video_stream;
187 vlc_demux_chained_t *p_parser;
188 bool b_flushed;
189 bool b_pl_playing; /* true when playing playlist */
191 /* stream input */
192 vlc_mutex_t read_block_lock;
194 /* Used to store bluray disc path */
195 char *psz_bd_path;
198 struct subpicture_updater_sys_t
200 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
201 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
202 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
206 * cut the connection between vout and overlay.
207 * - called when vout is closed or overlay is closed.
208 * - frees subpicture_updater_sys_t when both sides have been closed.
210 static void unref_subpicture_updater(subpicture_updater_sys_t *p_sys)
212 vlc_mutex_lock(&p_sys->lock);
213 int refs = --p_sys->ref_cnt;
214 p_sys->p_overlay = NULL;
215 vlc_mutex_unlock(&p_sys->lock);
217 if (refs < 1) {
218 vlc_mutex_destroy(&p_sys->lock);
219 free(p_sys);
223 /* Get a 3 char code
224 * FIXME: partiallyy duplicated from src/input/es_out.c
226 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
228 const iso639_lang_t *pl;
229 char *psz_lang;
230 char *p;
232 psz_lang = var_CreateGetString( p_demux, psz_var );
233 if( !psz_lang )
234 return LANGUAGE_DEFAULT;
236 /* XXX: we will use only the first value
237 * (and ignore other ones in case of a list) */
238 if( ( p = strchr( psz_lang, ',' ) ) )
239 *p = '\0';
241 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
243 if( *psz_lang == '\0' )
244 continue;
245 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
246 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
247 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
248 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
249 break;
252 free( psz_lang );
254 if( pl->psz_eng_name != NULL )
255 return pl->psz_iso639_2T;
257 return LANGUAGE_DEFAULT;
260 /*****************************************************************************
261 * Local prototypes
262 *****************************************************************************/
263 static es_out_t *esOutNew(demux_t *p_demux);
265 static int blurayControl(demux_t *, int, va_list);
266 static int blurayDemux(demux_t *);
268 static void blurayInitTitles(demux_t *p_demux, int menu_titles);
269 static int bluraySetTitle(demux_t *p_demux, int i_title);
271 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
272 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
274 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var,
275 vlc_value_t old, vlc_value_t val, void *p_data);
276 static int onIntfEvent(vlc_object_t *, char const *,
277 vlc_value_t, vlc_value_t, void *);
279 static void blurayResetParser(demux_t *p_demux);
280 static void notifyDiscontinuity( demux_sys_t *p_sys );
282 #define FROM_TICKS(a) ((a)*CLOCK_FREQ / INT64_C(90000))
283 #define TO_TICKS(a) ((a)*INT64_C(90000)/CLOCK_FREQ)
284 #define CUR_LENGTH p_sys->pp_title[p_demux->info.i_title]->i_length
286 /* */
287 static void FindMountPoint(char **file)
289 char *device = *file;
290 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
291 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
292 * we look up the real device */
293 char *bd_device = realpath(device, NULL);
294 if (bd_device == NULL)
295 return;
297 struct stat st;
298 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
299 FILE *mtab = setmntent ("/proc/self/mounts", "r");
300 struct mntent *m, mbuf;
301 char buf [8192];
303 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
304 if (!strcmp (m->mnt_fsname, bd_device)) {
305 free(device);
306 *file = strdup(m->mnt_dir);
307 break;
310 endmntent (mtab);
312 free(bd_device);
314 #elif defined(__APPLE__)
315 struct stat st;
316 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
317 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
318 if (fs_count > 0) {
319 struct statfs mbuf[128];
320 getfsstat (mbuf, fs_count * sizeof(mbuf[0]), MNT_NOWAIT);
321 for (int i = 0; i < fs_count; ++i)
322 if (!strcmp (mbuf[i].f_mntfromname, device)) {
323 free(device);
324 *file = strdup(mbuf[i].f_mntonname);
325 return;
329 #else
330 # warning Disc device to mount point not implemented
331 VLC_UNUSED( device );
332 #endif
335 static void blurayReleaseVout(demux_t *p_demux)
337 demux_sys_t *p_sys = p_demux->p_sys;
339 if (p_sys->p_vout != NULL) {
340 var_DelCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
341 var_DelCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
343 for (int i = 0; i < MAX_OVERLAY; i++) {
344 bluray_overlay_t *p_ov = p_sys->p_overlays[i];
345 if (p_ov) {
346 vlc_mutex_lock(&p_ov->lock);
347 if (p_ov->i_channel != -1) {
348 msg_Err(p_demux, "blurayReleaseVout: subpicture channel exists\n");
349 vout_FlushSubpictureChannel(p_sys->p_vout, p_ov->i_channel);
351 p_ov->i_channel = -1;
352 p_ov->status = ToDisplay;
353 vlc_mutex_unlock(&p_ov->lock);
355 if (p_ov->p_updater) {
356 unref_subpicture_updater(p_ov->p_updater);
357 p_ov->p_updater = NULL;
362 vlc_object_release(p_sys->p_vout);
363 p_sys->p_vout = NULL;
367 /*****************************************************************************
368 * BD-J background video
369 *****************************************************************************/
371 static void startBackground(demux_t *p_demux)
373 demux_sys_t *p_sys = p_demux->p_sys;
375 if (p_sys->p_dummy_video) {
376 return;
379 msg_Info(p_demux, "Start background");
381 /* */
382 es_format_t fmt;
383 es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_I420 );
384 video_format_Setup( &fmt.video, VLC_CODEC_I420,
385 1920, 1080, 1920, 1080, 1, 1);
386 fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
387 fmt.i_id = 4115; /* 4113 = main video. 4114 = MVC. 4115 = unused. */
388 fmt.i_group = 1;
390 p_sys->p_dummy_video = es_out_Add(p_demux->out, &fmt);
392 if (!p_sys->p_dummy_video) {
393 msg_Err(p_demux, "Error adding background ES");
394 goto out;
397 block_t *p_block = block_Alloc(fmt.video.i_width * fmt.video.i_height *
398 fmt.video.i_bits_per_pixel / 8);
399 if (!p_block) {
400 msg_Err(p_demux, "Error allocating block for background video");
401 goto out;
404 // XXX TODO: what would be correct timestamp ???
405 p_block->i_dts = p_block->i_pts = mdate() + CLOCK_FREQ/25;
407 uint8_t *p = p_block->p_buffer;
408 memset(p, 0, fmt.video.i_width * fmt.video.i_height);
409 p += fmt.video.i_width * fmt.video.i_height;
410 memset(p, 0x80, fmt.video.i_width * fmt.video.i_height / 2);
412 es_out_Send(p_demux->out, p_sys->p_dummy_video, p_block);
414 out:
415 es_format_Clean(&fmt);
418 static void stopBackground(demux_t *p_demux)
420 demux_sys_t *p_sys = p_demux->p_sys;
422 if (!p_sys->p_dummy_video) {
423 return;
426 msg_Info(p_demux, "Stop background");
428 es_out_Del(p_demux->out, p_sys->p_dummy_video);
429 p_sys->p_dummy_video = NULL;
432 /*****************************************************************************
433 * cache current playlist (title) information
434 *****************************************************************************/
436 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
438 vlc_mutex_lock(&p_sys->pl_info_lock);
440 if (p_sys->p_pl_info) {
441 bd_free_title_info(p_sys->p_pl_info);
443 p_sys->p_pl_info = info;
444 p_sys->p_clip_info = NULL;
446 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
447 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
450 vlc_mutex_unlock(&p_sys->pl_info_lock);
453 /*****************************************************************************
454 * create input attachment for thumbnail
455 *****************************************************************************/
457 static void attachThumbnail(demux_t *p_demux)
459 demux_sys_t *p_sys = p_demux->p_sys;
461 if (!p_sys->p_meta)
462 return;
464 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
465 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
466 int64_t size;
467 void *data;
468 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
469 char psz_name[64];
470 input_attachment_t *p_attachment;
472 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
474 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
475 if (p_attachment) {
476 p_sys->i_cover_idx = p_sys->i_attachments;
477 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
480 free(data);
482 #endif
485 /*****************************************************************************
486 * stream input
487 *****************************************************************************/
489 static int probeStream(demux_t *p_demux)
491 /* input must be seekable */
492 bool b_canseek = false;
493 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
494 if (!b_canseek) {
495 return VLC_EGENERIC;
498 /* first sector(s) should be filled with zeros */
499 size_t i_peek;
500 const uint8_t *p_peek;
501 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
502 if( i_peek != 2048 ) {
503 return VLC_EGENERIC;
505 while (i_peek > 0) {
506 if (p_peek[ --i_peek ]) {
507 return VLC_EGENERIC;
511 return VLC_SUCCESS;
514 #ifdef BLURAY_DEMUX
515 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
517 demux_t *p_demux = (demux_t*)object;
518 demux_sys_t *p_sys = p_demux->p_sys;
519 int result = -1;
521 assert(p_demux->s != NULL);
523 vlc_mutex_lock(&p_sys->read_block_lock);
525 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
526 size_t req = (size_t)2048 * num_blocks;
527 ssize_t got;
529 got = vlc_stream_Read( p_demux->s, buf, req);
530 if (got < 0) {
531 msg_Err(p_demux, "read from lba %d failed", lba);
532 } else {
533 result = got / 2048;
535 } else {
536 msg_Err(p_demux, "seek to lba %d failed", lba);
539 vlc_mutex_unlock(&p_sys->read_block_lock);
541 return result;
543 #endif
545 /*****************************************************************************
546 * probing of local files
547 *****************************************************************************/
549 /* Descriptor Tag (ECMA 167, 3/7.2) */
550 static int decode_descriptor_tag(const uint8_t *buf)
552 uint16_t id;
553 uint8_t checksum = 0;
554 int i;
556 id = buf[0] | (buf[1] << 8);
558 /* calculate tag checksum */
559 for (i = 0; i < 4; i++) {
560 checksum = (uint8_t)(checksum + buf[i]);
562 for (i = 5; i < 16; i++) {
563 checksum = (uint8_t)(checksum + buf[i]);
566 if (checksum != buf[4]) {
567 return -1;
570 return id;
573 static int probeFile(const char *psz_name)
575 struct stat stat_info;
576 uint8_t peek[2048];
577 unsigned i;
578 int ret = VLC_EGENERIC;
579 int fd;
581 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
582 if (fd == -1) {
583 return VLC_EGENERIC;
586 if (fstat(fd, &stat_info) == -1) {
587 goto bailout;
589 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
590 goto bailout;
593 /* first sector should be filled with zeros */
594 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
595 goto bailout;
597 for (i = 0; i < sizeof(peek); i++) {
598 if (peek[ i ]) {
599 goto bailout;
603 /* Check AVDP tag checksum */
604 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
605 read(fd, peek, 16) != 16 ||
606 decode_descriptor_tag(peek) != 2) {
607 goto bailout;
610 ret = VLC_SUCCESS;
612 bailout:
613 vlc_close(fd);
614 return ret;
617 /*****************************************************************************
618 * blurayOpen: module init function
619 *****************************************************************************/
620 static int blurayOpen(vlc_object_t *object)
622 demux_t *p_demux = (demux_t*)object;
623 demux_sys_t *p_sys;
624 bool forced;
625 uint64_t i_init_pos = 0;
627 const char *error_msg = NULL;
628 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
630 if (unlikely(!p_demux->p_input))
631 return VLC_EGENERIC;
633 forced = !strncasecmp(p_demux->psz_url, "bluray:", 7);
635 if (p_demux->s) {
636 if (!strncasecmp(p_demux->psz_url, "file:", 5)) {
637 /* use access_demux for local files */
638 return VLC_EGENERIC;
641 if (probeStream(p_demux) != VLC_SUCCESS) {
642 return VLC_EGENERIC;
645 } else if (!forced) {
646 if (!p_demux->psz_filepath) {
647 return VLC_EGENERIC;
650 if (probeFile(p_demux->psz_filepath) != VLC_SUCCESS) {
651 return VLC_EGENERIC;
655 /* */
656 p_demux->p_sys = p_sys = vlc_obj_calloc(object, 1, sizeof(*p_sys));
657 if (unlikely(!p_sys))
658 return VLC_ENOMEM;
660 p_sys->i_audio_stream_idx = -1;
661 p_sys->i_spu_stream_idx = -1;
662 p_sys->i_video_stream = -1;
663 p_sys->i_still_end_time = 0;
665 /* init demux info fields */
666 p_demux->info.i_update = 0;
667 p_demux->info.i_title = 0;
668 p_demux->info.i_seekpoint = 0;
670 TAB_INIT(p_sys->i_title, p_sys->pp_title);
671 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
673 vlc_mutex_init(&p_sys->pl_info_lock);
674 vlc_mutex_init(&p_sys->bdj_overlay_lock);
675 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
677 var_AddCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
679 /* Open BluRay */
680 #ifdef BLURAY_DEMUX
681 if (p_demux->s) {
682 i_init_pos = vlc_stream_Tell(p_demux->s);
684 p_sys->bluray = bd_init();
685 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
686 bd_close(p_sys->bluray);
687 p_sys->bluray = NULL;
689 } else
690 #endif
692 if (!p_demux->psz_filepath) {
693 /* no path provided (bluray://). use default DVD device. */
694 p_sys->psz_bd_path = var_InheritString(object, "dvd");
695 } else {
696 /* store current bd path */
697 p_sys->psz_bd_path = strdup(p_demux->psz_filepath);
700 /* If we're passed a block device, try to convert it to the mount point. */
701 FindMountPoint(&p_sys->psz_bd_path);
703 p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
705 if (!p_sys->bluray) {
706 goto error;
709 /* Warning the user about AACS/BD+ */
710 const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
712 /* Is it a bluray? */
713 if (!disc_info->bluray_detected) {
714 if (forced) {
715 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
717 goto error;
720 msg_Info(p_demux, "First play: %i, Top menu: %i\n"
721 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
722 disc_info->first_play_supported, disc_info->top_menu_supported,
723 disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
724 disc_info->num_unsupported_titles);
726 /* AACS */
727 if (disc_info->aacs_detected) {
728 msg_Dbg(p_demux, "Disc is using AACS");
729 if (!disc_info->libaacs_detected)
730 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
731 ", and your system does not have it."));
732 if (!disc_info->aacs_handled) {
733 if (disc_info->aacs_error_code) {
734 switch (disc_info->aacs_error_code) {
735 case BD_AACS_CORRUPTED_DISC:
736 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
737 case BD_AACS_NO_CONFIG:
738 BLURAY_ERROR(_("Missing AACS configuration file!"));
739 case BD_AACS_NO_PK:
740 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
741 case BD_AACS_NO_CERT:
742 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
743 case BD_AACS_CERT_REVOKED:
744 BLURAY_ERROR(_("AACS Host certificate revoked."));
745 case BD_AACS_MMC_FAILED:
746 BLURAY_ERROR(_("AACS MMC failed."));
752 /* BD+ */
753 if (disc_info->bdplus_detected) {
754 msg_Dbg(p_demux, "Disc is using BD+");
755 if (!disc_info->libbdplus_detected)
756 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
757 ", and your system does not have it."));
758 if (!disc_info->bdplus_handled)
759 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
760 "Missing configuration?"));
763 /* set player region code */
764 char *psz_region = var_InheritString(p_demux, "bluray-region");
765 unsigned int region = psz_region ? (psz_region[0] - 'A') : REGION_DEFAULT;
766 free(psz_region);
767 bd_set_player_setting(p_sys->bluray, BLURAY_PLAYER_SETTING_REGION_CODE, 1<<region);
769 /* set preferred languages */
770 const char *psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
771 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG, psz_code);
772 psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
773 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG, psz_code);
774 psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
775 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_MENU_LANG, psz_code);
777 /* Get disc metadata */
778 p_sys->p_meta = bd_get_meta(p_sys->bluray);
779 if (!p_sys->p_meta)
780 msg_Warn(p_demux, "Failed to get meta info.");
782 p_sys->i_cover_idx = -1;
783 attachThumbnail(p_demux);
785 p_sys->b_menu = var_InheritBool(p_demux, "bluray-menu");
787 /* Check BD-J capability */
788 if (p_sys->b_menu && disc_info->bdj_detected && !disc_info->bdj_handled) {
789 msg_Err(p_demux, "BD-J menus not supported. Playing without menus. "
790 "BD-J support: %d, JVM found: %d, JVM usable: %d",
791 disc_info->bdj_supported, disc_info->libjvm_detected, disc_info->bdj_handled);
792 vlc_dialog_display_error(p_demux, _("Java required"),
793 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
794 !disc_info->libjvm_detected ? _("Java was not found on your system.") : "");
795 p_sys->b_menu = false;
798 /* Get titles and chapters */
799 blurayInitTitles(p_demux, disc_info->num_hdmv_titles + disc_info->num_bdj_titles + 1/*Top Menu*/ + 1/*First Play*/);
802 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
804 bd_get_event(p_sys->bluray, NULL);
806 /* Registering overlay event handler */
807 bd_register_overlay_proc(p_sys->bluray, p_demux, blurayOverlayProc);
809 if (p_sys->b_menu) {
811 /* Register ARGB overlay handler for BD-J */
812 if (disc_info->num_bdj_titles)
813 bd_register_argb_overlay_proc(p_sys->bluray, p_demux, blurayArgbOverlayProc, NULL);
815 /* libbluray will start playback from "First-Title" title */
816 if (bd_play(p_sys->bluray) == 0)
817 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
819 } else {
820 /* set start title number */
821 if (bluraySetTitle(p_demux, p_sys->i_longest_title) != VLC_SUCCESS) {
822 msg_Err(p_demux, "Could not set the title %d", p_sys->i_longest_title);
823 goto error;
827 vlc_array_init(&p_sys->es);
828 p_sys->p_out = esOutNew(p_demux);
829 if (unlikely(p_sys->p_out == NULL))
830 goto error;
832 blurayResetParser(p_demux);
833 if (!p_sys->p_parser) {
834 msg_Err(p_demux, "Failed to create TS demuxer");
835 goto error;
838 p_demux->pf_control = blurayControl;
839 p_demux->pf_demux = blurayDemux;
841 return VLC_SUCCESS;
843 error:
844 if (error_msg)
845 vlc_dialog_display_error(p_demux, _("Blu-ray error"), "%s", error_msg);
846 blurayClose(object);
848 if (p_demux->s != NULL) {
849 /* restore stream position */
850 if (vlc_stream_Seek(p_demux->s, i_init_pos) != VLC_SUCCESS) {
851 msg_Err(p_demux, "Failed to seek back to stream start");
852 return VLC_ETIMEOUT;
856 return VLC_EGENERIC;
857 #undef BLURAY_ERROR
861 /*****************************************************************************
862 * blurayClose: module destroy function
863 *****************************************************************************/
864 static void blurayClose(vlc_object_t *object)
866 demux_t *p_demux = (demux_t*)object;
867 demux_sys_t *p_sys = p_demux->p_sys;
869 var_DelCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
871 setTitleInfo(p_sys, NULL);
874 * Close libbluray first.
875 * This will close all the overlays before we release p_vout
876 * bd_close(NULL) can crash
878 if (p_sys->bluray) {
879 bd_close(p_sys->bluray);
882 blurayReleaseVout(p_demux);
884 if (p_sys->p_parser)
885 vlc_demux_chained_Delete(p_sys->p_parser);
886 if (p_sys->p_out != NULL)
887 es_out_Delete(p_sys->p_out);
888 assert(vlc_array_count(&p_sys->es) == 0);
889 vlc_array_clear(&p_sys->es);
891 /* Titles */
892 for (unsigned int i = 0; i < p_sys->i_title; i++)
893 vlc_input_title_Delete(p_sys->pp_title[i]);
894 TAB_CLEAN(p_sys->i_title, p_sys->pp_title);
896 for (int i = 0; i < p_sys->i_attachments; i++)
897 vlc_input_attachment_Delete(p_sys->attachments[i]);
898 TAB_CLEAN(p_sys->i_attachments, p_sys->attachments);
900 vlc_mutex_destroy(&p_sys->pl_info_lock);
901 vlc_mutex_destroy(&p_sys->bdj_overlay_lock);
902 vlc_mutex_destroy(&p_sys->read_block_lock);
904 free(p_sys->psz_bd_path);
907 /*****************************************************************************
908 * Elementary streams handling
909 *****************************************************************************/
911 struct es_out_sys_t {
912 demux_t *p_demux;
915 typedef struct fmt_es_pair {
916 int i_id;
917 es_out_id_t *p_es;
918 } fmt_es_pair_t;
920 static int findEsPairIndex(demux_sys_t *p_sys, int i_id)
922 for (size_t i = 0; i < vlc_array_count(&p_sys->es); ++i)
923 if (((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->i_id == i_id)
924 return i;
926 return -1;
929 static int findEsPairIndexByEs(demux_sys_t *p_sys, es_out_id_t *p_es)
931 for (size_t i = 0; i < vlc_array_count(&p_sys->es); ++i)
932 if (((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->p_es == p_es)
933 return i;
935 return -1;
938 static void setStreamLang(demux_sys_t *p_sys, es_format_t *p_fmt)
940 const BLURAY_STREAM_INFO *p_streams;
941 int i_stream_count = 0;
943 vlc_mutex_lock(&p_sys->pl_info_lock);
945 if (p_sys->p_clip_info) {
946 if (p_fmt->i_cat == AUDIO_ES) {
947 p_streams = p_sys->p_clip_info->audio_streams;
948 i_stream_count = p_sys->p_clip_info->audio_stream_count;
949 } else if (p_fmt->i_cat == SPU_ES) {
950 p_streams = p_sys->p_clip_info->pg_streams;
951 i_stream_count = p_sys->p_clip_info->pg_stream_count;
955 for (int i = 0; i < i_stream_count; i++) {
956 if (p_fmt->i_id == p_streams[i].pid) {
957 free(p_fmt->psz_language);
958 p_fmt->psz_language = strndup((const char *)p_streams[i].lang, 3);
959 break;
963 vlc_mutex_unlock(&p_sys->pl_info_lock);
966 static int blurayEsPid(demux_sys_t *p_sys, int es_type, int i_es_idx)
968 int i_pid = -1;
970 vlc_mutex_lock(&p_sys->pl_info_lock);
972 if (p_sys->p_clip_info) {
973 if (es_type == AUDIO_ES) {
974 if (i_es_idx >= 0 && i_es_idx < p_sys->p_clip_info->audio_stream_count) {
975 i_pid = p_sys->p_clip_info->audio_streams[i_es_idx].pid;
977 } else if (es_type == SPU_ES) {
978 if (i_es_idx >= 0 && i_es_idx < p_sys->p_clip_info->pg_stream_count) {
979 i_pid = p_sys->p_clip_info->pg_streams[i_es_idx].pid;
984 vlc_mutex_unlock(&p_sys->pl_info_lock);
986 return i_pid;
989 static es_out_id_t *esOutAdd(es_out_t *p_out, const es_format_t *p_fmt)
991 demux_t *p_demux = p_out->p_sys->p_demux;
992 demux_sys_t *p_sys = p_demux->p_sys;
993 es_format_t fmt;
994 bool b_select = false;
996 es_format_Copy(&fmt, p_fmt);
998 switch (fmt.i_cat) {
999 case VIDEO_ES:
1000 if (p_sys->i_video_stream != -1 && p_sys->i_video_stream != p_fmt->i_id)
1001 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1002 break ;
1003 case AUDIO_ES:
1004 if (p_sys->i_audio_stream_idx != -1) {
1005 if (blurayEsPid(p_sys, AUDIO_ES, p_sys->i_audio_stream_idx) == p_fmt->i_id)
1006 b_select = true;
1007 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1009 setStreamLang(p_sys, &fmt);
1010 break ;
1011 case SPU_ES:
1012 if (p_sys->i_spu_stream_idx != -1) {
1013 if (blurayEsPid(p_sys, SPU_ES, p_sys->i_spu_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 ;
1021 es_out_id_t *p_es = es_out_Add(p_demux->out, &fmt);
1022 if (p_fmt->i_id >= 0) {
1023 /* Ensure we are not overriding anything */
1024 int idx = findEsPairIndex(p_sys, p_fmt->i_id);
1025 if (idx == -1) {
1026 fmt_es_pair_t *p_pair = malloc(sizeof(*p_pair));
1027 if (likely(p_pair != NULL)) {
1028 p_pair->i_id = p_fmt->i_id;
1029 p_pair->p_es = p_es;
1030 msg_Info(p_demux, "Adding ES %d", p_fmt->i_id);
1031 vlc_array_append_or_abort(&p_sys->es, p_pair);
1033 if (b_select) {
1034 if (fmt.i_cat == AUDIO_ES) {
1035 var_SetInteger( p_demux->p_input, "audio-es", p_fmt->i_id );
1036 } else if (fmt.i_cat == SPU_ES) {
1037 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? p_fmt->i_id : -1 );
1043 es_format_Clean(&fmt);
1044 return p_es;
1047 static int esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1049 return es_out_Send(p_out->p_sys->p_demux->out, p_es, p_block);
1052 static void esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1054 int idx = findEsPairIndexByEs(p_out->p_sys->p_demux->p_sys, p_es);
1055 if (idx >= 0) {
1056 free(vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, idx));
1057 vlc_array_remove(&p_out->p_sys->p_demux->p_sys->es, idx);
1059 es_out_Del(p_out->p_sys->p_demux->out, p_es);
1062 static int esOutControl(es_out_t *p_out, int i_query, va_list args)
1064 return es_out_vaControl(p_out->p_sys->p_demux->out, i_query, args);
1067 static void esOutDestroy(es_out_t *p_out)
1069 for (size_t i = 0; i < vlc_array_count(&p_out->p_sys->p_demux->p_sys->es); ++i)
1070 free(vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, i));
1071 vlc_array_clear(&p_out->p_sys->p_demux->p_sys->es);
1072 free(p_out->p_sys);
1073 free(p_out);
1076 static es_out_t *esOutNew(demux_t *p_demux)
1078 assert(vlc_array_count(&p_demux->p_sys->es) == 0);
1079 es_out_t *p_out = malloc(sizeof(*p_out));
1080 if (unlikely(p_out == NULL))
1081 return NULL;
1083 p_out->pf_add = esOutAdd;
1084 p_out->pf_control = esOutControl;
1085 p_out->pf_del = esOutDel;
1086 p_out->pf_destroy = esOutDestroy;
1087 p_out->pf_send = esOutSend;
1089 p_out->p_sys = malloc(sizeof(*p_out->p_sys));
1090 if (unlikely(p_out->p_sys == NULL)) {
1091 free(p_out);
1092 return NULL;
1094 p_out->p_sys->p_demux = p_demux;
1095 return p_out;
1098 /*****************************************************************************
1099 * subpicture_updater_t functions:
1100 *****************************************************************************/
1102 static bluray_overlay_t *updater_lock_overlay(subpicture_updater_sys_t *p_upd_sys)
1104 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1105 vlc_mutex_lock(&p_upd_sys->lock);
1107 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1108 if (ov) {
1109 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1110 vlc_mutex_lock(&ov->lock);
1111 return ov;
1114 /* overlay has been closed */
1115 vlc_mutex_unlock(&p_upd_sys->lock);
1116 return NULL;
1119 static void updater_unlock_overlay(subpicture_updater_sys_t *p_upd_sys)
1121 assert (p_upd_sys->p_overlay);
1123 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1124 vlc_mutex_unlock(&p_upd_sys->lock);
1127 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1128 bool b_fmt_src, const video_format_t *p_fmt_src,
1129 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1130 mtime_t i_ts)
1132 VLC_UNUSED(b_fmt_src);
1133 VLC_UNUSED(b_fmt_dst);
1134 VLC_UNUSED(p_fmt_src);
1135 VLC_UNUSED(p_fmt_dst);
1136 VLC_UNUSED(i_ts);
1138 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1139 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1141 if (!p_overlay) {
1142 return 1;
1145 int res = p_overlay->status == Outdated;
1147 updater_unlock_overlay(p_upd_sys);
1149 return res;
1152 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1153 const video_format_t *p_fmt_src,
1154 const video_format_t *p_fmt_dst,
1155 mtime_t i_ts)
1157 VLC_UNUSED(p_fmt_src);
1158 VLC_UNUSED(p_fmt_dst);
1159 VLC_UNUSED(i_ts);
1160 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1161 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1163 if (!p_overlay) {
1164 return;
1168 * When this function is called, all p_subpic regions are gone.
1169 * We need to duplicate our regions (stored internaly) to this subpic.
1171 subpicture_region_t *p_src = p_overlay->p_regions;
1172 if (!p_src) {
1173 updater_unlock_overlay(p_upd_sys);
1174 return;
1177 subpicture_region_t **p_dst = &p_subpic->p_region;
1178 while (p_src != NULL) {
1179 *p_dst = subpicture_region_Copy(p_src);
1180 if (*p_dst == NULL)
1181 break;
1182 p_dst = &(*p_dst)->p_next;
1183 p_src = p_src->p_next;
1185 if (*p_dst != NULL)
1186 (*p_dst)->p_next = NULL;
1187 p_overlay->status = Displayed;
1189 updater_unlock_overlay(p_upd_sys);
1192 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1194 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1195 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1197 if (p_overlay) {
1198 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1199 p_overlay->status = ToDisplay;
1200 p_overlay->i_channel = -1;
1201 updater_unlock_overlay(p_upd_sys);
1204 unref_subpicture_updater(p_upd_sys);
1207 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1209 subpicture_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1210 if (unlikely(p_upd_sys == NULL)) {
1211 return NULL;
1214 p_upd_sys->p_overlay = p_ov;
1216 subpicture_updater_t updater = {
1217 .pf_validate = subpictureUpdaterValidate,
1218 .pf_update = subpictureUpdaterUpdate,
1219 .pf_destroy = subpictureUpdaterDestroy,
1220 .p_sys = p_upd_sys,
1223 subpicture_t *p_pic = subpicture_New(&updater);
1224 if (p_pic == NULL) {
1225 free(p_upd_sys);
1226 return NULL;
1229 p_pic->i_original_picture_width = p_ov->width;
1230 p_pic->i_original_picture_height = p_ov->height;
1231 p_pic->b_ephemer = true;
1232 p_pic->b_absolute = true;
1234 vlc_mutex_init(&p_upd_sys->lock);
1235 p_upd_sys->ref_cnt = 2;
1237 p_ov->p_updater = p_upd_sys;
1239 return p_pic;
1242 /*****************************************************************************
1243 * User input events:
1244 *****************************************************************************/
1245 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var, vlc_value_t old,
1246 vlc_value_t val, void *p_data)
1248 demux_t *p_demux = (demux_t*)p_data;
1249 demux_sys_t *p_sys = p_demux->p_sys;
1250 VLC_UNUSED(old);
1251 VLC_UNUSED(p_vout);
1253 if (psz_var[6] == 'm') //Mouse moved
1254 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1255 else if (psz_var[6] == 'c') {
1256 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1257 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1258 } else {
1259 vlc_assert_unreachable();
1261 return VLC_SUCCESS;
1264 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1266 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1267 return VLC_EGENERIC;
1269 return VLC_SUCCESS;
1272 /*****************************************************************************
1273 * libbluray overlay handling:
1274 *****************************************************************************/
1276 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1278 demux_sys_t *p_sys = p_demux->p_sys;
1279 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1281 if (ov != NULL) {
1283 /* drop overlay from vout */
1284 if (ov->p_updater) {
1285 unref_subpicture_updater(ov->p_updater);
1287 /* no references to this overlay exist in vo anymore */
1288 if (p_sys->p_vout && ov->i_channel != -1) {
1289 vout_FlushSubpictureChannel(p_sys->p_vout, ov->i_channel);
1292 vlc_mutex_destroy(&ov->lock);
1293 subpicture_region_ChainDelete(ov->p_regions);
1294 free(ov);
1296 p_sys->p_overlays[plane] = NULL;
1299 for (int i = 0; i < MAX_OVERLAY; i++)
1300 if (p_sys->p_overlays[i])
1301 return;
1303 /* All overlays have been closed */
1304 blurayReleaseVout(p_demux);
1308 * Mark the overlay as "ToDisplay" status.
1309 * This will not send the overlay to the vout instantly, as the vout
1310 * may not be acquired (not acquirable) yet.
1311 * If is has already been acquired, the overlay has already been sent to it,
1312 * therefore, we only flag the overlay as "Outdated"
1314 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1316 demux_sys_t *p_sys = p_demux->p_sys;
1317 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1320 * If the overlay is already displayed, mark the picture as outdated.
1321 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1323 vlc_mutex_lock(&ov->lock);
1324 if (ov->status >= Displayed && p_sys->p_vout) {
1325 ov->status = Outdated;
1326 vlc_mutex_unlock(&ov->lock);
1327 return;
1331 * Mark the overlay as available, but don't display it right now.
1332 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1333 * the overlay is computed
1335 ov->status = ToDisplay;
1336 vlc_mutex_unlock(&ov->lock);
1339 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1341 demux_sys_t *p_sys = p_demux->p_sys;
1343 assert(p_sys->p_overlays[plane] == NULL);
1345 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1346 if (unlikely(ov == NULL))
1347 return;
1349 ov->width = width;
1350 ov->height = height;
1351 ov->i_channel = -1;
1353 vlc_mutex_init(&ov->lock);
1355 p_sys->p_overlays[plane] = ov;
1359 * Destroy every regions in the subpicture.
1360 * This is done in two steps:
1361 * - Wiping our private regions list
1362 * - Flagging the overlay as outdated, so the changes are replicated from
1363 * the subpicture_updater_t::pf_update
1364 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1366 static void blurayClearOverlay(demux_t *p_demux, int plane)
1368 demux_sys_t *p_sys = p_demux->p_sys;
1369 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1371 vlc_mutex_lock(&ov->lock);
1373 subpicture_region_ChainDelete(ov->p_regions);
1374 ov->p_regions = NULL;
1375 ov->status = Outdated;
1377 vlc_mutex_unlock(&ov->lock);
1381 * This will draw to the overlay by adding a region to our region list
1382 * This will have to be copied to the subpicture used to render the overlay.
1384 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1386 demux_sys_t *p_sys = p_demux->p_sys;
1389 * Compute a subpicture_region_t.
1390 * It will be copied and sent to the vout later.
1392 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1394 /* Find a region to update */
1395 subpicture_region_t **pp_reg = &p_sys->p_overlays[ov->plane]->p_regions;
1396 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1397 subpicture_region_t *p_last = NULL;
1398 while (p_reg != NULL) {
1399 p_last = p_reg;
1400 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1401 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1402 break;
1403 pp_reg = &p_reg->p_next;
1404 p_reg = p_reg->p_next;
1407 if (!ov->img) {
1408 if (p_reg) {
1409 /* drop region */
1410 *pp_reg = p_reg->p_next;
1411 subpicture_region_Delete(p_reg);
1413 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1414 return;
1417 /* If there is no region to update, create a new one. */
1418 if (!p_reg) {
1419 video_format_t fmt;
1420 video_format_Init(&fmt, 0);
1421 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1423 p_reg = subpicture_region_New(&fmt);
1424 p_reg->i_x = ov->x;
1425 p_reg->i_y = ov->y;
1426 /* Append it to our list. */
1427 if (p_last != NULL)
1428 p_last->p_next = p_reg;
1429 else /* If we don't have a last region, then our list empty */
1430 p_sys->p_overlays[ov->plane]->p_regions = p_reg;
1433 /* Now we can update the region, regardless it's an update or an insert */
1434 const BD_PG_RLE_ELEM *img = ov->img;
1435 for (int y = 0; y < ov->h; y++)
1436 for (int x = 0; x < ov->w;) {
1437 plane_t *p = &p_reg->p_picture->p[0];
1438 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1439 x += img->len;
1440 img++;
1443 if (ov->palette) {
1444 p_reg->fmt.p_palette->i_entries = 256;
1445 for (int i = 0; i < 256; ++i) {
1446 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1447 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1448 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1449 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1453 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1455 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1459 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1461 demux_t *p_demux = (demux_t*)ptr;
1462 demux_sys_t *p_sys = p_demux->p_sys;
1464 if (!overlay) {
1465 msg_Info(p_demux, "Closing overlays.");
1466 if (p_sys->p_vout)
1467 for (int i = 0; i < MAX_OVERLAY; i++)
1468 blurayCloseOverlay(p_demux, i);
1469 return;
1472 switch (overlay->cmd) {
1473 case BD_OVERLAY_INIT:
1474 msg_Info(p_demux, "Initializing overlay");
1475 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1476 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1477 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1478 break;
1479 case BD_OVERLAY_CLOSE:
1480 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1481 blurayClearOverlay(p_demux, overlay->plane);
1482 blurayCloseOverlay(p_demux, overlay->plane);
1483 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1484 break;
1485 case BD_OVERLAY_CLEAR:
1486 blurayClearOverlay(p_demux, overlay->plane);
1487 break;
1488 case BD_OVERLAY_FLUSH:
1489 blurayActivateOverlay(p_demux, overlay->plane);
1490 break;
1491 case BD_OVERLAY_DRAW:
1492 case BD_OVERLAY_WIPE:
1493 blurayDrawOverlay(p_demux, overlay);
1494 break;
1495 default:
1496 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
1497 break;
1502 * ARGB overlay (BD-J)
1504 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
1506 demux_sys_t *p_sys = p_demux->p_sys;
1508 blurayInitOverlay(p_demux, plane, width, height);
1510 if (!p_sys->p_overlays[plane]->p_regions) {
1511 video_format_t fmt;
1512 video_format_Init(&fmt, 0);
1513 video_format_Setup(&fmt, VLC_CODEC_RGBA, width, height, width, height, 1, 1);
1515 p_sys->p_overlays[plane]->p_regions = subpicture_region_New(&fmt);
1519 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
1521 demux_sys_t *p_sys = p_demux->p_sys;
1523 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1525 /* Find a region to update */
1526 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1527 if (!p_reg) {
1528 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1529 return;
1532 /* Now we can update the region */
1533 const uint32_t *src0 = ov->argb;
1534 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
1535 p_reg->p_picture->p[0].i_pitch * ov->y +
1536 ov->x * 4;
1538 for (int y = 0; y < ov->h; y++) {
1539 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1540 // - or add libbluray option to select the format ?
1541 for (int x = 0; x < ov->w; x++) {
1542 dst0[x*4 ] = src0[x]>>16; /* R */
1543 dst0[x*4+1] = src0[x]>>8; /* G */
1544 dst0[x*4+2] = src0[x]; /* B */
1545 dst0[x*4+3] = src0[x]>>24; /* A */
1548 src0 += ov->stride;
1549 dst0 += p_reg->p_picture->p[0].i_pitch;
1552 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1554 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1558 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
1560 demux_t *p_demux = (demux_t*)ptr;
1561 demux_sys_t *p_sys = p_demux->p_sys;
1563 switch (overlay->cmd) {
1564 case BD_ARGB_OVERLAY_INIT:
1565 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1566 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1567 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1568 break;
1569 case BD_ARGB_OVERLAY_CLOSE:
1570 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1571 blurayClearOverlay(p_demux, overlay->plane);
1572 blurayCloseOverlay(p_demux, overlay->plane);
1573 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1574 break;
1575 case BD_ARGB_OVERLAY_FLUSH:
1576 blurayActivateOverlay(p_demux, overlay->plane);
1577 break;
1578 case BD_ARGB_OVERLAY_DRAW:
1579 blurayDrawArgbOverlay(p_demux, overlay);
1580 break;
1581 default:
1582 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
1583 break;
1587 static void bluraySendOverlayToVout(demux_t *p_demux, bluray_overlay_t *p_ov)
1589 demux_sys_t *p_sys = p_demux->p_sys;
1591 assert(p_ov != NULL);
1592 assert(p_ov->i_channel == -1);
1594 if (p_ov->p_updater) {
1595 unref_subpicture_updater(p_ov->p_updater);
1596 p_ov->p_updater = NULL;
1599 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
1600 if (!p_pic) {
1601 msg_Err(p_demux, "bluraySubpictureCreate() failed");
1602 return;
1605 p_pic->i_start = p_pic->i_stop = mdate();
1606 p_pic->i_channel = vout_RegisterSubpictureChannel(p_sys->p_vout);
1607 p_ov->i_channel = p_pic->i_channel;
1610 * After this point, the picture should not be accessed from the demux thread,
1611 * as it is held by the vout thread.
1612 * This must be done only once per subpicture, ie. only once between each
1613 * blurayInitOverlay & blurayCloseOverlay call.
1615 vout_PutSubpicture(p_sys->p_vout, p_pic);
1618 * Mark the picture as Outdated, as it contains no region for now.
1619 * This will make the subpicture_updater_t call pf_update
1621 p_ov->status = Outdated;
1624 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
1626 t->i_length = FROM_TICKS(title_info->duration);
1628 for (int i = 0; i < t->i_seekpoint; i++)
1629 vlc_seekpoint_Delete( t->seekpoint[i] );
1630 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
1632 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
1633 seekpoint_t *s = vlc_seekpoint_New();
1634 if (!s) {
1635 break;
1637 s->i_time_offset = FROM_TICKS(title_info->chapters[j].start);
1639 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
1643 static void blurayInitTitles(demux_t *p_demux, int menu_titles)
1645 demux_sys_t *p_sys = p_demux->p_sys;
1646 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
1648 /* get and set the titles */
1649 unsigned i_title = menu_titles;
1651 if (!p_sys->b_menu) {
1652 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
1653 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
1656 for (unsigned int i = 0; i < i_title; i++) {
1657 input_title_t *t = vlc_input_title_New();
1658 if (!t)
1659 break;
1661 if (!p_sys->b_menu) {
1662 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
1663 blurayUpdateTitleInfo(t, title_info);
1664 bd_free_title_info(title_info);
1666 } else if (i == 0) {
1667 t->psz_name = strdup(_("Top Menu"));
1668 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
1669 } else if (i == i_title - 1) {
1670 t->psz_name = strdup(_("First Play"));
1671 if (di && di->first_play && di->first_play->interactive) {
1672 t->i_flags = INPUT_TITLE_INTERACTIVE;
1674 } else {
1675 /* add possible title name from disc metadata */
1676 if (di && di->titles && i <= di->num_titles) {
1677 if (di->titles[i]->name) {
1678 t->psz_name = strdup(di->titles[i]->name);
1680 if (di->titles[i]->interactive) {
1681 t->i_flags = INPUT_TITLE_INTERACTIVE;
1686 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
1690 static void blurayResetParser(demux_t *p_demux)
1693 * This is a hack and will have to be removed.
1694 * The parser should be flushed, and not destroy/created each time
1695 * we are changing title.
1697 demux_sys_t *p_sys = p_demux->p_sys;
1698 if (p_sys->p_parser)
1699 vlc_demux_chained_Delete(p_sys->p_parser);
1701 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
1703 if (!p_sys->p_parser)
1704 msg_Err(p_demux, "Failed to create TS demuxer");
1707 /*****************************************************************************
1708 * bluraySetTitle: select new BD title
1709 *****************************************************************************/
1710 static int bluraySetTitle(demux_t *p_demux, int i_title)
1712 demux_sys_t *p_sys = p_demux->p_sys;
1714 if (p_sys->b_menu) {
1715 int result;
1716 if (i_title <= 0) {
1717 msg_Dbg(p_demux, "Playing TopMenu Title");
1718 result = bd_menu_call(p_sys->bluray, -1);
1719 } else if (i_title >= (int)p_sys->i_title - 1) {
1720 msg_Dbg(p_demux, "Playing FirstPlay Title");
1721 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
1722 } else {
1723 msg_Dbg(p_demux, "Playing Title %i", i_title);
1724 result = bd_play_title(p_sys->bluray, i_title);
1727 if (result == 0) {
1728 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
1729 return VLC_EGENERIC;
1732 return VLC_SUCCESS;
1735 /* Looking for the main title, ie the longest duration */
1736 if (i_title < 0)
1737 i_title = p_sys->i_longest_title;
1738 else if ((unsigned)i_title > p_sys->i_title)
1739 return VLC_EGENERIC;
1741 msg_Dbg(p_demux, "Selecting Title %i", i_title);
1743 if (bd_select_title(p_sys->bluray, i_title) == 0) {
1744 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
1745 return VLC_EGENERIC;
1748 return VLC_SUCCESS;
1751 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
1752 # define BLURAY_AUDIO_STREAM 0
1753 #endif
1755 static void blurayStreamSelected(demux_sys_t *p_sys, int i_pid)
1757 vlc_mutex_lock(&p_sys->pl_info_lock);
1759 if (p_sys->p_clip_info) {
1760 if ((i_pid & 0xff00) == 0x1100) {
1761 // audio
1762 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
1763 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
1764 p_sys->i_audio_stream_idx = i_id;
1765 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
1766 break;
1769 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
1770 // subtitle
1771 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
1772 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
1773 p_sys->i_spu_stream_idx = i_id;
1774 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
1775 break;
1781 vlc_mutex_unlock(&p_sys->pl_info_lock);
1784 /*****************************************************************************
1785 * blurayControl: handle the controls
1786 *****************************************************************************/
1787 static int blurayControl(demux_t *p_demux, int query, va_list args)
1789 demux_sys_t *p_sys = p_demux->p_sys;
1790 bool *pb_bool;
1791 int64_t *pi_64;
1793 switch (query) {
1794 case DEMUX_CAN_SEEK:
1795 case DEMUX_CAN_PAUSE:
1796 case DEMUX_CAN_CONTROL_PACE:
1797 pb_bool = va_arg(args, bool *);
1798 *pb_bool = true;
1799 break;
1801 case DEMUX_GET_PTS_DELAY:
1802 pi_64 = va_arg(args, int64_t *);
1803 *pi_64 = INT64_C(1000) * var_InheritInteger(p_demux, "disc-caching");
1804 break;
1806 case DEMUX_SET_PAUSE_STATE:
1808 #ifdef BLURAY_RATE_NORMAL
1809 bool b_paused = (bool)va_arg(args, int);
1810 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
1811 return VLC_EGENERIC;
1813 #endif
1814 break;
1816 case DEMUX_SET_ES:
1818 int i_id = va_arg(args, int);
1819 blurayStreamSelected(p_sys, i_id);
1820 break;
1822 case DEMUX_SET_TITLE:
1824 int i_title = va_arg(args, int);
1825 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
1826 /* make sure GUI restores the old setting in title menu ... */
1827 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1828 return VLC_EGENERIC;
1830 blurayResetParser( p_demux );
1831 notifyDiscontinuity( p_sys );
1832 break;
1834 case DEMUX_SET_SEEKPOINT:
1836 int i_chapter = va_arg(args, int);
1837 bd_seek_chapter(p_sys->bluray, i_chapter);
1838 notifyDiscontinuity( p_sys );
1839 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
1840 break;
1843 case DEMUX_GET_TITLE_INFO:
1845 input_title_t ***ppp_title = va_arg(args, input_title_t***);
1846 int *pi_int = va_arg(args, int *);
1847 int *pi_title_offset = va_arg(args, int *);
1848 int *pi_chapter_offset = va_arg(args, int *);
1850 /* */
1851 *pi_title_offset = 0;
1852 *pi_chapter_offset = 0;
1854 /* Duplicate local title infos */
1855 *pi_int = 0;
1856 *ppp_title = vlc_alloc(p_sys->i_title, sizeof(input_title_t *));
1857 if(!*ppp_title)
1858 return VLC_EGENERIC;
1859 for (unsigned int i = 0; i < p_sys->i_title; i++)
1861 input_title_t *p_dup = vlc_input_title_Duplicate(p_sys->pp_title[i]);
1862 if(p_dup)
1863 (*ppp_title)[(*pi_int)++] = p_dup;
1866 return VLC_SUCCESS;
1869 case DEMUX_GET_LENGTH:
1871 int64_t *pi_length = va_arg(args, int64_t *);
1872 *pi_length = p_demux->info.i_title < (int)p_sys->i_title ? CUR_LENGTH : 0;
1873 return VLC_SUCCESS;
1875 case DEMUX_SET_TIME:
1877 int64_t i_time = va_arg(args, int64_t);
1878 bd_seek_time(p_sys->bluray, TO_TICKS(i_time));
1879 notifyDiscontinuity( p_sys );
1880 return VLC_SUCCESS;
1882 case DEMUX_GET_TIME:
1884 int64_t *pi_time = va_arg(args, int64_t *);
1885 *pi_time = (int64_t)FROM_TICKS(bd_tell_time(p_sys->bluray));
1886 return VLC_SUCCESS;
1889 case DEMUX_GET_POSITION:
1891 double *pf_position = va_arg(args, double *);
1892 *pf_position = p_demux->info.i_title < (int)p_sys->i_title && CUR_LENGTH > 0 ?
1893 (double)FROM_TICKS(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
1894 return VLC_SUCCESS;
1896 case DEMUX_SET_POSITION:
1898 double f_position = va_arg(args, double);
1899 bd_seek_time(p_sys->bluray, TO_TICKS(f_position*CUR_LENGTH));
1900 notifyDiscontinuity( p_sys );
1901 return VLC_SUCCESS;
1904 case DEMUX_GET_META:
1906 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
1907 const META_DL *meta = p_sys->p_meta;
1908 if (meta == NULL)
1909 return VLC_EGENERIC;
1911 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
1913 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
1914 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
1915 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
1917 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
1918 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
1920 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
1921 char psz_url[128];
1922 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
1923 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
1924 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
1926 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
1927 char *psz_thumbpath;
1928 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
1929 p_sys->psz_bd_path, meta->thumbnails[0].path) > -1) {
1930 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
1931 free(psz_thumbpath);
1932 if (unlikely(psz_thumburl == NULL))
1933 return VLC_ENOMEM;
1935 vlc_meta_SetArtURL(p_meta, psz_thumburl);
1936 free(psz_thumburl);
1940 return VLC_SUCCESS;
1943 case DEMUX_GET_ATTACHMENTS:
1945 input_attachment_t ***ppp_attach =
1946 va_arg(args, input_attachment_t ***);
1947 int *pi_int = va_arg(args, int *);
1949 if (p_sys->i_attachments <= 0)
1950 return VLC_EGENERIC;
1952 *pi_int = 0;
1953 *ppp_attach = vlc_alloc(p_sys->i_attachments, sizeof(input_attachment_t *));
1954 if(!*ppp_attach)
1955 return VLC_EGENERIC;
1956 for (int i = 0; i < p_sys->i_attachments; i++)
1958 input_attachment_t *p_dup = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
1959 if(p_dup)
1960 (*ppp_attach)[(*pi_int)++] = p_dup;
1962 return VLC_SUCCESS;
1965 case DEMUX_NAV_ACTIVATE:
1966 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
1967 return sendKeyEvent(p_sys, BD_VK_POPUP);
1969 return sendKeyEvent(p_sys, BD_VK_ENTER);
1970 case DEMUX_NAV_UP:
1971 return sendKeyEvent(p_sys, BD_VK_UP);
1972 case DEMUX_NAV_DOWN:
1973 return sendKeyEvent(p_sys, BD_VK_DOWN);
1974 case DEMUX_NAV_LEFT:
1975 return sendKeyEvent(p_sys, BD_VK_LEFT);
1976 case DEMUX_NAV_RIGHT:
1977 return sendKeyEvent(p_sys, BD_VK_RIGHT);
1978 case DEMUX_NAV_POPUP:
1979 return sendKeyEvent(p_sys, BD_VK_POPUP);
1980 case DEMUX_NAV_MENU:
1981 if (p_sys->b_menu) {
1982 if (bd_menu_call(p_sys->bluray, -1) == 1) {
1983 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1984 return VLC_SUCCESS;
1986 msg_Err(p_demux, "Can't select Top Menu title");
1987 return sendKeyEvent(p_sys, BD_VK_POPUP);
1989 return VLC_EGENERIC;
1991 case DEMUX_CAN_RECORD:
1992 case DEMUX_GET_FPS:
1993 case DEMUX_SET_GROUP:
1994 case DEMUX_HAS_UNSUPPORTED_META:
1995 default:
1996 return VLC_EGENERIC;
1998 return VLC_SUCCESS;
2001 /*****************************************************************************
2002 * libbluray event handling
2003 *****************************************************************************/
2004 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
2005 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
2007 for( size_t i=0; i< i_sinfo; i++ )
2009 const uint16_t i_pid = p_sinfo[i].pid;
2011 block_t *p_block = block_Alloc(192);
2012 if (!p_block)
2013 return;
2015 uint8_t ts_header[] = {
2016 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2017 0x47,
2018 (i_pid & 0x1f00) >> 8, i_pid & 0xFF, /* PID */
2019 0x20, /* adaptation field, no payload */
2020 183, /* adaptation field length */
2021 0x80, /* adaptation field: discontinuity indicator */
2024 memcpy(p_block->p_buffer, ts_header, sizeof(ts_header));
2025 memset(&p_block->p_buffer[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header));
2026 p_block->i_buffer = 192;
2028 vlc_demux_chained_Send(p_parser, p_block);
2032 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2033 p_clip->memb##_stream_count )
2035 static void notifyDiscontinuity( demux_sys_t *p_sys )
2037 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2038 if( p_clip )
2040 DONOTIFY(audio);
2041 DONOTIFY(video);
2042 DONOTIFY(pg);
2043 DONOTIFY(ig);
2044 DONOTIFY(sec_audio);
2045 DONOTIFY(sec_video);
2049 #undef DONOTIFY
2051 static void streamFlush( demux_sys_t *p_sys )
2054 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2055 * Packet is flushed only when TS packet with PUSI flag set is received.
2057 * Fix this by emitting (video) ts packet with PUSI flag set.
2058 * Add video sequence end code to payload so that also video decoder is flushed.
2059 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2062 if (p_sys->b_flushed)
2063 return;
2065 block_t *p_block = block_Alloc(192);
2066 if (!p_block)
2067 return;
2069 static const uint8_t seq_end_pes[] = {
2070 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2071 0x00, 0x00, 0x01, 0xb7, /* PES payload: sequence end */
2073 static const uint8_t vid_pusi_ts[] = {
2074 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2075 0x47, 0x50, 0x11, 0x30, /* TP header */
2076 (192 - (4 + 5) - sizeof(seq_end_pes)), /* adaptation field length */
2077 0x80, /* adaptation field: discontinuity indicator */
2080 memset(p_block->p_buffer, 0, 192);
2081 memcpy(p_block->p_buffer, vid_pusi_ts, sizeof(vid_pusi_ts));
2082 memcpy(p_block->p_buffer + 192 - sizeof(seq_end_pes), seq_end_pes, sizeof(seq_end_pes));
2083 p_block->i_buffer = 192;
2085 /* set correct sequence end code */
2086 vlc_mutex_lock(&p_sys->pl_info_lock);
2087 if (p_sys->p_clip_info != NULL) {
2088 if (p_sys->p_clip_info->video_streams[0].coding_type > 2) {
2089 /* VC1 / H.264 sequence end */
2090 p_block->p_buffer[191] = 0x0a;
2093 vlc_mutex_unlock(&p_sys->pl_info_lock);
2095 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2096 p_sys->b_flushed = true;
2099 static void blurayResetStillImage( demux_t *p_demux )
2101 demux_sys_t *p_sys = p_demux->p_sys;
2103 if (p_sys->i_still_end_time) {
2104 p_sys->i_still_end_time = 0;
2106 blurayResetParser(p_demux);
2107 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2111 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2113 demux_sys_t *p_sys = p_demux->p_sys;
2115 /* time period elapsed ? */
2116 if (p_sys->i_still_end_time > 0 && p_sys->i_still_end_time <= mdate()) {
2117 msg_Dbg(p_demux, "Still image end");
2118 bd_read_skip_still(p_sys->bluray);
2120 blurayResetStillImage(p_demux);
2121 return;
2124 /* show last frame as still image */
2125 if (!p_sys->i_still_end_time) {
2126 if (i_timeout) {
2127 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2128 p_sys->i_still_end_time = mdate() + i_timeout * CLOCK_FREQ;
2129 } else {
2130 msg_Dbg(p_demux, "Still image (infinite)");
2131 p_sys->i_still_end_time = -1;
2134 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2135 streamFlush(p_sys);
2137 /* stop buffering */
2138 bool b_empty;
2139 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2142 /* avoid busy loops (read returns no data) */
2143 msleep( 40000 );
2146 static void blurayStreamSelect(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2148 demux_sys_t *p_sys = p_demux->p_sys;
2149 int i_pid = -1;
2151 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2152 i_id--;
2154 if (i_type == BD_EVENT_AUDIO_STREAM) {
2155 p_sys->i_audio_stream_idx = i_id;
2156 i_pid = blurayEsPid(p_sys, AUDIO_ES, i_id);
2157 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2158 p_sys->i_spu_stream_idx = i_id;
2159 i_pid = blurayEsPid(p_sys, SPU_ES, i_id);
2162 if (i_pid > 0) {
2163 int i_idx = findEsPairIndex(p_sys, i_pid);
2164 if (i_idx >= 0) {
2165 if (i_type == BD_EVENT_AUDIO_STREAM) {
2166 var_SetInteger( p_demux->p_input, "audio-es", i_pid );
2167 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2168 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? i_pid : -1 );
2174 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2176 demux_sys_t *p_sys = p_demux->p_sys;
2178 blurayResetParser(p_demux);
2180 /* read title info and init some values */
2181 if (!p_sys->b_menu)
2182 p_demux->info.i_title = bd_get_current_title(p_sys->bluray);
2183 p_demux->info.i_seekpoint = 0;
2184 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2186 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2187 if (p_title_info) {
2188 blurayUpdateTitleInfo(p_sys->pp_title[p_demux->info.i_title], p_title_info);
2189 if (p_sys->b_menu)
2190 p_demux->info.i_update |= INPUT_UPDATE_TITLE_LIST;
2192 setTitleInfo(p_sys, p_title_info);
2194 blurayResetStillImage(p_demux);
2197 static void blurayUpdateCurrentClip(demux_t *p_demux, uint32_t clip)
2199 demux_sys_t *p_sys = p_demux->p_sys;
2201 vlc_mutex_lock(&p_sys->pl_info_lock);
2203 p_sys->p_clip_info = NULL;
2204 p_sys->i_video_stream = -1;
2206 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2208 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2210 /* Let's assume a single video track for now.
2211 * This may brake later, but it's enough for now.
2213 assert(p_sys->p_clip_info->video_stream_count >= 1);
2214 p_sys->i_video_stream = p_sys->p_clip_info->video_streams[0].pid;
2217 vlc_mutex_unlock(&p_sys->pl_info_lock);
2219 blurayResetStillImage(p_demux);
2222 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e)
2224 demux_sys_t *p_sys = p_demux->p_sys;
2226 switch (e->event) {
2227 case BD_EVENT_TITLE:
2228 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2229 p_demux->info.i_title = p_sys->i_title - 1;
2230 else
2231 p_demux->info.i_title = e->param;
2232 /* this is feature title, we don't know yet which playlist it will play (if any) */
2233 setTitleInfo(p_sys, NULL);
2234 /* reset title infos here ? */
2235 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT; /* might be BD-J title with no video */
2236 break;
2237 case BD_EVENT_PLAYLIST:
2238 /* Start of playlist playback (?????.mpls) */
2239 blurayUpdatePlaylist(p_demux, e->param);
2240 if (p_sys->b_pl_playing) {
2241 /* previous playlist was stopped in middle. flush to avoid delay */
2242 msg_Info(p_demux, "Stopping playlist playback");
2243 blurayResetParser(p_demux);
2244 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2246 p_sys->b_pl_playing = true;
2247 break;
2248 case BD_EVENT_PLAYITEM:
2249 blurayUpdateCurrentClip(p_demux, e->param);
2250 break;
2251 case BD_EVENT_CHAPTER:
2252 if (e->param && e->param < 0xffff)
2253 p_demux->info.i_seekpoint = e->param - 1;
2254 else
2255 p_demux->info.i_seekpoint = 0;
2256 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
2257 break;
2258 case BD_EVENT_PLAYMARK:
2259 case BD_EVENT_ANGLE:
2260 break;
2261 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2262 case BD_EVENT_UO_MASK_CHANGED:
2263 /* This event could be used to grey out unselectable items in title menu */
2264 break;
2265 #endif
2266 case BD_EVENT_MENU:
2267 p_sys->b_menu_open = e->param;
2268 break;
2269 case BD_EVENT_POPUP:
2270 p_sys->b_popup_available = e->param;
2271 /* TODO: show / hide pop-up menu button in gui ? */
2272 break;
2275 * Errors
2277 case BD_EVENT_ERROR:
2278 /* fatal error (with menus) */
2279 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2280 "Playback with BluRay menus failed");
2281 p_sys->b_fatal_error = true;
2282 break;
2283 case BD_EVENT_ENCRYPTED:
2284 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2285 "This disc seems to be encrypted");
2286 p_sys->b_fatal_error = true;
2287 break;
2288 case BD_EVENT_READ_ERROR:
2289 msg_Err(p_demux, "bluray: read error\n");
2290 break;
2293 * stream selection events
2295 case BD_EVENT_PG_TEXTST:
2296 p_sys->b_spu_enable = e->param;
2297 break;
2298 case BD_EVENT_AUDIO_STREAM:
2299 case BD_EVENT_PG_TEXTST_STREAM:
2300 blurayStreamSelect(p_demux, e->event, e->param);
2301 break;
2302 case BD_EVENT_IG_STREAM:
2303 case BD_EVENT_SECONDARY_AUDIO:
2304 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2305 case BD_EVENT_SECONDARY_VIDEO:
2306 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2307 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2308 break;
2311 * playback control events
2313 case BD_EVENT_STILL_TIME:
2314 blurayStillImage(p_demux, e->param);
2315 break;
2316 case BD_EVENT_DISCONTINUITY:
2317 /* reset demuxer (partially decoded PES packets must be dropped) */
2318 blurayResetParser(p_demux);
2319 break;
2320 case BD_EVENT_END_OF_TITLE:
2321 p_sys->b_pl_playing = false;
2322 break;
2323 case BD_EVENT_IDLE:
2324 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2325 /* avoid busy loop (bd_read() returns no data) */
2326 msleep( 40000 );
2327 break;
2329 default:
2330 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2331 break;
2335 static bool blurayIsBdjTitle(demux_t *p_demux)
2337 demux_sys_t *p_sys = p_demux->p_sys;
2338 unsigned int i_title = p_demux->info.i_title;
2339 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2341 if (di && di->titles) {
2342 if ((i_title <= di->num_titles && di->titles[i_title] && di->titles[i_title]->bdj) ||
2343 (i_title == p_sys->i_title - 1 && di->first_play && di->first_play->bdj)) {
2344 return true;
2348 return false;
2351 static void blurayHandleOverlays(demux_t *p_demux, int nread)
2353 demux_sys_t *p_sys = p_demux->p_sys;
2355 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2357 for (int i = 0; i < MAX_OVERLAY; i++) {
2358 bluray_overlay_t *ov = p_sys->p_overlays[i];
2359 if (!ov) {
2360 continue;
2362 vlc_mutex_lock(&ov->lock);
2363 bool display = ov->status == ToDisplay;
2364 vlc_mutex_unlock(&ov->lock);
2365 if (display) {
2366 if (p_sys->p_vout == NULL) {
2367 p_sys->p_vout = input_GetVout(p_demux->p_input);
2368 if (p_sys->p_vout != NULL) {
2369 var_AddCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
2370 var_AddCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
2374 /* NOTE: we might want to enable background video always when there's no video stream playing.
2375 Now, with some discs, there are perioids (even seconds) during which the video window
2376 disappears and just playlist is shown.
2377 (sometimes BD-J runs slowly ...)
2379 if (!p_sys->p_vout && !p_sys->p_dummy_video && p_sys->b_menu &&
2380 !p_sys->p_pl_info && nread == 0 &&
2381 blurayIsBdjTitle(p_demux)) {
2383 /* Looks like there's no video stream playing.
2384 Emit blank frame so that BD-J overlay can be drawn. */
2385 startBackground(p_demux);
2388 if (p_sys->p_vout != NULL) {
2389 bluraySendOverlayToVout(p_demux, ov);
2394 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2397 static int onIntfEvent( vlc_object_t *p_input, char const *psz_var,
2398 vlc_value_t oldval, vlc_value_t val, void *p_data )
2400 (void)p_input; (void) psz_var; (void) oldval;
2401 demux_t *p_demux = p_data;
2402 demux_sys_t *p_sys = p_demux->p_sys;
2404 if (val.i_int == INPUT_EVENT_VOUT) {
2406 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2407 if( p_sys->p_vout != NULL ) {
2408 blurayReleaseVout(p_demux);
2410 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2412 blurayHandleOverlays(p_demux, 1);
2415 return VLC_SUCCESS;
2418 #define BD_TS_PACKET_SIZE (192)
2419 #define NB_TS_PACKETS (200)
2421 static int blurayDemux(demux_t *p_demux)
2423 demux_sys_t *p_sys = p_demux->p_sys;
2424 BD_EVENT e;
2426 block_t *p_block = block_Alloc(NB_TS_PACKETS * (int64_t)BD_TS_PACKET_SIZE);
2427 if (!p_block)
2428 return VLC_DEMUXER_EGENERIC;
2430 int nread;
2432 if (p_sys->b_menu == false) {
2433 while (bd_get_event(p_sys->bluray, &e))
2434 blurayHandleEvent(p_demux, &e);
2436 nread = bd_read(p_sys->bluray, p_block->p_buffer,
2437 NB_TS_PACKETS * BD_TS_PACKET_SIZE);
2438 } else {
2439 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer,
2440 NB_TS_PACKETS * BD_TS_PACKET_SIZE, &e);
2441 while (e.event != BD_EVENT_NONE) {
2442 blurayHandleEvent(p_demux, &e);
2443 bd_get_event(p_sys->bluray, &e);
2447 blurayHandleOverlays(p_demux, nread);
2449 if (nread <= 0) {
2450 block_Release(p_block);
2451 if (p_sys->b_fatal_error || nread < 0) {
2452 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
2453 return VLC_DEMUXER_EGENERIC;
2455 if (!p_sys->b_menu) {
2456 return VLC_DEMUXER_EOF;
2458 return VLC_DEMUXER_SUCCESS;
2461 p_block->i_buffer = nread;
2463 stopBackground(p_demux);
2465 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2467 p_sys->b_flushed = false;
2469 return VLC_DEMUXER_SUCCESS;