]> git.sesse.net Git - vlc/blobdiff - src/input/input.c
input.c: fixed a possible locking problem in vlc_input_item_GetInfo
[vlc] / src / input / input.c
index 401eb46712e0bf8254fe3538d0273a601241eaa2..dcdf564644bad109b4c8616db08127e6ebbb9ad6 100644 (file)
@@ -162,7 +162,6 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
     vlc_mutex_lock( &p_item->lock );
     for( i = 0; i < p_item->i_options; i++ )
     {
-//        msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
         ParseOption( p_input, p_item->ppsz_options[i] );
     }
     vlc_mutex_unlock( &p_item->lock );
@@ -183,7 +182,7 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
         psz_parser = val.psz_string;
         while( (psz_start = strchr( psz_parser, '{' ) ) )
         {
-            seekpoint_t seekpoint;
+            seekpoint_t *p_seekpoint = vlc_seekpoint_New();
             char backup;
             psz_start++;
             psz_end = strchr( psz_start, '}' );
@@ -193,30 +192,28 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
             *psz_parser = 0;
             *psz_end = ',';
 
-            seekpoint.psz_name = 0;
-            seekpoint.i_byte_offset = 0;
-            seekpoint.i_time_offset = 0;
             while( (psz_end = strchr( psz_start, ',' ) ) )
             {
                 *psz_end = 0;
                 if( !strncmp( psz_start, "name=", 5 ) )
                 {
-                    seekpoint.psz_name = psz_start + 5;
+                    p_seekpoint->psz_name = psz_start + 5;
                 }
                 else if( !strncmp( psz_start, "bytes=", 6 ) )
                 {
-                    seekpoint.i_byte_offset = atoll(psz_start + 6);
+                    p_seekpoint->i_byte_offset = atoll(psz_start + 6);
                 }
                 else if( !strncmp( psz_start, "time=", 5 ) )
                 {
-                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
+                    p_seekpoint->i_time_offset = atoll(psz_start + 5) * 1000000;
                 }
                 psz_start = psz_end + 1;
             }
             msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
-                     seekpoint.psz_name, seekpoint.i_byte_offset,
-                     seekpoint.i_time_offset );
-            input_Control( p_input, INPUT_ADD_BOOKMARK, &seekpoint );
+                     p_seekpoint->psz_name, p_seekpoint->i_byte_offset,
+                     p_seekpoint->i_time_offset );
+            input_Control( p_input, INPUT_ADD_BOOKMARK, p_seekpoint );
+            vlc_seekpoint_Delete( p_seekpoint );
             *psz_parser = backup;
         }
         free( val.psz_string );
@@ -304,6 +301,7 @@ int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
 
     /* Create Object Variables for private use only */
     input_ConfigVarInit( p_input );
+    input_ControlVarInit( p_input );
 
     p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
 
@@ -610,16 +608,22 @@ static int Init( input_thread_t * p_input, vlc_bool_t b_quick )
     int i_es_out_mode;
     int i, i_delay;
 
