* sdp: begining of a SDP parser. It won't let you play anything for
authorLaurent Aimar <fenrir@videolan.org>
Sun, 3 Aug 2003 15:25:33 +0000 (15:25 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Sun, 3 Aug 2003 15:25:33 +0000 (15:25 +0000)
 now, it just does (incomplete) parsing.

modules/demux/sdp.c [new file with mode: 0644]

diff --git a/modules/demux/sdp.c b/modules/demux/sdp.c
new file mode 100644 (file)
index 0000000..9cd6d5f
--- /dev/null
@@ -0,0 +1,454 @@
+/*****************************************************************************
+ * sdp.c: SDP parser and builtin UDP/RTP/RTSP
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: sdp.c,v 1.1 2003/08/03 15:25:33 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include <ninput.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int  Open  ( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+vlc_module_begin();
+    set_description( _("SDP demuxer + UDP/RTP/RTSP") );
+    set_capability( "demux", 100 );
+    set_callbacks( Open, Close );
+    add_shortcut( "sdp" );
+vlc_module_end();
+
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int  Demux ( input_thread_t * );
+
+typedef struct
+{
+    char    *psz_media;
+    char    *psz_description;
+    char    *psz_connection;
+    char    *psz_bandwith;
+    char    *psz_key;
+
+} sdp_media_t;
+
+typedef struct
+{
+    char    *psz_origin;
+    char    *psz_session;
+    char    *psz_description;
+    char    *psz_uri;
+    char    *psz_email;
+    char    *psz_phone;
+    char    *psz_connection;
+    char    *psz_bandwith;
+    char    *psz_key;
+    char    *psz_timezone;
+
+    int         i_media;
+    sdp_media_t *media;
+
+} sdp_session_t;
+
+typedef struct
+{
+    int           i_session;
+    sdp_session_t *session;
+
+} sdp_t;
+
+struct demux_sys_t
+{
+    stream_t *s;
+
+    sdp_t    *p_sdp;
+};
+
+static sdp_t *sdp_Parse  ( char * );
+static void  sdp_Dump    ( input_thread_t *, sdp_t * );
+static void   sdp_Release( sdp_t * );
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t * p_this )
+{
+    input_thread_t *p_input = (input_thread_t *)p_this;
+    demux_sys_t    *p_sys;
+    uint8_t        *p_peek;
+
+    int            i_sdp;
+    int            i_sdp_max;
+    char           *psz_sdp;
+
+    /* See if it looks like a SDP
+       v, o, s fields are mandatory and in this order */
+    if( input_Peek( p_input, &p_peek, 7 ) < 7 )
+    {
+        msg_Err( p_input, "cannot peek" );
+        return VLC_EGENERIC;
+    }
+    if( strncmp( p_peek, "v=0\r\no=", 7 ) &&
+        strncmp( p_peek, "v=0\no=", 6 ) )
+    {
+        msg_Err( p_input, "SDP module discarded" );
+        return VLC_EGENERIC;
+    }
+
+    /* Set input_thread_t fields */
+    p_input->pf_demux = Demux;
+    p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
+
+    if( ( p_sys->s = stream_OpenInput( p_input ) ) == NULL )
+    {
+        msg_Err( p_input, "cannot create stream" );
+        goto error;
+    }
+
+    /* Read the complete SDP file */
+    i_sdp = 0;
+    i_sdp_max = 1024;
+    psz_sdp = malloc( i_sdp_max );
+    for( ;; )
+    {
+        int i_read;
+
+        i_read = stream_Read( p_sys->s, &psz_sdp[i_sdp], i_sdp_max - i_sdp -1 );
+        if( i_read <= i_sdp_max - i_sdp -1 )
+        {
+            if( i_read > 0 )
+            {
+                i_sdp += i_read;
+            }
+            break;
+        }
+        i_sdp += i_read;
+        i_sdp_max += 1024;
+        psz_sdp = realloc( psz_sdp, i_sdp_max );
+    }
+    psz_sdp[i_sdp] = '\0';
+
+    if( strlen( psz_sdp ) <= 0 )
+    {
+        msg_Err( p_input, "cannot read SDP file" );
+        goto error;
+
+    }
+
+    if( ( p_sys->p_sdp = sdp_Parse( psz_sdp ) ) == NULL )
+    {
+        msg_Err( p_input, "cannot parse SDP" );
+        goto error;
+    }
+    sdp_Dump( p_input, p_sys->p_sdp );
+
+    return VLC_SUCCESS;
+
+error:
+    if( p_sys->s )
+    {
+        stream_Release( p_sys->s );
+    }
+    free( p_sys );
+    return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * Close: frees unused data
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
+{
+    input_thread_t *p_input = (input_thread_t *)p_this;
+    demux_sys_t    *p_sys = p_input->p_demux_data;
+
+    sdp_Release( p_sys->p_sdp );
+    free( p_sys );
+}
+
+/*****************************************************************************
+ * Demux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int Demux ( input_thread_t *p_input )
+{
+
+    return 0;
+}
+
+/*****************************************************************************
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ *  SDP Parser
+ *****************************************************************************/
+static int   sdp_GetLine( char **ppsz_sdp, char *p_com, char **pp_arg )
+{
+    char *p = *ppsz_sdp;
+    char *p_end;
+    int  i_size;
+
+    if( p[0] < 'a' || p[0] > 'z' || p[1] != '=' )
+    {
+        return VLC_EGENERIC;
+    }
+
+    *p_com = p[0];
+
+    if( ( p_end = strstr( p, "\n" ) ) == NULL )
+    {
+        p_end = p + strlen( p );
+    }
+    else
+    {
+        while( *p_end == '\n' || *p_end == '\r' )
+        {
+            p_end--;
+        }
+        p_end++;
+    }
+
+    i_size = p_end - &p[2];
+    *pp_arg = malloc( i_size + 1 );
+    memcpy(  *pp_arg, &p[2], i_size );
+    (*pp_arg)[i_size] = '\0';
+
+    while( *p_end == '\r' || *p_end == '\n' )
+    {
+        p_end++;
+    }
+    *ppsz_sdp = p_end;
+    return VLC_SUCCESS;
+}
+
+static sdp_t *sdp_Parse  ( char *psz_sdp )
+{
+    sdp_t *sdp = malloc( sizeof( sdp_t ) );
+
+    sdp->i_session = -1;
+    sdp->session   = NULL;
+
+    for( ;; )
+    {
+#define p_session (&sdp->session[sdp->i_session])
+#define p_media   (&p_session->media[p_session->i_media])
+        char com, *psz;
+
+        if( sdp_GetLine( &psz_sdp, &com, &psz ) )
+        {
+            break;
+        }
+        fprintf( stderr, "com=%c arg=%s\n", com, psz );
+        if( sdp->i_session < 0 && ( com !='v' || strcmp( psz, "0" ) ) )
+        {
+            break;
+        }
+        switch( com )
+        {
+            case 'v':
+                fprintf( stderr, "New session added\n" );
+                if( sdp->i_session != -1 )
+                {
+                    p_session->i_media++;
+                }
+                /* Add a new session */
+                sdp->i_session++;
+                sdp->session =
+                    realloc( sdp->session,
+                             (sdp->i_session + 1)*sizeof(sdp_session_t) );
+                p_session->psz_origin     = NULL;
+                p_session->psz_session    = NULL;
+                p_session->psz_description= NULL;
+                p_session->psz_uri        = NULL;
+                p_session->psz_email      = NULL;
+                p_session->psz_phone      = NULL;
+                p_session->psz_connection = NULL;
+                p_session->psz_bandwith   = NULL;
+                p_session->psz_key        = NULL;
+                p_session->psz_timezone   = NULL;
+                p_session->i_media        = -1;
+                p_session->media          = NULL;
+                break;
+            case 'm':
+                fprintf( stderr, "New media added\n" );
+                p_session->i_media++;
+                p_session->media =
+                    realloc( p_session->media,
+                             (p_session->i_media + 1)*sizeof( sdp_media_t ) );
+                p_media->psz_media      = strdup( psz );
+                p_media->psz_description= NULL;
+                p_media->psz_connection = NULL;
+                p_media->psz_bandwith   = NULL;
+                p_media->psz_key        = NULL;
+                break;
+            case 'o':
+                p_session->psz_origin = strdup( psz );
+                break;
+            case 's':
+                p_session->psz_session = strdup( psz );
+                break;
+            case 'i':
+                if( p_session->i_media != -1 )
+                {
+                    p_media->psz_description = strdup( psz );
+                }
+                else
+                {
+                    p_session->psz_description = strdup( psz );
+                }
+                break;
+            case 'u':
+                p_session->psz_uri = strdup( psz );
+                break;
+            case 'e':
+                p_session->psz_email = strdup( psz );
+                break;
+            case 'p':
+                p_session->psz_phone = strdup( psz );
+                break;
+            case 'c':
+                if( p_session->i_media != -1 )
+                {
+                    p_media->psz_connection = strdup( psz );
+                }
+                else
+                {
+                    p_session->psz_connection = strdup( psz );
+                }
+                break;
+            case 'b':
+                if( p_session->i_media != -1 )
+                {
+                    p_media->psz_bandwith = strdup( psz );
+                }
+                else
+                {
+                    p_session->psz_bandwith = strdup( psz );
+                }
+                break;
+            case 'k':
+                if( p_session->i_media != -1 )
+                {
+                    p_media->psz_key = strdup( psz );
+                }
+                else
+                {
+                    p_session->psz_key = strdup( psz );
+                }
+                break;
+            case 'z':
+                p_session->psz_timezone   = strdup( psz );
+                break;
+
+            default:
+                fprintf( stderr, "unhandled com=%c\n", com );
+                break;
+        }
+
+#undef p_session
+    }
+
+    if( sdp->i_session < 0 )
+    {
+        free( sdp );
+        return NULL;
+    }
+    sdp->session[sdp->i_session].i_media++;
+    sdp->i_session++;
+
+    return sdp;
+}
+static void   sdp_Release( sdp_t *p_sdp )
+{
+#define FREE( p ) if( p ) { free( p ) ; (p) = NULL; }
+    int i, j;
+    for( i = 0; i < p_sdp->i_session; i++ )
+    {
+        FREE( p_sdp->session[i].psz_origin );
+        FREE( p_sdp->session[i].psz_session );
+        FREE( p_sdp->session[i].psz_description );
+        FREE( p_sdp->session[i].psz_uri );
+        FREE( p_sdp->session[i].psz_email );
+        FREE( p_sdp->session[i].psz_phone );
+        FREE( p_sdp->session[i].psz_connection );
+        FREE( p_sdp->session[i].psz_bandwith );
+        FREE( p_sdp->session[i].psz_key );
+        FREE( p_sdp->session[i].psz_timezone );
+
+        for( j = 0; j < p_sdp->session[i].i_media; j++ )
+        {
+            FREE( p_sdp->session[i].media[j].psz_media );
+            FREE( p_sdp->session[i].media[j].psz_description );
+            FREE( p_sdp->session[i].media[j].psz_connection );
+            FREE( p_sdp->session[i].media[j].psz_bandwith );
+            FREE( p_sdp->session[i].media[j].psz_key );
+        }
+        FREE( p_sdp->session[i].media);
+    }
+    FREE( p_sdp->session );
+    free( p_sdp );
+#undef FREE
+}
+
+static void  sdp_Dump   ( input_thread_t *p_input, sdp_t *p_sdp )
+{
+    int i, j;
+#define PRINTS( var, fmt ) \
+    if( var ) { msg_Dbg( p_input, "    - " fmt " : %s", var ); }
+#define PRINTM( var, fmt ) \
+    if( var ) { msg_Dbg( p_input, "        - " fmt " : %s", var ); }
+
+    for( i = 0; i < p_sdp->i_session; i++ )
+    {
+        msg_Dbg( p_input, "session[%d]", i );
+        PRINTS( p_sdp->session[i].psz_origin, "Origin" );
+        PRINTS( p_sdp->session[i].psz_session, "Session" );
+        PRINTS( p_sdp->session[i].psz_description, "Description" );
+        PRINTS( p_sdp->session[i].psz_uri, "URI" );
+        PRINTS( p_sdp->session[i].psz_email, "e-mail" );
+        PRINTS( p_sdp->session[i].psz_phone, "Phone" );
+        PRINTS( p_sdp->session[i].psz_connection, "Connection" );
+        PRINTS( p_sdp->session[i].psz_bandwith, "Bandwith" );
+        PRINTS( p_sdp->session[i].psz_key, "Key" );
+        PRINTS( p_sdp->session[i].psz_timezone, "TimeZone" );
+        for( j = 0; j < p_sdp->session[i].i_media; j++ )
+        {
+            msg_Dbg( p_input, "    - media[%d]", j );
+            PRINTM( p_sdp->session[i].media[j].psz_media, "Name" );
+            PRINTM( p_sdp->session[i].media[j].psz_description, "Description" );
+            PRINTM( p_sdp->session[i].media[j].psz_connection, "Connection" );
+            PRINTM( p_sdp->session[i].media[j].psz_bandwith, "Bandwith" );
+            PRINTM( p_sdp->session[i].media[j].psz_key, "Key" );
+        }
+    }
+#undef PRINTS
+}