[vlc-devel] [PATCH 07/10] Integrates browsing inside of the playlist

Julien 'Lta' BALLET elthariel at gmail.com
Mon May 26 11:41:47 CEST 2014


From: Julien 'Lta' BALLET <contact at lta.io>

What changes from the previous flow:

  - If an item is browsable, a browser thread is launched instead of
    an input_thread
  - If there's a browser_thread running, we go into LoopBrowser
    instead of LoopInput to clean it when done.
  - If the input emits a INPUT_EVENT_BROWSE, then a (new) retry flag
    is set to true and we retry this item instead of calling GetNextItem()
    This way the item will be browsed next loop, and the next element
    played will be (depending on settings) the first new element inside
    the browsed item (which is now a input_item_node)
---
 src/playlist/engine.c            |   1 +
 src/playlist/playlist_internal.h |  16 +++-
 src/playlist/thread.c            | 194 ++++++++++++++++++++++++++++++++++++---
 3 files changed, 191 insertions(+), 20 deletions(-)

diff --git a/src/playlist/engine.c b/src/playlist/engine.c
index ebb46dc..f102a52 100644
--- a/src/playlist/engine.c
+++ b/src/playlist/engine.c
@@ -274,6 +274,7 @@ playlist_t *playlist_Create( vlc_object_t *p_parent )
     pl_priv(p_playlist)->status.p_node = p_playlist->p_playing;
     pl_priv(p_playlist)->request.b_request = false;
     pl_priv(p_playlist)->status.i_status = PLAYLIST_STOPPED;
+    pl_priv(p_playlist)->status.b_retry = false;
 
     if(b_ml)
         playlist_MLLoad( p_playlist );
diff --git a/src/playlist/playlist_internal.h b/src/playlist/playlist_internal.h
index 51a3748..a361d89 100644
--- a/src/playlist/playlist_internal.h
+++ b/src/playlist/playlist_internal.h
@@ -55,15 +55,21 @@ typedef struct playlist_private_t
 
     vlc_sd_internal_t   **pp_sds;
     int                   i_sds;   /**< Number of service discovery modules */
-    input_thread_t *      p_input;  /**< the input thread associated
-                                     * with the current item */
+
+    /* Only one of the two below should be running and != NULL at any time */
+    input_thread_t *      p_input;    /**< the input thread associated
+                                       * with the current item */
+    browser_thread_t *    p_browser;  /**< OR the browser thread associated with
+                                       * the current item */
+
     input_resource_t *   p_input_resource; /**< input resources */
     struct {
         /* Current status. These fields are readonly, only the playlist
-         * main loop can touch it*/
+         * main loop can touch it */
         playlist_status_t   i_status;  /**< Current status of playlist */
-        playlist_item_t *   p_item; /**< Currently playing/active item */
-        playlist_item_t *   p_node; /**< Current node to play from */
+        playlist_item_t *   p_item;    /**< Currently playing/active item */
+        playlist_item_t *   p_node;    /**< Current node to play from */
+        bool                b_retry;   /**< Loop this item once as it needs browsing */
     } status;
 
     struct {
diff --git a/src/playlist/thread.c b/src/playlist/thread.c
index c41ea19..3b364f2 100644
--- a/src/playlist/thread.c
+++ b/src/playlist/thread.c
@@ -30,6 +30,7 @@
 #include <vlc_common.h>
 #include <vlc_es.h>
 #include <vlc_input.h>
+#include <vlc_browsing.h>
 #include <vlc_interface.h>
 #include <vlc_playlist.h>
 #include <vlc_rand.h>
@@ -98,18 +99,44 @@ static int InputEvent( vlc_object_t *p_this, char const *psz_cmd,
     playlist_t *p_playlist = p_data;
 
     if( newval.i_int != INPUT_EVENT_STATE &&
-        newval.i_int != INPUT_EVENT_DEAD )
+        newval.i_int != INPUT_EVENT_DEAD &&
+        newval.i_int != INPUT_EVENT_BROWSE )
         return VLC_SUCCESS;
 
     PL_LOCK;
 
-    /* XXX: signaling while not changing any parameter... suspicious... */
-    vlc_cond_signal( &pl_priv(p_playlist)->signal );
+    /* An (access) module tells us this item need browsing. Let's retry on this
+       item then. We don't signal since the sending input will die soon ! */
+    if( newval.i_int == INPUT_EVENT_BROWSE )
+        pl_priv(p_playlist)->status.b_retry = true;
+    else
+        /* XXX: signaling while not changing any parameter... suspicious...
+           Lta: it seems normal, it's used to make LoopRequest/Input resume
+           after an item has been played */
+       vlc_cond_signal( &pl_priv(p_playlist)->signal );
 
     PL_UNLOCK;
     return VLC_SUCCESS;
 }
 
+/* Browser Callback */
+static int BrowserEvent( vlc_object_t *p_this, char const *psz_cmd,
+                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
+    playlist_t *p_playlist = p_data;
+
+    if( newval.i_int != BROWSER_EVENT_STATE &&
+        newval.i_int != BROWSER_EVENT_DEAD )
+        return VLC_SUCCESS;
+
+    PL_LOCK;
+    vlc_cond_signal( &pl_priv(p_playlist)->signal );
+    PL_UNLOCK;
+
+    return VLC_SUCCESS;
+}
+
 /**
  * Synchronise the current index of the playlist
  * to match the index of the current item.
@@ -203,9 +230,6 @@ static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item )
     msg_Dbg( p_playlist, "creating new input thread" );
 
     p_input->i_nb_played++;
-    set_current_status_item( p_playlist, p_item );
-
-    p_sys->status.i_status = PLAYLIST_RUNNING;
 
     assert( p_sys->p_input == NULL );
 
@@ -246,6 +270,62 @@ static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item )
 }
 
 /**
+ * Starts the browsing of an item
+ *
+ * \param p_playlist The playlist object
+ * \param p_item The item to be browse
+ *
+ * \return VLC_SUCCESS or an error.
+ */
+static int BrowseItem( playlist_t *p_playlist, playlist_item_t *p_item )
+{
+    playlist_private_t *p_sys = pl_priv(p_playlist);
+    browser_thread_t   *p_browser;
+
+    msg_Dbg( p_playlist, "creating new browser thread for %s" ,
+             p_item->p_input->psz_uri );
+
+    p_sys->p_browser = p_browser = browser_Create( p_playlist, p_item->p_input );
+    if( p_browser != NULL )
+    {
+        var_AddCallback( p_browser, "intf-event", BrowserEvent, p_playlist );
+
+        if( browser_Start( p_browser ) )
+        {
+            browser_Release( p_browser );
+            p_sys->p_browser = p_browser = NULL;
+        }
+    }
+
+    return VLC_SUCCESS;
+}
+
+/**
+ * Starts the browser or the input for an item
+ *
+ * \param p_playlist the playlist object
+ * \param param p_item the item to play or browse
+ *
+ * \return nothing
+ */
+static int PlayOrBrowseItem( playlist_t *p_playlist, playlist_item_t *p_item )
+{
+    playlist_private_t *p_sys = pl_priv(p_playlist);
+
+    PL_ASSERT_LOCKED;
+
+    set_current_status_item( p_playlist, p_item );
+    p_sys->status.i_status = PLAYLIST_RUNNING;
+
+    if( input_item_NeedsBrowsing(p_item->p_input) )
+        BrowseItem( p_playlist, p_item );
+    else
+        PlayItem( p_playlist, p_item );
+
+    return VLC_SUCCESS;
+}
+
+/**
  * Compute the next playlist item depending on
  * the playlist course mode (forward, backward, random, view,...).
  *
@@ -425,7 +505,57 @@ static playlist_item_t *NextItem( playlist_t *p_playlist )
     return p_new;
 }
 
-static void LoopInput( playlist_t *p_playlist )
+
+/**
+ * Part of Playlist Loop that handle browser thread cleanup
+ *
+ * \return 1 if you need to synchronize (cond_wait) after calling it,
+ * 0 otherwise
+ */
+static bool LoopBrowser( playlist_t *p_playlist )
+{
+    playlist_private_t *p_sys = pl_priv(p_playlist);
+    browser_thread_t *p_browser = p_sys->p_browser;
+
+    assert ( p_browser != NULL );
+
+    if( p_sys->request.b_request || p_sys->killed )
+    {
+        PL_DEBUG( "incoming request - stopping current browser : req %d |  kill %d",
+                   p_sys->request.b_request, p_sys->killed );
+        browser_Stop( p_browser, true );
+    }
+
+#warning Unsynchronized access to *p_browser flags...
+    if( p_browser->b_dead )
+    {
+        p_sys->p_browser = NULL;
+        PL_DEBUG( "dead browser" );
+        PL_UNLOCK;
+
+        /* WARNING: Callback deletion are incompatible with the playlist lock. */
+        var_DelCallback( p_browser, "intf-event", BrowserEvent, p_playlist );
+        browser_Close( p_browser );
+        var_TriggerCallback( p_playlist, "activity" );
+        PL_LOCK;
+        return false;
+    }
+    /* This input has finished, ask it to die ! */
+    else if( p_browser->b_error || p_browser->b_eof )
+    {
+        PL_DEBUG( "finished browser" );
+        browser_Stop( p_browser, false );
+    }
+
+    return true;
+}
+
+/**
+ * Part of Playlist Loop that handle input thread cleanup
+ *
+ * \return true if you need to synchronize (cond_wait) after calling it
+ */
+static bool LoopInput( playlist_t *p_playlist )
 {
     playlist_private_t *p_sys = pl_priv(p_playlist);
     input_thread_t *p_input = p_sys->p_input;
@@ -455,7 +585,7 @@ static void LoopInput( playlist_t *p_playlist )
         input_Close( p_input );
         var_TriggerCallback( p_playlist, "activity" );
         PL_LOCK;
-        return;
+        return false;
     }
     /* This input has finished, ask it to die ! */
     else if( p_input->b_error || p_input->b_eof )
