blob: 531dade0e8a051384ccbda4c809c8a8e75a0ff03 [file] [log] [blame]
/*
* Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "test/testsupport/fixed_fps_video_frame_writer_adapter.h"
#include <cmath>
#include <utility>
#include "absl/types/optional.h"
#include "api/units/time_delta.h"
#include "api/video/video_sink_interface.h"
#include "rtc_base/checks.h"
#include "test/testsupport/video_frame_writer.h"
namespace webrtc {
namespace test {
namespace {
constexpr TimeDelta kOneSecond = TimeDelta::Seconds(1);
} // namespace
FixedFpsVideoFrameWriterAdapter::FixedFpsVideoFrameWriterAdapter(
int fps,
Clock* clock,
std::unique_ptr<VideoFrameWriter> delegate)
: inter_frame_interval_(kOneSecond / fps),
clock_(clock),
delegate_(std::move(delegate)) {}
FixedFpsVideoFrameWriterAdapter::~FixedFpsVideoFrameWriterAdapter() {
Close();
}
void FixedFpsVideoFrameWriterAdapter::Close() {
if (is_closed_) {
return;
}
is_closed_ = true;
if (!last_frame_.has_value()) {
return;
}
Timestamp now = Now();
RTC_CHECK(WriteMissedSlotsExceptLast(now));
RTC_CHECK(delegate_->WriteFrame(*last_frame_));
delegate_->Close();
}
bool FixedFpsVideoFrameWriterAdapter::WriteFrame(const VideoFrame& frame) {
RTC_CHECK(!is_closed_);
Timestamp now = Now();
if (!last_frame_.has_value()) {
RTC_CHECK(!last_frame_time_.IsFinite());
last_frame_ = frame;
last_frame_time_ = now;
return true;
}
RTC_CHECK(last_frame_time_.IsFinite());
if (last_frame_time_ > now) {
// New frame was recevied before expected time "slot" for current
// `last_frame_` came => just replace current `last_frame_` with
// received `frame`.
RTC_CHECK_LE(last_frame_time_ - now, inter_frame_interval_ / 2);
last_frame_ = frame;
return true;
}
if (!WriteMissedSlotsExceptLast(now)) {
return false;
}
if (now - last_frame_time_ < inter_frame_interval_ / 2) {
// New frame was received closer to the expected time "slot" for current
// `last_frame_` than to the next "slot" => just replace current
// `last_frame_` with received `frame`.
last_frame_ = frame;
return true;
}
if (!delegate_->WriteFrame(*last_frame_)) {
return false;
}
last_frame_ = frame;
last_frame_time_ = last_frame_time_ + inter_frame_interval_;
return true;
}
bool FixedFpsVideoFrameWriterAdapter::WriteMissedSlotsExceptLast(
Timestamp now) {
RTC_CHECK(last_frame_time_.IsFinite());
while (now - last_frame_time_ > inter_frame_interval_) {
if (!delegate_->WriteFrame(*last_frame_)) {
return false;
}
last_frame_time_ = last_frame_time_ + inter_frame_interval_;
}
return true;
}
Timestamp FixedFpsVideoFrameWriterAdapter::Now() const {
return clock_->CurrentTime();
}
} // namespace test
} // namespace webrtc