]> git.sesse.net Git - vlc/blobdiff - src/input/input.c
* src/input/clock.c: changes to the clock resync algo to remove some sensivity to...
[vlc] / src / input / input.c
index 441bb116294f2e137ec36e50568b4d3806a3b0d0..44ddf5197b9b8bb7660f081b20865856c7d74861 100644 (file)
@@ -26,6 +26,7 @@
  * Preamble
  *****************************************************************************/
 #include <stdlib.h>
+#include <ctype.h>
 
 #include <vlc/vlc.h>
 #include <vlc/input.h>
@@ -53,8 +54,8 @@ static void       ControlReduce( input_thread_t * );
 static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
 
 
-static void UpdateFromAccess( input_thread_t * );
-static void UpdateFromDemux( input_thread_t * );
+static int  UpdateFromAccess( input_thread_t * );
+static int  UpdateFromDemux( input_thread_t * );
 
 static void UpdateItemLength( input_thread_t *, int64_t i_length );
 
@@ -62,6 +63,7 @@ static void ParseOption( input_thread_t *p_input, const char *psz_option );
 
 static void DecodeUrl  ( char * );
 static void MRLSplit( input_thread_t *, char *, char **, char **, char ** );
+static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
 
 static input_source_t *InputSourceNew( input_thread_t *);
 static int  InputSourceInit( input_thread_t *, input_source_t *,
@@ -123,6 +125,7 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
     p_input->i_stop  = 0;
     p_input->i_title = 0;
     p_input->title   = NULL;
+    p_input->i_title_offset = p_input->i_seekpoint_offset = 0;
     p_input->i_state = INIT_S;
     p_input->i_rate  = INPUT_RATE_DEFAULT;
     p_input->i_bookmark = 0;
@@ -132,7 +135,6 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
     p_input->b_out_pace_control = VLC_FALSE;
     p_input->i_pts_delay = 0;
 
-
     /* Init Input fields */
     p_input->input.p_item = p_item;
     p_input->input.p_access = NULL;
@@ -141,6 +143,7 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
     p_input->input.b_title_demux = VLC_FALSE;
     p_input->input.i_title  = 0;
     p_input->input.title    = NULL;
+    p_input->input.i_title_offset = p_input->input.i_seekpoint_offset = 0;
     p_input->input.b_can_pace_control = VLC_TRUE;
     p_input->input.b_eof = VLC_FALSE;
     p_input->input.i_cr_average = 0;
@@ -344,18 +347,19 @@ static int Run( input_thread_t *p_input )
                 if( p_input->input.b_title_demux &&
                     p_input->input.p_demux->info.i_update )
                 {
-                    UpdateFromDemux( p_input );
+                    i_ret = UpdateFromDemux( p_input );
                     b_force_update = VLC_TRUE;
                 }
                 else if( !p_input->input.b_title_demux &&
                           p_input->input.p_access &&
                           p_input->input.p_access->info.i_update )
                 {
-                    UpdateFromAccess( p_input );
+                    i_ret = UpdateFromAccess( p_input );
                     b_force_update = VLC_TRUE;
                 }
             }
-            else if( i_ret == 0 )    /* EOF */
+
+            if( i_ret == 0 )    /* EOF */
             {
                 vlc_value_t repeat;
 
@@ -377,9 +381,21 @@ static int Run( input_thread_t *p_input )
                         var_Set( p_input, "input-repeat", repeat );
                     }
 
-                    /* Seek to title 0 position 0(start) */
-                    val.i_int = 0;
-                    input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
+                    /* Seek to start title/seekpoint */
+                    val.i_int = p_input->input.i_title_start -
+                        p_input->input.i_title_offset;
+                    if( val.i_int < 0 || val.i_int >= p_input->input.i_title )
+                        val.i_int = 0;
+                    input_ControlPush( p_input,
+                                       INPUT_CONTROL_SET_TITLE, &val );
+
+                    val.i_int = p_input->input.i_seekpoint_start -
+                        p_input->input.i_seekpoint_offset;
+                    if( val.i_int > 0 /* TODO: check upper boundary */ )
+                        input_ControlPush( p_input,
+                                           INPUT_CONTROL_SET_SEEKPOINT, &val );
+
+                    /* Seek to start position */
                     if( p_input->i_start > 0 )
                     {
                         val.i_time = p_input->i_start;
@@ -421,8 +437,7 @@ static int Run( input_thread_t *p_input )
         }
         vlc_mutex_unlock( &p_input->lock_control );
 
