xref: /aosp_15_r20/external/webrtc/test/testsupport/fixed_fps_video_frame_writer_adapter.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "test/testsupport/fixed_fps_video_frame_writer_adapter.h"
12 
13 #include <cmath>
14 #include <utility>
15 
16 #include "absl/types/optional.h"
17 #include "api/units/time_delta.h"
18 #include "api/video/video_sink_interface.h"
19 #include "rtc_base/checks.h"
20 #include "test/testsupport/video_frame_writer.h"
21 
22 namespace webrtc {
23 namespace test {
24 namespace {
25 
26 constexpr TimeDelta kOneSecond = TimeDelta::Seconds(1);
27 
28 }  // namespace
29 
FixedFpsVideoFrameWriterAdapter(int fps,Clock * clock,std::unique_ptr<VideoFrameWriter> delegate)30 FixedFpsVideoFrameWriterAdapter::FixedFpsVideoFrameWriterAdapter(
31     int fps,
32     Clock* clock,
33     std::unique_ptr<VideoFrameWriter> delegate)
34     : inter_frame_interval_(kOneSecond / fps),
35       clock_(clock),
36       delegate_(std::move(delegate)) {}
37 
~FixedFpsVideoFrameWriterAdapter()38 FixedFpsVideoFrameWriterAdapter::~FixedFpsVideoFrameWriterAdapter() {
39   Close();
40 }
41 
Close()42 void FixedFpsVideoFrameWriterAdapter::Close() {
43   if (is_closed_) {
44     return;
45   }
46   is_closed_ = true;
47   if (!last_frame_.has_value()) {
48     return;
49   }
50   Timestamp now = Now();
51   RTC_CHECK(WriteMissedSlotsExceptLast(now));
52   RTC_CHECK(delegate_->WriteFrame(*last_frame_));
53   delegate_->Close();
54 }
55 
WriteFrame(const VideoFrame & frame)56 bool FixedFpsVideoFrameWriterAdapter::WriteFrame(const VideoFrame& frame) {
57   RTC_CHECK(!is_closed_);
58   Timestamp now = Now();
59   if (!last_frame_.has_value()) {
60     RTC_CHECK(!last_frame_time_.IsFinite());
61     last_frame_ = frame;
62     last_frame_time_ = now;
63     return true;
64   }
65 
66   RTC_CHECK(last_frame_time_.IsFinite());
67 
68   if (last_frame_time_ > now) {
69     // New frame was recevied before expected time "slot" for current
70     // `last_frame_` came => just replace current `last_frame_` with
71     // received `frame`.
72     RTC_CHECK_LE(last_frame_time_ - now, inter_frame_interval_ / 2);
73     last_frame_ = frame;
74     return true;
75   }
76 
77   if (!WriteMissedSlotsExceptLast(now)) {
78     return false;
79   }
80 
81   if (now - last_frame_time_ < inter_frame_interval_ / 2) {
82     // New frame was received closer to the expected time "slot" for current
83     // `last_frame_` than to the next "slot" => just replace current
84     // `last_frame_` with received `frame`.
85     last_frame_ = frame;
86     return true;
87   }
88 
89   if (!delegate_->WriteFrame(*last_frame_)) {
90     return false;
91   }
92   last_frame_ = frame;
93   last_frame_time_ = last_frame_time_ + inter_frame_interval_;
94   return true;
95 }
96 
WriteMissedSlotsExceptLast(Timestamp now)97 bool FixedFpsVideoFrameWriterAdapter::WriteMissedSlotsExceptLast(
98     Timestamp now) {
99   RTC_CHECK(last_frame_time_.IsFinite());
100   while (now - last_frame_time_ > inter_frame_interval_) {
101     if (!delegate_->WriteFrame(*last_frame_)) {
102       return false;
103     }
104     last_frame_time_ = last_frame_time_ + inter_frame_interval_;
105   }
106   return true;
107 }
108 
Now() const109 Timestamp FixedFpsVideoFrameWriterAdapter::Now() const {
110   return clock_->CurrentTime();
111 }
112 
113 }  // namespace test
114 }  // namespace webrtc
115