⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtspclient.cpp

📁 H.264 RTSP 串流(live 555)視窗版本
💻 CPP
📖 第 1 页 / 共 5 页
字号:
  char* userAgentName = new char[userAgentNameSize];  sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, libVersionStr, libSuffix);  setUserAgentString(userAgentName);  delete[] userAgentName;}RTSPClient::~RTSPClient() {  reset();  delete[] fResponseBuffer;  delete[] fUserAgentHeaderStr;}Boolean RTSPClient::isRTSPClient() const {  return True;}void RTSPClient::reset() {  resetTCPSockets();  resetResponseBuffer();  fServerAddress = 0;  setBaseURL(NULL);  fCurrentAuthenticator.reset();  delete[] fLastSessionId; fLastSessionId = NULL;}void RTSPClient::resetTCPSockets() {  if (fInputSocketNum >= 0) {    envir().taskScheduler().disableBackgroundHandling(fInputSocketNum);    ::closeSocket(fInputSocketNum);    if (fOutputSocketNum != fInputSocketNum) {      envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum);      ::closeSocket(fOutputSocketNum);    }  }  fInputSocketNum = fOutputSocketNum = -1;}void RTSPClient::resetResponseBuffer() {  fResponseBytesAlreadySeen = 0;  fResponseBufferBytesLeft = responseBufferSize;}void RTSPClient::setBaseURL(char const* url) {  delete[] fBaseURL; fBaseURL = strDup(url);}int RTSPClient::openConnection() {  do {    // Set up a connection to the server.  Begin by parsing the URL:    NetAddress destAddress;    portNumBits urlPortNum;    char const* urlSuffix;    if (!parseRTSPURL(envir(), fBaseURL, destAddress, urlPortNum, &urlSuffix)) break;    portNumBits destPortNum      = fTunnelOverHTTPPortNum == 0 ? urlPortNum : fTunnelOverHTTPPortNum;    // We don't yet have a TCP socket (or we used to have one, but it got closed).  Set it up now.    fInputSocketNum = fOutputSocketNum = setupStreamSocket(envir(), 0);    if (fInputSocketNum < 0) break;          // Connect to the remote endpoint:    fServerAddress = *(unsigned*)(destAddress.data());    int connectResult = connectToServer(fInputSocketNum, destPortNum);    if (connectResult < 0) break;    else if (connectResult > 0) {      // The connection succeeded.  Arrange to handle responses to requests sent on it:      envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE,						    (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);    }    return connectResult;  } while (0);    resetTCPSockets();  return -1;}int RTSPClient::connectToServer(int socketNum, portNumBits remotePortNum) {  MAKE_SOCKADDR_IN(remoteName, fServerAddress, htons(remotePortNum));  if (fVerbosityLevel >= 1) {    envir() << "Opening connection to " << our_inet_ntoa(remoteName.sin_addr) << ", port " << remotePortNum << "...\n";  }  if (connect(socketNum, (struct sockaddr*) &remoteName, sizeof remoteName) != 0) {    if (envir().getErrno() == EINPROGRESS) {      // The connection is pending; we'll need to handle it later.  Wait for our socket to be 'writable', or have an exception.      envir().taskScheduler().setBackgroundHandling(socketNum, SOCKET_WRITABLE|SOCKET_EXCEPTION,						    (TaskScheduler::BackgroundHandlerProc*)&connectionHandler, this);      return 0;    }    envir().setResultErrMsg("connect() failed: ");    if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";    return -1;  }  if (fVerbosityLevel >= 1) envir() << "...local connection opened\n";  return 1;}char*RTSPClient::createAuthenticatorString(char const* cmd, char const* url) {  Authenticator& auth = fCurrentAuthenticator; // alias, for brevity  if (auth.realm() != NULL && auth.username() != NULL && auth.password() != NULL) {    // We have a filled-in authenticator, so use it:    char* authenticatorStr;    if (auth.nonce() != NULL) { // Digest authentication      char const* const authFmt =	"Authorization: Digest username=\"%s\", realm=\"%s\", "	"nonce=\"%s\", uri=\"%s\", response=\"%s\"\r\n";      char const* response = auth.computeDigestResponse(cmd, url);      unsigned authBufSize = strlen(authFmt)	+ strlen(auth.username()) + strlen(auth.realm())	+ strlen(auth.nonce()) + strlen(url) + strlen(response);      authenticatorStr = new char[authBufSize];      sprintf(authenticatorStr, authFmt,	      auth.username(), auth.realm(),	      auth.nonce(), url, response);      auth.reclaimDigestResponse(response);    } else { // Basic authentication      char const* const authFmt = "Authorization: Basic %s\r\n";      unsigned usernamePasswordLength = strlen(auth.username()) + 1 + strlen(auth.password());      char* usernamePassword = new char[usernamePasswordLength+1];      sprintf(usernamePassword, "%s:%s", auth.username(), auth.password());      char* response = base64Encode(usernamePassword, usernamePasswordLength);      unsigned const authBufSize = strlen(authFmt) + strlen(response) + 1;      authenticatorStr = new char[authBufSize];      sprintf(authenticatorStr, authFmt, response);      delete[] response; delete[] usernamePassword;    }    return authenticatorStr;  }  // We don't have a (filled-in) authenticator.  return strDup("");}static char* createSessionString(char const* sessionId) {  char* sessionStr;  if (sessionId != NULL) {    sessionStr = new char[20+strlen(sessionId)];    sprintf(sessionStr, "Session: %s\r\n", sessionId);  } else {    sessionStr = strDup("");  }  return sessionStr;}static char* createScaleString(float scale, float currentScale) {  char buf[100];  if (scale == 1.0f && currentScale == 1.0f) {    // This is the default value; we don't need a "Scale:" header:    buf[0] = '\0';  } else {    Locale l("C", LC_NUMERIC);    sprintf(buf, "Scale: %f\r\n", scale);  }  return strDup(buf);}static char* createRangeString(double start, double end) {  char buf[100];  if (start < 0) {    // We're resuming from a PAUSE; there's no "Range:" header at all    buf[0] = '\0';  } else if (end < 0) {    // There's no end time:    Locale l("C", LC_NUMERIC);    sprintf(buf, "Range: npt=%.3f-\r\n", start);  } else {    // There's both a start and an end time; include them both in the "Range:" hdr    Locale l("C", LC_NUMERIC);    sprintf(buf, "Range: npt=%.3f-%.3f\r\n", start, end);  }  return strDup(buf);}unsigned RTSPClient::sendRequest(RequestRecord* request) {  char* cmd = NULL;  do {    Boolean connectionIsPending = False;    if (!fRequestsAwaitingConnection.isEmpty()) {      // A connection is currently pending (with at least one enqueued request).  Enqueue this request also:      connectionIsPending = True;    } else if (fInputSocketNum < 0) { // we need to open a connection      int connectResult = openConnection();      if (connectResult < 0) break; // an error occurred      else if (connectResult == 0) {	// A connection is pending        connectionIsPending = True;      } // else the connection succeeded.  Continue sending the command.u    }    if (connectionIsPending) {      fRequestsAwaitingConnection.enqueue(request);      return request->cseq();    }    // If requested (and we're not already doing it, or have done it), set up the special protocol for tunneling RTSP-over-HTTP:    if (fTunnelOverHTTPPortNum != 0 && strcmp(request->commandName(), "GET") != 0 && fOutputSocketNum == fInputSocketNum) {      if (!setupHTTPTunneling1()) break;      fRequestsAwaitingHTTPTunneling.enqueue(request);      return request->cseq();    }    // Construct and send the command:    // First, construct command-specific headers that we need:    char* cmdURL = fBaseURL; // by default    Boolean cmdURLWasAllocated = False;    char const* protocolStr = "RTSP/1.0"; // by default    char* extraHeaders = (char*)""; // by default    Boolean extraHeadersWereAllocated = False;     char* contentLengthHeader = (char*)""; // by default    Boolean contentLengthHeaderWasAllocated = False;    char const* contentStr = request->contentStr(); // by default    if (contentStr == NULL) contentStr = "";    unsigned contentStrLen = strlen(contentStr);    if (contentStrLen > 0) {      char const* contentLengthHeaderFmt =	"Content-length: %d\r\n";      unsigned contentLengthHeaderSize = strlen(contentLengthHeaderFmt)	+ 20 /* max int len */;      contentLengthHeader = new char[contentLengthHeaderSize];      sprintf(contentLengthHeader, contentLengthHeaderFmt, contentStrLen);      contentLengthHeaderWasAllocated = True;    }    if (strcmp(request->commandName(), "DESCRIBE") == 0) {      extraHeaders = (char*)"Accept: application/sdp\r\n";    } else if (strcmp(request->commandName(), "OPTIONS") == 0) {    } else if (strcmp(request->commandName(), "ANNOUNCE") == 0) {      extraHeaders = (char*)"Content-Type: application/sdp\r\n";    } else if (strcmp(request->commandName(), "SETUP") == 0) {      MediaSubsession& subsession = *request->subsession();      Boolean streamUsingTCP = (request->booleanFlags()&0x1) != 0;      Boolean streamOutgoing = (request->booleanFlags()&0x2) != 0;      Boolean forceMulticastOnUnspecified = (request->booleanFlags()&0x4) != 0;      char const *prefix, *separator, *suffix;      constructSubsessionURL(subsession, prefix, separator, suffix);      char const* transportFmt;      if (strcmp(subsession.protocolName(), "UDP") == 0) {	suffix = "";	transportFmt = "Transport: RAW/RAW/UDP%s%s%s=%d-%d\r\n";      } else {	transportFmt = "Transport: RTP/AVP%s%s%s=%d-%d\r\n";      }      cmdURL = new char[strlen(prefix) + strlen(separator) + strlen(suffix) + 1];      cmdURLWasAllocated = True;      sprintf(cmdURL, "%s%s%s", prefix, separator, suffix);      // Construct a "Transport:" header.      char const* transportTypeStr;      char const* modeStr = streamOutgoing ? ";mode=receive" : "";          // Note: I think the above is nonstandard, but DSS wants it this way      char const* portTypeStr;      portNumBits rtpNumber, rtcpNumber;      if (streamUsingTCP) { // streaming over the RTSP connection	transportTypeStr = "/TCP;unicast";	portTypeStr = ";interleaved";	rtpNumber = fTCPStreamIdCount++;	rtcpNumber = fTCPStreamIdCount++;      } else { // normal RTP streaming	unsigned connectionAddress = subsession.connectionEndpointAddress();        Boolean requestMulticastStreaming	  = IsMulticastAddress(connectionAddress) || (connectionAddress == 0 && forceMulticastOnUnspecified);	transportTypeStr = requestMulticastStreaming ? ";multicast" : ";unicast";	portTypeStr = ";client_port";	rtpNumber = subsession.clientPortNum();	if (rtpNumber == 0) {	  envir().setResultMsg("Client port number unknown\n");	  delete[] cmdURL;	  break;	}	rtcpNumber = rtpNumber + 1;      }      unsigned transportSize = strlen(transportFmt)	+ strlen(transportTypeStr) + strlen(modeStr) + strlen(portTypeStr) + 2*5 /* max port len */;      char* transportStr = new char[transportSize];      sprintf(transportStr, transportFmt,	      transportTypeStr, modeStr, portTypeStr, rtpNumber, rtcpNumber);      // When sending more than one "SETUP" request, include a "Session:" header in the 2nd and later commands:      char* sessionStr = createSessionString(fLastSessionId);      // The "Transport:" and "Session:" (if present) headers make up the 'extra headers':      extraHeaders = new char[transportSize + strlen(sessionStr)];      extraHeadersWereAllocated = True;      sprintf(extraHeaders, "%s%s", transportStr, sessionStr);      delete[] transportStr; delete[] sessionStr;    } else if (strcmp(request->commandName(), "GET") == 0 || strcmp(request->commandName(), "POST") == 0) {      NetAddress destAddress;      portNumBits urlPortNum;      if (!parseRTSPURL(envir(), fBaseURL, destAddress, urlPortNum, (char const**)&cmdURL)) break;      if (cmdURL[0] == '\0') cmdURL = (char*)"/";      protocolStr = "HTTP/1.0";      if (strcmp(request->commandName(), "GET") == 0) {	// Create a 'session cookie' string, using MD5:	struct {	  struct timeval timestamp;	  unsigned counter;	} seedData;	gettimeofday(&seedData.timestamp, NULL);	seedData.counter = ++fSessionCookieCounter;	our_MD5Data((unsigned char*)(&seedData), sizeof seedData, fSessionCookie);	// DSS seems to require that the 'session cookie' string be 22 bytes long:	fSessionCookie[23] = '\0';		char const* const extraHeadersFmt =	  "x-sessioncookie: %s\r\n"	  "Accept: application/x-rtsp-tunnelled\r\n"	  "Pragma: no-cache\r\n"	  "Cache-Control: no-cache\r\n";

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -