qt: playlist: use item title if available
[vlc.git] / modules / access / bluray.c
blobd6278d133196ea1c95fbca17862cb55bdbf42bd3
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 #ifdef HAVE_GETMNTENT_R
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 } es_pair_t;
378 static bool es_pair_Add(vlc_array_t *p_array, const es_format_t *p_fmt,
379 es_out_id_t *p_es)
381 es_pair_t *p_pair = malloc(sizeof(*p_pair));
382 if (likely(p_pair != NULL))
384 p_pair->p_es = p_es;
385 p_pair->i_next_block_flags = 0;
386 p_pair->b_recyling = false;
387 if(vlc_array_append(p_array, p_pair) != VLC_SUCCESS)
389 free(p_pair);
390 p_pair = NULL;
392 else
394 es_format_Init(&p_pair->fmt, p_fmt->i_cat, p_fmt->i_codec);
395 es_format_Copy(&p_pair->fmt, p_fmt);
398 return p_pair != NULL;
401 static void es_pair_Delete(es_pair_t *p_pair)
403 es_format_Clean(&p_pair->fmt);
404 free(p_pair);
407 static void es_pair_Remove(vlc_array_t *p_array, es_pair_t *p_pair)
409 vlc_array_remove(p_array, vlc_array_index_of_item(p_array, p_pair));
410 es_pair_Delete(p_pair);
413 static es_pair_t *getEsPair(vlc_array_t *p_array,
414 bool (*match)(const es_pair_t *, const void *),
415 const void *param)
417 for (size_t i = 0; i < vlc_array_count(p_array); ++i)
419 es_pair_t *p_pair = vlc_array_item_at_index(p_array, i);
420 if(match(p_pair, param))
421 return p_pair;
423 return NULL;
426 static bool es_pair_compare_PID(const es_pair_t *p_pair, const void *p_pid)
428 return p_pair->fmt.i_id == *((const int *)p_pid);
431 static bool es_pair_compare_ES(const es_pair_t *p_pair, const void *p_es)
433 return p_pair->p_es == (const es_out_id_t *)p_es;
436 static bool es_pair_compare_Unused(const es_pair_t *p_pair, const void *priv)
438 VLC_UNUSED(priv);
439 return p_pair->b_recyling;
442 static es_pair_t *getEsPairByPID(vlc_array_t *p_array, int i_pid)
444 return getEsPair(p_array, es_pair_compare_PID, &i_pid);
447 static es_pair_t *getEsPairByES(vlc_array_t *p_array, const es_out_id_t *p_es)
449 return getEsPair(p_array, es_pair_compare_ES, p_es);
452 static es_pair_t *getUnusedEsPair(vlc_array_t *p_array)
454 return getEsPair(p_array, es_pair_compare_Unused, 0);
458 * Subpicture updater
460 struct bluray_spu_updater_sys_t
462 vlc_mutex_t lock; // protect p_overlay pointer and ref_cnt
463 bluray_overlay_t *p_overlay; // NULL if overlay has been closed
464 int ref_cnt; // one reference in vout (subpicture_t), one in input (bluray_overlay_t)
468 * cut the connection between vout and overlay.
469 * - called when vout is closed or overlay is closed.
470 * - frees bluray_spu_updater_sys_t when both sides have been closed.
472 static void unref_subpicture_updater(bluray_spu_updater_sys_t *p_sys)
474 vlc_mutex_lock(&p_sys->lock);
475 int refs = --p_sys->ref_cnt;
476 p_sys->p_overlay = NULL;
477 vlc_mutex_unlock(&p_sys->lock);
479 if (refs < 1)
480 free(p_sys);
483 /* Get a 3 char code
484 * FIXME: partiallyy duplicated from src/input/es_out.c
486 static const char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
488 const iso639_lang_t *pl;
489 char *psz_lang;
490 char *p;
492 psz_lang = var_CreateGetString( p_demux, psz_var );
493 if( !psz_lang )
494 return LANGUAGE_DEFAULT;
496 /* XXX: we will use only the first value
497 * (and ignore other ones in case of a list) */
498 if( ( p = strchr( psz_lang, ',' ) ) )
499 *p = '\0';
501 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
503 if( *psz_lang == '\0' )
504 continue;
505 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
506 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
507 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
508 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
509 break;
512 free( psz_lang );
514 if( pl->psz_eng_name != NULL )
515 return pl->psz_iso639_2T;
517 return LANGUAGE_DEFAULT;
520 /*****************************************************************************
521 * Local prototypes
522 *****************************************************************************/
523 static es_out_t *esOutNew(vlc_object_t*, es_out_t *, void *);
525 static int blurayControl(demux_t *, int, va_list);
526 static int blurayDemux(demux_t *);
528 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles);
529 static int bluraySetTitle(demux_t *p_demux, int i_title);
531 static void blurayOverlayProc(void *ptr, const BD_OVERLAY * const overlay);
532 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY * const overlay);
533 static void blurayCloseOverlay(demux_t *p_demux, int plane);
535 static void onMouseEvent(const vlc_mouse_t *mouse, void *user_data);
536 static void blurayRestartParser(demux_t *p_demux, bool, bool);
537 static void notifyDiscontinuityToParser( demux_sys_t *p_sys );
539 #define STILL_IMAGE_NOT_SET 0
540 #define STILL_IMAGE_INFINITE -1
542 #define CURRENT_TITLE p_sys->pp_title[p_sys->cur_title]
543 #define CUR_LENGTH CURRENT_TITLE->i_length
545 /* */
546 static void FindMountPoint(char **file)
548 char *device = *file;
549 #ifdef HAVE_GETMNTENT_R
550 /* bd path may be a symlink (e.g. /dev/dvd -> /dev/sr0), so make sure
551 * we look up the real device */
552 char *bd_device = realpath(device, NULL);
553 if (bd_device == NULL)
554 return;
556 struct stat st;
557 if (lstat (bd_device, &st) == 0 && S_ISBLK (st.st_mode)) {
558 FILE *mtab = setmntent ("/proc/self/mounts", "r");
559 if (mtab) {
560 struct mntent *m, mbuf;
561 char buf [8192];
563 while ((m = getmntent_r (mtab, &mbuf, buf, sizeof(buf))) != NULL) {
564 if (!strcmp (m->mnt_fsname, bd_device)) {
565 free(device);
566 *file = strdup(m->mnt_dir);
567 break;
570 endmntent (mtab);
573 free(bd_device);
575 #elif defined(__APPLE__)
576 struct stat st;
577 if (!stat (device, &st) && S_ISBLK (st.st_mode)) {
578 int fs_count = getfsstat (NULL, 0, MNT_NOWAIT);
579 if (fs_count > 0) {
580 int bufSize = fs_count * sizeof (struct statfs);
581 struct statfs* mbuf = malloc(bufSize);
582 getfsstat (mbuf, bufSize, MNT_NOWAIT);
583 for (int i = 0; i < fs_count; ++i)
584 if (!strcmp (mbuf[i].f_mntfromname, device)) {
585 free(device);
586 *file = strdup(mbuf[i].f_mntonname);
587 free(mbuf);
588 return;
591 free(mbuf);
594 #else
595 # warning Disc device to mount point not implemented
596 VLC_UNUSED( device );
597 #endif
600 /*****************************************************************************
601 * BD-J background video
602 *****************************************************************************/
604 static void bluraySendBackgroundImage(vlc_object_t *p_obj,
605 es_out_t *p_dst_out,
606 es_out_id_t *p_es,
607 const es_format_t *p_fmt)
609 msg_Info(p_obj, "Start background");
611 block_t *p_block = block_Alloc(p_fmt->video.i_width * p_fmt->video.i_height *
612 p_fmt->video.i_bits_per_pixel / 8);
613 if (!p_block) {
614 msg_Err(p_obj, "Error allocating block for background video");
615 return;
618 // XXX TODO: what would be correct timestamp ???
619 p_block->i_dts = p_block->i_pts = vlc_tick_now() + VLC_TICK_FROM_MS(40);
621 uint8_t *p = p_block->p_buffer;
622 memset(p, 0, p_fmt->video.i_width * p_fmt->video.i_height);
623 p += p_fmt->video.i_width * p_fmt->video.i_height;
624 memset(p, 0x80, p_fmt->video.i_width * p_fmt->video.i_height / 2);
626 es_out_SetPCR(p_dst_out, p_block->i_dts - VLC_TICK_FROM_MS(40));
627 es_out_Control(p_dst_out, ES_OUT_SET_ES, p_es);
628 es_out_Send(p_dst_out, p_es, p_block);
629 es_out_Control( p_dst_out, ES_OUT_VOUT_SET_MOUSE_EVENT, p_es, onMouseEvent, p_obj );
630 es_out_SetPCR(p_dst_out, p_block->i_dts);
633 /*****************************************************************************
634 * cache current playlist (title) information
635 *****************************************************************************/
637 static void setTitleInfo(demux_sys_t *p_sys, BLURAY_TITLE_INFO *info)
639 vlc_mutex_lock(&p_sys->pl_info_lock);
641 if (p_sys->p_pl_info) {
642 bd_free_title_info(p_sys->p_pl_info);
644 p_sys->p_pl_info = info;
645 p_sys->p_clip_info = NULL;
647 if (p_sys->p_pl_info && p_sys->p_pl_info->clip_count) {
648 p_sys->p_clip_info = &p_sys->p_pl_info->clips[0];
651 vlc_mutex_unlock(&p_sys->pl_info_lock);
654 /*****************************************************************************
655 * create input attachment for thumbnail
656 *****************************************************************************/
658 static void attachThumbnail(demux_t *p_demux)
660 demux_sys_t *p_sys = p_demux->p_sys;
662 if (!p_sys->p_meta)
663 return;
665 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,9,0)
666 if (p_sys->p_meta->thumb_count > 0 && p_sys->p_meta->thumbnails) {
667 int64_t size;
668 void *data;
669 if (bd_get_meta_file(p_sys->bluray, p_sys->p_meta->thumbnails[0].path, &data, &size) > 0) {
670 char psz_name[64];
671 input_attachment_t *p_attachment;
673 snprintf(psz_name, sizeof(psz_name), "picture%d_%s", p_sys->i_attachments, p_sys->p_meta->thumbnails[0].path);
675 p_attachment = vlc_input_attachment_New(psz_name, NULL, "Album art", data, size);
676 if (p_attachment) {
677 p_sys->i_cover_idx = p_sys->i_attachments;
678 TAB_APPEND(p_sys->i_attachments, p_sys->attachments, p_attachment);
681 free(data);
683 #endif
686 /*****************************************************************************
687 * stream input
688 *****************************************************************************/
690 static int probeStream(demux_t *p_demux)
692 /* input must be seekable */
693 bool b_canseek = false;
694 vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
695 if (!b_canseek) {
696 return VLC_EGENERIC;
699 /* first sector(s) should be filled with zeros */
700 size_t i_peek;
701 const uint8_t *p_peek;
702 i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 2048 );
703 if( i_peek != 2048 ) {
704 return VLC_EGENERIC;
706 while (i_peek > 0) {
707 if (p_peek[ --i_peek ]) {
708 return VLC_EGENERIC;
712 return VLC_SUCCESS;
715 #ifdef BLURAY_DEMUX
716 static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
718 demux_t *p_demux = (demux_t*)object;
719 demux_sys_t *p_sys = p_demux->p_sys;
720 int result = -1;
722 assert(p_demux->s != NULL);
724 vlc_mutex_lock(&p_sys->read_block_lock);
726 if (vlc_stream_Seek( p_demux->s, lba * INT64_C(2048) ) == VLC_SUCCESS) {
727 size_t req = (size_t)2048 * num_blocks;
728 ssize_t got;
730 got = vlc_stream_Read( p_demux->s, buf, req);
731 if (got < 0) {
732 msg_Err(p_demux, "read from lba %d failed", lba);
733 } else {
734 result = got / 2048;
736 } else {
737 msg_Err(p_demux, "seek to lba %d failed", lba);
740 vlc_mutex_unlock(&p_sys->read_block_lock);
742 return result;
744 #endif
746 /*****************************************************************************
747 * probing of local files
748 *****************************************************************************/
750 /* Descriptor Tag (ECMA 167, 3/7.2) */
751 static int decode_descriptor_tag(const uint8_t *buf)
753 uint16_t id;
754 uint8_t checksum = 0;
755 int i;
757 id = buf[0] | (buf[1] << 8);
759 /* calculate tag checksum */
760 for (i = 0; i < 4; i++) {
761 checksum = (uint8_t)(checksum + buf[i]);
763 for (i = 5; i < 16; i++) {
764 checksum = (uint8_t)(checksum + buf[i]);
767 if (checksum != buf[4]) {
768 return -1;
771 return id;
774 static int probeFile(const char *psz_name)
776 struct stat stat_info;
777 uint8_t peek[2048];
778 unsigned i;
779 int ret = VLC_EGENERIC;
780 int fd;
782 fd = vlc_open(psz_name, O_RDONLY | O_NONBLOCK);
783 if (fd == -1) {
784 return VLC_EGENERIC;
787 if (fstat(fd, &stat_info) == -1) {
788 goto bailout;
790 if (!S_ISREG(stat_info.st_mode) && !S_ISBLK(stat_info.st_mode)) {
791 goto bailout;
794 /* first sector should be filled with zeros */
795 if (read(fd, peek, sizeof(peek)) != sizeof(peek)) {
796 goto bailout;
798 for (i = 0; i < sizeof(peek); i++) {
799 if (peek[ i ]) {
800 goto bailout;
804 /* Check AVDP tag checksum */
805 if (lseek(fd, 256 * 2048, SEEK_SET) == -1 ||
806 read(fd, peek, 16) != 16 ||
807 decode_descriptor_tag(peek) != 2) {
808 goto bailout;
811 ret = VLC_SUCCESS;
813 bailout:
814 vlc_close(fd);
815 return ret;
818 /*****************************************************************************
819 * blurayOpen: module init function
820 *****************************************************************************/
821 static int blurayOpen(vlc_object_t *object)
823 demux_t *p_demux = (demux_t*)object;
824 demux_sys_t *p_sys;
825 bool forced;
826 uint64_t i_init_pos = 0;
828 const char *error_msg = NULL;
829 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
831 if (p_demux->out == NULL)
832 return VLC_EGENERIC;
834 forced = !strncasecmp(p_demux->psz_url, "bluray:", 7);
836 if (p_demux->s) {
837 if (!strncasecmp(p_demux->psz_url, "file:", 5)) {
838 /* use access_demux for local files */
839 return VLC_EGENERIC;
842 if (probeStream(p_demux) != VLC_SUCCESS) {
843 return VLC_EGENERIC;
846 } else if (!forced) {
847 if (!p_demux->psz_filepath) {
848 return VLC_EGENERIC;
851 if (probeFile(p_demux->psz_filepath) != VLC_SUCCESS) {
852 return VLC_EGENERIC;
856 /* */
857 p_demux->p_sys = p_sys = vlc_obj_calloc(object, 1, sizeof(*p_sys));
858 if (unlikely(!p_sys))
859 return VLC_ENOMEM;
861 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
863 /* init demux info fields */
864 p_sys->updates = 0;
866 TAB_INIT(p_sys->i_title, p_sys->pp_title);
867 TAB_INIT(p_sys->i_attachments, p_sys->attachments);
868 ARRAY_INIT(p_sys->events_delayed);
870 vlc_mouse_Init(&p_sys->oldmouse);
872 vlc_mutex_init(&p_sys->pl_info_lock);
873 vlc_mutex_init(&p_sys->bdj.lock);
874 vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
876 /* request sub demuxers to skip continuity check as some split
877 file concatenation are just resetting counters... */
878 var_Create( p_demux, "ts-cc-check", VLC_VAR_BOOL );
879 var_SetBool( p_demux, "ts-cc-check", false );
880 var_Create( p_demux, "ts-standard", VLC_VAR_STRING );
881 var_SetString( p_demux, "ts-standard", "mpeg" );
882 var_Create( p_demux, "ts-pmtfix-waitdata", VLC_VAR_BOOL );
883 var_SetBool( p_demux, "ts-pmtfix-waitdata", false );
884 var_Create( p_demux, "ts-patfix", VLC_VAR_BOOL );
885 var_SetBool( p_demux, "ts-patfix", false );
886 var_Create( p_demux, "ts-pcr-offsetfix", VLC_VAR_BOOL );
887 var_SetBool( p_demux, "ts-pcr-offsetfix", false );
889 #ifdef DEBUG_BLURAY
890 p_bluray_DebugObject = VLC_OBJECT(p_demux);
891 bd_set_debug_mask(BLURAY_DEBUG_MASK);
892 bd_set_debug_handler(bluray_DebugHandler);
893 #endif
895 /* Open BluRay */
896 #ifdef BLURAY_DEMUX
897 if (p_demux->s) {
898 i_init_pos = vlc_stream_Tell(p_demux->s);
900 p_sys->bluray = bd_init();
901 if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
902 bd_close(p_sys->bluray);
903 p_sys->bluray = NULL;
905 } else
906 #endif
908 if (!p_demux->psz_filepath) {
909 /* no path provided (bluray://). use default DVD device. */
910 p_sys->psz_bd_path = var_InheritString(object, "dvd");
911 } else {
912 /* store current bd path */
913 p_sys->psz_bd_path = strdup(p_demux->psz_filepath);
916 /* If we're passed a block device, try to convert it to the mount point. */
917 FindMountPoint(&p_sys->psz_bd_path);
919 p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
921 if (!p_sys->bluray) {
922 goto error;
925 /* Warning the user about AACS/BD+ */
926 const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
928 /* Is it a bluray? */
929 if (!disc_info->bluray_detected) {
930 if (forced) {
931 BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
933 goto error;
936 msg_Info(p_demux, "First play: %i, Top menu: %i\n"
937 "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
938 disc_info->first_play_supported, disc_info->top_menu_supported,
939 disc_info->num_hdmv_titles, disc_info->num_bdj_titles,
940 disc_info->num_unsupported_titles);
942 /* AACS */
943 if (disc_info->aacs_detected) {
944 msg_Dbg(p_demux, "Disc is using AACS");
945 if (!disc_info->libaacs_detected)
946 BLURAY_ERROR(_("This Blu-ray Disc needs a library for AACS decoding"
947 ", and your system does not have it."));
948 if (!disc_info->aacs_handled) {
949 if (disc_info->aacs_error_code) {
950 switch (disc_info->aacs_error_code) {
951 case BD_AACS_CORRUPTED_DISC:
952 BLURAY_ERROR(_("Blu-ray Disc is corrupted."));
953 case BD_AACS_NO_CONFIG:
954 BLURAY_ERROR(_("Missing AACS configuration file!"));
955 case BD_AACS_NO_PK:
956 BLURAY_ERROR(_("No valid processing key found in AACS config file."));
957 case BD_AACS_NO_CERT:
958 BLURAY_ERROR(_("No valid host certificate found in AACS config file."));
959 case BD_AACS_CERT_REVOKED:
960 BLURAY_ERROR(_("AACS Host certificate revoked."));
961 case BD_AACS_MMC_FAILED:
962 BLURAY_ERROR(_("AACS MMC failed."));
968 /* BD+ */
969 if (disc_info->bdplus_detected) {
970 msg_Dbg(p_demux, "Disc is using BD+");
971 if (!disc_info->libbdplus_detected)
972 BLURAY_ERROR(_("This Blu-ray Disc needs a library for BD+ decoding"
973 ", and your system does not have it."));
974 if (!disc_info->bdplus_handled)
975 BLURAY_ERROR(_("Your system BD+ decoding library does not work. "
976 "Missing configuration?"));
979 /* set player region code */
980 char *psz_region = var_InheritString(p_demux, "bluray-region");
981 unsigned int region = psz_region ? (psz_region[0] - 'A') : REGION_DEFAULT;
982 free(psz_region);
983 bd_set_player_setting(p_sys->bluray, BLURAY_PLAYER_SETTING_REGION_CODE, 1<<region);
985 /* set preferred languages */
986 const char *psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
987 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG, psz_code);
988 psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
989 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG, psz_code);
990 psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
991 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_MENU_LANG, psz_code);
993 /* Get disc metadata */
994 p_sys->p_meta = bd_get_meta(p_sys->bluray);
995 if (!p_sys->p_meta)
996 msg_Warn(p_demux, "Failed to get meta info.");
998 p_sys->i_cover_idx = -1;
999 attachThumbnail(p_demux);
1001 p_sys->b_menu = var_InheritBool(p_demux, "bluray-menu");
1003 /* Check BD-J capability */
1004 if (p_sys->b_menu && disc_info->bdj_detected && !disc_info->bdj_handled) {
1005 msg_Err(p_demux, "BD-J menus not supported. Playing without menus. "
1006 "BD-J support: %d, JVM found: %d, JVM usable: %d",
1007 disc_info->bdj_supported, disc_info->libjvm_detected, disc_info->bdj_handled);
1008 vlc_dialog_display_error(p_demux, _("Java required"),
1009 _("This Blu-ray disc requires Java for menus support.%s\nThe disc will be played without menus."),
1010 !disc_info->libjvm_detected ? _("Java was not found on your system.") : "");
1011 p_sys->b_menu = false;
1014 if(disc_info->bdj_detected &&p_sys->b_menu &&
1015 BDJO_IsBlacklisted(p_demux, p_sys->psz_bd_path))
1017 p_sys->b_menu = vlc_dialog_wait_question( p_demux,
1018 VLC_DIALOG_QUESTION_NORMAL,
1019 _("Play without Menus"),
1020 _("Try anyway"),
1021 NULL,
1022 _("BDJO Menu check"),
1023 "%s",
1024 _("Incompatible Java Menu detected"));
1027 /* Get titles and chapters */
1028 blurayInitTitles(p_demux, disc_info->num_hdmv_titles + disc_info->num_bdj_titles + 1/*Top Menu*/ + 1/*First Play*/);
1031 * Initialize the event queue, so we can receive events in blurayDemux(Menu).
1033 bd_get_event(p_sys->bluray, NULL);
1035 /* Registering overlay event handler */
1036 bd_register_overlay_proc(p_sys->bluray, p_demux, blurayOverlayProc);
1038 if (p_sys->b_menu) {
1040 /* Register ARGB overlay handler for BD-J */
1041 if (disc_info->num_bdj_titles)
1042 bd_register_argb_overlay_proc(p_sys->bluray, p_demux, blurayArgbOverlayProc, NULL);
1044 /* libbluray will start playback from "First-Title" title */
1045 if (bd_play(p_sys->bluray) == 0)
1046 BLURAY_ERROR(_("Failed to start bluray playback. Please try without menu support."));
1048 } else {
1049 /* set start title number */
1050 if (bluraySetTitle(p_demux, p_sys->i_longest_title) != VLC_SUCCESS) {
1051 msg_Err(p_demux, "Could not set the title %d", p_sys->i_longest_title);
1052 goto error;
1056 p_sys->p_tf_out = timestamps_filter_es_out_New(p_demux->out);
1057 if(unlikely(!p_sys->p_tf_out))
1058 goto error;
1060 p_sys->p_out = esOutNew(VLC_OBJECT(p_demux), p_sys->p_tf_out, p_demux);
1061 if (unlikely(p_sys->p_out == NULL))
1062 goto error;
1064 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
1065 if (!p_sys->p_parser) {
1066 msg_Err(p_demux, "Failed to create TS demuxer");
1067 goto error;
1070 p_demux->pf_control = blurayControl;
1071 p_demux->pf_demux = blurayDemux;
1073 return VLC_SUCCESS;
1075 error:
1076 if (error_msg)
1077 vlc_dialog_display_error(p_demux, _("Blu-ray error"), "%s", error_msg);
1078 blurayClose(object);
1080 if (p_demux->s != NULL) {
1081 /* restore stream position */
1082 if (vlc_stream_Seek(p_demux->s, i_init_pos) != VLC_SUCCESS) {
1083 msg_Err(p_demux, "Failed to seek back to stream start");
1084 return VLC_ETIMEOUT;
1088 return VLC_EGENERIC;
1089 #undef BLURAY_ERROR
1093 /*****************************************************************************
1094 * blurayClose: module destroy function
1095 *****************************************************************************/
1096 static void blurayClose(vlc_object_t *object)
1098 demux_t *p_demux = (demux_t*)object;
1099 demux_sys_t *p_sys = p_demux->p_sys;
1101 setTitleInfo(p_sys, NULL);
1104 * Close libbluray first.
1105 * This will close all the overlays before we release p_vout
1106 * bd_close(NULL) can crash
1108 if (p_sys->bluray) {
1109 bd_close(p_sys->bluray);
1112 vlc_mutex_lock(&p_sys->bdj.lock);
1113 for(int i = 0; i < MAX_OVERLAY; i++)
1114 blurayCloseOverlay(p_demux, i);
1115 vlc_mutex_unlock(&p_sys->bdj.lock);
1117 if (p_sys->p_parser)
1118 vlc_demux_chained_Delete(p_sys->p_parser);
1120 if (p_sys->p_out != NULL)
1121 es_out_Delete(p_sys->p_out);
1122 if(p_sys->p_tf_out)
1123 timestamps_filter_es_out_Delete(p_sys->p_tf_out);
1125 /* Titles */
1126 for (unsigned int i = 0; i < p_sys->i_title; i++)
1127 vlc_input_title_Delete(p_sys->pp_title[i]);
1128 TAB_CLEAN(p_sys->i_title, p_sys->pp_title);
1130 for (int i = 0; i < p_sys->i_attachments; i++)
1131 vlc_input_attachment_Release(p_sys->attachments[i]);
1132 TAB_CLEAN(p_sys->i_attachments, p_sys->attachments);
1134 ARRAY_RESET(p_sys->events_delayed);
1136 free(p_sys->psz_bd_path);
1139 /*****************************************************************************
1140 * Elementary streams handling
1141 *****************************************************************************/
1142 static uint8_t blurayGetStreamsUnlocked(demux_sys_t *p_sys,
1143 int i_stream_type,
1144 BLURAY_STREAM_INFO **pp_streams)
1146 if(!p_sys->p_clip_info)
1147 return 0;
1149 switch(i_stream_type)
1151 case BD_EVENT_AUDIO_STREAM:
1152 *pp_streams = p_sys->p_clip_info->audio_streams;
1153 return p_sys->p_clip_info->audio_stream_count;
1154 case BD_EVENT_PG_TEXTST_STREAM:
1155 *pp_streams = p_sys->p_clip_info->pg_streams;
1156 return p_sys->p_clip_info->pg_stream_count;
1157 default:
1158 return 0;
1162 static BLURAY_STREAM_INFO * blurayGetStreamInfoUnlocked(demux_sys_t *p_sys,
1163 int i_stream_type,
1164 uint8_t i_stream_idx)
1166 BLURAY_STREAM_INFO *p_streams = NULL;
1167 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_stream_type, &p_streams);
1168 if(i_stream_idx < i_streams_count)
1169 return &p_streams[i_stream_idx];
1170 else
1171 return NULL;
1174 static BLURAY_STREAM_INFO * blurayGetStreamInfoByPIDUnlocked(demux_sys_t *p_sys,
1175 int i_pid)
1177 for(int i_type=BD_EVENT_AUDIO_STREAM; i_type<=BD_EVENT_SECONDARY_VIDEO_STREAM; i_type++)
1179 BLURAY_STREAM_INFO *p_streams;
1180 uint8_t i_streams_count = blurayGetStreamsUnlocked(p_sys, i_type, &p_streams);
1181 for(uint8_t i=0; i<i_streams_count; i++)
1183 if(p_streams[i].pid == i_pid)
1184 return &p_streams[i];
1187 return NULL;
1190 static void setStreamLang(demux_sys_t *p_sys, es_format_t *p_fmt)
1192 vlc_mutex_lock(&p_sys->pl_info_lock);
1194 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoByPIDUnlocked(p_sys, p_fmt->i_id);
1195 if(p_stream)
1197 free(p_fmt->psz_language);
1198 p_fmt->psz_language = strndup((const char *)p_stream->lang, 3);
1201 vlc_mutex_unlock(&p_sys->pl_info_lock);
1204 static int blurayGetStreamPID(demux_sys_t *p_sys, int i_stream_type, uint8_t i_stream_idx)
1206 vlc_mutex_lock(&p_sys->pl_info_lock);
1208 BLURAY_STREAM_INFO *p_stream = blurayGetStreamInfoUnlocked(p_sys,
1209 i_stream_type,
1210 i_stream_idx);
1211 int i_pid = p_stream ? p_stream->pid : -1;
1213 vlc_mutex_unlock(&p_sys->pl_info_lock);
1215 return i_pid;
1218 /*****************************************************************************
1219 * bluray fake es_out
1220 *****************************************************************************/
1221 typedef struct
1223 es_out_t *p_dst_out;
1224 vlc_object_t *p_obj;
1225 vlc_array_t es; /* es_pair_t */
1226 bool b_entered_recycling;
1227 bool b_restart_decoders_on_reuse;
1228 void *priv;
1229 bool b_discontinuity;
1230 bool b_disable_output;
1231 bool b_lowdelay;
1232 vlc_mutex_t lock;
1233 struct
1235 int i_audio_pid; /* Selected audio stream. -1 if default */
1236 int i_spu_pid; /* Selected spu stream. -1 if default */
1237 } selected;
1238 struct
1240 es_out_id_t *p_video_es;
1241 size_t channels[MAX_OVERLAY];
1242 } overlay;
1243 es_out_t es_out;
1244 } bluray_esout_priv_t;
1246 enum
1248 BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID = ES_OUT_PRIVATE_START,
1249 BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID,
1250 BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY,
1251 BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT,
1252 BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT,
1253 BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY,
1254 BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY,
1255 BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY,
1256 BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY,
1257 BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS,
1260 static es_out_id_t *bluray_esOutAddUnlocked(bluray_esout_priv_t *esout_priv,
1261 const es_format_t *p_fmt)
1263 demux_t *p_demux = esout_priv->priv;
1264 demux_sys_t *p_sys = p_demux->p_sys;
1265 es_format_t fmt;
1266 bool b_select = false;
1268 es_format_Copy(&fmt, p_fmt);
1270 switch (fmt.i_cat) {
1271 case VIDEO_ES:
1272 if(esout_priv->b_lowdelay)
1274 fmt.video.i_frame_rate = 1; fmt.video.i_frame_rate_base = 1;
1275 fmt.b_packetized = true;
1277 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1278 b_select = (p_fmt->i_id == 0x1011);
1279 break;
1280 case AUDIO_ES:
1281 if (esout_priv->selected.i_audio_pid != -1) {
1282 if (esout_priv->selected.i_audio_pid == p_fmt->i_id)
1283 b_select = true;
1284 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1286 setStreamLang(p_sys, &fmt);
1287 break ;
1288 case SPU_ES:
1289 if (esout_priv->selected.i_spu_pid != -1) {
1290 if (esout_priv->selected.i_spu_pid == p_fmt->i_id)
1291 b_select = p_sys->b_spu_enable;
1292 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1294 setStreamLang(p_sys, &fmt);
1295 break ;
1296 default:
1300 es_out_id_t *p_es = NULL;
1301 if (p_fmt->i_id >= 0) {
1302 /* Ensure we are not overriding anything */
1303 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, p_fmt->i_id);
1304 if (p_pair == NULL)
1306 msg_Info(p_demux, "Adding ES %d select %d", p_fmt->i_id, b_select);
1307 p_es = es_out_Add(esout_priv->p_dst_out, &fmt);
1308 es_pair_Add(&esout_priv->es, &fmt, p_es);
1310 else
1312 msg_Info(p_demux, "Reusing ES %d", p_fmt->i_id);
1313 p_pair->b_recyling = false;
1314 p_es = p_pair->p_es;
1315 if(!es_format_IsSimilar(p_fmt, &p_pair->fmt) ||
1316 p_fmt->b_packetized != p_pair->fmt.b_packetized ||
1317 strcmp(fmt.psz_language ? fmt.psz_language : "",
1318 p_pair->fmt.psz_language ? p_pair->fmt.psz_language : "") ||
1319 esout_priv->b_restart_decoders_on_reuse)
1320 es_out_Control(esout_priv->p_dst_out, ES_OUT_SET_ES_FMT, p_pair->p_es, &fmt);
1321 es_format_Clean(&p_pair->fmt);
1322 es_format_Copy(&p_pair->fmt, &fmt);
1324 if (b_select)
1325 es_out_Control(esout_priv->p_dst_out, ES_OUT_SET_ES, p_es);
1328 if (p_es && fmt.i_cat == VIDEO_ES && b_select)
1330 es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_SET_MOUSE_EVENT, p_es,
1331 onMouseEvent, p_demux);
1332 esout_priv->overlay.p_video_es = p_es;
1335 es_format_Clean(&fmt);
1337 return p_es;
1340 static es_out_id_t *bluray_esOutAdd(es_out_t *p_out, input_source_t *in, const es_format_t *p_fmt)
1342 VLC_UNUSED(in);
1343 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1345 vlc_mutex_lock(&esout_priv->lock);
1346 es_out_id_t *p_es = bluray_esOutAddUnlocked(esout_priv, p_fmt);
1347 vlc_mutex_unlock(&esout_priv->lock);
1349 return p_es;
1352 static void bluray_esOutDeleteNonReusedESUnlocked(es_out_t *p_out)
1354 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1356 if(!esout_priv->b_entered_recycling)
1357 return;
1358 esout_priv->b_entered_recycling = false;
1359 esout_priv->b_restart_decoders_on_reuse = true;
1361 es_pair_t *p_pair;
1362 while((p_pair = getUnusedEsPair(&esout_priv->es)))
1364 msg_Info(esout_priv->p_obj, "Trashing unused ES %d", p_pair->fmt.i_id);
1366 if(esout_priv->overlay.p_video_es == p_pair->p_es)
1367 esout_priv->overlay.p_video_es = NULL;
1369 es_out_Del(esout_priv->p_dst_out, p_pair->p_es);
1371 es_pair_Remove(&esout_priv->es, p_pair);
1375 static int bluray_esOutSend(es_out_t *p_out, es_out_id_t *p_es, block_t *p_block)
1377 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1378 vlc_mutex_lock(&esout_priv->lock);
1380 bluray_esOutDeleteNonReusedESUnlocked(p_out);
1382 if(esout_priv->b_discontinuity)
1383 esout_priv->b_discontinuity = false;
1385 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1386 if(p_pair && p_pair->i_next_block_flags)
1388 p_block->i_flags |= p_pair->i_next_block_flags;
1389 p_pair->i_next_block_flags = 0;
1391 if(esout_priv->b_disable_output)
1393 block_Release(p_block);
1394 p_block = NULL;
1396 vlc_mutex_unlock(&esout_priv->lock);
1397 return (p_block) ? es_out_Send(esout_priv->p_dst_out, p_es, p_block) : VLC_SUCCESS;
1400 static void bluray_esOutDel(es_out_t *p_out, es_out_id_t *p_es)
1402 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1403 vlc_mutex_lock(&esout_priv->lock);
1405 if(esout_priv->b_discontinuity)
1406 esout_priv->b_discontinuity = false;
1408 es_pair_t *p_pair = getEsPairByES(&esout_priv->es, p_es);
1409 if (p_pair)
1411 p_pair->b_recyling = true;
1412 esout_priv->b_entered_recycling = true;
1415 vlc_mutex_unlock(&esout_priv->lock);
1418 static int bluray_esOutControl(es_out_t *p_out, input_source_t *in, int i_query, va_list args)
1420 VLC_UNUSED(in);
1421 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1422 int i_ret;
1423 vlc_mutex_lock(&esout_priv->lock);
1425 if(esout_priv->b_disable_output &&
1426 i_query < ES_OUT_PRIVATE_START)
1428 vlc_mutex_unlock(&esout_priv->lock);
1429 return VLC_EGENERIC;
1432 if(esout_priv->b_discontinuity)
1433 esout_priv->b_discontinuity = false;
1435 switch(i_query)
1437 case BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID:
1438 case BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID:
1440 bool b_select = (i_query == BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID);
1441 const int i_bluray_stream_type = va_arg(args, int);
1442 const int i_pid = va_arg(args, int);
1443 switch(i_bluray_stream_type)
1445 case BD_EVENT_AUDIO_STREAM:
1446 esout_priv->selected.i_audio_pid = i_pid;
1447 break;
1448 case BD_EVENT_PG_TEXTST_STREAM:
1449 esout_priv->selected.i_spu_pid = i_pid;
1450 break;
1451 default:
1452 break;
1455 es_pair_t *p_pair = getEsPairByPID(&esout_priv->es, i_pid);
1456 if(unlikely(!p_pair))
1458 vlc_mutex_unlock(&esout_priv->lock);
1459 return VLC_EGENERIC;
1462 i_ret = es_out_Control(esout_priv->p_dst_out,
1463 b_select ? ES_OUT_SET_ES : ES_OUT_UNSET_ES,
1464 p_pair->p_es);
1465 } break;
1467 case BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY:
1469 esout_priv->b_discontinuity = true;
1470 i_ret = VLC_SUCCESS;
1471 } break;
1473 case BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS:
1475 esout_priv->b_restart_decoders_on_reuse = !va_arg(args, int);
1476 i_ret = VLC_SUCCESS;
1477 } break;
1479 case BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT:
1480 case BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT:
1482 esout_priv->b_disable_output = (i_query == BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
1483 i_ret = VLC_SUCCESS;
1484 } break;
1486 case BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY:
1487 case BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY:
1489 esout_priv->b_lowdelay = (i_query == BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY);
1490 i_ret = VLC_SUCCESS;
1491 } break;
1493 case BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY:
1495 int i_plane = va_arg(args, int);
1496 subpicture_t *p_pic = va_arg(args, subpicture_t *);
1497 if(!esout_priv->overlay.p_video_es)
1499 es_format_t fmt;
1500 es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_I420);
1501 video_format_Setup(&fmt.video, VLC_CODEC_I420,
1502 1920, 1080, 1920, 1080, 1, 1);
1503 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1504 fmt.i_id = 0x1011;
1505 fmt.i_group = 1;
1506 fmt.video.i_frame_rate = 1; fmt.video.i_frame_rate_base = 1;
1507 fmt.b_packetized = true;
1508 esout_priv->overlay.p_video_es = bluray_esOutAddUnlocked(esout_priv, &fmt);
1509 if(esout_priv->overlay.p_video_es)
1511 bluraySendBackgroundImage(esout_priv->p_obj,
1512 esout_priv->p_dst_out,
1513 esout_priv->overlay.p_video_es,
1514 &fmt);
1516 es_format_Clean(&fmt);
1519 if(esout_priv->overlay.p_video_es && i_plane < MAX_OVERLAY)
1521 i_ret = es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_ADD_OVERLAY,
1522 esout_priv->overlay.p_video_es, p_pic,
1523 &esout_priv->overlay.channels[i_plane]);
1525 else
1527 i_ret = VLC_EGENERIC;
1529 break;
1532 case BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY:
1534 int i_plane = va_arg(args, int);
1535 if(esout_priv->overlay.p_video_es &&
1536 i_plane < MAX_OVERLAY &&
1537 (ssize_t)esout_priv->overlay.channels[i_plane] != VOUT_SPU_CHANNEL_INVALID)
1539 i_ret = es_out_Control(esout_priv->p_dst_out, ES_OUT_VOUT_DEL_OVERLAY,
1540 esout_priv->overlay.p_video_es,
1541 esout_priv->overlay.channels[i_plane]);
1542 esout_priv->overlay.channels[i_plane] = VOUT_SPU_CHANNEL_INVALID;
1544 else
1546 assert((ssize_t)esout_priv->overlay.channels[i_plane] == VOUT_SPU_CHANNEL_INVALID);
1547 i_ret = VLC_EGENERIC;
1549 break;
1552 case ES_OUT_SET_ES_DEFAULT:
1553 case ES_OUT_SET_ES:
1554 case ES_OUT_UNSET_ES:
1555 case ES_OUT_SET_ES_STATE:
1556 i_ret = VLC_EGENERIC;
1557 break;
1559 case ES_OUT_GET_ES_STATE:
1560 va_arg(args, es_out_id_t *);
1561 *va_arg(args, bool *) = true;
1562 i_ret = VLC_SUCCESS;
1563 break;
1565 default:
1566 i_ret = es_out_vaControl(esout_priv->p_dst_out, i_query, args);
1567 break;
1569 vlc_mutex_unlock(&esout_priv->lock);
1570 return i_ret;
1573 static void bluray_esOutDestroy(es_out_t *p_out)
1575 bluray_esout_priv_t *esout_priv = container_of(p_out, bluray_esout_priv_t, es_out);
1577 for (size_t i = 0; i < vlc_array_count(&esout_priv->es); ++i)
1578 es_pair_Delete(vlc_array_item_at_index(&esout_priv->es, i));
1579 vlc_array_clear(&esout_priv->es);
1580 free(esout_priv);
1583 static const struct es_out_callbacks bluray_esOutCallbacks = {
1584 .add = bluray_esOutAdd,
1585 .send = bluray_esOutSend,
1586 .del = bluray_esOutDel,
1587 .control = bluray_esOutControl,
1588 .destroy = bluray_esOutDestroy,
1591 static es_out_t *esOutNew(vlc_object_t *p_obj, es_out_t *p_dst_out, void *priv)
1593 bluray_esout_priv_t *esout_priv = malloc(sizeof(*esout_priv));
1594 if (unlikely(esout_priv == NULL))
1595 return NULL;
1597 vlc_array_init(&esout_priv->es);
1598 esout_priv->p_dst_out = p_dst_out;
1599 esout_priv->p_obj = p_obj;
1600 esout_priv->priv = priv;
1601 esout_priv->es_out.cbs = &bluray_esOutCallbacks;
1602 esout_priv->b_discontinuity = false;
1603 esout_priv->b_disable_output = false;
1604 esout_priv->b_entered_recycling = false;
1605 esout_priv->b_restart_decoders_on_reuse = true;
1606 esout_priv->b_lowdelay = false;
1607 esout_priv->selected.i_audio_pid = -1;
1608 esout_priv->selected.i_spu_pid = -1;
1609 esout_priv->overlay.p_video_es = NULL;
1610 for(size_t i=0; i<MAX_OVERLAY; i++)
1611 esout_priv->overlay.channels[i] = VOUT_SPU_CHANNEL_INVALID;
1612 vlc_mutex_init(&esout_priv->lock);
1613 return &esout_priv->es_out;
1616 /*****************************************************************************
1617 * subpicture_updater_t functions:
1618 *****************************************************************************/
1620 static bluray_overlay_t *updater_lock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1622 /* this lock is held while vout accesses overlay. => overlay can't be closed. */
1623 vlc_mutex_lock(&p_upd_sys->lock);
1625 bluray_overlay_t *ov = p_upd_sys->p_overlay;
1626 if (ov) {
1627 /* this lock is held while vout accesses overlay. => overlay can't be modified. */
1628 vlc_mutex_lock(&ov->lock);
1629 return ov;
1632 /* overlay has been closed */
1633 vlc_mutex_unlock(&p_upd_sys->lock);
1634 return NULL;
1637 static void updater_unlock_overlay(bluray_spu_updater_sys_t *p_upd_sys)
1639 assert (p_upd_sys->p_overlay);
1641 vlc_mutex_unlock(&p_upd_sys->p_overlay->lock);
1642 vlc_mutex_unlock(&p_upd_sys->lock);
1645 static int subpictureUpdaterValidate(subpicture_t *p_subpic,
1646 bool b_fmt_src, const video_format_t *p_fmt_src,
1647 bool b_fmt_dst, const video_format_t *p_fmt_dst,
1648 vlc_tick_t i_ts)
1650 VLC_UNUSED(b_fmt_src);
1651 VLC_UNUSED(b_fmt_dst);
1652 VLC_UNUSED(p_fmt_src);
1653 VLC_UNUSED(p_fmt_dst);
1654 VLC_UNUSED(i_ts);
1656 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1657 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1659 if (!p_overlay) {
1660 return 1;
1663 int res = p_overlay->status == Outdated;
1665 updater_unlock_overlay(p_upd_sys);
1667 return res;
1670 static void subpictureUpdaterUpdate(subpicture_t *p_subpic,
1671 const video_format_t *p_fmt_src,
1672 const video_format_t *p_fmt_dst,
1673 vlc_tick_t i_ts)
1675 VLC_UNUSED(p_fmt_src);
1676 VLC_UNUSED(p_fmt_dst);
1677 VLC_UNUSED(i_ts);
1678 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1679 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1681 if (!p_overlay) {
1682 return;
1686 * When this function is called, all p_subpic regions are gone.
1687 * We need to duplicate our regions (stored internaly) to this subpic.
1689 subpicture_region_t *p_src = p_overlay->p_regions;
1690 if (!p_src) {
1691 updater_unlock_overlay(p_upd_sys);
1692 return;
1695 subpicture_region_t **p_dst = &p_subpic->p_region;
1696 while (p_src != NULL) {
1697 *p_dst = subpicture_region_Copy(p_src);
1698 if (*p_dst == NULL)
1699 break;
1700 p_dst = &(*p_dst)->p_next;
1701 p_src = p_src->p_next;
1703 if (*p_dst != NULL)
1704 (*p_dst)->p_next = NULL;
1705 p_overlay->status = Displayed;
1707 updater_unlock_overlay(p_upd_sys);
1710 static void subpictureUpdaterDestroy(subpicture_t *p_subpic)
1712 bluray_spu_updater_sys_t *p_upd_sys = p_subpic->updater.p_sys;
1713 bluray_overlay_t *p_overlay = updater_lock_overlay(p_upd_sys);
1715 if (p_overlay) {
1716 /* vout is closed (seek, new clip, ?). Overlay must be redrawn. */
1717 p_overlay->status = ToDisplay;
1718 p_overlay->b_on_vout = false;
1719 updater_unlock_overlay(p_upd_sys);
1722 unref_subpicture_updater(p_upd_sys);
1725 static subpicture_t *bluraySubpictureCreate(bluray_overlay_t *p_ov)
1727 bluray_spu_updater_sys_t *p_upd_sys = malloc(sizeof(*p_upd_sys));
1728 if (unlikely(p_upd_sys == NULL)) {
1729 return NULL;
1732 p_upd_sys->p_overlay = p_ov;
1734 subpicture_updater_t updater = {
1735 .pf_validate = subpictureUpdaterValidate,
1736 .pf_update = subpictureUpdaterUpdate,
1737 .pf_destroy = subpictureUpdaterDestroy,
1738 .p_sys = p_upd_sys,
1741 subpicture_t *p_pic = subpicture_New(&updater);
1742 if (p_pic == NULL) {
1743 free(p_upd_sys);
1744 return NULL;
1747 p_pic->i_original_picture_width = p_ov->width;
1748 p_pic->i_original_picture_height = p_ov->height;
1749 p_pic->b_absolute = true;
1751 vlc_mutex_init(&p_upd_sys->lock);
1752 p_upd_sys->ref_cnt = 2;
1754 p_ov->p_updater = p_upd_sys;
1756 return p_pic;
1759 /*****************************************************************************
1760 * User input events:
1761 *****************************************************************************/
1762 static void onMouseEvent(const vlc_mouse_t *newmouse, void *user_data)
1764 demux_t *p_demux = user_data;
1765 demux_sys_t *p_sys = p_demux->p_sys;
1767 if (!newmouse) {
1768 vlc_mouse_Init(&p_sys->oldmouse);
1769 return;
1772 if (vlc_mouse_HasMoved(&p_sys->oldmouse, newmouse))
1773 bd_mouse_select(p_sys->bluray, -1, newmouse->i_x, newmouse->i_y);
1775 if (vlc_mouse_HasPressed( &p_sys->oldmouse, newmouse, MOUSE_BUTTON_LEFT))
1776 bd_user_input(p_sys->bluray, -1, BD_VK_MOUSE_ACTIVATE);
1777 p_sys->oldmouse = *newmouse;
1780 static int sendKeyEvent(demux_sys_t *p_sys, unsigned int key)
1782 if (bd_user_input(p_sys->bluray, -1, key) < 0)
1783 return VLC_EGENERIC;
1785 return VLC_SUCCESS;
1788 /*****************************************************************************
1789 * libbluray overlay handling:
1790 *****************************************************************************/
1792 static void blurayCloseOverlay(demux_t *p_demux, int plane)
1794 demux_sys_t *p_sys = p_demux->p_sys;
1795 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1797 if (ov != NULL) {
1799 /* drop overlay from vout */
1800 if (ov->p_updater) {
1801 unref_subpicture_updater(ov->p_updater);
1804 /* no references to this overlay exist in vo anymore */
1805 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DELETE_OVERLAY, plane);
1807 subpicture_region_ChainDelete(ov->p_regions);
1808 free(ov);
1810 p_sys->bdj.p_overlays[plane] = NULL;
1815 * Mark the overlay as "ToDisplay" status.
1816 * This will not send the overlay to the vout instantly, as the vout
1817 * may not be acquired (not acquirable) yet.
1818 * If is has already been acquired, the overlay has already been sent to it,
1819 * therefore, we only flag the overlay as "Outdated"
1821 static void blurayActivateOverlay(demux_t *p_demux, int plane)
1823 demux_sys_t *p_sys = p_demux->p_sys;
1824 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1826 if(!ov)
1827 return;
1830 * If the overlay is already displayed, mark the picture as outdated.
1831 * We must NOT use vout_PutSubpicture if a picture is already displayed.
1833 vlc_mutex_lock(&ov->lock);
1834 if (ov->status >= Displayed && ov->b_on_vout) {
1835 ov->status = Outdated;
1836 vlc_mutex_unlock(&ov->lock);
1837 return;
1841 * Mark the overlay as available, but don't display it right now.
1842 * the blurayDemuxMenu will send it to vout, as it may be unavailable when
1843 * the overlay is computed
1845 ov->status = ToDisplay;
1846 vlc_mutex_unlock(&ov->lock);
1850 * Destroy every regions in the subpicture.
1851 * This is done in two steps:
1852 * - Wiping our private regions list
1853 * - Flagging the overlay as outdated, so the changes are replicated from
1854 * the subpicture_updater_t::pf_update
1855 * This doesn't destroy the subpicture, as the overlay may be used again by libbluray.
1857 static void blurayClearOverlay(demux_t *p_demux, int plane)
1859 demux_sys_t *p_sys = p_demux->p_sys;
1860 bluray_overlay_t *ov = p_sys->bdj.p_overlays[plane];
1862 if(!ov)
1863 return;
1865 vlc_mutex_lock(&ov->lock);
1867 subpicture_region_ChainDelete(ov->p_regions);
1868 ov->p_regions = NULL;
1869 ov->status = Outdated;
1871 vlc_mutex_unlock(&ov->lock);
1874 static void blurayInitOverlay(demux_t *p_demux, int plane, int width, int height)
1876 demux_sys_t *p_sys = p_demux->p_sys;
1878 if(p_sys->bdj.p_overlays[plane])
1880 /* Should not happen */
1881 msg_Warn( p_demux, "Trying to init over an existing overlay" );
1882 blurayClearOverlay( p_demux, plane );
1883 blurayCloseOverlay( p_demux, plane );
1886 bluray_overlay_t *ov = calloc(1, sizeof(*ov));
1887 if (unlikely(ov == NULL))
1888 return;
1890 ov->width = width;
1891 ov->height = height;
1892 ov->b_on_vout = false;
1894 vlc_mutex_init(&ov->lock);
1896 p_sys->bdj.p_overlays[plane] = ov;
1900 * This will draw to the overlay by adding a region to our region list
1901 * This will have to be copied to the subpicture used to render the overlay.
1903 static void blurayDrawOverlay(demux_t *p_demux, const BD_OVERLAY* const eventov)
1905 demux_sys_t *p_sys = p_demux->p_sys;
1907 bluray_overlay_t *ov = p_sys->bdj.p_overlays[eventov->plane];
1908 if(!ov)
1909 return;
1912 * Compute a subpicture_region_t.
1913 * It will be copied and sent to the vout later.
1915 vlc_mutex_lock(&ov->lock);
1917 /* Find a region to update */
1918 subpicture_region_t **pp_reg = &ov->p_regions;
1919 subpicture_region_t *p_reg = ov->p_regions;
1920 subpicture_region_t *p_last = NULL;
1921 while (p_reg != NULL) {
1922 p_last = p_reg;
1923 if (p_reg->i_x == eventov->x &&
1924 p_reg->i_y == eventov->y &&
1925 p_reg->fmt.i_width == eventov->w &&
1926 p_reg->fmt.i_height == eventov->h &&
1927 p_reg->fmt.i_chroma == VLC_CODEC_YUVP)
1928 break;
1929 pp_reg = &p_reg->p_next;
1930 p_reg = p_reg->p_next;
1933 if (!eventov->img) {
1934 if (p_reg) {
1935 /* drop region */
1936 *pp_reg = p_reg->p_next;
1937 subpicture_region_Delete(p_reg);
1939 vlc_mutex_unlock(&ov->lock);
1940 return;
1943 /* If there is no region to update, create a new one. */
1944 if (!p_reg) {
1945 video_format_t fmt;
1946 video_format_Init(&fmt, 0);
1947 video_format_Setup(&fmt, VLC_CODEC_YUVP, eventov->w, eventov->h, eventov->w, eventov->h, 1, 1);
1949 p_reg = subpicture_region_New(&fmt);
1950 if (p_reg) {
1951 p_reg->i_x = eventov->x;
1952 p_reg->i_y = eventov->y;
1953 /* Append it to our list. */
1954 if (p_last != NULL)
1955 p_last->p_next = p_reg;
1956 else /* If we don't have a last region, then our list empty */
1957 ov->p_regions = p_reg;
1959 else
1961 vlc_mutex_unlock(&ov->lock);
1962 return;
1966 /* Now we can update the region, regardless it's an update or an insert */
1967 const BD_PG_RLE_ELEM *img = eventov->img;
1968 for (int y = 0; y < eventov->h; y++)
1969 for (int x = 0; x < eventov->w;) {
1970 plane_t *p = &p_reg->p_picture->p[0];
1971 memset(&p->p_pixels[y * p->i_pitch + x], img->color, img->len);
1972 x += img->len;
1973 img++;
1976 if (eventov->palette) {
1977 p_reg->fmt.p_palette->i_entries = 256;
1978 for (int i = 0; i < 256; ++i) {
1979 p_reg->fmt.p_palette->palette[i][0] = eventov->palette[i].Y;
1980 p_reg->fmt.p_palette->palette[i][1] = eventov->palette[i].Cb;
1981 p_reg->fmt.p_palette->palette[i][2] = eventov->palette[i].Cr;
1982 p_reg->fmt.p_palette->palette[i][3] = eventov->palette[i].T;
1986 vlc_mutex_unlock(&ov->lock);
1988 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
1992 static void blurayOverlayProc(void *ptr, const BD_OVERLAY *const overlay)
1994 demux_t *p_demux = (demux_t*)ptr;
1995 demux_sys_t *p_sys = p_demux->p_sys;
1997 vlc_mutex_lock(&p_sys->bdj.lock);
1999 if (!overlay) {
2000 msg_Info(p_demux, "Closing overlays.");
2001 for (int i = 0; i < MAX_OVERLAY; i++)
2002 blurayCloseOverlay(p_demux, i);
2003 vlc_mutex_unlock(&p_sys->bdj.lock);
2004 return;
2007 if(overlay->plane >= MAX_OVERLAY)
2008 return;
2010 switch (overlay->cmd) {
2011 case BD_OVERLAY_INIT:
2012 msg_Info(p_demux, "Initializing overlay");
2013 blurayInitOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
2014 break;
2015 case BD_OVERLAY_CLOSE:
2016 blurayClearOverlay(p_demux, overlay->plane);
2017 blurayCloseOverlay(p_demux, overlay->plane);
2018 break;
2019 case BD_OVERLAY_CLEAR:
2020 blurayClearOverlay(p_demux, overlay->plane);
2021 break;
2022 case BD_OVERLAY_FLUSH:
2023 blurayActivateOverlay(p_demux, overlay->plane);
2024 break;
2025 case BD_OVERLAY_DRAW:
2026 case BD_OVERLAY_WIPE:
2027 blurayDrawOverlay(p_demux, overlay);
2028 break;
2029 default:
2030 msg_Warn(p_demux, "Unknown BD overlay command: %u", overlay->cmd);
2031 break;
2034 vlc_mutex_unlock(&p_sys->bdj.lock);
2038 * ARGB overlay (BD-J)
2040 static void blurayInitArgbOverlay(demux_t *p_demux, int plane, int width, int height)
2042 blurayInitOverlay(p_demux, plane, width, height);
2045 static void blurayDrawArgbOverlay(demux_t *p_demux, const BD_ARGB_OVERLAY* const eventov)
2047 demux_sys_t *p_sys = p_demux->p_sys;
2049 bluray_overlay_t *ov = p_sys->bdj.p_overlays[eventov->plane];
2050 if(!ov)
2051 return;
2052 vlc_mutex_lock(&ov->lock);
2054 /* ARGB in word order -> byte order */
2055 #ifdef WORDS_BIG_ENDIAN
2056 const vlc_fourcc_t rgbchroma = VLC_CODEC_ARGB;
2057 #else
2058 const vlc_fourcc_t rgbchroma = VLC_CODEC_BGRA;
2059 #endif
2060 if (!ov->p_regions)
2062 video_format_t fmt;
2063 video_format_Init(&fmt, 0);
2064 video_format_Setup(&fmt,
2065 rgbchroma,
2066 eventov->stride, ov->height,
2067 ov->width, ov->height, 1, 1);
2068 ov->p_regions = subpicture_region_New(&fmt);
2071 /* Find a region to update */
2072 subpicture_region_t *p_reg = ov->p_regions;
2073 if (!p_reg || p_reg->fmt.i_chroma != rgbchroma) {
2074 vlc_mutex_unlock(&ov->lock);
2075 return;
2078 /* Now we can update the region */
2079 const uint32_t *src0 = eventov->argb;
2080 uint8_t *dst0 = p_reg->p_picture->p[0].p_pixels +
2081 p_reg->p_picture->p[0].i_pitch * eventov->y +
2082 eventov->x * 4;
2084 /* always true as for now, see bd_bdj_osd_cb */
2085 if(likely(eventov->stride == p_reg->p_picture->p[0].i_pitch / 4))
2087 memcpy(dst0, src0, (eventov->stride * eventov->h - eventov->x)*4);
2089 else
2091 for(uint16_t h = 0; h < eventov->h; h++)
2093 memcpy(dst0, src0, eventov->w * 4);
2094 src0 += eventov->stride;
2095 dst0 += p_reg->p_picture->p[0].i_pitch;
2099 vlc_mutex_unlock(&ov->lock);
2101 * /!\ The region is now stored in our internal list, but not in the subpicture /!\
2105 static void blurayArgbOverlayProc(void *ptr, const BD_ARGB_OVERLAY *const overlay)
2107 demux_t *p_demux = (demux_t*)ptr;
2108 demux_sys_t *p_sys = p_demux->p_sys;
2110 if(overlay->plane >= MAX_OVERLAY)
2111 return;
2113 switch (overlay->cmd) {
2114 case BD_ARGB_OVERLAY_INIT:
2115 vlc_mutex_lock(&p_sys->bdj.lock);
2116 blurayInitArgbOverlay(p_demux, overlay->plane, overlay->w, overlay->h);
2117 vlc_mutex_unlock(&p_sys->bdj.lock);
2118 break;
2119 case BD_ARGB_OVERLAY_CLOSE:
2120 vlc_mutex_lock(&p_sys->bdj.lock);
2121 blurayClearOverlay(p_demux, overlay->plane);
2122 blurayCloseOverlay(p_demux, overlay->plane);
2123 vlc_mutex_unlock(&p_sys->bdj.lock);
2124 break;
2125 case BD_ARGB_OVERLAY_FLUSH:
2126 blurayActivateOverlay(p_demux, overlay->plane);
2127 break;
2128 case BD_ARGB_OVERLAY_DRAW:
2129 blurayDrawArgbOverlay(p_demux, overlay);
2130 break;
2131 default:
2132 msg_Warn(p_demux, "Unknown BD ARGB overlay command: %u", overlay->cmd);
2133 break;
2137 static void bluraySendOverlayToVout(demux_t *p_demux, int plane, bluray_overlay_t *p_ov)
2139 demux_sys_t *p_sys = p_demux->p_sys;
2141 assert(p_ov != NULL);
2142 assert(!p_ov->b_on_vout);
2144 if (p_ov->p_updater) {
2145 unref_subpicture_updater(p_ov->p_updater);
2146 p_ov->p_updater = NULL;
2149 subpicture_t *p_pic = bluraySubpictureCreate(p_ov);
2150 if (!p_pic) {
2151 msg_Err(p_demux, "bluraySubpictureCreate() failed");
2152 return;
2156 * After this point, the picture should not be accessed from the demux thread,
2157 * as it is held by the vout thread.
2158 * This must be done only once per subpicture, ie. only once between each
2159 * blurayInitOverlay & blurayCloseOverlay call.
2161 int ret = es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_CREATE_OVERLAY,
2162 plane, p_pic);
2163 if (ret != VLC_SUCCESS)
2165 unref_subpicture_updater(p_ov->p_updater);
2166 p_ov->p_updater = NULL;
2167 p_ov->b_on_vout = false;
2168 subpicture_Delete(p_pic);
2169 return;
2171 p_ov->b_on_vout = true;
2174 * Mark the picture as Outdated, as it contains no region for now.
2175 * This will make the subpicture_updater_t call pf_update
2177 p_ov->status = Outdated;
2180 static bool blurayTitleIsRepeating(BLURAY_TITLE_INFO *title_info,
2181 unsigned repeats, unsigned ratio)
2183 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(1, 0, 0)
2184 const BLURAY_CLIP_INFO *prev = NULL;
2185 unsigned maxrepeats = 0;
2186 unsigned sequence = 0;
2187 if(!title_info->chapter_count)
2188 return false;
2190 for (unsigned int j = 0; j < title_info->chapter_count; j++)
2192 unsigned i = title_info->chapters[j].clip_ref;
2193 if(i < title_info->clip_count)
2195 if(prev == NULL ||
2196 /* non repeated does not need start time offset */
2197 title_info->clips[i].start_time == 0 ||
2198 /* repeats occurs on same segment */
2199 memcmp(title_info->clips[i].clip_id, prev->clip_id, 6) ||
2200 prev->in_time != title_info->clips[i].in_time ||
2201 prev->pkt_count != title_info->clips[i].pkt_count)
2203 sequence = 0;
2204 prev = &title_info->clips[i];
2205 continue;
2207 else
2209 if(maxrepeats < sequence++)
2210 maxrepeats = sequence;
2214 return (maxrepeats > repeats &&
2215 (100 * maxrepeats / title_info->chapter_count) >= ratio);
2216 #else
2217 return false;
2218 #endif
2221 static void blurayUpdateTitleInfo(input_title_t *t, BLURAY_TITLE_INFO *title_info)
2223 t->i_length = FROM_SCALE_NZ(title_info->duration);
2225 for (int i = 0; i < t->i_seekpoint; i++)
2226 vlc_seekpoint_Delete( t->seekpoint[i] );
2227 TAB_CLEAN(t->i_seekpoint, t->seekpoint);
2229 /* FIXME: have libbluray expose repeating titles */
2230 if(blurayTitleIsRepeating(title_info, 50, 90))
2231 return;
2233 for (unsigned int j = 0; j < title_info->chapter_count; j++) {
2234 seekpoint_t *s = vlc_seekpoint_New();
2235 if (!s) {
2236 break;
2238 s->i_time_offset = FROM_SCALE_NZ(title_info->chapters[j].start);
2240 TAB_APPEND(t->i_seekpoint, t->seekpoint, s);
2244 static void blurayInitTitles(demux_t *p_demux, uint32_t menu_titles)
2246 demux_sys_t *p_sys = p_demux->p_sys;
2247 const BLURAY_DISC_INFO *di = bd_get_disc_info(p_sys->bluray);
2249 /* get and set the titles */
2250 uint32_t i_title = menu_titles;
2252 if (!p_sys->b_menu) {
2253 i_title = bd_get_titles(p_sys->bluray, TITLES_RELEVANT, 60);
2254 p_sys->i_longest_title = bd_get_main_title(p_sys->bluray);
2257 for (uint32_t i = 0; i < i_title; i++) {
2258 input_title_t *t = vlc_input_title_New();
2259 if (!t)
2260 break;
2262 if (!p_sys->b_menu) {
2263 BLURAY_TITLE_INFO *title_info = bd_get_title_info(p_sys->bluray, i, 0);
2264 blurayUpdateTitleInfo(t, title_info);
2265 bd_free_title_info(title_info);
2267 } else if (i == 0) {
2268 t->psz_name = strdup(_("Top Menu"));
2269 t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
2270 } else if (i == i_title - 1) {
2271 t->psz_name = strdup(_("First Play"));
2272 if (di && di->first_play && di->first_play->interactive) {
2273 t->i_flags = INPUT_TITLE_INTERACTIVE;
2275 } else {
2276 /* add possible title name from disc metadata */
2277 if (di && di->titles && i <= di->num_titles) {
2278 if (di->titles[i]->name) {
2279 t->psz_name = strdup(di->titles[i]->name);
2281 if (di->titles[i]->interactive) {
2282 t->i_flags = INPUT_TITLE_INTERACTIVE;
2287 TAB_APPEND(p_sys->i_title, p_sys->pp_title, t);
2291 static void blurayRestartParser(demux_t *p_demux, bool b_flush, bool b_random_access)
2294 * This is a hack and will have to be removed.
2295 * The parser should be flushed, and not destroy/created each time
2296 * we are changing title.
2298 demux_sys_t *p_sys = p_demux->p_sys;
2300 if(b_flush)
2301 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DISABLE_OUTPUT);
2303 if (p_sys->p_parser)
2304 vlc_demux_chained_Delete(p_sys->p_parser);
2306 if(b_flush)
2307 es_out_Control(p_sys->p_tf_out, ES_OUT_TF_FILTER_RESET);
2309 p_sys->p_parser = vlc_demux_chained_New(VLC_OBJECT(p_demux), "ts", p_sys->p_out);
2310 if (!p_sys->p_parser)
2311 msg_Err(p_demux, "Failed to create TS demuxer");
2313 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_ENABLE_OUTPUT);
2315 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_RANDOM_ACCESS, b_random_access);
2318 /*****************************************************************************
2319 * bluraySetTitle: select new BD title
2320 *****************************************************************************/
2321 static int bluraySetTitle(demux_t *p_demux, int i_title)
2323 demux_sys_t *p_sys = p_demux->p_sys;
2325 if (p_sys->b_menu) {
2326 int result;
2327 if (i_title <= 0) {
2328 msg_Dbg(p_demux, "Playing TopMenu Title");
2329 result = bd_menu_call(p_sys->bluray, -1);
2330 } else if (i_title >= (int)p_sys->i_title - 1) {
2331 msg_Dbg(p_demux, "Playing FirstPlay Title");
2332 result = bd_play_title(p_sys->bluray, BLURAY_TITLE_FIRST_PLAY);
2333 } else {
2334 msg_Dbg(p_demux, "Playing Title %i", i_title);
2335 result = bd_play_title(p_sys->bluray, i_title);
2338 if (result == 0) {
2339 msg_Err(p_demux, "cannot play bd title '%d'", i_title);
2340 return VLC_EGENERIC;
2343 return VLC_SUCCESS;
2346 /* Looking for the main title, ie the longest duration */
2347 if (i_title < 0)
2348 i_title = p_sys->i_longest_title;
2349 else if ((unsigned)i_title > p_sys->i_title)
2350 return VLC_EGENERIC;
2352 msg_Dbg(p_demux, "Selecting Title %i", i_title);
2354 if (bd_select_title(p_sys->bluray, i_title) == 0) {
2355 msg_Err(p_demux, "cannot select bd title '%d'", i_title);
2356 return VLC_EGENERIC;
2359 return VLC_SUCCESS;
2362 #if BLURAY_VERSION < BLURAY_VERSION_CODE(0,9,2)
2363 # define BLURAY_AUDIO_STREAM 0
2364 #endif
2366 static void blurayOnUserStreamSelection(demux_t *p_demux, int i_pid)
2368 demux_sys_t *p_sys = p_demux->p_sys;
2369 vlc_mutex_lock(&p_sys->pl_info_lock);
2371 if(i_pid == -AUDIO_ES)
2372 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, 0, 0);
2373 else if(i_pid == -SPU_ES)
2374 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, 0, 0);
2375 else if (p_sys->p_clip_info)
2377 if ((i_pid & 0xff00) == 0x1100) {
2378 bool b_in_playlist = false;
2379 // audio
2380 for (int i_id = 0; i_id < p_sys->p_clip_info->audio_stream_count; i_id++) {
2381 if (i_pid == p_sys->p_clip_info->audio_streams[i_id].pid) {
2382 bd_select_stream(p_sys->bluray, BLURAY_AUDIO_STREAM, i_id + 1, 1);
2384 if(!p_sys->b_menu)
2385 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_AUDIO_LANG,
2386 (const char *) p_sys->p_clip_info->audio_streams[i_id].lang);
2387 b_in_playlist = true;
2388 break;
2391 if(!b_in_playlist && !p_sys->b_menu)
2393 /* Without menu, the selected playlist might not be correct and only
2394 exposing a subset of PID, although same length */
2395 msg_Warn(p_demux, "Incorrect playlist for menuless track, forcing");
2396 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID,
2397 BD_EVENT_AUDIO_STREAM, i_pid);
2399 } else if ((i_pid & 0xff00) == 0x1200 || i_pid == 0x1800) {
2400 bool b_in_playlist = false;
2401 // subtitle
2402 for (int i_id = 0; i_id < p_sys->p_clip_info->pg_stream_count; i_id++) {
2403 if (i_pid == p_sys->p_clip_info->pg_streams[i_id].pid) {
2404 bd_select_stream(p_sys->bluray, BLURAY_PG_TEXTST_STREAM, i_id + 1, 1);
2405 if(!p_sys->b_menu)
2406 bd_set_player_setting_str(p_sys->bluray, BLURAY_PLAYER_SETTING_PG_LANG,
2407 (const char *) p_sys->p_clip_info->pg_streams[i_id].lang);
2408 b_in_playlist = true;
2409 break;
2412 if(!b_in_playlist && !p_sys->b_menu)
2414 msg_Warn(p_demux, "Incorrect playlist for menuless track, forcing");
2415 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID,
2416 BD_EVENT_PG_TEXTST_STREAM, i_pid);
2421 vlc_mutex_unlock(&p_sys->pl_info_lock);
2424 /*****************************************************************************
2425 * blurayControl: handle the controls
2426 *****************************************************************************/
2427 static int blurayControl(demux_t *p_demux, int query, va_list args)
2429 demux_sys_t *p_sys = p_demux->p_sys;
2430 bool *pb_bool;
2432 switch (query) {
2433 case DEMUX_CAN_SEEK:
2434 case DEMUX_CAN_PAUSE:
2435 case DEMUX_CAN_CONTROL_PACE:
2436 pb_bool = va_arg(args, bool *);
2437 *pb_bool = true;
2438 break;
2440 case DEMUX_GET_PTS_DELAY:
2441 *va_arg(args, vlc_tick_t *) =
2442 VLC_TICK_FROM_MS(var_InheritInteger(p_demux, "disc-caching"));
2443 break;
2445 case DEMUX_SET_PAUSE_STATE:
2447 #ifdef BLURAY_RATE_NORMAL
2448 bool b_paused = (bool)va_arg(args, int);
2449 if (bd_set_rate(p_sys->bluray, BLURAY_RATE_NORMAL * (!b_paused)) < 0) {
2450 return VLC_EGENERIC;
2452 #endif
2453 break;
2455 case DEMUX_SET_ES:
2457 int i_id = va_arg(args, int);
2458 blurayOnUserStreamSelection(p_demux, i_id);
2459 break;
2461 case DEMUX_SET_ES_LIST:
2462 return VLC_EGENERIC; /* TODO */
2463 case DEMUX_SET_TITLE:
2465 int i_title = va_arg(args, int);
2466 if (bluraySetTitle(p_demux, i_title) != VLC_SUCCESS) {
2467 /* make sure GUI restores the old setting in title menu ... */
2468 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2469 return VLC_EGENERIC;
2471 blurayRestartParser(p_demux, true, false);
2472 notifyDiscontinuityToParser(p_sys);
2473 p_sys->b_draining = false;
2474 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
2475 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2476 break;
2478 case DEMUX_SET_SEEKPOINT:
2480 int i_chapter = va_arg(args, int);
2481 bd_seek_chapter(p_sys->bluray, i_chapter);
2482 blurayRestartParser(p_demux, true, false);
2483 notifyDiscontinuityToParser(p_sys);
2484 p_sys->b_draining = false;
2485 es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
2486 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2487 break;
2489 case DEMUX_TEST_AND_CLEAR_FLAGS:
2491 unsigned *restrict flags = va_arg(args, unsigned *);
2492 *flags &= p_sys->updates;
2493 p_sys->updates &= ~*flags;
2494 break;
2496 case DEMUX_GET_TITLE:
2497 *va_arg(args, int *) = p_sys->cur_title;
2498 break;
2500 case DEMUX_GET_SEEKPOINT:
2501 *va_arg(args, int *) = p_sys->cur_seekpoint;
2502 break;
2504 case DEMUX_GET_TITLE_INFO:
2506 input_title_t ***ppp_title = va_arg(args, input_title_t***);
2507 int *pi_int = va_arg(args, int *);
2508 int *pi_title_offset = va_arg(args, int *);
2509 int *pi_chapter_offset = va_arg(args, int *);
2511 /* */
2512 *pi_title_offset = 0;
2513 *pi_chapter_offset = 0;
2515 /* Duplicate local title infos */
2516 *pi_int = 0;
2517 *ppp_title = vlc_alloc(p_sys->i_title, sizeof(input_title_t *));
2518 if(!*ppp_title)
2519 return VLC_EGENERIC;
2520 for (unsigned int i = 0; i < p_sys->i_title; i++)
2522 input_title_t *p_dup = vlc_input_title_Duplicate(p_sys->pp_title[i]);
2523 if(p_dup)
2524 (*ppp_title)[(*pi_int)++] = p_dup;
2527 return VLC_SUCCESS;
2530 case DEMUX_GET_LENGTH:
2532 if(p_sys->cur_title < p_sys->i_title &&
2533 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2534 return VLC_EGENERIC;
2535 *va_arg(args, vlc_tick_t *) = p_sys->cur_title < p_sys->i_title ? CUR_LENGTH : 0;
2536 return VLC_SUCCESS;
2538 case DEMUX_SET_TIME:
2540 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(va_arg(args, vlc_tick_t)));
2541 blurayRestartParser(p_demux, true, true);
2542 notifyDiscontinuityToParser(p_sys);
2543 p_sys->b_draining = false;
2544 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2545 return VLC_SUCCESS;
2547 case DEMUX_GET_TIME:
2549 vlc_tick_t *pi_time = va_arg(args, vlc_tick_t *);
2550 if(p_sys->cur_title < p_sys->i_title &&
2551 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2552 return VLC_EGENERIC;
2553 *pi_time = FROM_SCALE_NZ(bd_tell_time(p_sys->bluray));
2554 return VLC_SUCCESS;
2557 case DEMUX_GET_POSITION:
2559 double *pf_position = va_arg(args, double *);
2560 if(p_sys->cur_title < p_sys->i_title &&
2561 (CURRENT_TITLE->i_flags & INPUT_TITLE_INTERACTIVE))
2562 return VLC_EGENERIC;
2563 *pf_position = p_sys->cur_title < p_sys->i_title && CUR_LENGTH > 0 ?
2564 (double)FROM_SCALE_NZ(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
2565 return VLC_SUCCESS;
2567 case DEMUX_SET_POSITION:
2569 double f_position = va_arg(args, double);
2570 bd_seek_time(p_sys->bluray, TO_SCALE_NZ(f_position*CUR_LENGTH));
2571 blurayRestartParser(p_demux, true, true);
2572 notifyDiscontinuityToParser(p_sys);
2573 p_sys->b_draining = false;
2574 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
2575 return VLC_SUCCESS;
2578 case DEMUX_GET_META:
2580 vlc_meta_t *p_meta = va_arg(args, vlc_meta_t *);
2581 const META_DL *meta = p_sys->p_meta;
2582 if (meta == NULL)
2583 return VLC_EGENERIC;
2585 if (!EMPTY_STR(meta->di_name)) vlc_meta_SetTitle(p_meta, meta->di_name);
2587 if (!EMPTY_STR(meta->language_code)) vlc_meta_AddExtra(p_meta, "Language", meta->language_code);
2588 if (!EMPTY_STR(meta->filename)) vlc_meta_AddExtra(p_meta, "Filename", meta->filename);
2589 if (!EMPTY_STR(meta->di_alternative)) vlc_meta_AddExtra(p_meta, "Alternative", meta->di_alternative);
2591 // if (meta->di_set_number > 0) vlc_meta_SetTrackNum(p_meta, meta->di_set_number);
2592 // if (meta->di_num_sets > 0) vlc_meta_AddExtra(p_meta, "Discs numbers in Set", meta->di_num_sets);
2594 if (p_sys->i_cover_idx >= 0 && p_sys->i_cover_idx < p_sys->i_attachments) {
2595 char psz_url[128];
2596 snprintf( psz_url, sizeof(psz_url), "attachment://%s",
2597 p_sys->attachments[p_sys->i_cover_idx]->psz_name );
2598 vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
2600 else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
2601 char *psz_thumbpath;
2602 if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
2603 p_sys->psz_bd_path, meta->thumbnails[0].path) > -1) {
2604 char *psz_thumburl = vlc_path2uri(psz_thumbpath, "file");
2605 free(psz_thumbpath);
2606 if (unlikely(psz_thumburl == NULL))
2607 return VLC_ENOMEM;
2609 vlc_meta_SetArtURL(p_meta, psz_thumburl);
2610 free(psz_thumburl);
2614 return VLC_SUCCESS;
2617 case DEMUX_GET_ATTACHMENTS:
2619 input_attachment_t ***ppp_attach =
2620 va_arg(args, input_attachment_t ***);
2621 int *pi_int = va_arg(args, int *);
2623 if (p_sys->i_attachments <= 0)
2624 return VLC_EGENERIC;
2626 *pi_int = 0;
2627 *ppp_attach = vlc_alloc(p_sys->i_attachments, sizeof(input_attachment_t *));
2628 if(!*ppp_attach)
2629 return VLC_EGENERIC;
2630 for (int i = 0; i < p_sys->i_attachments; i++)
2632 (*ppp_attach)[(*pi_int)++] = vlc_input_attachment_Hold(p_sys->attachments[i]);
2634 return VLC_SUCCESS;
2637 case DEMUX_NAV_ACTIVATE:
2638 if (p_sys->b_popup_available && !p_sys->b_menu_open) {
2639 return sendKeyEvent(p_sys, BD_VK_POPUP);
2641 return sendKeyEvent(p_sys, BD_VK_ENTER);
2642 case DEMUX_NAV_UP:
2643 return sendKeyEvent(p_sys, BD_VK_UP);
2644 case DEMUX_NAV_DOWN:
2645 return sendKeyEvent(p_sys, BD_VK_DOWN);
2646 case DEMUX_NAV_LEFT:
2647 return sendKeyEvent(p_sys, BD_VK_LEFT);
2648 case DEMUX_NAV_RIGHT:
2649 return sendKeyEvent(p_sys, BD_VK_RIGHT);
2650 case DEMUX_NAV_POPUP:
2651 return sendKeyEvent(p_sys, BD_VK_POPUP);
2652 case DEMUX_NAV_MENU:
2653 if (p_sys->b_menu) {
2654 if (bd_menu_call(p_sys->bluray, -1) == 1) {
2655 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2656 return VLC_SUCCESS;
2658 msg_Err(p_demux, "Can't select Top Menu title");
2659 return sendKeyEvent(p_sys, BD_VK_POPUP);
2661 return VLC_EGENERIC;
2663 case DEMUX_GET_TYPE:
2665 *va_arg( args, int* ) = ITEM_TYPE_DISC;
2666 break;
2669 case DEMUX_CAN_RECORD:
2670 case DEMUX_GET_FPS:
2671 case DEMUX_SET_GROUP_DEFAULT:
2672 case DEMUX_SET_GROUP_ALL:
2673 case DEMUX_SET_GROUP_LIST:
2674 case DEMUX_HAS_UNSUPPORTED_META:
2675 default:
2676 return VLC_EGENERIC;
2678 return VLC_SUCCESS;
2681 /*****************************************************************************
2682 * libbluray event handling
2683 *****************************************************************************/
2684 static void writeTsPacketWDiscontinuity( uint8_t *p_buf, uint16_t i_pid,
2685 const uint8_t *p_payload, uint8_t i_payload )
2687 uint8_t ts_header[] = {
2688 0x00, 0x00, 0x00, 0x00, /* TP extra header (ATC) */
2689 0x47,
2690 0x40 | ((i_pid & 0x1f00) >> 8), i_pid & 0xFF, /* PUSI + PID */
2691 i_payload ? 0x30 : 0x20, /* adaptation field, payload / no payload */
2692 192 - (4 + 5) - i_payload, /* adaptation field length */
2693 0x82, /* af: discontinuity indicator + priv data */
2694 0x0E, /* priv data size */
2695 'V', 'L', 'C', '_',
2696 'D', 'I', 'S', 'C', 'O', 'N', 'T', 'I', 'N', 'U',
2699 memcpy( p_buf, ts_header, sizeof(ts_header) );
2700 memset( &p_buf[sizeof(ts_header)], 0xFF, 192 - sizeof(ts_header) - i_payload );
2701 if( i_payload )
2702 memcpy( &p_buf[192 - i_payload], p_payload, i_payload );
2705 static void notifyStreamsDiscontinuity( vlc_demux_chained_t *p_parser,
2706 const BLURAY_STREAM_INFO *p_sinfo, size_t i_sinfo )
2708 for( size_t i=0; i< i_sinfo; i++ )
2710 const uint16_t i_pid = p_sinfo[i].pid;
2712 block_t *p_block = block_Alloc(192);
2713 if (!p_block)
2714 return;
2716 writeTsPacketWDiscontinuity( p_block->p_buffer, i_pid, NULL, 0 );
2718 vlc_demux_chained_Send(p_parser, p_block);
2722 #define DONOTIFY(memb) notifyStreamsDiscontinuity( p_sys->p_parser, p_clip->memb##_streams, \
2723 p_clip->memb##_stream_count )
2725 static void notifyDiscontinuityToParser( demux_sys_t *p_sys )
2727 const BLURAY_CLIP_INFO *p_clip = p_sys->p_clip_info;
2728 if( p_clip )
2730 DONOTIFY(audio);
2731 DONOTIFY(video);
2732 DONOTIFY(pg);
2733 DONOTIFY(ig);
2734 DONOTIFY(sec_audio);
2735 DONOTIFY(sec_video);
2739 #undef DONOTIFY
2741 static void streamFlush( demux_sys_t *p_sys )
2744 * MPEG-TS demuxer does not flush last video frame if size of PES packet is unknown.
2745 * Packet is flushed only when TS packet with PUSI flag set is received.
2747 * Fix this by emitting (video) ts packet with PUSI flag set.
2748 * Add video sequence end code to payload so that also video decoder is flushed.
2749 * Set PES packet size in the payload so that it will be sent to decoder immediately.
2752 if (p_sys->b_flushed)
2753 return;
2755 block_t *p_block = block_Alloc(192);
2756 if (!p_block)
2757 return;
2759 bd_stream_type_e i_coding_type;
2761 /* set correct sequence end code */
2762 vlc_mutex_lock(&p_sys->pl_info_lock);
2763 if (p_sys->p_clip_info != NULL)
2764 i_coding_type = p_sys->p_clip_info->video_streams[0].coding_type;
2765 else
2766 i_coding_type = 0;
2767 vlc_mutex_unlock(&p_sys->pl_info_lock);
2769 uint8_t i_eos;
2770 switch( i_coding_type )
2772 case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
2773 case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
2774 default:
2775 i_eos = 0xB7; /* MPEG2 sequence end */
2776 break;
2777 case BLURAY_STREAM_TYPE_VIDEO_VC1:
2778 case BLURAY_STREAM_TYPE_VIDEO_H264:
2779 i_eos = 0x0A; /* VC1 / H.264 sequence end */
2780 break;
2781 case BD_STREAM_TYPE_VIDEO_HEVC:
2782 i_eos = 0x48; /* HEVC sequence end NALU */
2783 break;
2786 uint8_t seq_end_pes[] = {
2787 0x00, 0x00, 0x01, 0xe0, 0x00, 0x08, 0x80, 0x00, 0x00, /* PES header */
2788 0x00, 0x00, 0x01, i_eos, /* PES payload: sequence end */
2789 0x00, /* 2nd byte for HEVC NAL, pads others */
2792 writeTsPacketWDiscontinuity( p_block->p_buffer, 0x1011, seq_end_pes, sizeof(seq_end_pes) );
2794 vlc_demux_chained_Send(p_sys->p_parser, p_block);
2795 p_sys->b_flushed = true;
2798 static void blurayResetStillImage( demux_t *p_demux )
2800 demux_sys_t *p_sys = p_demux->p_sys;
2802 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET) {
2803 p_sys->i_still_end_time = STILL_IMAGE_NOT_SET;
2805 blurayRestartParser(p_demux, false, false);
2806 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2810 static void blurayStillImage( demux_t *p_demux, unsigned i_timeout )
2812 demux_sys_t *p_sys = p_demux->p_sys;
2814 /* time period elapsed ? */
2815 if (p_sys->i_still_end_time != STILL_IMAGE_NOT_SET &&
2816 p_sys->i_still_end_time != STILL_IMAGE_INFINITE &&
2817 p_sys->i_still_end_time <= vlc_tick_now()) {
2818 msg_Dbg(p_demux, "Still image end");
2819 bd_read_skip_still(p_sys->bluray);
2821 blurayResetStillImage(p_demux);
2822 return;
2825 /* show last frame as still image */
2826 if (p_sys->i_still_end_time == STILL_IMAGE_NOT_SET) {
2827 if (i_timeout) {
2828 msg_Dbg(p_demux, "Still image (%d seconds)", i_timeout);
2829 p_sys->i_still_end_time = vlc_tick_now() + vlc_tick_from_sec( i_timeout );
2830 } else {
2831 msg_Dbg(p_demux, "Still image (infinite)");
2832 p_sys->i_still_end_time = STILL_IMAGE_INFINITE;
2835 /* flush demuxer and decoder (there won't be next video packet starting with ts PUSI) */
2836 streamFlush(p_sys);
2838 /* stop buffering */
2839 bool b_empty;
2840 es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
2843 /* avoid busy loops (read returns no data) */
2844 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
2847 static void blurayOnStreamSelectedEvent(demux_t *p_demux, uint32_t i_type, uint32_t i_id)
2849 demux_sys_t *p_sys = p_demux->p_sys;
2850 int i_pid = -1;
2852 /* The param we get is the real stream id, not an index, ie. it starts from 1 */
2853 i_id--;
2855 if (i_type == BD_EVENT_AUDIO_STREAM) {
2856 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2857 } else if (i_type == BD_EVENT_PG_TEXTST_STREAM) {
2858 i_pid = blurayGetStreamPID(p_sys, i_type, i_id);
2861 if (i_pid > 0)
2863 if (i_type == BD_EVENT_PG_TEXTST_STREAM && !p_sys->b_spu_enable)
2864 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_UNSET_ES_BY_PID, (int)i_type, i_pid);
2865 else
2866 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_SET_ES_BY_PID, (int)i_type, i_pid);
2870 static void blurayUpdatePlaylist(demux_t *p_demux, unsigned i_playlist)
2872 demux_sys_t *p_sys = p_demux->p_sys;
2874 blurayRestartParser(p_demux, true, false);
2876 /* read title info and init some values */
2877 if (!p_sys->b_menu)
2878 p_sys->cur_title = bd_get_current_title(p_sys->bluray);
2879 p_sys->cur_seekpoint = 0;
2880 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2882 BLURAY_TITLE_INFO *p_title_info = bd_get_playlist_info(p_sys->bluray, i_playlist, 0);
2883 if (p_title_info) {
2884 blurayUpdateTitleInfo(p_sys->pp_title[p_sys->cur_title], p_title_info);
2885 if (p_sys->b_menu)
2886 p_sys->updates |= INPUT_UPDATE_TITLE_LIST;
2888 setTitleInfo(p_sys, p_title_info);
2890 blurayResetStillImage(p_demux);
2893 static void blurayOnClipUpdate(demux_t *p_demux, uint32_t clip)
2895 demux_sys_t *p_sys = p_demux->p_sys;
2897 vlc_mutex_lock(&p_sys->pl_info_lock);
2899 p_sys->p_clip_info = NULL;
2901 if (p_sys->p_pl_info && clip < p_sys->p_pl_info->clip_count) {
2903 p_sys->p_clip_info = &p_sys->p_pl_info->clips[clip];
2905 /* Let's assume a single video track for now.
2906 * This may brake later, but it's enough for now.
2908 assert(p_sys->p_clip_info->video_stream_count >= 1);
2911 CLPI_CL *clpi = bd_get_clpi(p_sys->bluray, clip);
2912 if(clpi && clpi->clip.application_type != p_sys->clip_application_type)
2914 if(p_sys->clip_application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW ||
2915 clpi->clip.application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW)
2916 blurayRestartParser(p_demux, false, false);
2918 if(clpi->clip.application_type == BD_CLIP_APP_TYPE_TS_MAIN_PATH_TIMED_SLIDESHOW)
2919 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_ENABLE_LOW_DELAY);
2920 else
2921 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_DISABLE_LOW_DELAY);
2922 bd_free_clpi(clpi);
2925 vlc_mutex_unlock(&p_sys->pl_info_lock);
2927 blurayResetStillImage(p_demux);
2930 static void blurayHandleEvent(demux_t *p_demux, const BD_EVENT *e, bool b_delayed)
2932 demux_sys_t *p_sys = p_demux->p_sys;
2934 blurayDebugEvent(e->event, e->param);
2936 switch (e->event) {
2937 case BD_EVENT_TITLE:
2938 if (e->param == BLURAY_TITLE_FIRST_PLAY)
2939 p_sys->cur_title = p_sys->i_title - 1;
2940 else
2941 p_sys->cur_title = e->param;
2942 /* this is feature title, we don't know yet which playlist it will play (if any) */
2943 setTitleInfo(p_sys, NULL);
2944 /* reset title infos here ? */
2945 p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2946 /* might be BD-J title with no video */
2947 break;
2948 case BD_EVENT_PLAYLIST:
2949 /* Start of playlist playback (?????.mpls) */
2950 blurayUpdatePlaylist(p_demux, e->param);
2951 if (p_sys->b_pl_playing) {
2952 /* previous playlist was stopped in middle. flush to avoid delay */
2953 msg_Info(p_demux, "Stopping playlist playback");
2954 blurayRestartParser(p_demux, false, false);
2955 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
2957 p_sys->b_pl_playing = true;
2958 break;
2959 case BD_EVENT_PLAYITEM:
2960 notifyDiscontinuityToParser(p_sys);
2961 blurayOnClipUpdate(p_demux, e->param);
2962 break;
2963 case BD_EVENT_CHAPTER:
2964 if (e->param && e->param < 0xffff)
2965 p_sys->cur_seekpoint = e->param - 1;
2966 else
2967 p_sys->cur_seekpoint = 0;
2968 p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
2969 break;
2970 case BD_EVENT_PLAYMARK:
2971 case BD_EVENT_ANGLE:
2972 break;
2973 case BD_EVENT_SEEK:
2974 /* Seek will happen with any chapter/title or bd_seek(),
2975 but also BD-J initiated. We can't make the difference
2976 between input or vm ones, better double flush/pcr reset
2977 than break the clock by throwing post random access PCR */
2978 blurayRestartParser(p_demux, true, true);
2979 notifyDiscontinuityToParser(p_sys);
2980 es_out_Control(p_sys->p_out, ES_OUT_RESET_PCR);
2981 break;
2982 #if BLURAY_VERSION >= BLURAY_VERSION_CODE(0,8,1)
2983 case BD_EVENT_UO_MASK_CHANGED:
2984 /* This event could be used to grey out unselectable items in title menu */
2985 break;
2986 #endif
2987 case BD_EVENT_MENU:
2988 p_sys->b_menu_open = e->param;
2989 break;
2990 case BD_EVENT_POPUP:
2991 p_sys->b_popup_available = e->param;
2992 /* TODO: show / hide pop-up menu button in gui ? */
2993 break;
2996 * Errors
2998 case BD_EVENT_ERROR:
2999 /* fatal error (with menus) */
3000 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
3001 "Playback with BluRay menus failed");
3002 p_sys->b_fatal_error = true;
3003 break;
3004 case BD_EVENT_ENCRYPTED:
3005 vlc_dialog_display_error(p_demux, _("Blu-ray error"),
3006 "This disc seems to be encrypted");
3007 p_sys->b_fatal_error = true;
3008 break;
3009 case BD_EVENT_READ_ERROR:
3010 msg_Err(p_demux, "bluray: read error\n");
3011 break;
3014 * stream selection events
3016 case BD_EVENT_PG_TEXTST:
3017 p_sys->b_spu_enable = e->param;
3018 break;
3019 case BD_EVENT_AUDIO_STREAM:
3020 case BD_EVENT_PG_TEXTST_STREAM:
3021 if(b_delayed)
3022 blurayOnStreamSelectedEvent(p_demux, e->event, e->param);
3023 else
3024 ARRAY_APPEND(p_sys->events_delayed, *e);
3025 break;
3026 case BD_EVENT_IG_STREAM:
3027 case BD_EVENT_SECONDARY_AUDIO:
3028 case BD_EVENT_SECONDARY_AUDIO_STREAM:
3029 case BD_EVENT_SECONDARY_VIDEO:
3030 case BD_EVENT_SECONDARY_VIDEO_STREAM:
3031 case BD_EVENT_SECONDARY_VIDEO_SIZE:
3032 break;
3035 * playback control events
3037 case BD_EVENT_STILL_TIME:
3038 blurayStillImage(p_demux, e->param);
3039 break;
3040 case BD_EVENT_DISCONTINUITY:
3041 /* reset demuxer (partially decoded PES packets must be dropped) */
3042 blurayRestartParser(p_demux, false, true);
3043 es_out_Control(p_sys->p_out, BLURAY_ES_OUT_CONTROL_FLAG_DISCONTINUITY);
3044 break;
3045 case BD_EVENT_END_OF_TITLE:
3046 if(p_sys->b_pl_playing)
3048 notifyDiscontinuityToParser(p_sys);
3049 blurayRestartParser(p_demux, false, false);
3050 p_sys->b_draining = true;
3051 p_sys->b_pl_playing = false;
3053 break;
3054 case BD_EVENT_IDLE:
3055 /* nothing to do (ex. BD-J is preparing menus, waiting user input or running animation) */
3056 /* avoid busy loop (bd_read() returns no data) */
3057 vlc_tick_sleep( VLC_TICK_FROM_MS(40) );
3058 break;
3060 default:
3061 msg_Warn(p_demux, "event: %d param: %d", e->event, e->param);
3062 break;
3066 static void blurayHandleOverlays(demux_t *p_demux)
3068 demux_sys_t *p_sys = p_demux->p_sys;
3069 vlc_mutex_lock(&p_sys->bdj.lock);
3071 for (int i = 0; i < MAX_OVERLAY; i++) {
3072 bluray_overlay_t *ov = p_sys->bdj.p_overlays[i];
3073 if (!ov) {
3074 continue;
3076 vlc_mutex_lock(&ov->lock);
3077 bool display = ov->status == ToDisplay;
3078 vlc_mutex_unlock(&ov->lock);
3079 if (display && !ov->b_on_vout)
3081 /* NOTE: we might want to enable background video always when there's no video stream playing.
3082 Now, with some discs, there are perioids (even seconds) during which the video window
3083 disappears and just playlist is shown.
3084 (sometimes BD-J runs slowly ...)
3086 bluraySendOverlayToVout(p_demux, i, ov);
3090 vlc_mutex_unlock(&p_sys->bdj.lock);
3093 static int blurayDemux(demux_t *p_demux)
3095 demux_sys_t *p_sys = p_demux->p_sys;
3096 BD_EVENT e;
3098 if(p_sys->b_draining)
3100 bool b_empty = false;
3101 if(es_out_Control(p_sys->p_out, ES_OUT_GET_EMPTY, &b_empty) != VLC_SUCCESS || b_empty)
3103 es_out_Control(p_sys->p_out, ES_OUT_RESET_PCR);
3104 p_sys->b_draining = false;
3106 else
3108 msg_Dbg(p_demux, "Draining...");
3109 vlc_tick_sleep(VLC_TICK_FROM_MS(40));
3110 return VLC_DEMUXER_SUCCESS;
3114 block_t *p_block = block_Alloc(BD_READ_SIZE);
3115 if (!p_block)
3116 return VLC_DEMUXER_EGENERIC;
3118 int nread;
3120 if (p_sys->b_menu == false) {
3121 nread = bd_read(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE);
3122 while (bd_get_event(p_sys->bluray, &e))
3123 blurayHandleEvent(p_demux, &e, false);
3124 } else {
3125 nread = bd_read_ext(p_sys->bluray, p_block->p_buffer, BD_READ_SIZE, &e);
3126 while (e.event != BD_EVENT_NONE) {
3127 blurayHandleEvent(p_demux, &e, false);
3128 bd_get_event(p_sys->bluray, &e);
3132 /* Process delayed selections events */
3133 for(int i=0; i<p_sys->events_delayed.i_size; i++)
3134 blurayHandleEvent(p_demux, &p_sys->events_delayed.p_elems[i], true);
3135 p_sys->events_delayed.i_size = 0;
3137 blurayHandleOverlays(p_demux);
3139 if (nread <= 0) {
3140 block_Release(p_block);
3141 if (p_sys->b_fatal_error || nread < 0) {
3142 msg_Err(p_demux, "bluray: stopping playback after fatal error\n");
3143 return VLC_DEMUXER_EGENERIC;
3145 if (!p_sys->b_menu) {
3146 return VLC_DEMUXER_EOF;
3148 return VLC_DEMUXER_SUCCESS;
3151 p_block->i_buffer = nread;
3153 vlc_demux_chained_Send(p_sys->p_parser, p_block);
3155 p_sys->b_flushed = false;
3157 return VLC_DEMUXER_SUCCESS;