diff --git a/cscore/src/main/native/cpp/MjpegServerImpl.cpp b/cscore/src/main/native/cpp/MjpegServerImpl.cpp index b88b8b444e..9dd6f33c7d 100644 --- a/cscore/src/main/native/cpp/MjpegServerImpl.cpp +++ b/cscore/src/main/native/cpp/MjpegServerImpl.cpp @@ -643,8 +643,9 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) { Frame::Time lastFrameTime = 0; Frame::Time timePerFrame = 0; if (m_fps != 0) timePerFrame = 1000000.0 / m_fps; - // Allow fudge factor of 1 ms in frame rate - if (timePerFrame >= 1000) timePerFrame -= 1000; + Frame::Time averageFrameTime = 0; + Frame::Time averagePeriod = 1000000; // 1 second window + if (averagePeriod < timePerFrame) averagePeriod = timePerFrame * 10; StartStream(); while (m_active && !os.has_error()) { @@ -665,10 +666,26 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) { continue; } - if (frame.GetTime() < (lastFrameTime + timePerFrame)) { - // Limit FPS; sleep for 10 ms so we don't consume all processor time - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - continue; + auto thisFrameTime = frame.GetTime(); + if (thisFrameTime != 0 && timePerFrame != 0 && lastFrameTime != 0) { + Frame::Time deltaTime = thisFrameTime - lastFrameTime; + + // drop frame if it is early compared to the desired frame rate AND + // the current average is higher than the desired average + if (deltaTime < timePerFrame && averageFrameTime < timePerFrame) { + // sleep for 1 ms so we don't consume all processor time + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + // update average + if (averageFrameTime != 0) { + averageFrameTime = + averageFrameTime * (averagePeriod - timePerFrame) / averagePeriod + + deltaTime * timePerFrame / averagePeriod; + } else { + averageFrameTime = deltaTime; + } } int width = m_width != 0 ? m_width : frame.GetOriginalWidth(); @@ -705,7 +722,7 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) { // print the individual mimetype and the length // sending the content-length fixes random stream disruption observed // with firefox - lastFrameTime = frame.GetTime(); + lastFrameTime = thisFrameTime; double timestamp = lastFrameTime / 1000000.0; header.clear(); oss << "\r\n--" BOUNDARY "\r\n"