[vlc-devel] [PATCH 1/1] Supporting ONVIF PRofile-G recording playback

David R Robison david.robison at openroadsconsulting.com
Mon Aug 4 20:08:55 CEST 2014


Sorry for the multiple messages. I got git configured to send the e-mail,
hopefully this will fix the word wrap.

This is my first attempt at a patch to support ONVIF recorded playback.
This is done by adding a new libvlc_media_player function to set the 
absolute playback time in seconds. When this is done, the live555
module will send the correct PLAY request header. For example,

Range: clock=20140803T171157.000Z-20140804T171157.000Z

---
 include/vlc/libvlc_media_player.h |  9 +++++
 include/vlc_common.h              |  1 +
 include/vlc_demux.h               |  1 +
 include/vlc_variables.h           | 40 +++++++++++++++++++
 lib/libvlc.sym                    |  1 +
 lib/media_player.c                | 13 +++++++
 modules/access/live555.cpp        | 81 +++++++++++++++++++++++++++++++++++++++
 src/input/input.c                 | 36 +++++++++++++++++
 src/input/input_internal.h        |  1 +
 src/input/var.c                   | 20 ++++++++++
 src/misc/objects.c                |  5 +++
 src/misc/variables.c              |  5 +++
 12 files changed, 213 insertions(+)

diff --git a/include/vlc/libvlc_media_player.h b/include/vlc/libvlc_media_player.h
index 4b2f449..22d9f7b 100644
--- a/include/vlc/libvlc_media_player.h
+++ b/include/vlc/libvlc_media_player.h
@@ -663,6 +663,15 @@ LIBVLC_API libvlc_time_t libvlc_media_player_get_time( libvlc_media_player_t *p_
 LIBVLC_API void libvlc_media_player_set_time( libvlc_media_player_t *p_mi, libvlc_time_t i_time );
 
 /**
+ * Set the recorded playback time
+ *
+ * \param p_mi the Media Player
+ * \param i_time_f the playback from time in seconds
+ * \param i_time_t the playback to time in seconds (0 = no limit)
+ */
+LIBVLC_API void libvlc_media_player_set_timerng( libvlc_media_player_t *p_mi, libvlc_time_t i_time_f, libvlc_time_t i_time_t );
+
+/**
  * Get movie position as percentage between 0.0 and 1.0.
  *
  * \param p_mi the Media Player
diff --git a/include/vlc_common.h b/include/vlc_common.h
index 8b4b923..0724d8a 100644
--- a/include/vlc_common.h
+++ b/include/vlc_common.h
@@ -354,6 +354,7 @@ typedef union
     vlc_list_t *    p_list;
     mtime_t         i_time;
     struct { int32_t x; int32_t y; } coords;
+    struct { mtime_t f; mtime_t t; } timerng;
 
 } vlc_value_t;
 
diff --git a/include/vlc_demux.h b/include/vlc_demux.h
index 0dcee0d..8bc1598 100644
--- a/include/vlc_demux.h
+++ b/include/vlc_demux.h
@@ -107,6 +107,7 @@ enum demux_query_e
     DEMUX_GET_LENGTH,           /* arg1= int64_t *      res=    */
     DEMUX_GET_TIME,             /* arg1= int64_t *      res=    */
     DEMUX_SET_TIME,             /* arg1= int64_t arg2= bool b_precise   res=can fail    */
+    DEMUX_SET_TIMERNG,          /* arg1= int64_t arg2= int64_t arg3= bool b_precise   res=can fail    */
 
     /* TITLE_INFO only if more than 1 title or 1 chapter */
     DEMUX_GET_TITLE_INFO,       /* arg1=input_title_t*** arg2=int*
diff --git a/include/vlc_variables.h b/include/vlc_variables.h
index 420f0b4..4f7c432 100644
--- a/include/vlc_variables.h
+++ b/include/vlc_variables.h
@@ -60,6 +60,7 @@
 #define VLC_VAR_TIME      0x0060
 #define VLC_VAR_ADDRESS   0x0070
 #define VLC_VAR_COORDS    0x00A0
+#define VLC_VAR_TIMERNG   0x00B0
 /**@}*/
 
 /** \defgroup var_flags Additive flags
@@ -234,6 +235,24 @@ static inline int var_SetTime( vlc_object_t *p_obj, const char *psz_name, int64_
     return var_SetChecked( p_obj, psz_name, VLC_VAR_TIME, val );
 }
 
+/**
+ * Set the value of a time variable
+ *
+ * \param p_obj The object that holds the variable
+ * \param psz_name The name of the variable
+ * \param f The new from time value of this variable
+ * \param t The new to time value of this variable
+ */
+static inline int var_SetTimeRng( vlc_object_t *p_obj, const char *psz_name, 
+                                  mtime_t f, mtime_t t )
+{
+    vlc_value_t val;
+    val.timerng.f = f;
+    val.timerng.t = t;
+    return var_SetChecked( p_obj, psz_name, VLC_VAR_TIMERNG, val); 
+}
+#define var_SetTimeRng(o,n,f,t) var_SetTimeRng(VLC_OBJECT(o),n,f,t)
+
 static inline int var_SetCoords( vlc_object_t *obj, const char *name,
                                  int32_t x, int32_t y )
 {
@@ -344,6 +363,27 @@ static inline int64_t var_GetTime( vlc_object_t *p_obj, const char *psz_name )
         return 0;
 }
 
+/**
+ * Get a time value
+ *
+ * \param p_obj The object that holds the variable
+ * \param psz_name The name of the variable
+ */
+static inline void var_GetTimeRng( vlc_object_t *obj, const char *name, 
+                                   mtime_t *pf, mtime_t *pt )
+{
+    vlc_value_t val;
+
+    if (likely(!var_GetChecked (obj, name, VLC_VAR_TIMERNG, &val)))
+    {
+        *pf = val.timerng.f;
+        *pt = val.timerng.t;
+    }
+    else
+        *pf = *pt = 0;
+}
+#define var_GetTimeRng(o,n,f,t) var_GetTimeRng(VLC_OBJECT(o),n,f,t)
+
 static inline void var_GetCoords( vlc_object_t *obj, const char *name,
                                   int32_t *px, int32_t *py )
 {
diff --git a/lib/libvlc.sym b/lib/libvlc.sym
index c0c66dd..858af30 100644
--- a/lib/libvlc.sym
+++ b/lib/libvlc.sym
@@ -173,6 +173,7 @@ libvlc_media_player_set_nsobject
 libvlc_media_player_set_position
 libvlc_media_player_set_rate
 libvlc_media_player_set_time
+libvlc_media_player_set_timerng
 libvlc_media_player_set_title
 libvlc_media_player_set_xwindow
 libvlc_media_player_stop
diff --git a/lib/media_player.c b/lib/media_player.c
index b31a832..a440cba 100644
--- a/lib/media_player.c
+++ b/lib/media_player.c
@@ -1070,6 +1070,19 @@ void libvlc_media_player_set_time( libvlc_media_player_t *p_mi,
     vlc_object_release( p_input_thread );
 }
 
+void libvlc_media_player_set_timerng( libvlc_media_player_t *p_mi,
+                                   libvlc_time_t i_time_f, libvlc_time_t i_time_t )
+{
+    input_thread_t *p_input_thread;
+
+    p_input_thread = libvlc_get_input_thread ( p_mi );
+    if( !p_input_thread )
+        return;
+
+    var_SetTimeRng( p_input_thread, "timerng", to_mtime(i_time_f), to_mtime(i_time_t) );
+    vlc_object_release( p_input_thread );
+}
+
 void libvlc_media_player_set_position( libvlc_media_player_t *p_mi,
                                        float position )
 {
diff --git a/modules/access/live555.cpp b/modules/access/live555.cpp
index b14898c..cfbc95a 100644
--- a/modules/access/live555.cpp
+++ b/modules/access/live555.cpp
@@ -233,6 +233,8 @@ struct demux_sys_t
     int              i_live555_ret; /* live555 callback return code */
 
     float            f_seek_request;/* In case we receive a seek request while paused*/
+    mtime_t          i_timerng_request_f;/* In case we receive a set time range request while paused*/
+    mtime_t          i_timerng_request_t;/* In case we receive a set time range request while paused*/
 };
 
 
@@ -317,6 +319,8 @@ static int  Open ( vlc_object_t *p_this )
     p_sys->psz_path = strdup( p_demux->psz_location );
     p_sys->b_force_mcast = var_InheritBool( p_demux, "rtsp-mcast" );
     p_sys->f_seek_request = -1;
+    p_sys->i_timerng_request_f = -1;
+    p_sys->i_timerng_request_t = -1;
 
     /* parse URL for rtsp://[user:[passwd]@]serverip:port/options */
     vlc_UrlParse( &p_sys->url, p_sys->psz_path, 0 );
@@ -1415,6 +1419,16 @@ static int Demux( demux_t *p_demux )
 }
 
 /*****************************************************************************
+ * Format a time string for the RTSP header
+ *****************************************************************************/
+static char* makeRtspTime(char* buf, int buflen, mtime_t msecs) {
+    time_t secs = msecs / 1000;
+    if (secs <= 0) return NULL;
+    strftime(buf, buflen, "%Y%m%dT%H%M%S.000Z", gmtime(&secs));
+    return buf;
+}
+
+/*****************************************************************************
  * Control:
  *****************************************************************************/
 static int Control( demux_t *p_demux, int i_query, va_list args )
@@ -1521,6 +1535,62 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             }
             return VLC_EGENERIC;
 
