openRtsp分析3

6 篇文章 0 订阅
2 篇文章 0 订阅

接着上篇来分析。option命令完了就是

unsigned RTSPClient::sendDescribeCommand(responseHandler* responseHandler, Authenticator* authenticator) {
  if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
  return sendRequest(new RequestRecord(++fCSeq, "DESCRIBE", responseHandler));
}

基本过程在上一篇已经分析了。在sendRequest中也没什么好看的,就是把DESCRIBE请求组装发送了,sigleSetup继续执行,因为之前已经将read加入到select监听集中,所以又会到handleResponseBytes中。handleResponseBytes中对DESCRIBE的应答也没有做特殊的处理,然后就执行到了continueAfterDESCRIBE。

在 continueAfterDESCRIBE中我们看到session = MediaSession::createNew(*env, sdpDescription);

这里主要是根据应答的sdpDescription组装session。

MediaSession* MediaSession::createNew(UsageEnvironment& env,
				      char const* sdpDescription) {
  MediaSession* newSession = new MediaSession(env);
  if (newSession != NULL) {
    if (!newSession->initializeWithSDP(sdpDescription)) {
      delete newSession;
      return NULL;
    }
  }

  return newSession;
}

主要是initializeWithSDP根据sdp建立session。

但是没看到RTP socket建立的过程。不过在continueAfterDESCRIBE中看到了subsession->initiate(simpleRTPoffsetArg)

Boolean MediaSubsession::initiate(int useSpecialRTPoffset) {
  if (fReadSource != NULL) return True; // has already been initiated

  do {
    if (fCodecName == NULL) {
      env().setResultMsg("Codec is unspecified");
      break;
    }

    // Create RTP and RTCP 'Groupsocks' on which to receive incoming data.
    // (Groupsocks will work even for unicast addresses)
    struct in_addr tempAddr;
    tempAddr.s_addr = connectionEndpointAddress();
        // This could get changed later, as a result of a RTSP "SETUP"

    if (fClientPortNum != 0) {
      // The sockets' port numbers were specified for us.  Use these:
      Boolean const protocolIsRTP = strcmp(fProtocolName, "RTP") == 0;
      if (protocolIsRTP) {
	fClientPortNum = fClientPortNum&~1; // use an even-numbered port for RTP, and the next (odd-numbered) port for RTCP
      }
      if (isSSM()) {
	fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, fClientPortNum);
      } else {
	fRTPSocket = new Groupsock(env(), tempAddr, fClientPortNum, 255);//建立RTPsocket
      }
      if (fRTPSocket == NULL) {
	env().setResultMsg("Failed to create RTP socket");
	break;
      }
      
      if (protocolIsRTP) {
	// Set our RTCP port to be the RTP port +1
	portNumBits const rtcpPortNum = fClientPortNum|1;
	if (isSSM()) {
	  fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);
	} else {
	  fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);
	}
      }
    } else {
      // Port numbers were not specified in advance, so we use ephemeral port numbers.
      // Create sockets until we get a port-number pair (even: RTP; even+1: RTCP).
      // We need to make sure that we don't keep trying to use the same bad port numbers over and over again.
      // so we store bad sockets in a table, and delete them all when we're done.
      HashTable* socketHashTable = HashTable::create(ONE_WORD_HASH_KEYS);
      if (socketHashTable == NULL) break;
      Boolean success = False;
      NoReuse dummy(env()); // ensures that our new ephemeral port number won't be one that's already in use

      while (1) {
	// Create a new socket:
	if (isSSM()) {
	  fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, 0);
	} else {
	  fRTPSocket = new Groupsock(env(), tempAddr, 0, 255);
	}
	if (fRTPSocket == NULL) {
	  env().setResultMsg("MediaSession::initiate(): unable to create RTP and RTCP sockets");
	  break;
	}

	// Get the client port number, and check whether it's even (for RTP):
	Port clientPort(0);
	if (!getSourcePort(env(), fRTPSocket->socketNum(), clientPort)) {
	  break;
	}
	fClientPortNum = ntohs(clientPort.num()); 
	if ((fClientPortNum&1) != 0) { // it's odd
	  // Record this socket in our table, and keep trying:
	  unsigned key = (unsigned)fClientPortNum;
	  Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket);
	  delete existing; // in case it wasn't NULL
	  continue;
	}

	// Make sure we can use the next (i.e., odd) port number, for RTCP:
	portNumBits rtcpPortNum = fClientPortNum|1;
	if (isSSM()) {
	  fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);
	} else {
	  fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);
	}
	if (fRTCPSocket != NULL && fRTCPSocket->socketNum() >= 0) {
	  // Success! Use these two sockets.
	  success = True;
	  break;
	} else {
	  // We couldn't create the RTCP socket (perhaps that port number's already in use elsewhere?).
	  delete fRTCPSocket;

	  // Record the first socket in our table, and keep trying:
	  unsigned key = (unsigned)fClientPortNum;
	  Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket);
	  delete existing; // in case it wasn't NULL
	  continue;
	}
      }

      // Clean up the socket hash table (and contents):
      Groupsock* oldGS;
      while ((oldGS = (Groupsock*)socketHashTable->RemoveNext()) != NULL) {
	delete oldGS;
      }
      delete socketHashTable;

      if (!success) break; // a fatal error occurred trying to create the RTP and RTCP sockets; we can't continue
    }

    // Try to use a big receive buffer for RTP - at least 0.1 second of
    // specified bandwidth and at least 50 KB
    unsigned rtpBufSize = fBandwidth * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes
    if (rtpBufSize < 50 * 1024)
      rtpBufSize = 50 * 1024;
    increaseReceiveBufferTo(env(), fRTPSocket->socketNum(), rtpBufSize);

    if (isSSM() && fRTCPSocket != NULL) {
      // Special case for RTCP SSM: Send RTCP packets back to the source via unicast:
      fRTCPSocket->changeDestinationParameters(fSourceFilterAddr,0,~0);
    }

    // Create "fRTPSource" and "fReadSource":
    if (!createSourceObjects(useSpecialRTPoffset)) break;

    if (fReadSource == NULL) {
      env().setResultMsg("Failed to create read source");
      break;
    }

    // Finally, create our RTCP instance. (It starts running automatically)
    if (fRTPSource != NULL && fRTCPSocket != NULL) {
      // If bandwidth is specified, use it and add 5% for RTCP overhead.
      // Otherwise make a guess at 500 kbps.
      unsigned totSessionBandwidth
	= fBandwidth ? fBandwidth + fBandwidth / 20 : 500;
      fRTCPInstance = RTCPInstance::createNew(env(), fRTCPSocket,
					      totSessionBandwidth,
					      (unsigned char const*)
					      fParent.CNAME(),
					      NULL /* we're a client */,
					      fRTPSource);
      if (fRTCPInstance == NULL) {
	env().setResultMsg("Failed to create RTCP instance");
	break;
      }
    }

    return True;
  } while (0);

  delete fRTPSocket; fRTPSocket = NULL;
  delete fRTCPSocket; fRTCPSocket = NULL;
  Medium::close(fRTCPInstance); fRTCPInstance = NULL;
  Medium::close(fReadSource); fReadSource = fRTPSource = NULL;
  fClientPortNum = 0;
  return False;
}

这里主要建立RTP socket,

太多的代码就不一一列出,主要分析一下这个过程和线索。这里的fClientPortNum为0,故执行 fRTPSocket = new Groupsock(env(), tempAddr, 0, 255);

fSocketNum赋值为int newSocket = createSocket(SOCK_DGRAM);

创建完rtp socket再创建fRTCPInstance。然后就是创建了RTPSource,在createSourceObjects(useSpecialRTPoffset)中

主要根据fCodecName来创建RTPSource,这里以h264为例。

fReadSource = fRTPSource
	  = H264VideoRTPSource::createNew(env(), fRTPSocket,
					  fRTPPayloadFormat,
					  fRTPTimestampFrequency);

至此continueAfterDESCRIBE中重要的工作已经完成,再接着往下看。然后就执行setupStreams,在这其中主要是执行下面的代码

static MediaSubsessionIterator* setupIter = NULL;
  if (setupIter == NULL) setupIter = new MediaSubsessionIterator(*session);
  while ((subsession = setupIter->next()) != NULL) {
    // We have another subsession left to set up:
    if (subsession->clientPortNum() == 0) continue; // port # was not set

    setupSubsession(subsession, streamUsingTCP, continueAfterSETUP);
    return;
  }

sendSetupCommand(*subsession, afterFunc, False, streamUsingTCP, forceMulticastOnUnspecified, ourAuthenticator);中




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值