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

📄 rtspclient.cpp

📁 H.264 RTSP 串流(live 555)視窗版本
💻 CPP
📖 第 1 页 / 共 5 页
字号:
      envir().setResultMsg("Missing or bad \"Transport:\" header");      break;    }    delete[] subsession.connectionEndpointName();    subsession.connectionEndpointName() = serverAddressStr;    subsession.serverPortNum = serverPortNum;    subsession.rtpChannelId = rtpChannelId;    subsession.rtcpChannelId = rtcpChannelId;    if (streamUsingTCP) {      // Tell the subsession to receive RTP (and send/receive RTCP) over the RTSP stream:      if (subsession.rtpSource() != NULL) {	subsession.rtpSource()->setStreamSocket(fInputSocketNum, subsession.rtpChannelId);	subsession.rtpSource()->setServerRequestAlternativeByteHandler(handleAlternativeRequestByte, this);      }      if (subsession.rtcpInstance() != NULL) subsession.rtcpInstance()->setStreamSocket(fInputSocketNum, subsession.rtcpChannelId);    } else {      // Normal case.      // Set the RTP and RTCP sockets' destination address and port from the information in the SETUP response (if present):      netAddressBits destAddress = subsession.connectionEndpointAddress();      if (destAddress == 0) destAddress = fServerAddress;      subsession.setDestinations(destAddress);    }    success = True;  } while (0);  delete[] sessionId;  return success;}Boolean RTSPClient::handlePLAYResponse(MediaSession& session, MediaSubsession& subsession,                                       char const* scaleParamsStr, char const* rangeParamsStr, char const* rtpInfoParamsStr) {  Boolean scaleOK = False, rangeOK = False;  do {    if (&session != NULL) {      // The command was on the whole session      if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, session.scale())) break;      scaleOK = True;      if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, session.playStartTime(), session.playEndTime())) break;      rangeOK = True;      u_int16_t seqNum; u_int32_t timestamp;      if (rtpInfoParamsStr != NULL) {	if (!parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) break;	// This is data for our first subsession.  Fill it in, and do the same for our other subsessions:	MediaSubsessionIterator iter(session);	MediaSubsession* subsession;	while ((subsession = iter.next()) != NULL) {	  subsession->rtpInfo.seqNum = seqNum;	  subsession->rtpInfo.timestamp = timestamp;	  subsession->rtpInfo.infoIsNew = True;	  if (!parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) break;	}      }    } else {      // The command was on a subsession      if (scaleParamsStr != NULL && !parseScaleParam(scaleParamsStr, subsession.scale())) break;      scaleOK = True;      if (rangeParamsStr != NULL && !parseRangeParam(rangeParamsStr, subsession._playStartTime(), subsession._playEndTime())) break;      rangeOK = True;      u_int16_t seqNum; u_int32_t timestamp;      if (rtpInfoParamsStr != NULL) {	if (!parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) break;	subsession.rtpInfo.seqNum = seqNum;	subsession.rtpInfo.timestamp = timestamp;	subsession.rtpInfo.infoIsNew = True;      }    }    return True;  } while (0);  // An error occurred:  if (!scaleOK) {    envir().setResultMsg("Bad \"Scale:\" header");  } else if (!rangeOK) {    envir().setResultMsg("Bad \"Range:\" header");  } else {    envir().setResultMsg("Bad \"RTP-Info:\" header");  }  return False;}Boolean RTSPClient::handleTEARDOWNResponse(MediaSession& session, MediaSubsession& subsession) {  if (&session != NULL) {    // The command was on the whole session    // Run through each subsession, deleting its "sessionId":    MediaSubsessionIterator iter(session);    MediaSubsession* subsession;    while ((subsession = iter.next()) != NULL) {      delete[] (char*)subsession->sessionId;      subsession->sessionId = NULL;    }  } else {    // The command was on a subsession    delete[] (char*)subsession.sessionId;    subsession.sessionId = NULL;  }  return True;}Boolean RTSPClient::handleGET_PARAMETERResponse(char const* parameterName, char*& resultValueString) {  do {    // If "parameterName" is non-empty, it should be (possibly followed by ':' and whitespace) at the start of the result string:    if (parameterName != NULL && parameterName[0] != '\0') {      if (parameterName[1] == '\0') break; // sanity check; there should have been \r\n at the end of "parameterName"      unsigned parameterNameLen = strlen(parameterName);      // ASSERT: parameterNameLen >= 2;      parameterNameLen -= 2; // because of the trailing \r\n      if (_strncasecmp(resultValueString, parameterName, parameterNameLen) != 0) break; // parameter name wasn't in the output      resultValueString += parameterNameLen;      if (resultValueString[0] == ':') ++resultValueString;      while (resultValueString[0] == ' ' || resultValueString[0] == '\t') ++resultValueString;    }    // The rest of "resultValueStr" should be our desired result, but first trim off any \r and/or \n characters at the end:    unsigned resultLen = strlen(resultValueString);    while (resultLen > 0 && (resultValueString[resultLen-1] == '\r' || resultValueString[resultLen-1] == '\n')) --resultLen;    resultValueString[resultLen] = '\0';    return True;  } while (0);  // An error occurred:  envir().setResultMsg("Bad \"GET_PARAMETER\" response");  return False;}Boolean RTSPClient::handleAuthenticationFailure(char const* paramsStr) {  // Fill in "fCurrentAuthenticator" with the information from the "WWW-Authenticate:" header:  Boolean alreadyHadRealm = fCurrentAuthenticator.realm() != NULL;  char* realm = strDupSize(paramsStr);  char* nonce = strDupSize(paramsStr);  Boolean success = True;  if (sscanf(paramsStr, "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) {    fCurrentAuthenticator.setRealmAndNonce(realm, nonce);  } else if (sscanf(paramsStr, "Basic realm=\"%[^\"]\"", realm) == 1) {    fCurrentAuthenticator.setRealmAndNonce(realm, NULL); // Basic authentication  } else {    success = False; // bad "WWW-Authenticate:" header  }  delete[] realm; delete[] nonce;  if (alreadyHadRealm || fCurrentAuthenticator.username() == NULL || fCurrentAuthenticator.password() == NULL) {    // We already had a 'realm', or don't have a username and/or password,    // so the new "WWW-Authenticate:" header information won't help us.  We remain unauthenticated.    success = False;  }  return success;}Boolean RTSPClient::resendCommand(RequestRecord* request) {  if (fVerbosityLevel >= 1) envir() << "Resending...\n";  if (request != NULL) request->cseq() = ++fCSeq;  return sendRequest(request) != 0;}char const* RTSPClient::sessionURL(MediaSession const& session) const {  char const* url = session.controlPath();  if (url == NULL || strcmp(url, "*") == 0) url = fBaseURL;  return url;}void RTSPClient::handleAlternativeRequestByte(void* rtspClient, u_int8_t requestByte) {  ((RTSPClient*)rtspClient)->handleAlternativeRequestByte1(requestByte);}void RTSPClient::handleAlternativeRequestByte1(u_int8_t requestByte) {  fResponseBuffer[fResponseBytesAlreadySeen] = requestByte;  handleResponseBytes(1);}static Boolean isAbsoluteURL(char const* url) {  // Assumption: "url" is absolute if it contains a ':', before any  // occurrence of '/'  while (*url != '\0' && *url != '/') {    if (*url == ':') return True;    ++url;  }  return False;}void RTSPClient::constructSubsessionURL(MediaSubsession const& subsession,					char const*& prefix,					char const*& separator,					char const*& suffix) {  // Figure out what the URL describing "subsession" will look like.  // The URL is returned in three parts: prefix; separator; suffix  //##### NOTE: This code doesn't really do the right thing if "sessionURL()"  // doesn't end with a "/", and "subsession.controlPath()" is relative.  // The right thing would have been to truncate "sessionURL()" back to the  // rightmost "/", and then add "subsession.controlPath()".  // In practice, though, each "DESCRIBE" response typically contains  // a "Content-Base:" header that consists of "sessionURL()" followed by  // a "/", in which case this code ends up giving the correct result.  // However, we should really fix this code to do the right thing, and  // also check for and use the "Content-Base:" header appropriately. #####  prefix = sessionURL(subsession.parentSession());  if (prefix == NULL) prefix = "";  suffix = subsession.controlPath();  if (suffix == NULL) suffix = "";  if (isAbsoluteURL(suffix)) {    prefix = separator = "";  } else {    unsigned prefixLen = strlen(prefix);    separator = (prefixLen == 0 || prefix[prefixLen-1] == '/' || suffix[0] == '/') ? "" : "/";  }}Boolean RTSPClient::setupHTTPTunneling1() {  // Set up RTSP-over-HTTP tunneling, as described in  //     http://developer.apple.com/documentation/QuickTime/QTSS/Concepts/chapter_2_section_14.html  if (fVerbosityLevel >= 1) {    envir() << "Requesting RTSP-over-HTTP tunneling (on port " << fTunnelOverHTTPPortNum << ")\n\n";  }  // Begin by sending a HTTP "GET", to set up the server->client link.  Continue when we handle the response:  return sendRequest(new RequestRecord(1, "GET", responseHandlerForHTTP_GET)) != 0;}void RTSPClient::responseHandlerForHTTP_GET(RTSPClient* rtspClient, int responseCode, char* responseString) {  if (rtspClient != NULL) rtspClient->responseHandlerForHTTP_GET1(responseCode, responseString);}void RTSPClient::responseHandlerForHTTP_GET1(int responseCode, char* responseString) {  RequestRecord* request;  do {    // Having successfully set up (using the HTTP "GET" command) the server->client link, set up a second TCP connection    // (to the same server & port as before) for the client->server link.  All future output will be to this new socket.    fOutputSocketNum = setupStreamSocket(envir(), 0);    if (fOutputSocketNum < 0) break;    fHTTPTunnelingConnectionIsPending = True;    int connectResult = connectToServer(fOutputSocketNum, fTunnelOverHTTPPortNum);    if (connectResult < 0) break; // an error occurred    else if (connectResult == 0) {      // A connection is pending.  Continue setting up RTSP-over-HTTP when the connection completes.      // First, move the pending requests to the 'awaiting connection' queue:      while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {	fRequestsAwaitingConnection.enqueue(request);      }      return;    }    // The connection succeeded.  Continue setting up RTSP-over-HTTP:    if (!setupHTTPTunneling2()) break;    // RTSP-over-HTTP tunneling succeeded.  Resume the pending request(s):    while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {      sendRequest(request);    }    return;  } while (0);  // An error occurred.  Dequeue the pending request(s), and tell them about the error:  fHTTPTunnelingConnectionIsPending = False;  while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {    handleRequestError(request);    delete request;  }  resetTCPSockets();}Boolean RTSPClient::setupHTTPTunneling2() {  fHTTPTunnelingConnectionIsPending = False;  // Send a HTTP "POST", to set up the client->server link.  (Note that we won't see a reply to the "POST".)  return sendRequest(new RequestRecord(1, "POST", NULL)) != 0;}void RTSPClient::connectionHandler(void* instance, int /*mask*/) {  RTSPClient* client = (RTSPClient*)instance;  client->connectionHandler1();}void RTSPClient::connectionHandler1() {  // Restore normal handling on our sockets:  envir().taskScheduler().disableBackgroundHandling(fOutputSocketNum);  envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE,						(TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);  // Move all requests awaiting connection into a new, temporary queue, to clear "fRequestsAwaitingConnection"  // (so that "sendRequest()" doesn't get confused by "fRequestsAwaitingConnection" being nonempty, and enqueue them all over again).  RequestQueue tmpRequestQueue;  RequestRecord* request;  while ((request = fRequestsAwaitingConnection.dequeue()) != NULL) {    tmpRequestQueue.enqueue(request);  }  // Find out whether the connection succeeded or failed:  do {    int err = 0;    SOCKLEN_T len = sizeof err;    if (getsockopt(fInputSocketNum, SOL_SOCKET, SO_ERROR, (char*)&err, &len) < 0 || err != 0) {      envir().setResultErrMsg("Connection to server failed: ", err);      if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";      break;    }    // The connection succeeded.  If the connection came about from an attempt to set up RTSP-over-HTTP, finish this now:    if (fVerbosityLevel >= 1) envir() << "...remote connection opened\n";    if (fHTTPTunnelingConnectionIsPending && !setupHTTPTunneling2()) break;    // Resume sending all pending requests:    while ((request = tmpRequestQueue.dequeue()) != NULL) {      sendRequest(request);    }    return;  } while (0);  // An error occurred.  Tell all pending requests about the error:  while ((request = tmpRequestQueue.dequeue()) != NULL) {    handleRequestError(request);    delete request;  }  resetTCPSockets();}void RTSPClient::incomingDataHandler(void* instance, int /*mask*/) {  RTSPClient* client = (RTSPClient*)instance;

⌨️ 快捷键说明

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