+        case DEMUX_SET_TIMERNG:
+            if( p_sys->rtsp )
+            {
+                int i;
+                mtime_t timerng_f = (mtime_t)va_arg( args, mtime_t );
+                mtime_t timerng_t = (mtime_t)va_arg( args, mtime_t );
+
+                if( p_sys->b_paused )
+                {
+                    p_sys->i_timerng_request_f = timerng_f;
+                    p_sys->i_timerng_request_t = timerng_t;
+                    return VLC_SUCCESS;
+                }
+
+                p_sys->rtsp->sendPauseCommand( *p_sys->ms, default_live555_callback );
+
+                if( !wait_Live555_response( p_demux ) )
+                {
+                    msg_Err( p_demux, "PAUSE before seek failed %s",
+                        p_sys->env->getResultMsg() );
+                    return VLC_EGENERIC;
+                }
+
+                char time_from[24];
+                char time_to[24];
+                p_sys->rtsp->sendPlayCommand( *p_sys->ms, default_live555_callback, 
+                    makeRtspTime(time_from, sizeof time_from, timerng_f), 
+                    makeRtspTime(time_to, sizeof time_to, timerng_t), 
+                    1 );
+
+                if( !wait_Live555_response( p_demux ) )
+                {
+                    msg_Err( p_demux, "seek PLAY failed %s",
+                        p_sys->env->getResultMsg() );
+                    return VLC_EGENERIC;
+                }
+                p_sys->i_pcr = 0;
+
+                for( i = 0; i < p_sys->i_track; i++ )
+                {
+                    p_sys->track[i]->b_rtcp_sync = false;
+                    p_sys->track[i]->i_pts = VLC_TS_INVALID;
+                }
+
+                /* Retrieve the starttime if possible */
+                p_sys->f_npt = p_sys->f_npt_start = p_sys->ms->playStartTime();
+
+                /* Retrieve the duration if possible */
+                if( p_sys->ms->playEndTime() > 0 )
+                    p_sys->f_npt_length = p_sys->ms->playEndTime();
+
+                msg_Dbg( p_demux, "seek start: %f stop:%f", p_sys->f_npt_start, p_sys->f_npt_length );
+                return VLC_SUCCESS;
+            }
+            return VLC_EGENERIC;
+
         /* Special for access_demux */
         case DEMUX_CAN_PAUSE:
         case DEMUX_CAN_SEEK:
@@ -1620,6 +1690,15 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
                 return VLC_SUCCESS;
             if( b_pause )
                 p_sys->rtsp->sendPauseCommand( *p_sys->ms, default_live555_callback );
+            else if (p_sys->i_timerng_request_f > 0 || p_sys->i_timerng_request_t > 0)
+            {
+                char time_from[24];
+                char time_to[24];
+                p_sys->rtsp->sendPlayCommand( *p_sys->ms, default_live555_callback, 
+                    makeRtspTime(time_from, sizeof time_from, p_sys->i_timerng_request_f), 
+                    makeRtspTime(time_to, sizeof time_to, p_sys->i_timerng_request_t), 
+                    1 );
+            }
             else
                 p_sys->rtsp->sendPlayCommand( *p_sys->ms, default_live555_callback, p_sys->f_seek_request,
                                               -1.0f, p_sys->ms->scale() );
