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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * udp.c: raw UDP & RTP input module
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2004 VideoLAN
  5.  * $Id: udp.c 8606 2004-08-31 18:32:54Z hartman $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *          Tristan Leteurtre <tooney@via.ecp.fr>
  9.  *          Laurent Aimar <fenrir@via.ecp.fr>
  10.  *
  11.  * Reviewed: 23 October 2003, Jean-Paul Saman <jpsaman@wxs.nl>
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or
  16.  * (at your option) any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  26.  *****************************************************************************/
  27. /*****************************************************************************
  28.  * Preamble
  29.  *****************************************************************************/
  30. #include <stdlib.h>
  31. #include <vlc/vlc.h>
  32. #include <vlc/input.h>
  33. #include "network.h"
  34. /*****************************************************************************
  35.  * Module descriptor
  36.  *****************************************************************************/
  37. #define CACHING_TEXT N_("Caching value in ms")
  38. #define CACHING_LONGTEXT N_( 
  39.     "Allows you to modify the default caching value for UDP streams. This " 
  40.     "value should be set in millisecond units." )
  41. #define AUTO_MTU_TEXT N_("Autodetection of MTU")
  42. #define AUTO_MTU_LONGTEXT N_( 
  43.     "Allows growing the MTU if truncated packets are found" )
  44. static int  Open ( vlc_object_t * );
  45. static void Close( vlc_object_t * );
  46. vlc_module_begin();
  47.     set_description( _("UDP/RTP input") );
  48.     add_integer( "udp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
  49.                  CACHING_LONGTEXT, VLC_TRUE );
  50.     add_bool( "udp-auto-mtu", 1, NULL,
  51.               AUTO_MTU_TEXT, AUTO_MTU_LONGTEXT, VLC_TRUE );
  52.     set_capability( "access2", 0 );
  53.     add_shortcut( "udp" );
  54.     add_shortcut( "udpstream" );
  55.     add_shortcut( "udp4" );
  56.     add_shortcut( "udp6" );
  57.     add_shortcut( "rtp" );
  58.     add_shortcut( "rtp4" );
  59.     add_shortcut( "rtp6" );
  60.     set_callbacks( Open, Close );
  61. vlc_module_end();
  62. /*****************************************************************************
  63.  * Local prototypes
  64.  *****************************************************************************/
  65. #define RTP_HEADER_LEN 12
  66. static block_t *BlockUDP( access_t * );
  67. static block_t *BlockRTP( access_t * );
  68. static block_t *BlockChoose( access_t * );
  69. static int Control( access_t *, int, va_list );
  70. struct access_sys_t
  71. {
  72.     int fd;
  73.     int i_mtu;
  74.     vlc_bool_t b_auto_mtu;
  75. };
  76. /*****************************************************************************
  77.  * Open: open the socket
  78.  *****************************************************************************/
  79. static int Open( vlc_object_t *p_this )
  80. {
  81.     access_t     *p_access = (access_t*)p_this;
  82.     access_sys_t *p_sys;
  83.     char *psz_name = strdup( p_access->psz_path );
  84.     char *psz_parser = psz_name;
  85.     char *psz_server_addr = "";
  86.     char *psz_server_port = "";
  87.     char *psz_bind_addr = "";
  88.     char *psz_bind_port = "";
  89.     int  i_bind_port = 0;
  90.     int  i_server_port = 0;
  91.     /* First set ipv4/ipv6 */
  92.     var_Create( p_access, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  93.     var_Create( p_access, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  94.     if( *p_access->psz_access )
  95.     {
  96.         vlc_value_t val;
  97.         /* Find out which shortcut was used */
  98.         if( !strncmp( p_access->psz_access, "udp4", 6 ) ||
  99.             !strncmp( p_access->psz_access, "rtp4", 6 ))
  100.         {
  101.             val.b_bool = VLC_TRUE;
  102.             var_Set( p_access, "ipv4", val );
  103.             val.b_bool = VLC_FALSE;
  104.             var_Set( p_access, "ipv6", val );
  105.         }
  106.         else if( !strncmp( p_access->psz_access, "udp6", 6 ) ||
  107.                  !strncmp( p_access->psz_access, "rtp6", 6 ) )
  108.         {
  109.             val.b_bool = VLC_TRUE;
  110.             var_Set( p_access, "ipv6", val );
  111.             val.b_bool = VLC_FALSE;
  112.             var_Set( p_access, "ipv4", val );
  113.         }
  114.     }
  115.     /* Parse psz_name syntax :
  116.      * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
  117.     if( *psz_parser && *psz_parser != '@' )
  118.     {
  119.         /* Found server */
  120.         psz_server_addr = psz_parser;
  121.         while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' )
  122.         {
  123.             if( *psz_parser == '[' )
  124.             {
  125.                 /* IPv6 address */
  126.                 while( *psz_parser && *psz_parser != ']' )
  127.                 {
  128.                     psz_parser++;
  129.                 }
  130.             }
  131.             psz_parser++;
  132.         }
  133.         if( *psz_parser == ':' )
  134.         {
  135.             /* Found server port */
  136.             *psz_parser++ = ''; /* Terminate server name */
  137.             psz_server_port = psz_parser;
  138.             while( *psz_parser && *psz_parser != '@' )
  139.             {
  140.                 psz_parser++;
  141.             }
  142.         }
  143.     }
  144.     if( *psz_parser == '@' )
  145.     {
  146.         /* Found bind address or bind port */
  147.         *psz_parser++ = ''; /* Terminate server port or name if necessary */
  148.         if( *psz_parser && *psz_parser != ':' )
  149.         {
  150.             /* Found bind address */
  151.             psz_bind_addr = psz_parser;
  152.             while( *psz_parser && *psz_parser != ':' )
  153.             {
  154.                 if( *psz_parser == '[' )
  155.                 {
  156.                     /* IPv6 address */
  157.                     while( *psz_parser && *psz_parser != ']' )
  158.                     {
  159.                         psz_parser++;
  160.                     }
  161.                 }
  162.                 psz_parser++;
  163.             }
  164.         }
  165.         if( *psz_parser == ':' )
  166.         {
  167.             /* Found bind port */
  168.             *psz_parser++ = ''; /* Terminate bind address if necessary */
  169.             psz_bind_port = psz_parser;
  170.         }
  171.     }
  172.     i_server_port = strtol( psz_server_port, NULL, 10 );
  173.     if( ( i_bind_port   = strtol( psz_bind_port,   NULL, 10 ) ) == 0 )
  174.     {
  175.         i_bind_port = var_CreateGetInteger( p_access, "server-port" );
  176.     }
  177.     msg_Dbg( p_access, "opening server=%s:%d local=%s:%d",
  178.              psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
  179.     /* Set up p_access */
  180.     p_access->pf_read = NULL;
  181.     p_access->pf_block = BlockChoose;
  182.     p_access->pf_control = Control;
  183.     p_access->pf_seek = NULL;
  184.     p_access->info.i_update = 0;
  185.     p_access->info.i_size = 0;
  186.     p_access->info.i_pos = 0;
  187.     p_access->info.b_eof = VLC_FALSE;
  188.     p_access->info.i_title = 0;
  189.     p_access->info.i_seekpoint = 0;
  190.     p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
  191.     p_sys->fd = net_OpenUDP( p_access, psz_bind_addr, i_bind_port,
  192.                                       psz_server_addr, i_server_port );
  193.     if( p_sys->fd < 0 )
  194.     {
  195.         msg_Err( p_access, "cannot open socket" );
  196.         free( psz_name );
  197.         free( p_sys );
  198.         return VLC_EGENERIC;
  199.     }
  200.     free( psz_name );
  201.     /* FIXME */
  202.     p_sys->i_mtu = var_CreateGetInteger( p_access, "mtu" );
  203.     if( p_sys->i_mtu <= 1 )
  204.         p_sys->i_mtu  = 1500;   /* Avoid problem */
  205.     p_sys->b_auto_mtu = var_CreateGetBool( p_access, "udp-auto-mtu" );;
  206.     /* Update default_pts to a suitable value for udp access */
  207.     var_Create( p_access, "udp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  208.     return VLC_SUCCESS;
  209. }
  210. /*****************************************************************************
  211.  * Close: free unused data structures
  212.  *****************************************************************************/
  213. static void Close( vlc_object_t *p_this )
  214. {
  215.     access_t     *p_access = (access_t*)p_this;
  216.     access_sys_t *p_sys = p_access->p_sys;
  217.     net_Close( p_sys->fd );
  218.     free( p_sys );
  219. }
  220. /*****************************************************************************
  221.  * Control:
  222.  *****************************************************************************/
  223. static int Control( access_t *p_access, int i_query, va_list args )
  224. {
  225.     access_sys_t *p_sys = p_access->p_sys;
  226.     vlc_bool_t   *pb_bool;
  227.     int          *pi_int;
  228.     int64_t      *pi_64;
  229.     switch( i_query )
  230.     {
  231.         /* */
  232.         case ACCESS_CAN_SEEK:
  233.         case ACCESS_CAN_FASTSEEK:
  234.         case ACCESS_CAN_PAUSE:
  235.         case ACCESS_CAN_CONTROL_PACE:
  236.             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
  237.             *pb_bool = VLC_FALSE;
  238.             break;
  239.         /* */
  240.         case ACCESS_GET_MTU:
  241.             pi_int = (int*)va_arg( args, int * );
  242.             *pi_int = p_sys->i_mtu;
  243.             break;
  244.         case ACCESS_GET_PTS_DELAY:
  245.             pi_64 = (int64_t*)va_arg( args, int64_t * );
  246.             *pi_64 = var_GetInteger( p_access, "udp-caching" ) * 1000;
  247.             break;
  248.         /* */
  249.         case ACCESS_SET_PAUSE_STATE:
  250.         case ACCESS_GET_TITLE_INFO:
  251.         case ACCESS_SET_TITLE:
  252.         case ACCESS_SET_SEEKPOINT:
  253.         case ACCESS_SET_PRIVATE_ID_STATE:
  254.             return VLC_EGENERIC;
  255.         default:
  256.             msg_Warn( p_access, "unimplemented query in control" );
  257.             return VLC_EGENERIC;
  258.     }
  259.     return VLC_SUCCESS;
  260. }
  261. /*****************************************************************************
  262.  * BlockUDP:
  263.  *****************************************************************************/
  264. static block_t *BlockUDP( access_t *p_access )
  265. {
  266.     access_sys_t *p_sys = p_access->p_sys;
  267.     block_t      *p_block;
  268.     /* Read data */
  269.     p_block = block_New( p_access, p_sys->i_mtu );
  270.     p_block->i_buffer = net_Read( p_access, p_sys->fd, p_block->p_buffer, p_sys->i_mtu, VLC_FALSE );
  271.     if( p_block->i_buffer <= 0 )
  272.     {
  273.         block_Release( p_block );
  274.         return NULL;
  275.     }
  276.     if( p_block->i_buffer >= p_sys->i_mtu && p_sys->b_auto_mtu &&
  277.         p_sys->i_mtu < 32767 )
  278.     {
  279.         /* Increase by 100% */
  280.         p_sys->i_mtu *= 2;
  281.         msg_Dbg( p_access, "increasing MTU to %d", p_sys->i_mtu );
  282.     }
  283.     return p_block;
  284. }
  285. /*****************************************************************************
  286.  * BlockParseRTP/BlockRTP:
  287.  *****************************************************************************/
  288. static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
  289. {
  290.     int     i_rtp_version;
  291.     int     i_CSRC_count;
  292.     int     i_payload_type;
  293.     int     i_skip = 0;
  294.     if( p_block->i_buffer < RTP_HEADER_LEN )
  295.         goto trash;
  296.     /* Parse the header and make some verifications.
  297.      * See RFC 1889 & RFC 2250. */
  298.     i_rtp_version  = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
  299.     i_CSRC_count   = ( p_block->p_buffer[0] & 0x0F );
  300.     i_payload_type = ( p_block->p_buffer[1] & 0x7F );
  301.     if ( i_rtp_version != 2 )
  302.         msg_Dbg( p_access, "RTP version is %u, should be 2", i_rtp_version );
  303.     if( i_payload_type == 14 )
  304.         i_skip = 4;
  305.     else if( i_payload_type !=  33 && i_payload_type != 32 )
  306.         msg_Dbg( p_access, "unsupported RTP payload type (%u)", i_payload_type );
  307.     i_skip += RTP_HEADER_LEN + 4*i_CSRC_count;
  308.     /* A CSRC extension field is 32 bits in size (4 bytes) */
  309.     if( i_skip >= p_block->i_buffer )
  310.         goto trash;
  311.     /* Return the packet without the RTP header. */
  312.     p_block->i_buffer -= i_skip;
  313.     p_block->p_buffer += i_skip;
  314.     return p_block;
  315. trash:
  316.     msg_Warn( p_access, "received a too short packet for RTP" );
  317.     block_Release( p_block );
  318.     return NULL;
  319. }
  320. static block_t *BlockRTP( access_t *p_access )
  321. {
  322.     return BlockParseRTP( p_access, BlockUDP( p_access ) );
  323. }
  324. /*****************************************************************************
  325.  * BlockChoose: decide between RTP and UDP
  326.  *****************************************************************************/
  327. static block_t *BlockChoose( access_t *p_access )
  328. {
  329.     block_t *p_block;
  330.     int     i_rtp_version;
  331.     int     i_CSRC_count;
  332.     int     i_payload_type;
  333.     if( ( p_block = BlockUDP( p_access ) ) == NULL )
  334.         return NULL;
  335.     if( p_block->p_buffer[0] == 0x47 )
  336.     {
  337.         msg_Dbg( p_access, "detected TS over raw UDP" );
  338.         p_access->pf_block = BlockUDP;
  339.         return p_block;
  340.     }
  341.     if( p_block->i_buffer < RTP_HEADER_LEN )
  342.         return p_block;
  343.     /* Parse the header and make some verifications.
  344.      * See RFC 1889 & RFC 2250. */
  345.     i_rtp_version  = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
  346.     i_CSRC_count   = ( p_block->p_buffer[0] & 0x0F );
  347.     i_payload_type = ( p_block->p_buffer[1] & 0x7F );
  348.     if( i_rtp_version != 2 )
  349.     {
  350.         msg_Dbg( p_access, "no supported RTP header detected" );
  351.         p_access->pf_block = BlockUDP;
  352.         return p_block;
  353.     }
  354.     switch( i_payload_type )
  355.     {
  356.         case 33:
  357.             msg_Dbg( p_access, "detected TS over RTP" );
  358.             p_access->psz_demux = strdup( "ts" );
  359.             break;
  360.         case 14:
  361.             msg_Dbg( p_access, "detected MPEG audio over RTP" );
  362.             p_access->psz_demux = strdup( "mp3" );
  363.             break;
  364.         case 32:
  365.             msg_Dbg( p_access, "detected MPEG video over RTP" );
  366.             p_access->psz_demux = strdup( "es" );
  367.             break;
  368.         default:
  369.             msg_Dbg( p_access, "no RTP header detected" );
  370.             p_access->pf_block = BlockUDP;
  371.             return p_block;
  372.     }
  373.     p_access->pf_block = BlockRTP;
  374.     return BlockParseRTP( p_access, p_block );
  375. }