📄 rtsp_rtp.c
字号:
/* * Copyright (C) 2006 Benjamin Zores * based on the Freebox patch for xine by Vincent Mussard * but with many enhancements for better RTSP RFC compliance. * * 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 */#include <unistd.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <stdlib.h>#include <sys/types.h>#include <inttypes.h>#include "config.h"#ifndef HAVE_WINSOCK2#include <netdb.h>#include <netinet/in.h>#include <sys/socket.h>#include <arpa/inet.h>#else#include <winsock2.h>#include <ws2tcpip.h>#endif#include "mp_msg.h"#include "rtsp.h"#include "rtsp_rtp.h"#include "rtsp_session.h"#include "../freesdp/common.h"#include "../freesdp/parser.h"#define RTSP_DEFAULT_PORT 31336#define MAX_LENGTH 256#define RTSP_ACCEPT_SDP "Accept: application/sdp"#define RTSP_CONTENT_LENGTH "Content-length"#define RTSP_CONTENT_TYPE "Content-Type"#define RTSP_APPLICATION_SDP "application/sdp"#define RTSP_RANGE "Range: "#define RTSP_NPT_NOW "npt=now-"#define RTSP_MEDIA_CONTAINER_MPEG_TS "33"#define RTSP_TRANSPORT_REQUEST "Transport: RTP/AVP;%s;%s%i-%i;mode=\"PLAY\"" #define RTSP_TRANSPORT_MULTICAST "multicast"#define RTSP_TRANSPORT_UNICAST "unicast"#define RTSP_MULTICAST_PORT "port="#define RTSP_UNICAST_CLIENT_PORT "client_port="#define RTSP_UNICAST_SERVER_PORT "server_port="#define RTSP_SETUP_DESTINATION "destination="#define RTSP_SESSION "Session"#define RTSP_TRANSPORT "Transport"/* hardcoded RTCP RR - this is _NOT_ RFC compliant */#define RTCP_RR_SIZE 32#define RTCP_RR "\201\311\0\7(.JD\31+\306\343\0\0\0\0\0\0/E\0\0\2&\0\0\0\0\0\0\0\0\201"#define RTCP_SEND_FREQUENCY 1024int rtsp_port = 0;char *rtsp_destination = NULL;voidrtcp_send_rr (rtsp_t *s, struct rtp_rtsp_session_t *st){ if (st->rtcp_socket == -1) return; /* send RTCP RR every RTCP_SEND_FREQUENCY packets * FIXME : NOT CORRECT, HARDCODED, BUT MAKES SOME SERVERS HAPPY * not rfc compliant * http://www.faqs.org/rfcs/rfc1889.html chapter 6 for RTCP */ if (st->count == RTCP_SEND_FREQUENCY) { char rtcp_content[RTCP_RR_SIZE]; strcpy (rtcp_content, RTCP_RR); send (st->rtcp_socket, rtcp_content, RTCP_RR_SIZE, 0); /* ping RTSP server to keep connection alive. we use OPTIONS instead of PING as not all servers support it */ rtsp_request_options (s, "*"); st->count = 0; } else st->count++;}static struct rtp_rtsp_session_t *rtp_session_new (void){ struct rtp_rtsp_session_t *st = NULL; st = malloc (sizeof (struct rtp_rtsp_session_t)); st->rtp_socket = -1; st->rtcp_socket = -1; st->control_url = NULL; st->count = 0; return st;}voidrtp_session_free (struct rtp_rtsp_session_t *st){ if (!st) return; if (st->rtp_socket != -1) close (st->rtp_socket); if (st->rtcp_socket != -1) close (st->rtcp_socket); if (st->control_url) free (st->control_url); free (st);}static voidrtp_session_set_fd (struct rtp_rtsp_session_t *st, int rtp_sock, int rtcp_sock){ if (!st) return; st->rtp_socket = rtp_sock; st->rtcp_socket = rtcp_sock;}static intparse_port (const char *line, const char *param, int *rtp_port, int *rtcp_port){ char *parse1; char *parse2; char *parse3; char *line_copy = strdup (line); parse1 = strstr (line_copy, param); if (parse1) { parse2 = strstr (parse1, "-"); if (parse2) { parse3 = strstr (parse2, ";"); if (parse3) parse3[0] = 0; parse2[0] = 0; } else { free (line_copy); return 0; } } else { free (line_copy); return 0; } *rtp_port = atoi (parse1 + strlen (param)); *rtcp_port = atoi (parse2 + 1); free (line_copy); return 1;}static char *parse_destination (const char *line){ char *parse1; char *parse2; char *dest = NULL; char *line_copy = strdup (line); int len; parse1 = strstr (line_copy, RTSP_SETUP_DESTINATION); if (!parse1) { free (line_copy); return NULL; } parse2 = strstr (parse1, ";"); if (!parse2) { free (line_copy); return NULL; } len = strlen (parse1) - strlen (parse2) - strlen (RTSP_SETUP_DESTINATION) + 1; dest = (char *) malloc (len + 1); snprintf (dest, len, parse1 + strlen (RTSP_SETUP_DESTINATION)); free (line_copy); return dest;}static intrtcp_connect (int client_port, int server_port, const char* server_hostname){ struct sockaddr_in sin; struct hostent *hp; int s; if (client_port <= 1023) return -1; s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) return -1; hp = gethostbyname (server_hostname); if (!hp) { close (s); return -1; } sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons (client_port); if (bind (s, (struct sockaddr *) &sin, sizeof (sin))) {#ifndef HAVE_WINSOCK2 if (errno != EINPROGRESS)#else if (WSAGetLastError() != WSAEINPROGRESS)#endif { close (s); return -1; } } sin.sin_family = AF_INET; memcpy (&(sin.sin_addr.s_addr), hp->h_addr, sizeof (hp->h_addr)); sin.sin_port = htons (server_port); /* datagram socket */ if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0) { close (s); return -1; } return s;}static intrtp_connect (char *hostname, int port){ struct sockaddr_in sin; struct timeval tv; int err, err_len; int rxsockbufsz; int s; fd_set set; if (port <= 1023) return -1; s = socket (PF_INET, SOCK_DGRAM, 0); if (s == -1) return -1; sin.sin_family = AF_INET; if (!hostname || !strcmp (hostname, "0.0.0.0")) sin.sin_addr.s_addr = htonl (INADDR_ANY); else#ifndef HAVE_WINSOCK2#ifdef USE_ATON inet_aton (hostname, &sin.sin_addr);#else inet_pton (AF_INET, hostname, &sin.sin_addr);#endif#else sin.sin_addr.s_addr = htonl (INADDR_ANY);#endif sin.sin_port = htons (port); /* Increase the socket rx buffer size to maximum -- this is UDP */ rxsockbufsz = 240 * 1024; if (setsockopt (s, SOL_SOCKET, SO_RCVBUF, &rxsockbufsz, sizeof (rxsockbufsz))) mp_msg (MSGT_OPEN, MSGL_ERR, "Couldn't set receive socket buffer size\n"); /* if multicast address, add membership */ if ((ntohl (sin.sin_addr.s_addr) >> 28) == 0xe) { struct ip_mreq mcast; mcast.imr_multiaddr.s_addr = sin.sin_addr.s_addr; mcast.imr_interface.s_addr = 0; if (setsockopt (s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast, sizeof (mcast))) { mp_msg (MSGT_OPEN, MSGL_ERR, "IP_ADD_MEMBERSHIP failed\n"); close (s); return -1; } } /* datagram socket */ if (bind (s, (struct sockaddr *) &sin, sizeof (sin))) {#ifndef HAVE_WINSOCK2 if (errno != EINPROGRESS)#else if (WSAGetLastError() != WSAEINPROGRESS)#endif { mp_msg (MSGT_OPEN, MSGL_ERR, "bind: %s\n", strerror (errno)); close (s); return -1; } } tv.tv_sec = 0; tv.tv_usec = (1 * 1000000); /* 1 second timeout */ FD_ZERO (&set); FD_SET (s, &set);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -