[vlc-devel] [PATCH 5/9] preparser: add a timeout in playlist_preparser_Push

Thomas Guillem thomas at gllm.fr
Sun Jun 5 11:41:46 CEST 2016


By default, the timeout is 5 seconds, see "preparse_timeout" option.
---
 include/vlc_input_item.h |  1 +
 src/libvlc-module.c      |  7 +++++++
 src/libvlc.c             |  2 +-
 src/playlist/item.c      |  2 +-
 src/playlist/preparser.c | 28 ++++++++++++++++++++++++----
 src/playlist/preparser.h |  6 +++++-
 6 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/include/vlc_input_item.h b/include/vlc_input_item.h
index 85ad72c..f16491d 100644
--- a/include/vlc_input_item.h
+++ b/include/vlc_input_item.h
@@ -395,6 +395,7 @@ enum input_item_preparse_status
 {
     ITEM_PREPARSE_SKIPPED,
     ITEM_PREPARSE_FAILED,
+    ITEM_PREPARSE_TIMEOUT,
     ITEM_PREPARSE_DONE
 };
 
diff --git a/src/libvlc-module.c b/src/libvlc-module.c
index 74fc7e5..f4adad0 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -1090,6 +1090,10 @@ static const char *const ppsz_prefres[] = {
     "Automatically preparse files added to the playlist " \
     "(to retrieve some metadata)." )
 
+#define PREPARSE_TIMEOUT_TEXT N_( "Preparsing timeout" )
+#define PREPARSE_TIMEOUT_LONGTEXT N_( \
+    "Maximum time allowed to preparse a file" )
+
 #define METADATA_NETWORK_TEXT N_( "Allow metadata network access" )
 
 #define SD_TEXT N_( "Services discovery modules")
@@ -2016,6 +2020,9 @@ vlc_module_begin ()
     add_bool( "auto-preparse", true, PREPARSE_TEXT,
               PREPARSE_LONGTEXT, false )
 
+    add_integer( "preparse-timeout", 5000, PREPARSE_TIMEOUT_TEXT,
+                 PREPARSE_TIMEOUT_LONGTEXT, false )
+
     add_obsolete_integer( "album-art" )
     add_bool( "metadata-network-access", false, METADATA_NETWORK_TEXT,
                  METADATA_NETWORK_TEXT, false )
diff --git a/src/libvlc.c b/src/libvlc.c
index 694e3bb..316f481 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -627,7 +627,7 @@ int libvlc_MetaRequest(libvlc_int_t *libvlc, input_item_t *item,
     if( i_options & META_REQUEST_OPTION_DO_INTERACT )
         item->b_preparse_interact = true;
     vlc_mutex_unlock( &item->lock );
-    playlist_preparser_Push(priv->parser, item, i_options, NULL);
+    playlist_preparser_Push(priv->parser, item, i_options, -1, NULL);
     return VLC_SUCCESS;
 }
 
diff --git a/src/playlist/item.c b/src/playlist/item.c
index 00bd046..7d3c218 100644
--- a/src/playlist/item.c
+++ b/src/playlist/item.c
@@ -781,7 +781,7 @@ static void GoAndPreparse( playlist_t *p_playlist, int i_mode,
     char *psz_album = input_item_GetAlbum( p_item->p_input );
     if( sys->p_preparser != NULL && !input_item_IsPreparsed( p_item->p_input )
      && (EMPTY_STR(psz_artist) || EMPTY_STR(psz_album)) )
-        playlist_preparser_Push( sys->p_preparser, p_item->p_input, 0, NULL );
+        playlist_preparser_Push( sys->p_preparser, p_item->p_input, 0, -1, NULL );
     free( psz_artist );
     free( psz_album );
 }
diff --git a/src/playlist/preparser.c b/src/playlist/preparser.c
index cf62690..90795de 100644
--- a/src/playlist/preparser.c
+++ b/src/playlist/preparser.c
@@ -43,12 +43,14 @@ struct preparser_entry_t
     input_item_t    *p_item;
     input_item_meta_request_option_t i_options;
     void            *id;