-        if( b_force_update ||
-            i_intf_update < mdate() )
+        if( b_force_update || i_intf_update < mdate() )
         {
             vlc_value_t val;
             double f_pos;
@@ -529,6 +544,8 @@ static int Init( input_thread_t * p_input )
     /* Create global title (from master) */
     p_input->i_title = p_input->input.i_title;
     p_input->title   = p_input->input.title;
+    p_input->i_title_offset = p_input->input.i_title_offset;
+    p_input->i_seekpoint_offset = p_input->input.i_seekpoint_offset;
     if( p_input->i_title > 0 )
     {
         /* Setup variables */
@@ -547,8 +564,12 @@ static int Init( input_thread_t * p_input )
     /* If the desynchronisation requested by the user is < 0, we need to
      * cache more data. */
     var_Get( p_input, "audio-desync", &val );
-    if( val.i_int < 0 )
-        p_input->i_pts_delay -= (val.i_int * 1000);
+    if( val.i_int < 0 ) p_input->i_pts_delay -= (val.i_int * 1000);
+
+    /* Update cr_average depending on the caching */
+    p_input->input.i_cr_average *= (10 * p_input->i_pts_delay / 200000);
+    p_input->input.i_cr_average /= 10;
+    if( p_input->input.i_cr_average <= 0 ) p_input->input.i_cr_average = 1;
 
     /* Load master infos */
     /* Init length */
@@ -559,6 +580,17 @@ static int Init( input_thread_t * p_input )
 
         UpdateItemLength( p_input, val.i_time );
     }
+
+    /* Start title/chapter */
+    val.i_int = p_input->input.i_title_start -
+        p_input->input.i_title_offset;
+    if( val.i_int > 0 && val.i_int < p_input->input.i_title )
+        input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
+    val.i_int = p_input->input.i_seekpoint_start -
+        p_input->input.i_seekpoint_offset;
+    if( val.i_int > 0 /* TODO: check upper boundary */ )
+        input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );
+
     /* Start time*/
     /* Set start time */
     p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
@@ -708,6 +740,13 @@ static int Init( input_thread_t * p_input )
     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
                     val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
 
+    /* Inform the demuxer about waited group (needed only for DVB) */
+    if( val.b_bool )
+        demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, -1 );
+    else
+        demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP,
+                       (int) var_GetInteger( p_input, "program" ) );
+
     if( p_input->p_sout )
     {
         if( p_input->p_sout->i_out_pace_nocontrol > 0 )
@@ -810,6 +849,7 @@ static int Init( input_thread_t * p_input )
             vlc_meta_Delete( p_meta );
         }
     }
+    else if( p_meta ) vlc_meta_Delete( p_meta );
 
     msg_Dbg( p_input, "`%s' sucessfully opened",
              p_input->input.p_item->psz_uri );
@@ -842,7 +882,7 @@ error:
 /*****************************************************************************
  * Error: RunThread() error loop
  *****************************************************************************
- * This function is called when an error occured during thread main's loop.
+ * This function is called when an error occurred during thread main's loop.
  *****************************************************************************/
 static void Error( input_thread_t *p_input )
 {
@@ -861,8 +901,7 @@ static void End( input_thread_t * p_input )
     vlc_value_t val;
     int i;
 
-    msg_Dbg( p_input, "closing `%s'",
-             p_input->input.p_item->psz_uri );
+    msg_Dbg( p_input, "closing input" );
 
     /* We are at the end */
     p_input->i_state = END_S;
@@ -1212,6 +1251,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
             /* No need to force update, es_out does it if needed */
             es_out_Control( p_input->p_es_out,
                             ES_OUT_SET_GROUP, val.i_int );
+
+            demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, val.i_int );
             break;
 
         case INPUT_CONTROL_SET_ES:
@@ -1344,7 +1385,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
 /*****************************************************************************
  * UpdateFromDemux:
  *****************************************************************************/
-static void UpdateFromDemux( input_thread_t *p_input )
+static int UpdateFromDemux( input_thread_t *p_input )
 {
     demux_t *p_demux = p_input->input.p_demux;
     vlc_value_t v;
@@ -1366,12 +1407,38 @@ static void UpdateFromDemux( input_thread_t *p_input )
         p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
     }
     p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
+
+    /* Hmmm only works with master input */
+    if( p_input->input.p_demux == p_demux )
+    {
+        int i_title_end = p_input->input.i_title_end -
+            p_input->input.i_title_offset;
+        int i_seekpoint_end = p_input->input.i_seekpoint_end -
+            p_input->input.i_seekpoint_offset;
+
+        if( i_title_end >= 0 && i_seekpoint_end >= 0 )
+        {
+            if( p_demux->info.i_title > i_title_end ||
+                ( p_demux->info.i_title == i_title_end &&
+                  p_demux->info.i_seekpoint > i_seekpoint_end ) ) return 0;
+        }
+        else if( i_seekpoint_end >=0 )
+        {
+            if( p_demux->info.i_seekpoint > i_seekpoint_end ) return 0;
+        }
+        else if( i_title_end >= 0 )
+        {
+            if( p_demux->info.i_title > i_title_end ) return 0;
+        }
+    }
+
+    return 1;
 }
 
 /*****************************************************************************
  * UpdateFromAccess:
  *****************************************************************************/
