📄 rtsp.c
字号:
/***************************************************************************** * rtsp.c: rtsp VoD server module ***************************************************************************** * Copyright (C) 2003-2006 the VideoLAN team * $Id: rtsp.c 16987 2006-10-08 12:54:12Z jpsaman $ * * 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 *****************************************************************************/#include <stdlib.h>#include <errno.h>#include <vlc/vlc.h>#include <vlc/input.h>#include <vlc/sout.h>#include "vlc_httpd.h"#include "vlc_vod.h"#include "vlc_url.h"#include "network.h"#include "charset.h"/***************************************************************************** * Module descriptor *****************************************************************************/static int Open ( vlc_object_t * );static void Close( vlc_object_t * );#define HOST_TEXT N_( "RTSP host address" )/// \bug [String] extra space#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.\n To 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." )vlc_module_begin(); set_shortname( _("RTSP VoD" ) ); set_description( _("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, VLC_TRUE ); add_integer( "rtsp-throttle-users", 0, NULL, THROTLE_TEXT, THROTLE_LONGTEXT, VLC_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 */ vlc_bool_t b_playing; /* is it in "play" state */ vlc_bool_t 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{ /* 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; vlc_bool_t b_multicast; vlc_mutex_t lock; /* ES list */ int i_es; media_es_t **es; char *psz_mux; vlc_bool_t 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; /* List of media */ int i_media; vod_media_t **media;};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 rtsp_client_t *RtspClientNew( vod_media_t *, char * );static rtsp_client_t *RtspClientGet( vod_media_t *, char * );static void RtspClientDel( vod_media_t *, rtsp_client_t * );static int RtspCallback( httpd_callback_sys_t *, httpd_client_t *, httpd_message_t *, httpd_message_t * );static int RtspCallbackES( httpd_callback_sys_t *, httpd_client_t *, httpd_message_t *, 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 ); if( psz_url ) 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; var_Create( p_this, "rtsp-throttle-users", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); p_sys->i_throttle_users = var_GetInteger( p_this, "rtsp-throtle-users" ); msg_Dbg( p_this, "allowing up to %d connections", p_sys->i_throttle_users ); p_sys->i_connections = 0; 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 ); p_sys->media = NULL; p_sys->i_media = 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; return VLC_SUCCESS;error: if( p_sys && p_sys->p_rtsp_host ) httpd_HostDelete( p_sys->p_rtsp_host ); if( p_sys ) 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; httpd_HostDelete( p_sys->p_rtsp_host ); var_Destroy( p_this, "rtsp-throttle-users" ); /* TODO delete medias */ free( p_sys->psz_path ); 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 ) { msg_Err( p_vod, "not enough memory" ); return NULL; } memset( p_media, 0, sizeof(vod_media_t) ); p_media->es = 0; p_media->psz_mux = 0; p_media->rtsp = 0; p_media->b_raw = VLC_FALSE; asprintf( &p_media->psz_rtsp_path, "%s%s", p_sys->psz_path, psz_name ); 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 ); 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 ); 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 ); httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_SETUP, RtspCallback, (void*)p_media ); httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_DESCRIBE, RtspCallback, (void*)p_media ); httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_PLAY, RtspCallback, (void*)p_media ); httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_PAUSE, RtspCallback, (void*)p_media ); httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_TEARDOWN, RtspCallback, (void*)p_media ); p_media->p_vod = p_vod; TAB_APPEND( p_sys->i_media, p_sys->media, p_media ); vlc_mutex_init( p_vod, &p_media->lock ); p_media->psz_session_name = strdup(""); p_media->psz_session_description = strdup(""); p_media->psz_session_url = strdup(""); p_media->psz_session_email = strdup(""); p_media->i_port_audio = 1234; p_media->i_port_video = 1236; p_media->i_port = 1238; p_media->i_payload_type = 96; p_media->i_sdp_id = mdate(); p_media->i_sdp_version = 1; p_media->i_length = p_item->i_duration; vlc_mutex_lock( &p_item->lock ); msg_Dbg( p_vod, "media has %i declared ES", p_item->i_es ); for( i = 0; i < p_item->i_es; i++ ) { MediaAddES( p_vod, p_media, p_item->es[i] ); } vlc_mutex_unlock( &p_item->lock ); return p_media;}static void MediaDel( vod_t *p_vod, vod_media_t *p_media ){ vod_sys_t *p_sys = p_vod->p_sys; msg_Dbg( p_vod, "deleting media: %s", p_media->psz_rtsp_path ); while( p_media->i_rtsp > 0 ) RtspClientDel( p_media, p_media->rtsp[0] ); httpd_UrlDelete( p_media->p_rtsp_url ); if( p_media->psz_rtsp_path ) free( p_media->psz_rtsp_path ); if( p_media->psz_rtsp_control_v6 ) free( p_media->psz_rtsp_control_v6 ); if( p_media->psz_rtsp_control_v4 ) free( p_media->psz_rtsp_control_v4 ); TAB_REMOVE( p_sys->i_media, p_sys->media, p_media ); while( p_media->i_es ) MediaDelES( p_vod, p_media, &p_media->es[0]->fmt ); vlc_mutex_destroy( &p_media->lock ); free( p_media->psz_session_name ); free( p_media->psz_session_description ); free( p_media->psz_session_url ); free( p_media->psz_session_email ); free( p_media );}static int MediaAddES( vod_t *p_vod, vod_media_t *p_media, es_format_t *p_fmt ){ media_es_t *p_es = malloc( sizeof(media_es_t) ); char *psz_urlc; memset( p_es, 0, sizeof(media_es_t) ); p_media->psz_mux = NULL; /* TODO: update SDP, etc... */ asprintf( &psz_urlc, "%s/trackID=%d", p_media->psz_rtsp_path, p_media->i_es ); msg_Dbg( p_vod, " - ES %4.4s (%s)", (char *)&p_fmt->i_codec, psz_urlc ); switch( p_fmt->i_codec ) { case VLC_FOURCC( 's', '1', '6', 'b' ): if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 44100 ) { p_es->i_payload_type = 11; } else if( p_fmt->audio.i_channels == 2 && p_fmt->audio.i_rate == 44100 ) { p_es->i_payload_type = 10; } else { p_es->i_payload_type = p_media->i_payload_type++; } p_es->psz_rtpmap = malloc( strlen( "L16/*/*" ) + 20+1 ); sprintf( p_es->psz_rtpmap, "L16/%d/%d", p_fmt->audio.i_rate, p_fmt->audio.i_channels ); break; case VLC_FOURCC( 'u', '8', ' ', ' ' ): p_es->i_payload_type = p_media->i_payload_type++; p_es->psz_rtpmap = malloc( strlen( "L8/*/*" ) + 20+1 ); sprintf( p_es->psz_rtpmap, "L8/%d/%d", p_fmt->audio.i_rate, p_fmt->audio.i_channels ); break; case VLC_FOURCC( 'm', 'p', 'g', 'a' ): p_es->i_payload_type = 14; p_es->psz_rtpmap = strdup( "MPA/90000" ); break; case VLC_FOURCC( 'm', 'p', 'g', 'v' ): p_es->i_payload_type = 32;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -