access: srt: add support stream encryption
[vlc.git] / modules / access / bluray.c
blob3b982fb1ee085da32877bd7b6ab0f083ed01a6a3
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;
152 unsigned cur_title;
153 unsigned cur_seekpoint;
155 vlc_mutex_t pl_info_lock;
156 BLURAY_TITLE_INFO *p_pl_info;
157 const BLURAY_CLIP_INFO *p_clip_info;
159 /* Attachments */
160 int i_attachments;
161 input_attachment_t **attachments;
162 int i_cover_idx;
164 /* Meta information */
165 const META_DL *p_meta;
167 /* Menus */
168 bluray_overlay_t *p_overlays[MAX_OVERLAY];
169 bool b_fatal_error;
170 bool b_menu;
171 bool b_menu_open;
172 bool b_popup_available;
173 mtime_t i_still_end_time;
175 vlc_mutex_t bdj_overlay_lock; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
177 /* */
178 vout_thread_t *p_vout;
180 es_out_id_t *p_dummy_video;
182 /* TS stream */
183 es_out_t *p_out;
184 vlc_array_t es;
185 int i_audio_stream_idx; /* Selected audio stream. -1 if default */
186 int i_spu_stream_idx; /* Selected subtitle stream. -1 if default */
187 bool b_spu_enable; /* enabled / disabled */
188 int i_video_stream;
189 vlc_demux_chained_t *p_parser;
190 bool b_flushed;
191 bool b_pl_playing; /* true when playing playlist */
193 /* stream input */
194 vlc_mutex_t read_block_lock;
196 /* Used to store bluray disc path */
197 char *psz_bd_path;
200 struct subpicture_updater_sys_t
202 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
203 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
204 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
208 * cut the connection between vout and overlay.
209 * - called when vout is closed or overlay is closed.
210 * - frees subpicture_updater_sys_t when both sides have been closed.
212 static void unref_subpicture_updater(subpicture_updater_sys_t *p_sys)
214 vlc_mutex_lock(&p_sys->lock);
215 int refs = --p_sys->ref_cnt;
216 p_sys->p_overlay = NULL;
217 vlc_mutex_unlock(&p_sys->lock);
219 if (refs < 1) {
220 vlc_mutex_destroy(&p_sys->lock);
221 free(p_sys);
225 /* Get a 3 char code
226 * FIXME: partiallyy duplicated from src/input/es_out.c
228 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
230 const iso639_lang_t *pl;
231 char *psz_lang;
232 char *p;
234 psz_lang = var_CreateGetString( p_demux, psz_var );
235 if( !psz_lang )
236 return LANGUAGE_DEFAULT;
238 /* XXX: we will use only the first value
239 * (and ignore other ones in case of a list) */
240 if( ( p = strchr( psz_lang, ',' ) ) )
241 *p = '\0';
243 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
245 if( *psz_lang == '\0' )
246 continue;
247 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
248 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
249 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
250 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
251 break;
254 free( psz_lang );
256 if( pl->psz_eng_name != NULL )
257 return pl->psz_iso639_2T;
259 return LANGUAGE_DEFAULT;
262 /*****************************************************************************
263 * Local prototypes
264 *****************************************************************************/
265 static es_out_t *esOutNew(demux_t *p_demux);
267 static int blurayControl(demux_t *, int, va_list);
268 static int blurayDemux(demux_t *);
270 static void blurayInitTitles(demux_t *p_demux, int menu_titles);
271 static int bluraySetTitle(demux_t *p_demux, int i_title);
273 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
274 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
276 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var,
277 vlc_value_t old, vlc_value_t val, void *p_data);
278 static int onIntfEvent(vlc_object_t *, char const *,
279 vlc_value_t, vlc_value_t, void *);
281 static void blurayResetParser(demux_t *p_demux);
282 static void notifyDiscontinuity( demux_sys_t *p_sys );
284 #define FROM_TICKS(a) ((a)*CLOCK_FREQ / INT64_C(90000))
285 #define TO_TICKS(a) ((a)*INT64_C(90000)/CLOCK_FREQ)
286 #define CUR_LENGTH p_sys->pp_title[p_sys->cur_title]->i_length
288 /* */
289 static void FindMountPoint(char **file)
291 char *device = *file;
292 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
293 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
294 * we look up the real device */
295 char *bd_device = realpath(device, NULL);
296 if (bd_device == NULL)
297 return;
299 struct stat st;
300 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
301 FILE *mtab = setmntent ("/proc/self/mounts", "r");
302 struct mntent *m, mbuf;
303 char buf [8192];
305 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
306 if (!strcmp (m->mnt_fsname, bd_device)) {
307 free(device);
308 *file = strdup(m->mnt_dir);
309 break;
312 endmntent (mtab);
314 free(bd_device);
316 #elif defined(__APPLE__)
317 struct stat st;
318 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
319 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
320 if (fs_count > 0) {
321 struct statfs mbuf[128];
322 getfsstat (mbuf, fs_count * sizeof(mbuf[0]), MNT_NOWAIT);
323 for (int i = 0; i < fs_count; ++i)
324 if (!strcmp (mbuf[i].f_mntfromname, device)) {
325 free(device);
326 *file = strdup(mbuf[i].f_mntonname);
327 return;
331 #else
332 # warning Disc device to mount point not implemented
333 VLC_UNUSED( device );
334 #endif
337 static void blurayReleaseVout(demux_t *p_demux)
339 demux_sys_t *p_sys = p_demux->p_sys;
341 if (p_sys->p_vout != NULL) {
342 var_DelCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
343 var_DelCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
345 for (int i = 0; i < MAX_OVERLAY; i++) {
346 bluray_overlay_t *p_ov = p_sys->p_overlays[i];
347 if (p_ov) {
348 vlc_mutex_lock(&p_ov->lock);
349 if (p_ov->i_channel != -1) {
350 msg_Err(p_demux, "blurayReleaseVout: subpicture channel exists\n");
351 vout_FlushSubpictureChannel(p_sys->p_vout, p_ov->i_channel);
353 p_ov->i_channel = -1;
354 p_ov->status = ToDisplay;
355 vlc_mutex_unlock(&p_ov->lock);
357 if (p_ov->p_updater) {
358 unref_subpicture_updater(p_ov->p_updater);
359 p_ov->p_updater = NULL;
364 vlc_object_release(p_sys->p_vout);
365 p_sys->p_vout = NULL;
369 /*****************************************************************************
370 * BD-J background video
371 *****************************************************************************/
373 static void startBackground(demux_t *p_demux)
375 demux_sys_t *p_sys = p_demux->p_sys;
377 if (p_sys->p_dummy_video) {
378 return;
381 msg_Info(p_demux, "Start background");
383 /* */
384 es_format_t fmt;
385 es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_I420 );
386 video_format_Setup( &fmt.video, VLC_CODEC_I420,
387 1920, 1080, 1920, 1080, 1, 1);
388 fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
389 fmt.i_id = 4115; /* 4113 = main video. 4114 = MVC. 4115 = unused. */
390 fmt.i_group = 1;
392 p_sys->p_dummy_video = es_out_Add(p_demux->out, &fmt);
394 if (!p_sys->p_dummy_video) {
395 msg_Err(p_demux, "Error adding background ES");
396 goto out;
399 block_t *p_block = block_Alloc(fmt.video.i_width * fmt.video.i_height *
400 fmt.video.i_bits_per_pixel / 8);
401 if (!p_block) {
402 msg_Err(p_demux, "Error allocating block for background video");
403 goto out;
406 // XXX TODO: what would be correct timestamp ???
407 p_block->i_dts = p_block->i_pts = mdate() + CLOCK_FREQ/25;
409 uint8_t *p = p_block->p_buffer;
410 memset(p, 0, fmt.video.i_width * fmt.video.i_height);
411 p += fmt.video.i_width * fmt.video.i_height;
412 memset(p, 0x80, fmt.video.i_width * fmt.video.i_height / 2);
414 es_out_Send(p_demux->out, p_sys->p_dummy_video, p_block);
416 out:
417 es_format_Clean(&fmt);
420 static void stopBackground(demux_t *p_demux)
422 demux_sys_t *p_sys = p_demux->p_sys;
424 if (!p_sys->p_dummy_video) {
425 return;
428 msg_Info(p_demux, "Stop background");
430 es_out_Del(p_demux->out, p_sys->p_dummy_video);
431 p_sys->p_dummy_video = NULL;
434 /*****************************************************************************
435 * cache current playlist (title) information
436 *****************************************************************************/
438 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
440 vlc_mutex_lock(&p_sys->pl_info_lock);
442 if (p_sys->p_pl_info) {
443 bd_free_title_info(p_sys->p_pl_info);
445 p_sys->p_pl_info = info;
446 p_sys->p_clip_info = NULL;
448 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
449 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
452 vlc_mutex_unlock(&p_sys->pl_info_lock);
455 /*****************************************************************************
456 * create input attachment for thumbnail
457 *****************************************************************************/
459 static void attachThumbnail(demux_t *p_demux)
461 demux_sys_t *p_sys = p_demux->p_sys;
463 if (!p_sys->p_meta)
464 return;
466 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
467 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
468 int64_t size;
469 void *data;
470 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
471 char psz_name[64];
472 input_attachment_t *p_attachment;
474 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
476 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
477 if (p_attachment) {
478 p_sys->i_cover_idx = p_sys->i_attachments;
479 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
482 free(data);
484 #endif
487 /*****************************************************************************
488 * stream input
489 *****************************************************************************/
491 static int probeStream(demux_t *p_demux)
493 /* input must be seekable */
494 bool b_canseek = false;
495 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
496 if (!b_canseek) {
497 return VLC_EGENERIC;
500 /* first sector(s) should be filled with zeros */
501 size_t i_peek;
502 const uint8_t *p_peek;
503 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
504 if( i_peek != 2048 ) {
505 return VLC_EGENERIC;
507 while (i_peek > 0) {
508 if (p_peek[ --i_peek ]) {
509 return VLC_EGENERIC;
513 return VLC_SUCCESS;
516 #ifdef BLURAY_DEMUX
517 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
519 demux_t *p_demux = (demux_t*)object;
520 demux_sys_t *p_sys = p_demux->p_sys;
521 int result = -1;
523 assert(p_demux->s != NULL);
525 vlc_mutex_lock(&p_sys->read_block_lock);
527 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
528 size_t req = (size_t)2048 * num_blocks;
529 ssize_t got;
531 got = vlc_stream_Read( p_demux->s, buf, req);
532 if (got < 0) {
533 msg_Err(p_demux, "read from lba %d failed", lba);
534 } else {
535 result = got / 2048;
537 } else {
538 msg_Err(p_demux, "seek to lba %d failed", lba);
541 vlc_mutex_unlock(&p_sys->read_block_lock);
543 return result;
545 #endif
547 /*****************************************************************************
548 * probing of local files
549 *****************************************************************************/
551 /* Descriptor Tag (ECMA 167, 3/7.2) */
552 static int decode_descriptor_tag(const uint8_t *buf)
554 uint16_t id;
555 uint8_t checksum = 0;
556 int i;
558 id = buf[0] | (buf[1] << 8);
560 /* calculate tag checksum */
561 for (i = 0; i < 4; i++) {
562 checksum = (uint8_t)(checksum + buf[i]);
564 for (i = 5; i < 16; i++) {
565 checksum = (uint8_t)(checksum + buf[i]);
568 if (checksum != buf[4]) {
569 return -1;
572 return id;
575 static int probeFile(const char *psz_name)
577 struct stat stat_info;
578 uint8_t peek[2048];
579 unsigned i;
580 int ret = VLC_EGENERIC;
581 int fd;
583 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
584 if (fd == -1) {
585 return VLC_EGENERIC;
588 if (fstat(fd, &stat_info) == -1) {
589 goto bailout;
591 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
592 goto bailout;
595 /* first sector should be filled with zeros */
596 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
597 goto bailout;
599 for (i = 0; i < sizeof(peek); i++) {
600 if (peek[ i ]) {
601 goto bailout;
605 /* Check AVDP tag checksum */
606 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
607 read(fd, peek, 16) != 16 ||
608 decode_descriptor_tag(peek) != 2) {
609 goto bailout;
612 ret = VLC_SUCCESS;
614 bailout:
615 vlc_close(fd);
616 return ret;
619 /*****************************************************************************
620 * blurayOpen: module init function
621 *****************************************************************************/
622 static int blurayOpen(vlc_object_t *object)
624 demux_t *p_demux = (demux_t*)object;
625 demux_sys_t *p_sys;
626 bool forced;
627 uint64_t i_init_pos = 0;
629 const char *error_msg = NULL;
630 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
632 if (unlikely(!p_demux->p_input))
633 return VLC_EGENERIC;
635 forced = !strncasecmp(p_demux->psz_url, "bluray:", 7);
637 if (p_demux->s) {
638 if (!strncasecmp(p_demux->psz_url, "file:", 5)) {
639 /* use access_demux for local files */
640 return VLC_EGENERIC;
643 if (probeStream(p_demux) != VLC_SUCCESS) {
644 return VLC_EGENERIC;
647 } else if (!forced) {
648 if (!p_demux->psz_filepath) {
649 return VLC_EGENERIC;
652 if (probeFile(p_demux->psz_filepath) != VLC_SUCCESS) {
653 return VLC_EGENERIC;
657 /* */
658 p_demux->p_sys = p_sys = vlc_obj_calloc(object, 1, sizeof(*p_sys));
659 if (unlikely(!p_sys))
660 return VLC_ENOMEM;
662 p_sys->i_audio_stream_idx = -1;
663 p_sys->i_spu_stream_idx = -1;
664 p_sys->i_video_stream = -1;
665 p_sys->i_still_end_time = 0;
667 /* init demux info fields */
668 p_demux->info.i_update = 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 demux_t *p_demux = p_out->p_sys->p_demux;
1051 return es_out_Send(p_demux->out, p_es, p_block);
1054 static void esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1056 demux_t *p_demux = p_out->p_sys->p_demux;
1057 demux_sys_t *p_sys = p_demux->p_sys;
1059 int idx = findEsPairIndexByEs(p_sys, p_es);
1060 if (idx >= 0) {
1061 free(vlc_array_item_at_index(&p_sys->es, idx));
1062 vlc_array_remove(&p_sys->es, idx);
1064 es_out_Del(p_demux->out, p_es);
1067 static int esOutControl(es_out_t *p_out, int i_query, va_list args)
1069 demux_t *p_demux = p_out->p_sys->p_demux;
1071 return es_out_vaControl(p_demux->out, i_query, args);
1074 static void esOutDestroy(es_out_t *p_out)
1076 demux_t *p_demux = p_out->p_sys->p_demux;
1077 demux_sys_t *p_sys = p_demux->p_sys;
1079 for (size_t i = 0; i < vlc_array_count(&p_sys->es); ++i)
1080 free(vlc_array_item_at_index(&p_sys->es, i));
1081 vlc_array_clear(&p_sys->es);
1082 free(p_out->p_sys);
1083 free(p_out);
1086 static es_out_t *esOutNew(demux_t *p_demux)
1088 #ifndef NDEBUG
1089 demux_sys_t *p_sys = p_demux->p_sys;
1090 assert(vlc_array_count(&p_sys->es) == 0);
1091 #endif
1092 es_out_t *p_out = malloc(sizeof(*p_out));
1093 if (unlikely(p_out == NULL))
1094 return NULL;
1096 p_out->pf_add = esOutAdd;
1097 p_out->pf_control = esOutControl;
1098 p_out->pf_del = esOutDel;
1099 p_out->pf_destroy = esOutDestroy;
1100 p_out->pf_send = esOutSend;
1102 p_out->p_sys = malloc(sizeof(*p_out->p_sys));
1103 if (unlikely(p_out->p_sys == NULL)) {
1104 free(p_out);
1105 return NULL;
1107 p_out->p_sys->p_demux = p_demux;
1108 return p_out;
1111 /*****************************************************************************
1112 * subpicture_updater_t functions:
1113 *****************************************************************************/
1115 static bluray_overlay_t *updater_lock_overlay(subpicture_updater_sys_t *p_upd_sys)
1117 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1118 vlc_mutex_lock(&p_upd_sys->lock);
1120 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1121 if (ov) {
1122 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1123 vlc_mutex_lock(&ov->lock);
1124 return ov;
1127 /* overlay has been closed */
1128 vlc_mutex_unlock(&p_upd_sys->lock);
1129 return NULL;
1132 static void updater_unlock_overlay(subpicture_updater_sys_t *p_upd_sys)
1134 assert (p_upd_sys->p_overlay);
1136 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1137 vlc_mutex_unlock(&p_upd_sys->lock);
1140 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1141 bool b_fmt_src, const video_format_t *p_fmt_src,
1142 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1143 mtime_t i_ts)
1145 VLC_UNUSED(b_fmt_src);
1146 VLC_UNUSED(b_fmt_dst);
1147 VLC_UNUSED(p_fmt_src);
1148 VLC_UNUSED(p_fmt_dst);
1149 VLC_UNUSED(i_ts);
1151 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1152 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1154 if (!p_overlay) {
1155 return 1;
1158 int res = p_overlay->status == Outdated;
1160 updater_unlock_overlay(p_upd_sys);
1162 return res;
1165 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1166 const video_format_t *p_fmt_src,
1167 const video_format_t *p_fmt_dst,
1168 mtime_t i_ts)
1170 VLC_UNUSED(p_fmt_src);
1171 VLC_UNUSED(p_fmt_dst);
1172 VLC_UNUSED(i_ts);
1173 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1174 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1176 if (!p_overlay) {
1177 return;
1181 * When this function is called, all p_subpic regions are gone.
1182 * We need to duplicate our regions (stored internaly) to this subpic.
1184 subpicture_region_t *p_src = p_overlay->p_regions;
1185 if (!p_src) {
1186 updater_unlock_overlay(p_upd_sys);
1187 return;
1190 subpicture_region_t **p_dst = &p_subpic->p_region;
1191 while (p_src != NULL) {
1192 *p_dst = subpicture_region_Copy(p_src);
1193 if (*p_dst == NULL)
1194 break;
1195 p_dst = &(*p_dst)->p_next;
1196 p_src = p_src->p_next;
1198 if (*p_dst != NULL)
1199 (*p_dst)->p_next = NULL;
1200 p_overlay->status = Displayed;
1202 updater_unlock_overlay(p_upd_sys);
1205 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1207 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1208 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1210 if (p_overlay) {
1211 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1212 p_overlay->status = ToDisplay;
1213 p_overlay->i_channel = -1;
1214 updater_unlock_overlay(p_upd_sys);
1217 unref_subpicture_updater(p_upd_sys);
1220 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1222 subpicture_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1223 if (unlikely(p_upd_sys == NULL)) {
1224 return NULL;
1227 p_upd_sys->p_overlay = p_ov;
1229 subpicture_updater_t updater = {
1230 .pf_validate = subpictureUpdaterValidate,
1231 .pf_update = subpictureUpdaterUpdate,
1232 .pf_destroy = subpictureUpdaterDestroy,
1233 .p_sys = p_upd_sys,
1236 subpicture_t *p_pic = subpicture_New(&updater);
1237 if (p_pic == NULL) {
1238 free(p_upd_sys);
1239 return NULL;
1242 p_pic->i_original_picture_width = p_ov->width;
1243 p_pic->i_original_picture_height = p_ov->height;
1244 p_pic->b_ephemer = true;
1245 p_pic->b_absolute = true;
1247 vlc_mutex_init(&p_upd_sys->lock);
1248 p_upd_sys->ref_cnt = 2;
1250 p_ov->p_updater = p_upd_sys;
1252 return p_pic;
1255 /*****************************************************************************
1256 * User input events:
1257 *****************************************************************************/
1258 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var, vlc_value_t old,
1259 vlc_value_t val, void *p_data)
1261 demux_t *p_demux = (demux_t*)p_data;
1262 demux_sys_t *p_sys = p_demux->p_sys;
1263 VLC_UNUSED(old);
1264 VLC_UNUSED(p_vout);
1266 if (psz_var[6] == 'm') //Mouse moved
1267 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1268 else if (psz_var[6] == 'c') {
1269 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1270 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1271 } else {
1272 vlc_assert_unreachable();
1274 return VLC_SUCCESS;
1277 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1279 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1280 return VLC_EGENERIC;
1282 return VLC_SUCCESS;
1285 /*****************************************************************************
1286 * libbluray overlay handling:
1287 *****************************************************************************/
1289 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1291 demux_sys_t *p_sys = p_demux->p_sys;
1292 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1294 if (ov != NULL) {
1296 /* drop overlay from vout */
1297 if (ov->p_updater) {
1298 unref_subpicture_updater(ov->p_updater);
1300 /* no references to this overlay exist in vo anymore */
1301 if (p_sys->p_vout && ov->i_channel != -1) {
1302 vout_FlushSubpictureChannel(p_sys->p_vout, ov->i_channel);
1305 vlc_mutex_destroy(&ov->lock);
1306 subpicture_region_ChainDelete(ov->p_regions);
1307 free(ov);
1309 p_sys->p_overlays[plane] = NULL;
1312 for (int i = 0; i < MAX_OVERLAY; i++)
1313 if (p_sys->p_overlays[i])
1314 return;
1316 /* All overlays have been closed */
1317 blurayReleaseVout(p_demux);
1321 * Mark the overlay as "ToDisplay" status.
1322 * This will not send the overlay to the vout instantly, as the vout
1323 * may not be acquired (not acquirable) yet.
1324 * If is has already been acquired, the overlay has already been sent to it,
1325 * therefore, we only flag the overlay as "Outdated"
1327 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1329 demux_sys_t *p_sys = p_demux->p_sys;
1330 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1333 * If the overlay is already displayed, mark the picture as outdated.
1334 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1336 vlc_mutex_lock(&ov->lock);
1337 if (ov->status >= Displayed && p_sys->p_vout) {
1338 ov->status = Outdated;
1339 vlc_mutex_unlock(&ov->lock);
1340 return;
1344 * Mark the overlay as available, but don't display it right now.
1345 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1346 * the overlay is computed
1348 ov->status = ToDisplay;
1349 vlc_mutex_unlock(&ov->lock);
1352 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1354 demux_sys_t *p_sys = p_demux->p_sys;
1356 assert(p_sys->p_overlays[plane] == NULL);
1358 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1359 if (unlikely(ov == NULL))
1360 return;
1362 ov->width = width;
1363 ov->height = height;
1364 ov->i_channel = -1;
1366 vlc_mutex_init(&ov->lock);
1368 p_sys->p_overlays[plane] = ov;
1372 * Destroy every regions in the subpicture.
1373 * This is done in two steps:
1374 * - Wiping our private regions list
1375 * - Flagging the overlay as outdated, so the changes are replicated from
1376 * the subpicture_updater_t::pf_update
1377 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1379 static void blurayClearOverlay(demux_t *p_demux, int plane)
1381 demux_sys_t *p_sys = p_demux->p_sys;
1382 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1384 vlc_mutex_lock(&ov->lock);
1386 subpicture_region_ChainDelete(ov->p_regions);
1387 ov->p_regions = NULL;
1388 ov->status = Outdated;
1390 vlc_mutex_unlock(&ov->lock);
1394 * This will draw to the overlay by adding a region to our region list
1395 * This will have to be copied to the subpicture used to render the overlay.
1397 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1399 demux_sys_t *p_sys = p_demux->p_sys;
1402 * Compute a subpicture_region_t.
1403 * It will be copied and sent to the vout later.
1405 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1407 /* Find a region to update */
1408 subpicture_region_t **pp_reg = &p_sys->p_overlays[ov->plane]->p_regions;
1409 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1410 subpicture_region_t *p_last = NULL;
1411 while (p_reg != NULL) {
1412 p_last = p_reg;
1413 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1414 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1415 break;
1416 pp_reg = &p_reg->p_next;
1417 p_reg = p_reg->p_next;
1420 if (!ov->img) {
1421 if (p_reg) {
1422 /* drop region */
1423 *pp_reg = p_reg->p_next;
1424 subpicture_region_Delete(p_reg);
1426 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1427 return;
1430 /* If there is no region to update, create a new one. */
1431 if (!p_reg) {
1432 video_format_t fmt;
1433 video_format_Init(&fmt, 0);
1434 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1436 p_reg = subpicture_region_New(&fmt);
1437 p_reg->i_x = ov->x;
1438 p_reg->i_y = ov->y;
1439 /* Append it to our list. */
1440 if (p_last != NULL)
1441 p_last->p_next = p_reg;
1442 else /* If we don't have a last region, then our list empty */
1443 p_sys->p_overlays[ov->plane]->p_regions = p_reg;
1446 /* Now we can update the region, regardless it's an update or an insert */
1447 const BD_PG_RLE_ELEM *img = ov->img;
1448 for (int y = 0; y < ov->h; y++)
1449 for (int x = 0; x < ov->w;) {
1450 plane_t *p = &p_reg->p_picture->p[0];
1451 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1452 x += img->len;
1453 img++;
1456 if (ov->palette) {
1457 p_reg->fmt.p_palette->i_entries = 256;
1458 for (int i = 0; i < 256; ++i) {
1459 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1460 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1461 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1462 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1466 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1468 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1472 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1474 demux_t *p_demux = (demux_t*)ptr;
1475 demux_sys_t *p_sys = p_demux->p_sys;
1477 if (!overlay) {
1478 msg_Info(p_demux, "Closing overlays.");
1479 if (p_sys->p_vout)
1480 for (int i = 0; i < MAX_OVERLAY; i++)
1481 blurayCloseOverlay(p_demux, i);
1482 return;
1485 switch (overlay->cmd) {
1486 case BD_OVERLAY_INIT:
1487 msg_Info(p_demux, "Initializing overlay");
1488 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1489 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1490 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1491 break;
1492 case BD_OVERLAY_CLOSE:
1493 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1494 blurayClearOverlay(p_demux, overlay->plane);
1495 blurayCloseOverlay(p_demux, overlay->plane);
1496 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1497 break;
1498 case BD_OVERLAY_CLEAR:
1499 blurayClearOverlay(p_demux, overlay->plane);
1500 break;
1501 case BD_OVERLAY_FLUSH:
1502 blurayActivateOverlay(p_demux, overlay->plane);
1503 break;
1504 case BD_OVERLAY_DRAW:
1505 case BD_OVERLAY_WIPE:
1506 blurayDrawOverlay(p_demux, overlay);
1507 break;
1508 default:
1509 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
1510 break;
1515 * ARGB overlay (BD-J)
1517 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
1519 demux_sys_t *p_sys = p_demux->p_sys;
1521 blurayInitOverlay(p_demux, plane, width, height);
1523 if (!p_sys->p_overlays[plane]->p_regions) {
1524 video_format_t fmt;
1525 video_format_Init(&fmt, 0);
1526 video_format_Setup(&fmt, VLC_CODEC_RGBA, width, height, width, height, 1, 1);
1528 p_sys->p_overlays[plane]->p_regions = subpicture_region_New(&fmt);
1532 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
1534 demux_sys_t *p_sys = p_demux->p_sys;
1536 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1538 /* Find a region to update */
1539 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1540 if (!p_reg) {
1541 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1542 return;
1545 /* Now we can update the region */
1546 const uint32_t *src0 = ov->argb;
1547 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
1548 p_reg->p_picture->p[0].i_pitch * ov->y +
1549 ov->x * 4;
1551 for (int y = 0; y < ov->h; y++) {
1552 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1553 // - or add libbluray option to select the format ?
1554 for (int x = 0; x < ov->w; x++) {
1555 dst0[x*4 ] = src0[x]>>16; /* R */
1556 dst0[x*4+1] = src0[x]>>8; /* G */
1557 dst0[x*4+2] = src0[x]; /* B */
1558 dst0[x*4+3] = src0[x]>>24; /* A */
1561 src0 += ov->stride;
1562 dst0 += p_reg->p_picture->p[0].i_pitch;
1565 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1567 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1571 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
1573 demux_t *p_demux = (demux_t*)ptr;
1574 demux_sys_t *p_sys = p_demux->p_sys;
1576 switch (overlay->cmd) {
1577 case BD_ARGB_OVERLAY_INIT:
1578 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1579 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1580 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1581 break;
1582 case BD_ARGB_OVERLAY_CLOSE:
1583 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1584 blurayClearOverlay(p_demux, overlay->plane);
1585 blurayCloseOverlay(p_demux, overlay->plane);
1586 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1587 break;
1588 case BD_ARGB_OVERLAY_FLUSH:
1589 blurayActivateOverlay(p_demux, overlay->plane);
1590 break;
1591 case BD_ARGB_OVERLAY_DRAW:
1592 blurayDrawArgbOverlay(p_demux, overlay);
1593 break;
1594 default:
1595 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
1596 break;
1600 static void bluraySendOverlayToVout(demux_t *p_demux, bluray_overlay_t *p_ov)
1602 demux_sys_t *p_sys = p_demux->p_sys;
1604 assert(p_ov != NULL);
1605 assert(p_ov->i_channel == -1);
1607 if (p_ov->p_updater) {
1608 unref_subpicture_updater(p_ov->p_updater);
1609 p_ov->p_updater = NULL;
1612 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
1613 if (!p_pic) {
1614 msg_Err(p_demux, "bluraySubpictureCreate() failed");
1615 return;
1618 p_pic->i_start = p_pic->i_stop = mdate();
1619 p_pic->i_channel = vout_RegisterSubpictureChannel(p_sys->p_vout);
1620 p_ov->i_channel = p_pic->i_channel;
1623 * After this point, the picture should not be accessed from the demux thread,
1624 * as it is held by the vout thread.
1625 * This must be done only once per subpicture, ie. only once between each
1626 * blurayInitOverlay & blurayCloseOverlay call.
1628 vout_PutSubpicture(p_sys->p_vout, p_pic);
1631 * Mark the picture as Outdated, as it contains no region for now.
1632 * This will make the subpicture_updater_t call pf_update
1634 p_ov->status = Outdated;
1637 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
1639 t->i_length = FROM_TICKS(title_info->duration);
1641 for (int i = 0; i < t->i_seekpoint; i++)
1642 vlc_seekpoint_Delete( t->seekpoint[i] );
1643 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
1645 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
1646 seekpoint_t *s = vlc_seekpoint_New();
1647 if (!s) {
1648 break;
1650 s->i_time_offset = FROM_TICKS(title_info->chapters[j].start);
1652 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
1656 static void blurayInitTitles(demux_t *p_demux, int menu_titles)
1658 demux_sys_t *p_sys = p_demux->p_sys;
1659 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
1661 /* get and set the titles */
1662 unsigned i_title = menu_titles;
1664 if (!p_sys->b_menu) {
1665 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
1666 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
1669 for (unsigned int i = 0; i < i_title; i++) {
1670 input_title_t *t = vlc_input_title_New();
1671 if (!t)
1672 break;
1674 if (!p_sys->b_menu) {
1675 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
1676 blurayUpdateTitleInfo(t, title_info);
1677 bd_free_title_info(title_info);
1679 } else if (i == 0) {
1680 t->psz_name = strdup(_("Top Menu"));
1681 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
1682 } else if (i == i_title - 1) {
1683 t->psz_name = strdup(_("First Play"));
1684 if (di && di->first_play && di->first_play->interactive) {
1685 t->i_flags = INPUT_TITLE_INTERACTIVE;
1687 } else {
1688 /* add possible title name from disc metadata */
1689 if (di && di->titles && i <= di->num_titles) {
1690 if (di->titles[i]->name) {
1691 t->psz_name = strdup(di->titles[i]->name);
1693 if (di->titles[i]->interactive) {
1694 t->i_flags = INPUT_TITLE_INTERACTIVE;
1699 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
1703 static void blurayResetParser(demux_t *p_demux)
1706 * This is a hack and will have to be removed.
1707 * The parser should be flushed, and not destroy/created each time
1708 * we are changing title.
1710 demux_sys_t *p_sys = p_demux->p_sys;
1711 if (p_sys->p_parser)
1712 vlc_demux_chained_Delete(p_sys->p_parser);
1714 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
1716 if (!p_sys->p_parser)
1717 msg_Err(p_demux, "Failed to create TS demuxer");
1720 /*****************************************************************************
1721 * bluraySetTitle: select new BD title
1722 *****************************************************************************/
1723 static int bluraySetTitle(demux_t *p_demux, int i_title)
1725 demux_sys_t *p_sys = p_demux->p_sys;
1727 if (p_sys->b_menu) {
1728 int result;
1729 if (i_title <= 0) {
1730 msg_Dbg(p_demux, "Playing TopMenu Title");
1731 result = bd_menu_call(p_sys->bluray, -1);
1732 } else if (i_title >= (int)p_sys->i_title - 1) {
1733 msg_Dbg(p_demux, "Playing FirstPlay Title");
1734 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
1735 } else {
1736 msg_Dbg(p_demux, "Playing Title %i", i_title);
1737 result = bd_play_title(p_sys->bluray, i_title);
1740 if (result == 0) {
1741 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
1742 return VLC_EGENERIC;
1745 return VLC_SUCCESS;
1748 /* Looking for the main title, ie the longest duration */
1749 if (i_title < 0)
1750 i_title = p_sys->i_longest_title;
1751 else if ((unsigned)i_title > p_sys->i_title)
1752 return VLC_EGENERIC;
1754 msg_Dbg(p_demux, "Selecting Title %i", i_title);
1756 if (bd_select_title(p_sys->bluray, i_title) == 0) {
1757 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
1758 return VLC_EGENERIC;
1761 return VLC_SUCCESS;
1764 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
1765 # define BLURAY_AUDIO_STREAM 0
1766 #endif
1768 static void blurayStreamSelected(demux_sys_t *p_sys, int i_pid)
1770 vlc_mutex_lock(&p_sys->pl_info_lock);
1772 if (p_sys->p_clip_info) {
1773 if ((i_pid & 0xff00) == 0x1100) {
1774 // audio
1775 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
1776 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
1777 p_sys->i_audio_stream_idx = i_id;
1778 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
1779 break;
1782 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
1783 // subtitle
1784 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
1785 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
1786 p_sys->i_spu_stream_idx = i_id;
1787 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
1788 break;
1794 vlc_mutex_unlock(&p_sys->pl_info_lock);
1797 /*****************************************************************************
1798 * blurayControl: handle the controls
1799 *****************************************************************************/
1800 static int blurayControl(demux_t *p_demux, int query, va_list args)
1802 demux_sys_t *p_sys = p_demux->p_sys;
1803 bool *pb_bool;
1804 int64_t *pi_64;
1806 switch (query) {
1807 case DEMUX_CAN_SEEK:
1808 case DEMUX_CAN_PAUSE:
1809 case DEMUX_CAN_CONTROL_PACE:
1810 pb_bool = va_arg(args, bool *);
1811 *pb_bool = true;
1812 break;
1814 case DEMUX_GET_PTS_DELAY:
1815 pi_64 = va_arg(args, int64_t *);
1816 *pi_64 = INT64_C(1000) * var_InheritInteger(p_demux, "disc-caching");
1817 break;
1819 case DEMUX_SET_PAUSE_STATE:
1821 #ifdef BLURAY_RATE_NORMAL
1822 bool b_paused = (bool)va_arg(args, int);
1823 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
1824 return VLC_EGENERIC;
1826 #endif
1827 break;
1829 case DEMUX_SET_ES:
1831 int i_id = va_arg(args, int);
1832 blurayStreamSelected(p_sys, i_id);
1833 break;
1835 case DEMUX_SET_TITLE:
1837 int i_title = va_arg(args, int);
1838 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
1839 /* make sure GUI restores the old setting in title menu ... */
1840 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1841 return VLC_EGENERIC;
1843 blurayResetParser( p_demux );
1844 notifyDiscontinuity( p_sys );
1845 break;
1847 case DEMUX_SET_SEEKPOINT:
1849 int i_chapter = va_arg(args, int);
1850 bd_seek_chapter(p_sys->bluray, i_chapter);
1851 notifyDiscontinuity( p_sys );
1852 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
1853 break;
1856 case DEMUX_GET_TITLE:
1857 *va_arg(args, int *) = p_sys->cur_title;
1858 break;
1860 case DEMUX_GET_SEEKPOINT:
1861 *va_arg(args, int *) = p_sys->cur_seekpoint;
1862 break;
1864 case DEMUX_GET_TITLE_INFO:
1866 input_title_t ***ppp_title = va_arg(args, input_title_t***);
1867 int *pi_int = va_arg(args, int *);
1868 int *pi_title_offset = va_arg(args, int *);
1869 int *pi_chapter_offset = va_arg(args, int *);
1871 /* */
1872 *pi_title_offset = 0;
1873 *pi_chapter_offset = 0;
1875 /* Duplicate local title infos */
1876 *pi_int = 0;
1877 *ppp_title = vlc_alloc(p_sys->i_title, sizeof(input_title_t *));
1878 if(!*ppp_title)
1879 return VLC_EGENERIC;
1880 for (unsigned int i = 0; i < p_sys->i_title; i++)
1882 input_title_t *p_dup = vlc_input_title_Duplicate(p_sys->pp_title[i]);
1883 if(p_dup)
1884 (*ppp_title)[(*pi_int)++] = p_dup;
1887 return VLC_SUCCESS;
1890 case DEMUX_GET_LENGTH:
1892 int64_t *pi_length = va_arg(args, int64_t *);
1893 *pi_length = p_sys->cur_title < p_sys->i_title ? CUR_LENGTH : 0;
1894 return VLC_SUCCESS;
1896 case DEMUX_SET_TIME:
1898 int64_t i_time = va_arg(args, int64_t);
1899 bd_seek_time(p_sys->bluray, TO_TICKS(i_time));
1900 notifyDiscontinuity( p_sys );
1901 return VLC_SUCCESS;
1903 case DEMUX_GET_TIME:
1905 int64_t *pi_time = va_arg(args, int64_t *);
1906 *pi_time = (int64_t)FROM_TICKS(bd_tell_time(p_sys->bluray));
1907 return VLC_SUCCESS;
1910 case DEMUX_GET_POSITION:
1912 double *pf_position = va_arg(args, double *);
1913 *pf_position = p_sys->cur_title < p_sys->i_title && CUR_LENGTH > 0 ?
1914 (double)FROM_TICKS(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
1915 return VLC_SUCCESS;
1917 case DEMUX_SET_POSITION:
1919 double f_position = va_arg(args, double);
1920 bd_seek_time(p_sys->bluray, TO_TICKS(f_position*CUR_LENGTH));
1921 notifyDiscontinuity( p_sys );
1922 return VLC_SUCCESS;
1925 case DEMUX_GET_META:
1927 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
1928 const META_DL *meta = p_sys->p_meta;
1929 if (meta == NULL)
1930 return VLC_EGENERIC;
1932 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
1934 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
1935 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
1936 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
1938 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
1939 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
1941 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
1942 char psz_url[128];
1943 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
1944 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
1945 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
1947 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
1948 char *psz_thumbpath;
1949 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
1950 p_sys->psz_bd_path, meta->thumbnails[0].path) > -1) {
1951 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
1952 free(psz_thumbpath);
1953 if (unlikely(psz_thumburl == NULL))
1954 return VLC_ENOMEM;
1956 vlc_meta_SetArtURL(p_meta, psz_thumburl);
1957 free(psz_thumburl);
1961 return VLC_SUCCESS;
1964 case DEMUX_GET_ATTACHMENTS:
1966 input_attachment_t ***ppp_attach =
1967 va_arg(args, input_attachment_t ***);
1968 int *pi_int = va_arg(args, int *);
1970 if (p_sys->i_attachments <= 0)
1971 return VLC_EGENERIC;
1973 *pi_int = 0;
1974 *ppp_attach = vlc_alloc(p_sys->i_attachments, sizeof(input_attachment_t *));
1975 if(!*ppp_attach)
1976 return VLC_EGENERIC;
1977 for (int i = 0; i < p_sys->i_attachments; i++)
1979 input_attachment_t *p_dup = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
1980 if(p_dup)
1981 (*ppp_attach)[(*pi_int)++] = p_dup;
1983 return VLC_SUCCESS;
1986 case DEMUX_NAV_ACTIVATE:
1987 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
1988 return sendKeyEvent(p_sys, BD_VK_POPUP);
1990 return sendKeyEvent(p_sys, BD_VK_ENTER);
1991 case DEMUX_NAV_UP:
1992 return sendKeyEvent(p_sys, BD_VK_UP);
1993 case DEMUX_NAV_DOWN:
1994 return sendKeyEvent(p_sys, BD_VK_DOWN);
1995 case DEMUX_NAV_LEFT:
1996 return sendKeyEvent(p_sys, BD_VK_LEFT);
1997 case DEMUX_NAV_RIGHT:
1998 return sendKeyEvent(p_sys, BD_VK_RIGHT);
1999 case DEMUX_NAV_POPUP:
2000 return sendKeyEvent(p_sys, BD_VK_POPUP);
2001 case DEMUX_NAV_MENU:
2002 if (p_sys->b_menu) {
2003 if (bd_menu_call(p_sys->bluray, -1) == 1) {
2004 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2005 return VLC_SUCCESS;
2007 msg_Err(p_demux, "Can't select Top Menu title");
2008 return sendKeyEvent(p_sys, BD_VK_POPUP);
2010 return VLC_EGENERIC;
2012 case DEMUX_CAN_RECORD:
2013 case DEMUX_GET_FPS:
2014 case DEMUX_SET_GROUP:
2015 case DEMUX_HAS_UNSUPPORTED_META:
2016 default:
2017 return VLC_EGENERIC;
2019 return VLC_SUCCESS;
2022 /*****************************************************************************
2023 * libbluray event handling
2024 *****************************************************************************/
2025 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
2026 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
2028 for( size_t i=0; i< i_sinfo; i++ )
2030 const uint16_t i_pid = p_sinfo[i].pid;
2032 block_t *p_block = block_Alloc(192);
2033 if (!p_block)
2034 return;
2036 uint8_t ts_header[] = {
2037 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2038 0x47,
2039 (i_pid & 0x1f00) >> 8, i_pid & 0xFF, /* PID */
2040 0x20, /* adaptation field, no payload */
2041 183, /* adaptation field length */
2042 0x80, /* adaptation field: discontinuity indicator */
2045 memcpy(p_block->p_buffer, ts_header, sizeof(ts_header));
2046 memset(&p_block->p_buffer[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header));
2047 p_block->i_buffer = 192;
2049 vlc_demux_chained_Send(p_parser, p_block);
2053 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2054 p_clip->memb##_stream_count )
2056 static void notifyDiscontinuity( demux_sys_t *p_sys )
2058 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2059 if( p_clip )
2061 DONOTIFY(audio);
2062 DONOTIFY(video);
2063 DONOTIFY(pg);
2064 DONOTIFY(ig);
2065 DONOTIFY(sec_audio);
2066 DONOTIFY(sec_video);
2070 #undef DONOTIFY
2072 static void streamFlush( demux_sys_t *p_sys )
2075 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2076 * Packet is flushed only when TS packet with PUSI flag set is received.
2078 * Fix this by emitting (video) ts packet with PUSI flag set.
2079 * Add video sequence end code to payload so that also video decoder is flushed.
2080 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2083 if (p_sys->b_flushed)
2084 return;
2086 block_t *p_block = block_Alloc(192);
2087 if (!p_block)
2088 return;
2090 static const uint8_t seq_end_pes[] = {
2091 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2092 0x00, 0x00, 0x01, 0xb7, /* PES payload: sequence end */
2094 static const uint8_t vid_pusi_ts[] = {
2095 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2096 0x47, 0x50, 0x11, 0x30, /* TP header */
2097 (192 - (4 + 5) - sizeof(seq_end_pes)), /* adaptation field length */
2098 0x80, /* adaptation field: discontinuity indicator */
2101 memset(p_block->p_buffer, 0, 192);
2102 memcpy(p_block->p_buffer, vid_pusi_ts, sizeof(vid_pusi_ts));
2103 memcpy(p_block->p_buffer + 192 - sizeof(seq_end_pes), seq_end_pes, sizeof(seq_end_pes));
2104 p_block->i_buffer = 192;
2106 /* set correct sequence end code */
2107 vlc_mutex_lock(&p_sys->pl_info_lock);
2108 if (p_sys->p_clip_info != NULL) {
2109 if (p_sys->p_clip_info->video_streams[0].coding_type > 2) {
2110 /* VC1 / H.264 sequence end */
2111 p_block->p_buffer[191] = 0x0a;
2114 vlc_mutex_unlock(&p_sys->pl_info_lock);
2116 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2117 p_sys->b_flushed = true;
2120 static void blurayResetStillImage( demux_t *p_demux )
2122 demux_sys_t *p_sys = p_demux->p_sys;
2124 if (p_sys->i_still_end_time) {
2125 p_sys->i_still_end_time = 0;
2127 blurayResetParser(p_demux);
2128 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2132 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2134 demux_sys_t *p_sys = p_demux->p_sys;
2136 /* time period elapsed ? */
2137 if (p_sys->i_still_end_time > 0 && p_sys->i_still_end_time <= mdate()) {
2138 msg_Dbg(p_demux, "Still image end");
2139 bd_read_skip_still(p_sys->bluray);
2141 blurayResetStillImage(p_demux);
2142 return;
2145 /* show last frame as still image */
2146 if (!p_sys->i_still_end_time) {
2147 if (i_timeout) {
2148 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2149 p_sys->i_still_end_time = mdate() + i_timeout * CLOCK_FREQ;
2150 } else {
2151 msg_Dbg(p_demux, "Still image (infinite)");
2152 p_sys->i_still_end_time = -1;
2155 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2156 streamFlush(p_sys);
2158 /* stop buffering */
2159 bool b_empty;
2160 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2163 /* avoid busy loops (read returns no data) */
2164 msleep( 40000 );
2167 static void blurayStreamSelect(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2169 demux_sys_t *p_sys = p_demux->p_sys;
2170 int i_pid = -1;
2172 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2173 i_id--;
2175 if (i_type == BD_EVENT_AUDIO_STREAM) {
2176 p_sys->i_audio_stream_idx = i_id;
2177 i_pid = blurayEsPid(p_sys, AUDIO_ES, i_id);
2178 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2179 p_sys->i_spu_stream_idx = i_id;
2180 i_pid = blurayEsPid(p_sys, SPU_ES, i_id);
2183 if (i_pid > 0) {
2184 int i_idx = findEsPairIndex(p_sys, i_pid);
2185 if (i_idx >= 0) {
2186 if (i_type == BD_EVENT_AUDIO_STREAM) {
2187 var_SetInteger( p_demux->p_input, "audio-es", i_pid );
2188 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2189 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? i_pid : -1 );
2195 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2197 demux_sys_t *p_sys = p_demux->p_sys;
2199 blurayResetParser(p_demux);
2201 /* read title info and init some values */
2202 if (!p_sys->b_menu)
2203 p_sys->cur_title = bd_get_current_title(p_sys->bluray);
2204 p_sys->cur_seekpoint = 0;
2205 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2207 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2208 if (p_title_info) {
2209 blurayUpdateTitleInfo(p_sys->pp_title[p_sys->cur_title], p_title_info);
2210 if (p_sys->b_menu)
2211 p_demux->info.i_update |= INPUT_UPDATE_TITLE_LIST;
2213 setTitleInfo(p_sys, p_title_info);
2215 blurayResetStillImage(p_demux);
2218 static void blurayUpdateCurrentClip(demux_t *p_demux, uint32_t clip)
2220 demux_sys_t *p_sys = p_demux->p_sys;
2222 vlc_mutex_lock(&p_sys->pl_info_lock);
2224 p_sys->p_clip_info = NULL;
2225 p_sys->i_video_stream = -1;
2227 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2229 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2231 /* Let's assume a single video track for now.
2232 * This may brake later, but it's enough for now.
2234 assert(p_sys->p_clip_info->video_stream_count >= 1);
2235 p_sys->i_video_stream = p_sys->p_clip_info->video_streams[0].pid;
2238 vlc_mutex_unlock(&p_sys->pl_info_lock);
2240 blurayResetStillImage(p_demux);
2243 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e)
2245 demux_sys_t *p_sys = p_demux->p_sys;
2247 switch (e->event) {
2248 case BD_EVENT_TITLE:
2249 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2250 p_sys->cur_title = p_sys->i_title - 1;
2251 else
2252 p_sys->cur_title = e->param;
2253 /* this is feature title, we don't know yet which playlist it will play (if any) */
2254 setTitleInfo(p_sys, NULL);
2255 /* reset title infos here ? */
2256 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT; /* might be BD-J title with no video */
2257 break;
2258 case BD_EVENT_PLAYLIST:
2259 /* Start of playlist playback (?????.mpls) */
2260 blurayUpdatePlaylist(p_demux, e->param);
2261 if (p_sys->b_pl_playing) {
2262 /* previous playlist was stopped in middle. flush to avoid delay */
2263 msg_Info(p_demux, "Stopping playlist playback");
2264 blurayResetParser(p_demux);
2265 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2267 p_sys->b_pl_playing = true;
2268 break;
2269 case BD_EVENT_PLAYITEM:
2270 blurayUpdateCurrentClip(p_demux, e->param);
2271 break;
2272 case BD_EVENT_CHAPTER:
2273 if (e->param && e->param < 0xffff)
2274 p_sys->cur_seekpoint = e->param - 1;
2275 else
2276 p_sys->cur_seekpoint = 0;
2277 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
2278 break;
2279 case BD_EVENT_PLAYMARK:
2280 case BD_EVENT_ANGLE:
2281 break;
2282 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2283 case BD_EVENT_UO_MASK_CHANGED:
2284 /* This event could be used to grey out unselectable items in title menu */
2285 break;
2286 #endif
2287 case BD_EVENT_MENU:
2288 p_sys->b_menu_open = e->param;
2289 break;
2290 case BD_EVENT_POPUP:
2291 p_sys->b_popup_available = e->param;
2292 /* TODO: show / hide pop-up menu button in gui ? */
2293 break;
2296 * Errors
2298 case BD_EVENT_ERROR:
2299 /* fatal error (with menus) */
2300 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2301 "Playback with BluRay menus failed");
2302 p_sys->b_fatal_error = true;
2303 break;
2304 case BD_EVENT_ENCRYPTED:
2305 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2306 "This disc seems to be encrypted");
2307 p_sys->b_fatal_error = true;
2308 break;
2309 case BD_EVENT_READ_ERROR:
2310 msg_Err(p_demux, "bluray: read error\n");
2311 break;
2314 * stream selection events
2316 case BD_EVENT_PG_TEXTST:
2317 p_sys->b_spu_enable = e->param;
2318 break;
2319 case BD_EVENT_AUDIO_STREAM:
2320 case BD_EVENT_PG_TEXTST_STREAM:
2321 blurayStreamSelect(p_demux, e->event, e->param);
2322 break;
2323 case BD_EVENT_IG_STREAM:
2324 case BD_EVENT_SECONDARY_AUDIO:
2325 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2326 case BD_EVENT_SECONDARY_VIDEO:
2327 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2328 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2329 break;
2332 * playback control events
2334 case BD_EVENT_STILL_TIME:
2335 blurayStillImage(p_demux, e->param);
2336 break;
2337 case BD_EVENT_DISCONTINUITY:
2338 /* reset demuxer (partially decoded PES packets must be dropped) */
2339 blurayResetParser(p_demux);
2340 break;
2341 case BD_EVENT_END_OF_TITLE:
2342 p_sys->b_pl_playing = false;
2343 break;
2344 case BD_EVENT_IDLE:
2345 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2346 /* avoid busy loop (bd_read() returns no data) */
2347 msleep( 40000 );
2348 break;
2350 default:
2351 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2352 break;
2356 static bool blurayIsBdjTitle(demux_t *p_demux)
2358 demux_sys_t *p_sys = p_demux->p_sys;
2359 unsigned int i_title = p_sys->cur_title;
2360 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2362 if (di && di->titles) {
2363 if ((i_title <= di->num_titles && di->titles[i_title] && di->titles[i_title]->bdj) ||
2364 (i_title == p_sys->i_title - 1 && di->first_play && di->first_play->bdj)) {
2365 return true;
2369 return false;
2372 static void blurayHandleOverlays(demux_t *p_demux, int nread)
2374 demux_sys_t *p_sys = p_demux->p_sys;
2376 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2378 for (int i = 0; i < MAX_OVERLAY; i++) {
2379 bluray_overlay_t *ov = p_sys->p_overlays[i];
2380 if (!ov) {
2381 continue;
2383 vlc_mutex_lock(&ov->lock);
2384 bool display = ov->status == ToDisplay;
2385 vlc_mutex_unlock(&ov->lock);
2386 if (display) {
2387 if (p_sys->p_vout == NULL) {
2388 p_sys->p_vout = input_GetVout(p_demux->p_input);
2389 if (p_sys->p_vout != NULL) {
2390 var_AddCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
2391 var_AddCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
2395 /* NOTE: we might want to enable background video always when there's no video stream playing.
2396 Now, with some discs, there are perioids (even seconds) during which the video window
2397 disappears and just playlist is shown.
2398 (sometimes BD-J runs slowly ...)
2400 if (!p_sys->p_vout && !p_sys->p_dummy_video && p_sys->b_menu &&
2401 !p_sys->p_pl_info && nread == 0 &&
2402 blurayIsBdjTitle(p_demux)) {
2404 /* Looks like there's no video stream playing.
2405 Emit blank frame so that BD-J overlay can be drawn. */
2406 startBackground(p_demux);
2409 if (p_sys->p_vout != NULL) {
2410 bluraySendOverlayToVout(p_demux, ov);
2415 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2418 static int onIntfEvent( vlc_object_t *p_input, char const *psz_var,
2419 vlc_value_t oldval, vlc_value_t val, void *p_data )
2421 (void)p_input; (void) psz_var; (void) oldval;
2422 demux_t *p_demux = p_data;
2423 demux_sys_t *p_sys = p_demux->p_sys;
2425 if (val.i_int == INPUT_EVENT_VOUT) {
2427 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2428 if( p_sys->p_vout != NULL ) {
2429 blurayReleaseVout(p_demux);
2431 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2433 blurayHandleOverlays(p_demux, 1);
2436 return VLC_SUCCESS;
2439 #define BD_TS_PACKET_SIZE (192)
2440 #define NB_TS_PACKETS (200)
2442 static int blurayDemux(demux_t *p_demux)
2444 demux_sys_t *p_sys = p_demux->p_sys;
2445 BD_EVENT e;
2447 block_t *p_block = block_Alloc(NB_TS_PACKETS * (int64_t)BD_TS_PACKET_SIZE);
2448 if (!p_block)
2449 return VLC_DEMUXER_EGENERIC;
2451 int nread;
2453 if (p_sys->b_menu == false) {
2454 while (bd_get_event(p_sys->bluray, &e))
2455 blurayHandleEvent(p_demux, &e);
2457 nread = bd_read(p_sys->bluray, p_block->p_buffer,
2458 NB_TS_PACKETS * BD_TS_PACKET_SIZE);
2459 } else {
2460 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer,
2461 NB_TS_PACKETS * BD_TS_PACKET_SIZE, &e);
2462 while (e.event != BD_EVENT_NONE) {
2463 blurayHandleEvent(p_demux, &e);
2464 bd_get_event(p_sys->bluray, &e);
2468 blurayHandleOverlays(p_demux, nread);
2470 if (nread <= 0) {
2471 block_Release(p_block);
2472 if (p_sys->b_fatal_error || nread < 0) {
2473 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
2474 return VLC_DEMUXER_EGENERIC;
2476 if (!p_sys->b_menu) {
2477 return VLC_DEMUXER_EOF;
2479 return VLC_DEMUXER_SUCCESS;
2482 p_block->i_buffer = nread;
2484 stopBackground(p_demux);
2486 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2488 p_sys->b_flushed = false;
2490 return VLC_DEMUXER_SUCCESS;