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 Workeruint32_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 WorkerVideoRenderFrames::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 WorkerVideoRenderFrames::~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 Workerint32_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 Workerabsl::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 Workeruint32_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 Workerbool 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