/* Titles */
unsigned int i_title;
unsigned int i_longest_title;
+ unsigned int i_current_clip;
input_title_t **pp_title;
- unsigned int i_first_play;
- unsigned int i_top_menu;
/* Meta informations */
const META_DL *p_meta;
vout_thread_t *p_vout;
/* TS stream */
+ es_out_t *p_out;
+ vlc_array_t es;
+ int i_audio_stream; /* Selected audio stream. -1 if default */
+ int i_video_stream;
stream_t *p_parser;
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
+static es_out_t *esOutNew( demux_t *p_demux );
+
static int blurayControl(demux_t *, int, va_list);
static int blurayDemux(demux_t *);
return VLC_ENOMEM;
}
p_sys->current_overlay = -1;
+ p_sys->i_audio_stream = -1;
+ p_sys->i_video_stream = -1;
/* init demux info fields */
p_demux->info.i_update = 0;
}
}
+ vlc_array_init(&p_sys->es);
+ p_sys->p_out = esOutNew( p_demux );
+ if (unlikely(p_sys->p_out == NULL)) {
+ goto error;
+ }
+
blurayResetParser( p_demux );
if (!p_sys->p_parser) {
msg_Err(p_demux, "Failed to create TS demuxer");
vlc_object_release(p_sys->p_input);
if (p_sys->p_parser)
stream_Delete(p_sys->p_parser);
+ if (p_sys->p_out != NULL)
+ es_out_Delete(p_sys->p_out);
+ assert( vlc_array_count(&p_sys->es) == 0 );
+ vlc_array_clear( &p_sys->es );
/* Titles */
for (unsigned int i = 0; i < p_sys->i_title; i++)
free(p_sys);
}
+/*****************************************************************************
+ * Elementary streams handling
+ *****************************************************************************/
+
+struct es_out_sys_t {
+ demux_t *p_demux;
+};
+
+typedef struct fmt_es_pair {
+ int i_id;
+ es_out_id_t *p_es;
+} fmt_es_pair_t;
+
+static int findEsPairIndex( demux_sys_t *p_sys, int i_id )
+{
+ for ( int i = 0; i < vlc_array_count(&p_sys->es); ++i ) {
+ if ( ((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->i_id == i_id )
+ return i;
+ }
+ return -1;
+}
+
+static int findEsPairIndexByEs( demux_sys_t *p_sys, es_out_id_t *p_es )
+{
+ for ( int i = 0; i < vlc_array_count(&p_sys->es); ++i ) {
+ if ( ((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->p_es == p_es )
+ return i;
+ }
+ return -1;
+}
+
+static es_out_id_t *esOutAdd( es_out_t *p_out, const es_format_t *p_fmt )
+{
+ demux_sys_t *p_sys = p_out->p_sys->p_demux->p_sys;
+ es_format_t fmt;
+
+ es_format_Copy(&fmt, p_fmt);
+ switch (fmt.i_cat)
+ {
+ case VIDEO_ES:
+ if ( p_sys->i_video_stream != -1 && p_sys->i_video_stream != p_fmt->i_id )
+ fmt.i_priority = -2;
+ break ;
+ case AUDIO_ES:
+ if ( p_sys->i_audio_stream != -1 && p_sys->i_audio_stream != p_fmt->i_id )
+ fmt.i_priority = -2;
+ break ;
+ case SPU_ES:
+ break ;
+ }
+
+ es_out_id_t *p_es = es_out_Add( p_out->p_sys->p_demux->out, &fmt );
+ if ( p_fmt->i_id >= 0 ) {
+ /* Ensure we are not overriding anything */
+ int idx = findEsPairIndex(p_sys, p_fmt->i_id);
+ if ( idx == -1 ) {
+ fmt_es_pair_t *p_pair = malloc( sizeof(*p_pair) );
+ if ( likely(p_pair != NULL) ) {
+ p_pair->i_id = p_fmt->i_id;
+ p_pair->p_es = p_es;
+ msg_Err( p_out->p_sys->p_demux, "Adding ES %d", p_fmt->i_id );
+ vlc_array_append(&p_sys->es, p_pair);
+ }
+ }
+ }
+ es_format_Clean(&fmt);
+ return p_es;
+}
+
+static int esOutSend( es_out_t *p_out, es_out_id_t *p_es, block_t *p_block )
+{
+ return es_out_Send( p_out->p_sys->p_demux->out, p_es, p_block );
+}
+
+static void esOutDel( es_out_t *p_out, es_out_id_t *p_es )
+{
+ int idx = findEsPairIndexByEs( p_out->p_sys->p_demux->p_sys, p_es );
+ if (idx >= 0)
+ {
+ free( vlc_array_item_at_index( &p_out->p_sys->p_demux->p_sys->es, idx) );
+ vlc_array_remove(&p_out->p_sys->p_demux->p_sys->es, idx);
+ }
+ es_out_Del( p_out->p_sys->p_demux->out, p_es );
+}
+
+static int esOutControl( es_out_t *p_out, int i_query, va_list args )
+{
+ return es_out_vaControl( p_out->p_sys->p_demux->out, i_query, args );
+}
+
+static void esOutDestroy( es_out_t *p_out )
+{
+ for ( int i = 0; i < vlc_array_count(&p_out->p_sys->p_demux->p_sys->es); ++i )
+ free( vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, i) );
+ vlc_array_clear(&p_out->p_sys->p_demux->p_sys->es);
+ free( p_out->p_sys );
+ free( p_out );
+}
+
+static es_out_t *esOutNew( demux_t *p_demux )
+{
+ assert( vlc_array_count(&p_demux->p_sys->es) == 0 );
+ es_out_t *p_out = malloc( sizeof(*p_out) );
+ if ( unlikely(p_out == NULL) )
+ return NULL;
+
+ p_out->pf_add = &esOutAdd;
+ p_out->pf_control = &esOutControl;
+ p_out->pf_del = &esOutDel;
+ p_out->pf_destroy = &esOutDestroy;
+ p_out->pf_send = &esOutSend;
+
+ p_out->p_sys = malloc( sizeof(*p_out->p_sys) );
+ if ( unlikely( p_out->p_sys == NULL ) ) {
+ free( p_out );
+ return NULL;
+ }
+ p_out->p_sys->p_demux = p_demux;
+ return p_out;
+}
+
/*****************************************************************************
* subpicture_updater_t functions:
*****************************************************************************/
TAB_APPEND( p_sys->i_title, p_sys->pp_title, t );
bd_free_title_info(title_info);
}
-
- /* Create titles for BLURAY_TITLE_FIRST_PLAY & BLURAY_TITLE_TOP_MENU */
- input_title_t *p_first_play = vlc_input_title_New();
- if (unlikely(!p_first_play))
- return VLC_SUCCESS;
-
- p_first_play->psz_name = strdup("First play");
- p_sys->i_first_play = p_sys->i_title;
- TAB_APPEND(p_sys->i_title, p_sys->pp_title, p_first_play);
-
- input_title_t *p_top_menu = vlc_input_title_New();
- if (unlikely(!p_top_menu))
- return VLC_SUCCESS;
-
- p_top_menu->psz_name = strdup("Top menu");
- p_sys->i_top_menu = p_sys->i_title;
- TAB_APPEND(p_sys->i_title, p_sys->pp_title, p_top_menu);
return VLC_SUCCESS;
}
demux_sys_t *p_sys = p_demux->p_sys;
if (p_sys->p_parser)
stream_Delete(p_sys->p_parser);
- p_sys->p_parser = stream_DemuxNew(p_demux, "ts", p_demux->out);
+ p_sys->p_parser = stream_DemuxNew(p_demux, "ts", p_sys->p_out);
if (!p_sys->p_parser) {
msg_Err(p_demux, "Failed to create TS demuxer");
}
static void blurayUpdateTitle(demux_t *p_demux, unsigned i_title)
{
blurayResetParser(p_demux);
- if (i_title >= p_demux->p_sys->i_title) {
- if (i_title == BLURAY_TITLE_FIRST_PLAY)
- i_title = p_demux->p_sys->i_first_play;
- else if (i_title == BLURAY_TITLE_TOP_MENU)
- i_title = p_demux->p_sys->i_top_menu;
- else
- return;
- }
+ if (i_title >= p_demux->p_sys->i_title)
+ return;
/* read title info and init some values */
p_demux->info.i_title = i_title;
case DEMUX_GET_LENGTH:
{
int64_t *pi_length = (int64_t*)va_arg(args, int64_t *);
- *pi_length = CUR_LENGTH;
+ *pi_length = p_demux->info.i_title < (int)p_sys->i_title ? CUR_LENGTH : 0;
return VLC_SUCCESS;
}
case DEMUX_SET_TIME:
case DEMUX_GET_POSITION:
{
double *pf_position = (double*)va_arg( args, double * );
- *pf_position = (double)FROM_TICKS(bd_tell_time(p_sys->bluray))/CUR_LENGTH;
+ *pf_position = p_demux->info.i_title < (int)p_sys->i_title ?
+ (double)FROM_TICKS(bd_tell_time(p_sys->bluray))/CUR_LENGTH : 0.0;
return VLC_SUCCESS;
}
case DEMUX_SET_POSITION:
return VLC_SUCCESS;
}
+static void blurayUpdateCurrentClip( demux_t *p_demux, uint32_t clip )
+{
+ if (clip == 0xFF)
+ return ;
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ p_sys->i_current_clip = clip;
+ BLURAY_TITLE_INFO *info = bd_get_title_info(p_sys->bluray,
+ bd_get_current_title(p_sys->bluray), 0);
+ if ( info == NULL )
+ return ;
+ /* Let's assume a single video track for now.
+ * This may brake later, but it's enough for now.
+ */
+ assert(info->clips[p_sys->i_current_clip].video_stream_count >= 1);
+ p_sys->i_video_stream = info->clips[p_sys->i_current_clip].video_streams[0].pid;
+ bd_free_title_info(info);
+}
+
static void blurayHandleEvent( demux_t *p_demux, const BD_EVENT *e )
{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
switch (e->event)
{
case BD_EVENT_TITLE:
blurayUpdateTitle(p_demux, e->param);
break;
case BD_EVENT_PLAYITEM:
+ blurayUpdateCurrentClip(p_demux, e->param);
break;
case BD_EVENT_AUDIO_STREAM:
- break;
+ {
+ if ( e->param == 0xFF )
+ break ;
+ BLURAY_TITLE_INFO *info = bd_get_title_info(p_sys->bluray,
+ bd_get_current_title(p_sys->bluray), 0);
+ if ( info == NULL )
+ break ;
+ /* The param we get is the real stream id, not an index, ie. it starts from 1 */
+ int pid = info->clips[p_sys->i_current_clip].audio_streams[e->param - 1].pid;
+ int idx = findEsPairIndex( p_sys, pid );
+ if ( idx >= 0 ) {
+ es_out_id_t *p_es = vlc_array_item_at_index(&p_sys->es, idx);
+ es_out_Control( p_demux->out, ES_OUT_SET_ES, p_es );
+ }
+ bd_free_title_info( info );
+ p_sys->i_audio_stream = pid;
+ break ;
+ }
case BD_EVENT_CHAPTER:
p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
- p_demux->info.i_seekpoint = 0;
+ p_demux->info.i_seekpoint = e->param;
break;
case BD_EVENT_ANGLE:
case BD_EVENT_IG_STREAM: