]> git.sesse.net Git - vlc/blobdiff - modules/stream_out/vod.c
Make the video transcoder support filter chains that output multiple frames
[vlc] / modules / stream_out / vod.c
index be4f62a34c8e9a2a620fc9acdd074e7050b7c18e..41c8d254253babfd4b3e28d08b29325a4b1f5f8c 100644 (file)
@@ -60,8 +60,6 @@ struct media_es_t
 
 struct vod_media_t
 {
-    int id;
-
     /* VoD server */
     vod_t *p_vod;
 
@@ -79,31 +77,17 @@ struct vod_media_t
 
 struct vod_sys_t
 {
-    char *psz_rtsp_url;
-
-    /* List of media */
-    int i_media_id;
-    int i_media;
-    vod_media_t **media;
+    char *psz_rtsp_path;
 
     /* */
+    vlc_thread_t thread;
     block_fifo_t *p_fifo_cmd;
 };
 
 /* rtsp delayed command (to avoid deadlock between vlm/httpd) */
 typedef enum
 {
-    RTSP_CMD_TYPE_NONE,  /* Exit requested */
-
-    RTSP_CMD_TYPE_PLAY,
-    RTSP_CMD_TYPE_PAUSE,
     RTSP_CMD_TYPE_STOP,
-    RTSP_CMD_TYPE_SEEK,
-#if 0
-    RTSP_CMD_TYPE_REWIND,
-    RTSP_CMD_TYPE_FORWARD,
-#endif
-
     RTSP_CMD_TYPE_ADD,
     RTSP_CMD_TYPE_DEL,
 } rtsp_cmd_type_t;
@@ -112,20 +96,17 @@ typedef enum
 typedef struct
 {
     int i_type;
-    int i_media_id;
     vod_media_t *p_media;
-    char *psz_session;
     char *psz_arg;
-    int64_t i_arg;
 } rtsp_cmd_t;
 
 static vod_media_t *MediaNew( vod_t *, const char *, input_item_t * );
 static void         MediaDel( vod_t *, vod_media_t * );
 static void         MediaAskDel ( vod_t *, vod_media_t * );
 
-static void* CommandThread( vlc_object_t *p_this );
-static void  CommandPush( vod_t *, rtsp_cmd_type_t, vod_media_t *, const char *psz_session,
-                          int64_t i_arg, const char *psz_arg );
+static void* CommandThread( void *obj );
+static void  CommandPush( vod_t *, rtsp_cmd_type_t, vod_media_t *,
+                          const char *psz_arg );
 
 /*****************************************************************************
  * Open: Starts the RTSP server module
@@ -142,30 +123,37 @@ int OpenVoD( vlc_object_t *p_this )
     psz_url = var_InheritString( p_vod, "rtsp-host" );
 
     if( psz_url == NULL )
-        p_sys->psz_rtsp_url = strdup( "/" );
+        p_sys->psz_rtsp_path = strdup( "/" );
     else
-    if( !( strlen( psz_url ) > 0 && psz_url[strlen( psz_url ) - 1] == '/' ) )
     {
-         if( asprintf( &p_sys->psz_rtsp_url, "%s/", psz_url ) == -1 )
-         {
-             p_sys->psz_rtsp_url = NULL;
-             free( psz_url );
-             goto error;
-         }
-         free( psz_url );
-    }
-    else
-        p_sys->psz_rtsp_url = psz_url;
+        vlc_url_t url;
+        vlc_UrlParse( &url, psz_url, 0 );
+        free( psz_url );
+
+        if( url.psz_path == NULL )
+            p_sys->psz_rtsp_path = strdup( "/" );
+        else
+        if( !( strlen( url.psz_path ) > 0
+               && url.psz_path[strlen( url.psz_path ) - 1] == '/' ) )
+        {
+            if( asprintf( &p_sys->psz_rtsp_path, "%s/", url.psz_path ) == -1 )
+            {
+                p_sys->psz_rtsp_path = NULL;
+                vlc_UrlClean( &url );
+                goto error;
+            }
+        }
+        else
+            p_sys->psz_rtsp_path = strdup( url.psz_path );
 
-    TAB_INIT( p_sys->i_media, p_sys->media );
-    p_sys->i_media_id = 0;
+        vlc_UrlClean( &url );
+    }
 
     p_vod->pf_media_new = MediaNew;
     p_vod->pf_media_del = MediaAskDel;
 
     p_sys->p_fifo_cmd = block_FifoNew();
-    if( vlc_thread_create( p_vod, "rtsp vod thread", CommandThread,
-                           VLC_THREAD_PRIORITY_LOW ) )
+    if( vlc_clone( &p_sys->thread, CommandThread, p_vod, VLC_THREAD_PRIORITY_LOW ) )
     {
         msg_Err( p_vod, "cannot spawn rtsp vod thread" );
         block_FifoRelease( p_sys->p_fifo_cmd );
@@ -177,7 +165,7 @@ int OpenVoD( vlc_object_t *p_this )
 error:
     if( p_sys )
     {
-        free( p_sys->psz_rtsp_url );
+        free( p_sys->psz_rtsp_path );
         free( p_sys );
     }
 
@@ -193,9 +181,8 @@ void CloseVoD( vlc_object_t * p_this )
     vod_sys_t *p_sys = p_vod->p_sys;
 
     /* Stop command thread */
-    vlc_object_kill( p_vod );
-    CommandPush( p_vod, RTSP_CMD_TYPE_NONE, NULL, NULL, 0, NULL );
-    vlc_thread_join( p_vod );
+    vlc_cancel( p_sys->thread );
+    vlc_join( p_sys->thread, NULL );
 
     while( block_FifoCount( p_sys->p_fifo_cmd ) > 0 )
     {
@@ -205,17 +192,11 @@ void CloseVoD( vlc_object_t * p_this )
         block_Release( p_block_cmd );
         if ( cmd.i_type == RTSP_CMD_TYPE_DEL )
             MediaDel(p_vod, cmd.p_media);
-        free( cmd.psz_session );
         free( cmd.psz_arg );
     }
     block_FifoRelease( p_sys->p_fifo_cmd );
 
-    /* Check VLM is not buggy */
-    if( p_sys->i_media > 0 )
-        msg_Err( p_vod, "rtsp vod leaking %d medias", p_sys->i_media );
-    TAB_CLEAN( p_sys->i_media, p_sys->media );
-
-    free( p_sys->psz_rtsp_url );
+    free( p_sys->psz_rtsp_path );
     free( p_sys );
 }
 
@@ -225,8 +206,6 @@ void CloseVoD( vlc_object_t * p_this )
 static vod_media_t *MediaNew( vod_t *p_vod, const char *psz_name,
                               input_item_t *p_item )
 {
-    vod_sys_t *p_sys = p_vod->p_sys;
-
     vod_media_t *p_media = calloc( 1, sizeof(vod_media_t) );
     if( !p_media )
         return NULL;
@@ -281,54 +260,48 @@ static vod_media_t *MediaNew( vod_t *p_vod, const char *psz_name,
         goto error;
     }
 
-    char *psz_url;
+    msg_Dbg(p_vod, "adding media '%s'", psz_name);
 
-    if( asprintf( &psz_url, "%s%s", p_sys->psz_rtsp_url, psz_name ) < 0 )
-        goto error;
+    CommandPush( p_vod, RTSP_CMD_TYPE_ADD, p_media, psz_name );
+    return p_media;
 
-    vlc_url_t url;
-    vlc_UrlParse( &url, psz_url, 0 );
-    free( psz_url );
+error:
+    MediaDel(p_vod, p_media);
+    return NULL;
+}
 
-    p_media->rtsp = RtspSetup(VLC_OBJECT(p_vod), p_media, &url);
+static void MediaSetup( vod_t *p_vod, vod_media_t *p_media,
+                        const char *psz_name )
+{
+    vod_sys_t *p_sys = p_vod->p_sys;
+    char *psz_path;
+
+    if( asprintf( &psz_path, "%s%s", p_sys->psz_rtsp_path, psz_name ) < 0 )
+        return;
 
-    vlc_UrlClean( &url );
+    p_media->rtsp = RtspSetup(VLC_OBJECT(p_vod), p_media, psz_path);
+    free( psz_path );
 
     if (p_media->rtsp == NULL)
-        goto error;
+        return;
 
     for (int i = 0; i < p_media->i_es; i++)
     {
         media_es_t *p_es = p_media->es[i];
         p_es->rtsp_id = RtspAddId(p_media->rtsp, NULL, 0,
                                   p_es->rtp_fmt.clock_rate, -1);
-        if (p_es->rtsp_id == NULL)
-            goto error;
     }
-
-    p_media->id = p_sys->i_media_id++;
-
-    msg_Dbg(p_vod, "adding media '%s', id %i", psz_name, p_media->id);
-
-    CommandPush( p_vod, RTSP_CMD_TYPE_ADD, p_media, NULL, 0, NULL );
-    return p_media;
-
-error:
-    MediaDel(p_vod, p_media);
-    return NULL;
 }
 
 static void MediaAskDel ( vod_t *p_vod, vod_media_t *p_media )
 {
-    msg_Dbg( p_vod, "deleting media id %i", p_media->id );
-    CommandPush( p_vod, RTSP_CMD_TYPE_DEL, p_media, NULL, 0, NULL );
+    msg_Dbg( p_vod, "deleting media" );
+    CommandPush( p_vod, RTSP_CMD_TYPE_DEL, p_media, NULL );
 }
 
 static void MediaDel( vod_t *p_vod, vod_media_t *p_media )
 {
-    vod_sys_t *p_sys = p_vod->p_sys;
-
-    TAB_REMOVE( p_sys->i_media, p_sys->media, p_media );
+    (void) p_vod;
 
     if (p_media->rtsp != NULL)
     {
@@ -353,117 +326,63 @@ static void MediaDel( vod_t *p_vod, vod_media_t *p_media )
     free( p_media );
 }
 
-static void CommandPush( vod_t *p_vod, rtsp_cmd_type_t i_type, vod_media_t *p_media, const char *psz_session,
-                         int64_t i_arg, const char *psz_arg )
+static void CommandPush( vod_t *p_vod, rtsp_cmd_type_t i_type,
+                         vod_media_t *p_media, const char *psz_arg )
 {
     rtsp_cmd_t cmd;
     block_t *p_cmd;
 
-    memset( &cmd, 0, sizeof(cmd) );
     cmd.i_type = i_type;
     cmd.p_media = p_media;
-    if( p_media )
-        cmd.i_media_id = p_media->id;
-    if( psz_session )
-        cmd.psz_session = strdup(psz_session);
-    cmd.i_arg = i_arg;
     if( psz_arg )
         cmd.psz_arg = strdup(psz_arg);
+    else
+        cmd.psz_arg = NULL;
 
-    p_cmd = block_New( p_vod, sizeof(rtsp_cmd_t) );
+    p_cmd = block_Alloc( sizeof(rtsp_cmd_t) );
     memcpy( p_cmd->p_buffer, &cmd, sizeof(cmd) );
 
     block_FifoPut( p_vod->p_sys->p_fifo_cmd, p_cmd );
 }
 
-static void* CommandThread( vlc_object_t *p_this )
+static void* CommandThread( void *obj )
 {
-    vod_t *p_vod = (vod_t*)p_this;
+    vod_t *p_vod = (vod_t*)obj;
     vod_sys_t *p_sys = p_vod->p_sys;
-    int canc = vlc_savecancel ();
 
-    while( vlc_object_alive (p_vod) )
+    for( ;; )
     {
         block_t *p_block_cmd = block_FifoGet( p_sys->p_fifo_cmd );
         rtsp_cmd_t cmd;
-        vod_media_t *p_media = NULL;
-        int i;
 
         if( !p_block_cmd )
             break;
 
+        int canc = vlc_savecancel ();
         memcpy( &cmd, p_block_cmd->p_buffer, sizeof(cmd) );
         block_Release( p_block_cmd );
 
-        if( cmd.i_type == RTSP_CMD_TYPE_NONE )
-            break;
-
-        if ( cmd.i_type == RTSP_CMD_TYPE_ADD )
-        {
-            TAB_APPEND( p_sys->i_media, p_sys->media, cmd.p_media );
-            goto next;
-        }
-
-        if ( cmd.i_type == RTSP_CMD_TYPE_DEL )
-        {
-            MediaDel(p_vod, cmd.p_media);
-            goto next;
-        }
-
         /* */
-        for( i = 0; i < p_sys->i_media; i++ )
-        {
-            if( p_sys->media[i]->id == cmd.i_media_id )
-                break;
-        }
-        if( i >= p_sys->i_media )
-        {
-            goto next;
-        }
-        p_media = p_sys->media[i];
-
         switch( cmd.i_type )
         {
-        case RTSP_CMD_TYPE_PLAY:
-            vod_MediaControl( p_vod, p_media, cmd.psz_session,
-                              VOD_MEDIA_PLAY, cmd.psz_arg );
+        case RTSP_CMD_TYPE_ADD:
+            MediaSetup(p_vod, cmd.p_media, cmd.psz_arg);
             break;
-        case RTSP_CMD_TYPE_PAUSE:
-            vod_MediaControl( p_vod, p_media, cmd.psz_session,
-                              VOD_MEDIA_PAUSE );
+        case RTSP_CMD_TYPE_DEL:
+            MediaDel(p_vod, cmd.p_media);
             break;
-
         case RTSP_CMD_TYPE_STOP:
-            vod_MediaControl( p_vod, p_media, cmd.psz_session, VOD_MEDIA_STOP );
-            break;
-
-        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 );
+            vod_MediaControl( p_vod, cmd.p_media, cmd.psz_arg, VOD_MEDIA_STOP );
             break;
 
-        case RTSP_CMD_TYPE_FORWARD:
-            vod_MediaControl( p_vod, p_media, cmd.psz_session,
-                              VOD_MEDIA_FORWARD, cmd.f_arg );
-            break;
-#endif
-
         default:
             break;
         }
 
-    next:
-        free( cmd.psz_session );
         free( cmd.psz_arg );
+        vlc_restorecancel (canc);
     }
 
-    vlc_restorecancel (canc);
     return NULL;
 }
 
@@ -541,44 +460,41 @@ char *SDPGenerateVoD( const vod_media_t *p_media, const char *rtsp_url )
     return psz_sdp;
 }
 
-/* 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 */
-int vod_play(vod_media_t *p_media, const char *psz_session,
-             int64_t start, int64_t end, bool running)
+int vod_check_range(vod_media_t *p_media, const char *psz_session,
+                    int64_t start, int64_t end)
 {
+    (void) psz_session;
+
     if (p_media->i_length > 0 && (start > p_media->i_length
                                   || end > p_media->i_length))
         return VLC_EGENERIC;
 
-    /* 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");
-
     return VLC_SUCCESS;
 }
 
-void vod_pause(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 */
+void vod_play(vod_media_t *p_media, const char *psz_session,
+              int64_t *start, int64_t end)
+{
+    if (vod_check_range(p_media, psz_session, *start, end) != VLC_SUCCESS)
+        return;
+
+    /* 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, 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)
 {
-    CommandPush(p_media->p_vod, RTSP_CMD_TYPE_STOP, p_media,
-                psz_session, 0, NULL);
+    CommandPush(p_media->p_vod, RTSP_CMD_TYPE_STOP, p_media, psz_session);
 }