]> git.sesse.net Git - vlc/blobdiff - modules/demux/sdp.c
* sdp: do not register 'rtp' name for access.
[vlc] / modules / demux / sdp.c
index 9cd6d5f44d42ef2d52081fbe5b7c8758742db9a4..f711f7c0d4ff1c123634ee2b86bd5f664aee2a26 100644 (file)
@@ -2,7 +2,7 @@
  * 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 $
+ * $Id: sdp.c,v 1.7 2003/09/08 07:38:30 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
 #include <vlc/vlc.h>
 #include <vlc/input.h>
 
-#include <ninput.h>
+#include "codecs.h"
+
+#include "/usr/src/libmtools/mc.h"
 
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-static int  Open  ( vlc_object_t * );
-static void Close( vlc_object_t * );
+static int  DescribeOpen ( vlc_object_t * );
+static void DescribeClose( vlc_object_t * );
+
+static int  SDPOpen ( vlc_object_t * );
+static void SDPClose( vlc_object_t * );
 
 vlc_module_begin();
-    set_description( _("SDP demuxer + UDP/RTP/RTSP") );
+    set_description( _("SDP demuxer/reader") );
     set_capability( "demux", 100 );
-    set_callbacks( Open, Close );
+    set_callbacks( SDPOpen, SDPClose );
     add_shortcut( "sdp" );
+
+    add_submodule();
+        set_description( _("RTSP/RTP describe") );
+        add_shortcut( "rtp_sdp" );
+        add_shortcut( "rtsp" );
+        set_capability( "access", 0 );
+        set_callbacks( DescribeOpen, DescribeClose );
 vlc_module_end();
 
+static ssize_t  DescribeRead( input_thread_t *, byte_t *, size_t );
+static int      SDPDemux( input_thread_t * );
 
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static int  Demux ( input_thread_t * );
+struct access_sys_t
+{
+    int  i_sdp;
+    int  i_sdp_pos;
+    char *psz_sdp;
+};
 
-typedef struct
+struct demux_sys_t
 {
-    char    *psz_media;
-    char    *psz_description;
-    char    *psz_connection;
-    char    *psz_bandwith;
-    char    *psz_key;
+    stream_t       *s;
 
-} sdp_media_t;
+    media_client_t *mc;
+};
 
-typedef struct
+struct media_client_sys_t
 {
-    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
+    es_descriptor_t *es;
+
+    int64_t         i_timestamp;
+    vlc_bool_t      b_complete;
+    pes_packet_t    *p_pes;
+};
+
+static void CodecFourcc( char *psz_name, uint8_t *pi_cat,vlc_fourcc_t *pi_fcc);
+
+static void EsDecoderCreate( input_thread_t * p_input, media_client_es_t *p_es );
+static int  EsDecoderSend  ( input_thread_t * p_input,
+                             media_client_es_t *p_es, media_client_frame_t *p_frame );
+
+
+/*****************************************************************************
+ * DescribeOpen : create a SDP from an URL
+ *****************************************************************************
+ *
+ *****************************************************************************/
+static int  DescribeOpen( vlc_object_t *p_this )
 {
-    int           i_session;
-    sdp_session_t *session;
+    input_thread_t *p_input = (input_thread_t *)p_this;
+    access_sys_t   *p_sys;
+    char           *psz_uri;
+
+    if( p_input->psz_access == NULL ||
+        ( strcmp( p_input->psz_access, "rtsp" ) &&
+          strcmp( p_input->psz_access, "rtp_sdp" ) ) )
+    {
+        msg_Dbg( p_input, "invalid access name" );
+        return VLC_EGENERIC;
+    }
+
+    /* We cannot directly use p_input->psz_source as we cannot accept
+     * something like rtsp/<demuxer>:// */
+    psz_uri = malloc( strlen( p_input->psz_access ) +
+                      strlen( p_input->psz_name ) + 4 );
+    if( !strcmp( p_input->psz_access, "rtp_sdp" ) )
+    {
+        sprintf( psz_uri, "rtp://%s", p_input->psz_name );
+    }
+    else
+    {
+        sprintf( psz_uri, "%s://%s", p_input->psz_access, p_input->psz_name );
+    }
 
-} sdp_t;
+    msg_Dbg( p_input, "describing %s", psz_uri );
 
