1. 程式人生 > >live555學習三:RTP資料流的獲取

live555學習三:RTP資料流的獲取

前面有說到流struct streamState ,該結構體中包含了Track和source,這裡就先說說這個source的獲取

FramedSource* mediaSource = createNewStreamSource(clientSessionId,streamBitrate);這個函式是一個純虛擬函式,用來獲取資料流,

對於h264資料流,會呼叫這個函式

FramedSource* H264VideoFileServerMediaSubsession::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) {
  estBitrate = 500; // kbps, estimate

  // Create the video source:
  ByteStreamFileSource* fileSource = ByteStreamFileSource::createNew(envir(), fFileName);
  if (fileSource == NULL) return NULL;
  fFileSize = fileSource->fileSize();

  // Create a framer for the Video Elementary Stream:
  return H264VideoStreamFramer::createNew(envir(), fileSource);
}
這個函式實現了本地檔案的流化並生成資料流,fFileName就是本地檔案。若要實現實時資料流的傳輸,需要重寫這個函式,借鑑ProxyServerMediaSource.cpp檔案中的函式:
FramedSource* ProxyServerMediaSubsession::createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate) {
  ProxyServerMediaSession* const sms = (ProxyServerMediaSession*)fParentSession;

  if (verbosityLevel() > 0) {
    envir() << *this << "::createNewStreamSource(session id " << clientSessionId << ")\n";
  }

  // If we haven't yet created a data source from our 'media subsession' object, initiate() it to do so:
  if (fClientMediaSubsession.readSource() == NULL) {
    fClientMediaSubsession.receiveRawMP3ADUs(); // hack for MPA-ROBUST streams
    fClientMediaSubsession.receiveRawJPEGFrames(); // hack for proxying JPEG/RTP streams. (Don't do this if we're transcoding.)
    fClientMediaSubsession.initiate();
    if (verbosityLevel() > 0) {
      envir() << "\tInitiated: " << *this << "\n";
    }

    if (fClientMediaSubsession.readSource() != NULL) {
      // Add to the front of all data sources a filter that will 'normalize' their frames' presentation times,
      // before the frames get re-transmitted by our server:
      char const* const codecName = fClientMediaSubsession.codecName();
      FramedFilter* normalizerFilter = sms->fPresentationTimeSessionNormalizer
	->createNewPresentationTimeSubsessionNormalizer(fClientMediaSubsession.readSource(), fClientMediaSubsession.rtpSource(),
							codecName);
      fClientMediaSubsession.addFilter(normalizerFilter);

      // Some data sources require a 'framer' object to be added, before they can be fed into
      // a "RTPSink".  Adjust for this now:
      if (strcmp(codecName, "H264") == 0) {
	fClientMediaSubsession.addFilter(H264VideoStreamDiscreteFramer
					 ::createNew(envir(), fClientMediaSubsession.readSource()));
      } else if (strcmp(codecName, "H265") == 0) {
	fClientMediaSubsession.addFilter(H265VideoStreamDiscreteFramer
					 ::createNew(envir(), fClientMediaSubsession.readSource()));
      } else if (strcmp(codecName, "MP4V-ES") == 0) {
	fClientMediaSubsession.addFilter(MPEG4VideoStreamDiscreteFramer
					 ::createNew(envir(), fClientMediaSubsession.readSource(),
						     True/* leave PTs unmodified*/));
      } else if (strcmp(codecName, "MPV") == 0) {
	fClientMediaSubsession.addFilter(MPEG1or2VideoStreamDiscreteFramer
					 ::createNew(envir(), fClientMediaSubsession.readSource(),
						     False, 5.0, True/* leave PTs unmodified*/));
      } else if (strcmp(codecName, "DV") == 0) {
	fClientMediaSubsession.addFilter(DVVideoStreamFramer
					 ::createNew(envir(), fClientMediaSubsession.readSource(),
						     False, True/* leave PTs unmodified*/));
      }
    }

    if (fClientMediaSubsession.rtcpInstance() != NULL) {
      fClientMediaSubsession.rtcpInstance()->setByeHandler(subsessionByeHandler, this);
    }
  }

  ProxyRTSPClient* const proxyRTSPClient = sms->fProxyRTSPClient;
  if (clientSessionId != 0) {
    // We're being called as a result of implementing a RTSP "SETUP".
    if (!fHaveSetupStream) {
      // This is our first "SETUP".  Send RTSP "SETUP" and later "PLAY" commands to the proxied server, to start streaming:
      // (Before sending "SETUP", enqueue ourselves on the "RTSPClient"s 'SETUP queue', so we'll be able to get the correct
      //  "ProxyServerMediaSubsession" to handle the response.  (Note that responses come back in the same order as requests.))
      Boolean queueWasEmpty = proxyRTSPClient->fSetupQueueHead == NULL;
      if (queueWasEmpty) {
	proxyRTSPClient->fSetupQueueHead = this;
      } else {
	proxyRTSPClient->fSetupQueueTail->fNext = this;
      }
      proxyRTSPClient->fSetupQueueTail = this;

      // Hack: If there's already a pending "SETUP" request (for another track), don't send this track's "SETUP" right away, because
      // the server might not properly handle 'pipelined' requests.  Instead, wait until after previous "SETUP" responses come back.
      if (queueWasEmpty) {
	proxyRTSPClient->sendSetupCommand(fClientMediaSubsession, ::continueAfterSETUP,
					  False, proxyRTSPClient->fStreamRTPOverTCP, False, proxyRTSPClient->auth());
	++proxyRTSPClient->fNumSetupsDone;
	fHaveSetupStream = True;
      }
    } else {
      // This is a "SETUP" from a new client.  We know that there are no other currently active clients (otherwise we wouldn't
      // have been called here), so we know that the substream was previously "PAUSE"d.  Send "PLAY" downstream once again,
      // to resume the stream:
      if (!proxyRTSPClient->fLastCommandWasPLAY) { // so that we send only one "PLAY"; not one for each subsession
	proxyRTSPClient->sendPlayCommand(fClientMediaSubsession.parentSession(), NULL, -1.0f/*resume from previous point*/,
					 -1.0f, 1.0f, proxyRTSPClient->auth());
	proxyRTSPClient->fLastCommandWasPLAY = True;
      }
    }
  }

  estBitrate = fClientMediaSubsession.bandwidth();
  if (estBitrate == 0) estBitrate = 50; // kbps, estimate
  return fClientMediaSubsession.readSource();
}


上面兩個函式分別實現了本地檔案的流化和實時檔案的流化