]> git.sesse.net Git - vlc/commitdiff
rtsp: support Range header in responses
authorPierre Ynard <linkfanel@yahoo.fr>
Tue, 25 Jan 2011 18:51:32 +0000 (19:51 +0100)
committerPierre Ynard <linkfanel@yahoo.fr>
Tue, 25 Jan 2011 18:51:32 +0000 (19:51 +0100)
For VoD, the synchronization is bad, but accurate synchronization would
require at least changes in the core to add support for some kind of
"instant pausing" to the stream output. Synchronous calls to the VLM
shouldn't cause delay problems, no operation waits for the input.

include/vlc_vod.h
modules/misc/rtsp.c
modules/stream_out/rtp.c
modules/stream_out/rtp.h
modules/stream_out/rtsp.c
modules/stream_out/vod.c
src/input/vlm.c

index 6473516153d57ec1614b145e29e314b622d8311e..a19e9b65dc953cc5460116b5fb042d5e841a4a2c 100644 (file)
@@ -69,8 +69,8 @@ static inline int vod_MediaControl( vod_t *p_vod, vod_media_t *p_media,
 
 enum vod_query_e
 {
-    VOD_MEDIA_PLAY,         /* arg1= char *         res=    */
-    VOD_MEDIA_PAUSE,        /* arg1=                res=    */
+    VOD_MEDIA_PLAY,         /* arg1= char *, arg2= int64_t *, res=    */
+    VOD_MEDIA_PAUSE,        /* arg1= int64_t *      res=    */
     VOD_MEDIA_STOP,         /* arg1=                res=can fail    */
     VOD_MEDIA_SEEK,         /* arg1= double         res=    */
     VOD_MEDIA_REWIND,       /* arg1= double         res=    */
index 9f831de3bcc8b605502df77ebdd2bd42a3ec2ab3..ea437e6285b596d7855f37a1ec839de3b6285b4f 100644 (file)
@@ -826,12 +826,14 @@ static void* CommandThread( vlc_object_t *p_this )
         switch( cmd.i_type )
         {
         case RTSP_CMD_TYPE_PLAY:
+            cmd.i_arg = -1;
             vod_MediaControl( p_vod, p_media, cmd.psz_session,
-                              VOD_MEDIA_PLAY, cmd.psz_arg );
+                              VOD_MEDIA_PLAY, cmd.psz_arg, &cmd.i_arg );
             break;
         case RTSP_CMD_TYPE_PAUSE:
+            cmd.i_arg = -1;
             vod_MediaControl( p_vod, p_media, cmd.psz_session,
-                              VOD_MEDIA_PAUSE );
+                              VOD_MEDIA_PAUSE, &cmd.i_arg );
             break;
 
         case RTSP_CMD_TYPE_STOP:
index 758344713cef35e191972b12db7595a2783a5b35..78beb4fcca56747070953dc9a2559af82f45321f 100644 (file)
@@ -1552,11 +1552,16 @@ static int64_t rtp_init_ts( const vod_media_t *p_media,
 
 /* Return a timestamp corresponding to packets being sent now, and that
  * can be passed to rtp_compute_ts() to get rtptime values for each ES.
- * If the stream output is not started, the initial timestamp that will
- * be used with the first packets is returned instead. */
+ * Also return the NPT corresponding to this timestamp. If the stream
+ * output is not started, the initial timestamp that will be used with
+ * the first packets for NPT=0 is returned instead. */
 int64_t rtp_get_ts( const sout_stream_t *p_stream, const sout_stream_id_t *id,
-                    const vod_media_t *p_media, const char *psz_vod_session )
+                    const vod_media_t *p_media, const char *psz_vod_session,
+                    int64_t *p_npt )
 {
+    if (p_npt != NULL)
+        *p_npt = 0;
+
     if (id != NULL)
         p_stream = id->p_stream;
 
@@ -1576,7 +1581,11 @@ int64_t rtp_get_ts( const sout_stream_t *p_stream, const sout_stream_id_t *id,
     if( now < i_npt_zero )
         return p_sys->i_pts_zero;
 
-    return p_sys->i_pts_zero + (now - i_npt_zero); 
+    int64_t npt = now - i_npt_zero;
+    if (p_npt != NULL)
+        *p_npt = npt;
+
+    return p_sys->i_pts_zero + npt; 
 }
 
 void rtp_packetize_common( sout_stream_id_t *id, block_t *out,
index 89a01203d27015eb2491f199cf55479854fc6e91..df57db9f46b0399613e0f300740a4aa8b4be2f27 100644 (file)
@@ -50,7 +50,8 @@ int rtp_add_sink( sout_stream_id_t *id, int fd, bool rtcp_mux, uint16_t *seq );
 void rtp_del_sink( sout_stream_id_t *id, int fd );
 uint16_t rtp_get_seq( sout_stream_id_t *id );
 int64_t rtp_get_ts( const sout_stream_t *p_stream, const sout_stream_id_t *id,
-                    const vod_media_t *p_media, const char *psz_vod_session );
+                    const vod_media_t *p_media, const char *psz_vod_session,
+                    int64_t *p_npt );
 
 /* RTP packetization */
 void rtp_packetize_common (sout_stream_id_t *id, block_t *out,
@@ -95,8 +96,8 @@ void CloseVoD( vlc_object_t * );
 int vod_check_range(vod_media_t *p_media, const char *psz_session,
                     int64_t start, int64_t end);
 void vod_play(vod_media_t *p_media, const char *psz_session,
-              int64_t start, int64_t end, bool running);
-void vod_pause(vod_media_t *p_media, const char *psz_session);
+              int64_t *start, int64_t end);
+void vod_pause(vod_media_t *p_media, const char *psz_session, int64_t *npt);
 void vod_stop(vod_media_t *p_media, const char *psz_session);
 
 const char *vod_get_mux(const vod_media_t *p_media);
index c216539a357756c3928f9f35af3aadbb24c9d285..99e1f8813fad9a9780e797e5479aeb1aa40f89ed 100644 (file)
@@ -934,7 +934,7 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id,
             answer->i_status = 200;
 
             psz_session = httpd_MsgGet( query, "Session" );
-            int64_t start = -1, end = -1;
+            int64_t start = -1, end = -1, npt;
             const char *range = httpd_MsgGet (query, "Range");
             if (range != NULL)
             {
@@ -995,7 +995,8 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id,
                     }
                 }
                 int64_t ts = rtp_get_ts(vod ? NULL : (sout_stream_t *)owner,
-                                        sout_id, rtsp->vod_media, psz_session);
+                                        sout_id, rtsp->vod_media, psz_session,
+                                        vod ? NULL : &npt);
 
                 for( int i = 0; i < ses->trackc; i++ )
                 {
@@ -1045,12 +1046,18 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id,
                 }
                 if (vod)
                 {
-                    bool running = (sout_id != NULL);
-                    vod_play(rtsp->vod_media, psz_session, start, end, running);
+                    vod_play(rtsp->vod_media, psz_session, &start, end);
+                    npt = start;
                 }
             }
             vlc_mutex_unlock( &rtsp->lock );
 
+            if (ses != NULL)
+            {
+                double f_npt = (double) npt / CLOCK_FREQ;
+                httpd_MsgAdd( answer, "Range", "npt=%f-", f_npt );
+            }
+
             if( httpd_MsgGet( query, "Scale" ) != NULL )
                 httpd_MsgAdd( answer, "Scale", "1." );
             break;
@@ -1076,8 +1083,11 @@ static int RtspHandler( rtsp_stream_t *rtsp, rtsp_stream_id_t *id,
             {
                 if (id == NULL)
                 {
-                    if (vod)
-                        vod_pause(rtsp->vod_media, psz_session);
+                    assert(vod);
+                    int64_t npt;
+                    vod_pause(rtsp->vod_media, psz_session, &npt);
+                    double f_npt = (double) npt / CLOCK_FREQ;
+                    httpd_MsgAdd( answer, "Range", "npt=%f-", f_npt );
                 }
                 else /* "Mute" the selected track */
                 {
index 547ffd406f917203ce0e16df21b46d0701fe434b..2fb14ad35cb04a97b744dca20de217e32aec6fa2 100644 (file)
@@ -88,11 +88,13 @@ typedef enum
 {
     RTSP_CMD_TYPE_NONE,  /* Exit requested */
 
+#if 0
     RTSP_CMD_TYPE_PLAY,
     RTSP_CMD_TYPE_PAUSE,
+#endif
     RTSP_CMD_TYPE_STOP,
-    RTSP_CMD_TYPE_SEEK,
 #if 0
+    RTSP_CMD_TYPE_SEEK,
     RTSP_CMD_TYPE_REWIND,
     RTSP_CMD_TYPE_FORWARD,
 #endif
@@ -391,6 +393,7 @@ static void* CommandThread( vlc_object_t *p_this )
         /* */
         switch( cmd.i_type )
         {
+#if 0
         case RTSP_CMD_TYPE_PLAY:
             vod_MediaControl( p_vod, p_media, cmd.psz_session,
                               VOD_MEDIA_PLAY, cmd.psz_arg );
@@ -399,17 +402,18 @@ static void* CommandThread( vlc_object_t *p_this )
             vod_MediaControl( p_vod, p_media, cmd.psz_session,
                               VOD_MEDIA_PAUSE );
             break;
+#endif
 
         case RTSP_CMD_TYPE_STOP:
             vod_MediaControl( p_vod, p_media, cmd.psz_session, VOD_MEDIA_STOP );
             break;
 
+#if 0
         case RTSP_CMD_TYPE_SEEK:
             vod_MediaControl( p_vod, p_media, cmd.psz_session,
                               VOD_MEDIA_SEEK, cmd.i_arg );
             break;
 
-#if 0
         case RTSP_CMD_TYPE_REWIND:
             vod_MediaControl( p_vod, p_media, cmd.psz_session,
                               VOD_MEDIA_REWIND, cmd.f_arg );
@@ -522,33 +526,22 @@ int vod_check_range(vod_media_t *p_media, const char *psz_session,
 
 /* TODO: add support in the VLM for queueing proper PLAY requests with
  * start and end times, fetch whether the input is seekable... and then
- * clean this up and remove the running argument */
+ * clean this up */
 void vod_play(vod_media_t *p_media, const char *psz_session,
-              int64_t start, int64_t end, bool running)
+              int64_t *start, int64_t end)
 {
-    if (vod_check_range(p_media, psz_session, start, end) != VLC_SUCCESS)
+    if (vod_check_range(p_media, psz_session, *start, end) != VLC_SUCCESS)
         return;
 
-    /* We want to seek before unpausing, but it won't
-     * work if the instance is not running yet. */
-
-    if (!running)
-        /* We're passing the #vod{} sout chain here */
-        CommandPush(p_media->p_vod, RTSP_CMD_TYPE_PLAY, p_media,
-                    psz_session, 0, "vod");
-    if (start >= 0)
-        CommandPush(p_media->p_vod, RTSP_CMD_TYPE_SEEK, p_media,
-                    psz_session, start, NULL);
-    if (running)
-        /* This is the thing to do to unpause... */
-        CommandPush(p_media->p_vod, RTSP_CMD_TYPE_PLAY, p_media,
-                    psz_session, 0, "vod");
+    /* We're passing the #vod{} sout chain here */
+    vod_MediaControl(p_media->p_vod, p_media, psz_session,
+                     VOD_MEDIA_PLAY, "vod", start);
 }
 
-void vod_pause(vod_media_t *p_media, const char *psz_session)
+void vod_pause(vod_media_t *p_media, const char *psz_session, int64_t *npt)
 {
-    CommandPush(p_media->p_vod, RTSP_CMD_TYPE_PAUSE, p_media,
-                psz_session, 0, NULL);
+    vod_MediaControl(p_media->p_vod, p_media, psz_session,
+                     VOD_MEDIA_PAUSE, npt);
 }
 
 void vod_stop(vod_media_t *p_media, const char *psz_session)
index 290100aad791c66a2bb3f29de98e353c9b1548d7..070754afcdddec1ec02c0d62ea50ffd5f441aa6b 100644 (file)
@@ -317,13 +317,40 @@ static int vlm_MediaVodControl( void *p_private, vod_media_t *p_vod_media,
     switch( i_query )
     {
     case VOD_MEDIA_PLAY:
+    {
         psz = (const char *)va_arg( args, const char * );
+        int64_t *i_time = (int64_t *)va_arg( args, int64_t *);
+        bool b_retry = false;
+        if (*i_time < 0)
+        {
+            /* No start time requested: return the current NPT */
+            i_ret = vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_TIME, id, psz_id, i_time );
+            /* The instance is not running yet, it will start at 0 */
+            if (i_ret)
+                *i_time = 0;
+        }
+        else
+        {
+            /* We want to seek before unpausing, but it won't
+             * work if the instance is not running yet. */
+            b_retry = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_TIME, id, psz_id, *i_time );
+        }
+
         i_ret = vlm_ControlInternal( vlm, VLM_START_MEDIA_VOD_INSTANCE, id, psz_id, 0, psz );
+
+        if (!i_ret && b_retry)
+            i_ret = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_TIME, id, psz_id, *i_time );
         break;
+    }
 
     case VOD_MEDIA_PAUSE:
+    {
+        int64_t *i_time = (int64_t *)va_arg( args, int64_t *);
         i_ret = vlm_ControlInternal( vlm, VLM_PAUSE_MEDIA_INSTANCE, id, psz_id );
+        if (!i_ret)
+            i_ret = vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_TIME, id, psz_id, i_time );
         break;
+    }
 
     case VOD_MEDIA_STOP:
         i_ret = vlm_ControlInternal( vlm, VLM_STOP_MEDIA_INSTANCE, id, psz_id );