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)30FixedFpsVideoFrameWriterAdapter::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()38FixedFpsVideoFrameWriterAdapter::~FixedFpsVideoFrameWriterAdapter() { 39 Close(); 40 } 41 Close()42void 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)56bool 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)97bool 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() const109Timestamp FixedFpsVideoFrameWriterAdapter::Now() const { 110 return clock_->CurrentTime(); 111 } 112 113 } // namespace test 114 } // namespace webrtc 115