-static void UpdateFromAccess( input_thread_t *p_input )
+static int UpdateFromAccess( input_thread_t *p_input )
 {
     access_t *p_access = p_input->input.p_access;
     vlc_value_t v;
@@ -1383,6 +1450,8 @@ static void UpdateFromAccess( input_thread_t *p_input )
 
         input_ControlVarTitle( p_input, p_access->info.i_title );
 
+        stream_AccessUpdate( p_input->input.p_stream );
+
         p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
     }
     if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
@@ -1393,6 +1462,32 @@ static void UpdateFromAccess( input_thread_t *p_input )
         p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
     }
     p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
+
+    /* Hmmm only works with master input */
+    if( p_input->input.p_access == p_access )
+    {
+        int i_title_end = p_input->input.i_title_end -
+            p_input->input.i_title_offset;
+        int i_seekpoint_end = p_input->input.i_seekpoint_end -
+            p_input->input.i_seekpoint_offset;
+
+        if( i_title_end >= 0 && i_seekpoint_end >=0 )
+        {
+            if( p_access->info.i_title > i_title_end ||
+                ( p_access->info.i_title == i_title_end &&
+                  p_access->info.i_seekpoint > i_seekpoint_end ) ) return 0;
+        }
+        else if( i_seekpoint_end >=0 )
+        {
+            if( p_access->info.i_seekpoint > i_seekpoint_end ) return 0;
+        }
+        else if( i_title_end >= 0 )
+        {
+            if( p_access->info.i_title > i_title_end ) return 0;
+        }
+    }
+
+    return 1;
 }
 
 /*****************************************************************************
@@ -1450,6 +1545,14 @@ static int InputSourceInit( input_thread_t *p_input,
     msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
              psz_mrl, psz_access, psz_demux, psz_path );
 
+    /* Hack to allow udp://@:port syntax */
+    if( !psz_access ||
+        (strncmp( psz_access, "udp", 3 ) && strncmp( psz_access, "rtp", 3 )) )
+
+    /* Find optional titles and seekpoints */
+    MRLSections( p_input, psz_path, &in->i_title_start, &in->i_title_end,
+                 &in->i_seekpoint_start, &in->i_seekpoint_end );
+
     if( psz_forced_demux && *psz_forced_demux )
         psz_demux = psz_forced_demux;
 