+    mtime_t          timeout;
 };
 
 struct playlist_preparser_t
 {
     vlc_object_t        *object;
     playlist_fetcher_t  *p_fetcher;
+    mtime_t              default_timeout;
 
     input_thread_t      *input;
     void                *input_id;
@@ -77,6 +79,7 @@ playlist_preparser_t *playlist_preparser_New( vlc_object_t *parent )
     p_preparser->input_id = NULL;
     p_preparser->input_done = false;
     p_preparser->object = parent;
+    p_preparser->default_timeout = var_InheritInteger( parent, "preparse-timeout" );
     p_preparser->p_fetcher = playlist_fetcher_New( parent );
     if( unlikely(p_preparser->p_fetcher == NULL) )
         msg_Err( parent, "cannot create fetcher" );
@@ -93,7 +96,7 @@ playlist_preparser_t *playlist_preparser_New( vlc_object_t *parent )
 
 void playlist_preparser_Push( playlist_preparser_t *p_preparser, input_item_t *p_item,
                               input_item_meta_request_option_t i_options,
-                              void *id )
+                              mtime_t timeout, void *id )
 {
     preparser_entry_t *p_entry = malloc( sizeof(preparser_entry_t) );
 
@@ -102,6 +105,7 @@ void playlist_preparser_Push( playlist_preparser_t *p_preparser, input_item_t *p
     p_entry->p_item = p_item;
     p_entry->i_options = i_options;
     p_entry->id = id;
+    p_entry->timeout = timeout < 0 ? p_preparser->default_timeout : timeout;
     vlc_gc_incref( p_entry->p_item );
 
     vlc_mutex_lock( &p_preparser->lock );
@@ -227,6 +231,7 @@ static void Preparse( playlist_preparser_t *preparser,
     /* Do not preparse if it is already done (like by playing it) */
     if( b_preparse && !input_item_IsPreparsed( p_item ) )
     {
+        int status;
         preparser->input = input_CreatePreparser( preparser->object, p_item );
         if( preparser->input == NULL )
         {
@@ -240,9 +245,24 @@ static void Preparse( playlist_preparser_t *preparser,
                          preparser );
         if( input_Start( preparser->input ) == VLC_SUCCESS )
         {
-            while( !preparser->input_done )
-                vlc_cond_wait( &preparser->thread_wait, &preparser->lock );
+            if( p_entry->timeout > 0 )
+            {
+                mtime_t deadline = mdate() + p_entry->timeout;
+                int ret = 0;
+                while( !preparser->input_done && ret == 0 )
+                    ret =vlc_cond_timedwait( &preparser->thread_wait,
+                                             &preparser->lock, deadline );
+                status = ret == 0 ? ITEM_PREPARSE_DONE : ITEM_PREPARSE_TIMEOUT;
+            }
+            else
+            {
+                while( !preparser->input_done )
+                    vlc_cond_wait( &preparser->thread_wait, &preparser->lock );
+                status = ITEM_PREPARSE_DONE;
+            }
         }
+        else
+            status = ITEM_PREPARSE_FAILED;
 
         var_DelCallback( preparser->input, "intf-event", InputEvent,
                          preparser );
@@ -252,7 +272,7 @@ static void Preparse( playlist_preparser_t *preparser,
 
         var_SetAddress( preparser->object, "item-change", p_item );
         input_item_SetPreparsed( p_item, true );
-        input_item_SignalPreparseEnded( p_item, ITEM_PREPARSE_DONE );
+        input_item_SignalPreparseEnded( p_item, status );
     }
     else if (!b_preparse)
         input_item_SignalPreparseEnded( p_item, ITEM_PREPARSE_SKIPPED );
diff --git a/src/playlist/preparser.h b/src/playlist/preparser.h
index fb2b105..367533c 100644
--- a/src/playlist/preparser.h
+++ b/src/playlist/preparser.h
@@ -48,11 +48,15 @@ playlist_preparser_t *playlist_preparser_New( vlc_object_t * );
  * Listen to vlc_InputItemPreparseEnded event to get notified when item is
  * preparsed.
  *
+ * @param timeout maximum time allowed to preparse the item. If -1, the default
+ * "preparse-timeout" option will be used as a timeout. If 0, it will wait
+ * indefinitely. If > 0, the timeout will be used.
  * @param id unique id provided by the caller. This is can be used to cancel
  * the request with playlist_preparser_Cancel()
  */
 void playlist_preparser_Push( playlist_preparser_t *, input_item_t *,
-                              input_item_meta_request_option_t, void *id );
+                              input_item_meta_request_option_t,
+                              mtime_t timeout, void *id );
 
 void playlist_preparser_fetcher_Push( playlist_preparser_t *, input_item_t *,
                                       input_item_meta_request_option_t );
-- 
2.8.1



More information about the vlc-devel mailing list