sgimb.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:16k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * sgimb.c: a meta demux to parse sgimb referrer files
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 VideoLAN
  5.  * $Id: sgimb.c 9300 2004-11-13 01:35:28Z hartman $
  6.  *
  7.  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * This is a metademux for the Kasenna MediaBase metafile format.
  25.  * Kasenna MediaBase first returns this file when you are trying to access
  26.  * their MPEG streams (MIME: application/x-sgimb). Very few applications
  27.  * understand this format and the format is not really documented on the net.
  28.  * Following a typical MediaBase file. Notice the sgi prefix of all the elements.
  29.  * This stems from the fact that the MediaBase servers were first introduced by SGI?????.
  30.  *
  31.  * sgiNameServerHost=host.name.tld
  32.  *     Obvious: the host hosting this stream
  33.  * Stream="xdma://host.name.tld/demo/a_very_cool.mpg"
  34.  *     Not always present. xdma can be read as RTSP.
  35.  * sgiMovieName=/demo/a_very_cool.mpg
  36.  *     The path to the asset
  37.  * sgiAuxState=1|2
  38.  *     AuxState=2 is always Video On Demand (so not Scheduled)
  39.  *     Not present with Live streams
  40.  * sgiLiveFeed=True|False
  41.  *     Denounces if the stream is live or from assets (Canned?)
  42.  *     Live appears as a little sattelite dish in the web interface of Kasenna
  43.  * sgiFormatName=PARTNER_41_MPEG-4
  44.  *     The type of stream. One of:
  45.  *       PARTNER_41_MPEG-4 (RTSP MPEG-4 fully compliant)
  46.  *       MPEG1-Audio       (MP3 Audio streams in MPEG TS)
  47.  *       MPEG-1            (MPEG 1 A/V in MPEG TS)
  48.  *       MPEG-2            (MPEG 2 A/V in MPEG TS)
  49.  * sgiWidth=720
  50.  *     The width of the to be received stream. Only present if stream is not Live.
  51.  * sgiHeight=576
  52.  *     The height of the to be received stream. Only present if stream is not Live.
  53.  * sgiBitrate=1630208
  54.  *     The bitrate of the to be received stream. Only present if stream is not Live.
  55.  * sgiDuration=378345000
  56.  *     The duration of the to be received stream. Only present if stream is not Live.
  57.  * sgiQTFileBegin
  58.  * rtsptext
  59.  * rtsp://host.name.tld/demo/a_very_cool.mpg
  60.  * sgiQTFileEnd
  61.  *     Sometimes present. QT will recognize this as a RTSP reference file, if present.
  62.  * sgiApplicationName=MediaBaseURL
  63.  *     Beats me !! :)
  64.  * sgiElapsedTime=0
  65.  *     Time passed since the asset was started (resets for repeating non live assets?)
  66.  * sgiMulticastAddress=233.81.233.15
  67.  *     The multicast IP used for the Multicast feed.
  68.  *     Also defines if a stream is multicast or not. (blue dot in kasenna web interface)
  69.  * sgiMulticastPort=1234
  70.  *     The multicast port for the same Multicast feed.
  71.  * sgiPacketSize=16384
  72.  *     The packetsize of the UDP frames that Kasenna sends. They should have used a default
  73.  *     that is a multiple of 188 (TS frame size). Most networks don't support more than 1500 anyways.
  74.  *     Also, when you loose a frame of this size, imagecorruption is more likely then with smaller
  75.  *     frames.
  76.  * sgiServerVersion=6.1.2
  77.  *     Version of the server
  78.  * sgiRtspPort=554
  79.  *     TCP port used for RTSP communication
  80.  * AutoStart=True
  81.  *     Start playing automatically
  82.  * DeliveryService=cds
  83.  *     Simulcasted (scheduled unicast) content. (Green dot in Kasenna web interface) 
  84.  * sgiShowingName=A nice name that everyone likes
  85.  *     A human readible descriptive title for this stream.
  86.  * sgiSid=2311
  87.  *     Looks like this is the ID of the scheduled asset?
  88.  * sgiUserAccount=pid=1724&time=1078527309&displayText=You%20are%20logged%20as%20guest&
  89.  *     User Authentication. Above is a default guest entry. Not required for RTSP communication.
  90.  * sgiUserPassword=
  91.  *     Password :)
  92.  *
  93.  *****************************************************************************/
  94. /*****************************************************************************
  95.  * Preamble
  96.  *****************************************************************************/
  97. #include <stdlib.h>                                      /* malloc(), free() */
  98. #include <vlc/vlc.h>
  99. #include <vlc/input.h>
  100. #include <vlc_playlist.h>
  101. /*****************************************************************************
  102.  * Module descriptor
  103.  *****************************************************************************/
  104. static int  Activate  ( vlc_object_t * );
  105. static void Deactivate( vlc_object_t * );
  106. vlc_module_begin();
  107.     set_description( _("Kasenna MediaBase metademux") );
  108.     set_capability( "demux2", 170 );
  109.     set_callbacks( Activate, Deactivate );
  110.     add_shortcut( "sgimb" );
  111. vlc_module_end();
  112. /*****************************************************************************
  113.  * Local prototypes
  114.  *****************************************************************************/
  115. #define MAX_LINE 1024
  116. struct demux_sys_t
  117. {
  118.     char        *psz_uri;       /* Stream= or sgiQTFileBegin rtsp link */
  119.     char        *psz_server;    /* sgiNameServerHost= */
  120.     char        *psz_location;  /* sgiMovieName= */
  121.     char        *psz_name;      /* sgiShowingName= */
  122.     char        *psz_user;      /* sgiUserAccount= */
  123.     char        *psz_password;  /* sgiUserPassword= */
  124.     char        *psz_mcast_ip;  /* sgiMulticastAddress= */
  125.     int         i_mcast_port;   /* sgiMulticastPort= */
  126.     int         i_packet_size;  /* sgiPacketSize= */
  127.     mtime_t     i_duration;     /* sgiDuration= */
  128.     int         i_port;         /* sgiRtspPort= */
  129.     int         i_sid;          /* sgiSid= */
  130.     vlc_bool_t  b_concert;      /* DeliveryService=cds */
  131.     vlc_bool_t  b_rtsp_kasenna; /* kasenna style RTSP */
  132. };
  133. static int Demux ( demux_t *p_demux );
  134. static int Control( demux_t *p_demux, int i_query, va_list args );
  135. /*****************************************************************************
  136.  * Activate: initializes m3u demux structures
  137.  *****************************************************************************/
  138. static int Activate( vlc_object_t * p_this )
  139. {
  140.     demux_t *p_demux = (demux_t *)p_this;
  141.     demux_sys_t *p_sys;
  142.     byte_t *p_peek;
  143.     int i_size;
  144.     /* Lets check the content to see if this is a sgi mediabase file */
  145.     i_size = stream_Peek( p_demux->s, &p_peek, MAX_LINE );
  146.     i_size -= sizeof("sgiNameServerHost=") - 1;
  147.     if ( i_size > 0 )
  148.     {
  149.         while ( i_size && strncasecmp( p_peek, "sgiNameServerHost=",
  150.                                        sizeof("sgiNameServerHost=") - 1 ) )
  151.         {
  152.             p_peek++;
  153.             i_size--;
  154.         }
  155.         if ( !strncasecmp( p_peek, "sgiNameServerHost=",
  156.                            sizeof("sgiNameServerHost=") -1 ) )
  157.         {
  158.             p_demux->pf_demux = Demux;
  159.             p_demux->pf_control = Control;
  160.             p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
  161.             p_sys->psz_uri = NULL;
  162.             p_sys->psz_server = NULL;
  163.             p_sys->psz_location = NULL;
  164.             p_sys->psz_name = NULL;
  165.             p_sys->psz_user = NULL;
  166.             p_sys->psz_password = NULL;
  167.             p_sys->psz_mcast_ip = NULL;
  168.             p_sys->i_mcast_port = 0;
  169.             p_sys->i_packet_size = 0;
  170.             p_sys->i_duration = 0;
  171.             p_sys->i_port = 0;
  172.             p_sys->i_sid = 0;
  173.             p_sys->b_rtsp_kasenna = VLC_FALSE;
  174.             p_sys->b_concert = VLC_FALSE;
  175.             return VLC_SUCCESS;
  176.         }
  177.     }
  178.     return VLC_EGENERIC;
  179. }
  180. /*****************************************************************************
  181.  * Deactivate: frees unused data
  182.  *****************************************************************************/
  183. static void Deactivate( vlc_object_t *p_this )
  184. {
  185.     demux_t *p_demux = (demux_t*)p_this;
  186.     demux_sys_t *p_sys = p_demux->p_sys;
  187.     if( p_sys->psz_uri )
  188.         free( p_sys->psz_uri );
  189.     if( p_sys->psz_server )
  190.         free( p_sys->psz_server );
  191.     if( p_sys->psz_location )
  192.         free( p_sys->psz_location );
  193.     if( p_sys->psz_name )
  194.         free( p_sys->psz_name );
  195.     if( p_sys->psz_user )
  196.         free( p_sys->psz_user );
  197.     if( p_sys->psz_password )
  198.         free( p_sys->psz_password );
  199.     if( p_sys->psz_mcast_ip )
  200.         free( p_sys->psz_mcast_ip );
  201.     free( p_demux->p_sys );
  202.     return;
  203. }
  204. static int ParseLine ( demux_t *p_demux, char *psz_line )
  205. {
  206.     char        *psz_bol;
  207.     demux_sys_t *p_sys = p_demux->p_sys;
  208.     psz_bol = psz_line;
  209.     /* Remove unnecessary tabs or spaces at the beginning of line */
  210.     while( *psz_bol == ' ' || *psz_bol == 't' ||
  211.            *psz_bol == 'n' || *psz_bol == 'r' )
  212.     {
  213.         psz_bol++;
  214.     }
  215.     if( !strncasecmp( psz_bol, "rtsp://", sizeof("rtsp://") - 1 ) )
  216.     {
  217.         /* We found the link, it was inside a sgiQTFileBegin */
  218.         p_sys->psz_uri = strdup( psz_bol );
  219.     }
  220.     else if( !strncasecmp( psz_bol, "Stream="", sizeof("Stream="") - 1 ) )
  221.     {
  222.         psz_bol += sizeof("Stream="") - 1;
  223.         if ( !psz_bol )
  224.             return 0;
  225.         strrchr( psz_bol, '"' )[0] = '';
  226.         /* We cheat around xdma. for some reason xdma links work different then rtsp */
  227.         if( !strncasecmp( psz_bol, "xdma://", sizeof("xdma://") - 1 ) )
  228.         {
  229.             psz_bol[0] = 'r';
  230.             psz_bol[1] = 't';
  231.             psz_bol[2] = 's';
  232.             psz_bol[3] = 'p';
  233.         }
  234.         p_sys->psz_uri = strdup( psz_bol );
  235.     }
  236.     else if( !strncasecmp( psz_bol, "sgiNameServerHost=", sizeof("sgiNameServerHost=") - 1 ) )
  237.     {
  238.         psz_bol += sizeof("sgiNameServerHost=") - 1;
  239.         p_sys->psz_server = strdup( psz_bol );
  240.     }
  241.     else if( !strncasecmp( psz_bol, "sgiMovieName=", sizeof("sgiMovieName=") - 1 ) )
  242.     {
  243.         psz_bol += sizeof("sgiMovieName=") - 1;
  244.         p_sys->psz_location = strdup( psz_bol );
  245.     }
  246.     else if( !strncasecmp( psz_bol, "sgiUserAccount=", sizeof("sgiUserAccount=") - 1 ) )
  247.     {
  248.         psz_bol += sizeof("sgiUserAccount=") - 1;
  249.         p_sys->psz_user = strdup( psz_bol );
  250.     }
  251.     else if( !strncasecmp( psz_bol, "sgiUserPassword=", sizeof("sgiUserPassword=") - 1 ) )
  252.     {
  253.         psz_bol += sizeof("sgiUserPassword=") - 1;
  254.         p_sys->psz_password = strdup( psz_bol );
  255.     }
  256.     else if( !strncasecmp( psz_bol, "sgiShowingName=", sizeof("sgiShowingName=") - 1 ) )
  257.     {
  258.         psz_bol += sizeof("sgiShowingName=") - 1;
  259.         p_sys->psz_name = strdup( psz_bol );
  260.     }
  261.     else if( !strncasecmp( psz_bol, "sgiFormatName=", sizeof("sgiFormatName=") - 1 ) )
  262.     {
  263.         psz_bol += sizeof("sgiFormatName=") - 1;
  264.         if( !strcasestr( psz_bol, "MPEG-4") ) /*not mpeg4 */
  265.             p_sys->b_rtsp_kasenna = VLC_TRUE;
  266.     }
  267.     else if( !strncasecmp( psz_bol, "sgiMulticastAddress=", sizeof("sgiMulticastAddress=") - 1 ) )
  268.     {
  269.         psz_bol += sizeof("sgiMulticastAddress=") - 1;
  270.         p_sys->psz_mcast_ip = strdup( psz_bol );
  271.     }
  272.     else if( !strncasecmp( psz_bol, "sgiMulticastPort=", sizeof("sgiMulticastPort=") - 1 ) )
  273.     {
  274.         psz_bol += sizeof("sgiMulticastPort=") - 1;
  275.         p_sys->i_mcast_port = (int) strtol( psz_bol, NULL, 0 );
  276.     }
  277.     else if( !strncasecmp( psz_bol, "sgiPacketSize=", sizeof("sgiPacketSize=") - 1 ) )
  278.     {
  279.         psz_bol += sizeof("sgiPacketSize=") - 1;
  280.         p_sys->i_packet_size = (int) strtol( psz_bol, NULL, 0 );
  281.     }
  282.     else if( !strncasecmp( psz_bol, "sgiDuration=", sizeof("sgiDuration=") - 1 ) )
  283.     {
  284.         psz_bol += sizeof("sgiDuration=") - 1;
  285.         p_sys->i_duration = (mtime_t) strtol( psz_bol, NULL, 0 );
  286.     }
  287.     else if( !strncasecmp( psz_bol, "sgiRtspPort=", sizeof("sgiRtspPort=") - 1 ) )
  288.     {
  289.         psz_bol += sizeof("sgiRtspPort=") - 1;
  290.         p_sys->i_port = (int) strtol( psz_bol, NULL, 0 );
  291.     }
  292.     else if( !strncasecmp( psz_bol, "sgiSid=", sizeof("sgiSid=") - 1 ) )
  293.     {
  294.         psz_bol += sizeof("sgiSid=") - 1;
  295.         p_sys->i_sid = (int) strtol( psz_bol, NULL, 0 );
  296.     }
  297.     else if( !strncasecmp( psz_bol, "DeliveryService=cds", sizeof("DeliveryService=cds") - 1 ) )
  298.     {
  299.         p_sys->b_concert = VLC_TRUE;
  300.     }
  301.     else
  302.     {
  303.         /* This line isn't really important */
  304.         return 0;
  305.     }
  306.     return VLC_SUCCESS;
  307. }
  308. /*****************************************************************************
  309.  * Demux: reads and demuxes data packets
  310.  *****************************************************************************
  311.  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
  312.  *****************************************************************************/
  313. static int Demux ( demux_t *p_demux )
  314. {
  315.     demux_sys_t     *p_sys = p_demux->p_sys;
  316.     playlist_t      *p_playlist;
  317.     playlist_item_t *p_item;
  318.     
  319.     char            *psz_line;
  320.     int             i_position;
  321.     p_playlist = (playlist_t *) vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST,
  322.                                                  FIND_ANYWHERE );
  323.     if( !p_playlist )
  324.     {
  325.         msg_Err( p_demux, "can't find playlist" );
  326.         return -1;
  327.     }
  328.     p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
  329.     i_position = p_playlist->i_index + 1;
  330.     while( ( psz_line = stream_ReadLine( p_demux->s ) ) )
  331.     {
  332.         ParseLine( p_demux, psz_line );
  333.         if( psz_line ) free( psz_line );
  334.     }
  335.     if( p_sys->psz_mcast_ip )
  336.     {
  337.         /* Definetly schedules multicast session */
  338.         /* We don't care if it's live or not */
  339.         char *temp;
  340.         asprintf( &temp, "udp://@" "%s:%i", p_sys->psz_mcast_ip, p_sys->i_mcast_port );
  341.         if( p_sys->psz_uri ) free( p_sys->psz_uri );
  342.         p_sys->psz_uri = strdup( temp );
  343.         free( temp );
  344.     }
  345.     if( p_sys->psz_uri == NULL )
  346.     {
  347.         if( p_sys->psz_server && p_sys->psz_location )
  348.         {
  349.             char *temp;
  350.             
  351.             asprintf( &temp, "rtsp://" "%s:%i%s",
  352.                      p_sys->psz_server, p_sys->i_port > 0 ? p_sys->i_port : 554, p_sys->psz_location );
  353.             
  354.             p_sys->psz_uri = strdup( temp );
  355.             free( temp );
  356.         }
  357.     }
  358.     if( p_sys->b_concert )
  359.     {
  360.         /* It's definetly a simulcasted scheduled stream */
  361.         /* We don't care if it's live or not */
  362.         char *temp;
  363.         if( p_sys->psz_uri == NULL )
  364.         {
  365.             msg_Err( p_demux, "no URI was found" );
  366.             return -1;
  367.         }
  368.         
  369.         asprintf( &temp, "%s%%3FMeDiAbAsEshowingId=%d%%26MeDiAbAsEconcert%%3FMeDiAbAsE",
  370.                 p_sys->psz_uri, p_sys->i_sid );
  371.         free( p_sys->psz_uri );
  372.         p_sys->psz_uri = strdup( temp );
  373.         free( temp );
  374.     }
  375.     p_item = playlist_ItemNew( p_playlist, p_sys->psz_uri,
  376.                       p_sys->psz_name ? p_sys->psz_name : p_sys->psz_uri );
  377.     if( !p_item || !p_item->input.psz_uri )
  378.     {
  379.         msg_Err( p_demux, "A valid playlistitem could not be created" );
  380.         return VLC_EGENERIC;
  381.     }
  382.     if( p_sys->i_packet_size && p_sys->psz_mcast_ip )
  383.     {
  384.         char *psz_option;
  385.         p_sys->i_packet_size += 1000;
  386.         asprintf( &psz_option, "mtu=%i", p_sys->i_packet_size );
  387.         playlist_ItemAddOption( p_item, psz_option );
  388.         free( psz_option );
  389.     }
  390.     if( !p_sys->psz_mcast_ip )
  391.     {
  392.         char *psz_option;
  393. asprintf( &psz_option, "rtsp-caching=5000" );
  394. playlist_ItemAddOption( p_item, psz_option );
  395. free( psz_option );
  396.     }
  397.     if( !p_sys->psz_mcast_ip && p_sys->b_rtsp_kasenna )
  398.     {
  399.         char *psz_option;
  400.         asprintf( &psz_option, "rtsp-kasenna" );
  401.         playlist_ItemAddOption( p_item, psz_option );
  402.         free( psz_option );
  403.     }
  404.     playlist_ItemSetDuration( p_item, p_sys->i_duration );
  405.     playlist_AddItem( p_playlist, p_item, PLAYLIST_INSERT, i_position );
  406.     vlc_object_release( p_playlist );
  407.     return VLC_SUCCESS;
  408. }
  409. static int Control( demux_t *p_demux, int i_query, va_list args )
  410. {
  411.     return VLC_EGENERIC;
  412. }