-struct demux_sys_t
+    p_sys = p_input->p_access_data = malloc( sizeof( access_sys_t ) );
+    p_sys->i_sdp    = 0;
+    p_sys->i_sdp_pos= 0;
+    p_sys->psz_sdp  = media_client_describe_url( psz_uri );
+
+    if( p_sys->psz_sdp == NULL )
+    {
+        msg_Err( p_input, "cannot describe %s", psz_uri );
+        free( psz_uri );
+        return VLC_EGENERIC;
+    }
+    free( psz_uri );
+    p_sys->i_sdp = strlen( p_sys->psz_sdp );
+
+    p_input->i_mtu = 0;
+
+    /* Set exported functions */
+    p_input->pf_read = DescribeRead;
+    p_input->pf_seek = NULL;
+    p_input->pf_set_program = input_SetProgram;
+    p_input->pf_set_area = NULL;
+    p_input->p_private = NULL;
+
+    /* Finished to set some variable */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    p_input->stream.b_pace_control = VLC_FALSE;
+    p_input->stream.p_selected_area->i_tell = 0;
+    p_input->stream.b_seekable = 0;
+    p_input->stream.p_selected_area->i_size = 0;
+    p_input->stream.i_method = INPUT_METHOD_NETWORK;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    /* Update default_pts to a suitable value for RTSP access */
+    p_input->i_pts_delay = 4 * DEFAULT_PTS_DELAY;
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * DescribeClose
+ *****************************************************************************
+ *
+ *****************************************************************************/
+static void DescribeClose( vlc_object_t * p_this )
 {
-    stream_t *s;
+    input_thread_t *p_input = (input_thread_t *)p_this;
+    access_sys_t   *p_sys   = p_input->p_access_data;
 
-    sdp_t    *p_sdp;
-};
+    free( p_sys->psz_sdp );
+    free( p_sys );
+}
+
+/*****************************************************************************
+ * DescribeRead
+ *****************************************************************************
+ *
+ *****************************************************************************/
+static ssize_t DescribeRead( input_thread_t * p_input,
+                             byte_t * p_buffer, size_t i_len)
+{
+    access_sys_t   *p_sys   = p_input->p_access_data;
+    int            i_copy = __MIN( (int)i_len,
+                                   p_sys->i_sdp - p_sys->i_sdp_pos );
+    if( i_copy > 0 )
+    {
+        memcpy( p_buffer, &p_sys->psz_sdp[p_sys->i_sdp_pos], i_copy );
+        p_sys->i_sdp_pos += i_copy;
+    }
 
-static sdp_t *sdp_Parse  ( char * );
-static void  sdp_Dump    ( input_thread_t *, sdp_t * );
-static void   sdp_Release( sdp_t * );
+    return i_copy;
+}
 
 /*****************************************************************************
- * Open:
+ * SDPOpen:
+ *****************************************************************************
+ *
  *****************************************************************************/
-static int Open( vlc_object_t * p_this )
+static int SDPOpen( vlc_object_t * p_this )
 {
     input_thread_t *p_input = (input_thread_t *)p_this;
     demux_sys_t    *p_sys;
+
+    int            b_tcp = 0;   /* TODO */
+
     uint8_t        *p_peek;
 
     int            i_sdp;
     int            i_sdp_max;
     char           *psz_sdp;
 
+    int               i_es;
+    media_client_es_t **pp_es;
+    int               i;
+
+    char            *psz_uri;
+
     /* 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 )
@@ -116,17 +228,18 @@ static int Open( vlc_object_t * p_this )
         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 ) )
+    if( strncmp( p_peek, "v=0\r\n", 5 ) &&
+        strncmp( p_peek, "v=0\n", 4 ) )
     {
         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 ) );
+    p_input->pf_demux = SDPDemux;
+    p_input->pf_demux_control = demux_vaControlDefault;
 
+    p_sys = p_input->p_demux_data = malloc( sizeof( demux_sys_t ) );
+    p_sys->mc = media_client_create( b_tcp );
     if( ( p_sys->s = stream_OpenInput( p_input ) ) == NULL )
     {
         msg_Err( p_input, "cannot create stream" );
@@ -142,7 +255,7 @@ static int Open( vlc_object_t * p_this )
         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 < i_sdp_max - i_sdp -1 )
         {
             if( i_read > 0 )
             {
@@ -156,23 +269,62 @@ static int Open( vlc_object_t * p_this )
     }
     psz_sdp[i_sdp] = '\0';
 
-    if( strlen( psz_sdp ) <= 0 )
+    if( i_sdp == 0 )
     {
         msg_Err( p_input, "cannot read SDP file" );
+        free( psz_sdp );
         goto error;
+    }
+    msg_Dbg( p_input, "------sdp file-----\n%s", psz_sdp );
+    msg_Dbg( p_input, "-------------------" );
 
+    /* We cannot directly use p_input->psz_source as we cannot accept
+     * something like rtsp/<demuxer>:// */
+    psz_uri = malloc( strlen( p_input->psz_access ) +
+                      strlen( p_input->psz_name ) + 4 );
+    sprintf( psz_uri, "%s://%s", p_input->psz_access, p_input->psz_name );
+
+    if( media_client_add_sdp( p_sys->mc, psz_sdp, psz_uri ) )
+    {
+        msg_Err( p_input, "cannot add this description" );
+        free( psz_sdp );
+        goto error;
+    }
+    free( psz_sdp );
+
+    media_client_es( p_sys->mc, &pp_es, &i_es );
+    for( i = 0; i < i_es; i++ )
+    {
+        msg_Dbg( p_input, "es[%d] cat=%s codec=%s",
+                 i, pp_es[i]->psz_cat, pp_es[i]->psz_codec );
     }
 
-    if( ( p_sys->p_sdp = sdp_Parse( psz_sdp ) ) == NULL )
+
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( input_InitStream( p_input, 0 ) == -1)
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot init stream" );
+        goto error;
+    }
+    if( input_AddProgram( p_input, 0, 0) == NULL )
     {
-        msg_Err( p_input, "cannot parse SDP" );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot add program" );
         goto error;
     }
