]> git.sesse.net Git - vlc/blobdiff - modules/access/bluray.c
ALSA: rewrite capture plugin
[vlc] / modules / access / bluray.c
index 7cc738720830c7bc71bf88f0a7298293aeac52f9..1d4eb9655252ce595c4a0f1891641d2713014fe4 100644 (file)
@@ -97,9 +97,8 @@ struct  demux_sys_t
     /* 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;
@@ -114,6 +113,10 @@ struct  demux_sys_t
     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;
 };
 
@@ -125,6 +128,8 @@ struct subpicture_updater_sys_t
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
+static es_out_t *esOutNew( demux_t *p_demux );
+
 static int   blurayControl(demux_t *, int, va_list);
 static int   blurayDemux(demux_t *);
 
@@ -164,6 +169,8 @@ static int blurayOpen( vlc_object_t *object )
         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;
@@ -284,6 +291,12 @@ static int blurayOpen( vlc_object_t *object )
         }
     }
 
+    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");
@@ -328,6 +341,10 @@ static void blurayClose( vlc_object_t *object )
         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++)
@@ -337,6 +354,127 @@ static void blurayClose( vlc_object_t *object )
     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:
  *****************************************************************************/
@@ -736,23 +874,6 @@ static int blurayInitTitles(demux_t *p_demux )
         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;
 }
 
@@ -766,7 +887,7 @@ static void blurayResetParser( demux_t *p_demux )
     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");
     }
@@ -775,14 +896,8 @@ static void blurayResetParser( demux_t *p_demux )
 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;
@@ -881,7 +996,7 @@ static int blurayControl(demux_t *p_demux, int query, va_list args)
         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:
@@ -900,7 +1015,8 @@ static int blurayControl(demux_t *p_demux, int query, va_list args)
         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:
@@ -946,20 +1062,59 @@ static int blurayControl(demux_t *p_demux, int query, va_list args)
     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: