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