On Sep 11, 2025, at 5:43 AM,[email protected] wrote:

Hello.
I have an RTSP server, it is fully our code, but it is based on Live555.
Sorry, but if this “fully your code”, then you can’t expect help on this 
mailing list.  (But, a reminder that if it’s “based on LIVE555”, you are 
subject to the terms of the LGPL)

Code is not a problem, but there is a lot of them, I don't know which one you are interested on... This is the doGetNextFrame() function, here the frames fly to the client via live555:

voidVideoSource::doGetNextFrame()
{
  fFrameSize = 0;
  ingest::MediaFrame audio_frame_dummy;
  StorageResult result =StorageResult::OK;
  uint64_t summ_duration = 0;
  unsigned int start_delay = config_->GetStartStreamerDelay();
  unsigned int start_fps = config_->GetStartStreamerFps();

  while (fFrameSize == 0)
  {
    bool res = false;

    log_->Info("Next frame");

    if (!send_sei && !send_frame)
    {
      frame_.raw_data.resize(0);
      if (start_source_)
      {
        if (first_frame_ && storage_manager_->seek_position != 0)
        {
          result = storage_manager_->GetNextVideoFrame(frame_);
          first_frames_.push_back(frame_);
          log_->Info("Prepare frame: {} {} {} {}", frame_.frame_time, 
frame_.is_key, frame_.duration, frame_.raw_data.size());
          while (frame_.frame_time <= (uint64_t)storage_manager_->seek_position)
          {
            result = storage_manager_->GetNextVideoFrame(frame_);
            //log_->Info("Prepare frame: {} {} {} {}", frame_.frame_time, 
frame_.is_key, frame_.duration, frame_.raw_data.size());
            first_frames_.push_back(frame_);
          }
          send_sei = true;
        }

        if (!first_frames_.empty())
        {
          if (start_fps > 0)
            frame_.frame_time = storage_manager_->seek_position - 
first_frames_.size() * start_fps;
          else
            frame_.frame_time = first_frames_[0].frame_time;
        }
first_frame_ = false;

        //send VPS, SPS, PPS before the first frame
        frame_.is_key = false;
        frame_.duration = 0;
        if (!vps_.empty())
        {
          frame_.raw_data.assign(vps_.begin(), vps_.end());
          vps_.clear();
          log_->Info("Prepare VPS: {} {}", frame_.frame_time, 
frame_.raw_data.size());
        }
        else if (!sps_.empty())
        {
          frame_.raw_data.assign(sps_.begin(), sps_.end());
          sps_.clear();
          log_->Info("Prepare SPS: {} {}", frame_.frame_time, 
frame_.raw_data.size());
        }
        else if (!pps_.empty())
        {
          frame_.raw_data.assign(pps_.begin(), pps_.end());
          pps_.clear();
          log_->Info("Prepare PPS: {} {}", frame_.frame_time, 
frame_.raw_data.size());
        }
        else
        {
          send_sei = false;
          start_source_ = false;
        }

        if (stream_type_ ==chunk::StreamInfo::StreamSubtype::UNKNOWN)
        {
          //detect type of the stream
          if (videoreceiver::demuxer::Demuxer::GetH264NaluType((const unsigned 
char*)&frame_.raw_data[0], frame_.raw_data.size()))
            stream_type_ =chunk::StreamInfo::StreamSubtype::H264;
          else if (videoreceiver::demuxer::Demuxer::GetH265NaluType((const unsigned 
char*)&frame_.raw_data[0], frame_.raw_data.size()))
            stream_type_ =chunk::StreamInfo::StreamSubtype::H265;
        }
      }
      else
      {
        if (!first_frames_.empty())
        {
          frame_ = first_frames_[0];
          if (start_delay > 0)
            frame_.duration = start_delay;
          if (start_fps > 0)
            frame_.frame_time = storage_manager_->seek_position - 
first_frames_.size() * start_fps;
          first_frames_.erase(first_frames_.begin());
        }
        else
        {
          if (decimator_.OnlyKeyFrames())
          {
            if (!reverse_)
            {
              do
              {
                result = storage_manager_->GetNextVideoFrame(frame_);
                summ_duration += frame_.duration;
              }
              while (result ==StorageResult::OK && !frame_.is_key);

              frame_.duration = summ_duration;
            }
            else
            {
              do
              {
                result = storage_manager_->GetPrevVideoFrame(frame_);
                summ_duration += frame_.duration;
              }
              while (result ==StorageResult::OK && !frame_.is_key);

              frame_.duration = summ_duration;
            }
          }
          else
          {
            if (!reverse_)
              result = storage_manager_->GetNextVideoFrame(frame_);
          }
        }
        send_sei = true;
      }
    }

    if (send_sei && frame_.frame_time != 0 && stream_type_ 
!=chunk::StreamInfo::StreamSubtype::UNKNOWN)
    {
      //send SEI
      ingest::MediaFrame sei_frame;
      makeSeiFrame(frame_.frame_time, sei_frame);

      //log_->Info("Send SEI: {} {} {} {}", sei_frame.frame_time, 
sei_frame.is_key, sei_frame.duration, sei_frame.raw_data.size());
      memcpy(fTo, sei_frame.raw_data.data(), sei_frame.raw_data.size());
      fFrameSize = sei_frame.raw_data.size();
      send_sei = false;
      send_frame = true;

      fDurationInMicroseconds = 0;
    }
    else
    {
      //send the frame
      if (result ==StorageResult::OK)
      {
        if (decimator_.ApproveFrame(frame_.is_key))
        {
          log_->Info("Send frame: {} {} {} {}", frame_.frame_time, 
frame_.is_key, frame_.duration, frame_.raw_data.size());
          memcpy(fTo, frame_.raw_data.data(), frame_.raw_data.size());
          fFrameSize = frame_.raw_data.size();
        }
      }
      else if (result ==StorageResult::EMPTY_CHUNKS_QUEUE)
      {
        log_->Info("VideoSource::doGetNextFrame() end of chunks queue");
        handleClosure();
        return;
      }

      log_->Info("result={}", (int)result);

      send_frame = false;

      if (stream_type_ ==chunk::StreamInfo::StreamSubtype::UNKNOWN)
      {
        //detect type of the stream
        if (videoreceiver::demuxer::Demuxer::GetH264NaluType((const unsigned 
char*)&frame_.raw_data[0], frame_.raw_data.size()))
          stream_type_ =chunk::StreamInfo::StreamSubtype::H264;
        else if (videoreceiver::demuxer::Demuxer::GetH265NaluType((const unsigned 
char*)&frame_.raw_data[0], frame_.raw_data.size()))
          stream_type_ =chunk::StreamInfo::StreamSubtype::H265;
      }

      if (!first_frames_.empty() && start_delay > 0)
        fDurationInMicroseconds = start_delay * 1000;
      else
        fDurationInMicroseconds = 
static_cast<unsigned>(decimator_.CalcDuration(frame_.duration));
    }
  }

  //calculate RTP timestamp
  if (start_time_ == 0)
  {
    timeval s;
    gettimeofday(&s, NULL);
    start_time_ = ((long long)s.tv_sec * 1000000UL + s.tv_usec);
    first_frame_time_ = frame_.frame_time;
    //log_->Info("gettimeofday={},{} start_time_={} first_frame_time_={}", 
s.tv_sec, s.tv_usec, start_time_, first_frame_time_);
  }

  uint64_t t = uint64_t((double)frame_.frame_time * double(start_time_) / 
first_frame_time_);
  if (decimator_.rate_ == 1)
  {
      fPresentationTime.tv_sec = t / 1000000UL;
      fPresentationTime.tv_usec = t % 1000000UL;
  }
  else
    gettimeofday(&fPresentationTime, NULL);

  rtp_timestamp_ = t;
  //log_->Info("fDurationInMicroseconds={} fPresentationTime={},{} 
rtp_timestamp_={}", fDurationInMicroseconds, fPresentationTime.tv_sec,
  //  fPresentationTime.tv_usec, rtp_timestamp_);
  log_->Info("nextTask");
  nextTask() = envir().taskScheduler().scheduleDelayedTask(0, 
(TaskFunc*)FramedSource::afterGetting, this);
}




Ross Finlayson
Live Networks, Inc.
http://www.live555.com/


_______________________________________________
live-devel mailing list
[email protected]
http://lists.live555.com/mailman/listinfo/live-devel

_______________________________________________
live-devel mailing list
[email protected]
http://lists.live555.com/mailman/listinfo/live-devel

Reply via email to