@@ -1630,6 +1709,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
                 return VLC_EGENERIC;
             }
             p_sys->f_seek_request = -1;
+            p_sys->i_timerng_request_f = -1;
+            p_sys->i_timerng_request_t = -1;
             p_sys->b_paused = b_pause;
 
             /* When we Pause, we'll need the TimeoutPrevention thread to
diff --git a/src/input/input.c b/src/input/input.c
index 87bbfe8..eba638d 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -1469,6 +1469,7 @@ static int ControlGetReducedIndexLocked( input_thread_t *p_input )
               i_ct == INPUT_CONTROL_SET_RATE ||
               i_ct == INPUT_CONTROL_SET_POSITION ||
               i_ct == INPUT_CONTROL_SET_TIME ||
+              i_ct == INPUT_CONTROL_SET_TIMERNG ||
               i_ct == INPUT_CONTROL_SET_PROGRAM ||
               i_ct == INPUT_CONTROL_SET_TITLE ||
               i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
@@ -1536,6 +1537,7 @@ static bool ControlIsSeekRequest( int i_type )
     {
     case INPUT_CONTROL_SET_POSITION:
     case INPUT_CONTROL_SET_TIME:
+    case INPUT_CONTROL_SET_TIMERNG:
     case INPUT_CONTROL_SET_TITLE:
     case INPUT_CONTROL_SET_TITLE_NEXT:
     case INPUT_CONTROL_SET_TITLE_PREV:
@@ -1740,6 +1742,40 @@ static bool Control( input_thread_t *p_input,
             break;
         }
 
+        case INPUT_CONTROL_SET_TIMERNG:
+        {
+            int64_t i_time;
+            int i_ret;
+                    msg_Err( p_input, "INPUT_CONTROL_SET_TIMERNG %"PRId64" %"PRId64, val.timerng.f,val.timerng.t );
+
+            if( p_input->p->b_recording )
+            {
+                msg_Err( p_input, "INPUT_CONTROL_SET_TIMERNG ignored while recording" );
+                break;
+            }
+ 
+            /* Reset the decoders states and clock sync (before calling the demuxer) */
+            es_out_SetTime( p_input->p->p_es_out, -1 );
+
+            i_ret = demux_Control( p_input->p->input.p_demux,
+                                   DEMUX_SET_TIMERNG, val.timerng.f, val.timerng.t,
+                                   !p_input->p->b_fast_seek );
+            if( i_ret )
+            {
+                msg_Warn( p_input, "INPUT_CONTROL_SET_TIMERNG %"PRId64" %"PRId64
+                         " failed or not possible", val.timerng.f, val.timerng.t );
+            }
+            else
+            {
+                if( p_input->p->i_slave > 0 )
+                    SlaveSeek( p_input );
+                p_input->p->input.b_eof = false;
+
+                b_force_update = true;
+            }
+            break;
+        }
+
         case INPUT_CONTROL_SET_STATE:
             if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
                 msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
diff --git a/src/input/input_internal.h b/src/input/input_internal.h
index 9f71294..fa5971d 100644
--- a/src/input/input_internal.h
+++ b/src/input/input_internal.h
@@ -179,6 +179,7 @@ enum input_control_e
     INPUT_CONTROL_SET_POSITION,
 
     INPUT_CONTROL_SET_TIME,
+    INPUT_CONTROL_SET_TIMERNG,
 
     INPUT_CONTROL_SET_PROGRAM,
 
diff --git a/src/input/var.c b/src/input/var.c
index 7591de4..cceb6db 100644
--- a/src/input/var.c
+++ b/src/input/var.c
@@ -47,6 +47,8 @@ static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
                              vlc_value_t oldval, vlc_value_t newval, void * );
 static int TimeCallback    ( vlc_object_t *p_this, char const *psz_cmd,
                              vlc_value_t oldval, vlc_value_t newval, void * );