-    /* Initialize optional stream output. (before access/demuxer) */
+    /* Initialize optional stream output. (before access/demuxer)
+     * XXX: we add a special case if the uri starts by vlc.
+     * else 'vlc in.file --sout "" vlc:quit'  cannot work (the output will
+     * be destroyed in case of a file).
+     * (this will break playing of file starting by 'vlc:' but I don't
+     * want to add more logic, just force file by file:// or code it ;)
+     */
     if( !b_quick )
     {
         psz = var_GetString( p_input, "sout" );
-        if( *psz )
+        if( *psz && strncasecmp( p_input->input.p_item->psz_uri, "vlc:", 4 ) )
         {
             p_input->p_sout = sout_NewInstance( p_input, psz );
             if( p_input->p_sout == NULL )
             {
-                msg_Err( p_input, "cannot start stream output instance," \
+                msg_Err( p_input, "cannot start stream output instance, " \
                                   "aborting" );
                 free( psz );
                 return VLC_EGENERIC;
@@ -711,7 +715,7 @@ static int Init( input_thread_t * p_input, vlc_bool_t b_quick )
             {
                 vlc_value_t s;
 
-                msg_Dbg( p_input, "start-time: %ds",
+                msg_Dbg( p_input, "starting at time: %ds",
                                   (int)( p_input->i_start / I64C(1000000) ) );
 
                 s.i_time = p_input->i_start;
@@ -836,7 +840,7 @@ static int Init( input_thread_t * p_input, vlc_bool_t b_quick )
                     break;
                 }
 
-                msg_Dbg( p_input, "adding slave '%s'", psz );
+                msg_Dbg( p_input, "adding slave input '%s'", psz );
                 slave = InputSourceNew( p_input );
                 if( !InputSourceInit( p_input, slave, psz, NULL, VLC_FALSE ) )
                 {
@@ -908,6 +912,14 @@ static int Init( input_thread_t * p_input, vlc_bool_t b_quick )
             {
                 p_input->b_out_pace_control = VLC_TRUE;
             }
+
+            if( p_input->b_can_pace_control && p_input->b_out_pace_control )
+            {
+                /* We don't want a high input priority here or we'll
+                 * end-up sucking up all the CPU time */
+                vlc_thread_set_priority( p_input, VLC_THREAD_PRIORITY_LOW );
+            }
+
             msg_Dbg( p_input, "starting in %s mode",
                      p_input->b_out_pace_control ? "asynch" : "synch" );
         }
@@ -1142,8 +1154,9 @@ static void ControlReduce( input_thread_t *p_input )
         const int i_ct = p_input->control[i].i_type;
 
         /* XXX We can't merge INPUT_CONTROL_SET_ES */
-        msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control,
+/*        msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control,
                  i_lt, i_ct );
+*/
         if( i_lt == i_ct &&
             ( i_ct == INPUT_CONTROL_SET_STATE ||
               i_ct == INPUT_CONTROL_SET_RATE ||
@@ -1155,7 +1168,7 @@ static void ControlReduce( input_thread_t *p_input )
               i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
         {
             int j;
-            msg_Dbg( p_input, "merged at %d", i );
+//            msg_Dbg( p_input, "merged at %d", i );
             /* Remove the i-1 */
             for( j = i; j <  p_input->i_control; j++ )
                 p_input->control[j-1] = p_input->control[j];
@@ -1181,7 +1194,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
     switch( i_type )
     {
         case INPUT_CONTROL_SET_DIE:
-            msg_Dbg( p_input, "control: INPUT_CONTROL_SET_DIE proceed" );
+            msg_Dbg( p_input, "control: stopping input" );
             /* Mark all submodules to die */
             if( p_input->input.p_access )
                 p_input->input.p_access->b_die = VLC_TRUE;
@@ -1209,6 +1222,9 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
             }
             if( f_pos < 0.0 ) f_pos = 0.0;
             if( f_pos > 1.0 ) f_pos = 1.0;
+            /* Reset the decoders states and clock synch (before calling the demuxer */
+            es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+            input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
             if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION,
                                 f_pos ) )
             {
@@ -1220,8 +1236,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 if( p_input->i_slave > 0 )
                     SlaveSeek( p_input );
 
-                input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
-                es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+                //input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+                //es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
                 b_force_update = VLC_TRUE;
             }
             break;
@@ -1245,6 +1261,11 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 i_time += val.i_time;
             }
             if( i_time < 0 ) i_time = 0;
+
+            /* Reset the decoders states and clock synch (before calling the demuxer */
+            es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+            input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+
             i_ret = demux2_Control( p_input->input.p_demux,
                                     DEMUX_SET_TIME, i_time );
             if( i_ret )
@@ -1271,9 +1292,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 if( p_input->i_slave > 0 )
                     SlaveSeek( p_input );
 
-                input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
-
-                es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+                //input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+                //es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
                 b_force_update = VLC_TRUE;
             }
             break;
@@ -1295,7 +1315,9 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 {
                     /* FIXME What to do ? */
                     msg_Warn( p_input, "cannot unset pause -> EOF" );
+                    vlc_mutex_unlock( &p_input->lock_control );
                     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
+                    vlc_mutex_lock( &p_input->lock_control );
                 }
 
                 b_force_update = VLC_TRUE;
@@ -1483,9 +1505,23 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
             {
                 demux_t *p_demux = p_input->input.p_demux;
                 int i_seekpoint;
+                int64_t i_input_time;
+                int64_t i_seekpoint_time;
 
                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
-                    i_seekpoint = p_demux->info.i_seekpoint - 1;
+                {
+                    i_seekpoint = p_demux->info.i_seekpoint;
+                    i_seekpoint_time = p_input->input.title[p_demux->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
+                    if( i_seekpoint_time >= 0 &&
+                         !demux2_Control( p_demux,
+                                          DEMUX_GET_TIME, &i_input_time ) )
+                    {
+                        if ( i_input_time < i_seekpoint_time + 3000000 )
+                            i_seekpoint--;
+                    }
+                    else
+                        i_seekpoint--;
+                }
                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
                     i_seekpoint = p_demux->info.i_seekpoint + 1;
                 else
@@ -1502,12 +1538,27 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
             }
             else if( p_input->input.i_title > 0 )
             {
+                demux_t *p_demux = p_input->input.p_demux;
                 access_t *p_access = p_input->input.p_access;
                 int i_seekpoint;
+                int64_t i_input_time;
+                int64_t i_seekpoint_time;
 
                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
-                    i_seekpoint = p_access->info.i_seekpoint - 1;
-                else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+                {
+                    i_seekpoint = p_access->info.i_seekpoint;
+                    i_seekpoint_time = p_input->input.title[p_access->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
+                    if( i_seekpoint_time >= 0 &&
+                        demux2_Control( p_demux,
+                                        DEMUX_GET_TIME, &i_input_time ) )
+                    {
+                        if ( i_input_time < i_seekpoint_time + 3000000 )
+                            i_seekpoint--;
+                    }
+                    else
+                        i_seekpoint--;
+                }
+                else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) 
                     i_seekpoint = p_access->info.i_seekpoint + 1;
                 else
                     i_seekpoint = val.i_int;
@@ -1861,6 +1912,7 @@ static int InputSourceInit( input_thread_t *p_input,
     char *psz_access;
     char *psz_demux;
     char *psz_path;
+    char *psz;
     vlc_value_t val;
 
     /* Split uri */
@@ -1970,6 +2022,23 @@ static int InputSourceInit( input_thread_t *p_input,
             goto error;
         }
 
+        /* */
+        psz = var_GetString( p_input, "access-filter" );
+        if( *psz )
+        {
+            access_t *p_access = in->p_access;
+
+            /* TODO support chained access-filter */
+            in->p_access = access2_FilterNew( in->p_access, psz );
+            if( in->p_access == NULL )
+            {
+                in->p_access = p_access;
+                msg_Warn( p_input, "failed to insert access filter %s",
+                          psz );
+            }
+        }
+        free( psz );
+
         /* Get infos from access */
         if( !b_quick )
         {
@@ -2033,6 +2102,10 @@ static int InputSourceInit( input_thread_t *p_input,
             }
         }
     }
+
+    if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
+        in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
+
     free( psz_dup );
     return VLC_SUCCESS;
 
@@ -2308,7 +2381,8 @@ static void ParseOption( input_thread_t *p_input, const char *psz_option )
 
     var_Set( p_input, psz_name, val );
 
-    msg_Dbg( p_input, "set input option: %s to %s", psz_name, psz_value ? psz_value : ( val.b_bool ? "true" : "false") );
+    msg_Dbg( p_input, "set input option: %s to %s", psz_name,
+             psz_value ? psz_value : ( val.b_bool ? "true" : "false") );
 
   cleanup:
     if( psz_name ) free( psz_name );
@@ -2439,3 +2513,114 @@ static void MRLSections( input_thread_t *p_input, char *psz_source,
              psz_source, *pi_title_start, *pi_chapter_start,
              *pi_title_end, *pi_chapter_end );
 }
+
+
+/***********************************************************************
+ * Info management functions
+ ***********************************************************************/
+/**
+ * Get a info item from a given category in a given input item.
+ *
+ * \param p_i The input item to get info from
+ * \param psz_cat String representing the category for the info
+ * \param psz_name String representing the name of the desired info
+ * \return A pointer to the string with the given info if found, or an
+ *         empty string otherwise. The caller should free the returned
+ *         pointer.
+ */
+char *vlc_input_item_GetInfo( input_item_t *p_i,
+                              const char *psz_cat,
+                              const char *psz_name )
+{
+    int i,j;
+
+    vlc_mutex_lock( &p_i->lock );
+
+    for( i = 0 ; i< p_i->i_categories  ; i++ )
+    {
+        info_category_t *p_cat = p_i->pp_categories[i];
+
+        if( !psz_cat || strcmp( p_cat->psz_name, psz_cat ) )
+            continue;
+
+        for( j = 0; j < p_cat->i_infos ; j++ )
+        {
+            if( !strcmp( p_cat->pp_infos[j]->psz_name, psz_name ) )
+            {
+                char *psz_ret = strdup( p_cat->pp_infos[j]->psz_value );
+                vlc_mutex_unlock( &p_i->lock );
+                return psz_ret;
+            }
+        }
+    }
+    vlc_mutex_unlock( &p_i->lock );
+    return strdup( "" );
+}
+
+int vlc_input_item_AddInfo( input_item_t *p_i,
+                            const char *psz_cat,
+                            const char *psz_name,
+                            const char *psz_format, ... )
+{
+    va_list args;
+    int i;
+    info_t *p_info = NULL;
+    info_category_t *p_cat = NULL ;
+
+    vlc_mutex_lock( &p_i->lock );
+
+    for( i = 0 ; i < p_i->i_categories ; i ++ )
+    {
+        if( !strcmp( p_i->pp_categories[i]->psz_name, psz_cat ) )
+        {
+            p_cat = p_i->pp_categories[i];
+            break;
+        }
+    }
+    if( !p_cat )
+    {
+        if( !(p_cat = (info_category_t *)malloc( sizeof(info_category_t) )) )
+        {
+            vlc_mutex_unlock( &p_i->lock );
+            return VLC_EGENERIC;
+        }
+        p_cat->psz_name = strdup( psz_cat );
+        p_cat->i_infos = 0;
+        p_cat->pp_infos = 0;
+        INSERT_ELEM( p_i->pp_categories, p_i->i_categories, p_i->i_categories,
+                     p_cat );
+    }
+
+    for( i = 0; i< p_cat->i_infos; i++ )
+    {
+        if( !strcmp( p_cat->pp_infos[i]->psz_name, psz_name ) )
+        {
+            p_info = p_cat->pp_infos[i];
+            break;
+        }
+    }
+
+    if( !p_info )
+    {
+        if( ( p_info = (info_t *)malloc( sizeof( info_t ) ) ) == NULL )
+        {
+            vlc_mutex_unlock( &p_i->lock );
+            return VLC_EGENERIC;
+        }
+        INSERT_ELEM( p_cat->pp_infos, p_cat->i_infos, p_cat->i_infos, p_info );
+        p_info->psz_name = strdup( psz_name );
+    }
+    else
+    {
+        if( p_info->psz_value ) free( p_info->psz_value );
+    }
+
+    va_start( args, psz_format );
+    vasprintf( &p_info->psz_value, psz_format, args);
+    va_end( args );
+
+    vlc_mutex_unlock( &p_i->lock );
+
+    return VLC_SUCCESS;
+}
+