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