+static int TimeRngCallback ( vlc_object_t *p_this, char const *psz_cmd,
+                             vlc_value_t oldval, vlc_value_t newval, void * );
 static int ProgramCallback ( vlc_object_t *p_this, char const *psz_cmd,
                              vlc_value_t oldval, vlc_value_t newval, void * );
 static int TitleCallback   ( vlc_object_t *p_this, char const *psz_cmd,
@@ -91,6 +93,7 @@ static const vlc_input_callback_t p_input_callbacks[] =
     CALLBACK( "position", PositionCallback ),
     CALLBACK( "position-offset", PositionCallback ),
     CALLBACK( "time", TimeCallback ),
+    CALLBACK( "timerng", TimeRngCallback ),
     CALLBACK( "time-offset", TimeCallback ),
     CALLBACK( "bookmark", BookmarkCallback ),
     CALLBACK( "program", ProgramCallback ),
@@ -152,6 +155,11 @@ void input_ControlVarInit ( input_thread_t *p_input )
     val.i_time = 0;
     var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
 
+    /* TimeRng */
+    var_Create( p_input, "timerng",  VLC_VAR_TIMERNG );
+    val.timerng.f = val.timerng.t = 0;
+    var_Change( p_input, "timerng", VLC_VAR_SETVALUE, &val, NULL );
+
     /* Bookmark */
     var_Create( p_input, "bookmark", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
                 VLC_VAR_ISCOMMAND );
@@ -652,6 +660,18 @@ static int TimeCallback( vlc_object_t *p_this, char const *psz_cmd,
     return VLC_SUCCESS;
 }
 
+static int TimeRngCallback( vlc_object_t *p_this, char const *psz_cmd,
+                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    input_thread_t *p_input = (input_thread_t*)p_this;
+    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
+
+ 
+    /* */
+    input_ControlPush( p_input, INPUT_CONTROL_SET_TIMERNG, &newval );
+    return VLC_SUCCESS;
+}
+
 static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval,
                             void *p_data )
diff --git a/src/misc/objects.c b/src/misc/objects.c
index 0026ea8..e3a396c 100644
--- a/src/misc/objects.c
+++ b/src/misc/objects.c
@@ -591,6 +591,7 @@ static void DumpVariable (const void *data, const VISIT which, const int depth)
         MYCASE( VARIABLE, "variable" );
         MYCASE( FLOAT, "float" );
         MYCASE( TIME, "time" );
+        MYCASE( TIMERNG, "timerng" );
         MYCASE( COORDS, "coords" );
         MYCASE( ADDRESS, "address" );
 #undef MYCASE
@@ -624,6 +625,10 @@ static void DumpVariable (const void *data, const VISIT which, const int depth)
         case VLC_VAR_TIME:
             printf( ": %"PRIi64, (int64_t)p_var->val.i_time );
             break;
+        case VLC_VAR_TIMERNG:
+            printf( ": %"PRIi64"x%"PRIi64,
+                    p_var->val.timerng.f, p_var->val.timerng.t );
+            break;
         case VLC_VAR_COORDS:
             printf( ": %"PRId32"x%"PRId32,
                     p_var->val.coords.x, p_var->val.coords.y );
diff --git a/src/misc/variables.c b/src/misc/variables.c
index a631863..d43b156 100644
--- a/src/misc/variables.c
+++ b/src/misc/variables.c
@@ -124,6 +124,7 @@ float_ops  = { CmpFloat,   DupDummy,  FreeDummy,  },
 int_ops    = { CmpInt,     DupDummy,  FreeDummy,  },
 string_ops = { CmpString,  DupString, FreeString, },
 time_ops   = { CmpTime,    DupDummy,  FreeDummy,  },
+timerng_ops = { NULL,      DupDummy,  FreeDummy,  };
 coords_ops = { NULL,       DupDummy,  FreeDummy,  };
 
 /*****************************************************************************
@@ -256,6 +257,10 @@ int var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
             p_var->ops = &time_ops;
             p_var->val.i_time = 0;
             break;
+        case VLC_VAR_TIMERNG:
+            p_var->ops = &timerng_ops;
+            p_var->val.timerng.f = p_var->val.timerng.t = 0;
+            break;
         case VLC_VAR_COORDS:
             p_var->ops = &coords_ops;
             p_var->val.coords.x = p_var->val.coords.y = 0;
-- 
1.9.1



This email communication (including any attachments) may contain confidential and/or privileged material intended solely for the individual or entity to which it is addressed.
If you are not the intended recipient, please delete this email immediately.




More information about the vlc-devel mailing list