<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<blockquote type="cite"
cite="mid:239F8F92-3099-40DF-9DB2-D51B4F388506@live555.com">
<pre wrap="" class="moz-quote-pre">
</pre>
<blockquote type="cite">
<pre wrap="" class="moz-quote-pre">On Sep 11, 2025, at 5:43 AM, <a class="moz-txt-link-abbreviated" href="mailto:d.gordenin@ngslab.ru">d.gordenin@ngslab.ru</a> wrote:
Hello.
I have an RTSP server, it is fully our code, but it is based on Live555.
</pre>
</blockquote>
<pre wrap="" class="moz-quote-pre">
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)</pre>
</blockquote>
<p>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:</p>
<pre>void <a class="moz-txt-link-freetext" href="VideoSource::doGetNextFrame()">VideoSource::doGetNextFrame()</a>
{
fFrameSize = 0;
<a class="moz-txt-link-freetext" href="ingest::MediaFrame">ingest::MediaFrame</a> audio_frame_dummy;
StorageResult result = <a class="moz-txt-link-freetext" href="StorageResult::OK">StorageResult::OK</a>;
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_ == <a class="moz-txt-link-freetext" href="chunk::StreamInfo::StreamSubtype::UNKNOWN">chunk::StreamInfo::StreamSubtype::UNKNOWN</a>)
{
//detect type of the stream
if (<a class="moz-txt-link-freetext" href="videoreceiver::demuxer::Demuxer::GetH264NaluType((const">videoreceiver::demuxer::Demuxer::GetH264NaluType((const</a> unsigned char*)&frame_.raw_data[0], frame_.raw_data.size()))
stream_type_ = <a class="moz-txt-link-freetext" href="chunk::StreamInfo::StreamSubtype::H264">chunk::StreamInfo::StreamSubtype::H264</a>;
else if (<a class="moz-txt-link-freetext" href="videoreceiver::demuxer::Demuxer::GetH265NaluType((const">videoreceiver::demuxer::Demuxer::GetH265NaluType((const</a> unsigned char*)&frame_.raw_data[0], frame_.raw_data.size()))
stream_type_ = <a class="moz-txt-link-freetext" href="chunk::StreamInfo::StreamSubtype::H265">chunk::StreamInfo::StreamSubtype::H265</a>;
}
}
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 == <a class="moz-txt-link-freetext" href="StorageResult::OK">StorageResult::OK</a> && !frame_.is_key);
frame_.duration = summ_duration;
}
else
{
do
{
result = storage_manager_->GetPrevVideoFrame(frame_);
summ_duration += frame_.duration;
}
while (result == <a class="moz-txt-link-freetext" href="StorageResult::OK">StorageResult::OK</a> && !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_ != <a class="moz-txt-link-freetext" href="chunk::StreamInfo::StreamSubtype::UNKNOWN">chunk::StreamInfo::StreamSubtype::UNKNOWN</a>)
{
//send SEI
<a class="moz-txt-link-freetext" href="ingest::MediaFrame">ingest::MediaFrame</a> 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 == <a class="moz-txt-link-freetext" href="StorageResult::OK">StorageResult::OK</a>)
{
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 == <a class="moz-txt-link-freetext" href="StorageResult::EMPTY_CHUNKS_QUEUE">StorageResult::EMPTY_CHUNKS_QUEUE</a>)
{
log_->Info(<a class="moz-txt-link-rfc2396E" href="VideoSource::doGetNextFrame()endofchunksqueue">"VideoSource::doGetNextFrame() end of chunks queue"</a>);
handleClosure();
return;
}
log_->Info("result={}", (int)result);
send_frame = false;
if (stream_type_ == <a class="moz-txt-link-freetext" href="chunk::StreamInfo::StreamSubtype::UNKNOWN">chunk::StreamInfo::StreamSubtype::UNKNOWN</a>)
{
//detect type of the stream
if (<a class="moz-txt-link-freetext" href="videoreceiver::demuxer::Demuxer::GetH264NaluType((const">videoreceiver::demuxer::Demuxer::GetH264NaluType((const</a> unsigned char*)&frame_.raw_data[0], frame_.raw_data.size()))
stream_type_ = <a class="moz-txt-link-freetext" href="chunk::StreamInfo::StreamSubtype::H264">chunk::StreamInfo::StreamSubtype::H264</a>;
else if (<a class="moz-txt-link-freetext" href="videoreceiver::demuxer::Demuxer::GetH265NaluType((const">videoreceiver::demuxer::Demuxer::GetH265NaluType((const</a> unsigned char*)&frame_.raw_data[0], frame_.raw_data.size()))
stream_type_ = <a class="moz-txt-link-freetext" href="chunk::StreamInfo::StreamSubtype::H265">chunk::StreamInfo::StreamSubtype::H265</a>;
}
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*)<a class="moz-txt-link-freetext" href="FramedSource::afterGetting">FramedSource::afterGetting</a>, this);
}
</pre>
<p></p>
<p><br>
</p>
<blockquote type="cite"
cite="mid:239F8F92-3099-40DF-9DB2-D51B4F388506@live555.com">
<pre wrap="" class="moz-quote-pre">
Ross Finlayson
Live Networks, Inc.
<a class="moz-txt-link-freetext" href="http://www.live555.com/">http://www.live555.com/</a>
_______________________________________________
live-devel mailing list
<a class="moz-txt-link-abbreviated" href="mailto:live-devel@lists.live555.com">live-devel@lists.live555.com</a>
<a class="moz-txt-link-freetext" href="http://lists.live555.com/mailman/listinfo/live-devel">http://lists.live555.com/mailman/listinfo/live-devel</a>
</pre>
</blockquote>
<p><br>
</p>
</body>
</html>