@@ -1470,9 +1573,9 @@ static int InputSourceInit( input_thread_t *p_input,
         p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
 
         in->b_title_demux = VLC_TRUE;
-        if( demux2_Control( in->p_demux,
-                            DEMUX_GET_TITLE_INFO,
-                            &in->title, &in->i_title ) )
+        if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
+                            &in->title, &in->i_title,
+                            &in->i_title_offset, &in->i_seekpoint_offset ) )
         {
             in->i_title = 0;
             in->title   = NULL;
@@ -1535,9 +1638,10 @@ static int InputSourceInit( input_thread_t *p_input,
         p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
 
         in->b_title_demux = VLC_FALSE;
-        if( access2_Control( in->p_access,
-                             ACCESS_GET_TITLE_INFO,
-                             &in->title, &in->i_title ) )
+        if( access2_Control( in->p_access, ACCESS_GET_TITLE_INFO,
+                             &in->title, &in->i_title,
+                             &in->i_title_offset, &in->i_seekpoint_offset ) )
+
         {
             in->i_title = 0;
             in->title   = NULL;
@@ -1576,7 +1680,8 @@ static int InputSourceInit( input_thread_t *p_input,
         if( in->i_title <= 0 )
         {
             if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
-                                &in->title, &in->i_title ) )
+                                &in->title, &in->i_title,
+                                &in->i_title_offset, &in->i_seekpoint_offset ))
             {
                 in->i_title = 0;
                 in->title   = NULL;
@@ -1869,21 +1974,28 @@ static void ParseOption( input_thread_t *p_input, const char *psz_option )
     return;
 }
 
+/*****************************************************************************
+ * MRLSplit: parse the access, demux and url part of the
+ *           Media Resource Locator.
+ *****************************************************************************/
 static void MRLSplit( input_thread_t *p_input, char *psz_dup,
                       char **ppsz_access, char **ppsz_demux, char **ppsz_path )
 {
     char *psz_access = NULL;
     char *psz_demux  = NULL;
     char *psz_path   = NULL;
-    char *psz;
+    char *psz, *psz_check;
 
     psz = strchr( psz_dup, ':' );
 
+    /* '@' not allowed in access/demux part */
+    psz_check = strchr( psz_dup, '@' );
+    if( psz_check && psz_check < psz ) psz = 0;
+
 #if defined( WIN32 ) || defined( UNDER_CE )
     if( psz - psz_dup == 1 )
     {
-        msg_Warn( p_input, "drive letter %c: found in source string",
-                  psz_dup[0] );
+        msg_Warn( p_input, "drive letter %c: found in source", *psz_dup );
         psz_path = psz_dup;
     }
     else
@@ -1892,8 +2004,7 @@ static void MRLSplit( input_thread_t *p_input, char *psz_dup,
     if( psz )
     {
         *psz++ = '\0';
-        if( psz[0] == '/' && psz[1] == '/' )
-            psz += 2;
+        if( psz[0] == '/' && psz[1] == '/' ) psz += 2;
 
         psz_path = psz;
 
@@ -1911,18 +2022,79 @@ static void MRLSplit( input_thread_t *p_input, char *psz_dup,
         psz_path = psz_dup;
     }
 
-    if( psz_access == NULL )
-        *ppsz_access = "";
-    else
-        *ppsz_access = psz_access;
+    if( !psz_access ) *ppsz_access = "";
+    else *ppsz_access = psz_access;
 
-    if( psz_demux == NULL )
-        *ppsz_demux = "";
-    else
-        *ppsz_demux = psz_demux;
+    if( !psz_demux ) *ppsz_demux = "";
+    else *ppsz_demux = psz_demux;
 
-    if( psz_path == NULL )
-        *ppsz_path = "";
-    else
-        *ppsz_path = psz_path;
+    if( !psz_path ) *ppsz_path = "";
+    else *ppsz_path = psz_path;
+}
+
+/*****************************************************************************
+ * MRLSections: parse title and seekpoint info from the Media Resource Locator.
+ *
+ * Syntax:
+ * [url][@[title-start][:chapter-start][-[title-end][:chapter-end]]]
+ *****************************************************************************/
+static void MRLSections( input_thread_t *p_input, char *psz_source,
+                         int *pi_title_start, int *pi_title_end,
+                         int *pi_chapter_start, int *pi_chapter_end )
+{
+    char *psz, *psz_end, *psz_next, *psz_check;
+
+    *pi_title_start = *pi_title_end = -1;
+    *pi_chapter_start = *pi_chapter_end = -1;
+
+    /* Start by parsing titles and chapters */
+    if( !psz_source || !( psz = strrchr( psz_source, '@' ) ) ) return;
+
+    /* Check we are really dealing with a title/chapter section */
+    psz_check = psz + 1;
+    if( !*psz_check ) return;
+    if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
+    if( *psz_check != ':' && *psz_check != '-' && *psz_check ) return;
+    if( *psz_check == ':' && ++psz_check )
+        if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
+    if( *psz_check != '-' && *psz_check ) return;
+    if( *psz_check == '-' && ++psz_check )
+        if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
+    if( *psz_check != ':' && *psz_check ) return;
+    if( *psz_check == ':' && ++psz_check )
+        if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
+    if( *psz_check ) return;
+
+    /* Separate start and end */
+    *psz++ = 0;
+    if( ( psz_end = strchr( psz, '-' ) ) ) *psz_end++ = 0;
+
+    /* Look for the start title */
+    *pi_title_start = strtol( psz, &psz_next, 0 );
+    if( !*pi_title_start && psz == psz_next ) *pi_title_start = -1;
+    *pi_title_end = *pi_title_start;
+    psz = psz_next;
+
+    /* Look for the start chapter */
+    if( *psz ) psz++;
+    *pi_chapter_start = strtol( psz, &psz_next, 0 );
+    if( !*pi_chapter_start && psz == psz_next ) *pi_chapter_start = -1;
+    *pi_chapter_end = *pi_chapter_start;
+
+    if( psz_end )
+    {
+        /* Look for the end title */
+        *pi_title_end = strtol( psz_end, &psz_next, 0 );
+        if( !*pi_title_end && psz_end == psz_next ) *pi_title_end = -1;
+        psz_end = psz_next;
+
+        /* Look for the end chapter */
+        if( *psz_end ) psz_end++;
+        *pi_chapter_end = strtol( psz_end, &psz_next, 0 );
+        if( !*pi_chapter_end && psz_end == psz_next ) *pi_chapter_end = -1;
+    }
+
+    msg_Dbg( p_input, "source=`%s' title=%d/%d seekpoint=%d/%d",
+             psz_source, *pi_title_start, *pi_chapter_start,
+             *pi_title_end, *pi_chapter_end );
 }