-    sdp_Dump( p_input, p_sys->p_sdp );
+    p_input->stream.pp_programs[0]->b_is_ok = 0;
+    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
+    p_input->stream.i_mux_rate = 0 / 50;
+    p_input->stream.p_selected_program->b_is_ok = 1;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
 
     return VLC_SUCCESS;
 
 error:
+    media_client_release( p_sys->mc );
+
     if( p_sys->s )
     {
         stream_Release( p_sys->s );
@@ -182,273 +334,272 @@ error:
 }
 
 /*****************************************************************************
- * Close: frees unused data
+ * SDPClose:
+ *****************************************************************************
+ *
  *****************************************************************************/
-static void Close( vlc_object_t *p_this )
+static void SDPClose( 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 );
+    int               i_es;
+    media_client_es_t **pp_es;
+    int               i;
+
+    media_client_es( p_sys->mc, &pp_es, &i_es );
+    for( i = 0; i < i_es; i++ )
+    {
+        msg_Dbg( p_input, "es[%d] cat=%s codec=%s",
+                 i, pp_es[i]->psz_cat, pp_es[i]->psz_codec );
+
+        if( pp_es[i]->p_sys )
+        {
+            free( pp_es[i]->p_sys );
+        }
+    }
+
+    media_client_release( p_sys->mc );
+    stream_Release( p_sys->s );
     free( p_sys );
 }
 
 /*****************************************************************************
- * Demux: reads and demuxes data packets
+ * SDPDemux:
  *****************************************************************************
  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
  *****************************************************************************/
-static int Demux ( input_thread_t *p_input )
+static int SDPDemux( input_thread_t * p_input )
 {
+    demux_sys_t  *p_sys = p_input->p_demux_data;
+
+    media_client_es_t    *p_es;
+    media_client_frame_t *p_frame;
+
+
+    while( !p_input->b_die && !p_input->b_error )
+    {
+        if( media_client_read( p_sys->mc, &p_es, &p_frame, 500 ) )
+        {
+            msg_Dbg( p_input, "no data" );
+            return 1;
+        }
+
+        if( p_es == NULL )
+        {
+            continue;
+        }
+
+        if( p_es->p_sys == NULL )
+        {
+            EsDecoderCreate( p_input, p_es );
+        }
+
+        if( p_es->p_sys->es && p_es->p_sys->es->p_decoder_fifo &&
+            p_frame->i_data > 0 )
+        {
+            EsDecoderSend( p_input, p_es, p_frame );
+        }
+        return 1;
+    }
 
     return 0;
 }
 
-/*****************************************************************************
- *
- *****************************************************************************/
 
