codec/hxxx_helper: removing redundant new-line from call to msg_Dbg
[vlc.git] / modules / access / bluray.c
blob4bd03dfac4d9bd766989bbcbc662431b43be1718
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 forced = !strcasecmp(p_demux->psz_access, "bluray");
632 if (p_demux->s) {
633 if (!strcasecmp(p_demux->psz_access, "file")) {
634 /* use access_demux for local files */
635 return VLC_EGENERIC;
638 if (probeStream(p_demux) != VLC_SUCCESS) {
639 return VLC_EGENERIC;
642 } else if (!forced) {
643 if (!p_demux->psz_file) {
644 return VLC_EGENERIC;
647 if (probeFile(p_demux->psz_file) != VLC_SUCCESS) {
648 return VLC_EGENERIC;
652 /* */
653 p_demux->p_sys = p_sys = calloc(1, sizeof(*p_sys));
654 if (unlikely(!p_sys))
655 return VLC_ENOMEM;
657 p_sys->i_audio_stream_idx = -1;
658 p_sys->i_spu_stream_idx = -1;
659 p_sys->i_video_stream = -1;
660 p_sys->i_still_end_time = 0;
662 /* init demux info fields */
663 p_demux->info.i_update = 0;
664 p_demux->info.i_title = 0;
665 p_demux->info.i_seekpoint = 0;
667 TAB_INIT(p_sys->i_title, p_sys->pp_title);
668 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
670 vlc_mutex_init(&p_sys->pl_info_lock);
671 vlc_mutex_init(&p_sys->bdj_overlay_lock);
672 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
674 var_AddCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
676 /* Open BluRay */
677 #ifdef BLURAY_DEMUX
678 if (p_demux->s) {
679 i_init_pos = vlc_stream_Tell(p_demux->s);
681 p_sys->bluray = bd_init();
682 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
683 bd_close(p_sys->bluray);
684 p_sys->bluray = NULL;
686 } else
687 #endif
689 if (!p_demux->psz_file) {
690 /* no path provided (bluray://). use default DVD device. */
691 p_sys->psz_bd_path = var_InheritString(object, "dvd");
692 } else {
693 /* store current bd path */
694 p_sys->psz_bd_path = strdup(p_demux->psz_file);
697 /* If we're passed a block device, try to convert it to the mount point. */
698 FindMountPoint(&p_sys->psz_bd_path);
700 p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
702 if (!p_sys->bluray) {
703 goto error;
706 /* Warning the user about AACS/BD+ */
707 const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
709 /* Is it a bluray? */
710 if (!disc_info->bluray_detected) {
711 if (forced) {
712 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
714 goto error;
717 msg_Info(p_demux, "First play: %i, Top menu: %i\n"
718 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
719 disc_info->first_play_supported, disc_info->top_menu_supported,
720 disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
721 disc_info->num_unsupported_titles);
723 /* AACS */
724 if (disc_info->aacs_detected) {
725 msg_Dbg(p_demux, "Disc is using AACS");
726 if (!disc_info->libaacs_detected)
727 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
728 ", and your system does not have it."));
729 if (!disc_info->aacs_handled) {
730 if (disc_info->aacs_error_code) {
731 switch (disc_info->aacs_error_code) {
732 case BD_AACS_CORRUPTED_DISC:
733 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
734 case BD_AACS_NO_CONFIG:
735 BLURAY_ERROR(_("Missing AACS configuration file!"));
736 case BD_AACS_NO_PK:
737 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
738 case BD_AACS_NO_CERT:
739 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
740 case BD_AACS_CERT_REVOKED:
741 BLURAY_ERROR(_("AACS Host certificate revoked."));
742 case BD_AACS_MMC_FAILED:
743 BLURAY_ERROR(_("AACS MMC failed."));
749 /* BD+ */
750 if (disc_info->bdplus_detected) {
751 msg_Dbg(p_demux, "Disc is using BD+");
752 if (!disc_info->libbdplus_detected)
753 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
754 ", and your system does not have it."));
755 if (!disc_info->bdplus_handled)
756 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
757 "Missing configuration?"));
760 /* set player region code */
761 char *psz_region = var_InheritString(p_demux, "bluray-region");
762 unsigned int region = psz_region ? (psz_region[0] - 'A') : REGION_DEFAULT;
763 free(psz_region);
764 bd_set_player_setting(p_sys->bluray, BLURAY_PLAYER_SETTING_REGION_CODE, 1<<region);
766 /* set preferred languages */
767 const char *psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
768 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG, psz_code);
769 psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
770 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG, psz_code);
771 psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
772 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_MENU_LANG, psz_code);
774 /* Get disc metadata */
775 p_sys->p_meta = bd_get_meta(p_sys->bluray);
776 if (!p_sys->p_meta)
777 msg_Warn(p_demux, "Failed to get meta info.");
779 p_sys->i_cover_idx = -1;
780 attachThumbnail(p_demux);
782 p_sys->b_menu = var_InheritBool(p_demux, "bluray-menu");
784 /* Check BD-J capability */
785 if (p_sys->b_menu && disc_info->bdj_detected && !disc_info->bdj_handled) {
786 msg_Err(p_demux, "BD-J menus not supported. Playing without menus. "
787 "BD-J support: %d, JVM found: %d, JVM usable: %d",
788 disc_info->bdj_supported, disc_info->libjvm_detected, disc_info->bdj_handled);
789 vlc_dialog_display_error(p_demux, _("Java required"),
790 _("This Blu-ray disc needs Java for menus.%s\nDisc is played without menus."),
791 !disc_info->libjvm_detected ? _(" Java was not found from your system.") : "");
792 p_sys->b_menu = false;
795 /* Get titles and chapters */
796 blurayInitTitles(p_demux, disc_info->num_hdmv_titles + disc_info->num_bdj_titles + 1/*Top Menu*/ + 1/*First Play*/);
799 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
801 bd_get_event(p_sys->bluray, NULL);
803 /* Registering overlay event handler */
804 bd_register_overlay_proc(p_sys->bluray, p_demux, blurayOverlayProc);
805 if (unlikely(!p_demux->p_input)) {
806 msg_Err(p_demux, "Could not get parent input");
807 goto error;
810 if (p_sys->b_menu) {
812 /* Register ARGB overlay handler for BD-J */
813 if (disc_info->num_bdj_titles)
814 bd_register_argb_overlay_proc(p_sys->bluray, p_demux, blurayArgbOverlayProc, NULL);
816 /* libbluray will start playback from "First-Title" title */
817 if (bd_play(p_sys->bluray) == 0)
818 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
820 } else {
821 /* set start title number */
822 if (bluraySetTitle(p_demux, p_sys->i_longest_title) != VLC_SUCCESS) {
823 msg_Err(p_demux, "Could not set the title %d", p_sys->i_longest_title);
824 goto error;
828 vlc_array_init(&p_sys->es);
829 p_sys->p_out = esOutNew(p_demux);
830 if (unlikely(p_sys->p_out == NULL))
831 goto error;
833 blurayResetParser(p_demux);
834 if (!p_sys->p_parser) {
835 msg_Err(p_demux, "Failed to create TS demuxer");
836 goto error;
839 p_demux->pf_control = blurayControl;
840 p_demux->pf_demux = blurayDemux;
842 return VLC_SUCCESS;
844 error:
845 if (error_msg)
846 vlc_dialog_display_error(p_demux, _("Blu-ray error"), "%s", error_msg);
847 blurayClose(object);
849 if (p_demux->s != NULL) {
850 /* restore stream position */
851 if (vlc_stream_Seek(p_demux->s, i_init_pos) != VLC_SUCCESS) {
852 msg_Err(p_demux, "Failed to seek back to stream start");
853 return VLC_ETIMEOUT;
857 return VLC_EGENERIC;
858 #undef BLURAY_ERROR
862 /*****************************************************************************
863 * blurayClose: module destroy function
864 *****************************************************************************/
865 static void blurayClose(vlc_object_t *object)
867 demux_t *p_demux = (demux_t*)object;
868 demux_sys_t *p_sys = p_demux->p_sys;
870 var_DelCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
872 setTitleInfo(p_sys, NULL);
875 * Close libbluray first.
876 * This will close all the overlays before we release p_vout
877 * bd_close(NULL) can crash
879 if (p_sys->bluray) {
880 bd_close(p_sys->bluray);
883 blurayReleaseVout(p_demux);
885 if (p_sys->p_parser)
886 vlc_demux_chained_Delete(p_sys->p_parser);
887 if (p_sys->p_out != NULL)
888 es_out_Delete(p_sys->p_out);
889 assert(vlc_array_count(&p_sys->es) == 0);
890 vlc_array_clear(&p_sys->es);
892 /* Titles */
893 for (unsigned int i = 0; i < p_sys->i_title; i++)
894 vlc_input_title_Delete(p_sys->pp_title[i]);
895 TAB_CLEAN(p_sys->i_title, p_sys->pp_title);
897 for (int i = 0; i < p_sys->i_attachments; i++)
898 vlc_input_attachment_Delete(p_sys->attachments[i]);
899 TAB_CLEAN(p_sys->i_attachments, p_sys->attachments);
901 vlc_mutex_destroy(&p_sys->pl_info_lock);
902 vlc_mutex_destroy(&p_sys->bdj_overlay_lock);
903 vlc_mutex_destroy(&p_sys->read_block_lock);
905 free(p_sys->psz_bd_path);
906 free(p_sys);
909 /*****************************************************************************
910 * Elementary streams handling
911 *****************************************************************************/
913 struct es_out_sys_t {
914 demux_t *p_demux;
917 typedef struct fmt_es_pair {
918 int i_id;
919 es_out_id_t *p_es;
920 } fmt_es_pair_t;
922 static int findEsPairIndex(demux_sys_t *p_sys, int i_id)
924 for (size_t i = 0; i < vlc_array_count(&p_sys->es); ++i)
925 if (((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->i_id == i_id)
926 return i;
928 return -1;
931 static int findEsPairIndexByEs(demux_sys_t *p_sys, es_out_id_t *p_es)
933 for (size_t i = 0; i < vlc_array_count(&p_sys->es); ++i)
934 if (((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->p_es == p_es)
935 return i;
937 return -1;
940 static void setStreamLang(demux_sys_t *p_sys, es_format_t *p_fmt)
942 const BLURAY_STREAM_INFO *p_streams;
943 int i_stream_count = 0;
945 vlc_mutex_lock(&p_sys->pl_info_lock);
947 if (p_sys->p_clip_info) {
948 if (p_fmt->i_cat == AUDIO_ES) {
949 p_streams = p_sys->p_clip_info->audio_streams;
950 i_stream_count = p_sys->p_clip_info->audio_stream_count;
951 } else if (p_fmt->i_cat == SPU_ES) {
952 p_streams = p_sys->p_clip_info->pg_streams;
953 i_stream_count = p_sys->p_clip_info->pg_stream_count;
957 for (int i = 0; i < i_stream_count; i++) {
958 if (p_fmt->i_id == p_streams[i].pid) {
959 free(p_fmt->psz_language);
960 p_fmt->psz_language = strndup((const char *)p_streams[i].lang, 3);
961 break;
965 vlc_mutex_unlock(&p_sys->pl_info_lock);
968 static int blurayEsPid(demux_sys_t *p_sys, int es_type, int i_es_idx)
970 int i_pid = -1;
972 vlc_mutex_lock(&p_sys->pl_info_lock);
974 if (p_sys->p_clip_info) {
975 if (es_type == AUDIO_ES) {
976 if (i_es_idx >= 0 && i_es_idx < p_sys->p_clip_info->audio_stream_count) {
977 i_pid = p_sys->p_clip_info->audio_streams[i_es_idx].pid;
979 } else if (es_type == SPU_ES) {
980 if (i_es_idx >= 0 && i_es_idx < p_sys->p_clip_info->pg_stream_count) {
981 i_pid = p_sys->p_clip_info->pg_streams[i_es_idx].pid;
986 vlc_mutex_unlock(&p_sys->pl_info_lock);
988 return i_pid;
991 static es_out_id_t *esOutAdd(es_out_t *p_out, const es_format_t *p_fmt)
993 demux_t *p_demux = p_out->p_sys->p_demux;
994 demux_sys_t *p_sys = p_demux->p_sys;
995 es_format_t fmt;
996 bool b_select = false;
998 es_format_Copy(&fmt, p_fmt);
1000 switch (fmt.i_cat) {
1001 case VIDEO_ES:
1002 if (p_sys->i_video_stream != -1 && p_sys->i_video_stream != p_fmt->i_id)
1003 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1004 break ;
1005 case AUDIO_ES:
1006 if (p_sys->i_audio_stream_idx != -1) {
1007 if (blurayEsPid(p_sys, AUDIO_ES, p_sys->i_audio_stream_idx) == p_fmt->i_id)
1008 b_select = true;
1009 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1011 setStreamLang(p_sys, &fmt);
1012 break ;
1013 case SPU_ES:
1014 if (p_sys->i_spu_stream_idx != -1) {
1015 if (blurayEsPid(p_sys, SPU_ES, p_sys->i_spu_stream_idx) == p_fmt->i_id)
1016 b_select = true;
1017 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1019 setStreamLang(p_sys, &fmt);
1020 break ;
1023 es_out_id_t *p_es = es_out_Add(p_demux->out, &fmt);
1024 if (p_fmt->i_id >= 0) {
1025 /* Ensure we are not overriding anything */
1026 int idx = findEsPairIndex(p_sys, p_fmt->i_id);
1027 if (idx == -1) {
1028 fmt_es_pair_t *p_pair = malloc(sizeof(*p_pair));
1029 if (likely(p_pair != NULL)) {
1030 p_pair->i_id = p_fmt->i_id;
1031 p_pair->p_es = p_es;
1032 msg_Info(p_demux, "Adding ES %d", p_fmt->i_id);
1033 vlc_array_append(&p_sys->es, p_pair);
1035 if (b_select) {
1036 if (fmt.i_cat == AUDIO_ES) {
1037 var_SetInteger( p_demux->p_input, "audio-es", p_fmt->i_id );
1038 } else if (fmt.i_cat == SPU_ES) {
1039 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? p_fmt->i_id : -1 );
1045 es_format_Clean(&fmt);
1046 return p_es;
1049 static int esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1051 return es_out_Send(p_out->p_sys->p_demux->out, p_es, p_block);
1054 static void esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1056 int idx = findEsPairIndexByEs(p_out->p_sys->p_demux->p_sys, p_es);
1057 if (idx >= 0) {
1058 free(vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, idx));
1059 vlc_array_remove(&p_out->p_sys->p_demux->p_sys->es, idx);
1061 es_out_Del(p_out->p_sys->p_demux->out, p_es);
1064 static int esOutControl(es_out_t *p_out, int i_query, va_list args)
1066 return es_out_vaControl(p_out->p_sys->p_demux->out, i_query, args);
1069 static void esOutDestroy(es_out_t *p_out)
1071 for (size_t i = 0; i < vlc_array_count(&p_out->p_sys->p_demux->p_sys->es); ++i)
1072 free(vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, i));
1073 vlc_array_clear(&p_out->p_sys->p_demux->p_sys->es);
1074 free(p_out->p_sys);
1075 free(p_out);
1078 static es_out_t *esOutNew(demux_t *p_demux)
1080 assert(vlc_array_count(&p_demux->p_sys->es) == 0);
1081 es_out_t *p_out = malloc(sizeof(*p_out));
1082 if (unlikely(p_out == NULL))
1083 return NULL;
1085 p_out->pf_add = esOutAdd;
1086 p_out->pf_control = esOutControl;
1087 p_out->pf_del = esOutDel;
1088 p_out->pf_destroy = esOutDestroy;
1089 p_out->pf_send = esOutSend;
1091 p_out->p_sys = malloc(sizeof(*p_out->p_sys));
1092 if (unlikely(p_out->p_sys == NULL)) {
1093 free(p_out);
1094 return NULL;
1096 p_out->p_sys->p_demux = p_demux;
1097 return p_out;
1100 /*****************************************************************************
1101 * subpicture_updater_t functions:
1102 *****************************************************************************/
1104 static bluray_overlay_t *updater_lock_overlay(subpicture_updater_sys_t *p_upd_sys)
1106 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1107 vlc_mutex_lock(&p_upd_sys->lock);
1109 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1110 if (ov) {
1111 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1112 vlc_mutex_lock(&ov->lock);
1113 return ov;
1116 /* overlay has been closed */
1117 vlc_mutex_unlock(&p_upd_sys->lock);
1118 return NULL;
1121 static void updater_unlock_overlay(subpicture_updater_sys_t *p_upd_sys)
1123 assert (p_upd_sys->p_overlay);
1125 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1126 vlc_mutex_unlock(&p_upd_sys->lock);
1129 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1130 bool b_fmt_src, const video_format_t *p_fmt_src,
1131 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1132 mtime_t i_ts)
1134 VLC_UNUSED(b_fmt_src);
1135 VLC_UNUSED(b_fmt_dst);
1136 VLC_UNUSED(p_fmt_src);
1137 VLC_UNUSED(p_fmt_dst);
1138 VLC_UNUSED(i_ts);
1140 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1141 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1143 if (!p_overlay) {
1144 return 1;
1147 int res = p_overlay->status == Outdated;
1149 updater_unlock_overlay(p_upd_sys);
1151 return res;
1154 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1155 const video_format_t *p_fmt_src,
1156 const video_format_t *p_fmt_dst,
1157 mtime_t i_ts)
1159 VLC_UNUSED(p_fmt_src);
1160 VLC_UNUSED(p_fmt_dst);
1161 VLC_UNUSED(i_ts);
1162 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1163 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1165 if (!p_overlay) {
1166 return;
1170 * When this function is called, all p_subpic regions are gone.
1171 * We need to duplicate our regions (stored internaly) to this subpic.
1173 subpicture_region_t *p_src = p_overlay->p_regions;
1174 if (!p_src) {
1175 updater_unlock_overlay(p_upd_sys);
1176 return;
1179 subpicture_region_t **p_dst = &p_subpic->p_region;
1180 while (p_src != NULL) {
1181 *p_dst = subpicture_region_Copy(p_src);
1182 if (*p_dst == NULL)
1183 break;
1184 p_dst = &(*p_dst)->p_next;
1185 p_src = p_src->p_next;
1187 if (*p_dst != NULL)
1188 (*p_dst)->p_next = NULL;
1189 p_overlay->status = Displayed;
1191 updater_unlock_overlay(p_upd_sys);
1194 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1196 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1197 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1199 if (p_overlay) {
1200 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1201 p_overlay->status = ToDisplay;
1202 p_overlay->i_channel = -1;
1203 updater_unlock_overlay(p_upd_sys);
1206 unref_subpicture_updater(p_upd_sys);
1209 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1211 subpicture_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1212 if (unlikely(p_upd_sys == NULL)) {
1213 return NULL;
1216 p_upd_sys->p_overlay = p_ov;
1218 subpicture_updater_t updater = {
1219 .pf_validate = subpictureUpdaterValidate,
1220 .pf_update = subpictureUpdaterUpdate,
1221 .pf_destroy = subpictureUpdaterDestroy,
1222 .p_sys = p_upd_sys,
1225 subpicture_t *p_pic = subpicture_New(&updater);
1226 if (p_pic == NULL) {
1227 free(p_upd_sys);
1228 return NULL;
1231 p_pic->i_original_picture_width = p_ov->width;
1232 p_pic->i_original_picture_height = p_ov->height;
1233 p_pic->b_ephemer = true;
1234 p_pic->b_absolute = true;
1236 vlc_mutex_init(&p_upd_sys->lock);
1237 p_upd_sys->ref_cnt = 2;
1239 p_ov->p_updater = p_upd_sys;
1241 return p_pic;
1244 /*****************************************************************************
1245 * User input events:
1246 *****************************************************************************/
1247 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var, vlc_value_t old,
1248 vlc_value_t val, void *p_data)
1250 demux_t *p_demux = (demux_t*)p_data;
1251 demux_sys_t *p_sys = p_demux->p_sys;
1252 VLC_UNUSED(old);
1253 VLC_UNUSED(p_vout);
1255 if (psz_var[6] == 'm') //Mouse moved
1256 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1257 else if (psz_var[6] == 'c') {
1258 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1259 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1260 } else {
1261 vlc_assert_unreachable();
1263 return VLC_SUCCESS;
1266 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1268 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1269 return VLC_EGENERIC;
1271 return VLC_SUCCESS;
1274 /*****************************************************************************
1275 * libbluray overlay handling:
1276 *****************************************************************************/
1278 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1280 demux_sys_t *p_sys = p_demux->p_sys;
1281 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1283 if (ov != NULL) {
1285 /* drop overlay from vout */
1286 if (ov->p_updater) {
1287 unref_subpicture_updater(ov->p_updater);
1289 /* no references to this overlay exist in vo anymore */
1290 if (p_sys->p_vout && ov->i_channel != -1) {
1291 vout_FlushSubpictureChannel(p_sys->p_vout, ov->i_channel);
1294 vlc_mutex_destroy(&ov->lock);
1295 subpicture_region_ChainDelete(ov->p_regions);
1296 free(ov);
1298 p_sys->p_overlays[plane] = NULL;
1301 for (int i = 0; i < MAX_OVERLAY; i++)
1302 if (p_sys->p_overlays[i])
1303 return;
1305 /* All overlays have been closed */
1306 blurayReleaseVout(p_demux);
1310 * Mark the overlay as "ToDisplay" status.
1311 * This will not send the overlay to the vout instantly, as the vout
1312 * may not be acquired (not acquirable) yet.
1313 * If is has already been acquired, the overlay has already been sent to it,
1314 * therefore, we only flag the overlay as "Outdated"
1316 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1318 demux_sys_t *p_sys = p_demux->p_sys;
1319 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1322 * If the overlay is already displayed, mark the picture as outdated.
1323 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1325 vlc_mutex_lock(&ov->lock);
1326 if (ov->status >= Displayed && p_sys->p_vout) {
1327 ov->status = Outdated;
1328 vlc_mutex_unlock(&ov->lock);
1329 return;
1333 * Mark the overlay as available, but don't display it right now.
1334 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1335 * the overlay is computed
1337 ov->status = ToDisplay;
1338 vlc_mutex_unlock(&ov->lock);
1341 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1343 demux_sys_t *p_sys = p_demux->p_sys;
1345 assert(p_sys->p_overlays[plane] == NULL);
1347 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1348 if (unlikely(ov == NULL))
1349 return;
1351 ov->width = width;
1352 ov->height = height;
1353 ov->i_channel = -1;
1355 vlc_mutex_init(&ov->lock);
1357 p_sys->p_overlays[plane] = ov;
1361 * Destroy every regions in the subpicture.
1362 * This is done in two steps:
1363 * - Wiping our private regions list
1364 * - Flagging the overlay as outdated, so the changes are replicated from
1365 * the subpicture_updater_t::pf_update
1366 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1368 static void blurayClearOverlay(demux_t *p_demux, int plane)
1370 demux_sys_t *p_sys = p_demux->p_sys;
1371 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1373 vlc_mutex_lock(&ov->lock);
1375 subpicture_region_ChainDelete(ov->p_regions);
1376 ov->p_regions = NULL;
1377 ov->status = Outdated;
1379 vlc_mutex_unlock(&ov->lock);
1383 * This will draw to the overlay by adding a region to our region list
1384 * This will have to be copied to the subpicture used to render the overlay.
1386 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1388 demux_sys_t *p_sys = p_demux->p_sys;
1391 * Compute a subpicture_region_t.
1392 * It will be copied and sent to the vout later.
1394 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1396 /* Find a region to update */
1397 subpicture_region_t **pp_reg = &p_sys->p_overlays[ov->plane]->p_regions;
1398 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1399 subpicture_region_t *p_last = NULL;
1400 while (p_reg != NULL) {
1401 p_last = p_reg;
1402 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1403 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1404 break;
1405 pp_reg = &p_reg->p_next;
1406 p_reg = p_reg->p_next;
1409 if (!ov->img) {
1410 if (p_reg) {
1411 /* drop region */
1412 *pp_reg = p_reg->p_next;
1413 subpicture_region_Delete(p_reg);
1415 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1416 return;
1419 /* If there is no region to update, create a new one. */
1420 if (!p_reg) {
1421 video_format_t fmt;
1422 video_format_Init(&fmt, 0);
1423 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1425 p_reg = subpicture_region_New(&fmt);
1426 p_reg->i_x = ov->x;
1427 p_reg->i_y = ov->y;
1428 /* Append it to our list. */
1429 if (p_last != NULL)
1430 p_last->p_next = p_reg;
1431 else /* If we don't have a last region, then our list empty */
1432 p_sys->p_overlays[ov->plane]->p_regions = p_reg;
1435 /* Now we can update the region, regardless it's an update or an insert */
1436 const BD_PG_RLE_ELEM *img = ov->img;
1437 for (int y = 0; y < ov->h; y++)
1438 for (int x = 0; x < ov->w;) {
1439 plane_t *p = &p_reg->p_picture->p[0];
1440 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1441 x += img->len;
1442 img++;
1445 if (ov->palette) {
1446 p_reg->fmt.p_palette->i_entries = 256;
1447 for (int i = 0; i < 256; ++i) {
1448 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1449 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1450 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1451 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1455 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1457 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1461 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1463 demux_t *p_demux = (demux_t*)ptr;
1464 demux_sys_t *p_sys = p_demux->p_sys;
1466 if (!overlay) {
1467 msg_Info(p_demux, "Closing overlays.");
1468 if (p_sys->p_vout)
1469 for (int i = 0; i < MAX_OVERLAY; i++)
1470 blurayCloseOverlay(p_demux, i);
1471 return;
1474 switch (overlay->cmd) {
1475 case BD_OVERLAY_INIT:
1476 msg_Info(p_demux, "Initializing overlay");
1477 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1478 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1479 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1480 break;
1481 case BD_OVERLAY_CLOSE:
1482 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1483 blurayClearOverlay(p_demux, overlay->plane);
1484 blurayCloseOverlay(p_demux, overlay->plane);
1485 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1486 break;
1487 case BD_OVERLAY_CLEAR:
1488 blurayClearOverlay(p_demux, overlay->plane);
1489 break;
1490 case BD_OVERLAY_FLUSH:
1491 blurayActivateOverlay(p_demux, overlay->plane);
1492 break;
1493 case BD_OVERLAY_DRAW:
1494 case BD_OVERLAY_WIPE:
1495 blurayDrawOverlay(p_demux, overlay);
1496 break;
1497 default:
1498 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
1499 break;
1504 * ARGB overlay (BD-J)
1506 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
1508 demux_sys_t *p_sys = p_demux->p_sys;
1510 blurayInitOverlay(p_demux, plane, width, height);
1512 if (!p_sys->p_overlays[plane]->p_regions) {
1513 video_format_t fmt;
1514 video_format_Init(&fmt, 0);
1515 video_format_Setup(&fmt, VLC_CODEC_RGBA, width, height, width, height, 1, 1);
1517 p_sys->p_overlays[plane]->p_regions = subpicture_region_New(&fmt);
1521 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
1523 demux_sys_t *p_sys = p_demux->p_sys;
1525 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1527 /* Find a region to update */
1528 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1529 if (!p_reg) {
1530 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1531 return;
1534 /* Now we can update the region */
1535 const uint32_t *src0 = ov->argb;
1536 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
1537 p_reg->p_picture->p[0].i_pitch * ov->y +
1538 ov->x * 4;
1540 for (int y = 0; y < ov->h; y++) {
1541 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1542 // - or add libbluray option to select the format ?
1543 for (int x = 0; x < ov->w; x++) {
1544 dst0[x*4 ] = src0[x]>>16; /* R */
1545 dst0[x*4+1] = src0[x]>>8; /* G */
1546 dst0[x*4+2] = src0[x]; /* B */
1547 dst0[x*4+3] = src0[x]>>24; /* A */
1550 src0 += ov->stride;
1551 dst0 += p_reg->p_picture->p[0].i_pitch;
1554 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1556 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1560 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
1562 demux_t *p_demux = (demux_t*)ptr;
1563 demux_sys_t *p_sys = p_demux->p_sys;
1565 switch (overlay->cmd) {
1566 case BD_ARGB_OVERLAY_INIT:
1567 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1568 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1569 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1570 break;
1571 case BD_ARGB_OVERLAY_CLOSE:
1572 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1573 blurayClearOverlay(p_demux, overlay->plane);
1574 blurayCloseOverlay(p_demux, overlay->plane);
1575 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1576 break;
1577 case BD_ARGB_OVERLAY_FLUSH:
1578 blurayActivateOverlay(p_demux, overlay->plane);
1579 break;
1580 case BD_ARGB_OVERLAY_DRAW:
1581 blurayDrawArgbOverlay(p_demux, overlay);
1582 break;
1583 default:
1584 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
1585 break;
1589 static void bluraySendOverlayToVout(demux_t *p_demux, bluray_overlay_t *p_ov)
1591 demux_sys_t *p_sys = p_demux->p_sys;
1593 assert(p_ov != NULL);
1594 assert(p_ov->i_channel == -1);
1596 if (p_ov->p_updater) {
1597 unref_subpicture_updater(p_ov->p_updater);
1598 p_ov->p_updater = NULL;
1601 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
1602 if (!p_pic) {
1603 msg_Err(p_demux, "bluraySubpictureCreate() failed");
1604 return;
1607 p_pic->i_start = p_pic->i_stop = mdate();
1608 p_pic->i_channel = vout_RegisterSubpictureChannel(p_sys->p_vout);
1609 p_ov->i_channel = p_pic->i_channel;
1612 * After this point, the picture should not be accessed from the demux thread,
1613 * as it is held by the vout thread.
1614 * This must be done only once per subpicture, ie. only once between each
1615 * blurayInitOverlay & blurayCloseOverlay call.
1617 vout_PutSubpicture(p_sys->p_vout, p_pic);
1620 * Mark the picture as Outdated, as it contains no region for now.
1621 * This will make the subpicture_updater_t call pf_update
1623 p_ov->status = Outdated;
1626 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
1628 t->i_length = FROM_TICKS(title_info->duration);
1630 for (int i = 0; i < t->i_seekpoint; i++)
1631 vlc_seekpoint_Delete( t->seekpoint[i] );
1632 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
1634 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
1635 seekpoint_t *s = vlc_seekpoint_New();
1636 if (!s) {
1637 break;
1639 s->i_time_offset = FROM_TICKS(title_info->chapters[j].start);
1641 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
1645 static void blurayInitTitles(demux_t *p_demux, int menu_titles)
1647 demux_sys_t *p_sys = p_demux->p_sys;
1648 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
1650 /* get and set the titles */
1651 unsigned i_title = menu_titles;
1653 if (!p_sys->b_menu) {
1654 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
1655 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
1658 for (unsigned int i = 0; i < i_title; i++) {
1659 input_title_t *t = vlc_input_title_New();
1660 if (!t)
1661 break;
1663 if (!p_sys->b_menu) {
1664 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
1665 blurayUpdateTitleInfo(t, title_info);
1666 bd_free_title_info(title_info);
1668 } else if (i == 0) {
1669 t->psz_name = strdup(_("Top Menu"));
1670 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
1671 } else if (i == i_title - 1) {
1672 t->psz_name = strdup(_("First Play"));
1673 if (di && di->first_play && di->first_play->interactive) {
1674 t->i_flags = INPUT_TITLE_INTERACTIVE;
1676 } else {
1677 /* add possible title name from disc metadata */
1678 if (di && di->titles && i <= di->num_titles) {
1679 if (di->titles[i]->name) {
1680 t->psz_name = strdup(di->titles[i]->name);
1682 if (di->titles[i]->interactive) {
1683 t->i_flags = INPUT_TITLE_INTERACTIVE;
1688 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
1692 static void blurayResetParser(demux_t *p_demux)
1695 * This is a hack and will have to be removed.
1696 * The parser should be flushed, and not destroy/created each time
1697 * we are changing title.
1699 demux_sys_t *p_sys = p_demux->p_sys;
1700 if (p_sys->p_parser)
1701 vlc_demux_chained_Delete(p_sys->p_parser);
1703 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
1705 if (!p_sys->p_parser)
1706 msg_Err(p_demux, "Failed to create TS demuxer");
1709 /*****************************************************************************
1710 * bluraySetTitle: select new BD title
1711 *****************************************************************************/
1712 static int bluraySetTitle(demux_t *p_demux, int i_title)
1714 demux_sys_t *p_sys = p_demux->p_sys;
1716 if (p_sys->b_menu) {
1717 int result;
1718 if (i_title <= 0) {
1719 msg_Dbg(p_demux, "Playing TopMenu Title");
1720 result = bd_menu_call(p_sys->bluray, -1);
1721 } else if (i_title >= (int)p_sys->i_title - 1) {
1722 msg_Dbg(p_demux, "Playing FirstPlay Title");
1723 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
1724 } else {
1725 msg_Dbg(p_demux, "Playing Title %i", i_title);
1726 result = bd_play_title(p_sys->bluray, i_title);
1729 if (result == 0) {
1730 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
1731 return VLC_EGENERIC;
1734 return VLC_SUCCESS;
1737 /* Looking for the main title, ie the longest duration */
1738 if (i_title < 0)
1739 i_title = p_sys->i_longest_title;
1740 else if ((unsigned)i_title > p_sys->i_title)
1741 return VLC_EGENERIC;
1743 msg_Dbg(p_demux, "Selecting Title %i", i_title);
1745 if (bd_select_title(p_sys->bluray, i_title) == 0) {
1746 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
1747 return VLC_EGENERIC;
1750 blurayResetParser(p_demux);
1752 return VLC_SUCCESS;
1755 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
1756 # define BLURAY_AUDIO_STREAM 0
1757 #endif
1759 static void blurayStreamSelected(demux_sys_t *p_sys, int i_pid)
1761 vlc_mutex_lock(&p_sys->pl_info_lock);
1763 if (p_sys->p_clip_info) {
1764 if ((i_pid & 0xff00) == 0x1100) {
1765 // audio
1766 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
1767 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
1768 p_sys->i_audio_stream_idx = i_id;
1769 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
1770 break;
1773 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
1774 // subtitle
1775 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
1776 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
1777 p_sys->i_spu_stream_idx = i_id;
1778 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
1779 break;
1785 vlc_mutex_unlock(&p_sys->pl_info_lock);
1788 /*****************************************************************************
1789 * blurayControl: handle the controls
1790 *****************************************************************************/
1791 static int blurayControl(demux_t *p_demux, int query, va_list args)
1793 demux_sys_t *p_sys = p_demux->p_sys;
1794 bool *pb_bool;
1795 int64_t *pi_64;
1797 switch (query) {
1798 case DEMUX_CAN_SEEK:
1799 case DEMUX_CAN_PAUSE:
1800 case DEMUX_CAN_CONTROL_PACE:
1801 pb_bool = va_arg(args, bool *);
1802 *pb_bool = true;
1803 break;
1805 case DEMUX_GET_PTS_DELAY:
1806 pi_64 = va_arg(args, int64_t *);
1807 *pi_64 = INT64_C(1000) * var_InheritInteger(p_demux, "disc-caching");
1808 break;
1810 case DEMUX_SET_PAUSE_STATE:
1812 #ifdef BLURAY_RATE_NORMAL
1813 bool b_paused = (bool)va_arg(args, int);
1814 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
1815 return VLC_EGENERIC;
1817 #endif
1818 break;
1820 case DEMUX_SET_ES:
1822 int i_id = va_arg(args, int);
1823 blurayStreamSelected(p_sys, i_id);
1824 break;
1826 case DEMUX_SET_TITLE:
1828 int i_title = va_arg(args, int);
1829 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
1830 /* make sure GUI restores the old setting in title menu ... */
1831 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1832 notifyDiscontinuity( p_sys );
1833 return VLC_EGENERIC;
1835 break;
1837 case DEMUX_SET_SEEKPOINT:
1839 int i_chapter = va_arg(args, int);
1840 bd_seek_chapter(p_sys->bluray, i_chapter);
1841 notifyDiscontinuity( p_sys );
1842 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
1843 break;
1846 case DEMUX_GET_TITLE_INFO:
1848 input_title_t ***ppp_title = va_arg(args, input_title_t***);
1849 int *pi_int = va_arg(args, int *);
1850 int *pi_title_offset = va_arg(args, int *);
1851 int *pi_chapter_offset = va_arg(args, int *);
1853 /* */
1854 *pi_title_offset = 0;
1855 *pi_chapter_offset = 0;
1857 /* Duplicate local title infos */
1858 *pi_int = p_sys->i_title;
1859 *ppp_title = malloc(p_sys->i_title * sizeof(input_title_t *));
1860 for (unsigned int i = 0; i < p_sys->i_title; i++)
1861 (*ppp_title)[i] = vlc_input_title_Duplicate(p_sys->pp_title[i]);
1863 return VLC_SUCCESS;
1866 case DEMUX_GET_LENGTH:
1868 int64_t *pi_length = va_arg(args, int64_t *);
1869 *pi_length = p_demux->info.i_title < (int)p_sys->i_title ? CUR_LENGTH : 0;
1870 return VLC_SUCCESS;
1872 case DEMUX_SET_TIME:
1874 int64_t i_time = va_arg(args, int64_t);
1875 bd_seek_time(p_sys->bluray, TO_TICKS(i_time));
1876 notifyDiscontinuity( p_sys );
1877 return VLC_SUCCESS;
1879 case DEMUX_GET_TIME:
1881 int64_t *pi_time = va_arg(args, int64_t *);
1882 *pi_time = (int64_t)FROM_TICKS(bd_tell_time(p_sys->bluray));
1883 return VLC_SUCCESS;
1886 case DEMUX_GET_POSITION:
1888 double *pf_position = va_arg(args, double *);
1889 *pf_position = p_demux->info.i_title < (int)p_sys->i_title && CUR_LENGTH > 0 ?
1890 (double)FROM_TICKS(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
1891 return VLC_SUCCESS;
1893 case DEMUX_SET_POSITION:
1895 double f_position = va_arg(args, double);
1896 bd_seek_time(p_sys->bluray, TO_TICKS(f_position*CUR_LENGTH));
1897 notifyDiscontinuity( p_sys );
1898 return VLC_SUCCESS;
1901 case DEMUX_GET_META:
1903 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
1904 const META_DL *meta = p_sys->p_meta;
1905 if (meta == NULL)
1906 return VLC_EGENERIC;
1908 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
1910 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
1911 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
1912 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
1914 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
1915 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
1917 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
1918 char psz_url[128];
1919 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
1920 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
1921 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
1923 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
1924 char *psz_thumbpath;
1925 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
1926 p_sys->psz_bd_path, meta->thumbnails[0].path) > 0) {
1927 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
1928 if (unlikely(psz_thumburl == NULL)) {
1929 free(psz_thumbpath);
1930 return VLC_ENOMEM;
1933 vlc_meta_SetArtURL(p_meta, psz_thumburl);
1934 free(psz_thumburl);
1936 free(psz_thumbpath);
1939 return VLC_SUCCESS;
1942 case DEMUX_GET_ATTACHMENTS:
1944 input_attachment_t ***ppp_attach =
1945 va_arg(args, input_attachment_t ***);
1946 int *pi_int = va_arg(args, int *);
1948 if (p_sys->i_attachments <= 0)
1949 return VLC_EGENERIC;
1951 *pi_int = p_sys->i_attachments;
1952 *ppp_attach = xmalloc(sizeof(input_attachment_t *) * p_sys->i_attachments);
1953 for (int i = 0; i < p_sys->i_attachments; i++)
1954 (*ppp_attach)[i] = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
1955 return VLC_SUCCESS;
1958 case DEMUX_NAV_ACTIVATE:
1959 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
1960 return sendKeyEvent(p_sys, BD_VK_POPUP);
1962 return sendKeyEvent(p_sys, BD_VK_ENTER);
1963 case DEMUX_NAV_UP:
1964 return sendKeyEvent(p_sys, BD_VK_UP);
1965 case DEMUX_NAV_DOWN:
1966 return sendKeyEvent(p_sys, BD_VK_DOWN);
1967 case DEMUX_NAV_LEFT:
1968 return sendKeyEvent(p_sys, BD_VK_LEFT);
1969 case DEMUX_NAV_RIGHT:
1970 return sendKeyEvent(p_sys, BD_VK_RIGHT);
1971 case DEMUX_NAV_POPUP:
1972 return sendKeyEvent(p_sys, BD_VK_POPUP);
1973 case DEMUX_NAV_MENU:
1974 if (p_sys->b_menu) {
1975 if (bd_menu_call(p_sys->bluray, -1) == 1) {
1976 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1977 return VLC_SUCCESS;
1979 msg_Err(p_demux, "Can't select Top Menu title");
1980 return sendKeyEvent(p_sys, BD_VK_POPUP);
1982 return VLC_EGENERIC;
1984 case DEMUX_CAN_RECORD:
1985 case DEMUX_GET_FPS:
1986 case DEMUX_SET_GROUP:
1987 case DEMUX_HAS_UNSUPPORTED_META:
1988 default:
1989 return VLC_EGENERIC;
1991 return VLC_SUCCESS;
1994 /*****************************************************************************
1995 * libbluray event handling
1996 *****************************************************************************/
1997 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
1998 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
2000 for( size_t i=0; i< i_sinfo; i++ )
2002 const uint16_t i_pid = p_sinfo[i].pid;
2004 block_t *p_block = block_Alloc(192);
2005 if (!p_block)
2006 return;
2008 uint8_t ts_header[] = {
2009 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2010 0x47,
2011 (i_pid & 0x1f00) >> 8, i_pid & 0xFF, /* PID */
2012 0x20, /* adaptation field, no payload */
2013 183, /* adaptation field length */
2014 0x80, /* adaptation field: discontinuity indicator */
2017 memcpy(p_block->p_buffer, ts_header, sizeof(ts_header));
2018 memset(&p_block->p_buffer[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header));
2019 p_block->i_buffer = 192;
2021 vlc_demux_chained_Send(p_parser, p_block);
2025 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2026 p_clip->memb##_stream_count )
2028 static void notifyDiscontinuity( demux_sys_t *p_sys )
2030 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2031 if( p_clip )
2033 DONOTIFY(audio);
2034 DONOTIFY(video);
2035 DONOTIFY(pg);
2036 DONOTIFY(ig);
2037 DONOTIFY(sec_audio);
2038 DONOTIFY(sec_video);
2042 #undef DONOTIFY
2044 static void streamFlush( demux_sys_t *p_sys )
2047 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2048 * Packet is flushed only when TS packet with PUSI flag set is received.
2050 * Fix this by emitting (video) ts packet with PUSI flag set.
2051 * Add video sequence end code to payload so that also video decoder is flushed.
2052 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2055 if (p_sys->b_flushed)
2056 return;
2058 block_t *p_block = block_Alloc(192);
2059 if (!p_block)
2060 return;
2062 static const uint8_t seq_end_pes[] = {
2063 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2064 0x00, 0x00, 0x01, 0xb7, /* PES payload: sequence end */
2066 static const uint8_t vid_pusi_ts[] = {
2067 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2068 0x47, 0x50, 0x11, 0x30, /* TP header */
2069 (192 - (4 + 5) - sizeof(seq_end_pes)), /* adaptation field length */
2070 0x80, /* adaptation field: discontinuity indicator */
2073 memset(p_block->p_buffer, 0, 192);
2074 memcpy(p_block->p_buffer, vid_pusi_ts, sizeof(vid_pusi_ts));
2075 memcpy(p_block->p_buffer + 192 - sizeof(seq_end_pes), seq_end_pes, sizeof(seq_end_pes));
2076 p_block->i_buffer = 192;
2078 /* set correct sequence end code */
2079 vlc_mutex_lock(&p_sys->pl_info_lock);
2080 if (p_sys->p_clip_info != NULL) {
2081 if (p_sys->p_clip_info->video_streams[0].coding_type > 2) {
2082 /* VC1 / H.264 sequence end */
2083 p_block->p_buffer[191] = 0x0a;
2086 vlc_mutex_unlock(&p_sys->pl_info_lock);
2088 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2089 p_sys->b_flushed = true;
2092 static void blurayResetStillImage( demux_t *p_demux )
2094 demux_sys_t *p_sys = p_demux->p_sys;
2096 if (p_sys->i_still_end_time) {
2097 p_sys->i_still_end_time = 0;
2099 blurayResetParser(p_demux);
2100 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2104 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2106 demux_sys_t *p_sys = p_demux->p_sys;
2108 /* time period elapsed ? */
2109 if (p_sys->i_still_end_time > 0 && p_sys->i_still_end_time <= mdate()) {
2110 msg_Dbg(p_demux, "Still image end");
2111 bd_read_skip_still(p_sys->bluray);
2113 blurayResetStillImage(p_demux);
2114 return;
2117 /* show last frame as still image */
2118 if (!p_sys->i_still_end_time) {
2119 if (i_timeout) {
2120 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2121 p_sys->i_still_end_time = mdate() + i_timeout * CLOCK_FREQ;
2122 } else {
2123 msg_Dbg(p_demux, "Still image (infinite)");
2124 p_sys->i_still_end_time = -1;
2127 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2128 streamFlush(p_sys);
2130 /* stop buffering */
2131 bool b_empty;
2132 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2135 /* avoid busy loops (read returns no data) */
2136 msleep( 40000 );
2139 static void blurayStreamSelect(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2141 demux_sys_t *p_sys = p_demux->p_sys;
2142 int i_pid = -1;
2144 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2145 i_id--;
2147 if (i_type == BD_EVENT_AUDIO_STREAM) {
2148 p_sys->i_audio_stream_idx = i_id;
2149 i_pid = blurayEsPid(p_sys, AUDIO_ES, i_id);
2150 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2151 p_sys->i_spu_stream_idx = i_id;
2152 i_pid = blurayEsPid(p_sys, SPU_ES, i_id);
2155 if (i_pid > 0) {
2156 int i_idx = findEsPairIndex(p_sys, i_pid);
2157 if (i_idx >= 0) {
2158 if (i_type == BD_EVENT_AUDIO_STREAM) {
2159 var_SetInteger( p_demux->p_input, "audio-es", i_pid );
2160 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2161 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? i_pid : -1 );
2167 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2169 demux_sys_t *p_sys = p_demux->p_sys;
2171 blurayResetParser(p_demux);
2173 /* read title info and init some values */
2174 if (!p_sys->b_menu)
2175 p_demux->info.i_title = bd_get_current_title(p_sys->bluray);
2176 p_demux->info.i_seekpoint = 0;
2177 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2179 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2180 if (p_title_info) {
2181 blurayUpdateTitleInfo(p_sys->pp_title[p_demux->info.i_title], p_title_info);
2182 if (p_sys->b_menu)
2183 p_demux->info.i_update |= INPUT_UPDATE_TITLE_LIST;
2185 setTitleInfo(p_sys, p_title_info);
2187 blurayResetStillImage(p_demux);
2190 static void blurayUpdateCurrentClip(demux_t *p_demux, uint32_t clip)
2192 demux_sys_t *p_sys = p_demux->p_sys;
2194 vlc_mutex_lock(&p_sys->pl_info_lock);
2196 p_sys->p_clip_info = NULL;
2197 p_sys->i_video_stream = -1;
2199 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2201 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2203 /* Let's assume a single video track for now.
2204 * This may brake later, but it's enough for now.
2206 assert(p_sys->p_clip_info->video_stream_count >= 1);
2207 p_sys->i_video_stream = p_sys->p_clip_info->video_streams[0].pid;
2210 vlc_mutex_unlock(&p_sys->pl_info_lock);
2212 blurayResetStillImage(p_demux);
2215 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e)
2217 demux_sys_t *p_sys = p_demux->p_sys;
2219 switch (e->event) {
2220 case BD_EVENT_TITLE:
2221 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2222 p_demux->info.i_title = p_sys->i_title - 1;
2223 else
2224 p_demux->info.i_title = e->param;
2225 /* this is feature title, we don't know yet which playlist it will play (if any) */
2226 setTitleInfo(p_sys, NULL);
2227 /* reset title infos here ? */
2228 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT; /* might be BD-J title with no video */
2229 break;
2230 case BD_EVENT_PLAYLIST:
2231 /* Start of playlist playback (?????.mpls) */
2232 blurayUpdatePlaylist(p_demux, e->param);
2233 if (p_sys->b_pl_playing) {
2234 /* previous playlist was stopped in middle. flush to avoid delay */
2235 msg_Info(p_demux, "Stopping playlist playback");
2236 blurayResetParser(p_demux);
2237 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2239 p_sys->b_pl_playing = true;
2240 break;
2241 case BD_EVENT_PLAYITEM:
2242 blurayUpdateCurrentClip(p_demux, e->param);
2243 break;
2244 case BD_EVENT_CHAPTER:
2245 if (e->param && e->param < 0xffff)
2246 p_demux->info.i_seekpoint = e->param - 1;
2247 else
2248 p_demux->info.i_seekpoint = 0;
2249 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
2250 break;
2251 case BD_EVENT_PLAYMARK:
2252 case BD_EVENT_ANGLE:
2253 break;
2254 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2255 case BD_EVENT_UO_MASK_CHANGED:
2256 /* This event could be used to grey out unselectable items in title menu */
2257 break;
2258 #endif
2259 case BD_EVENT_MENU:
2260 p_sys->b_menu_open = e->param;
2261 break;
2262 case BD_EVENT_POPUP:
2263 p_sys->b_popup_available = e->param;
2264 /* TODO: show / hide pop-up menu button in gui ? */
2265 break;
2268 * Errors
2270 case BD_EVENT_ERROR:
2271 /* fatal error (with menus) */
2272 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2273 "Playback with BluRay menus failed");
2274 p_sys->b_fatal_error = true;
2275 break;
2276 case BD_EVENT_ENCRYPTED:
2277 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2278 "This disc seems to be encrypted");
2279 p_sys->b_fatal_error = true;
2280 break;
2281 case BD_EVENT_READ_ERROR:
2282 msg_Err(p_demux, "bluray: read error\n");
2283 break;
2286 * stream selection events
2288 case BD_EVENT_PG_TEXTST:
2289 p_sys->b_spu_enable = e->param;
2290 break;
2291 case BD_EVENT_AUDIO_STREAM:
2292 case BD_EVENT_PG_TEXTST_STREAM:
2293 blurayStreamSelect(p_demux, e->event, e->param);
2294 break;
2295 case BD_EVENT_IG_STREAM:
2296 case BD_EVENT_SECONDARY_AUDIO:
2297 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2298 case BD_EVENT_SECONDARY_VIDEO:
2299 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2300 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2301 break;
2304 * playback control events
2306 case BD_EVENT_STILL_TIME:
2307 blurayStillImage(p_demux, e->param);
2308 break;
2309 case BD_EVENT_DISCONTINUITY:
2310 /* reset demuxer (partially decoded PES packets must be dropped) */
2311 blurayResetParser(p_demux);
2312 break;
2313 case BD_EVENT_END_OF_TITLE:
2314 p_sys->b_pl_playing = false;
2315 break;
2316 case BD_EVENT_IDLE:
2317 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2318 /* avoid busy loop (bd_read() returns no data) */
2319 msleep( 40000 );
2320 break;
2322 default:
2323 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2324 break;
2328 static bool blurayIsBdjTitle(demux_t *p_demux)
2330 demux_sys_t *p_sys = p_demux->p_sys;
2331 unsigned int i_title = p_demux->info.i_title;
2332 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2334 if (di && di->titles) {
2335 if ((i_title <= di->num_titles && di->titles[i_title] && di->titles[i_title]->bdj) ||
2336 (i_title == p_sys->i_title - 1 && di->first_play && di->first_play->bdj)) {
2337 return true;
2341 return false;
2344 static void blurayHandleOverlays(demux_t *p_demux, int nread)
2346 demux_sys_t *p_sys = p_demux->p_sys;
2348 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2350 for (int i = 0; i < MAX_OVERLAY; i++) {
2351 bluray_overlay_t *ov = p_sys->p_overlays[i];
2352 if (!ov) {
2353 continue;
2355 vlc_mutex_lock(&ov->lock);
2356 bool display = ov->status == ToDisplay;
2357 vlc_mutex_unlock(&ov->lock);
2358 if (display) {
2359 if (p_sys->p_vout == NULL) {
2360 p_sys->p_vout = input_GetVout(p_demux->p_input);
2361 if (p_sys->p_vout != NULL) {
2362 var_AddCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
2363 var_AddCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
2367 /* NOTE: we might want to enable background video always when there's no video stream playing.
2368 Now, with some discs, there are perioids (even seconds) during which the video window
2369 disappears and just playlist is shown.
2370 (sometimes BD-J runs slowly ...)
2372 if (!p_sys->p_vout && !p_sys->p_dummy_video && p_sys->b_menu &&
2373 !p_sys->p_pl_info && nread == 0 &&
2374 blurayIsBdjTitle(p_demux)) {
2376 /* Looks like there's no video stream playing.
2377 Emit blank frame so that BD-J overlay can be drawn. */
2378 startBackground(p_demux);
2381 if (p_sys->p_vout != NULL) {
2382 bluraySendOverlayToVout(p_demux, ov);
2387 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2390 static int onIntfEvent( vlc_object_t *p_input, char const *psz_var,
2391 vlc_value_t oldval, vlc_value_t val, void *p_data )
2393 (void)p_input; (void) psz_var; (void) oldval;
2394 demux_t *p_demux = p_data;
2395 demux_sys_t *p_sys = p_demux->p_sys;
2397 if (val.i_int == INPUT_EVENT_VOUT) {
2399 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2400 if( p_sys->p_vout != NULL ) {
2401 blurayReleaseVout(p_demux);
2403 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2405 blurayHandleOverlays(p_demux, 1);
2408 return VLC_SUCCESS;
2411 #define BD_TS_PACKET_SIZE (192)
2412 #define NB_TS_PACKETS (200)
2414 static int blurayDemux(demux_t *p_demux)
2416 demux_sys_t *p_sys = p_demux->p_sys;
2417 BD_EVENT e;
2419 block_t *p_block = block_Alloc(NB_TS_PACKETS * (int64_t)BD_TS_PACKET_SIZE);
2420 if (!p_block)
2421 return VLC_DEMUXER_EGENERIC;
2423 int nread;
2425 if (p_sys->b_menu == false) {
2426 while (bd_get_event(p_sys->bluray, &e))
2427 blurayHandleEvent(p_demux, &e);
2429 nread = bd_read(p_sys->bluray, p_block->p_buffer,
2430 NB_TS_PACKETS * BD_TS_PACKET_SIZE);
2431 } else {
2432 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer,
2433 NB_TS_PACKETS * BD_TS_PACKET_SIZE, &e);
2434 while (e.event != BD_EVENT_NONE) {
2435 blurayHandleEvent(p_demux, &e);
2436 bd_get_event(p_sys->bluray, &e);
2440 blurayHandleOverlays(p_demux, nread);
2442 if (nread <= 0) {
2443 block_Release(p_block);
2444 if (p_sys->b_fatal_error || nread < 0) {
2445 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
2446 return VLC_DEMUXER_EGENERIC;
2448 if (!p_sys->b_menu) {
2449 return VLC_DEMUXER_EOF;
2451 return VLC_DEMUXER_SUCCESS;
2454 p_block->i_buffer = nread;
2456 stopBackground(p_demux);
2458 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2460 p_sys->b_flushed = false;
2462 return VLC_DEMUXER_SUCCESS;