📄 rtsp.c
字号:
/***************************************************************************** * rtsp.c: rtsp VoD server module ***************************************************************************** * Copyright (C) 2003-2006 the VideoLAN team * $Id: 561e110cae0a647b6a087abcd47642e3bfef78f6 $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * Gildas Bazin <gbazin@videolan.org> * * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_input.h>#include <vlc_sout.h>#include <vlc_block.h>#include "vlc_httpd.h"#include "vlc_vod.h"#include "vlc_url.h"#include <vlc_network.h>#include <vlc_charset.h>#include <vlc_strings.h>#include <errno.h>#ifndef WIN32# include <locale.h>#endif#ifdef HAVE_XLOCALE_H# include <xlocale.h>#endif/***************************************************************************** * Module descriptor *****************************************************************************/static int Open ( vlc_object_t * );static void Close( vlc_object_t * );#define HOST_TEXT N_( "RTSP host address" )#define HOST_LONGTEXT N_( \ "This defines the address, port and path the RTSP VOD server will listen " \ "on.\nSyntax is address:port/path. The default is to listen on all "\ "interfaces (address 0.0.0.0), on port 554, with no path.\nTo listen " \ "only on the local interface, use \"localhost\" as address." )#define THROTLE_TEXT N_( "Maximum number of connections" )#define THROTLE_LONGTEXT N_( "This limits the maximum number of clients " \ "that can connect to the RTSP VOD. 0 means no limit." )#define RAWMUX_TEXT N_( "MUX for RAW RTSP transport" )#define SESSION_TIMEOUT_TEXT N_( "Sets the timeout option in the RTSP " \ "session string" )#define SESSION_TIMEOUT_LONGTEXT N_( "Defines what timeout option to add " \ "to the RTSP session ID string. Setting it to a negative number removes " \ "the timeout option entirely. This is needed by some IPTV STBs (such as " \ "those made by HansunTech) which get confused by it. The default is 5." )vlc_module_begin(); set_shortname( N_("RTSP VoD" ) ); set_description( N_("RTSP VoD server") ); set_category( CAT_SOUT ); set_subcategory( SUBCAT_SOUT_VOD ); set_capability( "vod server", 1 ); set_callbacks( Open, Close ); add_shortcut( "rtsp" ); add_string ( "rtsp-host", NULL, NULL, HOST_TEXT, HOST_LONGTEXT, true ); add_string( "rtsp-raw-mux", "ts", NULL, RAWMUX_TEXT, RAWMUX_TEXT, true ); add_integer( "rtsp-throttle-users", 0, NULL, THROTLE_TEXT, THROTLE_LONGTEXT, true ); add_integer( "rtsp-session-timeout", 5, NULL, SESSION_TIMEOUT_TEXT, SESSION_TIMEOUT_LONGTEXT, true );vlc_module_end();/***************************************************************************** * Exported prototypes *****************************************************************************/typedef struct media_es_t media_es_t;typedef struct{ media_es_t *p_media_es; char *psz_ip; int i_port;} rtsp_client_es_t;typedef struct{ char *psz_session; int64_t i_last; /* for timeout */ bool b_playing; /* is it in "play" state */ bool b_paused; /* is it in "pause" state */ int i_es; rtsp_client_es_t **es;} rtsp_client_t;struct media_es_t{ /* VoD server */ vod_t *p_vod; /* RTSP server */ httpd_url_t *p_rtsp_url; vod_media_t *p_media; es_format_t fmt; int i_port; uint8_t i_payload_type; char *psz_rtpmap; char *psz_fmtp;};struct vod_media_t{ int id; /* VoD server */ vod_t *p_vod; /* RTSP server */ httpd_url_t *p_rtsp_url; char *psz_rtsp_control_v4; char *psz_rtsp_control_v6; char *psz_rtsp_path; int i_port; int i_port_audio; int i_port_video; int i_ttl; int i_payload_type; int64_t i_sdp_id; int i_sdp_version; bool b_multicast; vlc_mutex_t lock; /* ES list */ int i_es; media_es_t **es; char *psz_mux; bool b_raw; /* RTSP client */ int i_rtsp; rtsp_client_t **rtsp; /* Infos */ char *psz_session_name; char *psz_session_description; char *psz_session_url; char *psz_session_email; mtime_t i_length;};struct vod_sys_t{ /* RTSP server */ httpd_host_t *p_rtsp_host; char *psz_path; int i_port; int i_throttle_users; int i_connections; char *psz_raw_mux; int i_session_timeout; /* List of media */ vlc_mutex_t lock_media; int i_media_id; int i_media; vod_media_t **media; /* */ block_fifo_t *p_fifo_cmd;};/* rtsp delayed command (to avoid deadlock between vlm/httpd) */typedef enum{ RTSP_CMD_TYPE_NONE, /* Exit requested */ RTSP_CMD_TYPE_PLAY, RTSP_CMD_TYPE_PAUSE, RTSP_CMD_TYPE_STOP, RTSP_CMD_TYPE_SEEK, RTSP_CMD_TYPE_REWIND, RTSP_CMD_TYPE_FORWARD,} rtsp_cmd_type_t;static vod_media_t *MediaNew( vod_t *, const char *, input_item_t * );static void MediaDel( vod_t *, vod_media_t * );static int MediaAddES( vod_t *, vod_media_t *, es_format_t * );static void MediaDelES( vod_t *, vod_media_t *, es_format_t * );static void* CommandThread( vlc_object_t *p_this );static void CommandPush( vod_t *, rtsp_cmd_type_t, vod_media_t *, const char *psz_session, double f_arg, const char *psz_arg );static rtsp_client_t *RtspClientNew( vod_media_t *, char * );static rtsp_client_t *RtspClientGet( vod_media_t *, const char * );static void RtspClientDel( vod_media_t *, rtsp_client_t * );static int RtspCallback( httpd_callback_sys_t *, httpd_client_t *, httpd_message_t *, const httpd_message_t * );static int RtspCallbackES( httpd_callback_sys_t *, httpd_client_t *, httpd_message_t *, const httpd_message_t * );static char *SDPGenerate( const vod_media_t *, httpd_client_t *cl );static void sprintf_hexa( char *s, uint8_t *p_data, int i_data ){ static const char hex[16] = "0123456789abcdef"; int i; for( i = 0; i < i_data; i++ ) { s[2*i+0] = hex[(p_data[i]>>4)&0xf]; s[2*i+1] = hex[(p_data[i] )&0xf]; } s[2*i_data] = '\0';}/***************************************************************************** * Open: Starts the RTSP server module *****************************************************************************/static int Open( vlc_object_t *p_this ){ vod_t *p_vod = (vod_t *)p_this; vod_sys_t *p_sys = 0; char *psz_url = 0; vlc_url_t url; psz_url = config_GetPsz( p_vod, "rtsp-host" ); vlc_UrlParse( &url, psz_url, 0 ); free( psz_url ); if( url.i_port <= 0 ) url.i_port = 554; p_vod->p_sys = p_sys = malloc( sizeof( vod_sys_t ) ); if( !p_sys ) goto error; p_sys->p_rtsp_host = 0; p_sys->i_session_timeout = var_CreateGetInteger( p_this, "rtsp-session-timeout" ); p_sys->i_throttle_users = var_CreateGetInteger( p_this, "rtsp-throttle-users" ); msg_Dbg( p_this, "allowing up to %d connections", p_sys->i_throttle_users ); p_sys->i_connections = 0; p_sys->psz_raw_mux = var_CreateGetString( p_this, "rtsp-raw-mux" ); p_sys->p_rtsp_host = httpd_HostNew( VLC_OBJECT(p_vod), url.psz_host, url.i_port ); if( !p_sys->p_rtsp_host ) { msg_Err( p_vod, "cannot create RTSP server (%s:%i)", url.psz_host, url.i_port ); goto error; } p_sys->psz_path = strdup( url.psz_path ? url.psz_path : "/" ); p_sys->i_port = url.i_port; vlc_UrlClean( &url ); vlc_mutex_init( &p_sys->lock_media ); TAB_INIT( p_sys->i_media, p_sys->media ); p_sys->i_media_id = 0; p_vod->pf_media_new = MediaNew; p_vod->pf_media_del = MediaDel; p_vod->pf_media_add_es = MediaAddES; p_vod->pf_media_del_es = MediaDelES; p_sys->p_fifo_cmd = block_FifoNew(); if( vlc_thread_create( p_vod, "rtsp vod thread", CommandThread, VLC_THREAD_PRIORITY_LOW, false ) ) { msg_Err( p_vod, "cannot spawn rtsp vod thread" ); block_FifoRelease( p_sys->p_fifo_cmd ); free( p_sys->psz_path ); goto error; } return VLC_SUCCESS;error: if( p_sys ) { if( p_sys->p_rtsp_host ) httpd_HostDelete( p_sys->p_rtsp_host ); free( p_sys->psz_raw_mux ); free( p_sys ); } vlc_UrlClean( &url ); return VLC_EGENERIC;}/***************************************************************************** * Close: *****************************************************************************/static void Close( vlc_object_t * p_this ){ vod_t *p_vod = (vod_t *)p_this; vod_sys_t *p_sys = p_vod->p_sys; /* Stop command thread */ vlc_object_kill( p_vod ); CommandPush( p_vod, RTSP_CMD_TYPE_NONE, NULL, NULL, 0.0, NULL ); vlc_thread_join( p_vod ); block_FifoRelease( p_sys->p_fifo_cmd ); httpd_HostDelete( p_sys->p_rtsp_host ); var_Destroy( p_this, "rtsp-session-timeout" ); var_Destroy( p_this, "rtsp-throttle-users" ); var_Destroy( p_this, "rtsp-raw-mux" ); /* Check VLM is not buggy */ if( p_sys->i_media > 0 ) msg_Err( p_vod, "rtsp vod leaking %d medias", p_sys->i_media ); TAB_CLEAN( p_sys->i_media, p_sys->media ); vlc_mutex_destroy( &p_sys->lock_media ); free( p_sys->psz_path ); free( p_sys->psz_raw_mux ); free( p_sys );}/***************************************************************************** * Media handling *****************************************************************************/static vod_media_t *MediaNew( vod_t *p_vod, const char *psz_name, input_item_t *p_item ){ vod_sys_t *p_sys = p_vod->p_sys; vod_media_t *p_media = malloc( sizeof(vod_media_t) ); int i; if( !p_media ) return NULL; memset( p_media, 0, sizeof(vod_media_t) ); p_media->id = p_sys->i_media_id++; TAB_INIT( p_media->i_es, p_media->es ); p_media->psz_mux = 0; TAB_INIT( p_media->i_rtsp, p_media->rtsp ); p_media->b_raw = false; if( asprintf( &p_media->psz_rtsp_path, "%s%s", p_sys->psz_path, psz_name ) <0 ) return NULL; p_media->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, p_media->psz_rtsp_path, NULL, NULL, NULL ); if( !p_media->p_rtsp_url ) { msg_Err( p_vod, "cannot create RTSP url (%s)", p_media->psz_rtsp_path); free( p_media->psz_rtsp_path ); free( p_media ); return NULL; } msg_Dbg( p_vod, "created RTSP url: %s", p_media->psz_rtsp_path ); if( asprintf( &p_media->psz_rtsp_control_v4, "a=control:rtsp://%%s:%d%s/trackID=%%d\r\n", p_sys->i_port, p_media->psz_rtsp_path ) < 0 ) { httpd_UrlDelete( p_media->p_rtsp_url ); free( p_media->psz_rtsp_path ); free( p_media ); return NULL; } if( asprintf( &p_media->psz_rtsp_control_v6, "a=control:rtsp://[%%s]:%d%s/trackID=%%d\r\n", p_sys->i_port, p_media->psz_rtsp_path ) < 0 ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -