demux: mkv: handle WAVE_FORMAT_MPEG_ADTS_AAC
[vlc.git] / modules / access / bluray.c
blobbdd3ffac80be109faedf159ce5eb1c436af99cd4
1 /*****************************************************************************
2 * bluray.c: Blu-ray disc support plugin
3 *****************************************************************************
4 * Copyright © 2010-2012 VideoLAN, VLC authors and libbluray AUTHORS
6 * Authors: Jean-Baptiste Kempf <jb@videolan.org>
7 * Hugo Beauzée-Luyssen <hugo@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <assert.h>
30 #if defined (HAVE_MNTENT_H) && defined(HAVE_SYS_STAT_H)
31 # include <mntent.h>
32 #endif
33 #include <fcntl.h> /* O_* */
34 #include <unistd.h> /* close() */
35 #include <sys/stat.h>
37 #ifdef __APPLE__
38 # include <sys/param.h>
39 # include <sys/ucred.h>
40 # include <sys/mount.h>
41 #endif
43 #include <vlc_common.h>
44 #include <vlc_plugin.h>
45 #include <vlc_demux.h> /* demux_t */
46 #include <vlc_input.h> /* Seekpoints, chapters */
47 #include <vlc_atomic.h>
48 #include <vlc_dialog.h> /* BD+/AACS warnings */
49 #include <vlc_vout.h> /* vout_PutSubpicture / subpicture_t */
50 #include <vlc_url.h> /* vlc_path2uri */
51 #include <vlc_iso_lang.h>
52 #include <vlc_fs.h>
54 /* FIXME we should find a better way than including that */
55 #include "../../src/text/iso-639_def.h"
58 #include <libbluray/bluray.h>
59 #include <libbluray/bluray-version.h>
60 #include <libbluray/keys.h>
61 #include <libbluray/meta_data.h>
62 #include <libbluray/overlay.h>
64 /*****************************************************************************
65 * Module descriptor
66 *****************************************************************************/
68 #define BD_MENU_TEXT N_("Blu-ray menus")
69 #define BD_MENU_LONGTEXT N_("Use Blu-ray menus. If disabled, "\
70 "the movie will start directly")
71 #define BD_REGION_TEXT N_("Region code")
72 #define BD_REGION_LONGTEXT N_("Blu-Ray player region code. "\
73 "Some discs can be played only with a correct region code.")
75 static const char *const ppsz_region_code[] = {
76 "A", "B", "C" };
77 static const char *const ppsz_region_code_text[] = {
78 "Region A", "Region B", "Region C" };
80 #define REGION_DEFAULT 1 /* Index to region list. Actual region code is (1<<REGION_DEFAULT) */
81 #define LANGUAGE_DEFAULT ("eng")
83 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,0)
84 # define BLURAY_DEMUX
85 #endif
87 /* Callbacks */
88 static int blurayOpen (vlc_object_t *);
89 static void blurayClose(vlc_object_t *);
91 vlc_module_begin ()
92 set_shortname(N_("Blu-ray"))
93 set_description(N_("Blu-ray Disc support (libbluray)"))
95 set_category(CAT_INPUT)
96 set_subcategory(SUBCAT_INPUT_ACCESS)
97 set_capability("access_demux", 200)
98 add_bool("bluray-menu", true, BD_MENU_TEXT, BD_MENU_LONGTEXT, false)
99 add_string("bluray-region", ppsz_region_code[REGION_DEFAULT], BD_REGION_TEXT, BD_REGION_LONGTEXT, false)
100 change_string_list(ppsz_region_code, ppsz_region_code_text)
102 add_shortcut("bluray", "file")
104 set_callbacks(blurayOpen, blurayClose)
106 #ifdef BLURAY_DEMUX
107 /* demux module */
108 add_submodule()
109 set_description( "BluRay demuxer" )
110 set_category( CAT_INPUT )
111 set_subcategory( SUBCAT_INPUT_DEMUX )
112 set_capability( "demux", 5 )
113 set_callbacks( blurayOpen, blurayClose )
114 #endif
116 vlc_module_end ()
118 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
119 #define MAX_OVERLAY 2
121 typedef enum OverlayStatus {
122 Closed = 0,
123 ToDisplay, //Used to mark the overlay to be displayed the first time.
124 Displayed,
125 Outdated //used to update the overlay after it has been sent to the vout
126 } OverlayStatus;
128 typedef struct bluray_overlay_t
130 vlc_mutex_t lock;
131 int i_channel;
132 OverlayStatus status;
133 subpicture_region_t *p_regions;
134 int width, height;
136 /* pointer to last subpicture updater.
137 * used to disconnect this overlay from vout when:
138 * - the overlay is closed
139 * - vout is changed and this overlay is sent to the new vout
141 struct subpicture_updater_sys_t *p_updater;
142 } bluray_overlay_t;
144 struct demux_sys_t
146 BLURAY *bluray;
148 /* Titles */
149 unsigned int i_title;
150 unsigned int i_longest_title;
151 input_title_t **pp_title;
153 vlc_mutex_t pl_info_lock;
154 BLURAY_TITLE_INFO *p_pl_info;
155 const BLURAY_CLIP_INFO *p_clip_info;
157 /* Attachments */
158 int i_attachments;
159 input_attachment_t **attachments;
160 int i_cover_idx;
162 /* Meta information */
163 const META_DL *p_meta;
165 /* Menus */
166 bluray_overlay_t *p_overlays[MAX_OVERLAY];
167 bool b_fatal_error;
168 bool b_menu;
169 bool b_menu_open;
170 bool b_popup_available;
171 mtime_t i_still_end_time;
173 vlc_mutex_t bdj_overlay_lock; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
175 /* */
176 vout_thread_t *p_vout;
178 es_out_id_t *p_dummy_video;
180 /* TS stream */
181 es_out_t *p_out;
182 vlc_array_t es;
183 int i_audio_stream_idx; /* Selected audio stream. -1 if default */
184 int i_spu_stream_idx; /* Selected subtitle stream. -1 if default */
185 bool b_spu_enable; /* enabled / disabled */
186 int i_video_stream;
187 vlc_demux_chained_t *p_parser;
188 bool b_flushed;
189 bool b_pl_playing; /* true when playing playlist */
191 /* stream input */
192 vlc_mutex_t read_block_lock;
194 /* Used to store bluray disc path */
195 char *psz_bd_path;
198 struct subpicture_updater_sys_t
200 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
201 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
202 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
206 * cut the connection between vout and overlay.
207 * - called when vout is closed or overlay is closed.
208 * - frees subpicture_updater_sys_t when both sides have been closed.
210 static void unref_subpicture_updater(subpicture_updater_sys_t *p_sys)
212 vlc_mutex_lock(&p_sys->lock);
213 int refs = --p_sys->ref_cnt;
214 p_sys->p_overlay = NULL;
215 vlc_mutex_unlock(&p_sys->lock);
217 if (refs < 1) {
218 vlc_mutex_destroy(&p_sys->lock);
219 free(p_sys);
223 /* Get a 3 char code
224 * FIXME: partiallyy duplicated from src/input/es_out.c
226 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
228 const iso639_lang_t *pl;
229 char *psz_lang;
230 char *p;
232 psz_lang = var_CreateGetString( p_demux, psz_var );
233 if( !psz_lang )
234 return LANGUAGE_DEFAULT;
236 /* XXX: we will use only the first value
237 * (and ignore other ones in case of a list) */
238 if( ( p = strchr( psz_lang, ',' ) ) )
239 *p = '\0';
241 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
243 if( *psz_lang == '\0' )
244 continue;
245 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
246 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
247 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
248 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
249 break;
252 free( psz_lang );
254 if( pl->psz_eng_name != NULL )
255 return pl->psz_iso639_2T;
257 return LANGUAGE_DEFAULT;
260 /*****************************************************************************
261 * Local prototypes
262 *****************************************************************************/
263 static es_out_t *esOutNew(demux_t *p_demux);
265 static int blurayControl(demux_t *, int, va_list);
266 static int blurayDemux(demux_t *);
268 static void blurayInitTitles(demux_t *p_demux, int menu_titles);
269 static int bluraySetTitle(demux_t *p_demux, int i_title);
271 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
272 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
274 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var,
275 vlc_value_t old, vlc_value_t val, void *p_data);
276 static int onIntfEvent(vlc_object_t *, char const *,
277 vlc_value_t, vlc_value_t, void *);
279 static void blurayResetParser(demux_t *p_demux);
280 static void notifyDiscontinuity( demux_sys_t *p_sys );
282 #define FROM_TICKS(a) ((a)*CLOCK_FREQ / INT64_C(90000))
283 #define TO_TICKS(a) ((a)*INT64_C(90000)/CLOCK_FREQ)
284 #define CUR_LENGTH p_sys->pp_title[p_demux->info.i_title]->i_length
286 /* */
287 static void FindMountPoint(char **file)
289 char *device = *file;
290 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
291 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
292 * we look up the real device */
293 char *bd_device = realpath(device, NULL);
294 if (bd_device == NULL)
295 return;
297 struct stat st;
298 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
299 FILE *mtab = setmntent ("/proc/self/mounts", "r");
300 struct mntent *m, mbuf;
301 char buf [8192];
303 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
304 if (!strcmp (m->mnt_fsname, bd_device)) {
305 free(device);
306 *file = strdup(m->mnt_dir);
307 break;
310 endmntent (mtab);
312 free(bd_device);
314 #elif defined(__APPLE__)
315 struct stat st;
316 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
317 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
318 if (fs_count > 0) {
319 struct statfs mbuf[128];
320 getfsstat (mbuf, fs_count * sizeof(mbuf[0]), MNT_NOWAIT);
321 for (int i = 0; i < fs_count; ++i)
322 if (!strcmp (mbuf[i].f_mntfromname, device)) {
323 free(device);
324 *file = strdup(mbuf[i].f_mntonname);
325 return;
329 #else
330 # warning Disc device to mount point not implemented
331 VLC_UNUSED( device );
332 #endif
335 static void blurayReleaseVout(demux_t *p_demux)
337 demux_sys_t *p_sys = p_demux->p_sys;
339 if (p_sys->p_vout != NULL) {
340 var_DelCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
341 var_DelCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
343 for (int i = 0; i < MAX_OVERLAY; i++) {
344 bluray_overlay_t *p_ov = p_sys->p_overlays[i];
345 if (p_ov) {
346 vlc_mutex_lock(&p_ov->lock);
347 if (p_ov->i_channel != -1) {
348 msg_Err(p_demux, "blurayReleaseVout: subpicture channel exists\n");
349 vout_FlushSubpictureChannel(p_sys->p_vout, p_ov->i_channel);
351 p_ov->i_channel = -1;
352 p_ov->status = ToDisplay;
353 vlc_mutex_unlock(&p_ov->lock);
355 if (p_ov->p_updater) {
356 unref_subpicture_updater(p_ov->p_updater);
357 p_ov->p_updater = NULL;
362 vlc_object_release(p_sys->p_vout);
363 p_sys->p_vout = NULL;
367 /*****************************************************************************
368 * BD-J background video
369 *****************************************************************************/
371 static void startBackground(demux_t *p_demux)
373 demux_sys_t *p_sys = p_demux->p_sys;
375 if (p_sys->p_dummy_video) {
376 return;
379 msg_Info(p_demux, "Start background");
381 /* */
382 es_format_t fmt;
383 es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_I420 );
384 video_format_Setup( &fmt.video, VLC_CODEC_I420,
385 1920, 1080, 1920, 1080, 1, 1);
386 fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
387 fmt.i_id = 4115; /* 4113 = main video. 4114 = MVC. 4115 = unused. */
388 fmt.i_group = 1;
390 p_sys->p_dummy_video = es_out_Add(p_demux->out, &fmt);
392 if (!p_sys->p_dummy_video) {
393 msg_Err(p_demux, "Error adding background ES");
394 goto out;
397 block_t *p_block = block_Alloc(fmt.video.i_width * fmt.video.i_height *
398 fmt.video.i_bits_per_pixel / 8);
399 if (!p_block) {
400 msg_Err(p_demux, "Error allocating block for background video");
401 goto out;
404 // XXX TODO: what would be correct timestamp ???
405 p_block->i_dts = p_block->i_pts = mdate() + CLOCK_FREQ/25;
407 uint8_t *p = p_block->p_buffer;
408 memset(p, 0, fmt.video.i_width * fmt.video.i_height);
409 p += fmt.video.i_width * fmt.video.i_height;
410 memset(p, 0x80, fmt.video.i_width * fmt.video.i_height / 2);
412 es_out_Send(p_demux->out, p_sys->p_dummy_video, p_block);
414 out:
415 es_format_Clean(&fmt);
418 static void stopBackground(demux_t *p_demux)
420 demux_sys_t *p_sys = p_demux->p_sys;
422 if (!p_sys->p_dummy_video) {
423 return;
426 msg_Info(p_demux, "Stop background");
428 es_out_Del(p_demux->out, p_sys->p_dummy_video);
429 p_sys->p_dummy_video = NULL;
432 /*****************************************************************************
433 * cache current playlist (title) information
434 *****************************************************************************/
436 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
438 vlc_mutex_lock(&p_sys->pl_info_lock);
440 if (p_sys->p_pl_info) {
441 bd_free_title_info(p_sys->p_pl_info);
443 p_sys->p_pl_info = info;
444 p_sys->p_clip_info = NULL;
446 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
447 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
450 vlc_mutex_unlock(&p_sys->pl_info_lock);
453 /*****************************************************************************
454 * create input attachment for thumbnail
455 *****************************************************************************/
457 static void attachThumbnail(demux_t *p_demux)
459 demux_sys_t *p_sys = p_demux->p_sys;
461 if (!p_sys->p_meta)
462 return;
464 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
465 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
466 int64_t size;
467 void *data;
468 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
469 char psz_name[64];
470 input_attachment_t *p_attachment;
472 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
474 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
475 if (p_attachment) {
476 p_sys->i_cover_idx = p_sys->i_attachments;
477 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
480 free(data);
482 #endif
485 /*****************************************************************************
486 * stream input
487 *****************************************************************************/
489 static int probeStream(demux_t *p_demux)
491 /* input must be seekable */
492 bool b_canseek = false;
493 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
494 if (!b_canseek) {
495 return VLC_EGENERIC;
498 /* first sector(s) should be filled with zeros */
499 size_t i_peek;
500 const uint8_t *p_peek;
501 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
502 if( i_peek != 2048 ) {
503 return VLC_EGENERIC;
505 while (i_peek > 0) {
506 if (p_peek[ --i_peek ]) {
507 return VLC_EGENERIC;
511 return VLC_SUCCESS;
514 #ifdef BLURAY_DEMUX
515 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
517 demux_t *p_demux = (demux_t*)object;
518 demux_sys_t *p_sys = p_demux->p_sys;
519 int result = -1;
521 assert(p_demux->s != NULL);
523 vlc_mutex_lock(&p_sys->read_block_lock);
525 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
526 size_t req = (size_t)2048 * num_blocks;
527 ssize_t got;
529 got = vlc_stream_Read( p_demux->s, buf, req);
530 if (got < 0) {
531 msg_Err(p_demux, "read from lba %d failed", lba);
532 } else {
533 result = got / 2048;
535 } else {
536 msg_Err(p_demux, "seek to lba %d failed", lba);
539 vlc_mutex_unlock(&p_sys->read_block_lock);
541 return result;
543 #endif
545 /*****************************************************************************
546 * probing of local files
547 *****************************************************************************/
549 /* Descriptor Tag (ECMA 167, 3/7.2) */
550 static int decode_descriptor_tag(const uint8_t *buf)
552 uint16_t id;
553 uint8_t checksum = 0;
554 int i;
556 id = buf[0] | (buf[1] << 8);
558 /* calculate tag checksum */
559 for (i = 0; i < 4; i++) {
560 checksum = (uint8_t)(checksum + buf[i]);
562 for (i = 5; i < 16; i++) {
563 checksum = (uint8_t)(checksum + buf[i]);
566 if (checksum != buf[4]) {
567 return -1;
570 return id;
573 static int probeFile(const char *psz_name)
575 struct stat stat_info;
576 uint8_t peek[2048];
577 unsigned i;
578 int ret = VLC_EGENERIC;
579 int fd;
581 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
582 if (fd == -1) {
583 return VLC_EGENERIC;
586 if (fstat(fd, &stat_info) == -1) {
587 goto bailout;
589 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
590 goto bailout;
593 /* first sector should be filled with zeros */
594 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
595 goto bailout;
597 for (i = 0; i < sizeof(peek); i++) {
598 if (peek[ i ]) {
599 goto bailout;
603 /* Check AVDP tag checksum */
604 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
605 read(fd, peek, 16) != 16 ||
606 decode_descriptor_tag(peek) != 2) {
607 goto bailout;
610 ret = VLC_SUCCESS;
612 bailout:
613 vlc_close(fd);
614 return ret;
617 /*****************************************************************************
618 * blurayOpen: module init function
619 *****************************************************************************/
620 static int blurayOpen(vlc_object_t *object)
622 demux_t *p_demux = (demux_t*)object;
623 demux_sys_t *p_sys;
624 bool forced;
625 uint64_t i_init_pos = 0;
627 const char *error_msg = NULL;
628 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
630 if (unlikely(!p_demux->p_input))
631 return VLC_EGENERIC;
633 forced = !strcasecmp(p_demux->psz_access, "bluray");
635 if (p_demux->s) {
636 if (!strcasecmp(p_demux->psz_access, "file")) {
637 /* use access_demux for local files */
638 return VLC_EGENERIC;
641 if (probeStream(p_demux) != VLC_SUCCESS) {
642 return VLC_EGENERIC;
645 } else if (!forced) {
646 if (!p_demux->psz_file) {
647 return VLC_EGENERIC;
650 if (probeFile(p_demux->psz_file) != VLC_SUCCESS) {
651 return VLC_EGENERIC;
655 /* */
656 p_demux->p_sys = p_sys = vlc_calloc(object, 1, sizeof(*p_sys));
657 if (unlikely(!p_sys))
658 return VLC_ENOMEM;
660 p_sys->i_audio_stream_idx = -1;
661 p_sys->i_spu_stream_idx = -1;
662 p_sys->i_video_stream = -1;
663 p_sys->i_still_end_time = 0;
665 /* init demux info fields */
666 p_demux->info.i_update = 0;
667 p_demux->info.i_title = 0;
668 p_demux->info.i_seekpoint = 0;
670 TAB_INIT(p_sys->i_title, p_sys->pp_title);
671 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
673 vlc_mutex_init(&p_sys->pl_info_lock);
674 vlc_mutex_init(&p_sys->bdj_overlay_lock);
675 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
677 var_AddCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
679 /* Open BluRay */
680 #ifdef BLURAY_DEMUX
681 if (p_demux->s) {
682 i_init_pos = vlc_stream_Tell(p_demux->s);
684 p_sys->bluray = bd_init();
685 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
686 bd_close(p_sys->bluray);
687 p_sys->bluray = NULL;
689 } else
690 #endif
692 if (!p_demux->psz_file) {
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_file);
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 needs Java for menus.%s\nDisc is played without menus."),
794 !disc_info->libjvm_detected ? _(" Java was not found from 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_Init(&fmt, p_fmt->i_cat, p_fmt->i_codec);
997 es_format_Copy(&fmt, p_fmt);
999 switch (fmt.i_cat) {
1000 case VIDEO_ES:
1001 if (p_sys->i_video_stream != -1 && p_sys->i_video_stream != p_fmt->i_id)
1002 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1003 break ;
1004 case AUDIO_ES:
1005 if (p_sys->i_audio_stream_idx != -1) {
1006 if (blurayEsPid(p_sys, AUDIO_ES, p_sys->i_audio_stream_idx) == p_fmt->i_id)
1007 b_select = true;
1008 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1010 setStreamLang(p_sys, &fmt);
1011 break ;
1012 case SPU_ES:
1013 if (p_sys->i_spu_stream_idx != -1) {
1014 if (blurayEsPid(p_sys, SPU_ES, p_sys->i_spu_stream_idx) == p_fmt->i_id)
1015 b_select = true;
1016 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1018 setStreamLang(p_sys, &fmt);
1019 break ;
1022 es_out_id_t *p_es = es_out_Add(p_demux->out, &fmt);
1023 if (p_fmt->i_id >= 0) {
1024 /* Ensure we are not overriding anything */
1025 int idx = findEsPairIndex(p_sys, p_fmt->i_id);
1026 if (idx == -1) {
1027 fmt_es_pair_t *p_pair = malloc(sizeof(*p_pair));
1028 if (likely(p_pair != NULL)) {
1029 p_pair->i_id = p_fmt->i_id;
1030 p_pair->p_es = p_es;
1031 msg_Info(p_demux, "Adding ES %d", p_fmt->i_id);
1032 vlc_array_append(&p_sys->es, p_pair);
1034 if (b_select) {
1035 if (fmt.i_cat == AUDIO_ES) {
1036 var_SetInteger( p_demux->p_input, "audio-es", p_fmt->i_id );
1037 } else if (fmt.i_cat == SPU_ES) {
1038 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? p_fmt->i_id : -1 );
1044 es_format_Clean(&fmt);
1045 return p_es;
1048 static int esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1050 return es_out_Send(p_out->p_sys->p_demux->out, p_es, p_block);
1053 static void esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1055 int idx = findEsPairIndexByEs(p_out->p_sys->p_demux->p_sys, p_es);
1056 if (idx >= 0) {
1057 free(vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, idx));
1058 vlc_array_remove(&p_out->p_sys->p_demux->p_sys->es, idx);
1060 es_out_Del(p_out->p_sys->p_demux->out, p_es);
1063 static int esOutControl(es_out_t *p_out, int i_query, va_list args)
1065 return es_out_vaControl(p_out->p_sys->p_demux->out, i_query, args);
1068 static void esOutDestroy(es_out_t *p_out)
1070 for (size_t i = 0; i < vlc_array_count(&p_out->p_sys->p_demux->p_sys->es); ++i)
1071 free(vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, i));
1072 vlc_array_clear(&p_out->p_sys->p_demux->p_sys->es);
1073 free(p_out->p_sys);
1074 free(p_out);
1077 static es_out_t *esOutNew(demux_t *p_demux)
1079 assert(vlc_array_count(&p_demux->p_sys->es) == 0);
1080 es_out_t *p_out = malloc(sizeof(*p_out));
1081 if (unlikely(p_out == NULL))
1082 return NULL;
1084 p_out->pf_add = esOutAdd;
1085 p_out->pf_control = esOutControl;
1086 p_out->pf_del = esOutDel;
1087 p_out->pf_destroy = esOutDestroy;
1088 p_out->pf_send = esOutSend;
1090 p_out->p_sys = malloc(sizeof(*p_out->p_sys));
1091 if (unlikely(p_out->p_sys == NULL)) {
1092 free(p_out);
1093 return NULL;
1095 p_out->p_sys->p_demux = p_demux;
1096 return p_out;
1099 /*****************************************************************************
1100 * subpicture_updater_t functions:
1101 *****************************************************************************/
1103 static bluray_overlay_t *updater_lock_overlay(subpicture_updater_sys_t *p_upd_sys)
1105 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1106 vlc_mutex_lock(&p_upd_sys->lock);
1108 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1109 if (ov) {
1110 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1111 vlc_mutex_lock(&ov->lock);
1112 return ov;
1115 /* overlay has been closed */
1116 vlc_mutex_unlock(&p_upd_sys->lock);
1117 return NULL;
1120 static void updater_unlock_overlay(subpicture_updater_sys_t *p_upd_sys)
1122 assert (p_upd_sys->p_overlay);
1124 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1125 vlc_mutex_unlock(&p_upd_sys->lock);
1128 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1129 bool b_fmt_src, const video_format_t *p_fmt_src,
1130 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1131 mtime_t i_ts)
1133 VLC_UNUSED(b_fmt_src);
1134 VLC_UNUSED(b_fmt_dst);
1135 VLC_UNUSED(p_fmt_src);
1136 VLC_UNUSED(p_fmt_dst);
1137 VLC_UNUSED(i_ts);
1139 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1140 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1142 if (!p_overlay) {
1143 return 1;
1146 int res = p_overlay->status == Outdated;
1148 updater_unlock_overlay(p_upd_sys);
1150 return res;
1153 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1154 const video_format_t *p_fmt_src,
1155 const video_format_t *p_fmt_dst,
1156 mtime_t i_ts)
1158 VLC_UNUSED(p_fmt_src);
1159 VLC_UNUSED(p_fmt_dst);
1160 VLC_UNUSED(i_ts);
1161 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1162 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1164 if (!p_overlay) {
1165 return;
1169 * When this function is called, all p_subpic regions are gone.
1170 * We need to duplicate our regions (stored internaly) to this subpic.
1172 subpicture_region_t *p_src = p_overlay->p_regions;
1173 if (!p_src) {
1174 updater_unlock_overlay(p_upd_sys);
1175 return;
1178 subpicture_region_t **p_dst = &p_subpic->p_region;
1179 while (p_src != NULL) {
1180 *p_dst = subpicture_region_Copy(p_src);
1181 if (*p_dst == NULL)
1182 break;
1183 p_dst = &(*p_dst)->p_next;
1184 p_src = p_src->p_next;
1186 if (*p_dst != NULL)
1187 (*p_dst)->p_next = NULL;
1188 p_overlay->status = Displayed;
1190 updater_unlock_overlay(p_upd_sys);
1193 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1195 subpicture_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1196 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1198 if (p_overlay) {
1199 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1200 p_overlay->status = ToDisplay;
1201 p_overlay->i_channel = -1;
1202 updater_unlock_overlay(p_upd_sys);
1205 unref_subpicture_updater(p_upd_sys);
1208 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1210 subpicture_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1211 if (unlikely(p_upd_sys == NULL)) {
1212 return NULL;
1215 p_upd_sys->p_overlay = p_ov;
1217 subpicture_updater_t updater = {
1218 .pf_validate = subpictureUpdaterValidate,
1219 .pf_update = subpictureUpdaterUpdate,
1220 .pf_destroy = subpictureUpdaterDestroy,
1221 .p_sys = p_upd_sys,
1224 subpicture_t *p_pic = subpicture_New(&updater);
1225 if (p_pic == NULL) {
1226 free(p_upd_sys);
1227 return NULL;
1230 p_pic->i_original_picture_width = p_ov->width;
1231 p_pic->i_original_picture_height = p_ov->height;
1232 p_pic->b_ephemer = true;
1233 p_pic->b_absolute = true;
1235 vlc_mutex_init(&p_upd_sys->lock);
1236 p_upd_sys->ref_cnt = 2;
1238 p_ov->p_updater = p_upd_sys;
1240 return p_pic;
1243 /*****************************************************************************
1244 * User input events:
1245 *****************************************************************************/
1246 static int onMouseEvent(vlc_object_t *p_vout, const char *psz_var, vlc_value_t old,
1247 vlc_value_t val, void *p_data)
1249 demux_t *p_demux = (demux_t*)p_data;
1250 demux_sys_t *p_sys = p_demux->p_sys;
1251 VLC_UNUSED(old);
1252 VLC_UNUSED(p_vout);
1254 if (psz_var[6] == 'm') //Mouse moved
1255 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1256 else if (psz_var[6] == 'c') {
1257 bd_mouse_select(p_sys->bluray, -1, val.coords.x, val.coords.y);
1258 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1259 } else {
1260 vlc_assert_unreachable();
1262 return VLC_SUCCESS;
1265 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1267 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1268 return VLC_EGENERIC;
1270 return VLC_SUCCESS;
1273 /*****************************************************************************
1274 * libbluray overlay handling:
1275 *****************************************************************************/
1277 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1279 demux_sys_t *p_sys = p_demux->p_sys;
1280 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1282 if (ov != NULL) {
1284 /* drop overlay from vout */
1285 if (ov->p_updater) {
1286 unref_subpicture_updater(ov->p_updater);
1288 /* no references to this overlay exist in vo anymore */
1289 if (p_sys->p_vout && ov->i_channel != -1) {
1290 vout_FlushSubpictureChannel(p_sys->p_vout, ov->i_channel);
1293 vlc_mutex_destroy(&ov->lock);
1294 subpicture_region_ChainDelete(ov->p_regions);
1295 free(ov);
1297 p_sys->p_overlays[plane] = NULL;
1300 for (int i = 0; i < MAX_OVERLAY; i++)
1301 if (p_sys->p_overlays[i])
1302 return;
1304 /* All overlays have been closed */
1305 blurayReleaseVout(p_demux);
1309 * Mark the overlay as "ToDisplay" status.
1310 * This will not send the overlay to the vout instantly, as the vout
1311 * may not be acquired (not acquirable) yet.
1312 * If is has already been acquired, the overlay has already been sent to it,
1313 * therefore, we only flag the overlay as "Outdated"
1315 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1317 demux_sys_t *p_sys = p_demux->p_sys;
1318 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1321 * If the overlay is already displayed, mark the picture as outdated.
1322 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1324 vlc_mutex_lock(&ov->lock);
1325 if (ov->status >= Displayed && p_sys->p_vout) {
1326 ov->status = Outdated;
1327 vlc_mutex_unlock(&ov->lock);
1328 return;
1332 * Mark the overlay as available, but don't display it right now.
1333 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1334 * the overlay is computed
1336 ov->status = ToDisplay;
1337 vlc_mutex_unlock(&ov->lock);
1340 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1342 demux_sys_t *p_sys = p_demux->p_sys;
1344 assert(p_sys->p_overlays[plane] == NULL);
1346 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1347 if (unlikely(ov == NULL))
1348 return;
1350 ov->width = width;
1351 ov->height = height;
1352 ov->i_channel = -1;
1354 vlc_mutex_init(&ov->lock);
1356 p_sys->p_overlays[plane] = ov;
1360 * Destroy every regions in the subpicture.
1361 * This is done in two steps:
1362 * - Wiping our private regions list
1363 * - Flagging the overlay as outdated, so the changes are replicated from
1364 * the subpicture_updater_t::pf_update
1365 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1367 static void blurayClearOverlay(demux_t *p_demux, int plane)
1369 demux_sys_t *p_sys = p_demux->p_sys;
1370 bluray_overlay_t *ov = p_sys->p_overlays[plane];
1372 vlc_mutex_lock(&ov->lock);
1374 subpicture_region_ChainDelete(ov->p_regions);
1375 ov->p_regions = NULL;
1376 ov->status = Outdated;
1378 vlc_mutex_unlock(&ov->lock);
1382 * This will draw to the overlay by adding a region to our region list
1383 * This will have to be copied to the subpicture used to render the overlay.
1385 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1387 demux_sys_t *p_sys = p_demux->p_sys;
1390 * Compute a subpicture_region_t.
1391 * It will be copied and sent to the vout later.
1393 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1395 /* Find a region to update */
1396 subpicture_region_t **pp_reg = &p_sys->p_overlays[ov->plane]->p_regions;
1397 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1398 subpicture_region_t *p_last = NULL;
1399 while (p_reg != NULL) {
1400 p_last = p_reg;
1401 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1402 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1403 break;
1404 pp_reg = &p_reg->p_next;
1405 p_reg = p_reg->p_next;
1408 if (!ov->img) {
1409 if (p_reg) {
1410 /* drop region */
1411 *pp_reg = p_reg->p_next;
1412 subpicture_region_Delete(p_reg);
1414 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1415 return;
1418 /* If there is no region to update, create a new one. */
1419 if (!p_reg) {
1420 video_format_t fmt;
1421 video_format_Init(&fmt, 0);
1422 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1424 p_reg = subpicture_region_New(&fmt);
1425 p_reg->i_x = ov->x;
1426 p_reg->i_y = ov->y;
1427 /* Append it to our list. */
1428 if (p_last != NULL)
1429 p_last->p_next = p_reg;
1430 else /* If we don't have a last region, then our list empty */
1431 p_sys->p_overlays[ov->plane]->p_regions = p_reg;
1434 /* Now we can update the region, regardless it's an update or an insert */
1435 const BD_PG_RLE_ELEM *img = ov->img;
1436 for (int y = 0; y < ov->h; y++)
1437 for (int x = 0; x < ov->w;) {
1438 plane_t *p = &p_reg->p_picture->p[0];
1439 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1440 x += img->len;
1441 img++;
1444 if (ov->palette) {
1445 p_reg->fmt.p_palette->i_entries = 256;
1446 for (int i = 0; i < 256; ++i) {
1447 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1448 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1449 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1450 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1454 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1456 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1460 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1462 demux_t *p_demux = (demux_t*)ptr;
1463 demux_sys_t *p_sys = p_demux->p_sys;
1465 if (!overlay) {
1466 msg_Info(p_demux, "Closing overlays.");
1467 if (p_sys->p_vout)
1468 for (int i = 0; i < MAX_OVERLAY; i++)
1469 blurayCloseOverlay(p_demux, i);
1470 return;
1473 switch (overlay->cmd) {
1474 case BD_OVERLAY_INIT:
1475 msg_Info(p_demux, "Initializing overlay");
1476 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1477 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1478 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1479 break;
1480 case BD_OVERLAY_CLOSE:
1481 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1482 blurayClearOverlay(p_demux, overlay->plane);
1483 blurayCloseOverlay(p_demux, overlay->plane);
1484 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1485 break;
1486 case BD_OVERLAY_CLEAR:
1487 blurayClearOverlay(p_demux, overlay->plane);
1488 break;
1489 case BD_OVERLAY_FLUSH:
1490 blurayActivateOverlay(p_demux, overlay->plane);
1491 break;
1492 case BD_OVERLAY_DRAW:
1493 case BD_OVERLAY_WIPE:
1494 blurayDrawOverlay(p_demux, overlay);
1495 break;
1496 default:
1497 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
1498 break;
1503 * ARGB overlay (BD-J)
1505 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
1507 demux_sys_t *p_sys = p_demux->p_sys;
1509 blurayInitOverlay(p_demux, plane, width, height);
1511 if (!p_sys->p_overlays[plane]->p_regions) {
1512 video_format_t fmt;
1513 video_format_Init(&fmt, 0);
1514 video_format_Setup(&fmt, VLC_CODEC_RGBA, width, height, width, height, 1, 1);
1516 p_sys->p_overlays[plane]->p_regions = subpicture_region_New(&fmt);
1520 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
1522 demux_sys_t *p_sys = p_demux->p_sys;
1524 vlc_mutex_lock(&p_sys->p_overlays[ov->plane]->lock);
1526 /* Find a region to update */
1527 subpicture_region_t *p_reg = p_sys->p_overlays[ov->plane]->p_regions;
1528 if (!p_reg) {
1529 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1530 return;
1533 /* Now we can update the region */
1534 const uint32_t *src0 = ov->argb;
1535 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
1536 p_reg->p_picture->p[0].i_pitch * ov->y +
1537 ov->x * 4;
1539 for (int y = 0; y < ov->h; y++) {
1540 // XXX: add support for this format ? Should be possible with OPENGL/VDPAU/...
1541 // - or add libbluray option to select the format ?
1542 for (int x = 0; x < ov->w; x++) {
1543 dst0[x*4 ] = src0[x]>>16; /* R */
1544 dst0[x*4+1] = src0[x]>>8; /* G */
1545 dst0[x*4+2] = src0[x]; /* B */
1546 dst0[x*4+3] = src0[x]>>24; /* A */
1549 src0 += ov->stride;
1550 dst0 += p_reg->p_picture->p[0].i_pitch;
1553 vlc_mutex_unlock(&p_sys->p_overlays[ov->plane]->lock);
1555 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1559 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
1561 demux_t *p_demux = (demux_t*)ptr;
1562 demux_sys_t *p_sys = p_demux->p_sys;
1564 switch (overlay->cmd) {
1565 case BD_ARGB_OVERLAY_INIT:
1566 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1567 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1568 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1569 break;
1570 case BD_ARGB_OVERLAY_CLOSE:
1571 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
1572 blurayClearOverlay(p_demux, overlay->plane);
1573 blurayCloseOverlay(p_demux, overlay->plane);
1574 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
1575 break;
1576 case BD_ARGB_OVERLAY_FLUSH:
1577 blurayActivateOverlay(p_demux, overlay->plane);
1578 break;
1579 case BD_ARGB_OVERLAY_DRAW:
1580 blurayDrawArgbOverlay(p_demux, overlay);
1581 break;
1582 default:
1583 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
1584 break;
1588 static void bluraySendOverlayToVout(demux_t *p_demux, bluray_overlay_t *p_ov)
1590 demux_sys_t *p_sys = p_demux->p_sys;
1592 assert(p_ov != NULL);
1593 assert(p_ov->i_channel == -1);
1595 if (p_ov->p_updater) {
1596 unref_subpicture_updater(p_ov->p_updater);
1597 p_ov->p_updater = NULL;
1600 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
1601 if (!p_pic) {
1602 msg_Err(p_demux, "bluraySubpictureCreate() failed");
1603 return;
1606 p_pic->i_start = p_pic->i_stop = mdate();
1607 p_pic->i_channel = vout_RegisterSubpictureChannel(p_sys->p_vout);
1608 p_ov->i_channel = p_pic->i_channel;
1611 * After this point, the picture should not be accessed from the demux thread,
1612 * as it is held by the vout thread.
1613 * This must be done only once per subpicture, ie. only once between each
1614 * blurayInitOverlay & blurayCloseOverlay call.
1616 vout_PutSubpicture(p_sys->p_vout, p_pic);
1619 * Mark the picture as Outdated, as it contains no region for now.
1620 * This will make the subpicture_updater_t call pf_update
1622 p_ov->status = Outdated;
1625 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
1627 t->i_length = FROM_TICKS(title_info->duration);
1629 for (int i = 0; i < t->i_seekpoint; i++)
1630 vlc_seekpoint_Delete( t->seekpoint[i] );
1631 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
1633 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
1634 seekpoint_t *s = vlc_seekpoint_New();
1635 if (!s) {
1636 break;
1638 s->i_time_offset = FROM_TICKS(title_info->chapters[j].start);
1640 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
1644 static void blurayInitTitles(demux_t *p_demux, int menu_titles)
1646 demux_sys_t *p_sys = p_demux->p_sys;
1647 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
1649 /* get and set the titles */
1650 unsigned i_title = menu_titles;
1652 if (!p_sys->b_menu) {
1653 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
1654 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
1657 for (unsigned int i = 0; i < i_title; i++) {
1658 input_title_t *t = vlc_input_title_New();
1659 if (!t)
1660 break;
1662 if (!p_sys->b_menu) {
1663 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
1664 blurayUpdateTitleInfo(t, title_info);
1665 bd_free_title_info(title_info);
1667 } else if (i == 0) {
1668 t->psz_name = strdup(_("Top Menu"));
1669 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
1670 } else if (i == i_title - 1) {
1671 t->psz_name = strdup(_("First Play"));
1672 if (di && di->first_play && di->first_play->interactive) {
1673 t->i_flags = INPUT_TITLE_INTERACTIVE;
1675 } else {
1676 /* add possible title name from disc metadata */
1677 if (di && di->titles && i <= di->num_titles) {
1678 if (di->titles[i]->name) {
1679 t->psz_name = strdup(di->titles[i]->name);
1681 if (di->titles[i]->interactive) {
1682 t->i_flags = INPUT_TITLE_INTERACTIVE;
1687 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
1691 static void blurayResetParser(demux_t *p_demux)
1694 * This is a hack and will have to be removed.
1695 * The parser should be flushed, and not destroy/created each time
1696 * we are changing title.
1698 demux_sys_t *p_sys = p_demux->p_sys;
1699 if (p_sys->p_parser)
1700 vlc_demux_chained_Delete(p_sys->p_parser);
1702 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
1704 if (!p_sys->p_parser)
1705 msg_Err(p_demux, "Failed to create TS demuxer");
1708 /*****************************************************************************
1709 * bluraySetTitle: select new BD title
1710 *****************************************************************************/
1711 static int bluraySetTitle(demux_t *p_demux, int i_title)
1713 demux_sys_t *p_sys = p_demux->p_sys;
1715 if (p_sys->b_menu) {
1716 int result;
1717 if (i_title <= 0) {
1718 msg_Dbg(p_demux, "Playing TopMenu Title");
1719 result = bd_menu_call(p_sys->bluray, -1);
1720 } else if (i_title >= (int)p_sys->i_title - 1) {
1721 msg_Dbg(p_demux, "Playing FirstPlay Title");
1722 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
1723 } else {
1724 msg_Dbg(p_demux, "Playing Title %i", i_title);
1725 result = bd_play_title(p_sys->bluray, i_title);
1728 if (result == 0) {
1729 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
1730 return VLC_EGENERIC;
1733 return VLC_SUCCESS;
1736 /* Looking for the main title, ie the longest duration */
1737 if (i_title < 0)
1738 i_title = p_sys->i_longest_title;
1739 else if ((unsigned)i_title > p_sys->i_title)
1740 return VLC_EGENERIC;
1742 msg_Dbg(p_demux, "Selecting Title %i", i_title);
1744 if (bd_select_title(p_sys->bluray, i_title) == 0) {
1745 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
1746 return VLC_EGENERIC;
1749 return VLC_SUCCESS;
1752 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
1753 # define BLURAY_AUDIO_STREAM 0
1754 #endif
1756 static void blurayStreamSelected(demux_sys_t *p_sys, int i_pid)
1758 vlc_mutex_lock(&p_sys->pl_info_lock);
1760 if (p_sys->p_clip_info) {
1761 if ((i_pid & 0xff00) == 0x1100) {
1762 // audio
1763 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
1764 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
1765 p_sys->i_audio_stream_idx = i_id;
1766 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
1767 break;
1770 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
1771 // subtitle
1772 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
1773 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
1774 p_sys->i_spu_stream_idx = i_id;
1775 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
1776 break;
1782 vlc_mutex_unlock(&p_sys->pl_info_lock);
1785 /*****************************************************************************
1786 * blurayControl: handle the controls
1787 *****************************************************************************/
1788 static int blurayControl(demux_t *p_demux, int query, va_list args)
1790 demux_sys_t *p_sys = p_demux->p_sys;
1791 bool *pb_bool;
1792 int64_t *pi_64;
1794 switch (query) {
1795 case DEMUX_CAN_SEEK:
1796 case DEMUX_CAN_PAUSE:
1797 case DEMUX_CAN_CONTROL_PACE:
1798 pb_bool = va_arg(args, bool *);
1799 *pb_bool = true;
1800 break;
1802 case DEMUX_GET_PTS_DELAY:
1803 pi_64 = va_arg(args, int64_t *);
1804 *pi_64 = INT64_C(1000) * var_InheritInteger(p_demux, "disc-caching");
1805 break;
1807 case DEMUX_SET_PAUSE_STATE:
1809 #ifdef BLURAY_RATE_NORMAL
1810 bool b_paused = (bool)va_arg(args, int);
1811 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
1812 return VLC_EGENERIC;
1814 #endif
1815 break;
1817 case DEMUX_SET_ES:
1819 int i_id = va_arg(args, int);
1820 blurayStreamSelected(p_sys, i_id);
1821 break;
1823 case DEMUX_SET_TITLE:
1825 int i_title = va_arg(args, int);
1826 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
1827 /* make sure GUI restores the old setting in title menu ... */
1828 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1829 return VLC_EGENERIC;
1831 blurayResetParser( p_demux );
1832 notifyDiscontinuity( p_sys );
1833 break;
1835 case DEMUX_SET_SEEKPOINT:
1837 int i_chapter = va_arg(args, int);
1838 bd_seek_chapter(p_sys->bluray, i_chapter);
1839 notifyDiscontinuity( p_sys );
1840 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
1841 break;
1844 case DEMUX_GET_TITLE_INFO:
1846 input_title_t ***ppp_title = va_arg(args, input_title_t***);
1847 int *pi_int = va_arg(args, int *);
1848 int *pi_title_offset = va_arg(args, int *);
1849 int *pi_chapter_offset = va_arg(args, int *);
1851 /* */
1852 *pi_title_offset = 0;
1853 *pi_chapter_offset = 0;
1855 /* Duplicate local title infos */
1856 *pi_int = p_sys->i_title;
1857 *ppp_title = malloc(p_sys->i_title * sizeof(input_title_t *));
1858 for (unsigned int i = 0; i < p_sys->i_title; i++)
1859 (*ppp_title)[i] = vlc_input_title_Duplicate(p_sys->pp_title[i]);
1861 return VLC_SUCCESS;
1864 case DEMUX_GET_LENGTH:
1866 int64_t *pi_length = va_arg(args, int64_t *);
1867 *pi_length = p_demux->info.i_title < (int)p_sys->i_title ? CUR_LENGTH : 0;
1868 return VLC_SUCCESS;
1870 case DEMUX_SET_TIME:
1872 int64_t i_time = va_arg(args, int64_t);
1873 bd_seek_time(p_sys->bluray, TO_TICKS(i_time));
1874 notifyDiscontinuity( p_sys );
1875 return VLC_SUCCESS;
1877 case DEMUX_GET_TIME:
1879 int64_t *pi_time = va_arg(args, int64_t *);
1880 *pi_time = (int64_t)FROM_TICKS(bd_tell_time(p_sys->bluray));
1881 return VLC_SUCCESS;
1884 case DEMUX_GET_POSITION:
1886 double *pf_position = va_arg(args, double *);
1887 *pf_position = p_demux->info.i_title < (int)p_sys->i_title && CUR_LENGTH > 0 ?
1888 (double)FROM_TICKS(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
1889 return VLC_SUCCESS;
1891 case DEMUX_SET_POSITION:
1893 double f_position = va_arg(args, double);
1894 bd_seek_time(p_sys->bluray, TO_TICKS(f_position*CUR_LENGTH));
1895 notifyDiscontinuity( p_sys );
1896 return VLC_SUCCESS;
1899 case DEMUX_GET_META:
1901 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
1902 const META_DL *meta = p_sys->p_meta;
1903 if (meta == NULL)
1904 return VLC_EGENERIC;
1906 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
1908 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
1909 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
1910 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
1912 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
1913 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
1915 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
1916 char psz_url[128];
1917 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
1918 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
1919 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
1921 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
1922 char *psz_thumbpath;
1923 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
1924 p_sys->psz_bd_path, meta->thumbnails[0].path) > -1) {
1925 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
1926 free(psz_thumbpath);
1927 if (unlikely(psz_thumburl == NULL))
1928 return VLC_ENOMEM;
1930 vlc_meta_SetArtURL(p_meta, psz_thumburl);
1931 free(psz_thumburl);
1935 return VLC_SUCCESS;
1938 case DEMUX_GET_ATTACHMENTS:
1940 input_attachment_t ***ppp_attach =
1941 va_arg(args, input_attachment_t ***);
1942 int *pi_int = va_arg(args, int *);
1944 if (p_sys->i_attachments <= 0)
1945 return VLC_EGENERIC;
1947 *pi_int = p_sys->i_attachments;
1948 *ppp_attach = xmalloc(sizeof(input_attachment_t *) * p_sys->i_attachments);
1949 for (int i = 0; i < p_sys->i_attachments; i++)
1950 (*ppp_attach)[i] = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
1951 return VLC_SUCCESS;
1954 case DEMUX_NAV_ACTIVATE:
1955 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
1956 return sendKeyEvent(p_sys, BD_VK_POPUP);
1958 return sendKeyEvent(p_sys, BD_VK_ENTER);
1959 case DEMUX_NAV_UP:
1960 return sendKeyEvent(p_sys, BD_VK_UP);
1961 case DEMUX_NAV_DOWN:
1962 return sendKeyEvent(p_sys, BD_VK_DOWN);
1963 case DEMUX_NAV_LEFT:
1964 return sendKeyEvent(p_sys, BD_VK_LEFT);
1965 case DEMUX_NAV_RIGHT:
1966 return sendKeyEvent(p_sys, BD_VK_RIGHT);
1967 case DEMUX_NAV_POPUP:
1968 return sendKeyEvent(p_sys, BD_VK_POPUP);
1969 case DEMUX_NAV_MENU:
1970 if (p_sys->b_menu) {
1971 if (bd_menu_call(p_sys->bluray, -1) == 1) {
1972 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
1973 return VLC_SUCCESS;
1975 msg_Err(p_demux, "Can't select Top Menu title");
1976 return sendKeyEvent(p_sys, BD_VK_POPUP);
1978 return VLC_EGENERIC;
1980 case DEMUX_CAN_RECORD:
1981 case DEMUX_GET_FPS:
1982 case DEMUX_SET_GROUP:
1983 case DEMUX_HAS_UNSUPPORTED_META:
1984 default:
1985 return VLC_EGENERIC;
1987 return VLC_SUCCESS;
1990 /*****************************************************************************
1991 * libbluray event handling
1992 *****************************************************************************/
1993 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
1994 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
1996 for( size_t i=0; i< i_sinfo; i++ )
1998 const uint16_t i_pid = p_sinfo[i].pid;
2000 block_t *p_block = block_Alloc(192);
2001 if (!p_block)
2002 return;
2004 uint8_t ts_header[] = {
2005 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2006 0x47,
2007 (i_pid & 0x1f00) >> 8, i_pid & 0xFF, /* PID */
2008 0x20, /* adaptation field, no payload */
2009 183, /* adaptation field length */
2010 0x80, /* adaptation field: discontinuity indicator */
2013 memcpy(p_block->p_buffer, ts_header, sizeof(ts_header));
2014 memset(&p_block->p_buffer[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header));
2015 p_block->i_buffer = 192;
2017 vlc_demux_chained_Send(p_parser, p_block);
2021 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2022 p_clip->memb##_stream_count )
2024 static void notifyDiscontinuity( demux_sys_t *p_sys )
2026 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2027 if( p_clip )
2029 DONOTIFY(audio);
2030 DONOTIFY(video);
2031 DONOTIFY(pg);
2032 DONOTIFY(ig);
2033 DONOTIFY(sec_audio);
2034 DONOTIFY(sec_video);
2038 #undef DONOTIFY
2040 static void streamFlush( demux_sys_t *p_sys )
2043 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2044 * Packet is flushed only when TS packet with PUSI flag set is received.
2046 * Fix this by emitting (video) ts packet with PUSI flag set.
2047 * Add video sequence end code to payload so that also video decoder is flushed.
2048 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2051 if (p_sys->b_flushed)
2052 return;
2054 block_t *p_block = block_Alloc(192);
2055 if (!p_block)
2056 return;
2058 static const uint8_t seq_end_pes[] = {
2059 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2060 0x00, 0x00, 0x01, 0xb7, /* PES payload: sequence end */
2062 static const uint8_t vid_pusi_ts[] = {
2063 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2064 0x47, 0x50, 0x11, 0x30, /* TP header */
2065 (192 - (4 + 5) - sizeof(seq_end_pes)), /* adaptation field length */
2066 0x80, /* adaptation field: discontinuity indicator */
2069 memset(p_block->p_buffer, 0, 192);
2070 memcpy(p_block->p_buffer, vid_pusi_ts, sizeof(vid_pusi_ts));
2071 memcpy(p_block->p_buffer + 192 - sizeof(seq_end_pes), seq_end_pes, sizeof(seq_end_pes));
2072 p_block->i_buffer = 192;
2074 /* set correct sequence end code */
2075 vlc_mutex_lock(&p_sys->pl_info_lock);
2076 if (p_sys->p_clip_info != NULL) {
2077 if (p_sys->p_clip_info->video_streams[0].coding_type > 2) {
2078 /* VC1 / H.264 sequence end */
2079 p_block->p_buffer[191] = 0x0a;
2082 vlc_mutex_unlock(&p_sys->pl_info_lock);
2084 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2085 p_sys->b_flushed = true;
2088 static void blurayResetStillImage( demux_t *p_demux )
2090 demux_sys_t *p_sys = p_demux->p_sys;
2092 if (p_sys->i_still_end_time) {
2093 p_sys->i_still_end_time = 0;
2095 blurayResetParser(p_demux);
2096 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2100 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2102 demux_sys_t *p_sys = p_demux->p_sys;
2104 /* time period elapsed ? */
2105 if (p_sys->i_still_end_time > 0 && p_sys->i_still_end_time <= mdate()) {
2106 msg_Dbg(p_demux, "Still image end");
2107 bd_read_skip_still(p_sys->bluray);
2109 blurayResetStillImage(p_demux);
2110 return;
2113 /* show last frame as still image */
2114 if (!p_sys->i_still_end_time) {
2115 if (i_timeout) {
2116 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2117 p_sys->i_still_end_time = mdate() + i_timeout * CLOCK_FREQ;
2118 } else {
2119 msg_Dbg(p_demux, "Still image (infinite)");
2120 p_sys->i_still_end_time = -1;
2123 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2124 streamFlush(p_sys);
2126 /* stop buffering */
2127 bool b_empty;
2128 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2131 /* avoid busy loops (read returns no data) */
2132 msleep( 40000 );
2135 static void blurayStreamSelect(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2137 demux_sys_t *p_sys = p_demux->p_sys;
2138 int i_pid = -1;
2140 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2141 i_id--;
2143 if (i_type == BD_EVENT_AUDIO_STREAM) {
2144 p_sys->i_audio_stream_idx = i_id;
2145 i_pid = blurayEsPid(p_sys, AUDIO_ES, i_id);
2146 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2147 p_sys->i_spu_stream_idx = i_id;
2148 i_pid = blurayEsPid(p_sys, SPU_ES, i_id);
2151 if (i_pid > 0) {
2152 int i_idx = findEsPairIndex(p_sys, i_pid);
2153 if (i_idx >= 0) {
2154 if (i_type == BD_EVENT_AUDIO_STREAM) {
2155 var_SetInteger( p_demux->p_input, "audio-es", i_pid );
2156 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2157 var_SetInteger( p_demux->p_input, "spu-es", p_sys->b_spu_enable ? i_pid : -1 );
2163 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2165 demux_sys_t *p_sys = p_demux->p_sys;
2167 blurayResetParser(p_demux);
2169 /* read title info and init some values */
2170 if (!p_sys->b_menu)
2171 p_demux->info.i_title = bd_get_current_title(p_sys->bluray);
2172 p_demux->info.i_seekpoint = 0;
2173 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2175 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2176 if (p_title_info) {
2177 blurayUpdateTitleInfo(p_sys->pp_title[p_demux->info.i_title], p_title_info);
2178 if (p_sys->b_menu)
2179 p_demux->info.i_update |= INPUT_UPDATE_TITLE_LIST;
2181 setTitleInfo(p_sys, p_title_info);
2183 blurayResetStillImage(p_demux);
2186 static void blurayUpdateCurrentClip(demux_t *p_demux, uint32_t clip)
2188 demux_sys_t *p_sys = p_demux->p_sys;
2190 vlc_mutex_lock(&p_sys->pl_info_lock);
2192 p_sys->p_clip_info = NULL;
2193 p_sys->i_video_stream = -1;
2195 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2197 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2199 /* Let's assume a single video track for now.
2200 * This may brake later, but it's enough for now.
2202 assert(p_sys->p_clip_info->video_stream_count >= 1);
2203 p_sys->i_video_stream = p_sys->p_clip_info->video_streams[0].pid;
2206 vlc_mutex_unlock(&p_sys->pl_info_lock);
2208 blurayResetStillImage(p_demux);
2211 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e)
2213 demux_sys_t *p_sys = p_demux->p_sys;
2215 switch (e->event) {
2216 case BD_EVENT_TITLE:
2217 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2218 p_demux->info.i_title = p_sys->i_title - 1;
2219 else
2220 p_demux->info.i_title = e->param;
2221 /* this is feature title, we don't know yet which playlist it will play (if any) */
2222 setTitleInfo(p_sys, NULL);
2223 /* reset title infos here ? */
2224 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT; /* might be BD-J title with no video */
2225 break;
2226 case BD_EVENT_PLAYLIST:
2227 /* Start of playlist playback (?????.mpls) */
2228 blurayUpdatePlaylist(p_demux, e->param);
2229 if (p_sys->b_pl_playing) {
2230 /* previous playlist was stopped in middle. flush to avoid delay */
2231 msg_Info(p_demux, "Stopping playlist playback");
2232 blurayResetParser(p_demux);
2233 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2235 p_sys->b_pl_playing = true;
2236 break;
2237 case BD_EVENT_PLAYITEM:
2238 blurayUpdateCurrentClip(p_demux, e->param);
2239 break;
2240 case BD_EVENT_CHAPTER:
2241 if (e->param && e->param < 0xffff)
2242 p_demux->info.i_seekpoint = e->param - 1;
2243 else
2244 p_demux->info.i_seekpoint = 0;
2245 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
2246 break;
2247 case BD_EVENT_PLAYMARK:
2248 case BD_EVENT_ANGLE:
2249 break;
2250 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2251 case BD_EVENT_UO_MASK_CHANGED:
2252 /* This event could be used to grey out unselectable items in title menu */
2253 break;
2254 #endif
2255 case BD_EVENT_MENU:
2256 p_sys->b_menu_open = e->param;
2257 break;
2258 case BD_EVENT_POPUP:
2259 p_sys->b_popup_available = e->param;
2260 /* TODO: show / hide pop-up menu button in gui ? */
2261 break;
2264 * Errors
2266 case BD_EVENT_ERROR:
2267 /* fatal error (with menus) */
2268 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2269 "Playback with BluRay menus failed");
2270 p_sys->b_fatal_error = true;
2271 break;
2272 case BD_EVENT_ENCRYPTED:
2273 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2274 "This disc seems to be encrypted");
2275 p_sys->b_fatal_error = true;
2276 break;
2277 case BD_EVENT_READ_ERROR:
2278 msg_Err(p_demux, "bluray: read error\n");
2279 break;
2282 * stream selection events
2284 case BD_EVENT_PG_TEXTST:
2285 p_sys->b_spu_enable = e->param;
2286 break;
2287 case BD_EVENT_AUDIO_STREAM:
2288 case BD_EVENT_PG_TEXTST_STREAM:
2289 blurayStreamSelect(p_demux, e->event, e->param);
2290 break;
2291 case BD_EVENT_IG_STREAM:
2292 case BD_EVENT_SECONDARY_AUDIO:
2293 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2294 case BD_EVENT_SECONDARY_VIDEO:
2295 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2296 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2297 break;
2300 * playback control events
2302 case BD_EVENT_STILL_TIME:
2303 blurayStillImage(p_demux, e->param);
2304 break;
2305 case BD_EVENT_DISCONTINUITY:
2306 /* reset demuxer (partially decoded PES packets must be dropped) */
2307 blurayResetParser(p_demux);
2308 break;
2309 case BD_EVENT_END_OF_TITLE:
2310 p_sys->b_pl_playing = false;
2311 break;
2312 case BD_EVENT_IDLE:
2313 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2314 /* avoid busy loop (bd_read() returns no data) */
2315 msleep( 40000 );
2316 break;
2318 default:
2319 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2320 break;
2324 static bool blurayIsBdjTitle(demux_t *p_demux)
2326 demux_sys_t *p_sys = p_demux->p_sys;
2327 unsigned int i_title = p_demux->info.i_title;
2328 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2330 if (di && di->titles) {
2331 if ((i_title <= di->num_titles && di->titles[i_title] && di->titles[i_title]->bdj) ||
2332 (i_title == p_sys->i_title - 1 && di->first_play && di->first_play->bdj)) {
2333 return true;
2337 return false;
2340 static void blurayHandleOverlays(demux_t *p_demux, int nread)
2342 demux_sys_t *p_sys = p_demux->p_sys;
2344 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2346 for (int i = 0; i < MAX_OVERLAY; i++) {
2347 bluray_overlay_t *ov = p_sys->p_overlays[i];
2348 if (!ov) {
2349 continue;
2351 vlc_mutex_lock(&ov->lock);
2352 bool display = ov->status == ToDisplay;
2353 vlc_mutex_unlock(&ov->lock);
2354 if (display) {
2355 if (p_sys->p_vout == NULL) {
2356 p_sys->p_vout = input_GetVout(p_demux->p_input);
2357 if (p_sys->p_vout != NULL) {
2358 var_AddCallback(p_sys->p_vout, "mouse-moved", onMouseEvent, p_demux);
2359 var_AddCallback(p_sys->p_vout, "mouse-clicked", onMouseEvent, p_demux);
2363 /* NOTE: we might want to enable background video always when there's no video stream playing.
2364 Now, with some discs, there are perioids (even seconds) during which the video window
2365 disappears and just playlist is shown.
2366 (sometimes BD-J runs slowly ...)
2368 if (!p_sys->p_vout && !p_sys->p_dummy_video && p_sys->b_menu &&
2369 !p_sys->p_pl_info && nread == 0 &&
2370 blurayIsBdjTitle(p_demux)) {
2372 /* Looks like there's no video stream playing.
2373 Emit blank frame so that BD-J overlay can be drawn. */
2374 startBackground(p_demux);
2377 if (p_sys->p_vout != NULL) {
2378 bluraySendOverlayToVout(p_demux, ov);
2383 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2386 static int onIntfEvent( vlc_object_t *p_input, char const *psz_var,
2387 vlc_value_t oldval, vlc_value_t val, void *p_data )
2389 (void)p_input; (void) psz_var; (void) oldval;
2390 demux_t *p_demux = p_data;
2391 demux_sys_t *p_sys = p_demux->p_sys;
2393 if (val.i_int == INPUT_EVENT_VOUT) {
2395 vlc_mutex_lock(&p_sys->bdj_overlay_lock);
2396 if( p_sys->p_vout != NULL ) {
2397 blurayReleaseVout(p_demux);
2399 vlc_mutex_unlock(&p_sys->bdj_overlay_lock);
2401 blurayHandleOverlays(p_demux, 1);
2404 return VLC_SUCCESS;
2407 #define BD_TS_PACKET_SIZE (192)
2408 #define NB_TS_PACKETS (200)
2410 static int blurayDemux(demux_t *p_demux)
2412 demux_sys_t *p_sys = p_demux->p_sys;
2413 BD_EVENT e;
2415 block_t *p_block = block_Alloc(NB_TS_PACKETS * (int64_t)BD_TS_PACKET_SIZE);
2416 if (!p_block)
2417 return VLC_DEMUXER_EGENERIC;
2419 int nread;
2421 if (p_sys->b_menu == false) {
2422 while (bd_get_event(p_sys->bluray, &e))
2423 blurayHandleEvent(p_demux, &e);
2425 nread = bd_read(p_sys->bluray, p_block->p_buffer,
2426 NB_TS_PACKETS * BD_TS_PACKET_SIZE);
2427 } else {
2428 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer,
2429 NB_TS_PACKETS * BD_TS_PACKET_SIZE, &e);
2430 while (e.event != BD_EVENT_NONE) {
2431 blurayHandleEvent(p_demux, &e);
2432 bd_get_event(p_sys->bluray, &e);
2436 blurayHandleOverlays(p_demux, nread);
2438 if (nread <= 0) {
2439 block_Release(p_block);
2440 if (p_sys->b_fatal_error || nread < 0) {
2441 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
2442 return VLC_DEMUXER_EGENERIC;
2444 if (!p_sys->b_menu) {
2445 return VLC_DEMUXER_EOF;
2447 return VLC_DEMUXER_SUCCESS;
2450 p_block->i_buffer = nread;
2452 stopBackground(p_demux);
2454 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2456 p_sys->b_flushed = false;
2458 return VLC_DEMUXER_SUCCESS;