access: bluray: process stream selection event last
[vlc.git] / modules / access / bluray.c
blobe8f0b6fde1ae2b61490006aeb459693abfd5aa88
1 /*****************************************************************************
2 * bluray.c: Blu-ray disc support plugin
3 *****************************************************************************
4 * Copyright © 2010-2012 VideoLAN, VLC authors and libbluray AUTHORS
6 * Authors: Jean-Baptiste Kempf <jb@videolan.org>
7 * Hugo Beauzée-Luyssen <hugo@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <assert.h>
29 #include <stdatomic.h>
31 #if defined (HAVE_MNTENT_H) && defined(HAVE_SYS_STAT_H)
32 # include <mntent.h>
33 #endif
34 #include <fcntl.h> /* O_* */
35 #include <unistd.h> /* close() */
36 #include <sys/stat.h>
38 #ifdef __APPLE__
39 # include <sys/param.h>
40 # include <sys/ucred.h>
41 # include <sys/mount.h>
42 #endif
44 #include <vlc_common.h>
45 #include <vlc_mouse.h>
46 #include <vlc_plugin.h>
47 #include <vlc_demux.h> /* demux_t */
48 #include <vlc_input.h> /* Seekpoints, chapters */
49 #include <vlc_dialog.h> /* BD+/AACS warnings */
50 #include <vlc_url.h> /* vlc_path2uri */
51 #include <vlc_iso_lang.h>
52 #include <vlc_fs.h>
54 #include "../demux/mpeg/timestamps.h"
55 #include "../demux/timestamps_filter.h"
57 /* FIXME we should find a better way than including that */
58 #include "../../src/text/iso-639_def.h"
61 #include <libbluray/bluray.h>
62 #include <libbluray/bluray-version.h>
63 #include <libbluray/keys.h>
64 #include <libbluray/meta_data.h>
65 #include <libbluray/overlay.h>
66 #include <libbluray/clpi_data.h>
68 //#define DEBUG_BLURAY
69 //#define DEBUG_BLURAY_EVENTS
71 #ifdef DEBUG_BLURAY
72 # include <libbluray/log_control.h>
73 # define BLURAY_DEBUG_MASK (0xFFFFF & ~DBG_STREAM)
74 static vlc_object_t *p_bluray_DebugObject;
75 static void bluray_DebugHandler(const char *psz)
77 size_t len = strlen(psz);
78 if(len < 1) return;
79 char *psz_log = NULL;
80 if(psz[len - 1] == '\n')
81 psz_log = strndup(psz, len - 1);
82 msg_Dbg(p_bluray_DebugObject, "%s", psz_log ? psz_log : psz);
83 free(psz_log);
85 #endif
87 #ifdef DEBUG_BLURAY_EVENTS
88 # define BD_DEBUG_EVENT_ENTRY(a) [a]=#a
89 static const char * bluray_event_debug_strings[] =
91 BD_DEBUG_EVENT_ENTRY(BD_EVENT_NONE),
92 BD_DEBUG_EVENT_ENTRY(BD_EVENT_ERROR),
93 BD_DEBUG_EVENT_ENTRY(BD_EVENT_READ_ERROR),
94 BD_DEBUG_EVENT_ENTRY(BD_EVENT_ENCRYPTED),
95 BD_DEBUG_EVENT_ENTRY(BD_EVENT_ANGLE),
96 BD_DEBUG_EVENT_ENTRY(BD_EVENT_TITLE),
97 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PLAYLIST),
98 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PLAYITEM),
99 BD_DEBUG_EVENT_ENTRY(BD_EVENT_CHAPTER),
100 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PLAYMARK),
101 BD_DEBUG_EVENT_ENTRY(BD_EVENT_END_OF_TITLE),
102 BD_DEBUG_EVENT_ENTRY(BD_EVENT_AUDIO_STREAM),
103 BD_DEBUG_EVENT_ENTRY(BD_EVENT_IG_STREAM),
104 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PG_TEXTST_STREAM),
105 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PIP_PG_TEXTST_STREAM),
106 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_AUDIO_STREAM),
107 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_VIDEO_STREAM),
108 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PG_TEXTST),
109 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PIP_PG_TEXTST),
110 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_AUDIO),
111 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_VIDEO),
112 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SECONDARY_VIDEO_SIZE),
113 BD_DEBUG_EVENT_ENTRY(BD_EVENT_PLAYLIST_STOP),
114 BD_DEBUG_EVENT_ENTRY(BD_EVENT_DISCONTINUITY),
115 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SEEK),
116 BD_DEBUG_EVENT_ENTRY(BD_EVENT_STILL),
117 BD_DEBUG_EVENT_ENTRY(BD_EVENT_STILL_TIME),
118 BD_DEBUG_EVENT_ENTRY(BD_EVENT_SOUND_EFFECT),
119 BD_DEBUG_EVENT_ENTRY(BD_EVENT_IDLE),
120 BD_DEBUG_EVENT_ENTRY(BD_EVENT_POPUP),
121 BD_DEBUG_EVENT_ENTRY(BD_EVENT_MENU),
122 BD_DEBUG_EVENT_ENTRY(BD_EVENT_STEREOSCOPIC_STATUS),
123 BD_DEBUG_EVENT_ENTRY(BD_EVENT_KEY_INTEREST_TABLE),
124 BD_DEBUG_EVENT_ENTRY(BD_EVENT_UO_MASK_CHANGED),
126 # define blurayDebugEvent(e, v) do {\
127 if(e < ARRAY_SIZE(bluray_event_debug_strings))\
128 msg_Dbg(p_demux, "Event %s %x", bluray_event_debug_strings[e], v);\
129 else\
130 msg_Dbg(p_demux, "Event Unk 0x%x %x", e, v);\
131 } while(0)
132 #else
133 # define blurayDebugEvent(e, v)
134 #endif
136 #ifdef BLURAY_HAS_BDJO_DATA_H
137 /* System version check menu freeze. See
138 * https://code.videolan.org/videolan/libbluray/issues/1
139 * To be removed with fix[ed,able] libbluray */
140 # include <libbluray/bdjo_data.h>
141 # include <strings.h>
142 static int BDJO_FileSelect( const char *psz_filename )
144 int i_len = strlen( psz_filename );
145 if ( i_len <= 5 )
146 return 0;
147 else
148 return ! strcasecmp( &psz_filename[i_len - 5], ".bdjo" );
151 static bool BDJO_IsBlacklisted(demux_t *p_demux, const char *psz_bd_path)
153 const char * rgsz_class_blacklist[] =
155 "com.macrovision.bdplus.Handshake",
158 bool b_ret = false;
159 char *psz_bdjo_dir;
160 if(-1 == asprintf(&psz_bdjo_dir, "%s/BDMV/BDJO", psz_bd_path))
161 return false;
163 char **ppsz_filenames = NULL;
164 int i_files = vlc_scandir(psz_bdjo_dir, &ppsz_filenames, BDJO_FileSelect, NULL);
165 if(i_files < 1)
167 free(psz_bdjo_dir);
168 return false;
171 for( int i=0; i<i_files && !b_ret; i++ )
173 char *psz_bdjo_file;
174 if(-1 < asprintf(&psz_bdjo_file, "%s/%s", psz_bdjo_dir, ppsz_filenames[i]))
176 struct bdjo_data *bdjo = bd_read_bdjo(psz_bdjo_file);
177 if(bdjo)
179 size_t k=0;
180 for(uint8_t j=0; j<bdjo->app_table.num_app && !b_ret; j++)
181 for(; k<ARRAY_SIZE(rgsz_class_blacklist) && !b_ret; k++)
182 b_ret = (!strcmp(rgsz_class_blacklist[k],
183 bdjo->app_table.app[j].initial_class));
184 #ifdef DEBUG_BLURAY
185 if(b_ret)
186 msg_Warn(p_demux, "Found blacklisted class %s in %s",
187 rgsz_class_blacklist[k],
188 ppsz_filenames[i]);
189 #else
190 VLC_UNUSED(p_demux);
191 #endif
192 bd_free_bdjo(bdjo);
194 free(psz_bdjo_file);
198 free(psz_bdjo_dir);
200 for( int i=0; i<i_files; i++ )
201 free(ppsz_filenames[i]);
202 free(ppsz_filenames);
204 return b_ret;
206 #else
207 # define BDJO_IsBlacklisted(foo, bar) (0)
208 #endif
210 /*****************************************************************************
211 * Module descriptor
212 *****************************************************************************/
214 #define BD_MENU_TEXT N_("Blu-ray menus")
215 #define BD_MENU_LONGTEXT N_("Use Blu-ray menus. If disabled, "\
216 "the movie will start directly")
217 #define BD_REGION_TEXT N_("Region code")
218 #define BD_REGION_LONGTEXT N_("Blu-Ray player region code. "\
219 "Some discs can be played only with a correct region code.")
221 static const char *const ppsz_region_code[] = {
222 "A", "B", "C" };
223 static const char *const ppsz_region_code_text[] = {
224 "Region A", "Region B", "Region C" };
226 #define REGION_DEFAULT 1 /* Index to region list. Actual region code is (1<<REGION_DEFAULT) */
227 #define LANGUAGE_DEFAULT ("eng")
229 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,0)
230 # define BLURAY_DEMUX
231 #endif
233 #ifndef BD_STREAM_TYPE_VIDEO_HEVC
234 # define BD_STREAM_TYPE_VIDEO_HEVC 0x24
235 #endif
237 #define BD_CLUSTER_SIZE 6144
238 #define BD_READ_SIZE (10 * BD_CLUSTER_SIZE)
240 /* Callbacks */
241 static int blurayOpen (vlc_object_t *);
242 static void blurayClose(vlc_object_t *);
244 vlc_module_begin ()
245 set_shortname(N_("Blu-ray"))
246 set_description(N_("Blu-ray Disc support (libbluray)"))
248 set_category(CAT_INPUT)
249 set_subcategory(SUBCAT_INPUT_ACCESS)
250 set_capability("access", 500)
251 add_bool("bluray-menu", true, BD_MENU_TEXT, BD_MENU_LONGTEXT, false)
252 add_string("bluray-region", ppsz_region_code[REGION_DEFAULT], BD_REGION_TEXT, BD_REGION_LONGTEXT, false)
253 change_string_list(ppsz_region_code, ppsz_region_code_text)
255 add_shortcut("bluray", "file")
257 set_callbacks(blurayOpen, blurayClose)
259 #ifdef BLURAY_DEMUX
260 /* demux module */
261 add_submodule()
262 set_description( "BluRay demuxer" )
263 set_category( CAT_INPUT )
264 set_subcategory( SUBCAT_INPUT_DEMUX )
265 set_capability( "demux", 5 )
266 set_callbacks( blurayOpen, blurayClose )
267 #endif
269 vlc_module_end ()
271 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
272 #define MAX_OVERLAY 2
274 typedef enum OverlayStatus {
275 Closed = 0,
276 ToDisplay, //Used to mark the overlay to be displayed the first time.
277 Displayed,
278 Outdated //used to update the overlay after it has been sent to the vout
279 } OverlayStatus;
281 typedef struct bluray_spu_updater_sys_t bluray_spu_updater_sys_t;
283 typedef struct bluray_overlay_t
285 vlc_mutex_t lock;
286 bool b_on_vout;
287 OverlayStatus status;
288 subpicture_region_t *p_regions;
289 int width, height;
291 /* pointer to last subpicture updater.
292 * used to disconnect this overlay from vout when:
293 * - the overlay is closed
294 * - vout is changed and this overlay is sent to the new vout
296 bluray_spu_updater_sys_t *p_updater;
297 } bluray_overlay_t;
299 typedef struct
301 BLURAY *bluray;
302 bool b_draining;
304 /* Titles */
305 unsigned int i_title;
306 unsigned int i_longest_title;
307 input_title_t **pp_title;
308 unsigned cur_title;
309 unsigned cur_seekpoint;
310 unsigned updates;
312 /* Events */
313 DECL_ARRAY(BD_EVENT) events_delayed;
315 vlc_mutex_t pl_info_lock;
316 BLURAY_TITLE_INFO *p_pl_info;
317 const BLURAY_CLIP_INFO *p_clip_info;
318 enum
320 BD_CLIP_APP_TYPE_TS_MAIN_PATH_MOVIE = 1,
321 BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW = 2,
322 BD_CLIP_APP_TYPE_TS_MAIN_PATH_BROWSABLE_SLIDESHOW = 3,
323 BD_CLIP_APP_TYPE_TS_SUB_PATH_BROWSABLE_SLIDESHOW = 4,
324 BD_CLIP_APP_TYPE_TS_SUB_PATH_INTERACTIVE_MENU = 5,
325 BD_CLIP_APP_TYPE_TS_SUB_PATH_TEXT_SUBTITLE = 6,
326 BD_CLIP_APP_TYPE_TS_SUB_PATH_ELEMENTARY_STREAM_PATH = 7,
327 } clip_application_type;
329 /* Attachments */
330 int i_attachments;
331 input_attachment_t **attachments;
332 int i_cover_idx;
334 /* Meta information */
335 const META_DL *p_meta;
337 /* Menus */
338 bool b_fatal_error;
339 bool b_menu;
340 bool b_menu_open;
341 bool b_popup_available;
342 vlc_tick_t i_still_end_time;
343 struct
345 bluray_overlay_t *p_overlays[MAX_OVERLAY];
346 vlc_mutex_t lock; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
347 } bdj;
349 /* */
350 vlc_mouse_t oldmouse;
352 /* TS stream */
353 es_out_t *p_tf_out;
354 es_out_t *p_out;
355 bool b_spu_enable; /* enabled / disabled */
356 vlc_demux_chained_t *p_parser;
357 bool b_flushed;
358 bool b_pl_playing; /* true when playing playlist */
360 /* stream input */
361 vlc_mutex_t read_block_lock;
363 /* Used to store bluray disc path */
364 char *psz_bd_path;
365 } demux_sys_t;
368 * Local ES index storage
370 typedef struct
372 es_format_t fmt;
373 es_out_id_t *p_es;
374 int i_next_block_flags;
375 bool b_recyling;
376 bool b_restart_decoders_on_reuse;
377 } es_pair_t;
379 static bool es_pair_Add(vlc_array_t *p_array, const es_format_t *p_fmt,
380 es_out_id_t *p_es)
382 es_pair_t *p_pair = malloc(sizeof(*p_pair));
383 if (likely(p_pair != NULL))
385 p_pair->p_es = p_es;
386 p_pair->i_next_block_flags = 0;
387 p_pair->b_recyling = false;
388 p_pair->b_restart_decoders_on_reuse = true;
389 if(vlc_array_append(p_array, p_pair) != VLC_SUCCESS)
391 free(p_pair);
392 p_pair = NULL;
394 else
396 es_format_Init(&p_pair->fmt, p_fmt->i_cat, p_fmt->i_codec);
397 es_format_Copy(&p_pair->fmt, p_fmt);
400 return p_pair != NULL;
403 static void es_pair_Remove(vlc_array_t *p_array, es_pair_t *p_pair)
405 vlc_array_remove(p_array, vlc_array_index_of_item(p_array, p_pair));
406 es_format_Clean(&p_pair->fmt);
407 free(p_pair);
410 static es_pair_t *getEsPair(vlc_array_t *p_array,
411 bool (*match)(const es_pair_t *, const void *),
412 const void *param)
414 for (size_t i = 0; i < vlc_array_count(p_array); ++i)
416 es_pair_t *p_pair = vlc_array_item_at_index(p_array, i);
417 if(match(p_pair, param))
418 return p_pair;
420 return NULL;
423 static bool es_pair_compare_PID(const es_pair_t *p_pair, const void *p_pid)
425 return p_pair->fmt.i_id == *((const int *)p_pid);
428 static bool es_pair_compare_ES(const es_pair_t *p_pair, const void *p_es)
430 return p_pair->p_es == (const es_out_id_t *)p_es;
433 static bool es_pair_compare_Unused(const es_pair_t *p_pair, const void *priv)
435 VLC_UNUSED(priv);
436 return p_pair->b_recyling;
439 static es_pair_t *getEsPairByPID(vlc_array_t *p_array, int i_pid)
441 return getEsPair(p_array, es_pair_compare_PID, &i_pid);
444 static es_pair_t *getEsPairByES(vlc_array_t *p_array, const es_out_id_t *p_es)
446 return getEsPair(p_array, es_pair_compare_ES, p_es);
449 static es_pair_t *getUnusedEsPair(vlc_array_t *p_array)
451 return getEsPair(p_array, es_pair_compare_Unused, 0);
455 * Subpicture updater
457 struct bluray_spu_updater_sys_t
459 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
460 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
461 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
465 * cut the connection between vout and overlay.
466 * - called when vout is closed or overlay is closed.
467 * - frees bluray_spu_updater_sys_t when both sides have been closed.
469 static void unref_subpicture_updater(bluray_spu_updater_sys_t *p_sys)
471 vlc_mutex_lock(&p_sys->lock);
472 int refs = --p_sys->ref_cnt;
473 p_sys->p_overlay = NULL;
474 vlc_mutex_unlock(&p_sys->lock);
476 if (refs < 1) {
477 vlc_mutex_destroy(&p_sys->lock);
478 free(p_sys);
482 /* Get a 3 char code
483 * FIXME: partiallyy duplicated from src/input/es_out.c
485 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
487 const iso639_lang_t *pl;
488 char *psz_lang;
489 char *p;
491 psz_lang = var_CreateGetString( p_demux, psz_var );
492 if( !psz_lang )
493 return LANGUAGE_DEFAULT;
495 /* XXX: we will use only the first value
496 * (and ignore other ones in case of a list) */
497 if( ( p = strchr( psz_lang, ',' ) ) )
498 *p = '\0';
500 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
502 if( *psz_lang == '\0' )
503 continue;
504 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
505 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
506 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
507 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
508 break;
511 free( psz_lang );
513 if( pl->psz_eng_name != NULL )
514 return pl->psz_iso639_2T;
516 return LANGUAGE_DEFAULT;
519 /*****************************************************************************
520 * Local prototypes
521 *****************************************************************************/
522 static es_out_t *esOutNew(vlc_object_t*, es_out_t *, void *);
524 static int blurayControl(demux_t *, int, va_list);
525 static int blurayDemux(demux_t *);
527 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles);
528 static int bluraySetTitle(demux_t *p_demux, int i_title);
530 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
531 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
532 static void blurayCloseOverlay(demux_t *p_demux, int plane);
534 static void onMouseEvent(const vlc_mouse_t *mouse, void *user_data);
535 static void blurayRestartParser(demux_t *p_demux, bool, bool);
536 static void notifyDiscontinuityToParser( demux_sys_t *p_sys );
538 #define STILL_IMAGE_NOT_SET 0
539 #define STILL_IMAGE_INFINITE -1
541 #define CURRENT_TITLE p_sys->pp_title[p_sys->cur_title]
542 #define CUR_LENGTH CURRENT_TITLE->i_length
544 /* */
545 static void FindMountPoint(char **file)
547 char *device = *file;
548 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
549 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
550 * we look up the real device */
551 char *bd_device = realpath(device, NULL);
552 if (bd_device == NULL)
553 return;
555 struct stat st;
556 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
557 FILE *mtab = setmntent ("/proc/self/mounts", "r");
558 if (mtab) {
559 struct mntent *m, mbuf;
560 char buf [8192];
562 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
563 if (!strcmp (m->mnt_fsname, bd_device)) {
564 free(device);
565 *file = strdup(m->mnt_dir);
566 break;
569 endmntent (mtab);
572 free(bd_device);
574 #elif defined(__APPLE__)
575 struct stat st;
576 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
577 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
578 if (fs_count > 0) {
579 struct statfs mbuf[128];
580 getfsstat (mbuf, fs_count * sizeof(mbuf[0]), MNT_NOWAIT);
581 for (int i = 0; i < fs_count; ++i)
582 if (!strcmp (mbuf[i].f_mntfromname, device)) {
583 free(device);
584 *file = strdup(mbuf[i].f_mntonname);
585 return;
589 #else
590 # warning Disc device to mount point not implemented
591 VLC_UNUSED( device );
592 #endif
595 /*****************************************************************************
596 * BD-J background video
597 *****************************************************************************/
599 static void bluraySendBackgroundImage(vlc_object_t *p_obj,
600 es_out_t *p_dst_out,
601 es_out_id_t *p_es,
602 const es_format_t *p_fmt)
604 msg_Info(p_obj, "Start background");
606 block_t *p_block = block_Alloc(p_fmt->video.i_width * p_fmt->video.i_height *
607 p_fmt->video.i_bits_per_pixel / 8);
608 if (!p_block) {
609 msg_Err(p_obj, "Error allocating block for background video");
610 return;
613 // XXX TODO: what would be correct timestamp ???
614 p_block->i_dts = p_block->i_pts = vlc_tick_now() + VLC_TICK_FROM_MS(40);
616 uint8_t *p = p_block->p_buffer;
617 memset(p, 0, p_fmt->video.i_width * p_fmt->video.i_height);
618 p += p_fmt->video.i_width * p_fmt->video.i_height;
619 memset(p, 0x80, p_fmt->video.i_width * p_fmt->video.i_height / 2);
621 es_out_SetPCR(p_dst_out, p_block->i_dts - VLC_TICK_FROM_MS(40));
622 es_out_Control(p_dst_out, ES_OUT_SET_ES, p_es);
623 es_out_Send(p_dst_out, p_es, p_block);
624 es_out_Control( p_dst_out, ES_OUT_VOUT_SET_MOUSE_EVENT, p_es, onMouseEvent, p_obj );
625 es_out_SetPCR(p_dst_out, p_block->i_dts);
628 /*****************************************************************************
629 * cache current playlist (title) information
630 *****************************************************************************/
632 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
634 vlc_mutex_lock(&p_sys->pl_info_lock);
636 if (p_sys->p_pl_info) {
637 bd_free_title_info(p_sys->p_pl_info);
639 p_sys->p_pl_info = info;
640 p_sys->p_clip_info = NULL;
642 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
643 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
646 vlc_mutex_unlock(&p_sys->pl_info_lock);
649 /*****************************************************************************
650 * create input attachment for thumbnail
651 *****************************************************************************/
653 static void attachThumbnail(demux_t *p_demux)
655 demux_sys_t *p_sys = p_demux->p_sys;
657 if (!p_sys->p_meta)
658 return;
660 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
661 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
662 int64_t size;
663 void *data;
664 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
665 char psz_name[64];
666 input_attachment_t *p_attachment;
668 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
670 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
671 if (p_attachment) {
672 p_sys->i_cover_idx = p_sys->i_attachments;
673 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
676 free(data);
678 #endif
681 /*****************************************************************************
682 * stream input
683 *****************************************************************************/
685 static int probeStream(demux_t *p_demux)
687 /* input must be seekable */
688 bool b_canseek = false;
689 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
690 if (!b_canseek) {
691 return VLC_EGENERIC;
694 /* first sector(s) should be filled with zeros */
695 size_t i_peek;
696 const uint8_t *p_peek;
697 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
698 if( i_peek != 2048 ) {
699 return VLC_EGENERIC;
701 while (i_peek > 0) {
702 if (p_peek[ --i_peek ]) {
703 return VLC_EGENERIC;
707 return VLC_SUCCESS;
710 #ifdef BLURAY_DEMUX
711 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
713 demux_t *p_demux = (demux_t*)object;
714 demux_sys_t *p_sys = p_demux->p_sys;
715 int result = -1;
717 assert(p_demux->s != NULL);
719 vlc_mutex_lock(&p_sys->read_block_lock);
721 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
722 size_t req = (size_t)2048 * num_blocks;
723 ssize_t got;
725 got = vlc_stream_Read( p_demux->s, buf, req);
726 if (got < 0) {
727 msg_Err(p_demux, "read from lba %d failed", lba);
728 } else {
729 result = got / 2048;
731 } else {
732 msg_Err(p_demux, "seek to lba %d failed", lba);
735 vlc_mutex_unlock(&p_sys->read_block_lock);
737 return result;
739 #endif
741 /*****************************************************************************
742 * probing of local files
743 *****************************************************************************/
745 /* Descriptor Tag (ECMA 167, 3/7.2) */
746 static int decode_descriptor_tag(const uint8_t *buf)
748 uint16_t id;
749 uint8_t checksum = 0;
750 int i;
752 id = buf[0] | (buf[1] << 8);
754 /* calculate tag checksum */
755 for (i = 0; i < 4; i++) {
756 checksum = (uint8_t)(checksum + buf[i]);
758 for (i = 5; i < 16; i++) {
759 checksum = (uint8_t)(checksum + buf[i]);
762 if (checksum != buf[4]) {
763 return -1;
766 return id;
769 static int probeFile(const char *psz_name)
771 struct stat stat_info;
772 uint8_t peek[2048];
773 unsigned i;
774 int ret = VLC_EGENERIC;
775 int fd;
777 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
778 if (fd == -1) {
779 return VLC_EGENERIC;
782 if (fstat(fd, &stat_info) == -1) {
783 goto bailout;
785 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
786 goto bailout;
789 /* first sector should be filled with zeros */
790 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
791 goto bailout;
793 for (i = 0; i < sizeof(peek); i++) {
794 if (peek[ i ]) {
795 goto bailout;
799 /* Check AVDP tag checksum */
800 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
801 read(fd, peek, 16) != 16 ||
802 decode_descriptor_tag(peek) != 2) {
803 goto bailout;
806 ret = VLC_SUCCESS;
808 bailout:
809 vlc_close(fd);
810 return ret;
813 /*****************************************************************************
814 * blurayOpen: module init function
815 *****************************************************************************/
816 static int blurayOpen(vlc_object_t *object)
818 demux_t *p_demux = (demux_t*)object;
819 demux_sys_t *p_sys;
820 bool forced;
821 uint64_t i_init_pos = 0;
823 const char *error_msg = NULL;
824 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
826 if (p_demux->out == NULL)
827 return VLC_EGENERIC;
829 forced = !strncasecmp(p_demux->psz_url, "bluray:", 7);
831 if (p_demux->s) {
832 if (!strncasecmp(p_demux->psz_url, "file:", 5)) {
833 /* use access_demux for local files */
834 return VLC_EGENERIC;
837 if (probeStream(p_demux) != VLC_SUCCESS) {
838 return VLC_EGENERIC;
841 } else if (!forced) {
842 if (!p_demux->psz_filepath) {
843 return VLC_EGENERIC;
846 if (probeFile(p_demux->psz_filepath) != VLC_SUCCESS) {
847 return VLC_EGENERIC;
851 /* */
852 p_demux->p_sys = p_sys = vlc_obj_calloc(object, 1, sizeof(*p_sys));
853 if (unlikely(!p_sys))
854 return VLC_ENOMEM;
856 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
858 /* init demux info fields */
859 p_sys->updates = 0;
861 TAB_INIT(p_sys->i_title, p_sys->pp_title);
862 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
863 ARRAY_INIT(p_sys->events_delayed);
865 vlc_mouse_Init(&p_sys->oldmouse);
867 vlc_mutex_init(&p_sys->pl_info_lock);
868 vlc_mutex_init(&p_sys->bdj.lock);
869 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
871 /* request sub demuxers to skip continuity check as some split
872 file concatenation are just resetting counters... */
873 var_Create( p_demux, "ts-cc-check", VLC_VAR_BOOL );
874 var_SetBool( p_demux, "ts-cc-check", false );
875 var_Create( p_demux, "ts-standard", VLC_VAR_STRING );
876 var_SetString( p_demux, "ts-standard", "mpeg" );
877 var_Create( p_demux, "ts-pmtfix-waitdata", VLC_VAR_BOOL );
878 var_SetBool( p_demux, "ts-pmtfix-waitdata", false );
879 var_Create( p_demux, "ts-patfix", VLC_VAR_BOOL );
880 var_SetBool( p_demux, "ts-patfix", false );
881 var_Create( p_demux, "ts-pcr-offsetfix", VLC_VAR_BOOL );
882 var_SetBool( p_demux, "ts-pcr-offsetfix", false );
884 #ifdef DEBUG_BLURAY
885 p_bluray_DebugObject = VLC_OBJECT(p_demux);
886 bd_set_debug_mask(BLURAY_DEBUG_MASK);
887 bd_set_debug_handler(bluray_DebugHandler);
888 #endif
890 /* Open BluRay */
891 #ifdef BLURAY_DEMUX
892 if (p_demux->s) {
893 i_init_pos = vlc_stream_Tell(p_demux->s);
895 p_sys->bluray = bd_init();
896 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
897 bd_close(p_sys->bluray);
898 p_sys->bluray = NULL;
900 } else
901 #endif
903 if (!p_demux->psz_filepath) {
904 /* no path provided (bluray://). use default DVD device. */
905 p_sys->psz_bd_path = var_InheritString(object, "dvd");
906 } else {
907 /* store current bd path */
908 p_sys->psz_bd_path = strdup(p_demux->psz_filepath);
911 /* If we're passed a block device, try to convert it to the mount point. */
912 FindMountPoint(&p_sys->psz_bd_path);
914 p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
916 if (!p_sys->bluray) {
917 goto error;
920 /* Warning the user about AACS/BD+ */
921 const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
923 /* Is it a bluray? */
924 if (!disc_info->bluray_detected) {
925 if (forced) {
926 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
928 goto error;
931 msg_Info(p_demux, "First play: %i, Top menu: %i\n"
932 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
933 disc_info->first_play_supported, disc_info->top_menu_supported,
934 disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
935 disc_info->num_unsupported_titles);
937 /* AACS */
938 if (disc_info->aacs_detected) {
939 msg_Dbg(p_demux, "Disc is using AACS");
940 if (!disc_info->libaacs_detected)
941 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
942 ", and your system does not have it."));
943 if (!disc_info->aacs_handled) {
944 if (disc_info->aacs_error_code) {
945 switch (disc_info->aacs_error_code) {
946 case BD_AACS_CORRUPTED_DISC:
947 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
948 case BD_AACS_NO_CONFIG:
949 BLURAY_ERROR(_("Missing AACS configuration file!"));
950 case BD_AACS_NO_PK:
951 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
952 case BD_AACS_NO_CERT:
953 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
954 case BD_AACS_CERT_REVOKED:
955 BLURAY_ERROR(_("AACS Host certificate revoked."));
956 case BD_AACS_MMC_FAILED:
957 BLURAY_ERROR(_("AACS MMC failed."));
963 /* BD+ */
964 if (disc_info->bdplus_detected) {
965 msg_Dbg(p_demux, "Disc is using BD+");
966 if (!disc_info->libbdplus_detected)
967 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
968 ", and your system does not have it."));
969 if (!disc_info->bdplus_handled)
970 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
971 "Missing configuration?"));
974 /* set player region code */
975 char *psz_region = var_InheritString(p_demux, "bluray-region");
976 unsigned int region = psz_region ? (psz_region[0] - 'A') : REGION_DEFAULT;
977 free(psz_region);
978 bd_set_player_setting(p_sys->bluray, BLURAY_PLAYER_SETTING_REGION_CODE, 1<<region);
980 /* set preferred languages */
981 const char *psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
982 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG, psz_code);
983 psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
984 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG, psz_code);
985 psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
986 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_MENU_LANG, psz_code);
988 /* Get disc metadata */
989 p_sys->p_meta = bd_get_meta(p_sys->bluray);
990 if (!p_sys->p_meta)
991 msg_Warn(p_demux, "Failed to get meta info.");
993 p_sys->i_cover_idx = -1;
994 attachThumbnail(p_demux);
996 p_sys->b_menu = var_InheritBool(p_demux, "bluray-menu");
998 /* Check BD-J capability */
999 if (p_sys->b_menu && disc_info->bdj_detected && !disc_info->bdj_handled) {
1000 msg_Err(p_demux, "BD-J menus not supported. Playing without menus. "
1001 "BD-J support: %d, JVM found: %d, JVM usable: %d",
1002 disc_info->bdj_supported, disc_info->libjvm_detected, disc_info->bdj_handled);
1003 vlc_dialog_display_error(p_demux, _("Java required"),
1004 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
1005 !disc_info->libjvm_detected ? _("Java was not found on your system.") : "");
1006 p_sys->b_menu = false;
1009 if(disc_info->bdj_detected &&p_sys->b_menu &&
1010 BDJO_IsBlacklisted(p_demux, p_sys->psz_bd_path))
1012 p_sys->b_menu = vlc_dialog_wait_question( p_demux,
1013 VLC_DIALOG_QUESTION_NORMAL,
1014 _("Play without Menus"),
1015 _("Try anyway"),
1016 NULL,
1017 _("BDJO Menu check"),
1018 "%s",
1019 _("Incompatible Java Menu detected"));
1022 /* Get titles and chapters */
1023 blurayInitTitles(p_demux, disc_info->num_hdmv_titles + disc_info->num_bdj_titles + 1/*Top Menu*/ + 1/*First Play*/);
1026 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
1028 bd_get_event(p_sys->bluray, NULL);
1030 /* Registering overlay event handler */
1031 bd_register_overlay_proc(p_sys->bluray, p_demux, blurayOverlayProc);
1033 if (p_sys->b_menu) {
1035 /* Register ARGB overlay handler for BD-J */
1036 if (disc_info->num_bdj_titles)
1037 bd_register_argb_overlay_proc(p_sys->bluray, p_demux, blurayArgbOverlayProc, NULL);
1039 /* libbluray will start playback from "First-Title" title */
1040 if (bd_play(p_sys->bluray) == 0)
1041 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
1043 } else {
1044 /* set start title number */
1045 if (bluraySetTitle(p_demux, p_sys->i_longest_title) != VLC_SUCCESS) {
1046 msg_Err(p_demux, "Could not set the title %d", p_sys->i_longest_title);
1047 goto error;
1051 p_sys->p_tf_out = timestamps_filter_es_out_New(p_demux->out);
1052 if(unlikely(!p_sys->p_tf_out))
1053 goto error;
1055 p_sys->p_out = esOutNew(VLC_OBJECT(p_demux), p_sys->p_tf_out, p_demux);
1056 if (unlikely(p_sys->p_out == NULL))
1057 goto error;
1059 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
1060 if (!p_sys->p_parser) {
1061 msg_Err(p_demux, "Failed to create TS demuxer");
1062 goto error;
1065 p_demux->pf_control = blurayControl;
1066 p_demux->pf_demux = blurayDemux;
1068 return VLC_SUCCESS;
1070 error:
1071 if (error_msg)
1072 vlc_dialog_display_error(p_demux, _("Blu-ray error"), "%s", error_msg);
1073 blurayClose(object);
1075 if (p_demux->s != NULL) {
1076 /* restore stream position */
1077 if (vlc_stream_Seek(p_demux->s, i_init_pos) != VLC_SUCCESS) {
1078 msg_Err(p_demux, "Failed to seek back to stream start");
1079 return VLC_ETIMEOUT;
1083 return VLC_EGENERIC;
1084 #undef BLURAY_ERROR
1088 /*****************************************************************************
1089 * blurayClose: module destroy function
1090 *****************************************************************************/
1091 static void blurayClose(vlc_object_t *object)
1093 demux_t *p_demux = (demux_t*)object;
1094 demux_sys_t *p_sys = p_demux->p_sys;
1096 setTitleInfo(p_sys, NULL);
1099 * Close libbluray first.
1100 * This will close all the overlays before we release p_vout
1101 * bd_close(NULL) can crash
1103 if (p_sys->bluray) {
1104 bd_close(p_sys->bluray);
1107 vlc_mutex_lock(&p_sys->bdj.lock);
1108 for(int i = 0; i < MAX_OVERLAY; i++)
1109 blurayCloseOverlay(p_demux, i);
1110 vlc_mutex_unlock(&p_sys->bdj.lock);
1112 if (p_sys->p_parser)
1113 vlc_demux_chained_Delete(p_sys->p_parser);
1115 if (p_sys->p_out != NULL)
1116 es_out_Delete(p_sys->p_out);
1117 if(p_sys->p_tf_out)
1118 timestamps_filter_es_out_Delete(p_sys->p_tf_out);
1120 /* Titles */
1121 for (unsigned int i = 0; i < p_sys->i_title; i++)
1122 vlc_input_title_Delete(p_sys->pp_title[i]);
1123 TAB_CLEAN(p_sys->i_title, p_sys->pp_title);
1125 for (int i = 0; i < p_sys->i_attachments; i++)
1126 vlc_input_attachment_Delete(p_sys->attachments[i]);
1127 TAB_CLEAN(p_sys->i_attachments, p_sys->attachments);
1129 ARRAY_RESET(p_sys->events_delayed);
1131 vlc_mutex_destroy(&p_sys->pl_info_lock);
1132 vlc_mutex_destroy(&p_sys->bdj.lock);
1133 vlc_mutex_destroy(&p_sys->read_block_lock);
1135 free(p_sys->psz_bd_path);
1138 /*****************************************************************************
1139 * Elementary streams handling
1140 *****************************************************************************/
1141 static uint8_t blurayGetStreamsUnlocked(demux_sys_t *p_sys,
1142 int i_stream_type,
1143 BLURAY_STREAM_INFO **pp_streams)
1145 if(!p_sys->p_clip_info)
1146 return 0;
1148 switch(i_stream_type)
1150 case BD_EVENT_AUDIO_STREAM:
1151 *pp_streams = p_sys->p_clip_info->audio_streams;
1152 return p_sys->p_clip_info->audio_stream_count;
1153 case BD_EVENT_PG_TEXTST_STREAM:
1154 *pp_streams = p_sys->p_clip_info->pg_streams;
1155 return p_sys->p_clip_info->pg_stream_count;
1156 default:
1157 return 0;
1161 static BLURAY_STREAM_INFO * blurayGetStreamInfoUnlocked(demux_sys_t *p_sys,
1162 int i_stream_type,
1163 uint8_t i_stream_idx)
1165 BLURAY_STREAM_INFO *p_streams = NULL;
1166 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_stream_type, &p_streams);
1167 if(i_stream_idx < i_streams_count)
1168 return &p_streams[i_stream_idx];
1169 else
1170 return NULL;
1173 static BLURAY_STREAM_INFO * blurayGetStreamInfoByPIDUnlocked(demux_sys_t *p_sys,
1174 int i_pid)
1176 for(int i_type=BD_EVENT_AUDIO_STREAM; i_type<=BD_EVENT_SECONDARY_VIDEO_STREAM; i_type++)
1178 BLURAY_STREAM_INFO *p_streams;
1179 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_type, &p_streams);
1180 for(uint8_t i=0; i<i_streams_count; i++)
1182 if(p_streams[i].pid == i_pid)
1183 return &p_streams[i];
1186 return NULL;
1189 static void setStreamLang(demux_sys_t *p_sys, es_format_t *p_fmt)
1191 vlc_mutex_lock(&p_sys->pl_info_lock);
1193 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoByPIDUnlocked(p_sys, p_fmt->i_id);
1194 if(p_stream)
1196 free(p_fmt->psz_language);
1197 p_fmt->psz_language = strndup((const char *)p_stream->lang, 3);
1200 vlc_mutex_unlock(&p_sys->pl_info_lock);
1203 static int blurayGetStreamPID(demux_sys_t *p_sys, int i_stream_type, uint8_t i_stream_idx)
1205 vlc_mutex_lock(&p_sys->pl_info_lock);
1207 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoUnlocked(p_sys,
1208 i_stream_type,
1209 i_stream_idx);
1210 int i_pid = p_stream ? p_stream->pid : -1;
1212 vlc_mutex_unlock(&p_sys->pl_info_lock);
1214 return i_pid;
1217 /*****************************************************************************
1218 * bluray fake es_out
1219 *****************************************************************************/
1220 typedef struct
1222 es_out_t *p_dst_out;
1223 vlc_object_t *p_obj;
1224 vlc_array_t es; /* es_pair_t */
1225 bool b_entered_recycling;
1226 bool b_restart_decoders_on_reuse;
1227 void *priv;
1228 bool b_discontinuity;
1229 bool b_disable_output;
1230 bool b_lowdelay;
1231 vlc_mutex_t lock;
1232 struct
1234 int i_audio_pid; /* Selected audio stream. -1 if default */
1235 int i_spu_pid; /* Selected spu stream. -1 if default */
1236 } selected;
1237 struct
1239 es_out_id_t *p_video_es;
1240 int channels[MAX_OVERLAY];
1241 } overlay;
1242 es_out_t es_out;
1243 } bluray_esout_priv_t;
1245 enum
1247 BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID = ES_OUT_PRIVATE_START,
1248 BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID,
1249 BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY,
1250 BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT,
1251 BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT,
1252 BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY,
1253 BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY,
1254 BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY,
1255 BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY,
1256 BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS,
1259 static es_out_id_t *bluray_esOutAddUnlocked(bluray_esout_priv_t *esout_priv,
1260 const es_format_t *p_fmt)
1262 demux_t *p_demux = esout_priv->priv;
1263 demux_sys_t *p_sys = p_demux->p_sys;
1264 es_format_t fmt;
1265 bool b_select = false;
1267 es_format_Copy(&fmt, p_fmt);
1269 switch (fmt.i_cat) {
1270 case VIDEO_ES:
1271 if(esout_priv->b_lowdelay)
1273 fmt.video.i_frame_rate = 1; fmt.video.i_frame_rate_base = 1;
1274 fmt.b_packetized = true;
1276 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1277 b_select = (p_fmt->i_id == 0x1011);
1278 break;
1279 case AUDIO_ES:
1280 if (esout_priv->selected.i_audio_pid != -1) {
1281 if (esout_priv->selected.i_audio_pid == p_fmt->i_id)
1282 b_select = true;
1283 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1285 setStreamLang(p_sys, &fmt);
1286 break ;
1287 case SPU_ES:
1288 if (esout_priv->selected.i_spu_pid != -1) {
1289 if (esout_priv->selected.i_spu_pid == p_fmt->i_id)
1290 b_select = p_sys->b_spu_enable;
1291 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1293 setStreamLang(p_sys, &fmt);
1294 break ;
1295 default:
1299 es_out_id_t *p_es = NULL;
1300 if (p_fmt->i_id >= 0) {
1301 /* Ensure we are not overriding anything */
1302 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, p_fmt->i_id);
1303 if (p_pair == NULL)
1305 msg_Info(p_demux, "Adding ES %d select %d", p_fmt->i_id, b_select);
1306 p_es = es_out_Add(esout_priv->p_dst_out, &fmt);
1307 es_pair_Add(&esout_priv->es, &fmt, p_es);
1309 else
1311 msg_Info(p_demux, "Reusing ES %d", p_fmt->i_id);
1312 p_pair->b_recyling = false;
1313 p_es = p_pair->p_es;
1314 if(!es_format_IsSimilar(p_fmt, &p_pair->fmt) ||
1315 p_fmt->b_packetized != p_pair->fmt.b_packetized ||
1316 esout_priv->b_restart_decoders_on_reuse)
1317 es_out_Control(esout_priv->p_dst_out, ES_OUT_SET_ES_FMT, p_pair->p_es, &fmt);
1318 es_format_Clean(&p_pair->fmt);
1319 es_format_Copy(&p_pair->fmt, &fmt);
1321 if (b_select)
1322 es_out_Control(esout_priv->p_dst_out, ES_OUT_SET_ES, p_es);
1325 if (p_es && fmt.i_cat == VIDEO_ES && b_select)
1327 es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_SET_MOUSE_EVENT, p_es,
1328 onMouseEvent, p_demux);
1329 esout_priv->overlay.p_video_es = p_es;
1332 es_format_Clean(&fmt);
1334 return p_es;
1337 static es_out_id_t *bluray_esOutAdd(es_out_t *p_out, const es_format_t *p_fmt)
1339 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1341 vlc_mutex_lock(&esout_priv->lock);
1342 es_out_id_t *p_es = bluray_esOutAddUnlocked(esout_priv, p_fmt);
1343 vlc_mutex_unlock(&esout_priv->lock);
1345 return p_es;
1348 static void bluray_esOutDeleteNonReusedESUnlocked(es_out_t *p_out)
1350 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1352 if(!esout_priv->b_entered_recycling)
1353 return;
1354 esout_priv->b_entered_recycling = false;
1355 esout_priv->b_restart_decoders_on_reuse = true;
1357 es_pair_t *p_pair;
1358 while((p_pair = getUnusedEsPair(&esout_priv->es)))
1360 msg_Info(esout_priv->p_obj, "Trashing unused ES %d", p_pair->fmt.i_id);
1362 if(esout_priv->overlay.p_video_es == p_pair->p_es)
1363 esout_priv->overlay.p_video_es = NULL;
1365 es_out_Del(esout_priv->p_dst_out, p_pair->p_es);
1367 es_pair_Remove(&esout_priv->es, p_pair);
1371 static int bluray_esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1373 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1374 vlc_mutex_lock(&esout_priv->lock);
1376 bluray_esOutDeleteNonReusedESUnlocked(p_out);
1378 if(esout_priv->b_discontinuity)
1379 esout_priv->b_discontinuity = false;
1381 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1382 if(p_pair && p_pair->i_next_block_flags)
1384 p_block->i_flags |= p_pair->i_next_block_flags;
1385 p_pair->i_next_block_flags = 0;
1387 if(esout_priv->b_disable_output)
1389 block_Release(p_block);
1390 p_block = NULL;
1392 vlc_mutex_unlock(&esout_priv->lock);
1393 return (p_block) ? es_out_Send(esout_priv->p_dst_out, p_es, p_block) : VLC_SUCCESS;
1396 static void bluray_esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1398 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1399 vlc_mutex_lock(&esout_priv->lock);
1401 if(esout_priv->b_discontinuity)
1402 esout_priv->b_discontinuity = false;
1404 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1405 if (p_pair)
1407 p_pair->b_recyling = true;
1408 esout_priv->b_entered_recycling = true;
1411 vlc_mutex_unlock(&esout_priv->lock);
1414 static int bluray_esOutControl(es_out_t *p_out, int i_query, va_list args)
1416 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1417 int i_ret;
1418 vlc_mutex_lock(&esout_priv->lock);
1420 if(esout_priv->b_disable_output &&
1421 i_query < ES_OUT_PRIVATE_START)
1423 vlc_mutex_unlock(&esout_priv->lock);
1424 return VLC_EGENERIC;
1427 if(esout_priv->b_discontinuity)
1428 esout_priv->b_discontinuity = false;
1430 switch(i_query)
1432 case BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID:
1433 case BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID:
1435 bool b_select = (i_query == BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID);
1436 const int i_bluray_stream_type = va_arg(args, int);
1437 const int i_pid = va_arg(args, int);
1438 switch(i_bluray_stream_type)
1440 case BD_EVENT_AUDIO_STREAM:
1441 esout_priv->selected.i_audio_pid = i_pid;
1442 break;
1443 case BD_EVENT_PG_TEXTST_STREAM:
1444 esout_priv->selected.i_spu_pid = i_pid;
1445 break;
1446 default:
1447 break;
1450 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, i_pid);
1451 if(unlikely(!p_pair))
1453 vlc_mutex_unlock(&esout_priv->lock);
1454 return VLC_EGENERIC;
1457 i_ret = es_out_Control(esout_priv->p_dst_out,
1458 b_select ? ES_OUT_SET_ES : ES_OUT_UNSET_ES,
1459 p_pair->p_es);
1460 } break;
1462 case BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY:
1464 esout_priv->b_discontinuity = true;
1465 i_ret = VLC_SUCCESS;
1466 } break;
1468 case BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS:
1470 esout_priv->b_restart_decoders_on_reuse = !va_arg(args, int);
1471 i_ret = VLC_SUCCESS;
1472 } break;
1474 case BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT:
1475 case BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT:
1477 esout_priv->b_disable_output = (i_query == BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
1478 i_ret = VLC_SUCCESS;
1479 } break;
1481 case BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY:
1482 case BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY:
1484 esout_priv->b_lowdelay = (i_query == BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY);
1485 i_ret = VLC_SUCCESS;
1486 } break;
1488 case BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY:
1490 int i_plane = va_arg(args, int);
1491 subpicture_t *p_pic = va_arg(args, subpicture_t *);
1492 if(!esout_priv->overlay.p_video_es)
1494 es_format_t fmt;
1495 es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_I420);
1496 video_format_Setup(&fmt.video, VLC_CODEC_I420,
1497 1920, 1080, 1920, 1080, 1, 1);
1498 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1499 fmt.i_id = 0x1011;
1500 fmt.i_group = 1;
1501 fmt.video.i_frame_rate = 1; fmt.video.i_frame_rate_base = 1;
1502 fmt.b_packetized = true;
1503 esout_priv->overlay.p_video_es = bluray_esOutAddUnlocked(esout_priv, &fmt);
1504 if(esout_priv->overlay.p_video_es)
1506 bluraySendBackgroundImage(esout_priv->p_obj,
1507 esout_priv->p_dst_out,
1508 esout_priv->overlay.p_video_es,
1509 &fmt);
1511 es_format_Clean(&fmt);
1514 if(esout_priv->overlay.p_video_es && i_plane < MAX_OVERLAY)
1516 i_ret = es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_ADD_OVERLAY,
1517 esout_priv->overlay.p_video_es, p_pic,
1518 &esout_priv->overlay.channels[i_plane]);
1520 else
1522 i_ret = VLC_EGENERIC;
1524 break;
1527 case BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY:
1529 int i_plane = va_arg(args, int);
1530 if(esout_priv->overlay.p_video_es &&
1531 i_plane < MAX_OVERLAY &&
1532 esout_priv->overlay.channels[i_plane] != VOUT_SPU_CHANNEL_INVALID)
1534 i_ret = es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_FLUSH_OVERLAY,
1535 esout_priv->overlay.p_video_es,
1536 esout_priv->overlay.channels[i_plane]);
1537 esout_priv->overlay.channels[i_plane] = VOUT_SPU_CHANNEL_INVALID;
1539 else
1541 assert(esout_priv->overlay.channels[i_plane] == VOUT_SPU_CHANNEL_INVALID);
1542 i_ret = VLC_EGENERIC;
1544 break;
1547 case ES_OUT_SET_ES_DEFAULT:
1548 case ES_OUT_SET_ES:
1549 case ES_OUT_UNSET_ES:
1550 case ES_OUT_SET_ES_STATE:
1551 i_ret = VLC_EGENERIC;
1552 break;
1554 case ES_OUT_GET_ES_STATE:
1555 va_arg(args, es_out_id_t *);
1556 *va_arg(args, bool *) = true;
1557 i_ret = VLC_SUCCESS;
1558 break;
1560 default:
1561 i_ret = es_out_vaControl(esout_priv->p_dst_out, i_query, args);
1562 break;
1564 vlc_mutex_unlock(&esout_priv->lock);
1565 return i_ret;
1568 static void bluray_esOutDestroy(es_out_t *p_out)
1570 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1572 for (size_t i = 0; i < vlc_array_count(&esout_priv->es); ++i)
1573 free(vlc_array_item_at_index(&esout_priv->es, i));
1574 vlc_array_clear(&esout_priv->es);
1575 vlc_mutex_destroy(&esout_priv->lock);
1576 free(esout_priv);
1579 static const struct es_out_callbacks bluray_esOutCallbacks = {
1580 .add = bluray_esOutAdd,
1581 .send = bluray_esOutSend,
1582 .del = bluray_esOutDel,
1583 .control = bluray_esOutControl,
1584 .destroy = bluray_esOutDestroy,
1587 static es_out_t *esOutNew(vlc_object_t *p_obj, es_out_t *p_dst_out, void *priv)
1589 bluray_esout_priv_t *esout_priv = malloc(sizeof(*esout_priv));
1590 if (unlikely(esout_priv == NULL))
1591 return NULL;
1593 vlc_array_init(&esout_priv->es);
1594 esout_priv->p_dst_out = p_dst_out;
1595 esout_priv->p_obj = p_obj;
1596 esout_priv->priv = priv;
1597 esout_priv->es_out.cbs = &bluray_esOutCallbacks;
1598 esout_priv->b_discontinuity = false;
1599 esout_priv->b_disable_output = false;
1600 esout_priv->b_entered_recycling = false;
1601 esout_priv->b_restart_decoders_on_reuse = true;
1602 esout_priv->b_lowdelay = false;
1603 esout_priv->selected.i_audio_pid = -1;
1604 esout_priv->selected.i_spu_pid = -1;
1605 esout_priv->overlay.p_video_es = NULL;
1606 for(size_t i=0; i<MAX_OVERLAY; i++)
1607 esout_priv->overlay.channels[i] = VOUT_SPU_CHANNEL_INVALID;
1608 vlc_mutex_init(&esout_priv->lock);
1609 return &esout_priv->es_out;
1612 /*****************************************************************************
1613 * subpicture_updater_t functions:
1614 *****************************************************************************/
1616 static bluray_overlay_t *updater_lock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1618 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1619 vlc_mutex_lock(&p_upd_sys->lock);
1621 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1622 if (ov) {
1623 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1624 vlc_mutex_lock(&ov->lock);
1625 return ov;
1628 /* overlay has been closed */
1629 vlc_mutex_unlock(&p_upd_sys->lock);
1630 return NULL;
1633 static void updater_unlock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1635 assert (p_upd_sys->p_overlay);
1637 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1638 vlc_mutex_unlock(&p_upd_sys->lock);
1641 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1642 bool b_fmt_src, const video_format_t *p_fmt_src,
1643 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1644 vlc_tick_t i_ts)
1646 VLC_UNUSED(b_fmt_src);
1647 VLC_UNUSED(b_fmt_dst);
1648 VLC_UNUSED(p_fmt_src);
1649 VLC_UNUSED(p_fmt_dst);
1650 VLC_UNUSED(i_ts);
1652 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1653 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1655 if (!p_overlay) {
1656 return 1;
1659 int res = p_overlay->status == Outdated;
1661 updater_unlock_overlay(p_upd_sys);
1663 return res;
1666 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1667 const video_format_t *p_fmt_src,
1668 const video_format_t *p_fmt_dst,
1669 vlc_tick_t i_ts)
1671 VLC_UNUSED(p_fmt_src);
1672 VLC_UNUSED(p_fmt_dst);
1673 VLC_UNUSED(i_ts);
1674 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1675 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1677 if (!p_overlay) {
1678 return;
1682 * When this function is called, all p_subpic regions are gone.
1683 * We need to duplicate our regions (stored internaly) to this subpic.
1685 subpicture_region_t *p_src = p_overlay->p_regions;
1686 if (!p_src) {
1687 updater_unlock_overlay(p_upd_sys);
1688 return;
1691 subpicture_region_t **p_dst = &p_subpic->p_region;
1692 while (p_src != NULL) {
1693 *p_dst = subpicture_region_Copy(p_src);
1694 if (*p_dst == NULL)
1695 break;
1696 p_dst = &(*p_dst)->p_next;
1697 p_src = p_src->p_next;
1699 if (*p_dst != NULL)
1700 (*p_dst)->p_next = NULL;
1701 p_overlay->status = Displayed;
1703 updater_unlock_overlay(p_upd_sys);
1706 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1708 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1709 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1711 if (p_overlay) {
1712 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1713 p_overlay->status = ToDisplay;
1714 p_overlay->b_on_vout = false;
1715 updater_unlock_overlay(p_upd_sys);
1718 unref_subpicture_updater(p_upd_sys);
1721 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1723 bluray_spu_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1724 if (unlikely(p_upd_sys == NULL)) {
1725 return NULL;
1728 p_upd_sys->p_overlay = p_ov;
1730 subpicture_updater_t updater = {
1731 .pf_validate = subpictureUpdaterValidate,
1732 .pf_update = subpictureUpdaterUpdate,
1733 .pf_destroy = subpictureUpdaterDestroy,
1734 .p_sys = p_upd_sys,
1737 subpicture_t *p_pic = subpicture_New(&updater);
1738 if (p_pic == NULL) {
1739 free(p_upd_sys);
1740 return NULL;
1743 p_pic->i_original_picture_width = p_ov->width;
1744 p_pic->i_original_picture_height = p_ov->height;
1745 p_pic->b_absolute = true;
1747 vlc_mutex_init(&p_upd_sys->lock);
1748 p_upd_sys->ref_cnt = 2;
1750 p_ov->p_updater = p_upd_sys;
1752 return p_pic;
1755 /*****************************************************************************
1756 * User input events:
1757 *****************************************************************************/
1758 static void onMouseEvent(const vlc_mouse_t *newmouse, void *user_data)
1760 demux_t *p_demux = user_data;
1761 demux_sys_t *p_sys = p_demux->p_sys;
1763 if (!newmouse) {
1764 vlc_mouse_Init(&p_sys->oldmouse);
1765 return;
1768 if (vlc_mouse_HasMoved(&p_sys->oldmouse, newmouse))
1769 bd_mouse_select(p_sys->bluray, -1, newmouse->i_x, newmouse->i_y);
1771 if (vlc_mouse_HasPressed( &p_sys->oldmouse, newmouse, MOUSE_BUTTON_LEFT))
1772 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1773 p_sys->oldmouse = *newmouse;
1776 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1778 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1779 return VLC_EGENERIC;
1781 return VLC_SUCCESS;
1784 /*****************************************************************************
1785 * libbluray overlay handling:
1786 *****************************************************************************/
1788 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1790 demux_sys_t *p_sys = p_demux->p_sys;
1791 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1793 if (ov != NULL) {
1795 /* drop overlay from vout */
1796 if (ov->p_updater) {
1797 unref_subpicture_updater(ov->p_updater);
1800 /* no references to this overlay exist in vo anymore */
1801 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY, plane);
1803 vlc_mutex_destroy(&ov->lock);
1804 subpicture_region_ChainDelete(ov->p_regions);
1805 free(ov);
1807 p_sys->bdj.p_overlays[plane] = NULL;
1812 * Mark the overlay as "ToDisplay" status.
1813 * This will not send the overlay to the vout instantly, as the vout
1814 * may not be acquired (not acquirable) yet.
1815 * If is has already been acquired, the overlay has already been sent to it,
1816 * therefore, we only flag the overlay as "Outdated"
1818 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1820 demux_sys_t *p_sys = p_demux->p_sys;
1821 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1824 * If the overlay is already displayed, mark the picture as outdated.
1825 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1827 vlc_mutex_lock(&ov->lock);
1828 if (ov->status >= Displayed && ov->b_on_vout) {
1829 ov->status = Outdated;
1830 vlc_mutex_unlock(&ov->lock);
1831 return;
1835 * Mark the overlay as available, but don't display it right now.
1836 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1837 * the overlay is computed
1839 ov->status = ToDisplay;
1840 vlc_mutex_unlock(&ov->lock);
1843 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1845 demux_sys_t *p_sys = p_demux->p_sys;
1847 assert(p_sys->bdj.p_overlays[plane] == NULL);
1849 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1850 if (unlikely(ov == NULL))
1851 return;
1853 ov->width = width;
1854 ov->height = height;
1855 ov->b_on_vout = false;
1857 vlc_mutex_init(&ov->lock);
1859 p_sys->bdj.p_overlays[plane] = ov;
1863 * Destroy every regions in the subpicture.
1864 * This is done in two steps:
1865 * - Wiping our private regions list
1866 * - Flagging the overlay as outdated, so the changes are replicated from
1867 * the subpicture_updater_t::pf_update
1868 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1870 static void blurayClearOverlay(demux_t *p_demux, int plane)
1872 demux_sys_t *p_sys = p_demux->p_sys;
1873 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1875 vlc_mutex_lock(&ov->lock);
1877 subpicture_region_ChainDelete(ov->p_regions);
1878 ov->p_regions = NULL;
1879 ov->status = Outdated;
1881 vlc_mutex_unlock(&ov->lock);
1885 * This will draw to the overlay by adding a region to our region list
1886 * This will have to be copied to the subpicture used to render the overlay.
1888 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1890 demux_sys_t *p_sys = p_demux->p_sys;
1893 * Compute a subpicture_region_t.
1894 * It will be copied and sent to the vout later.
1896 vlc_mutex_lock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1898 /* Find a region to update */
1899 subpicture_region_t **pp_reg = &p_sys->bdj.p_overlays[ov->plane]->p_regions;
1900 subpicture_region_t *p_reg = p_sys->bdj.p_overlays[ov->plane]->p_regions;
1901 subpicture_region_t *p_last = NULL;
1902 while (p_reg != NULL) {
1903 p_last = p_reg;
1904 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1905 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1906 break;
1907 pp_reg = &p_reg->p_next;
1908 p_reg = p_reg->p_next;
1911 if (!ov->img) {
1912 if (p_reg) {
1913 /* drop region */
1914 *pp_reg = p_reg->p_next;
1915 subpicture_region_Delete(p_reg);
1917 vlc_mutex_unlock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1918 return;
1921 /* If there is no region to update, create a new one. */
1922 if (!p_reg) {
1923 video_format_t fmt;
1924 video_format_Init(&fmt, 0);
1925 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1927 p_reg = subpicture_region_New(&fmt);
1928 if (p_reg) {
1929 p_reg->i_x = ov->x;
1930 p_reg->i_y = ov->y;
1931 /* Append it to our list. */
1932 if (p_last != NULL)
1933 p_last->p_next = p_reg;
1934 else /* If we don't have a last region, then our list empty */
1935 p_sys->bdj.p_overlays[ov->plane]->p_regions = p_reg;
1939 /* Now we can update the region, regardless it's an update or an insert */
1940 const BD_PG_RLE_ELEM *img = ov->img;
1941 for (int y = 0; y < ov->h; y++)
1942 for (int x = 0; x < ov->w;) {
1943 plane_t *p = &p_reg->p_picture->p[0];
1944 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1945 x += img->len;
1946 img++;
1949 if (ov->palette) {
1950 p_reg->fmt.p_palette->i_entries = 256;
1951 for (int i = 0; i < 256; ++i) {
1952 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1953 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1954 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1955 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1959 vlc_mutex_unlock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1961 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1965 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1967 demux_t *p_demux = (demux_t*)ptr;
1968 demux_sys_t *p_sys = p_demux->p_sys;
1970 vlc_mutex_lock(&p_sys->bdj.lock);
1972 if (!overlay) {
1973 msg_Info(p_demux, "Closing overlays.");
1974 for (int i = 0; i < MAX_OVERLAY; i++)
1975 blurayCloseOverlay(p_demux, i);
1976 vlc_mutex_unlock(&p_sys->bdj.lock);
1977 return;
1980 switch (overlay->cmd) {
1981 case BD_OVERLAY_INIT:
1982 msg_Info(p_demux, "Initializing overlay");
1983 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1984 break;
1985 case BD_OVERLAY_CLOSE:
1986 blurayClearOverlay(p_demux, overlay->plane);
1987 blurayCloseOverlay(p_demux, overlay->plane);
1988 break;
1989 case BD_OVERLAY_CLEAR:
1990 blurayClearOverlay(p_demux, overlay->plane);
1991 break;
1992 case BD_OVERLAY_FLUSH:
1993 blurayActivateOverlay(p_demux, overlay->plane);
1994 break;
1995 case BD_OVERLAY_DRAW:
1996 case BD_OVERLAY_WIPE:
1997 blurayDrawOverlay(p_demux, overlay);
1998 break;
1999 default:
2000 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
2001 break;
2004 vlc_mutex_unlock(&p_sys->bdj.lock);
2008 * ARGB overlay (BD-J)
2010 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
2012 blurayInitOverlay(p_demux, plane, width, height);
2015 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
2017 demux_sys_t *p_sys = p_demux->p_sys;
2019 bluray_overlay_t *bdov = p_sys->bdj.p_overlays[ov->plane];
2020 vlc_mutex_lock(&bdov->lock);
2022 if (!bdov->p_regions)
2024 video_format_t fmt;
2025 video_format_Init(&fmt, 0);
2026 video_format_Setup(&fmt,
2027 /* ARGB in word order -> byte order */
2028 #ifdef WORDS_BIG_ENDIAN
2029 VLC_CODEC_ARGB,
2030 #else
2031 VLC_CODEC_BGRA,
2032 #endif
2033 ov->stride, bdov->height,
2034 bdov->width, bdov->height, 1, 1);
2035 bdov->p_regions = subpicture_region_New(&fmt);
2038 /* Find a region to update */
2039 subpicture_region_t *p_reg = bdov->p_regions;
2040 if (!p_reg) {
2041 vlc_mutex_unlock(&bdov->lock);
2042 return;
2045 /* Now we can update the region */
2046 const uint32_t *src0 = ov->argb;
2047 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
2048 p_reg->p_picture->p[0].i_pitch * ov->y +
2049 ov->x * 4;
2051 for (int y = 0; y < ov->h; y++)
2053 memcpy(dst0, src0, ov->w * 4);
2054 src0 += ov->stride;
2055 dst0 += p_reg->p_picture->p[0].i_pitch;
2058 vlc_mutex_unlock(&bdov->lock);
2060 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
2064 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
2066 demux_t *p_demux = (demux_t*)ptr;
2067 demux_sys_t *p_sys = p_demux->p_sys;
2069 switch (overlay->cmd) {
2070 case BD_ARGB_OVERLAY_INIT:
2071 vlc_mutex_lock(&p_sys->bdj.lock);
2072 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
2073 vlc_mutex_unlock(&p_sys->bdj.lock);
2074 break;
2075 case BD_ARGB_OVERLAY_CLOSE:
2076 vlc_mutex_lock(&p_sys->bdj.lock);
2077 blurayClearOverlay(p_demux, overlay->plane);
2078 blurayCloseOverlay(p_demux, overlay->plane);
2079 vlc_mutex_unlock(&p_sys->bdj.lock);
2080 break;
2081 case BD_ARGB_OVERLAY_FLUSH:
2082 blurayActivateOverlay(p_demux, overlay->plane);
2083 break;
2084 case BD_ARGB_OVERLAY_DRAW:
2085 blurayDrawArgbOverlay(p_demux, overlay);
2086 break;
2087 default:
2088 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
2089 break;
2093 static void bluraySendOverlayToVout(demux_t *p_demux, int plane, bluray_overlay_t *p_ov)
2095 demux_sys_t *p_sys = p_demux->p_sys;
2097 assert(p_ov != NULL);
2098 assert(!p_ov->b_on_vout);
2100 if (p_ov->p_updater) {
2101 unref_subpicture_updater(p_ov->p_updater);
2102 p_ov->p_updater = NULL;
2105 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
2106 if (!p_pic) {
2107 msg_Err(p_demux, "bluraySubpictureCreate() failed");
2108 return;
2112 * After this point, the picture should not be accessed from the demux thread,
2113 * as it is held by the vout thread.
2114 * This must be done only once per subpicture, ie. only once between each
2115 * blurayInitOverlay & blurayCloseOverlay call.
2117 int ret = es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY,
2118 plane, p_pic);
2119 if (ret != VLC_SUCCESS)
2121 unref_subpicture_updater(p_ov->p_updater);
2122 p_ov->p_updater = NULL;
2123 p_ov->b_on_vout = false;
2124 subpicture_Delete(p_pic);
2125 return;
2127 p_ov->b_on_vout = true;
2130 * Mark the picture as Outdated, as it contains no region for now.
2131 * This will make the subpicture_updater_t call pf_update
2133 p_ov->status = Outdated;
2136 static bool blurayTitleIsRepeating(BLURAY_TITLE_INFO *title_info,
2137 unsigned repeats, unsigned ratio)
2139 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(1, 0, 0)
2140 const BLURAY_CLIP_INFO *prev = NULL;
2141 unsigned maxrepeats = 0;
2142 unsigned sequence = 0;
2143 if(!title_info->chapter_count)
2144 return false;
2146 for (unsigned int j = 0; j < title_info->chapter_count; j++)
2148 unsigned i = title_info->chapters[j].clip_ref;
2149 if(i < title_info->clip_count)
2151 if(prev == NULL ||
2152 /* non repeated does not need start time offset */
2153 title_info->clips[i].start_time == 0 ||
2154 /* repeats occurs on same segment */
2155 memcmp(title_info->clips[i].clip_id, prev->clip_id, 6) ||
2156 prev->in_time != title_info->clips[i].in_time ||
2157 prev->pkt_count != title_info->clips[i].pkt_count)
2159 sequence = 0;
2160 prev = &title_info->clips[i];
2161 continue;
2163 else
2165 if(maxrepeats < sequence++)
2166 maxrepeats = sequence;
2170 return (maxrepeats > repeats &&
2171 (100 * maxrepeats / title_info->chapter_count) >= ratio);
2172 #else
2173 return false;
2174 #endif
2177 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
2179 t->i_length = FROM_SCALE_NZ(title_info->duration);
2181 for (int i = 0; i < t->i_seekpoint; i++)
2182 vlc_seekpoint_Delete( t->seekpoint[i] );
2183 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
2185 /* FIXME: have libbluray expose repeating titles */
2186 if(blurayTitleIsRepeating(title_info, 50, 90))
2187 return;
2189 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
2190 seekpoint_t *s = vlc_seekpoint_New();
2191 if (!s) {
2192 break;
2194 s->i_time_offset = FROM_SCALE_NZ(title_info->chapters[j].start);
2196 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
2200 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles)
2202 demux_sys_t *p_sys = p_demux->p_sys;
2203 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2205 /* get and set the titles */
2206 uint32_t i_title = menu_titles;
2208 if (!p_sys->b_menu) {
2209 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
2210 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
2213 for (uint32_t i = 0; i < i_title; i++) {
2214 input_title_t *t = vlc_input_title_New();
2215 if (!t)
2216 break;
2218 if (!p_sys->b_menu) {
2219 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
2220 blurayUpdateTitleInfo(t, title_info);
2221 bd_free_title_info(title_info);
2223 } else if (i == 0) {
2224 t->psz_name = strdup(_("Top Menu"));
2225 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
2226 } else if (i == i_title - 1) {
2227 t->psz_name = strdup(_("First Play"));
2228 if (di && di->first_play && di->first_play->interactive) {
2229 t->i_flags = INPUT_TITLE_INTERACTIVE;
2231 } else {
2232 /* add possible title name from disc metadata */
2233 if (di && di->titles && i <= di->num_titles) {
2234 if (di->titles[i]->name) {
2235 t->psz_name = strdup(di->titles[i]->name);
2237 if (di->titles[i]->interactive) {
2238 t->i_flags = INPUT_TITLE_INTERACTIVE;
2243 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
2247 static void blurayRestartParser(demux_t *p_demux, bool b_flush, bool b_random_access)
2250 * This is a hack and will have to be removed.
2251 * The parser should be flushed, and not destroy/created each time
2252 * we are changing title.
2254 demux_sys_t *p_sys = p_demux->p_sys;
2256 if(b_flush)
2257 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
2259 if (p_sys->p_parser)
2260 vlc_demux_chained_Delete(p_sys->p_parser);
2262 if(b_flush)
2263 es_out_Control(p_sys->p_tf_out, ES_OUT_TF_FILTER_RESET);
2265 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
2266 if (!p_sys->p_parser)
2267 msg_Err(p_demux, "Failed to create TS demuxer");
2269 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT);
2271 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS, b_random_access);
2274 /*****************************************************************************
2275 * bluraySetTitle: select new BD title
2276 *****************************************************************************/
2277 static int bluraySetTitle(demux_t *p_demux, int i_title)
2279 demux_sys_t *p_sys = p_demux->p_sys;
2281 if (p_sys->b_menu) {
2282 int result;
2283 if (i_title <= 0) {
2284 msg_Dbg(p_demux, "Playing TopMenu Title");
2285 result = bd_menu_call(p_sys->bluray, -1);
2286 } else if (i_title >= (int)p_sys->i_title - 1) {
2287 msg_Dbg(p_demux, "Playing FirstPlay Title");
2288 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
2289 } else {
2290 msg_Dbg(p_demux, "Playing Title %i", i_title);
2291 result = bd_play_title(p_sys->bluray, i_title);
2294 if (result == 0) {
2295 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
2296 return VLC_EGENERIC;
2299 return VLC_SUCCESS;
2302 /* Looking for the main title, ie the longest duration */
2303 if (i_title < 0)
2304 i_title = p_sys->i_longest_title;
2305 else if ((unsigned)i_title > p_sys->i_title)
2306 return VLC_EGENERIC;
2308 msg_Dbg(p_demux, "Selecting Title %i", i_title);
2310 if (bd_select_title(p_sys->bluray, i_title) == 0) {
2311 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
2312 return VLC_EGENERIC;
2315 return VLC_SUCCESS;
2318 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
2319 # define BLURAY_AUDIO_STREAM 0
2320 #endif
2322 static void blurayOnUserStreamSelection(demux_sys_t *p_sys, int i_pid)
2324 vlc_mutex_lock(&p_sys->pl_info_lock);
2326 if(i_pid == -AUDIO_ES)
2327 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, 0, 0);
2328 else if(i_pid == -SPU_ES)
2329 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, 0, 0);
2330 else if (p_sys->p_clip_info)
2333 if ((i_pid & 0xff00) == 0x1100) {
2334 // audio
2335 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
2336 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
2337 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
2338 if(!p_sys->b_menu)
2339 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG,
2340 (const char *) p_sys->p_clip_info->audio_streams[i_id].lang);
2341 break;
2344 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
2345 // subtitle
2346 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
2347 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
2348 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
2349 if(!p_sys->b_menu)
2350 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG,
2351 (const char *) p_sys->p_clip_info->pg_streams[i_id].lang);
2352 break;
2358 vlc_mutex_unlock(&p_sys->pl_info_lock);
2361 /*****************************************************************************
2362 * blurayControl: handle the controls
2363 *****************************************************************************/
2364 static int blurayControl(demux_t *p_demux, int query, va_list args)
2366 demux_sys_t *p_sys = p_demux->p_sys;
2367 bool *pb_bool;
2369 switch (query) {
2370 case DEMUX_CAN_SEEK:
2371 case DEMUX_CAN_PAUSE:
2372 case DEMUX_CAN_CONTROL_PACE:
2373 pb_bool = va_arg(args, bool *);
2374 *pb_bool = true;
2375 break;
2377 case DEMUX_GET_PTS_DELAY:
2378 *va_arg(args, vlc_tick_t *) =
2379 VLC_TICK_FROM_MS(var_InheritInteger(p_demux, "disc-caching"));
2380 break;
2382 case DEMUX_SET_PAUSE_STATE:
2384 #ifdef BLURAY_RATE_NORMAL
2385 bool b_paused = (bool)va_arg(args, int);
2386 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
2387 return VLC_EGENERIC;
2389 #endif
2390 break;
2392 case DEMUX_SET_ES:
2394 int i_id = va_arg(args, int);
2395 blurayOnUserStreamSelection(p_sys, i_id);
2396 break;
2398 case DEMUX_SET_TITLE:
2400 int i_title = va_arg(args, int);
2401 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
2402 /* make sure GUI restores the old setting in title menu ... */
2403 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2404 return VLC_EGENERIC;
2406 blurayRestartParser(p_demux, true, false);
2407 notifyDiscontinuityToParser(p_sys);
2408 p_sys->b_draining = false;
2409 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
2410 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2411 break;
2413 case DEMUX_SET_SEEKPOINT:
2415 int i_chapter = va_arg(args, int);
2416 bd_seek_chapter(p_sys->bluray, i_chapter);
2417 blurayRestartParser(p_demux, true, false);
2418 notifyDiscontinuityToParser(p_sys);
2419 p_sys->b_draining = false;
2420 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
2421 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2422 break;
2424 case DEMUX_TEST_AND_CLEAR_FLAGS:
2426 unsigned *restrict flags = va_arg(args, unsigned *);
2427 *flags &= p_sys->updates;
2428 p_sys->updates &= ~*flags;
2429 break;
2431 case DEMUX_GET_TITLE:
2432 *va_arg(args, int *) = p_sys->cur_title;
2433 break;
2435 case DEMUX_GET_SEEKPOINT:
2436 *va_arg(args, int *) = p_sys->cur_seekpoint;
2437 break;
2439 case DEMUX_GET_TITLE_INFO:
2441 input_title_t ***ppp_title = va_arg(args, input_title_t***);
2442 int *pi_int = va_arg(args, int *);
2443 int *pi_title_offset = va_arg(args, int *);
2444 int *pi_chapter_offset = va_arg(args, int *);
2446 /* */
2447 *pi_title_offset = 0;
2448 *pi_chapter_offset = 0;
2450 /* Duplicate local title infos */
2451 *pi_int = 0;
2452 *ppp_title = vlc_alloc(p_sys->i_title, sizeof(input_title_t *));
2453 if(!*ppp_title)
2454 return VLC_EGENERIC;
2455 for (unsigned int i = 0; i < p_sys->i_title; i++)
2457 input_title_t *p_dup = vlc_input_title_Duplicate(p_sys->pp_title[i]);
2458 if(p_dup)
2459 (*ppp_title)[(*pi_int)++] = p_dup;
2462 return VLC_SUCCESS;
2465 case DEMUX_GET_LENGTH:
2467 if(p_sys->cur_title < p_sys->i_title &&
2468 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2469 return VLC_EGENERIC;
2470 *va_arg(args, vlc_tick_t *) = p_sys->cur_title < p_sys->i_title ? CUR_LENGTH : 0;
2471 return VLC_SUCCESS;
2473 case DEMUX_SET_TIME:
2475 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(va_arg(args, vlc_tick_t)));
2476 blurayRestartParser(p_demux, true, true);
2477 notifyDiscontinuityToParser(p_sys);
2478 p_sys->b_draining = false;
2479 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2480 return VLC_SUCCESS;
2482 case DEMUX_GET_TIME:
2484 vlc_tick_t *pi_time = va_arg(args, vlc_tick_t *);
2485 if(p_sys->cur_title < p_sys->i_title &&
2486 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2487 return VLC_EGENERIC;
2488 *pi_time = FROM_SCALE_NZ(bd_tell_time(p_sys->bluray));
2489 return VLC_SUCCESS;
2492 case DEMUX_GET_POSITION:
2494 double *pf_position = va_arg(args, double *);
2495 if(p_sys->cur_title < p_sys->i_title &&
2496 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2497 return VLC_EGENERIC;
2498 *pf_position = p_sys->cur_title < p_sys->i_title && CUR_LENGTH > 0 ?
2499 (double)FROM_SCALE_NZ(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
2500 return VLC_SUCCESS;
2502 case DEMUX_SET_POSITION:
2504 double f_position = va_arg(args, double);
2505 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(f_position*CUR_LENGTH));
2506 blurayRestartParser(p_demux, true, true);
2507 notifyDiscontinuityToParser(p_sys);
2508 p_sys->b_draining = false;
2509 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2510 return VLC_SUCCESS;
2513 case DEMUX_GET_META:
2515 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
2516 const META_DL *meta = p_sys->p_meta;
2517 if (meta == NULL)
2518 return VLC_EGENERIC;
2520 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
2522 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
2523 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
2524 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
2526 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
2527 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
2529 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
2530 char psz_url[128];
2531 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
2532 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
2533 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
2535 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
2536 char *psz_thumbpath;
2537 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
2538 p_sys->psz_bd_path, meta->thumbnails[0].path) > -1) {
2539 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
2540 free(psz_thumbpath);
2541 if (unlikely(psz_thumburl == NULL))
2542 return VLC_ENOMEM;
2544 vlc_meta_SetArtURL(p_meta, psz_thumburl);
2545 free(psz_thumburl);
2549 return VLC_SUCCESS;
2552 case DEMUX_GET_ATTACHMENTS:
2554 input_attachment_t ***ppp_attach =
2555 va_arg(args, input_attachment_t ***);
2556 int *pi_int = va_arg(args, int *);
2558 if (p_sys->i_attachments <= 0)
2559 return VLC_EGENERIC;
2561 *pi_int = 0;
2562 *ppp_attach = vlc_alloc(p_sys->i_attachments, sizeof(input_attachment_t *));
2563 if(!*ppp_attach)
2564 return VLC_EGENERIC;
2565 for (int i = 0; i < p_sys->i_attachments; i++)
2567 input_attachment_t *p_dup = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
2568 if(p_dup)
2569 (*ppp_attach)[(*pi_int)++] = p_dup;
2571 return VLC_SUCCESS;
2574 case DEMUX_NAV_ACTIVATE:
2575 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
2576 return sendKeyEvent(p_sys, BD_VK_POPUP);
2578 return sendKeyEvent(p_sys, BD_VK_ENTER);
2579 case DEMUX_NAV_UP:
2580 return sendKeyEvent(p_sys, BD_VK_UP);
2581 case DEMUX_NAV_DOWN:
2582 return sendKeyEvent(p_sys, BD_VK_DOWN);
2583 case DEMUX_NAV_LEFT:
2584 return sendKeyEvent(p_sys, BD_VK_LEFT);
2585 case DEMUX_NAV_RIGHT:
2586 return sendKeyEvent(p_sys, BD_VK_RIGHT);
2587 case DEMUX_NAV_POPUP:
2588 return sendKeyEvent(p_sys, BD_VK_POPUP);
2589 case DEMUX_NAV_MENU:
2590 if (p_sys->b_menu) {
2591 if (bd_menu_call(p_sys->bluray, -1) == 1) {
2592 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2593 return VLC_SUCCESS;
2595 msg_Err(p_demux, "Can't select Top Menu title");
2596 return sendKeyEvent(p_sys, BD_VK_POPUP);
2598 return VLC_EGENERIC;
2600 case DEMUX_CAN_RECORD:
2601 case DEMUX_GET_FPS:
2602 case DEMUX_SET_GROUP_DEFAULT:
2603 case DEMUX_SET_GROUP_ALL:
2604 case DEMUX_SET_GROUP_LIST:
2605 case DEMUX_HAS_UNSUPPORTED_META:
2606 default:
2607 return VLC_EGENERIC;
2609 return VLC_SUCCESS;
2612 /*****************************************************************************
2613 * libbluray event handling
2614 *****************************************************************************/
2615 static void writeTsPacketWDiscontinuity( uint8_t *p_buf, uint16_t i_pid,
2616 const uint8_t *p_payload, uint8_t i_payload )
2618 uint8_t ts_header[] = {
2619 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2620 0x47,
2621 0x40 | ((i_pid & 0x1f00) >> 8), i_pid & 0xFF, /* PUSI + PID */
2622 i_payload ? 0x30 : 0x20, /* adaptation field, payload / no payload */
2623 192 - (4 + 5) - i_payload, /* adaptation field length */
2624 0x82, /* af: discontinuity indicator + priv data */
2625 0x0E, /* priv data size */
2626 'V', 'L', 'C', '_',
2627 'D', 'I', 'S', 'C', 'O', 'N', 'T', 'I', 'N', 'U',
2630 memcpy( p_buf, ts_header, sizeof(ts_header) );
2631 memset( &p_buf[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header) - i_payload );
2632 if( i_payload )
2633 memcpy( &p_buf[192 - i_payload], p_payload, i_payload );
2636 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
2637 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
2639 for( size_t i=0; i< i_sinfo; i++ )
2641 const uint16_t i_pid = p_sinfo[i].pid;
2643 block_t *p_block = block_Alloc(192);
2644 if (!p_block)
2645 return;
2647 writeTsPacketWDiscontinuity( p_block->p_buffer, i_pid, NULL, 0 );
2649 vlc_demux_chained_Send(p_parser, p_block);
2653 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2654 p_clip->memb##_stream_count )
2656 static void notifyDiscontinuityToParser( demux_sys_t *p_sys )
2658 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2659 if( p_clip )
2661 DONOTIFY(audio);
2662 DONOTIFY(video);
2663 DONOTIFY(pg);
2664 DONOTIFY(ig);
2665 DONOTIFY(sec_audio);
2666 DONOTIFY(sec_video);
2670 #undef DONOTIFY
2672 static void streamFlush( demux_sys_t *p_sys )
2675 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2676 * Packet is flushed only when TS packet with PUSI flag set is received.
2678 * Fix this by emitting (video) ts packet with PUSI flag set.
2679 * Add video sequence end code to payload so that also video decoder is flushed.
2680 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2683 if (p_sys->b_flushed)
2684 return;
2686 block_t *p_block = block_Alloc(192);
2687 if (!p_block)
2688 return;
2690 bd_stream_type_e i_coding_type;
2692 /* set correct sequence end code */
2693 vlc_mutex_lock(&p_sys->pl_info_lock);
2694 if (p_sys->p_clip_info != NULL)
2695 i_coding_type = p_sys->p_clip_info->video_streams[0].coding_type;
2696 else
2697 i_coding_type = 0;
2698 vlc_mutex_unlock(&p_sys->pl_info_lock);
2700 uint8_t i_eos;
2701 switch( i_coding_type )
2703 case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
2704 case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
2705 default:
2706 i_eos = 0xB7; /* MPEG2 sequence end */
2707 break;
2708 case BLURAY_STREAM_TYPE_VIDEO_VC1:
2709 case BLURAY_STREAM_TYPE_VIDEO_H264:
2710 i_eos = 0x0A; /* VC1 / H.264 sequence end */
2711 break;
2712 case BD_STREAM_TYPE_VIDEO_HEVC:
2713 i_eos = 0x48; /* HEVC sequence end NALU */
2714 break;
2717 uint8_t seq_end_pes[] = {
2718 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2719 0x00, 0x00, 0x01, i_eos, /* PES payload: sequence end */
2720 0x00, /* 2nd byte for HEVC NAL, pads others */
2723 writeTsPacketWDiscontinuity( p_block->p_buffer, 0x1011, seq_end_pes, sizeof(seq_end_pes) );
2725 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2726 p_sys->b_flushed = true;
2729 static void blurayResetStillImage( demux_t *p_demux )
2731 demux_sys_t *p_sys = p_demux->p_sys;
2733 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET) {
2734 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
2736 blurayRestartParser(p_demux, false, false);
2737 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2741 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2743 demux_sys_t *p_sys = p_demux->p_sys;
2745 /* time period elapsed ? */
2746 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET &&
2747 p_sys->i_still_end_time != STILL_IMAGE_INFINITE &&
2748 p_sys->i_still_end_time <= vlc_tick_now()) {
2749 msg_Dbg(p_demux, "Still image end");
2750 bd_read_skip_still(p_sys->bluray);
2752 blurayResetStillImage(p_demux);
2753 return;
2756 /* show last frame as still image */
2757 if (p_sys->i_still_end_time == STILL_IMAGE_NOT_SET) {
2758 if (i_timeout) {
2759 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2760 p_sys->i_still_end_time = vlc_tick_now() + vlc_tick_from_sec( i_timeout );
2761 } else {
2762 msg_Dbg(p_demux, "Still image (infinite)");
2763 p_sys->i_still_end_time = STILL_IMAGE_INFINITE;
2766 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2767 streamFlush(p_sys);
2769 /* stop buffering */
2770 bool b_empty;
2771 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2774 /* avoid busy loops (read returns no data) */
2775 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2778 static void blurayOnStreamSelectedEvent(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2780 demux_sys_t *p_sys = p_demux->p_sys;
2781 int i_pid = -1;
2783 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2784 i_id--;
2786 if (i_type == BD_EVENT_AUDIO_STREAM) {
2787 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2788 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2789 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2792 if (i_pid > 0)
2794 if (i_type == BD_EVENT_PG_TEXTST_STREAM && !p_sys->b_spu_enable)
2795 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID, (int)i_type, i_pid);
2796 else
2797 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID, (int)i_type, i_pid);
2801 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2803 demux_sys_t *p_sys = p_demux->p_sys;
2805 blurayRestartParser(p_demux, true, false);
2807 /* read title info and init some values */
2808 if (!p_sys->b_menu)
2809 p_sys->cur_title = bd_get_current_title(p_sys->bluray);
2810 p_sys->cur_seekpoint = 0;
2811 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2813 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2814 if (p_title_info) {
2815 blurayUpdateTitleInfo(p_sys->pp_title[p_sys->cur_title], p_title_info);
2816 if (p_sys->b_menu)
2817 p_sys->updates |= INPUT_UPDATE_TITLE_LIST;
2819 setTitleInfo(p_sys, p_title_info);
2821 blurayResetStillImage(p_demux);
2824 static void blurayOnClipUpdate(demux_t *p_demux, uint32_t clip)
2826 demux_sys_t *p_sys = p_demux->p_sys;
2828 vlc_mutex_lock(&p_sys->pl_info_lock);
2830 p_sys->p_clip_info = NULL;
2832 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2834 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2836 /* Let's assume a single video track for now.
2837 * This may brake later, but it's enough for now.
2839 assert(p_sys->p_clip_info->video_stream_count >= 1);
2842 CLPI_CL *clpi = bd_get_clpi(p_sys->bluray, clip);
2843 if(clpi && clpi->clip.application_type != p_sys->clip_application_type)
2845 if(p_sys->clip_application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW ||
2846 clpi->clip.application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW)
2847 blurayRestartParser(p_demux, false, false);
2849 if(clpi->clip.application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW)
2850 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY);
2851 else
2852 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY);
2853 bd_free_clpi(clpi);
2856 vlc_mutex_unlock(&p_sys->pl_info_lock);
2858 blurayResetStillImage(p_demux);
2861 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e, bool b_delayed)
2863 demux_sys_t *p_sys = p_demux->p_sys;
2865 blurayDebugEvent(e->event, e->param);
2867 switch (e->event) {
2868 case BD_EVENT_TITLE:
2869 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2870 p_sys->cur_title = p_sys->i_title - 1;
2871 else
2872 p_sys->cur_title = e->param;
2873 /* this is feature title, we don't know yet which playlist it will play (if any) */
2874 setTitleInfo(p_sys, NULL);
2875 /* reset title infos here ? */
2876 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2877 /* might be BD-J title with no video */
2878 break;
2879 case BD_EVENT_PLAYLIST:
2880 /* Start of playlist playback (?????.mpls) */
2881 blurayUpdatePlaylist(p_demux, e->param);
2882 if (p_sys->b_pl_playing) {
2883 /* previous playlist was stopped in middle. flush to avoid delay */
2884 msg_Info(p_demux, "Stopping playlist playback");
2885 blurayRestartParser(p_demux, false, false);
2886 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2888 p_sys->b_pl_playing = true;
2889 break;
2890 case BD_EVENT_PLAYITEM:
2891 notifyDiscontinuityToParser(p_sys);
2892 blurayOnClipUpdate(p_demux, e->param);
2893 break;
2894 case BD_EVENT_CHAPTER:
2895 if (e->param && e->param < 0xffff)
2896 p_sys->cur_seekpoint = e->param - 1;
2897 else
2898 p_sys->cur_seekpoint = 0;
2899 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2900 break;
2901 case BD_EVENT_PLAYMARK:
2902 case BD_EVENT_ANGLE:
2903 break;
2904 case BD_EVENT_SEEK:
2905 /* Seek will happen with any chapter/title or bd_seek(),
2906 but also BD-J initiated. We can't make the difference
2907 between input or vm ones, better double flush/pcr reset
2908 than break the clock by throwing post random access PCR */
2909 blurayRestartParser(p_demux, true, true);
2910 notifyDiscontinuityToParser(p_sys);
2911 es_out_Control(p_sys->p_out, ES_OUT_RESET_PCR);
2912 break;
2913 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2914 case BD_EVENT_UO_MASK_CHANGED:
2915 /* This event could be used to grey out unselectable items in title menu */
2916 break;
2917 #endif
2918 case BD_EVENT_MENU:
2919 p_sys->b_menu_open = e->param;
2920 break;
2921 case BD_EVENT_POPUP:
2922 p_sys->b_popup_available = e->param;
2923 /* TODO: show / hide pop-up menu button in gui ? */
2924 break;
2927 * Errors
2929 case BD_EVENT_ERROR:
2930 /* fatal error (with menus) */
2931 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2932 "Playback with BluRay menus failed");
2933 p_sys->b_fatal_error = true;
2934 break;
2935 case BD_EVENT_ENCRYPTED:
2936 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2937 "This disc seems to be encrypted");
2938 p_sys->b_fatal_error = true;
2939 break;
2940 case BD_EVENT_READ_ERROR:
2941 msg_Err(p_demux, "bluray: read error\n");
2942 break;
2945 * stream selection events
2947 case BD_EVENT_PG_TEXTST:
2948 p_sys->b_spu_enable = e->param;
2949 break;
2950 case BD_EVENT_AUDIO_STREAM:
2951 case BD_EVENT_PG_TEXTST_STREAM:
2952 if(b_delayed)
2953 blurayOnStreamSelectedEvent(p_demux, e->event, e->param);
2954 else
2955 ARRAY_APPEND(p_sys->events_delayed, *e);
2956 break;
2957 case BD_EVENT_IG_STREAM:
2958 case BD_EVENT_SECONDARY_AUDIO:
2959 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2960 case BD_EVENT_SECONDARY_VIDEO:
2961 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2962 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2963 break;
2966 * playback control events
2968 case BD_EVENT_STILL_TIME:
2969 blurayStillImage(p_demux, e->param);
2970 break;
2971 case BD_EVENT_DISCONTINUITY:
2972 /* reset demuxer (partially decoded PES packets must be dropped) */
2973 blurayRestartParser(p_demux, false, true);
2974 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2975 break;
2976 case BD_EVENT_END_OF_TITLE:
2977 if(p_sys->b_pl_playing)
2979 notifyDiscontinuityToParser(p_sys);
2980 blurayRestartParser(p_demux, false, false);
2981 p_sys->b_draining = true;
2982 p_sys->b_pl_playing = false;
2984 break;
2985 case BD_EVENT_IDLE:
2986 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2987 /* avoid busy loop (bd_read() returns no data) */
2988 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2989 break;
2991 default:
2992 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2993 break;
2997 static void blurayHandleOverlays(demux_t *p_demux)
2999 demux_sys_t *p_sys = p_demux->p_sys;
3000 vlc_mutex_lock(&p_sys->bdj.lock);
3002 for (int i = 0; i < MAX_OVERLAY; i++) {
3003 bluray_overlay_t *ov = p_sys->bdj.p_overlays[i];
3004 if (!ov) {
3005 continue;
3007 vlc_mutex_lock(&ov->lock);
3008 bool display = ov->status == ToDisplay;
3009 vlc_mutex_unlock(&ov->lock);
3010 if (display && !ov->b_on_vout)
3012 /* NOTE: we might want to enable background video always when there's no video stream playing.
3013 Now, with some discs, there are perioids (even seconds) during which the video window
3014 disappears and just playlist is shown.
3015 (sometimes BD-J runs slowly ...)
3017 bluraySendOverlayToVout(p_demux, i, ov);
3021 vlc_mutex_unlock(&p_sys->bdj.lock);
3024 static int blurayDemux(demux_t *p_demux)
3026 demux_sys_t *p_sys = p_demux->p_sys;
3027 BD_EVENT e;
3029 if(p_sys->b_draining)
3031 bool b_empty = false;
3032 if(es_out_Control(p_sys->p_out, ES_OUT_GET_EMPTY, &b_empty) != VLC_SUCCESS || b_empty)
3034 es_out_Control(p_sys->p_out, ES_OUT_RESET_PCR);
3035 p_sys->b_draining = false;
3037 else
3039 msg_Dbg(p_demux, "Draining...");
3040 vlc_tick_sleep(VLC_TICK_FROM_MS(40));
3041 return VLC_DEMUXER_SUCCESS;
3045 block_t *p_block = block_Alloc(BD_READ_SIZE);
3046 if (!p_block)
3047 return VLC_DEMUXER_EGENERIC;
3049 int nread;
3051 if (p_sys->b_menu == false) {
3052 nread = bd_read(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE);
3053 while (bd_get_event(p_sys->bluray, &e))
3054 blurayHandleEvent(p_demux, &e, false);
3055 } else {
3056 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE, &e);
3057 while (e.event != BD_EVENT_NONE) {
3058 blurayHandleEvent(p_demux, &e, false);
3059 bd_get_event(p_sys->bluray, &e);
3063 /* Process delayed selections events */
3064 for(int i=0; i<p_sys->events_delayed.i_size; i++)
3065 blurayHandleEvent(p_demux, &p_sys->events_delayed.p_elems[i], true);
3066 p_sys->events_delayed.i_size = 0;
3068 blurayHandleOverlays(p_demux);
3070 if (nread <= 0) {
3071 block_Release(p_block);
3072 if (p_sys->b_fatal_error || nread < 0) {
3073 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
3074 return VLC_DEMUXER_EGENERIC;
3076 if (!p_sys->b_menu) {
3077 return VLC_DEMUXER_EOF;
3079 return VLC_DEMUXER_SUCCESS;
3082 p_block->i_buffer = nread;
3084 vlc_demux_chained_Send(p_sys->p_parser, p_block);
3086 p_sys->b_flushed = false;
3088 return VLC_DEMUXER_SUCCESS;