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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * udp.c
  3.  *****************************************************************************
  4.  * Copyright (C) 2001, 2002 VideoLAN
  5.  * $Id: udp.c 8769 2004-09-22 15:25:11Z gbazin $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *          Eric Petit <titer@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <string.h>
  31. #include <errno.h>
  32. #include <fcntl.h>
  33. #include <vlc/vlc.h>
  34. #include <vlc/sout.h>
  35. #ifdef HAVE_UNISTD_H
  36. #   include <unistd.h>
  37. #endif
  38. #ifdef WIN32
  39. #   include <winsock2.h>
  40. #   include <ws2tcpip.h>
  41. #   ifndef IN_MULTICAST
  42. #       define IN_MULTICAST(a) IN_CLASSD(a)
  43. #   endif
  44. #else
  45. #   include <sys/socket.h>
  46. #endif
  47. #include "network.h"
  48. /*****************************************************************************
  49.  * Module descriptor
  50.  *****************************************************************************/
  51. static int  Open ( vlc_object_t * );
  52. static void Close( vlc_object_t * );
  53. #define SOUT_CFG_PREFIX "sout-udp-"
  54. #define CACHING_TEXT N_("Caching value (ms)")
  55. #define CACHING_LONGTEXT N_( 
  56.     "Allows you to modify the default caching value for UDP streams. This " 
  57.     "value should be set in millisecond units." )
  58. #define TTL_TEXT N_("Time To Live")
  59. #define TTL_LONGTEXT N_("Allows you to define the time to live of the " 
  60.                         "outgoing stream.")
  61. #define GROUP_TEXT N_("Group packets")
  62. #define GROUP_LONGTEXT N_("Packets can be sent one by one at the right time " 
  63.                           "or by groups. This allows you to give the number " 
  64.                           "of packets that will be sent at a time. It " 
  65.                           "helps reducing the scheduling load on " 
  66.                           "heavily-loaded systems." )
  67. #define LATE_TEXT N_("Late delay (ms)" )
  68. #define LATE_LONGTEXT N_("Late packets are dropped. This allows you to give " 
  69.                        "the time (in milliseconds) a packet is allowed to be" 
  70.                        " late.")
  71. #define RAW_TEXT N_("Raw write")
  72. #define RAW_LONGTEXT N_("If you enable this option, packets will be sent " 
  73.                        "directly, without trying to fill the MTU (ie, " 
  74.                        "without trying to make the biggest possible packets " 
  75.                        "in order to improve streaming)." )
  76. vlc_module_begin();
  77.     set_description( _("UDP stream output") );
  78.     add_integer( SOUT_CFG_PREFIX "caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
  79.     add_integer( SOUT_CFG_PREFIX "ttl", 0, NULL,TTL_TEXT, TTL_LONGTEXT,
  80.                                  VLC_TRUE );
  81.     add_integer( SOUT_CFG_PREFIX "group", 1, NULL, GROUP_TEXT, GROUP_LONGTEXT,
  82.                                  VLC_TRUE );
  83.     add_integer( SOUT_CFG_PREFIX "late", 0, NULL, LATE_TEXT, LATE_LONGTEXT,
  84.                                  VLC_TRUE );
  85.     add_bool( SOUT_CFG_PREFIX "raw",  0, NULL, RAW_TEXT, RAW_LONGTEXT,
  86.                                  VLC_TRUE );
  87.     set_capability( "sout access", 100 );
  88.     add_shortcut( "udp" );
  89.     add_shortcut( "rtp" ); // Will work only with ts muxer
  90.     set_callbacks( Open, Close );
  91. vlc_module_end();
  92. /*****************************************************************************
  93.  * Exported prototypes
  94.  *****************************************************************************/
  95. static const char *ppsz_sout_options[] = {
  96.     "caching",
  97.     "ttl",
  98.     "group",
  99.     "late",
  100.     "raw",
  101.     NULL
  102. };
  103. static int  Write   ( sout_access_out_t *, block_t * );
  104. static int  WriteRaw( sout_access_out_t *, block_t * );
  105. static int  Seek    ( sout_access_out_t *, off_t  );
  106. static void ThreadWrite( vlc_object_t * );
  107. static block_t *NewUDPPacket( sout_access_out_t *, mtime_t );
  108. typedef struct sout_access_thread_t
  109. {
  110.     VLC_COMMON_MEMBERS
  111.     sout_instance_t *p_sout;
  112.     block_fifo_t *p_fifo;
  113.     int         i_handle;
  114.     int64_t     i_caching;
  115.     int64_t     i_late;
  116.     int         i_group;
  117. } sout_access_thread_t;
  118. struct sout_access_out_sys_t
  119. {
  120.     int                 b_rtpts;  // 1 if add rtp/ts header
  121.     uint16_t            i_sequence_number;
  122.     uint32_t            i_ssrc;
  123.     int                 i_mtu;
  124.     block_t             *p_buffer;
  125.     sout_access_thread_t *p_thread;
  126.     vlc_bool_t          b_mtu_warning;
  127. };
  128. #define DEFAULT_PORT 1234
  129. /*****************************************************************************
  130.  * Open: open the file
  131.  *****************************************************************************/
  132. static int Open( vlc_object_t *p_this )
  133. {
  134.     sout_access_out_t       *p_access = (sout_access_out_t*)p_this;
  135.     sout_access_out_sys_t   *p_sys;
  136.     char                *psz_parser;
  137.     char                *psz_dst_addr;
  138.     int                 i_dst_port;
  139.     module_t            *p_network;
  140.     network_socket_t    socket_desc;
  141.     vlc_value_t         val;
  142.     sout_CfgParse( p_access, SOUT_CFG_PREFIX,
  143.                    ppsz_sout_options, p_access->p_cfg );
  144.     if( !( p_sys = malloc( sizeof( sout_access_out_sys_t ) ) ) )
  145.     {
  146.         msg_Err( p_access, "not enough memory" );
  147.         return VLC_EGENERIC;
  148.     }
  149.     memset( p_sys, 0, sizeof(sout_access_out_sys_t) );
  150.     p_access->p_sys = p_sys;
  151.     if( p_access->psz_access != NULL &&
  152.         !strcmp( p_access->psz_access, "rtp" ) )
  153.     {
  154.         msg_Warn( p_access, "be careful that rtp output only works with ts "
  155.                   "payload (not an error)" );
  156.         p_sys->b_rtpts = 1;
  157.     }
  158.     else
  159.     {
  160.         p_sys->b_rtpts = 0;
  161.     }
  162.     psz_parser = strdup( p_access->psz_name );
  163.     psz_dst_addr = psz_parser;
  164.     i_dst_port = 0;
  165.     if ( *psz_parser == '[' )
  166.     {
  167.         while( *psz_parser && *psz_parser != ']' )
  168.         {
  169.             psz_parser++;
  170.         }
  171.     }
  172.     while( *psz_parser && *psz_parser != ':' )
  173.     {
  174.         psz_parser++;
  175.     }
  176.     if( *psz_parser == ':' )
  177.     {
  178.         *psz_parser = '';
  179.         psz_parser++;
  180.         i_dst_port = atoi( psz_parser );
  181.     }
  182.     if( i_dst_port <= 0 )
  183.     {
  184.         i_dst_port = DEFAULT_PORT;
  185.     }
  186.     p_sys->p_thread =
  187.         vlc_object_create( p_access, sizeof( sout_access_thread_t ) );
  188.     if( !p_sys->p_thread )
  189.     {
  190.         msg_Err( p_access, "out of memory" );
  191.         return VLC_EGENERIC;
  192.     }
  193.     p_sys->p_thread->p_sout = p_access->p_sout;
  194.     p_sys->p_thread->b_die  = 0;
  195.     p_sys->p_thread->b_error= 0;
  196.     p_sys->p_thread->p_fifo = block_FifoNew( p_access );
  197.     socket_desc.i_type = NETWORK_UDP;
  198.     socket_desc.psz_server_addr = psz_dst_addr;
  199.     socket_desc.i_server_port   = i_dst_port;
  200.     socket_desc.psz_bind_addr   = "";
  201.     socket_desc.i_bind_port     = 0;
  202.     var_Get( p_access, SOUT_CFG_PREFIX "ttl", &val );
  203.     socket_desc.i_ttl = val.i_int;
  204.     p_sys->p_thread->p_private = (void*)&socket_desc;
  205.     if( !( p_network = module_Need( p_sys->p_thread, "network", NULL, 0 ) ) )
  206.     {
  207.         msg_Err( p_access, "failed to open a connection (udp)" );
  208.         return VLC_EGENERIC;
  209.     }
  210.     module_Unneed( p_sys->p_thread, p_network );
  211.     p_sys->p_thread->i_handle = socket_desc.i_handle;
  212.     var_Get( p_access, SOUT_CFG_PREFIX "caching", &val );
  213.     p_sys->p_thread->i_caching = (int64_t)val.i_int * 1000;
  214.     var_Get( p_access, SOUT_CFG_PREFIX "group", &val );
  215.     p_sys->p_thread->i_group = val.i_int;
  216.     var_Get( p_access, SOUT_CFG_PREFIX "late", &val );
  217.     p_sys->p_thread->i_late = (int64_t)val.i_int * 1000;
  218.     p_sys->i_mtu = socket_desc.i_mtu;
  219. #ifdef WIN32
  220.     if( vlc_thread_create( p_sys->p_thread, "sout write thread", ThreadWrite,
  221.                            VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
  222. #else
  223.     if( vlc_thread_create( p_sys->p_thread, "sout write thread", ThreadWrite,
  224.                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
  225. #endif
  226.     {
  227.         msg_Err( p_access->p_sout, "cannot spawn sout access thread" );
  228.         vlc_object_destroy( p_sys->p_thread );
  229.         return VLC_EGENERIC;
  230.     }
  231.     srand( (uint32_t)mdate());
  232.     p_sys->p_buffer          = NULL;
  233.     p_sys->i_sequence_number = rand()&0xffff;
  234.     p_sys->i_ssrc            = rand()&0xffffffff;
  235.     var_Get( p_access, SOUT_CFG_PREFIX "raw", &val );
  236.     if( val.b_bool )  p_access->pf_write = WriteRaw;
  237.     else p_access->pf_write = Write;
  238.     p_access->pf_seek = Seek;
  239.     msg_Dbg( p_access, "udp access output opened(%s:%d)",
  240.              psz_dst_addr, i_dst_port );
  241.     free( psz_dst_addr );
  242.     /* update p_sout->i_out_pace_nocontrol */
  243.     p_access->p_sout->i_out_pace_nocontrol++;
  244.     return VLC_SUCCESS;
  245. }
  246. /*****************************************************************************
  247.  * Close: close the target
  248.  *****************************************************************************/
  249. static void Close( vlc_object_t * p_this )
  250. {
  251.     sout_access_out_t     *p_access = (sout_access_out_t*)p_this;
  252.     sout_access_out_sys_t *p_sys = p_access->p_sys;
  253.     int i;
  254.     p_sys->p_thread->b_die = 1;
  255.     for( i = 0; i < 10; i++ )
  256.     {
  257.         block_t *p_dummy = block_New( p_access, p_sys->i_mtu );
  258.         p_dummy->i_dts = 0;
  259.         p_dummy->i_pts = 0;
  260.         p_dummy->i_length = 0;
  261.         block_FifoPut( p_sys->p_thread->p_fifo, p_dummy );
  262.     }
  263.     vlc_thread_join( p_sys->p_thread );
  264.     block_FifoRelease( p_sys->p_thread->p_fifo );
  265.     if( p_sys->p_buffer ) block_Release( p_sys->p_buffer );
  266.     net_Close( p_sys->p_thread->i_handle );
  267.     /* update p_sout->i_out_pace_nocontrol */
  268.     p_access->p_sout->i_out_pace_nocontrol--;
  269.     msg_Dbg( p_access, "udp access output closed" );
  270.     free( p_sys );
  271. }
  272. /*****************************************************************************
  273.  * Write: standard write on a file descriptor.
  274.  *****************************************************************************/
  275. static int Write( sout_access_out_t *p_access, block_t *p_buffer )
  276. {
  277.     sout_access_out_sys_t *p_sys = p_access->p_sys;
  278.     while( p_buffer )
  279.     {
  280.         block_t *p_next;
  281.         int i_packets = 0;
  282.         if( !p_sys->b_mtu_warning && p_buffer->i_buffer > p_sys->i_mtu )
  283.         {
  284.             msg_Warn( p_access, "packet size > MTU, you should probably "
  285.                       "increase the MTU" );
  286.             p_sys->b_mtu_warning = VLC_TRUE;
  287.         }
  288.         /* Check if there is enough space in the buffer */
  289.         if( p_sys->p_buffer &&
  290.             p_sys->p_buffer->i_buffer + p_buffer->i_buffer > p_sys->i_mtu )
  291.         {
  292.             block_FifoPut( p_sys->p_thread->p_fifo, p_sys->p_buffer );
  293.             p_sys->p_buffer = NULL;
  294.         }
  295.         while( p_buffer->i_buffer )
  296.         {
  297.             int i_write = __MIN( p_buffer->i_buffer, p_sys->i_mtu );
  298.             i_packets++;
  299.             if( !p_sys->p_buffer )
  300.             {
  301.                 p_sys->p_buffer = NewUDPPacket( p_access, p_buffer->i_dts );
  302.                 if( !p_sys->p_buffer ) break;
  303.             }
  304.             memcpy( p_sys->p_buffer->p_buffer + p_sys->p_buffer->i_buffer,
  305.                     p_buffer->p_buffer, i_write );
  306.             p_sys->p_buffer->i_buffer += i_write;
  307.             p_buffer->p_buffer += i_write;
  308.             p_buffer->i_buffer -= i_write;
  309.             if( p_sys->p_buffer->i_buffer == p_sys->i_mtu || i_packets > 1 )
  310.             {
  311.                 /* Flush */
  312.                 block_FifoPut( p_sys->p_thread->p_fifo, p_sys->p_buffer );
  313.                 p_sys->p_buffer = NULL;
  314.             }
  315.         }
  316.         p_next = p_buffer->p_next;
  317.         block_Release( p_buffer );
  318.         p_buffer = p_next;
  319.     }
  320.     return( p_sys->p_thread->b_error ? -1 : 0 );
  321. }
  322. /*****************************************************************************
  323.  * WriteRaw: write p_buffer without trying to fill mtu
  324.  *****************************************************************************/
  325. static int WriteRaw( sout_access_out_t *p_access, block_t *p_buffer )
  326. {
  327.     sout_access_out_sys_t   *p_sys = p_access->p_sys;
  328.     block_FifoPut( p_sys->p_thread->p_fifo, p_buffer );
  329.     return( p_sys->p_thread->b_error ? -1 : 0 );
  330. }
  331. /*****************************************************************************
  332.  * Seek: seek to a specific location in a file
  333.  *****************************************************************************/
  334. static int Seek( sout_access_out_t *p_access, off_t i_pos )
  335. {
  336.     msg_Err( p_access, "UDP sout access cannot seek" );
  337.     return -1;
  338. }
  339. /*****************************************************************************
  340.  * NewUDPPacket: allocate a new UDP packet of size p_sys->i_mtu
  341.  *****************************************************************************/
  342. static block_t *NewUDPPacket( sout_access_out_t *p_access, mtime_t i_dts)
  343. {
  344.     sout_access_out_sys_t *p_sys = p_access->p_sys;
  345.     block_t *p_buffer;
  346.     p_buffer = block_New( p_access->p_sout, p_sys->i_mtu );
  347.     p_buffer->i_dts = i_dts;
  348.     p_buffer->i_buffer = 0;
  349.     if( p_sys->b_rtpts )
  350.     {
  351.         mtime_t i_timestamp = p_buffer->i_dts * 9 / 100;
  352.         /* add rtp/ts header */
  353.         p_buffer->p_buffer[0] = 0x80;
  354.         p_buffer->p_buffer[1] = 0x21; // mpeg2-ts
  355.         p_buffer->p_buffer[2] = ( p_sys->i_sequence_number >> 8 )&0xff;
  356.         p_buffer->p_buffer[3] = p_sys->i_sequence_number&0xff;
  357.         p_sys->i_sequence_number++;
  358.         p_buffer->p_buffer[4] = ( i_timestamp >> 24 )&0xff;
  359.         p_buffer->p_buffer[5] = ( i_timestamp >> 16 )&0xff;
  360.         p_buffer->p_buffer[6] = ( i_timestamp >>  8 )&0xff;
  361.         p_buffer->p_buffer[7] = i_timestamp&0xff;
  362.         p_buffer->p_buffer[ 8] = ( p_sys->i_ssrc >> 24 )&0xff;
  363.         p_buffer->p_buffer[ 9] = ( p_sys->i_ssrc >> 16 )&0xff;
  364.         p_buffer->p_buffer[10] = ( p_sys->i_ssrc >>  8 )&0xff;
  365.         p_buffer->p_buffer[11] = p_sys->i_ssrc&0xff;
  366.         p_buffer->i_buffer = 12;
  367.     }
  368.     return p_buffer;
  369. }
  370. /*****************************************************************************
  371.  * ThreadWrite: Write a packet on the network at the good time.
  372.  *****************************************************************************/
  373. static void ThreadWrite( vlc_object_t *p_this )
  374. {
  375.     sout_access_thread_t *p_thread = (sout_access_thread_t*)p_this;
  376.     mtime_t              i_date_last = -1;
  377.     mtime_t              i_to_send = p_thread->i_group;
  378.     int                  i_dropped_packets = 0;
  379.     while( !p_thread->b_die )
  380.     {
  381.         block_t *p_pk;
  382.         mtime_t       i_date, i_sent;
  383.         p_pk = block_FifoGet( p_thread->p_fifo );
  384.         i_date = p_thread->i_caching + p_pk->i_dts;
  385.         if( i_date_last > 0 )
  386.         {
  387.             if( i_date - i_date_last > 2000000 )
  388.             {
  389.                 if( !i_dropped_packets )
  390.                     msg_Dbg( p_thread, "mmh, hole ("I64Fd" > 2s) -> drop",
  391.                              i_date - i_date_last );
  392.                 block_Release( p_pk  );
  393.                 i_date_last = i_date;
  394.                 i_dropped_packets++;
  395.                 continue;
  396.             }
  397.             else if( i_date - i_date_last < 0 )
  398.             {
  399.                 if( !i_dropped_packets )
  400.                     msg_Dbg( p_thread, "mmh, packets in the past ("I64Fd")"
  401.                              " -> drop", i_date - i_date_last );
  402.                 block_Release( p_pk  );
  403.                 i_date_last = i_date;
  404.                 i_dropped_packets++;
  405.                 continue;
  406.             }
  407.         }
  408.         i_sent = mdate();
  409.         if( p_thread->i_late > 0 && i_sent > i_date + p_thread->i_late )
  410.         {
  411.             if( !i_dropped_packets )
  412.             {
  413.                 msg_Dbg( p_thread, "late packet to send (" I64Fd ") -> drop",
  414.                          i_sent - i_date );
  415.             }
  416.             block_Release( p_pk  );
  417.             i_date_last = i_date;
  418.             i_dropped_packets++;
  419.             continue;
  420.         }
  421.         i_to_send--;
  422.         if ( !i_to_send )
  423.         {
  424.             mwait( i_date );
  425.             i_to_send = p_thread->i_group;
  426.         }
  427.         send( p_thread->i_handle, p_pk->p_buffer, p_pk->i_buffer, 0 );
  428.         if( i_dropped_packets )
  429.         {
  430.             msg_Dbg( p_thread, "dropped %i packets", i_dropped_packets );
  431.             i_dropped_packets = 0;
  432.         }
  433. #if 0
  434.         i_sent = mdate();
  435.         if ( i_sent > i_date + 20000 )
  436.         {
  437.             msg_Dbg( p_thread, "packet has been sent too late (" I64Fd ")",
  438.                      i_sent - i_date );
  439.         }
  440. #endif
  441.         block_Release( p_pk  );
  442.         i_date_last = i_date;
  443.     }
  444. }