-/*****************************************************************************
- *  SDP Parser
- *****************************************************************************/
-static int   sdp_GetLine( char **ppsz_sdp, char *p_com, char **pp_arg )
+
+static struct
+{
+    char *psz_codec;
+
+    int          i_cat;
+    vlc_fourcc_t i_fcc;
+
+} rtp_codec_map[] =
 {
-    char *p = *ppsz_sdp;
-    char *p_end;
-    int  i_size;
+    { "L16",        AUDIO_ES,   VLC_FOURCC( 't', 'w', 'o', 's' ) },
+    { "MPA",        AUDIO_ES,   VLC_FOURCC( 'm', 'p', 'g', 'a' ) },
+    { "MP4V-ES",    VIDEO_ES,   VLC_FOURCC( 'm', 'p', '4', 'v' ) },
+    { "MP4A-ES",    AUDIO_ES,   VLC_FOURCC( 'm', 'p', '4', 'a' ) },
+/*  { "H263-1998",  VIDEO_ES,   VLC_FOURCC( 'h', '2', '6', '3' ) }, */
+    { NULL,         UNKNOWN_ES, 0 }
+};
 
-    if( p[0] < 'a' || p[0] > 'z' || p[1] != '=' )
+static void CodecFourcc( char *psz_name, uint8_t *pi_cat, vlc_fourcc_t *pi_fcc)
+{
+    int i;
+    for( i = 0; rtp_codec_map[i].psz_codec != NULL; i++ )
     {
-        return VLC_EGENERIC;
+        if( !strcasecmp( psz_name, rtp_codec_map[i].psz_codec ) )
+        {
+            break;
+        }
     }
+    *pi_cat = rtp_codec_map[i].i_cat;
+    *pi_fcc = rtp_codec_map[i].i_fcc;
+}
 
-    *p_com = p[0];
-
-    if( ( p_end = strstr( p, "\n" ) ) == NULL )
+static void EsDecoderCreate( input_thread_t * p_input, media_client_es_t *p_es )
+{
+    msg_Dbg( p_input, "adding es cat=%s codec=%s",
+             p_es->psz_cat, p_es->psz_codec );
+
+    p_es->p_sys = malloc( sizeof( media_client_sys_t ) );
+    p_es->p_sys->p_pes = NULL;
+    p_es->p_sys->b_complete = VLC_FALSE;
+    p_es->p_sys->i_timestamp = 0;
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( !strcmp( p_es->psz_cat, "audio" ) )
+    {
+        p_es->p_sys->es =
+            input_AddES( p_input,
+                         p_input->stream.p_selected_program,
+                         1 , AUDIO_ES, NULL, 0 );
+    }
+    else if( !strcmp( p_es->psz_cat, "video" ) )
     {
-        p_end = p + strlen( p );
+        p_es->p_sys->es =
+            input_AddES( p_input,
+                         p_input->stream.p_selected_program,
+                         1 , VIDEO_ES, NULL, 0 );
     }
     else
     {
-        while( *p_end == '\n' || *p_end == '\r' )
-        {
-            p_end--;
-        }
-        p_end++;
+        msg_Warn( p_input, "cat unsuported" );
+        p_es->p_sys->es = NULL;
     }
-
-    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' )
+    if( p_es->p_sys->es )
     {
-        p_end++;
+        CodecFourcc( p_es->psz_codec,
+                     &p_es->p_sys->es->i_cat,
+                     &p_es->p_sys->es->i_fourcc );
+        msg_Dbg( p_input, "cat=%d fcc=%4.4s",
+                 p_es->p_sys->es->i_cat,
+                 (char*)&p_es->p_sys->es->i_fourcc );
+        if( p_es->p_sys->es->i_cat == AUDIO_ES )
+        {
+            WAVEFORMATEX *p_wf;
+            int          i_size = sizeof( WAVEFORMATEX ) +
+                                  p_es->i_extra_data;
+            p_wf = malloc( i_size );
+            p_wf->wFormatTag     = 0;
+            p_wf->nChannels      = p_es->audio.i_channels;
+            p_wf->nSamplesPerSec = p_es->audio.i_samplerate;
+            p_wf->nBlockAlign    = 0;
+            p_wf->wBitsPerSample = 0;
+            if( !strcmp( p_es->psz_codec, "L16" ) )
+            {
+                p_wf->wBitsPerSample = 16;
+            }
+
+            p_wf->cbSize         = p_es->i_extra_data;
+            if( p_es->i_extra_data > 0 )
+            {
+                memcpy( &p_wf[1], p_es->p_extra_data,
+                        p_es->i_extra_data );
+            }
+            p_es->p_sys->es->p_waveformatex = (void*)p_wf;
+            p_es->p_sys->es->p_bitmapinfoheader = NULL;
+        }
+        else if( p_es->p_sys->es->i_cat == VIDEO_ES )
+        {
+            BITMAPINFOHEADER *p_bih;
+            int              i_size = sizeof( BITMAPINFOHEADER ) +
+                                      p_es->i_extra_data;
+            p_bih = malloc( i_size );
+            p_bih->biSize       = i_size;
+            p_bih->biWidth      = p_es->video.i_width;
+            p_bih->biHeight     = p_es->video.i_height;
+            p_bih->biPlanes     = 1;
+            p_bih->biBitCount   = 24;
+            p_bih->biCompression= 0;
+            p_bih->biSizeImage  = 0;
+            p_bih->biXPelsPerMeter = 0;
+            p_bih->biYPelsPerMeter = 0;
+            p_bih->biClrUsed       = 0;
+            p_bih->biClrImportant  = 0;
+
+            if( p_es->i_extra_data > 0 )
+            {
+                memcpy( &p_bih[1], p_es->p_extra_data,
+                        p_es->i_extra_data );
+            }
+            p_es->p_sys->es->p_waveformatex = NULL;
+            p_es->p_sys->es->p_bitmapinfoheader = (void*)p_bih;
+        }
+        input_SelectES( p_input, p_es->p_sys->es );
     }
-    *ppsz_sdp = p_end;
-    return VLC_SUCCESS;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
 }
 