@@ -464,7 +594,25 @@ static void LoopInput( playlist_t *p_playlist )
         input_Stop( p_input, false );
     }
 
-    vlc_cond_wait( &p_sys->signal, &p_sys->lock );
+    return true;
+}
+
+static void LoopInputOrBrowser( playlist_t *p_playlist )
+{
+    playlist_private_t *p_sys = pl_priv(p_playlist);
+
+    if( p_sys->p_input != NULL || p_sys->p_browser != NULL )
+    {
+        bool b_need_sync = false;
+
+        if( p_sys->p_input != NULL)
+            b_need_sync = LoopInput( p_playlist );
+        else if( p_sys->p_browser != NULL)
+            b_need_sync = LoopBrowser( p_playlist );
+
+        if( b_need_sync )
+            vlc_cond_wait( &p_sys->signal, &p_sys->lock );
+    }
 }
 
 static void LoopRequest( playlist_t *p_playlist, int i_status )
@@ -485,12 +633,28 @@ static void LoopRequest( playlist_t *p_playlist, int i_status )
         return;
     }
 
-    playlist_item_t *p_item = NextItem( p_playlist );
-    if( p_item )
+    playlist_item_t *p_item;
+    if( p_sys->status.b_retry )
+    {
+        p_item = get_current_status_item( p_playlist );
+        p_sys->status.b_retry = false;
+
+        if( p_item )
+            msg_Dbg( p_playlist, "retrying this playlist item" );
+        else
+            msg_Err( p_playlist, "Trying to retry when no current item");
+    }
+    else
+    {
+        p_item = NextItem( p_playlist );
+        if( p_item )
+            msg_Dbg( p_playlist, "starting playback/browsing of the new playlist item" );
+    }
+
+    if( p_item != NULL )
     {
-        msg_Dbg( p_playlist, "starting playback of the new playlist item" );
         ResyncCurrentIndex( p_playlist, p_item );
-        PlayItem( p_playlist, p_item );
+        PlayOrBrowseItem( p_playlist, p_item );
         return;
     }
 
@@ -515,8 +679,8 @@ static void *Thread ( void *data )
     PL_LOCK;
     for( ;; )
     {
-        while( p_sys->p_input != NULL )
-            LoopInput( p_playlist );
+        while( p_sys->p_input != NULL || p_sys->p_browser != NULL)
+            LoopInputOrBrowser( p_playlist );
 
         if( p_sys->killed )
             break; /* THE END */
-- 
1.9.3




More information about the vlc-devel mailing list