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

David R. Robison david.robison at openroadsconsulting.com
Mon Aug 4 19:31:28 CEST 2014


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


-- 

David R Robison
Open Roads Consulting, Inc.
103 Watson Road, Chesapeake, VA 23320
phone: (757) 546-3401
e-mail: david.robison at openroadsconsulting.com
web: http://openroadsconsulting.com
blog: http://therobe.blogspot.com
book: http://www.xulonpress.com/bookstore/bookdetail.php?PB_ISBN=9781597816526



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