access: bluray: workaround BDJO update checks
[vlc.git] / modules / access / bluray.c
blob6e8125f4c08f20ae2eb325681e3d36cb1355cb2b
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 for(uint8_t j=0; j<bdjo->app_table.num_app && !b_ret; j++)
180 for(size_t k=0; k<ARRAY_SIZE(rgsz_class_blacklist) && !b_ret; k++)
181 b_ret = (!strcmp(rgsz_class_blacklist[k],
182 bdjo->app_table.app[j].initial_class));
183 #ifdef DEBUG_BLURAY
184 if(b_ret)
185 msg_Warn("Found blacklisted class %s in %s", rgsz_class_blacklist[k],
186 ppsz_filenames[i]);
187 #else
188 VLC_UNUSED(p_demux);
189 #endif
190 bd_free_bdjo(bdjo);
192 free(psz_bdjo_file);
196 free(psz_bdjo_dir);
198 for( int i=0; i<i_files; i++ )
199 free(ppsz_filenames[i]);
200 free(ppsz_filenames);
202 return b_ret;
204 #else
205 # define BDJO_IsBlacklisted(foo, bar) (0)
206 #endif
208 /*****************************************************************************
209 * Module descriptor
210 *****************************************************************************/
212 #define BD_MENU_TEXT N_("Blu-ray menus")
213 #define BD_MENU_LONGTEXT N_("Use Blu-ray menus. If disabled, "\
214 "the movie will start directly")
215 #define BD_REGION_TEXT N_("Region code")
216 #define BD_REGION_LONGTEXT N_("Blu-Ray player region code. "\
217 "Some discs can be played only with a correct region code.")
219 static const char *const ppsz_region_code[] = {
220 "A", "B", "C" };
221 static const char *const ppsz_region_code_text[] = {
222 "Region A", "Region B", "Region C" };
224 #define REGION_DEFAULT 1 /* Index to region list. Actual region code is (1<<REGION_DEFAULT) */
225 #define LANGUAGE_DEFAULT ("eng")
227 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,0)
228 # define BLURAY_DEMUX
229 #endif
231 #ifndef BD_STREAM_TYPE_VIDEO_HEVC
232 # define BD_STREAM_TYPE_VIDEO_HEVC 0x24
233 #endif
235 #define BD_CLUSTER_SIZE 6144
236 #define BD_READ_SIZE (10 * BD_CLUSTER_SIZE)
238 /* Callbacks */
239 static int blurayOpen (vlc_object_t *);
240 static void blurayClose(vlc_object_t *);
242 vlc_module_begin ()
243 set_shortname(N_("Blu-ray"))
244 set_description(N_("Blu-ray Disc support (libbluray)"))
246 set_category(CAT_INPUT)
247 set_subcategory(SUBCAT_INPUT_ACCESS)
248 set_capability("access", 500)
249 add_bool("bluray-menu", true, BD_MENU_TEXT, BD_MENU_LONGTEXT, false)
250 add_string("bluray-region", ppsz_region_code[REGION_DEFAULT], BD_REGION_TEXT, BD_REGION_LONGTEXT, false)
251 change_string_list(ppsz_region_code, ppsz_region_code_text)
253 add_shortcut("bluray", "file")
255 set_callbacks(blurayOpen, blurayClose)
257 #ifdef BLURAY_DEMUX
258 /* demux module */
259 add_submodule()
260 set_description( "BluRay demuxer" )
261 set_category( CAT_INPUT )
262 set_subcategory( SUBCAT_INPUT_DEMUX )
263 set_capability( "demux", 5 )
264 set_callbacks( blurayOpen, blurayClose )
265 #endif
267 vlc_module_end ()
269 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
270 #define MAX_OVERLAY 2
272 typedef enum OverlayStatus {
273 Closed = 0,
274 ToDisplay, //Used to mark the overlay to be displayed the first time.
275 Displayed,
276 Outdated //used to update the overlay after it has been sent to the vout
277 } OverlayStatus;
279 typedef struct bluray_spu_updater_sys_t bluray_spu_updater_sys_t;
281 typedef struct bluray_overlay_t
283 vlc_mutex_t lock;
284 bool b_on_vout;
285 OverlayStatus status;
286 subpicture_region_t *p_regions;
287 int width, height;
289 /* pointer to last subpicture updater.
290 * used to disconnect this overlay from vout when:
291 * - the overlay is closed
292 * - vout is changed and this overlay is sent to the new vout
294 bluray_spu_updater_sys_t *p_updater;
295 } bluray_overlay_t;
297 typedef struct
299 BLURAY *bluray;
300 bool b_draining;
302 /* Titles */
303 unsigned int i_title;
304 unsigned int i_longest_title;
305 input_title_t **pp_title;
306 unsigned cur_title;
307 unsigned cur_seekpoint;
308 unsigned updates;
310 vlc_mutex_t pl_info_lock;
311 BLURAY_TITLE_INFO *p_pl_info;
312 const BLURAY_CLIP_INFO *p_clip_info;
313 enum
315 BD_CLIP_APP_TYPE_TS_MAIN_PATH_MOVIE = 1,
316 BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW = 2,
317 BD_CLIP_APP_TYPE_TS_MAIN_PATH_BROWSABLE_SLIDESHOW = 3,
318 BD_CLIP_APP_TYPE_TS_SUB_PATH_BROWSABLE_SLIDESHOW = 4,
319 BD_CLIP_APP_TYPE_TS_SUB_PATH_INTERACTIVE_MENU = 5,
320 BD_CLIP_APP_TYPE_TS_SUB_PATH_TEXT_SUBTITLE = 6,
321 BD_CLIP_APP_TYPE_TS_SUB_PATH_ELEMENTARY_STREAM_PATH = 7,
322 } clip_application_type;
324 /* Attachments */
325 int i_attachments;
326 input_attachment_t **attachments;
327 int i_cover_idx;
329 /* Meta information */
330 const META_DL *p_meta;
332 /* Menus */
333 bool b_fatal_error;
334 bool b_menu;
335 bool b_menu_open;
336 bool b_popup_available;
337 vlc_tick_t i_still_end_time;
338 struct
340 bluray_overlay_t *p_overlays[MAX_OVERLAY];
341 vlc_mutex_t lock; /* used to lock BD-J overlay open/close while overlays are being sent to vout */
342 } bdj;
344 /* */
345 vlc_mouse_t oldmouse;
347 /* TS stream */
348 es_out_t *p_tf_out;
349 es_out_t *p_out;
350 bool b_spu_enable; /* enabled / disabled */
351 vlc_demux_chained_t *p_parser;
352 bool b_flushed;
353 bool b_pl_playing; /* true when playing playlist */
355 /* stream input */
356 vlc_mutex_t read_block_lock;
358 /* Used to store bluray disc path */
359 char *psz_bd_path;
360 } demux_sys_t;
363 * Local ES index storage
365 typedef struct
367 es_format_t fmt;
368 es_out_id_t *p_es;
369 int i_next_block_flags;
370 bool b_recyling;
371 bool b_restart_decoders_on_reuse;
372 } es_pair_t;
374 static bool es_pair_Add(vlc_array_t *p_array, const es_format_t *p_fmt,
375 es_out_id_t *p_es)
377 es_pair_t *p_pair = malloc(sizeof(*p_pair));
378 if (likely(p_pair != NULL))
380 p_pair->p_es = p_es;
381 p_pair->i_next_block_flags = 0;
382 p_pair->b_recyling = false;
383 p_pair->b_restart_decoders_on_reuse = true;
384 if(vlc_array_append(p_array, p_pair) != VLC_SUCCESS)
386 free(p_pair);
387 p_pair = NULL;
389 else
391 es_format_Init(&p_pair->fmt, p_fmt->i_cat, p_fmt->i_codec);
392 es_format_Copy(&p_pair->fmt, p_fmt);
395 return p_pair != NULL;
398 static void es_pair_Remove(vlc_array_t *p_array, es_pair_t *p_pair)
400 vlc_array_remove(p_array, vlc_array_index_of_item(p_array, p_pair));
401 es_format_Clean(&p_pair->fmt);
402 free(p_pair);
405 static es_pair_t *getEsPair(vlc_array_t *p_array,
406 bool (*match)(const es_pair_t *, const void *),
407 const void *param)
409 for (size_t i = 0; i < vlc_array_count(p_array); ++i)
411 es_pair_t *p_pair = vlc_array_item_at_index(p_array, i);
412 if(match(p_pair, param))
413 return p_pair;
415 return NULL;
418 static bool es_pair_compare_PID(const es_pair_t *p_pair, const void *p_pid)
420 return p_pair->fmt.i_id == *((const int *)p_pid);
423 static bool es_pair_compare_ES(const es_pair_t *p_pair, const void *p_es)
425 return p_pair->p_es == (const es_out_id_t *)p_es;
428 static bool es_pair_compare_Unused(const es_pair_t *p_pair, const void *priv)
430 VLC_UNUSED(priv);
431 return p_pair->b_recyling;
434 static es_pair_t *getEsPairByPID(vlc_array_t *p_array, int i_pid)
436 return getEsPair(p_array, es_pair_compare_PID, &i_pid);
439 static es_pair_t *getEsPairByES(vlc_array_t *p_array, const es_out_id_t *p_es)
441 return getEsPair(p_array, es_pair_compare_ES, p_es);
444 static es_pair_t *getUnusedEsPair(vlc_array_t *p_array)
446 return getEsPair(p_array, es_pair_compare_Unused, 0);
450 * Subpicture updater
452 struct bluray_spu_updater_sys_t
454 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
455 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
456 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
460 * cut the connection between vout and overlay.
461 * - called when vout is closed or overlay is closed.
462 * - frees bluray_spu_updater_sys_t when both sides have been closed.
464 static void unref_subpicture_updater(bluray_spu_updater_sys_t *p_sys)
466 vlc_mutex_lock(&p_sys->lock);
467 int refs = --p_sys->ref_cnt;
468 p_sys->p_overlay = NULL;
469 vlc_mutex_unlock(&p_sys->lock);
471 if (refs < 1) {
472 vlc_mutex_destroy(&p_sys->lock);
473 free(p_sys);
477 /* Get a 3 char code
478 * FIXME: partiallyy duplicated from src/input/es_out.c
480 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
482 const iso639_lang_t *pl;
483 char *psz_lang;
484 char *p;
486 psz_lang = var_CreateGetString( p_demux, psz_var );
487 if( !psz_lang )
488 return LANGUAGE_DEFAULT;
490 /* XXX: we will use only the first value
491 * (and ignore other ones in case of a list) */
492 if( ( p = strchr( psz_lang, ',' ) ) )
493 *p = '\0';
495 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
497 if( *psz_lang == '\0' )
498 continue;
499 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
500 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
501 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
502 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
503 break;
506 free( psz_lang );
508 if( pl->psz_eng_name != NULL )
509 return pl->psz_iso639_2T;
511 return LANGUAGE_DEFAULT;
514 /*****************************************************************************
515 * Local prototypes
516 *****************************************************************************/
517 static es_out_t *esOutNew(vlc_object_t*, es_out_t *, void *);
519 static int blurayControl(demux_t *, int, va_list);
520 static int blurayDemux(demux_t *);
522 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles);
523 static int bluraySetTitle(demux_t *p_demux, int i_title);
525 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
526 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
527 static void blurayCloseOverlay(demux_t *p_demux, int plane);
529 static void onMouseEvent(const vlc_mouse_t *mouse, void *user_data);
530 static void blurayRestartParser(demux_t *p_demux, bool, bool);
531 static void notifyDiscontinuityToParser( demux_sys_t *p_sys );
533 #define STILL_IMAGE_NOT_SET 0
534 #define STILL_IMAGE_INFINITE -1
536 #define CURRENT_TITLE p_sys->pp_title[p_sys->cur_title]
537 #define CUR_LENGTH CURRENT_TITLE->i_length
539 /* */
540 static void FindMountPoint(char **file)
542 char *device = *file;
543 #if defined (HAVE_MNTENT_H) && defined (HAVE_SYS_STAT_H)
544 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
545 * we look up the real device */
546 char *bd_device = realpath(device, NULL);
547 if (bd_device == NULL)
548 return;
550 struct stat st;
551 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
552 FILE *mtab = setmntent ("/proc/self/mounts", "r");
553 if (mtab) {
554 struct mntent *m, mbuf;
555 char buf [8192];
557 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
558 if (!strcmp (m->mnt_fsname, bd_device)) {
559 free(device);
560 *file = strdup(m->mnt_dir);
561 break;
564 endmntent (mtab);
567 free(bd_device);
569 #elif defined(__APPLE__)
570 struct stat st;
571 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
572 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
573 if (fs_count > 0) {
574 struct statfs mbuf[128];
575 getfsstat (mbuf, fs_count * sizeof(mbuf[0]), MNT_NOWAIT);
576 for (int i = 0; i < fs_count; ++i)
577 if (!strcmp (mbuf[i].f_mntfromname, device)) {
578 free(device);
579 *file = strdup(mbuf[i].f_mntonname);
580 return;
584 #else
585 # warning Disc device to mount point not implemented
586 VLC_UNUSED( device );
587 #endif
590 /*****************************************************************************
591 * BD-J background video
592 *****************************************************************************/
594 static void bluraySendBackgroundImage(vlc_object_t *p_obj,
595 es_out_t *p_dst_out,
596 es_out_id_t *p_es,
597 const es_format_t *p_fmt)
599 msg_Info(p_obj, "Start background");
601 block_t *p_block = block_Alloc(p_fmt->video.i_width * p_fmt->video.i_height *
602 p_fmt->video.i_bits_per_pixel / 8);
603 if (!p_block) {
604 msg_Err(p_obj, "Error allocating block for background video");
605 return;
608 // XXX TODO: what would be correct timestamp ???
609 p_block->i_dts = p_block->i_pts = vlc_tick_now() + VLC_TICK_FROM_MS(40);
611 uint8_t *p = p_block->p_buffer;
612 memset(p, 0, p_fmt->video.i_width * p_fmt->video.i_height);
613 p += p_fmt->video.i_width * p_fmt->video.i_height;
614 memset(p, 0x80, p_fmt->video.i_width * p_fmt->video.i_height / 2);
616 es_out_SetPCR(p_dst_out, p_block->i_dts - VLC_TICK_FROM_MS(40));
617 es_out_Control(p_dst_out, ES_OUT_SET_ES, p_es);
618 es_out_Send(p_dst_out, p_es, p_block);
619 es_out_Control( p_dst_out, ES_OUT_VOUT_SET_MOUSE_EVENT, p_es, onMouseEvent, p_obj );
620 es_out_SetPCR(p_dst_out, p_block->i_dts);
623 /*****************************************************************************
624 * cache current playlist (title) information
625 *****************************************************************************/
627 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
629 vlc_mutex_lock(&p_sys->pl_info_lock);
631 if (p_sys->p_pl_info) {
632 bd_free_title_info(p_sys->p_pl_info);
634 p_sys->p_pl_info = info;
635 p_sys->p_clip_info = NULL;
637 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
638 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
641 vlc_mutex_unlock(&p_sys->pl_info_lock);
644 /*****************************************************************************
645 * create input attachment for thumbnail
646 *****************************************************************************/
648 static void attachThumbnail(demux_t *p_demux)
650 demux_sys_t *p_sys = p_demux->p_sys;
652 if (!p_sys->p_meta)
653 return;
655 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
656 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
657 int64_t size;
658 void *data;
659 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
660 char psz_name[64];
661 input_attachment_t *p_attachment;
663 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
665 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
666 if (p_attachment) {
667 p_sys->i_cover_idx = p_sys->i_attachments;
668 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
671 free(data);
673 #endif
676 /*****************************************************************************
677 * stream input
678 *****************************************************************************/
680 static int probeStream(demux_t *p_demux)
682 /* input must be seekable */
683 bool b_canseek = false;
684 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
685 if (!b_canseek) {
686 return VLC_EGENERIC;
689 /* first sector(s) should be filled with zeros */
690 size_t i_peek;
691 const uint8_t *p_peek;
692 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
693 if( i_peek != 2048 ) {
694 return VLC_EGENERIC;
696 while (i_peek > 0) {
697 if (p_peek[ --i_peek ]) {
698 return VLC_EGENERIC;
702 return VLC_SUCCESS;
705 #ifdef BLURAY_DEMUX
706 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
708 demux_t *p_demux = (demux_t*)object;
709 demux_sys_t *p_sys = p_demux->p_sys;
710 int result = -1;
712 assert(p_demux->s != NULL);
714 vlc_mutex_lock(&p_sys->read_block_lock);
716 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
717 size_t req = (size_t)2048 * num_blocks;
718 ssize_t got;
720 got = vlc_stream_Read( p_demux->s, buf, req);
721 if (got < 0) {
722 msg_Err(p_demux, "read from lba %d failed", lba);
723 } else {
724 result = got / 2048;
726 } else {
727 msg_Err(p_demux, "seek to lba %d failed", lba);
730 vlc_mutex_unlock(&p_sys->read_block_lock);
732 return result;
734 #endif
736 /*****************************************************************************
737 * probing of local files
738 *****************************************************************************/
740 /* Descriptor Tag (ECMA 167, 3/7.2) */
741 static int decode_descriptor_tag(const uint8_t *buf)
743 uint16_t id;
744 uint8_t checksum = 0;
745 int i;
747 id = buf[0] | (buf[1] << 8);
749 /* calculate tag checksum */
750 for (i = 0; i < 4; i++) {
751 checksum = (uint8_t)(checksum + buf[i]);
753 for (i = 5; i < 16; i++) {
754 checksum = (uint8_t)(checksum + buf[i]);
757 if (checksum != buf[4]) {
758 return -1;
761 return id;
764 static int probeFile(const char *psz_name)
766 struct stat stat_info;
767 uint8_t peek[2048];
768 unsigned i;
769 int ret = VLC_EGENERIC;
770 int fd;
772 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
773 if (fd == -1) {
774 return VLC_EGENERIC;
777 if (fstat(fd, &stat_info) == -1) {
778 goto bailout;
780 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
781 goto bailout;
784 /* first sector should be filled with zeros */
785 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
786 goto bailout;
788 for (i = 0; i < sizeof(peek); i++) {
789 if (peek[ i ]) {
790 goto bailout;
794 /* Check AVDP tag checksum */
795 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
796 read(fd, peek, 16) != 16 ||
797 decode_descriptor_tag(peek) != 2) {
798 goto bailout;
801 ret = VLC_SUCCESS;
803 bailout:
804 vlc_close(fd);
805 return ret;
808 /*****************************************************************************
809 * blurayOpen: module init function
810 *****************************************************************************/
811 static int blurayOpen(vlc_object_t *object)
813 demux_t *p_demux = (demux_t*)object;
814 demux_sys_t *p_sys;
815 bool forced;
816 uint64_t i_init_pos = 0;
818 const char *error_msg = NULL;
819 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
821 if (p_demux->out == NULL)
822 return VLC_EGENERIC;
824 forced = !strncasecmp(p_demux->psz_url, "bluray:", 7);
826 if (p_demux->s) {
827 if (!strncasecmp(p_demux->psz_url, "file:", 5)) {
828 /* use access_demux for local files */
829 return VLC_EGENERIC;
832 if (probeStream(p_demux) != VLC_SUCCESS) {
833 return VLC_EGENERIC;
836 } else if (!forced) {
837 if (!p_demux->psz_filepath) {
838 return VLC_EGENERIC;
841 if (probeFile(p_demux->psz_filepath) != VLC_SUCCESS) {
842 return VLC_EGENERIC;
846 /* */
847 p_demux->p_sys = p_sys = vlc_obj_calloc(object, 1, sizeof(*p_sys));
848 if (unlikely(!p_sys))
849 return VLC_ENOMEM;
851 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
853 /* init demux info fields */
854 p_sys->updates = 0;
856 TAB_INIT(p_sys->i_title, p_sys->pp_title);
857 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
859 vlc_mouse_Init(&p_sys->oldmouse);
861 vlc_mutex_init(&p_sys->pl_info_lock);
862 vlc_mutex_init(&p_sys->bdj.lock);
863 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
865 /* request sub demuxers to skip continuity check as some split
866 file concatenation are just resetting counters... */
867 var_Create( p_demux, "ts-cc-check", VLC_VAR_BOOL );
868 var_SetBool( p_demux, "ts-cc-check", false );
869 var_Create( p_demux, "ts-standard", VLC_VAR_STRING );
870 var_SetString( p_demux, "ts-standard", "mpeg" );
871 var_Create( p_demux, "ts-pmtfix-waitdata", VLC_VAR_BOOL );
872 var_SetBool( p_demux, "ts-pmtfix-waitdata", false );
873 var_Create( p_demux, "ts-patfix", VLC_VAR_BOOL );
874 var_SetBool( p_demux, "ts-patfix", false );
875 var_Create( p_demux, "ts-pcr-offsetfix", VLC_VAR_BOOL );
876 var_SetBool( p_demux, "ts-pcr-offsetfix", false );
878 #ifdef DEBUG_BLURAY
879 p_bluray_DebugObject = VLC_OBJECT(p_demux);
880 bd_set_debug_mask(BLURAY_DEBUG_MASK);
881 bd_set_debug_handler(bluray_DebugHandler);
882 #endif
884 /* Open BluRay */
885 #ifdef BLURAY_DEMUX
886 if (p_demux->s) {
887 i_init_pos = vlc_stream_Tell(p_demux->s);
889 p_sys->bluray = bd_init();
890 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
891 bd_close(p_sys->bluray);
892 p_sys->bluray = NULL;
894 } else
895 #endif
897 if (!p_demux->psz_filepath) {
898 /* no path provided (bluray://). use default DVD device. */
899 p_sys->psz_bd_path = var_InheritString(object, "dvd");
900 } else {
901 /* store current bd path */
902 p_sys->psz_bd_path = strdup(p_demux->psz_filepath);
905 /* If we're passed a block device, try to convert it to the mount point. */
906 FindMountPoint(&p_sys->psz_bd_path);
908 p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
910 if (!p_sys->bluray) {
911 goto error;
914 /* Warning the user about AACS/BD+ */
915 const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
917 /* Is it a bluray? */
918 if (!disc_info->bluray_detected) {
919 if (forced) {
920 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
922 goto error;
925 msg_Info(p_demux, "First play: %i, Top menu: %i\n"
926 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
927 disc_info->first_play_supported, disc_info->top_menu_supported,
928 disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
929 disc_info->num_unsupported_titles);
931 /* AACS */
932 if (disc_info->aacs_detected) {
933 msg_Dbg(p_demux, "Disc is using AACS");
934 if (!disc_info->libaacs_detected)
935 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
936 ", and your system does not have it."));
937 if (!disc_info->aacs_handled) {
938 if (disc_info->aacs_error_code) {
939 switch (disc_info->aacs_error_code) {
940 case BD_AACS_CORRUPTED_DISC:
941 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
942 case BD_AACS_NO_CONFIG:
943 BLURAY_ERROR(_("Missing AACS configuration file!"));
944 case BD_AACS_NO_PK:
945 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
946 case BD_AACS_NO_CERT:
947 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
948 case BD_AACS_CERT_REVOKED:
949 BLURAY_ERROR(_("AACS Host certificate revoked."));
950 case BD_AACS_MMC_FAILED:
951 BLURAY_ERROR(_("AACS MMC failed."));
957 /* BD+ */
958 if (disc_info->bdplus_detected) {
959 msg_Dbg(p_demux, "Disc is using BD+");
960 if (!disc_info->libbdplus_detected)
961 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
962 ", and your system does not have it."));
963 if (!disc_info->bdplus_handled)
964 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
965 "Missing configuration?"));
968 /* set player region code */
969 char *psz_region = var_InheritString(p_demux, "bluray-region");
970 unsigned int region = psz_region ? (psz_region[0] - 'A') : REGION_DEFAULT;
971 free(psz_region);
972 bd_set_player_setting(p_sys->bluray, BLURAY_PLAYER_SETTING_REGION_CODE, 1<<region);
974 /* set preferred languages */
975 const char *psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
976 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG, psz_code);
977 psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
978 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG, psz_code);
979 psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
980 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_MENU_LANG, psz_code);
982 /* Get disc metadata */
983 p_sys->p_meta = bd_get_meta(p_sys->bluray);
984 if (!p_sys->p_meta)
985 msg_Warn(p_demux, "Failed to get meta info.");
987 p_sys->i_cover_idx = -1;
988 attachThumbnail(p_demux);
990 p_sys->b_menu = var_InheritBool(p_demux, "bluray-menu");
992 /* Check BD-J capability */
993 if (p_sys->b_menu && disc_info->bdj_detected && !disc_info->bdj_handled) {
994 msg_Err(p_demux, "BD-J menus not supported. Playing without menus. "
995 "BD-J support: %d, JVM found: %d, JVM usable: %d",
996 disc_info->bdj_supported, disc_info->libjvm_detected, disc_info->bdj_handled);
997 vlc_dialog_display_error(p_demux, _("Java required"),
998 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
999 !disc_info->libjvm_detected ? _("Java was not found on your system.") : "");
1000 p_sys->b_menu = false;
1003 if(disc_info->bdj_detected &&p_sys->b_menu &&
1004 BDJO_IsBlacklisted(p_demux, p_sys->psz_bd_path))
1006 p_sys->b_menu = vlc_dialog_wait_question( p_demux,
1007 VLC_DIALOG_QUESTION_NORMAL,
1008 _("Play without Menus"),
1009 _("Try anyway"),
1010 NULL,
1011 _("BDJO Menu check"),
1012 "%s",
1013 _("Incompatible Java Menu detected"));
1016 /* Get titles and chapters */
1017 blurayInitTitles(p_demux, disc_info->num_hdmv_titles + disc_info->num_bdj_titles + 1/*Top Menu*/ + 1/*First Play*/);
1020 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
1022 bd_get_event(p_sys->bluray, NULL);
1024 /* Registering overlay event handler */
1025 bd_register_overlay_proc(p_sys->bluray, p_demux, blurayOverlayProc);
1027 if (p_sys->b_menu) {
1029 /* Register ARGB overlay handler for BD-J */
1030 if (disc_info->num_bdj_titles)
1031 bd_register_argb_overlay_proc(p_sys->bluray, p_demux, blurayArgbOverlayProc, NULL);
1033 /* libbluray will start playback from "First-Title" title */
1034 if (bd_play(p_sys->bluray) == 0)
1035 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
1037 } else {
1038 /* set start title number */
1039 if (bluraySetTitle(p_demux, p_sys->i_longest_title) != VLC_SUCCESS) {
1040 msg_Err(p_demux, "Could not set the title %d", p_sys->i_longest_title);
1041 goto error;
1045 p_sys->p_tf_out = timestamps_filter_es_out_New(p_demux->out);
1046 if(unlikely(!p_sys->p_tf_out))
1047 goto error;
1049 p_sys->p_out = esOutNew(VLC_OBJECT(p_demux), p_sys->p_tf_out, p_demux);
1050 if (unlikely(p_sys->p_out == NULL))
1051 goto error;
1053 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
1054 if (!p_sys->p_parser) {
1055 msg_Err(p_demux, "Failed to create TS demuxer");
1056 goto error;
1059 p_demux->pf_control = blurayControl;
1060 p_demux->pf_demux = blurayDemux;
1062 return VLC_SUCCESS;
1064 error:
1065 if (error_msg)
1066 vlc_dialog_display_error(p_demux, _("Blu-ray error"), "%s", error_msg);
1067 blurayClose(object);
1069 if (p_demux->s != NULL) {
1070 /* restore stream position */
1071 if (vlc_stream_Seek(p_demux->s, i_init_pos) != VLC_SUCCESS) {
1072 msg_Err(p_demux, "Failed to seek back to stream start");
1073 return VLC_ETIMEOUT;
1077 return VLC_EGENERIC;
1078 #undef BLURAY_ERROR
1082 /*****************************************************************************
1083 * blurayClose: module destroy function
1084 *****************************************************************************/
1085 static void blurayClose(vlc_object_t *object)
1087 demux_t *p_demux = (demux_t*)object;
1088 demux_sys_t *p_sys = p_demux->p_sys;
1090 setTitleInfo(p_sys, NULL);
1093 * Close libbluray first.
1094 * This will close all the overlays before we release p_vout
1095 * bd_close(NULL) can crash
1097 if (p_sys->bluray) {
1098 bd_close(p_sys->bluray);
1101 vlc_mutex_lock(&p_sys->bdj.lock);
1102 for(int i = 0; i < MAX_OVERLAY; i++)
1103 blurayCloseOverlay(p_demux, i);
1104 vlc_mutex_unlock(&p_sys->bdj.lock);
1106 if (p_sys->p_parser)
1107 vlc_demux_chained_Delete(p_sys->p_parser);
1109 if (p_sys->p_out != NULL)
1110 es_out_Delete(p_sys->p_out);
1111 if(p_sys->p_tf_out)
1112 timestamps_filter_es_out_Delete(p_sys->p_tf_out);
1114 /* Titles */
1115 for (unsigned int i = 0; i < p_sys->i_title; i++)
1116 vlc_input_title_Delete(p_sys->pp_title[i]);
1117 TAB_CLEAN(p_sys->i_title, p_sys->pp_title);
1119 for (int i = 0; i < p_sys->i_attachments; i++)
1120 vlc_input_attachment_Delete(p_sys->attachments[i]);
1121 TAB_CLEAN(p_sys->i_attachments, p_sys->attachments);
1123 vlc_mutex_destroy(&p_sys->pl_info_lock);
1124 vlc_mutex_destroy(&p_sys->bdj.lock);
1125 vlc_mutex_destroy(&p_sys->read_block_lock);
1127 free(p_sys->psz_bd_path);
1130 /*****************************************************************************
1131 * Elementary streams handling
1132 *****************************************************************************/
1133 static uint8_t blurayGetStreamsUnlocked(demux_sys_t *p_sys,
1134 int i_stream_type,
1135 BLURAY_STREAM_INFO **pp_streams)
1137 if(!p_sys->p_clip_info)
1138 return 0;
1140 switch(i_stream_type)
1142 case BD_EVENT_AUDIO_STREAM:
1143 *pp_streams = p_sys->p_clip_info->audio_streams;
1144 return p_sys->p_clip_info->audio_stream_count;
1145 case BD_EVENT_PG_TEXTST_STREAM:
1146 *pp_streams = p_sys->p_clip_info->pg_streams;
1147 return p_sys->p_clip_info->pg_stream_count;
1148 default:
1149 return 0;
1153 static BLURAY_STREAM_INFO * blurayGetStreamInfoUnlocked(demux_sys_t *p_sys,
1154 int i_stream_type,
1155 uint8_t i_stream_idx)
1157 BLURAY_STREAM_INFO *p_streams = NULL;
1158 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_stream_type, &p_streams);
1159 if(i_stream_idx < i_streams_count)
1160 return &p_streams[i_stream_idx];
1161 else
1162 return NULL;
1165 static BLURAY_STREAM_INFO * blurayGetStreamInfoByPIDUnlocked(demux_sys_t *p_sys,
1166 int i_pid)
1168 for(int i_type=BD_EVENT_AUDIO_STREAM; i_type<=BD_EVENT_SECONDARY_VIDEO_STREAM; i_type++)
1170 BLURAY_STREAM_INFO *p_streams;
1171 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_type, &p_streams);
1172 for(uint8_t i=0; i<i_streams_count; i++)
1174 if(p_streams[i].pid == i_pid)
1175 return &p_streams[i];
1178 return NULL;
1181 static void setStreamLang(demux_sys_t *p_sys, es_format_t *p_fmt)
1183 vlc_mutex_lock(&p_sys->pl_info_lock);
1185 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoByPIDUnlocked(p_sys, p_fmt->i_id);
1186 if(p_stream)
1188 free(p_fmt->psz_language);
1189 p_fmt->psz_language = strndup((const char *)p_stream->lang, 3);
1192 vlc_mutex_unlock(&p_sys->pl_info_lock);
1195 static int blurayGetStreamPID(demux_sys_t *p_sys, int i_stream_type, uint8_t i_stream_idx)
1197 vlc_mutex_lock(&p_sys->pl_info_lock);
1199 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoUnlocked(p_sys,
1200 i_stream_type,
1201 i_stream_idx);
1202 int i_pid = p_stream ? p_stream->pid : -1;
1204 vlc_mutex_unlock(&p_sys->pl_info_lock);
1206 return i_pid;
1209 /*****************************************************************************
1210 * bluray fake es_out
1211 *****************************************************************************/
1212 typedef struct
1214 es_out_t *p_dst_out;
1215 vlc_object_t *p_obj;
1216 vlc_array_t es; /* es_pair_t */
1217 bool b_entered_recycling;
1218 bool b_restart_decoders_on_reuse;
1219 void *priv;
1220 bool b_discontinuity;
1221 bool b_disable_output;
1222 bool b_lowdelay;
1223 vlc_mutex_t lock;
1224 struct
1226 int i_audio_pid; /* Selected audio stream. -1 if default */
1227 int i_spu_pid; /* Selected spu stream. -1 if default */
1228 } selected;
1229 struct
1231 es_out_id_t *p_video_es;
1232 int channels[MAX_OVERLAY];
1233 } overlay;
1234 es_out_t es_out;
1235 } bluray_esout_priv_t;
1237 enum
1239 BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID = ES_OUT_PRIVATE_START,
1240 BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID,
1241 BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY,
1242 BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT,
1243 BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT,
1244 BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY,
1245 BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY,
1246 BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY,
1247 BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY,
1248 BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS,
1251 static es_out_id_t *bluray_esOutAddUnlocked(bluray_esout_priv_t *esout_priv,
1252 const es_format_t *p_fmt)
1254 demux_t *p_demux = esout_priv->priv;
1255 demux_sys_t *p_sys = p_demux->p_sys;
1256 es_format_t fmt;
1257 bool b_select = false;
1259 es_format_Copy(&fmt, p_fmt);
1261 switch (fmt.i_cat) {
1262 case VIDEO_ES:
1263 if(esout_priv->b_lowdelay)
1265 fmt.video.i_frame_rate = 1; fmt.video.i_frame_rate_base = 1;
1266 fmt.b_packetized = true;
1268 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1269 b_select = (p_fmt->i_id == 0x1011);
1270 break;
1271 case AUDIO_ES:
1272 if (esout_priv->selected.i_audio_pid != -1) {
1273 if (esout_priv->selected.i_audio_pid == p_fmt->i_id)
1274 b_select = true;
1275 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1277 setStreamLang(p_sys, &fmt);
1278 break ;
1279 case SPU_ES:
1280 if (esout_priv->selected.i_spu_pid != -1) {
1281 if (esout_priv->selected.i_spu_pid == p_fmt->i_id)
1282 b_select = p_sys->b_spu_enable;
1283 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1285 setStreamLang(p_sys, &fmt);
1286 break ;
1287 default:
1291 es_out_id_t *p_es = NULL;
1292 if (p_fmt->i_id >= 0) {
1293 /* Ensure we are not overriding anything */
1294 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, p_fmt->i_id);
1295 if (p_pair == NULL)
1297 msg_Info(p_demux, "Adding ES %d select %d", p_fmt->i_id, b_select);
1298 p_es = es_out_Add(esout_priv->p_dst_out, &fmt);
1299 es_pair_Add(&esout_priv->es, &fmt, p_es);
1301 else
1303 msg_Info(p_demux, "Reusing ES %d", p_fmt->i_id);
1304 p_pair->b_recyling = false;
1305 p_es = p_pair->p_es;
1306 if(!es_format_IsSimilar(p_fmt, &p_pair->fmt) ||
1307 p_fmt->b_packetized != p_pair->fmt.b_packetized ||
1308 esout_priv->b_restart_decoders_on_reuse)
1309 es_out_Control(esout_priv->p_dst_out, ES_OUT_SET_ES_FMT, p_pair->p_es, &fmt);
1310 es_format_Clean(&p_pair->fmt);
1311 es_format_Copy(&p_pair->fmt, &fmt);
1313 if (b_select)
1314 es_out_Control(esout_priv->p_dst_out, ES_OUT_SET_ES, p_es);
1317 if (p_es && fmt.i_cat == VIDEO_ES && b_select)
1319 es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_SET_MOUSE_EVENT, p_es,
1320 onMouseEvent, p_demux);
1321 esout_priv->overlay.p_video_es = p_es;
1324 es_format_Clean(&fmt);
1326 return p_es;
1329 static es_out_id_t *bluray_esOutAdd(es_out_t *p_out, const es_format_t *p_fmt)
1331 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1333 vlc_mutex_lock(&esout_priv->lock);
1334 es_out_id_t *p_es = bluray_esOutAddUnlocked(esout_priv, p_fmt);
1335 vlc_mutex_unlock(&esout_priv->lock);
1337 return p_es;
1340 static void bluray_esOutDeleteNonReusedESUnlocked(es_out_t *p_out)
1342 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1344 if(!esout_priv->b_entered_recycling)
1345 return;
1346 esout_priv->b_entered_recycling = false;
1347 esout_priv->b_restart_decoders_on_reuse = true;
1349 es_pair_t *p_pair;
1350 while((p_pair = getUnusedEsPair(&esout_priv->es)))
1352 msg_Info(esout_priv->p_obj, "Trashing unused ES %d", p_pair->fmt.i_id);
1354 if(esout_priv->overlay.p_video_es == p_pair->p_es)
1355 esout_priv->overlay.p_video_es = NULL;
1357 es_out_Del(esout_priv->p_dst_out, p_pair->p_es);
1359 es_pair_Remove(&esout_priv->es, p_pair);
1363 static int bluray_esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1365 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1366 vlc_mutex_lock(&esout_priv->lock);
1368 bluray_esOutDeleteNonReusedESUnlocked(p_out);
1370 if(esout_priv->b_discontinuity)
1371 esout_priv->b_discontinuity = false;
1373 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1374 if(p_pair && p_pair->i_next_block_flags)
1376 p_block->i_flags |= p_pair->i_next_block_flags;
1377 p_pair->i_next_block_flags = 0;
1379 if(esout_priv->b_disable_output)
1381 block_Release(p_block);
1382 p_block = NULL;
1384 vlc_mutex_unlock(&esout_priv->lock);
1385 return (p_block) ? es_out_Send(esout_priv->p_dst_out, p_es, p_block) : VLC_SUCCESS;
1388 static void bluray_esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1390 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1391 vlc_mutex_lock(&esout_priv->lock);
1393 if(esout_priv->b_discontinuity)
1394 esout_priv->b_discontinuity = false;
1396 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1397 if (p_pair)
1399 p_pair->b_recyling = true;
1400 esout_priv->b_entered_recycling = true;
1403 vlc_mutex_unlock(&esout_priv->lock);
1406 static int bluray_esOutControl(es_out_t *p_out, int i_query, va_list args)
1408 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1409 int i_ret;
1410 vlc_mutex_lock(&esout_priv->lock);
1412 if(esout_priv->b_disable_output &&
1413 i_query < ES_OUT_PRIVATE_START)
1415 vlc_mutex_unlock(&esout_priv->lock);
1416 return VLC_EGENERIC;
1419 if(esout_priv->b_discontinuity)
1420 esout_priv->b_discontinuity = false;
1422 switch(i_query)
1424 case BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID:
1425 case BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID:
1427 bool b_select = (i_query == BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID);
1428 const int i_bluray_stream_type = va_arg(args, int);
1429 const int i_pid = va_arg(args, int);
1430 switch(i_bluray_stream_type)
1432 case BD_EVENT_AUDIO_STREAM:
1433 esout_priv->selected.i_audio_pid = i_pid;
1434 break;
1435 case BD_EVENT_PG_TEXTST_STREAM:
1436 esout_priv->selected.i_spu_pid = i_pid;
1437 break;
1438 default:
1439 break;
1442 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, i_pid);
1443 if(unlikely(!p_pair))
1445 vlc_mutex_unlock(&esout_priv->lock);
1446 return VLC_EGENERIC;
1449 i_ret = es_out_Control(esout_priv->p_dst_out,
1450 b_select ? ES_OUT_SET_ES : ES_OUT_UNSET_ES,
1451 p_pair->p_es);
1452 } break;
1454 case BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY:
1456 esout_priv->b_discontinuity = true;
1457 i_ret = VLC_SUCCESS;
1458 } break;
1460 case BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS:
1462 esout_priv->b_restart_decoders_on_reuse = !va_arg(args, int);
1463 i_ret = VLC_SUCCESS;
1464 } break;
1466 case BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT:
1467 case BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT:
1469 esout_priv->b_disable_output = (i_query == BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
1470 i_ret = VLC_SUCCESS;
1471 } break;
1473 case BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY:
1474 case BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY:
1476 esout_priv->b_lowdelay = (i_query == BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY);
1477 i_ret = VLC_SUCCESS;
1478 } break;
1480 case BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY:
1482 int i_plane = va_arg(args, int);
1483 subpicture_t *p_pic = va_arg(args, subpicture_t *);
1484 if(!esout_priv->overlay.p_video_es)
1486 es_format_t fmt;
1487 es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_I420);
1488 video_format_Setup(&fmt.video, VLC_CODEC_I420,
1489 1920, 1080, 1920, 1080, 1, 1);
1490 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1491 fmt.i_id = 0x1011;
1492 fmt.i_group = 1;
1493 fmt.video.i_frame_rate = 1; fmt.video.i_frame_rate_base = 1;
1494 fmt.b_packetized = true;
1495 esout_priv->overlay.p_video_es = bluray_esOutAddUnlocked(esout_priv, &fmt);
1496 if(esout_priv->overlay.p_video_es)
1498 bluraySendBackgroundImage(esout_priv->p_obj,
1499 esout_priv->p_dst_out,
1500 esout_priv->overlay.p_video_es,
1501 &fmt);
1503 es_format_Clean(&fmt);
1506 if(esout_priv->overlay.p_video_es && i_plane < MAX_OVERLAY)
1508 i_ret = es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_ADD_OVERLAY,
1509 esout_priv->overlay.p_video_es, p_pic,
1510 &esout_priv->overlay.channels[i_plane]);
1512 else
1514 i_ret = VLC_EGENERIC;
1516 break;
1519 case BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY:
1521 int i_plane = va_arg(args, int);
1522 if(esout_priv->overlay.p_video_es &&
1523 i_plane < MAX_OVERLAY &&
1524 esout_priv->overlay.channels[i_plane] != VOUT_SPU_CHANNEL_INVALID)
1526 i_ret = es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_FLUSH_OVERLAY,
1527 esout_priv->overlay.p_video_es,
1528 esout_priv->overlay.channels[i_plane]);
1529 esout_priv->overlay.channels[i_plane] = VOUT_SPU_CHANNEL_INVALID;
1531 else
1533 assert(esout_priv->overlay.channels[i_plane] == VOUT_SPU_CHANNEL_INVALID);
1534 i_ret = VLC_EGENERIC;
1536 break;
1539 case ES_OUT_SET_ES_DEFAULT:
1540 case ES_OUT_SET_ES:
1541 case ES_OUT_UNSET_ES:
1542 case ES_OUT_SET_ES_STATE:
1543 i_ret = VLC_EGENERIC;
1544 break;
1546 case ES_OUT_GET_ES_STATE:
1547 va_arg(args, es_out_id_t *);
1548 *va_arg(args, bool *) = true;
1549 i_ret = VLC_SUCCESS;
1550 break;
1552 default:
1553 i_ret = es_out_vaControl(esout_priv->p_dst_out, i_query, args);
1554 break;
1556 vlc_mutex_unlock(&esout_priv->lock);
1557 return i_ret;
1560 static void bluray_esOutDestroy(es_out_t *p_out)
1562 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1564 for (size_t i = 0; i < vlc_array_count(&esout_priv->es); ++i)
1565 free(vlc_array_item_at_index(&esout_priv->es, i));
1566 vlc_array_clear(&esout_priv->es);
1567 vlc_mutex_destroy(&esout_priv->lock);
1568 free(esout_priv);
1571 static const struct es_out_callbacks bluray_esOutCallbacks = {
1572 .add = bluray_esOutAdd,
1573 .send = bluray_esOutSend,
1574 .del = bluray_esOutDel,
1575 .control = bluray_esOutControl,
1576 .destroy = bluray_esOutDestroy,
1579 static es_out_t *esOutNew(vlc_object_t *p_obj, es_out_t *p_dst_out, void *priv)
1581 bluray_esout_priv_t *esout_priv = malloc(sizeof(*esout_priv));
1582 if (unlikely(esout_priv == NULL))
1583 return NULL;
1585 vlc_array_init(&esout_priv->es);
1586 esout_priv->p_dst_out = p_dst_out;
1587 esout_priv->p_obj = p_obj;
1588 esout_priv->priv = priv;
1589 esout_priv->es_out.cbs = &bluray_esOutCallbacks;
1590 esout_priv->b_discontinuity = false;
1591 esout_priv->b_disable_output = false;
1592 esout_priv->b_entered_recycling = false;
1593 esout_priv->b_restart_decoders_on_reuse = true;
1594 esout_priv->b_lowdelay = false;
1595 esout_priv->selected.i_audio_pid = -1;
1596 esout_priv->selected.i_spu_pid = -1;
1597 esout_priv->overlay.p_video_es = NULL;
1598 for(size_t i=0; i<MAX_OVERLAY; i++)
1599 esout_priv->overlay.channels[i] = VOUT_SPU_CHANNEL_INVALID;
1600 vlc_mutex_init(&esout_priv->lock);
1601 return &esout_priv->es_out;
1604 /*****************************************************************************
1605 * subpicture_updater_t functions:
1606 *****************************************************************************/
1608 static bluray_overlay_t *updater_lock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1610 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1611 vlc_mutex_lock(&p_upd_sys->lock);
1613 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1614 if (ov) {
1615 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1616 vlc_mutex_lock(&ov->lock);
1617 return ov;
1620 /* overlay has been closed */
1621 vlc_mutex_unlock(&p_upd_sys->lock);
1622 return NULL;
1625 static void updater_unlock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1627 assert (p_upd_sys->p_overlay);
1629 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1630 vlc_mutex_unlock(&p_upd_sys->lock);
1633 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1634 bool b_fmt_src, const video_format_t *p_fmt_src,
1635 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1636 vlc_tick_t i_ts)
1638 VLC_UNUSED(b_fmt_src);
1639 VLC_UNUSED(b_fmt_dst);
1640 VLC_UNUSED(p_fmt_src);
1641 VLC_UNUSED(p_fmt_dst);
1642 VLC_UNUSED(i_ts);
1644 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1645 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1647 if (!p_overlay) {
1648 return 1;
1651 int res = p_overlay->status == Outdated;
1653 updater_unlock_overlay(p_upd_sys);
1655 return res;
1658 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1659 const video_format_t *p_fmt_src,
1660 const video_format_t *p_fmt_dst,
1661 vlc_tick_t i_ts)
1663 VLC_UNUSED(p_fmt_src);
1664 VLC_UNUSED(p_fmt_dst);
1665 VLC_UNUSED(i_ts);
1666 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1667 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1669 if (!p_overlay) {
1670 return;
1674 * When this function is called, all p_subpic regions are gone.
1675 * We need to duplicate our regions (stored internaly) to this subpic.
1677 subpicture_region_t *p_src = p_overlay->p_regions;
1678 if (!p_src) {
1679 updater_unlock_overlay(p_upd_sys);
1680 return;
1683 subpicture_region_t **p_dst = &p_subpic->p_region;
1684 while (p_src != NULL) {
1685 *p_dst = subpicture_region_Copy(p_src);
1686 if (*p_dst == NULL)
1687 break;
1688 p_dst = &(*p_dst)->p_next;
1689 p_src = p_src->p_next;
1691 if (*p_dst != NULL)
1692 (*p_dst)->p_next = NULL;
1693 p_overlay->status = Displayed;
1695 updater_unlock_overlay(p_upd_sys);
1698 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1700 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1701 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1703 if (p_overlay) {
1704 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1705 p_overlay->status = ToDisplay;
1706 p_overlay->b_on_vout = false;
1707 updater_unlock_overlay(p_upd_sys);
1710 unref_subpicture_updater(p_upd_sys);
1713 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1715 bluray_spu_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1716 if (unlikely(p_upd_sys == NULL)) {
1717 return NULL;
1720 p_upd_sys->p_overlay = p_ov;
1722 subpicture_updater_t updater = {
1723 .pf_validate = subpictureUpdaterValidate,
1724 .pf_update = subpictureUpdaterUpdate,
1725 .pf_destroy = subpictureUpdaterDestroy,
1726 .p_sys = p_upd_sys,
1729 subpicture_t *p_pic = subpicture_New(&updater);
1730 if (p_pic == NULL) {
1731 free(p_upd_sys);
1732 return NULL;
1735 p_pic->i_original_picture_width = p_ov->width;
1736 p_pic->i_original_picture_height = p_ov->height;
1737 p_pic->b_absolute = true;
1739 vlc_mutex_init(&p_upd_sys->lock);
1740 p_upd_sys->ref_cnt = 2;
1742 p_ov->p_updater = p_upd_sys;
1744 return p_pic;
1747 /*****************************************************************************
1748 * User input events:
1749 *****************************************************************************/
1750 static void onMouseEvent(const vlc_mouse_t *newmouse, void *user_data)
1752 demux_t *p_demux = user_data;
1753 demux_sys_t *p_sys = p_demux->p_sys;
1755 if (!newmouse) {
1756 vlc_mouse_Init(&p_sys->oldmouse);
1757 return;
1760 if (vlc_mouse_HasMoved(&p_sys->oldmouse, newmouse))
1761 bd_mouse_select(p_sys->bluray, -1, newmouse->i_x, newmouse->i_y);
1763 if (vlc_mouse_HasPressed( &p_sys->oldmouse, newmouse, MOUSE_BUTTON_LEFT))
1764 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1765 p_sys->oldmouse = *newmouse;
1768 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1770 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1771 return VLC_EGENERIC;
1773 return VLC_SUCCESS;
1776 /*****************************************************************************
1777 * libbluray overlay handling:
1778 *****************************************************************************/
1780 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1782 demux_sys_t *p_sys = p_demux->p_sys;
1783 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1785 if (ov != NULL) {
1787 /* drop overlay from vout */
1788 if (ov->p_updater) {
1789 unref_subpicture_updater(ov->p_updater);
1792 /* no references to this overlay exist in vo anymore */
1793 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY, plane);
1795 vlc_mutex_destroy(&ov->lock);
1796 subpicture_region_ChainDelete(ov->p_regions);
1797 free(ov);
1799 p_sys->bdj.p_overlays[plane] = NULL;
1804 * Mark the overlay as "ToDisplay" status.
1805 * This will not send the overlay to the vout instantly, as the vout
1806 * may not be acquired (not acquirable) yet.
1807 * If is has already been acquired, the overlay has already been sent to it,
1808 * therefore, we only flag the overlay as "Outdated"
1810 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1812 demux_sys_t *p_sys = p_demux->p_sys;
1813 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1816 * If the overlay is already displayed, mark the picture as outdated.
1817 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1819 vlc_mutex_lock(&ov->lock);
1820 if (ov->status >= Displayed && ov->b_on_vout) {
1821 ov->status = Outdated;
1822 vlc_mutex_unlock(&ov->lock);
1823 return;
1827 * Mark the overlay as available, but don't display it right now.
1828 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1829 * the overlay is computed
1831 ov->status = ToDisplay;
1832 vlc_mutex_unlock(&ov->lock);
1835 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1837 demux_sys_t *p_sys = p_demux->p_sys;
1839 assert(p_sys->bdj.p_overlays[plane] == NULL);
1841 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1842 if (unlikely(ov == NULL))
1843 return;
1845 ov->width = width;
1846 ov->height = height;
1847 ov->b_on_vout = false;
1849 vlc_mutex_init(&ov->lock);
1851 p_sys->bdj.p_overlays[plane] = ov;
1855 * Destroy every regions in the subpicture.
1856 * This is done in two steps:
1857 * - Wiping our private regions list
1858 * - Flagging the overlay as outdated, so the changes are replicated from
1859 * the subpicture_updater_t::pf_update
1860 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1862 static void blurayClearOverlay(demux_t *p_demux, int plane)
1864 demux_sys_t *p_sys = p_demux->p_sys;
1865 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1867 vlc_mutex_lock(&ov->lock);
1869 subpicture_region_ChainDelete(ov->p_regions);
1870 ov->p_regions = NULL;
1871 ov->status = Outdated;
1873 vlc_mutex_unlock(&ov->lock);
1877 * This will draw to the overlay by adding a region to our region list
1878 * This will have to be copied to the subpicture used to render the overlay.
1880 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const ov)
1882 demux_sys_t *p_sys = p_demux->p_sys;
1885 * Compute a subpicture_region_t.
1886 * It will be copied and sent to the vout later.
1888 vlc_mutex_lock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1890 /* Find a region to update */
1891 subpicture_region_t **pp_reg = &p_sys->bdj.p_overlays[ov->plane]->p_regions;
1892 subpicture_region_t *p_reg = p_sys->bdj.p_overlays[ov->plane]->p_regions;
1893 subpicture_region_t *p_last = NULL;
1894 while (p_reg != NULL) {
1895 p_last = p_reg;
1896 if (p_reg->i_x == ov->x && p_reg->i_y == ov->y &&
1897 p_reg->fmt.i_width == ov->w && p_reg->fmt.i_height == ov->h)
1898 break;
1899 pp_reg = &p_reg->p_next;
1900 p_reg = p_reg->p_next;
1903 if (!ov->img) {
1904 if (p_reg) {
1905 /* drop region */
1906 *pp_reg = p_reg->p_next;
1907 subpicture_region_Delete(p_reg);
1909 vlc_mutex_unlock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1910 return;
1913 /* If there is no region to update, create a new one. */
1914 if (!p_reg) {
1915 video_format_t fmt;
1916 video_format_Init(&fmt, 0);
1917 video_format_Setup(&fmt, VLC_CODEC_YUVP, ov->w, ov->h, ov->w, ov->h, 1, 1);
1919 p_reg = subpicture_region_New(&fmt);
1920 p_reg->i_x = ov->x;
1921 p_reg->i_y = ov->y;
1922 /* Append it to our list. */
1923 if (p_last != NULL)
1924 p_last->p_next = p_reg;
1925 else /* If we don't have a last region, then our list empty */
1926 p_sys->bdj.p_overlays[ov->plane]->p_regions = p_reg;
1929 /* Now we can update the region, regardless it's an update or an insert */
1930 const BD_PG_RLE_ELEM *img = ov->img;
1931 for (int y = 0; y < ov->h; y++)
1932 for (int x = 0; x < ov->w;) {
1933 plane_t *p = &p_reg->p_picture->p[0];
1934 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1935 x += img->len;
1936 img++;
1939 if (ov->palette) {
1940 p_reg->fmt.p_palette->i_entries = 256;
1941 for (int i = 0; i < 256; ++i) {
1942 p_reg->fmt.p_palette->palette[i][0] = ov->palette[i].Y;
1943 p_reg->fmt.p_palette->palette[i][1] = ov->palette[i].Cb;
1944 p_reg->fmt.p_palette->palette[i][2] = ov->palette[i].Cr;
1945 p_reg->fmt.p_palette->palette[i][3] = ov->palette[i].T;
1949 vlc_mutex_unlock(&p_sys->bdj.p_overlays[ov->plane]->lock);
1951 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1955 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1957 demux_t *p_demux = (demux_t*)ptr;
1958 demux_sys_t *p_sys = p_demux->p_sys;
1960 vlc_mutex_lock(&p_sys->bdj.lock);
1962 if (!overlay) {
1963 msg_Info(p_demux, "Closing overlays.");
1964 for (int i = 0; i < MAX_OVERLAY; i++)
1965 blurayCloseOverlay(p_demux, i);
1966 vlc_mutex_unlock(&p_sys->bdj.lock);
1967 return;
1970 switch (overlay->cmd) {
1971 case BD_OVERLAY_INIT:
1972 msg_Info(p_demux, "Initializing overlay");
1973 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
1974 break;
1975 case BD_OVERLAY_CLOSE:
1976 blurayClearOverlay(p_demux, overlay->plane);
1977 blurayCloseOverlay(p_demux, overlay->plane);
1978 break;
1979 case BD_OVERLAY_CLEAR:
1980 blurayClearOverlay(p_demux, overlay->plane);
1981 break;
1982 case BD_OVERLAY_FLUSH:
1983 blurayActivateOverlay(p_demux, overlay->plane);
1984 break;
1985 case BD_OVERLAY_DRAW:
1986 case BD_OVERLAY_WIPE:
1987 blurayDrawOverlay(p_demux, overlay);
1988 break;
1989 default:
1990 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
1991 break;
1994 vlc_mutex_unlock(&p_sys->bdj.lock);
1998 * ARGB overlay (BD-J)
2000 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
2002 blurayInitOverlay(p_demux, plane, width, height);
2005 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const ov)
2007 demux_sys_t *p_sys = p_demux->p_sys;
2009 bluray_overlay_t *bdov = p_sys->bdj.p_overlays[ov->plane];
2010 vlc_mutex_lock(&bdov->lock);
2012 if (!bdov->p_regions)
2014 video_format_t fmt;
2015 video_format_Init(&fmt, 0);
2016 video_format_Setup(&fmt,
2017 /* ARGB in word order -> byte order */
2018 #ifdef WORDS_BIG_ENDIAN
2019 VLC_CODEC_ARGB,
2020 #else
2021 VLC_CODEC_BGRA,
2022 #endif
2023 ov->stride, bdov->height,
2024 bdov->width, bdov->height, 1, 1);
2025 bdov->p_regions = subpicture_region_New(&fmt);
2028 /* Find a region to update */
2029 subpicture_region_t *p_reg = bdov->p_regions;
2030 if (!p_reg) {
2031 vlc_mutex_unlock(&bdov->lock);
2032 return;
2035 /* Now we can update the region */
2036 const uint32_t *src0 = ov->argb;
2037 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
2038 p_reg->p_picture->p[0].i_pitch * ov->y +
2039 ov->x * 4;
2041 for (int y = 0; y < ov->h; y++)
2043 memcpy(dst0, src0, ov->w * 4);
2044 src0 += ov->stride;
2045 dst0 += p_reg->p_picture->p[0].i_pitch;
2048 vlc_mutex_unlock(&bdov->lock);
2050 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
2054 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
2056 demux_t *p_demux = (demux_t*)ptr;
2057 demux_sys_t *p_sys = p_demux->p_sys;
2059 switch (overlay->cmd) {
2060 case BD_ARGB_OVERLAY_INIT:
2061 vlc_mutex_lock(&p_sys->bdj.lock);
2062 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
2063 vlc_mutex_unlock(&p_sys->bdj.lock);
2064 break;
2065 case BD_ARGB_OVERLAY_CLOSE:
2066 vlc_mutex_lock(&p_sys->bdj.lock);
2067 blurayClearOverlay(p_demux, overlay->plane);
2068 blurayCloseOverlay(p_demux, overlay->plane);
2069 vlc_mutex_unlock(&p_sys->bdj.lock);
2070 break;
2071 case BD_ARGB_OVERLAY_FLUSH:
2072 blurayActivateOverlay(p_demux, overlay->plane);
2073 break;
2074 case BD_ARGB_OVERLAY_DRAW:
2075 blurayDrawArgbOverlay(p_demux, overlay);
2076 break;
2077 default:
2078 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
2079 break;
2083 static void bluraySendOverlayToVout(demux_t *p_demux, int plane, bluray_overlay_t *p_ov)
2085 demux_sys_t *p_sys = p_demux->p_sys;
2087 assert(p_ov != NULL);
2088 assert(!p_ov->b_on_vout);
2090 if (p_ov->p_updater) {
2091 unref_subpicture_updater(p_ov->p_updater);
2092 p_ov->p_updater = NULL;
2095 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
2096 if (!p_pic) {
2097 msg_Err(p_demux, "bluraySubpictureCreate() failed");
2098 return;
2102 * After this point, the picture should not be accessed from the demux thread,
2103 * as it is held by the vout thread.
2104 * This must be done only once per subpicture, ie. only once between each
2105 * blurayInitOverlay & blurayCloseOverlay call.
2107 int ret = es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY,
2108 plane, p_pic);
2109 if (ret != VLC_SUCCESS)
2111 unref_subpicture_updater(p_ov->p_updater);
2112 p_ov->p_updater = NULL;
2113 p_ov->b_on_vout = false;
2114 subpicture_Delete(p_pic);
2115 return;
2117 p_ov->b_on_vout = true;
2120 * Mark the picture as Outdated, as it contains no region for now.
2121 * This will make the subpicture_updater_t call pf_update
2123 p_ov->status = Outdated;
2126 static bool blurayTitleIsRepeating(BLURAY_TITLE_INFO *title_info,
2127 unsigned repeats, unsigned ratio)
2129 const BLURAY_CLIP_INFO *prev = NULL;
2130 unsigned maxrepeats = 0;
2131 unsigned sequence = 0;
2132 if(!title_info->chapter_count)
2133 return false;
2135 for (unsigned int j = 0; j < title_info->chapter_count; j++)
2137 unsigned i = title_info->chapters[j].clip_ref;
2138 if(i < title_info->clip_count)
2140 if(prev == NULL ||
2141 /* non repeated does not need start time offset */
2142 title_info->clips[i].start_time == 0 ||
2143 /* repeats occurs on same segment */
2144 memcmp(title_info->clips[i].clip_id, prev->clip_id, 6) ||
2145 prev->in_time != title_info->clips[i].in_time ||
2146 prev->pkt_count != title_info->clips[i].pkt_count)
2148 sequence = 0;
2149 prev = &title_info->clips[i];
2150 continue;
2152 else
2154 if(maxrepeats < sequence++)
2155 maxrepeats = sequence;
2159 return (maxrepeats > repeats &&
2160 (100 * maxrepeats / title_info->chapter_count) >= ratio);
2163 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
2165 t->i_length = FROM_SCALE_NZ(title_info->duration);
2167 for (int i = 0; i < t->i_seekpoint; i++)
2168 vlc_seekpoint_Delete( t->seekpoint[i] );
2169 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
2171 /* FIXME: have libbluray expose repeating titles */
2172 if(blurayTitleIsRepeating(title_info, 50, 90))
2173 return;
2175 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
2176 seekpoint_t *s = vlc_seekpoint_New();
2177 if (!s) {
2178 break;
2180 s->i_time_offset = FROM_SCALE_NZ(title_info->chapters[j].start);
2182 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
2186 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles)
2188 demux_sys_t *p_sys = p_demux->p_sys;
2189 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2191 /* get and set the titles */
2192 uint32_t i_title = menu_titles;
2194 if (!p_sys->b_menu) {
2195 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
2196 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
2199 for (uint32_t i = 0; i < i_title; i++) {
2200 input_title_t *t = vlc_input_title_New();
2201 if (!t)
2202 break;
2204 if (!p_sys->b_menu) {
2205 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
2206 blurayUpdateTitleInfo(t, title_info);
2207 bd_free_title_info(title_info);
2209 } else if (i == 0) {
2210 t->psz_name = strdup(_("Top Menu"));
2211 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
2212 } else if (i == i_title - 1) {
2213 t->psz_name = strdup(_("First Play"));
2214 if (di && di->first_play && di->first_play->interactive) {
2215 t->i_flags = INPUT_TITLE_INTERACTIVE;
2217 } else {
2218 /* add possible title name from disc metadata */
2219 if (di && di->titles && i <= di->num_titles) {
2220 if (di->titles[i]->name) {
2221 t->psz_name = strdup(di->titles[i]->name);
2223 if (di->titles[i]->interactive) {
2224 t->i_flags = INPUT_TITLE_INTERACTIVE;
2229 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
2233 static void blurayRestartParser(demux_t *p_demux, bool b_flush, bool b_random_access)
2236 * This is a hack and will have to be removed.
2237 * The parser should be flushed, and not destroy/created each time
2238 * we are changing title.
2240 demux_sys_t *p_sys = p_demux->p_sys;
2242 if(b_flush)
2243 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
2245 if (p_sys->p_parser)
2246 vlc_demux_chained_Delete(p_sys->p_parser);
2248 if(b_flush)
2249 es_out_Control(p_sys->p_tf_out, ES_OUT_TF_FILTER_RESET);
2251 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
2252 if (!p_sys->p_parser)
2253 msg_Err(p_demux, "Failed to create TS demuxer");
2255 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT);
2257 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS, b_random_access);
2260 /*****************************************************************************
2261 * bluraySetTitle: select new BD title
2262 *****************************************************************************/
2263 static int bluraySetTitle(demux_t *p_demux, int i_title)
2265 demux_sys_t *p_sys = p_demux->p_sys;
2267 if (p_sys->b_menu) {
2268 int result;
2269 if (i_title <= 0) {
2270 msg_Dbg(p_demux, "Playing TopMenu Title");
2271 result = bd_menu_call(p_sys->bluray, -1);
2272 } else if (i_title >= (int)p_sys->i_title - 1) {
2273 msg_Dbg(p_demux, "Playing FirstPlay Title");
2274 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
2275 } else {
2276 msg_Dbg(p_demux, "Playing Title %i", i_title);
2277 result = bd_play_title(p_sys->bluray, i_title);
2280 if (result == 0) {
2281 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
2282 return VLC_EGENERIC;
2285 return VLC_SUCCESS;
2288 /* Looking for the main title, ie the longest duration */
2289 if (i_title < 0)
2290 i_title = p_sys->i_longest_title;
2291 else if ((unsigned)i_title > p_sys->i_title)
2292 return VLC_EGENERIC;
2294 msg_Dbg(p_demux, "Selecting Title %i", i_title);
2296 if (bd_select_title(p_sys->bluray, i_title) == 0) {
2297 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
2298 return VLC_EGENERIC;
2301 return VLC_SUCCESS;
2304 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
2305 # define BLURAY_AUDIO_STREAM 0
2306 #endif
2308 static void blurayOnUserStreamSelection(demux_sys_t *p_sys, int i_pid)
2310 vlc_mutex_lock(&p_sys->pl_info_lock);
2312 if(i_pid == -AUDIO_ES)
2313 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, 0, 0);
2314 else if(i_pid == -SPU_ES)
2315 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, 0, 0);
2316 else if (p_sys->p_clip_info)
2319 if ((i_pid & 0xff00) == 0x1100) {
2320 // audio
2321 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
2322 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
2323 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
2324 if(!p_sys->b_menu)
2325 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG,
2326 (const char *) p_sys->p_clip_info->audio_streams[i_id].lang);
2327 break;
2330 } else if ((i_pid & 0xff00) == 0x1400 || i_pid == 0x1800) {
2331 // subtitle
2332 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
2333 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
2334 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
2335 if(!p_sys->b_menu)
2336 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG,
2337 (const char *) p_sys->p_clip_info->pg_streams[i_id].lang);
2338 break;
2344 vlc_mutex_unlock(&p_sys->pl_info_lock);
2347 /*****************************************************************************
2348 * blurayControl: handle the controls
2349 *****************************************************************************/
2350 static int blurayControl(demux_t *p_demux, int query, va_list args)
2352 demux_sys_t *p_sys = p_demux->p_sys;
2353 bool *pb_bool;
2355 switch (query) {
2356 case DEMUX_CAN_SEEK:
2357 case DEMUX_CAN_PAUSE:
2358 case DEMUX_CAN_CONTROL_PACE:
2359 pb_bool = va_arg(args, bool *);
2360 *pb_bool = true;
2361 break;
2363 case DEMUX_GET_PTS_DELAY:
2364 *va_arg(args, vlc_tick_t *) =
2365 VLC_TICK_FROM_MS(var_InheritInteger(p_demux, "disc-caching"));
2366 break;
2368 case DEMUX_SET_PAUSE_STATE:
2370 #ifdef BLURAY_RATE_NORMAL
2371 bool b_paused = (bool)va_arg(args, int);
2372 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
2373 return VLC_EGENERIC;
2375 #endif
2376 break;
2378 case DEMUX_SET_ES:
2380 int i_id = va_arg(args, int);
2381 blurayOnUserStreamSelection(p_sys, i_id);
2382 break;
2384 case DEMUX_SET_TITLE:
2386 int i_title = va_arg(args, int);
2387 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
2388 /* make sure GUI restores the old setting in title menu ... */
2389 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2390 return VLC_EGENERIC;
2392 blurayRestartParser(p_demux, true, false);
2393 notifyDiscontinuityToParser(p_sys);
2394 p_sys->b_draining = false;
2395 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
2396 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2397 break;
2399 case DEMUX_SET_SEEKPOINT:
2401 int i_chapter = va_arg(args, int);
2402 bd_seek_chapter(p_sys->bluray, i_chapter);
2403 blurayRestartParser(p_demux, true, false);
2404 notifyDiscontinuityToParser(p_sys);
2405 p_sys->b_draining = false;
2406 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
2407 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2408 break;
2410 case DEMUX_TEST_AND_CLEAR_FLAGS:
2412 unsigned *restrict flags = va_arg(args, unsigned *);
2413 *flags &= p_sys->updates;
2414 p_sys->updates &= ~*flags;
2415 break;
2417 case DEMUX_GET_TITLE:
2418 *va_arg(args, int *) = p_sys->cur_title;
2419 break;
2421 case DEMUX_GET_SEEKPOINT:
2422 *va_arg(args, int *) = p_sys->cur_seekpoint;
2423 break;
2425 case DEMUX_GET_TITLE_INFO:
2427 input_title_t ***ppp_title = va_arg(args, input_title_t***);
2428 int *pi_int = va_arg(args, int *);
2429 int *pi_title_offset = va_arg(args, int *);
2430 int *pi_chapter_offset = va_arg(args, int *);
2432 /* */
2433 *pi_title_offset = 0;
2434 *pi_chapter_offset = 0;
2436 /* Duplicate local title infos */
2437 *pi_int = 0;
2438 *ppp_title = vlc_alloc(p_sys->i_title, sizeof(input_title_t *));
2439 if(!*ppp_title)
2440 return VLC_EGENERIC;
2441 for (unsigned int i = 0; i < p_sys->i_title; i++)
2443 input_title_t *p_dup = vlc_input_title_Duplicate(p_sys->pp_title[i]);
2444 if(p_dup)
2445 (*ppp_title)[(*pi_int)++] = p_dup;
2448 return VLC_SUCCESS;
2451 case DEMUX_GET_LENGTH:
2453 if(p_sys->cur_title < p_sys->i_title &&
2454 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2455 return VLC_EGENERIC;
2456 *va_arg(args, vlc_tick_t *) = p_sys->cur_title < p_sys->i_title ? CUR_LENGTH : 0;
2457 return VLC_SUCCESS;
2459 case DEMUX_SET_TIME:
2461 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(va_arg(args, vlc_tick_t)));
2462 blurayRestartParser(p_demux, true, true);
2463 notifyDiscontinuityToParser(p_sys);
2464 p_sys->b_draining = false;
2465 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2466 return VLC_SUCCESS;
2468 case DEMUX_GET_TIME:
2470 vlc_tick_t *pi_time = va_arg(args, vlc_tick_t *);
2471 if(p_sys->cur_title < p_sys->i_title &&
2472 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2473 return VLC_EGENERIC;
2474 *pi_time = FROM_SCALE_NZ(bd_tell_time(p_sys->bluray));
2475 return VLC_SUCCESS;
2478 case DEMUX_GET_POSITION:
2480 double *pf_position = va_arg(args, double *);
2481 if(p_sys->cur_title < p_sys->i_title &&
2482 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2483 return VLC_EGENERIC;
2484 *pf_position = p_sys->cur_title < p_sys->i_title && CUR_LENGTH > 0 ?
2485 (double)FROM_SCALE_NZ(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
2486 return VLC_SUCCESS;
2488 case DEMUX_SET_POSITION:
2490 double f_position = va_arg(args, double);
2491 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(f_position*CUR_LENGTH));
2492 blurayRestartParser(p_demux, true, true);
2493 notifyDiscontinuityToParser(p_sys);
2494 p_sys->b_draining = false;
2495 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2496 return VLC_SUCCESS;
2499 case DEMUX_GET_META:
2501 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
2502 const META_DL *meta = p_sys->p_meta;
2503 if (meta == NULL)
2504 return VLC_EGENERIC;
2506 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
2508 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
2509 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
2510 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
2512 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
2513 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
2515 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
2516 char psz_url[128];
2517 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
2518 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
2519 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
2521 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
2522 char *psz_thumbpath;
2523 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
2524 p_sys->psz_bd_path, meta->thumbnails[0].path) > -1) {
2525 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
2526 free(psz_thumbpath);
2527 if (unlikely(psz_thumburl == NULL))
2528 return VLC_ENOMEM;
2530 vlc_meta_SetArtURL(p_meta, psz_thumburl);
2531 free(psz_thumburl);
2535 return VLC_SUCCESS;
2538 case DEMUX_GET_ATTACHMENTS:
2540 input_attachment_t ***ppp_attach =
2541 va_arg(args, input_attachment_t ***);
2542 int *pi_int = va_arg(args, int *);
2544 if (p_sys->i_attachments <= 0)
2545 return VLC_EGENERIC;
2547 *pi_int = 0;
2548 *ppp_attach = vlc_alloc(p_sys->i_attachments, sizeof(input_attachment_t *));
2549 if(!*ppp_attach)
2550 return VLC_EGENERIC;
2551 for (int i = 0; i < p_sys->i_attachments; i++)
2553 input_attachment_t *p_dup = vlc_input_attachment_Duplicate(p_sys->attachments[i]);
2554 if(p_dup)
2555 (*ppp_attach)[(*pi_int)++] = p_dup;
2557 return VLC_SUCCESS;
2560 case DEMUX_NAV_ACTIVATE:
2561 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
2562 return sendKeyEvent(p_sys, BD_VK_POPUP);
2564 return sendKeyEvent(p_sys, BD_VK_ENTER);
2565 case DEMUX_NAV_UP:
2566 return sendKeyEvent(p_sys, BD_VK_UP);
2567 case DEMUX_NAV_DOWN:
2568 return sendKeyEvent(p_sys, BD_VK_DOWN);
2569 case DEMUX_NAV_LEFT:
2570 return sendKeyEvent(p_sys, BD_VK_LEFT);
2571 case DEMUX_NAV_RIGHT:
2572 return sendKeyEvent(p_sys, BD_VK_RIGHT);
2573 case DEMUX_NAV_POPUP:
2574 return sendKeyEvent(p_sys, BD_VK_POPUP);
2575 case DEMUX_NAV_MENU:
2576 if (p_sys->b_menu) {
2577 if (bd_menu_call(p_sys->bluray, -1) == 1) {
2578 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2579 return VLC_SUCCESS;
2581 msg_Err(p_demux, "Can't select Top Menu title");
2582 return sendKeyEvent(p_sys, BD_VK_POPUP);
2584 return VLC_EGENERIC;
2586 case DEMUX_CAN_RECORD:
2587 case DEMUX_GET_FPS:
2588 case DEMUX_SET_GROUP_DEFAULT:
2589 case DEMUX_SET_GROUP_ALL:
2590 case DEMUX_SET_GROUP_LIST:
2591 case DEMUX_HAS_UNSUPPORTED_META:
2592 default:
2593 return VLC_EGENERIC;
2595 return VLC_SUCCESS;
2598 /*****************************************************************************
2599 * libbluray event handling
2600 *****************************************************************************/
2601 static void writeTsPacketWDiscontinuity( uint8_t *p_buf, uint16_t i_pid,
2602 const uint8_t *p_payload, uint8_t i_payload )
2604 uint8_t ts_header[] = {
2605 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2606 0x47,
2607 0x40 | ((i_pid & 0x1f00) >> 8), i_pid & 0xFF, /* PUSI + PID */
2608 i_payload ? 0x30 : 0x20, /* adaptation field, payload / no payload */
2609 192 - (4 + 5) - i_payload, /* adaptation field length */
2610 0x82, /* af: discontinuity indicator + priv data */
2611 0x0E, /* priv data size */
2612 'V', 'L', 'C', '_',
2613 'D', 'I', 'S', 'C', 'O', 'N', 'T', 'I', 'N', 'U',
2616 memcpy( p_buf, ts_header, sizeof(ts_header) );
2617 memset( &p_buf[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header) - i_payload );
2618 if( i_payload )
2619 memcpy( &p_buf[192 - i_payload], p_payload, i_payload );
2622 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
2623 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
2625 for( size_t i=0; i< i_sinfo; i++ )
2627 const uint16_t i_pid = p_sinfo[i].pid;
2629 block_t *p_block = block_Alloc(192);
2630 if (!p_block)
2631 return;
2633 writeTsPacketWDiscontinuity( p_block->p_buffer, i_pid, NULL, 0 );
2635 vlc_demux_chained_Send(p_parser, p_block);
2639 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2640 p_clip->memb##_stream_count )
2642 static void notifyDiscontinuityToParser( demux_sys_t *p_sys )
2644 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2645 if( p_clip )
2647 DONOTIFY(audio);
2648 DONOTIFY(video);
2649 DONOTIFY(pg);
2650 DONOTIFY(ig);
2651 DONOTIFY(sec_audio);
2652 DONOTIFY(sec_video);
2656 #undef DONOTIFY
2658 static void streamFlush( demux_sys_t *p_sys )
2661 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2662 * Packet is flushed only when TS packet with PUSI flag set is received.
2664 * Fix this by emitting (video) ts packet with PUSI flag set.
2665 * Add video sequence end code to payload so that also video decoder is flushed.
2666 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2669 if (p_sys->b_flushed)
2670 return;
2672 block_t *p_block = block_Alloc(192);
2673 if (!p_block)
2674 return;
2676 bd_stream_type_e i_coding_type;
2678 /* set correct sequence end code */
2679 vlc_mutex_lock(&p_sys->pl_info_lock);
2680 if (p_sys->p_clip_info != NULL)
2681 i_coding_type = p_sys->p_clip_info->video_streams[0].coding_type;
2682 else
2683 i_coding_type = 0;
2684 vlc_mutex_unlock(&p_sys->pl_info_lock);
2686 uint8_t i_eos;
2687 switch( i_coding_type )
2689 case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
2690 case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
2691 default:
2692 i_eos = 0xB7; /* MPEG2 sequence end */
2693 break;
2694 case BLURAY_STREAM_TYPE_VIDEO_VC1:
2695 case BLURAY_STREAM_TYPE_VIDEO_H264:
2696 i_eos = 0x0A; /* VC1 / H.264 sequence end */
2697 break;
2698 case BD_STREAM_TYPE_VIDEO_HEVC:
2699 i_eos = 0x48; /* HEVC sequence end NALU */
2700 break;
2703 uint8_t seq_end_pes[] = {
2704 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES header */
2705 0x00, 0x00, 0x01, i_eos, /* PES payload: sequence end */
2706 0x00, /* 2nd byte for HEVC NAL, pads others */
2709 writeTsPacketWDiscontinuity( p_block->p_buffer, 0x1011, seq_end_pes, sizeof(seq_end_pes) );
2711 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2712 p_sys->b_flushed = true;
2715 static void blurayResetStillImage( demux_t *p_demux )
2717 demux_sys_t *p_sys = p_demux->p_sys;
2719 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET) {
2720 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
2722 blurayRestartParser(p_demux, false, false);
2723 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2727 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2729 demux_sys_t *p_sys = p_demux->p_sys;
2731 /* time period elapsed ? */
2732 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET &&
2733 p_sys->i_still_end_time != STILL_IMAGE_INFINITE &&
2734 p_sys->i_still_end_time <= vlc_tick_now()) {
2735 msg_Dbg(p_demux, "Still image end");
2736 bd_read_skip_still(p_sys->bluray);
2738 blurayResetStillImage(p_demux);
2739 return;
2742 /* show last frame as still image */
2743 if (p_sys->i_still_end_time == STILL_IMAGE_NOT_SET) {
2744 if (i_timeout) {
2745 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2746 p_sys->i_still_end_time = vlc_tick_now() + vlc_tick_from_sec( i_timeout );
2747 } else {
2748 msg_Dbg(p_demux, "Still image (infinite)");
2749 p_sys->i_still_end_time = STILL_IMAGE_INFINITE;
2752 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2753 streamFlush(p_sys);
2755 /* stop buffering */
2756 bool b_empty;
2757 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2760 /* avoid busy loops (read returns no data) */
2761 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2764 static void blurayOnStreamSelectedEvent(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2766 demux_sys_t *p_sys = p_demux->p_sys;
2767 int i_pid = -1;
2769 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2770 i_id--;
2772 if (i_type == BD_EVENT_AUDIO_STREAM) {
2773 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2774 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2775 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2778 if (i_pid > 0)
2780 if (i_type == BD_EVENT_PG_TEXTST_STREAM && !p_sys->b_spu_enable)
2781 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID, (int)i_type, i_pid);
2782 else
2783 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID, (int)i_type, i_pid);
2787 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2789 demux_sys_t *p_sys = p_demux->p_sys;
2791 blurayRestartParser(p_demux, true, false);
2793 /* read title info and init some values */
2794 if (!p_sys->b_menu)
2795 p_sys->cur_title = bd_get_current_title(p_sys->bluray);
2796 p_sys->cur_seekpoint = 0;
2797 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2799 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2800 if (p_title_info) {
2801 blurayUpdateTitleInfo(p_sys->pp_title[p_sys->cur_title], p_title_info);
2802 if (p_sys->b_menu)
2803 p_sys->updates |= INPUT_UPDATE_TITLE_LIST;
2805 setTitleInfo(p_sys, p_title_info);
2807 blurayResetStillImage(p_demux);
2810 static void blurayOnClipUpdate(demux_t *p_demux, uint32_t clip)
2812 demux_sys_t *p_sys = p_demux->p_sys;
2814 vlc_mutex_lock(&p_sys->pl_info_lock);
2816 p_sys->p_clip_info = NULL;
2818 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2820 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2822 /* Let's assume a single video track for now.
2823 * This may brake later, but it's enough for now.
2825 assert(p_sys->p_clip_info->video_stream_count >= 1);
2828 CLPI_CL *clpi = bd_get_clpi(p_sys->bluray, clip);
2829 if(clpi && clpi->clip.application_type != p_sys->clip_application_type)
2831 if(p_sys->clip_application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW ||
2832 clpi->clip.application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW)
2833 blurayRestartParser(p_demux, false, false);
2835 if(clpi->clip.application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW)
2836 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY);
2837 else
2838 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY);
2839 bd_free_clpi(clpi);
2842 vlc_mutex_unlock(&p_sys->pl_info_lock);
2844 blurayResetStillImage(p_demux);
2847 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e)
2849 demux_sys_t *p_sys = p_demux->p_sys;
2851 blurayDebugEvent(e->event, e->param);
2853 switch (e->event) {
2854 case BD_EVENT_TITLE:
2855 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2856 p_sys->cur_title = p_sys->i_title - 1;
2857 else
2858 p_sys->cur_title = e->param;
2859 /* this is feature title, we don't know yet which playlist it will play (if any) */
2860 setTitleInfo(p_sys, NULL);
2861 /* reset title infos here ? */
2862 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2863 /* might be BD-J title with no video */
2864 break;
2865 case BD_EVENT_PLAYLIST:
2866 /* Start of playlist playback (?????.mpls) */
2867 blurayUpdatePlaylist(p_demux, e->param);
2868 if (p_sys->b_pl_playing) {
2869 /* previous playlist was stopped in middle. flush to avoid delay */
2870 msg_Info(p_demux, "Stopping playlist playback");
2871 blurayRestartParser(p_demux, false, false);
2872 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2874 p_sys->b_pl_playing = true;
2875 break;
2876 case BD_EVENT_PLAYITEM:
2877 notifyDiscontinuityToParser(p_sys);
2878 blurayOnClipUpdate(p_demux, e->param);
2879 break;
2880 case BD_EVENT_CHAPTER:
2881 if (e->param && e->param < 0xffff)
2882 p_sys->cur_seekpoint = e->param - 1;
2883 else
2884 p_sys->cur_seekpoint = 0;
2885 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2886 break;
2887 case BD_EVENT_PLAYMARK:
2888 case BD_EVENT_ANGLE:
2889 break;
2890 case BD_EVENT_SEEK:
2891 /* Seek will happen with any chapter/title or bd_seek(),
2892 but also BD-J initiated. We can't make the difference
2893 between input or vm ones, better double flush/pcr reset
2894 than break the clock by throwing post random access PCR */
2895 blurayRestartParser(p_demux, true, true);
2896 notifyDiscontinuityToParser(p_sys);
2897 es_out_Control(p_sys->p_out, ES_OUT_RESET_PCR);
2898 break;
2899 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2900 case BD_EVENT_UO_MASK_CHANGED:
2901 /* This event could be used to grey out unselectable items in title menu */
2902 break;
2903 #endif
2904 case BD_EVENT_MENU:
2905 p_sys->b_menu_open = e->param;
2906 break;
2907 case BD_EVENT_POPUP:
2908 p_sys->b_popup_available = e->param;
2909 /* TODO: show / hide pop-up menu button in gui ? */
2910 break;
2913 * Errors
2915 case BD_EVENT_ERROR:
2916 /* fatal error (with menus) */
2917 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2918 "Playback with BluRay menus failed");
2919 p_sys->b_fatal_error = true;
2920 break;
2921 case BD_EVENT_ENCRYPTED:
2922 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
2923 "This disc seems to be encrypted");
2924 p_sys->b_fatal_error = true;
2925 break;
2926 case BD_EVENT_READ_ERROR:
2927 msg_Err(p_demux, "bluray: read error\n");
2928 break;
2931 * stream selection events
2933 case BD_EVENT_PG_TEXTST:
2934 p_sys->b_spu_enable = e->param;
2935 break;
2936 case BD_EVENT_AUDIO_STREAM:
2937 case BD_EVENT_PG_TEXTST_STREAM:
2938 blurayOnStreamSelectedEvent(p_demux, e->event, e->param);
2939 break;
2940 case BD_EVENT_IG_STREAM:
2941 case BD_EVENT_SECONDARY_AUDIO:
2942 case BD_EVENT_SECONDARY_AUDIO_STREAM:
2943 case BD_EVENT_SECONDARY_VIDEO:
2944 case BD_EVENT_SECONDARY_VIDEO_STREAM:
2945 case BD_EVENT_SECONDARY_VIDEO_SIZE:
2946 break;
2949 * playback control events
2951 case BD_EVENT_STILL_TIME:
2952 blurayStillImage(p_demux, e->param);
2953 break;
2954 case BD_EVENT_DISCONTINUITY:
2955 /* reset demuxer (partially decoded PES packets must be dropped) */
2956 blurayRestartParser(p_demux, false, true);
2957 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2958 break;
2959 case BD_EVENT_END_OF_TITLE:
2960 if(p_sys->b_pl_playing)
2962 notifyDiscontinuityToParser(p_sys);
2963 blurayRestartParser(p_demux, false, false);
2964 p_sys->b_draining = true;
2965 p_sys->b_pl_playing = false;
2967 break;
2968 case BD_EVENT_IDLE:
2969 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
2970 /* avoid busy loop (bd_read() returns no data) */
2971 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2972 break;
2974 default:
2975 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
2976 break;
2980 static void blurayHandleOverlays(demux_t *p_demux)
2982 demux_sys_t *p_sys = p_demux->p_sys;
2983 vlc_mutex_lock(&p_sys->bdj.lock);
2985 for (int i = 0; i < MAX_OVERLAY; i++) {
2986 bluray_overlay_t *ov = p_sys->bdj.p_overlays[i];
2987 if (!ov) {
2988 continue;
2990 vlc_mutex_lock(&ov->lock);
2991 bool display = ov->status == ToDisplay;
2992 vlc_mutex_unlock(&ov->lock);
2993 if (display && !ov->b_on_vout)
2995 /* NOTE: we might want to enable background video always when there's no video stream playing.
2996 Now, with some discs, there are perioids (even seconds) during which the video window
2997 disappears and just playlist is shown.
2998 (sometimes BD-J runs slowly ...)
3000 bluraySendOverlayToVout(p_demux, i, ov);
3004 vlc_mutex_unlock(&p_sys->bdj.lock);
3007 static int blurayDemux(demux_t *p_demux)
3009 demux_sys_t *p_sys = p_demux->p_sys;
3010 BD_EVENT e;
3012 if(p_sys->b_draining)
3014 bool b_empty = false;
3015 if(es_out_Control(p_sys->p_out, ES_OUT_GET_EMPTY, &b_empty) != VLC_SUCCESS || b_empty)
3017 es_out_Control(p_sys->p_out, ES_OUT_RESET_PCR);
3018 p_sys->b_draining = false;
3020 else
3022 msg_Dbg(p_demux, "Draining...");
3023 vlc_tick_sleep(VLC_TICK_FROM_MS(40));
3024 return VLC_DEMUXER_SUCCESS;
3028 block_t *p_block = block_Alloc(BD_READ_SIZE);
3029 if (!p_block)
3030 return VLC_DEMUXER_EGENERIC;
3032 int nread;
3034 if (p_sys->b_menu == false) {
3035 nread = bd_read(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE);
3036 while (bd_get_event(p_sys->bluray, &e))
3037 blurayHandleEvent(p_demux, &e);
3038 } else {
3039 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE, &e);
3040 while (e.event != BD_EVENT_NONE) {
3041 blurayHandleEvent(p_demux, &e);
3042 bd_get_event(p_sys->bluray, &e);
3046 blurayHandleOverlays(p_demux);
3048 if (nread <= 0) {
3049 block_Release(p_block);
3050 if (p_sys->b_fatal_error || nread < 0) {
3051 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
3052 return VLC_DEMUXER_EGENERIC;
3054 if (!p_sys->b_menu) {
3055 return VLC_DEMUXER_EOF;
3057 return VLC_DEMUXER_SUCCESS;
3060 p_block->i_buffer = nread;
3062 vlc_demux_chained_Send(p_sys->p_parser, p_block);
3064 p_sys->b_flushed = false;
3066 return VLC_DEMUXER_SUCCESS;