-static sdp_t *sdp_Parse  ( char *psz_sdp )
+static int  EsDecoderSend  ( input_thread_t * p_input,
+                             media_client_es_t *p_es, media_client_frame_t *p_frame )
 {
-    sdp_t *sdp = malloc( sizeof( sdp_t ) );
+    media_client_sys_t *tk = p_es->p_sys;
+    data_packet_t *p_data;
 
-    sdp->i_session = -1;
-    sdp->session   = NULL;
-
-    for( ;; )
+    if( tk->p_pes && tk->b_complete )
     {
-#define p_session (&sdp->session[sdp->i_session])
-#define p_media   (&p_session->media[p_session->i_media])
-        char com, *psz;
+        tk->p_pes->i_dts = 0;
+        tk->p_pes->i_pts = 0;
 
-        if( sdp_GetLine( &psz_sdp, &com, &psz ) )
+        if( tk->i_timestamp > 0 )
         {
-            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;
+            input_ClockManageRef( p_input,
+                                  p_input->stream.p_selected_program,
+                                  tk->i_timestamp * 9 / 100 );
+            tk->p_pes->i_pts =
+            tk->p_pes->i_dts =
+                input_ClockGetTS( p_input,
+                                  p_input->stream.p_selected_program,
+                                  tk->i_timestamp * 9 / 100 );
         }
 
-#undef p_session
-    }
+        msg_Dbg( p_input, "codec=%s frame pts=%lld dts=%lld",
+                 p_es->psz_codec,
+                 tk->p_pes->i_pts, tk->p_pes->i_dts );
 
-    if( sdp->i_session < 0 )
-    {
-        free( sdp );
-        return NULL;
+
+        input_DecodePES( tk->es->p_decoder_fifo, tk->p_pes );
+        tk->p_pes = 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++ )
+    if( tk->p_pes == NULL )
     {
-        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++ )
+        tk->b_complete = VLC_FALSE;
+        tk->i_timestamp = p_frame->i_pts;
+        tk->p_pes = input_NewPES( p_input->p_method_data );
+        if( tk->p_pes == NULL )
         {
-            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 );
+            msg_Err( p_input, "cannot allocate pes" );
+            return -1;
         }
-        FREE( p_sdp->session[i].media);
+        tk->p_pes->i_rate = p_input->stream.control.i_rate;
+        tk->p_pes->i_nb_data  = 0;
+        tk->p_pes->i_pes_size = 0;
     }
-    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 ); }
+    if( ( p_data = input_NewPacket( p_input->p_method_data,
+                                    p_frame->i_data ) ) == NULL )
+    {
+        msg_Err( p_input, "cannot allocate data" );
+        return -1;
+    }
+    p_data->p_payload_end = p_data->p_payload_start + p_frame->i_data;
+    memcpy( p_data->p_payload_start, p_frame->p_data, p_frame->i_data);
 
-    for( i = 0; i < p_sdp->i_session; i++ )
+    if( tk->p_pes->p_first == NULL )
     {
-        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" );
-        }
+        tk->p_pes->p_first = p_data;
     }
-#undef PRINTS
+    else
+    {
+        tk->p_pes->p_last->p_next = p_data;
+    }
+    tk->p_pes->p_last = p_data;
+    tk->p_pes->i_pes_size += p_frame->i_data;
+    tk->p_pes->i_nb_data++;
+
+    tk->b_complete = p_frame->b_completed;
 }
+