📄 rtsp.c
字号:
} else { answer->i_status = 500; answer->p_body = NULL; answer->i_body = 0; } break; } case HTTPD_MSG_PAUSE: psz_session = httpd_MsgGet( query, "Session" ); msg_Dbg( p_vod, "HTTPD_MSG_PAUSE for session: %s", psz_session ); p_rtsp = RtspClientGet( p_media, psz_session ); if( !p_rtsp ) break; CommandPush( p_vod, RTSP_CMD_TYPE_PAUSE, p_media, psz_session, 0, NULL ); p_rtsp->b_paused = true; answer->i_status = 200; answer->i_body = 0; answer->p_body = NULL; break; case HTTPD_MSG_TEARDOWN: /* for now only multicast so easy again */ answer->i_status = 200; answer->i_body = 0; answer->p_body = NULL; psz_session = httpd_MsgGet( query, "Session" ); msg_Dbg( p_vod, "HTTPD_MSG_TEARDOWN for session: %s", psz_session); p_rtsp = RtspClientGet( p_media, psz_session ); if( !p_rtsp ) break; CommandPush( p_vod, RTSP_CMD_TYPE_STOP, p_media, psz_session, 0, NULL ); RtspClientDel( p_media, p_rtsp ); break; case HTTPD_MSG_GETPARAMETER: answer->i_status = 200; answer->i_body = 0; answer->p_body = NULL; break; default: return VLC_EGENERIC; } httpd_MsgAdd( answer, "Server", "VLC Server" ); httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); psz_cseq = httpd_MsgGet( query, "Cseq" ); psz_cseq ? i_cseq = atoi( psz_cseq ) : 0; httpd_MsgAdd( answer, "CSeq", "%d", i_cseq ); httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" ); if( psz_session ) { if( p_media->p_vod->p_sys->i_session_timeout >= 0 ) httpd_MsgAdd( answer, "Session", "%s;timeout=%i", psz_session, p_media->p_vod->p_sys->i_session_timeout ); else httpd_MsgAdd( answer, "Session", "%s", psz_session ); } return VLC_SUCCESS;}static int RtspCallbackES( httpd_callback_sys_t *p_args, httpd_client_t *cl, httpd_message_t *answer, const httpd_message_t *query ){ media_es_t *p_es = (media_es_t*)p_args; vod_media_t *p_media = p_es->p_media; vod_t *p_vod = p_media->p_vod; rtsp_client_t *p_rtsp = NULL; const char *psz_transport = NULL; const char *psz_playnow = NULL; /* support option: x-playNow */ const char *psz_session = NULL; const char *psz_position = NULL; const char *psz_cseq = NULL; int i_cseq = 0; int i; if( answer == NULL || query == NULL ) return VLC_SUCCESS; msg_Dbg( p_vod, "RtspCallback query: type=%d", query->i_type ); answer->i_proto = HTTPD_PROTO_RTSP; answer->i_version = query->i_version; answer->i_type = HTTPD_MSG_ANSWER; answer->i_body = 0; answer->p_body = NULL; switch( query->i_type ) { case HTTPD_MSG_SETUP: psz_playnow = httpd_MsgGet( query, "x-playNow" ); psz_transport = httpd_MsgGet( query, "Transport" ); msg_Dbg( p_vod, "HTTPD_MSG_SETUP: transport=%s", psz_transport ); if( strstr( psz_transport, "unicast" ) && strstr( psz_transport, "client_port=" ) ) { rtsp_client_t *p_rtsp = NULL; rtsp_client_es_t *p_rtsp_es = NULL; char ip[NI_MAXNUMERICHOST]; int i_port = atoi( strstr( psz_transport, "client_port=" ) + strlen("client_port=") ); if( httpd_ClientIP( cl, ip ) == NULL ) { answer->i_status = 500; answer->i_body = 0; answer->p_body = NULL; break; } msg_Dbg( p_vod, "HTTPD_MSG_SETUP: unicast ip=%s port=%d", ip, i_port ); psz_session = httpd_MsgGet( query, "Session" ); if( !psz_session || !*psz_session ) { char *psz_new; if( ( p_vod->p_sys->i_throttle_users > 0 ) && ( p_vod->p_sys->i_connections >= p_vod->p_sys->i_throttle_users ) ) { answer->i_status = 503; answer->i_body = 0; answer->p_body = NULL; break; } if( asprintf( &psz_new, "%d", rand() ) < 0 ) return VLC_ENOMEM; psz_session = psz_new; p_rtsp = RtspClientNew( p_media, psz_new ); } else { p_rtsp = RtspClientGet( p_media, psz_session ); if( !p_rtsp ) { answer->i_status = 454; answer->i_body = 0; answer->p_body = NULL; break; } } p_rtsp_es = malloc( sizeof(rtsp_client_es_t) ); if( !p_rtsp_es ) { answer->i_status = 500; answer->i_body = 0; answer->p_body = NULL; break; } p_rtsp_es->i_port = i_port; p_rtsp_es->psz_ip = strdup( ip ); p_rtsp_es->p_media_es = p_es; TAB_APPEND( p_rtsp->i_es, p_rtsp->es, p_rtsp_es ); answer->i_status = 200; answer->i_body = 0; answer->p_body = NULL; if( p_media->b_raw ) { if( strstr( psz_transport, "MP2T/H2221/UDP" ) ) { httpd_MsgAdd( answer, "Transport", "MP2T/H2221/UDP;client_port=%d-%d", p_rtsp_es->i_port, p_rtsp_es->i_port + 1 ); } else if( strstr( psz_transport, "RAW/RAW/UDP" ) ) { httpd_MsgAdd( answer, "Transport", "RAW/RAW/UDP;client_port=%d-%d", p_rtsp_es->i_port, p_rtsp_es->i_port + 1 ); } } else { httpd_MsgAdd( answer, "Transport", "RTP/AVP/UDP;client_port=%d-%d", p_rtsp_es->i_port, p_rtsp_es->i_port + 1 ); } } else /* TODO strstr( psz_transport, "interleaved" ) ) */ { answer->i_status = 461; answer->i_body = 0; answer->p_body = NULL; } /* Intentional fall-through on x-playNow option in RTSP request */ if( !psz_playnow ) break; case HTTPD_MSG_PLAY: /* This is kind of a kludge. Should we only support Aggregate * Operations ? */ psz_session = httpd_MsgGet( query, "Session" ); msg_Dbg( p_vod, "HTTPD_MSG_PLAY for session: %s", psz_session ); p_rtsp = RtspClientGet( p_media, psz_session ); psz_position = httpd_MsgGet( query, "Range" ); if( psz_position ) psz_position = strstr( psz_position, "npt=" ); if( psz_position ) { double f_pos = ParseNPT (psz_position + 4); msg_Dbg( p_vod, "seeking request: %s", psz_position ); f_pos /= ((double)(p_media->i_length))/1000 /1000 / 100; CommandPush( p_vod, RTSP_CMD_TYPE_SEEK, p_media, psz_session, f_pos, NULL ); } if( !psz_playnow ) { answer->i_status = 200; answer->i_body = 0; answer->p_body = NULL; } break; case HTTPD_MSG_TEARDOWN: answer->i_status = 200; answer->i_body = 0; answer->p_body = NULL; psz_session = httpd_MsgGet( query, "Session" ); msg_Dbg( p_vod, "HTTPD_MSG_TEARDOWN for session: %s", psz_session); p_rtsp = RtspClientGet( p_media, psz_session ); if( !p_rtsp ) break; for( i = 0; i < p_rtsp->i_es; i++ ) { if( p_rtsp->es[i]->p_media_es == p_es ) { free( p_rtsp->es[i]->psz_ip ); TAB_REMOVE( p_rtsp->i_es, p_rtsp->es, p_rtsp->es[i] ); break; } } if( !p_rtsp->i_es ) { CommandPush( p_vod, RTSP_CMD_TYPE_STOP, p_media, psz_session, 0, NULL ); RtspClientDel( p_media, p_rtsp ); } break; case HTTPD_MSG_PAUSE: /* This is kind of a kludge. Should we only support Aggregate * Operations ? */ psz_session = httpd_MsgGet( query, "Session" ); msg_Dbg( p_vod, "HTTPD_MSG_PAUSE for session: %s", psz_session ); p_rtsp = RtspClientGet( p_media, psz_session ); if( !p_rtsp ) break; CommandPush( p_vod, RTSP_CMD_TYPE_PAUSE, p_media, psz_session, 0, NULL ); p_rtsp->b_paused = true; answer->i_status = 200; answer->i_body = 0; answer->p_body = NULL; break; default: return VLC_EGENERIC; break; } httpd_MsgAdd( answer, "Server", "VLC Server" ); httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); psz_cseq = httpd_MsgGet( query, "Cseq" ); if (psz_cseq) i_cseq = atoi( psz_cseq ); else i_cseq = 0; httpd_MsgAdd( answer, "Cseq", "%d", i_cseq ); httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" ); if( psz_session ) httpd_MsgAdd( answer, "Session", "%s"/*;timeout=5*/, psz_session ); return VLC_SUCCESS;}/***************************************************************************** * SDPGenerate: TODO * FIXME: need to be moved to a common place ? *****************************************************************************/static char *SDPGenerate( const vod_media_t *p_media, httpd_client_t *cl ){ int i, i_size; char *p, *psz_sdp, ip[NI_MAXNUMERICHOST], ipv; const char *psz_control; if( httpd_ServerIP( cl, ip ) == NULL ) return NULL; p = strchr( ip, '%' ); if( p != NULL ) *p = '\0'; /* remove scope if present */ ipv = ( strchr( ip, ':' ) != NULL ) ? '6' : '4'; /* Calculate size */ i_size = sizeof( "v=0\r\n" ) + sizeof( "o=- * * IN IP4 \r\n" ) + 10 + NI_MAXNUMERICHOST + sizeof( "s=*\r\n" ) + strlen( p_media->psz_session_name ) + sizeof( "i=*\r\n" ) + strlen( p_media->psz_session_description ) + sizeof( "u=*\r\n" ) + strlen( p_media->psz_session_url ) + sizeof( "e=*\r\n" ) + strlen( p_media->psz_session_email ) + sizeof( "c=IN IP4 0.0.0.0\r\n" ) + 20 + 10 + sizeof( "t=0 0\r\n" ) + /* FIXME */ sizeof( "a=tool:"PACKAGE_STRING"\r\n" ) + sizeof( "a=range:npt=0-1000000000.000\r\n" ); psz_control = (ipv == '6') ? p_media->psz_rtsp_control_v6 : p_media->psz_rtsp_control_v4; for( i = 0; i < p_media->i_es; i++ ) { media_es_t *p_es = p_media->es[i]; i_size += sizeof( "m=**d*o * RTP/AVP *\r\n" ) + 19; if( p_es->psz_rtpmap ) { i_size += sizeof( "a=rtpmap:* *\r\n" ) + strlen( p_es->psz_rtpmap ) + 9; } if( p_es->psz_fmtp ) { i_size += sizeof( "a=fmtp:* *\r\n" ) + strlen( p_es->psz_fmtp ) + 9; } } i_size += (strlen( psz_control ) + strlen( ip ) + 9) * p_media->i_es; p = psz_sdp = malloc( i_size ); p += sprintf( p, "v=0\r\n" ); p += sprintf( p, "o=- %"PRId64" %d IN IP%c %s\r\n", p_media->i_sdp_id, p_media->i_sdp_version, ipv, ip ); if( *p_media->psz_session_name ) p += sprintf( p, "s=%s\r\n", p_media->psz_session_name ); if( *p_media->psz_session_description ) p += sprintf( p, "i=%s\r\n", p_media->psz_session_description ); if( *p_media->psz_session_url ) p += sprintf( p, "u=%s\r\n", p_media->psz_session_url ); if( *p_media->psz_session_email ) p += sprintf( p, "e=%s\r\n", p_media->psz_session_email ); p += sprintf( p, "c=IN IP%c %s\r\n", ipv, ipv == '6' ? "::" : "0.0.0.0" ); p += sprintf( p, "t=0 0\r\n" ); /* FIXME */ p += sprintf( p, "a=tool:"PACKAGE_STRING"\r\n" ); if( p_media->i_length > 0 ) { lldiv_t d = lldiv( p_media->i_length / 1000, 1000 ); p += sprintf( p, "a=range:npt=0-%lld.%03u\r\n", d.quot, (unsigned)d.rem ); } for( i = 0; i < p_media->i_es; i++ ) { media_es_t *p_es = p_media->es[i]; if( p_es->fmt.i_cat == AUDIO_ES ) { p += sprintf( p, "m=audio %d RTP/AVP %d\r\n", p_es->i_port, p_es->i_payload_type ); } else if( p_es->fmt.i_cat == VIDEO_ES ) { p += sprintf( p, "m=video %d RTP/AVP %d\r\n", p_es->i_port, p_es->i_payload_type ); } else { continue; } if( p_es->psz_rtpmap ) { p += sprintf( p, "a=rtpmap:%d %s\r\n", p_es->i_payload_type, p_es->psz_rtpmap ); } if( p_es->psz_fmtp ) { p += sprintf( p, "a=fmtp:%d %s\r\n", p_es->i_payload_type, p_es->psz_fmtp ); } p += sprintf( p, psz_control, ip, i ); } return psz_sdp;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -