live555学习一:数据流的处理

来源:互联网 发布:阿里云邮箱个人 编辑:程序博客网 时间:2024/05/21 07:12

最近一直在看live555,准备用live555搭建自己的流媒体转发服务器,我用的live555的proxyserver目录下的源文件:live555ProxyServer.cpp搭建的转发服务器,要搭建自己的可以借鉴这个实例。

live555的数据流:

在live555下用结构体

struct streamState{     ServerMediaSubsession *subsession; //Track:静态数据,会被其他rtp会话重用     void *streamToken;  //类StreamState(真正的数据流),}*fStreamStates;
表示一个流。

该流的初始化:

在服务器收到setUp请求时,会建立连接同时准备流(fStreamStates)——Track(subsession)+数据流(streamToken),数据流streamToken包含了Source和RTPSink。
1.fStreamState中subsession初始化

①先根据rtsp://协议传入的streamName生成一个ServerMediaSession类对象:fOurServerMediaSession,

将该类对象fOurServerMediaSession存入hash表中:

ServerMediaSubsessionIterator iter(*fOurServerMediaSession);
③从hash表中提取subsession并赋给fStreamStates中的subsession

iter.reset();              ServerMediaSubsession* subsession;              for (unsigned i = 0; i < fNumStreamStates; ++i) {                  subsession = iter.next();                  fStreamStates[i].subsession = subsession;//初始化Track               ……              }
2.fStreamState中streamToken初始化

streamToken的初始化位于函数void OnDemandServerMediaSubsession::getStreamParameters(……)中,

创建原始流FramedSource* mediaSource = createNewStreamSource(clientSessionId,streamBitrate);

创建RTPSink,rtpSink = createNewRTPSink(rtpGroupsock, rtpPayloadType,mediaSource);

根据FramedSource和RTPSink创建数据流streamToken:

// Set up the state of the stream.  The stream will get started later:           streamToken = fLastStreamToken = new StreamState(*this, serverRTPPort,                  serverRTCPPort, rtpSink, udpSink, streamBitrate, mediaSource,                  rtpGroupsock, rtcpGroupsock); 

3.根据得到的Track和streamToken实例化对象fStreamStates

do {          // First, make sure the specified stream name exists:           fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);          if (fOurServerMediaSession == NULL) {              // Check for the special case (noted above), before we up:               if (urlPreSuffix[0] == '\0') {                  streamName = urlSuffix;              } else {                  concatenatedStreamName = new char[strlen(urlPreSuffix)                          + strlen(urlSuffix) + 2]; // allow for the "/" and the trailing '\0'                   sprintf(concatenatedStreamName, "%s/%s", urlPreSuffix,                          urlSuffix);                  streamName = concatenatedStreamName;              }              trackId = NULL;                  // Check again:               fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);          }          if (fOurServerMediaSession == NULL) {              handleCmd_notFound(cseq);              break;          }              fOurServerMediaSession->incrementReferenceCount();              //为一个流中所有的track都分配一个stream state           if (fStreamStates == NULL) {              // This is the first "SETUP" for this session.  Set up our               // array of states for all of this session's subsessions (tracks):               ServerMediaSubsessionIterator iter(*fOurServerMediaSession);              for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {              } // begin by counting the number of subsessions (tracks)                   fStreamStates = new struct streamState[fNumStreamStates];                  iter.reset();              ServerMediaSubsession* subsession;              for (unsigned i = 0; i < fNumStreamStates; ++i) {                  subsession = iter.next();                  fStreamStates[i].subsession = subsession;                  fStreamStates[i].streamToken = NULL; // for now; it may be changed by the "getStreamParameters()" call that comes later               }          }  


服务器处理SETUP请求:

void RTSPServer::RTSPClientSession::handleCmd_SETUP(          char const* cseq,          char const* urlPreSuffix,          char const* urlSuffix,          char const* fullRequestStr)  {      // Normally, "urlPreSuffix" should be the session (stream) name,       // and "urlSuffix" should be the subsession (track) name.       // However (being "liberal in what we accept"), we also handle       // 'aggregate' SETUP requests (i.e., without a track name),       // in the special case where we have only a single track.  I.e.,       // in this case, we also handle:       //    "urlPreSuffix" is empty and "urlSuffix" is the session (stream) name, or       //    "urlPreSuffix" concatenated with "urlSuffix" (with "/" inbetween)       //    is the session (stream) name.       char const* streamName = urlPreSuffix; // in the normal case       char const* trackId = urlSuffix; // in the normal case       char* concatenatedStreamName = NULL; // in the normal case           do {          // First, make sure the specified stream name exists:           fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);          if (fOurServerMediaSession == NULL) {              // Check for the special case (noted above), before we up:               if (urlPreSuffix[0] == '\0') {                  streamName = urlSuffix;              } else {                  concatenatedStreamName = new char[strlen(urlPreSuffix)                          + strlen(urlSuffix) + 2]; // allow for the "/" and the trailing '\0'                   sprintf(concatenatedStreamName, "%s/%s", urlPreSuffix,                          urlSuffix);                  streamName = concatenatedStreamName;              }              trackId = NULL;                  // Check again:               fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);          }          if (fOurServerMediaSession == NULL) {              handleCmd_notFound(cseq);              break;          }              fOurServerMediaSession->incrementReferenceCount();              //为一个流中所有的track都分配一个stream state           if (fStreamStates == NULL) {              // This is the first "SETUP" for this session.  Set up our               // array of states for all of this session's subsessions (tracks):               ServerMediaSubsessionIterator iter(*fOurServerMediaSession);              for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {              } // begin by counting the number of subsessions (tracks)                   fStreamStates = new struct streamState[fNumStreamStates];                  iter.reset();              ServerMediaSubsession* subsession;              for (unsigned i = 0; i < fNumStreamStates; ++i) {                  subsession = iter.next();                  fStreamStates[i].subsession = subsession;                  fStreamStates[i].streamToken = NULL; // for now; it may be changed by the "getStreamParameters()" call that comes later               }          }              //查找当前请求的track的信息           // Look up information for the specified subsession (track):           ServerMediaSubsession* subsession = NULL;          unsigned streamNum;          if (trackId != NULL && trackId[0] != '\0') { // normal case               for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum) {                  subsession = fStreamStates[streamNum].subsession;                  if (subsession != NULL  && strcmp(trackId, subsession->trackId()) == 0)                      break; //找到啦!               }              if (streamNum >= fNumStreamStates) {                  // The specified track id doesn't exist, so this request fails:                   handleCmd_notFound(cseq);                  break;              }          } else {              // Weird case: there was no track id in the URL.               // This works only if we have only one subsession:               if (fNumStreamStates != 1) {                  handleCmd_bad(cseq);                  break;              }              streamNum = 0;              subsession = fStreamStates[streamNum].subsession;          }          // ASSERT: subsession != NULL               //分析RTSP请求字符串中的传输要求           // Look for a "Transport:" header in the request string, to extract client parameters:           StreamingMode streamingMode;          char* streamingModeString = NULL; // set when RAW_UDP streaming is specified           char* clientsDestinationAddressStr;          u_int8_t clientsDestinationTTL;          portNumBits clientRTPPortNum, clientRTCPPortNum;          unsigned char rtpChannelId, rtcpChannelId;          parseTransportHeader(fullRequestStr, streamingMode, streamingModeString,                  clientsDestinationAddressStr, clientsDestinationTTL,                  clientRTPPortNum, clientRTCPPortNum, rtpChannelId,                  rtcpChannelId);          if (streamingMode == RTP_TCP && rtpChannelId == 0xFF                  || streamingMode != RTP_TCP &&                  fClientOutputSocket != fClientInputSocket) {              // An anomolous situation, caused by a buggy client.  Either:               //     1/ TCP streaming was requested, but with no "interleaving=" fields.  (QuickTime Player sometimes does this.), or               //     2/ TCP streaming was not requested, but we're doing RTSP-over-HTTP tunneling (which implies TCP streaming).               // In either case, we assume TCP streaming, and set the RTP and RTCP channel ids to proper values:               streamingMode = RTP_TCP;              rtpChannelId = fTCPStreamIdCount;              rtcpChannelId = fTCPStreamIdCount + 1;          }          fTCPStreamIdCount += 2;              Port clientRTPPort(clientRTPPortNum);          Port clientRTCPPort(clientRTCPPortNum);              // Next, check whether a "Range:" header is present in the request.           // This isn't legal, but some clients do this to combine "SETUP" and "PLAY":           double rangeStart = 0.0, rangeEnd = 0.0;          fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart,                  rangeEnd) || parsePlayNowHeader(fullRequestStr);              // Then, get server parameters from the 'subsession':           int tcpSocketNum = streamingMode == RTP_TCP ? fClientOutputSocket : -1;          netAddressBits destinationAddress = 0;          u_int8_t destinationTTL = 255;  #ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTING           if (clientsDestinationAddressStr != NULL) {              // Use the client-provided "destination" address.               // Note: This potentially allows the server to be used in denial-of-service               // attacks, so don't enable this code unless you're sure that clients are               // trusted.               destinationAddress = our_inet_addr(clientsDestinationAddressStr);          }          // Also use the client-provided TTL.           destinationTTL = clientsDestinationTTL;  #endif           delete[] clientsDestinationAddressStr;          Port serverRTPPort(0);          Port serverRTCPPort(0);              // Make sure that we transmit on the same interface that's used by           // the client (in case we're a multi-homed server):           struct sockaddr_in sourceAddr;          SOCKLEN_T namelen = sizeof sourceAddr;          getsockname(fClientInputSocket, (struct sockaddr*) &sourceAddr, &namelen);          netAddressBits origSendingInterfaceAddr = SendingInterfaceAddr;          netAddressBits origReceivingInterfaceAddr = ReceivingInterfaceAddr;          // NOTE: The following might not work properly, so we ifdef it out for now:   #ifdef HACK_FOR_MULTIHOMED_SERVERS           ReceivingInterfaceAddr = SendingInterfaceAddr = sourceAddr.sin_addr.s_addr;  #endif               //获取rtp连接信息,在其中已建立起了server端的rtp和rtcp socket,返回           //fStreamStates[streamNum].streamToken表示数据流已经建立起来了           subsession->getStreamParameters(fOurSessionId,                  fClientAddr.sin_addr.s_addr, clientRTPPort, clientRTCPPort,                  tcpSocketNum, rtpChannelId, rtcpChannelId, destinationAddress,                  destinationTTL, fIsMulticast, serverRTPPort, serverRTCPPort,                  fStreamStates[streamNum].streamToken);          SendingInterfaceAddr = origSendingInterfaceAddr;          ReceivingInterfaceAddr = origReceivingInterfaceAddr;              //形成RTSP回应字符串           struct in_addr destinationAddr;          destinationAddr.s_addr = destinationAddress;          char* destAddrStr = strDup(our_inet_ntoa(destinationAddr));          char* sourceAddrStr = strDup(our_inet_ntoa(sourceAddr.sin_addr));          if (fIsMulticast) {              switch (streamingMode) {              case RTP_UDP:                  snprintf(                          (char*) fResponseBuffer,                          sizeof fResponseBuffer,                          "RTSP/1.0 200 OK\r\n"                                  "CSeq: %s\r\n"                                  "%s"                                  "Transport: RTP/AVP;multicast;destination=%s;source=%s;port=%d-%d;ttl=%d\r\n"                                  "Session: %08X\r\n\r\n", cseq, dateHeader(),                          destAddrStr, sourceAddrStr, ntohs(serverRTPPort.num()),                          ntohs(serverRTCPPort.num()), destinationTTL,                          fOurSessionId);                  break;              case RTP_TCP:                  // multicast streams can't be sent via TCP                   handleCmd_unsupportedTransport(cseq);                  break;              case RAW_UDP:                  snprintf(                          (char*) fResponseBuffer,                          sizeof fResponseBuffer,                          "RTSP/1.0 200 OK\r\n"                                  "CSeq: %s\r\n"                                  "%s"                                  "Transport: %s;multicast;destination=%s;source=%s;port=%d;ttl=%d\r\n"                                  "Session: %08X\r\n\r\n", cseq, dateHeader(),                          streamingModeString, destAddrStr, sourceAddrStr,                          ntohs(serverRTPPort.num()), destinationTTL,                          fOurSessionId);                  break;              }          } else {              switch (streamingMode) {              case RTP_UDP: {                  snprintf(                          (char*) fResponseBuffer,                          sizeof fResponseBuffer,                          "RTSP/1.0 200 OK\r\n"                                  "CSeq: %s\r\n"                                  "%s"                                  "Transport: RTP/AVP;unicast;destination=%s;source=%s;client_port=%d-%d;server_port=%d-%d\r\n"                                  "Session: %08X\r\n\r\n", cseq, dateHeader(),                          destAddrStr, sourceAddrStr, ntohs(clientRTPPort.num()),                          ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()),                          ntohs(serverRTCPPort.num()), fOurSessionId);                  break;              }              case RTP_TCP: {                  snprintf(                          (char*) fResponseBuffer,                          sizeof fResponseBuffer,                          "RTSP/1.0 200 OK\r\n"                                  "CSeq: %s\r\n"                                  "%s"                                  "Transport: RTP/AVP/TCP;unicast;destination=%s;source=%s;interleaved=%d-%d\r\n"                                  "Session: %08X\r\n\r\n", cseq, dateHeader(),                          destAddrStr, sourceAddrStr, rtpChannelId, rtcpChannelId,                          fOurSessionId);                  break;              }              case RAW_UDP: {                  snprintf(                          (char*) fResponseBuffer,                          sizeof fResponseBuffer,                          "RTSP/1.0 200 OK\r\n"                                  "CSeq: %s\r\n"                                  "%s"                                  "Transport: %s;unicast;destination=%s;source=%s;client_port=%d;server_port=%d\r\n"                                  "Session: %08X\r\n\r\n", cseq, dateHeader(),                          streamingModeString, destAddrStr, sourceAddrStr,                          ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()),                          fOurSessionId);                  break;              }              }          }          delete[] destAddrStr;          delete[] sourceAddrStr;          delete[] streamingModeString;      } while (0);          delete[] concatenatedStreamName;      //返回后,回应字符串会被立即发送   }  


0 0