xref: /aosp_15_r20/external/webrtc/video/render/video_render_frames.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "video/render/video_render_frames.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <type_traits>
14*d9f75844SAndroid Build Coastguard Worker #include <utility>
15*d9f75844SAndroid Build Coastguard Worker 
16*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/time_utils.h"
19*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/metrics.h"
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
22*d9f75844SAndroid Build Coastguard Worker namespace {
23*d9f75844SAndroid Build Coastguard Worker // Don't render frames with timestamp older than 500ms from now.
24*d9f75844SAndroid Build Coastguard Worker const int kOldRenderTimestampMS = 500;
25*d9f75844SAndroid Build Coastguard Worker // Don't render frames with timestamp more than 10s into the future.
26*d9f75844SAndroid Build Coastguard Worker const int kFutureRenderTimestampMS = 10000;
27*d9f75844SAndroid Build Coastguard Worker 
28*d9f75844SAndroid Build Coastguard Worker const uint32_t kEventMaxWaitTimeMs = 200;
29*d9f75844SAndroid Build Coastguard Worker const uint32_t kMinRenderDelayMs = 10;
30*d9f75844SAndroid Build Coastguard Worker const uint32_t kMaxRenderDelayMs = 500;
31*d9f75844SAndroid Build Coastguard Worker const size_t kMaxIncomingFramesBeforeLogged = 100;
32*d9f75844SAndroid Build Coastguard Worker 
EnsureValidRenderDelay(uint32_t render_delay)33*d9f75844SAndroid Build Coastguard Worker uint32_t EnsureValidRenderDelay(uint32_t render_delay) {
34*d9f75844SAndroid Build Coastguard Worker   return (render_delay < kMinRenderDelayMs || render_delay > kMaxRenderDelayMs)
35*d9f75844SAndroid Build Coastguard Worker              ? kMinRenderDelayMs
36*d9f75844SAndroid Build Coastguard Worker              : render_delay;
37*d9f75844SAndroid Build Coastguard Worker }
38*d9f75844SAndroid Build Coastguard Worker }  // namespace
39*d9f75844SAndroid Build Coastguard Worker 
VideoRenderFrames(uint32_t render_delay_ms)40*d9f75844SAndroid Build Coastguard Worker VideoRenderFrames::VideoRenderFrames(uint32_t render_delay_ms)
41*d9f75844SAndroid Build Coastguard Worker     : render_delay_ms_(EnsureValidRenderDelay(render_delay_ms)) {}
42*d9f75844SAndroid Build Coastguard Worker 
~VideoRenderFrames()43*d9f75844SAndroid Build Coastguard Worker VideoRenderFrames::~VideoRenderFrames() {
44*d9f75844SAndroid Build Coastguard Worker   frames_dropped_ += incoming_frames_.size();
45*d9f75844SAndroid Build Coastguard Worker   RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DroppedFrames.RenderQueue",
46*d9f75844SAndroid Build Coastguard Worker                             frames_dropped_);
47*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "WebRTC.Video.DroppedFrames.RenderQueue "
48*d9f75844SAndroid Build Coastguard Worker                    << frames_dropped_;
49*d9f75844SAndroid Build Coastguard Worker }
50*d9f75844SAndroid Build Coastguard Worker 
AddFrame(VideoFrame && new_frame)51*d9f75844SAndroid Build Coastguard Worker int32_t VideoRenderFrames::AddFrame(VideoFrame&& new_frame) {
52*d9f75844SAndroid Build Coastguard Worker   const int64_t time_now = rtc::TimeMillis();
53*d9f75844SAndroid Build Coastguard Worker 
54*d9f75844SAndroid Build Coastguard Worker   // Drop old frames only when there are other frames in the queue, otherwise, a
55*d9f75844SAndroid Build Coastguard Worker   // really slow system never renders any frames.
56*d9f75844SAndroid Build Coastguard Worker   if (!incoming_frames_.empty() &&
57*d9f75844SAndroid Build Coastguard Worker       new_frame.render_time_ms() + kOldRenderTimestampMS < time_now) {
58*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Too old frame, timestamp=" << new_frame.timestamp();
59*d9f75844SAndroid Build Coastguard Worker     ++frames_dropped_;
60*d9f75844SAndroid Build Coastguard Worker     return -1;
61*d9f75844SAndroid Build Coastguard Worker   }
62*d9f75844SAndroid Build Coastguard Worker 
63*d9f75844SAndroid Build Coastguard Worker   if (new_frame.render_time_ms() > time_now + kFutureRenderTimestampMS) {
64*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Frame too long into the future, timestamp="
65*d9f75844SAndroid Build Coastguard Worker                         << new_frame.timestamp();
66*d9f75844SAndroid Build Coastguard Worker     ++frames_dropped_;
67*d9f75844SAndroid Build Coastguard Worker     return -1;
68*d9f75844SAndroid Build Coastguard Worker   }
69*d9f75844SAndroid Build Coastguard Worker 
70*d9f75844SAndroid Build Coastguard Worker   if (new_frame.render_time_ms() < last_render_time_ms_) {
71*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Frame scheduled out of order, render_time="
72*d9f75844SAndroid Build Coastguard Worker                         << new_frame.render_time_ms()
73*d9f75844SAndroid Build Coastguard Worker                         << ", latest=" << last_render_time_ms_;
74*d9f75844SAndroid Build Coastguard Worker     // For more details, see bug:
75*d9f75844SAndroid Build Coastguard Worker     // https://bugs.chromium.org/p/webrtc/issues/detail?id=7253
76*d9f75844SAndroid Build Coastguard Worker     ++frames_dropped_;
77*d9f75844SAndroid Build Coastguard Worker     return -1;
78*d9f75844SAndroid Build Coastguard Worker   }
79*d9f75844SAndroid Build Coastguard Worker 
80*d9f75844SAndroid Build Coastguard Worker   last_render_time_ms_ = new_frame.render_time_ms();
81*d9f75844SAndroid Build Coastguard Worker   incoming_frames_.emplace_back(std::move(new_frame));
82*d9f75844SAndroid Build Coastguard Worker 
83*d9f75844SAndroid Build Coastguard Worker   if (incoming_frames_.size() > kMaxIncomingFramesBeforeLogged) {
84*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Stored incoming frames: "
85*d9f75844SAndroid Build Coastguard Worker                         << incoming_frames_.size();
86*d9f75844SAndroid Build Coastguard Worker   }
87*d9f75844SAndroid Build Coastguard Worker   return static_cast<int32_t>(incoming_frames_.size());
88*d9f75844SAndroid Build Coastguard Worker }
89*d9f75844SAndroid Build Coastguard Worker 
FrameToRender()90*d9f75844SAndroid Build Coastguard Worker absl::optional<VideoFrame> VideoRenderFrames::FrameToRender() {
91*d9f75844SAndroid Build Coastguard Worker   absl::optional<VideoFrame> render_frame;
92*d9f75844SAndroid Build Coastguard Worker   // Get the newest frame that can be released for rendering.
93*d9f75844SAndroid Build Coastguard Worker   while (!incoming_frames_.empty() && TimeToNextFrameRelease() <= 0) {
94*d9f75844SAndroid Build Coastguard Worker     if (render_frame) {
95*d9f75844SAndroid Build Coastguard Worker       ++frames_dropped_;
96*d9f75844SAndroid Build Coastguard Worker     }
97*d9f75844SAndroid Build Coastguard Worker     render_frame = std::move(incoming_frames_.front());
98*d9f75844SAndroid Build Coastguard Worker     incoming_frames_.pop_front();
99*d9f75844SAndroid Build Coastguard Worker   }
100*d9f75844SAndroid Build Coastguard Worker   return render_frame;
101*d9f75844SAndroid Build Coastguard Worker }
102*d9f75844SAndroid Build Coastguard Worker 
TimeToNextFrameRelease()103*d9f75844SAndroid Build Coastguard Worker uint32_t VideoRenderFrames::TimeToNextFrameRelease() {
104*d9f75844SAndroid Build Coastguard Worker   if (incoming_frames_.empty()) {
105*d9f75844SAndroid Build Coastguard Worker     return kEventMaxWaitTimeMs;
106*d9f75844SAndroid Build Coastguard Worker   }
107*d9f75844SAndroid Build Coastguard Worker   const int64_t time_to_release = incoming_frames_.front().render_time_ms() -
108*d9f75844SAndroid Build Coastguard Worker                                   render_delay_ms_ - rtc::TimeMillis();
109*d9f75844SAndroid Build Coastguard Worker   return time_to_release < 0 ? 0u : static_cast<uint32_t>(time_to_release);
110*d9f75844SAndroid Build Coastguard Worker }
111*d9f75844SAndroid Build Coastguard Worker 
HasPendingFrames() const112*d9f75844SAndroid Build Coastguard Worker bool VideoRenderFrames::HasPendingFrames() const {
113*d9f75844SAndroid Build Coastguard Worker   return !incoming_frames_.empty();
114*d9f75844SAndroid Build Coastguard Worker }
115*d9f75844SAndroid Build Coastguard Worker 
116*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
117