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 "webrtc/modules/video_render/video_render_frames.h" 12 13 #include <assert.h> 14 15 #include "webrtc/common_video/interface/texture_video_frame.h" 16 #include "webrtc/modules/interface/module_common_types.h" 17 #include "webrtc/system_wrappers/interface/tick_util.h" 18 #include "webrtc/system_wrappers/interface/trace.h" 19 20 namespace webrtc { 21 22 const uint32_t KEventMaxWaitTimeMs = 200; 23 const uint32_t kMinRenderDelayMs = 10; 24 const uint32_t kMaxRenderDelayMs= 500; 25 26 VideoRenderFrames::VideoRenderFrames() 27 : render_delay_ms_(10) { 28 } 29 30 VideoRenderFrames::~VideoRenderFrames() { 31 ReleaseAllFrames(); 32 } 33 34 int32_t VideoRenderFrames::AddFrame(I420VideoFrame* new_frame) { 35 const int64_t time_now = TickTime::MillisecondTimestamp(); 36 37 // Drop old frames only when there are other frames in the queue, otherwise, a 38 // really slow system never renders any frames. 39 if (!incoming_frames_.empty() && 40 new_frame->render_time_ms() + KOldRenderTimestampMS < time_now) { 41 WEBRTC_TRACE(kTraceWarning, 42 kTraceVideoRenderer, 43 -1, 44 "%s: too old frame, timestamp=%u.", 45 __FUNCTION__, 46 new_frame->timestamp()); 47 return -1; 48 } 49 50 if (new_frame->render_time_ms() > time_now + KFutureRenderTimestampMS) { 51 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1, 52 "%s: frame too long into the future, timestamp=%u.", 53 __FUNCTION__, new_frame->timestamp()); 54 return -1; 55 } 56 57 if (new_frame->native_handle() != NULL) { 58 incoming_frames_.push_back(new_frame->CloneFrame()); 59 return static_cast<int32_t>(incoming_frames_.size()); 60 } 61 62 // Get an empty frame 63 I420VideoFrame* frame_to_add = NULL; 64 if (!empty_frames_.empty()) { 65 frame_to_add = empty_frames_.front(); 66 empty_frames_.pop_front(); 67 } 68 if (!frame_to_add) { 69 if (empty_frames_.size() + incoming_frames_.size() > 70 KMaxNumberOfFrames) { 71 // Already allocated too many frames. 72 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, 73 -1, "%s: too many frames, timestamp=%u, limit=%d", 74 __FUNCTION__, new_frame->timestamp(), KMaxNumberOfFrames); 75 return -1; 76 } 77 78 // Allocate new memory. 79 WEBRTC_TRACE(kTraceMemory, kTraceVideoRenderer, -1, 80 "%s: allocating buffer %d", __FUNCTION__, 81 empty_frames_.size() + incoming_frames_.size()); 82 83 frame_to_add = new I420VideoFrame(); 84 if (!frame_to_add) { 85 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1, 86 "%s: could not create new frame for", __FUNCTION__); 87 return -1; 88 } 89 } 90 91 frame_to_add->CreateEmptyFrame(new_frame->width(), new_frame->height(), 92 new_frame->stride(kYPlane), 93 new_frame->stride(kUPlane), 94 new_frame->stride(kVPlane)); 95 // TODO(mflodman) Change this! 96 // Remove const ness. Copying will be costly. 97 frame_to_add->SwapFrame(new_frame); 98 incoming_frames_.push_back(frame_to_add); 99 100 return static_cast<int32_t>(incoming_frames_.size()); 101 } 102 103 I420VideoFrame* VideoRenderFrames::FrameToRender() { 104 I420VideoFrame* render_frame = NULL; 105 FrameList::iterator iter = incoming_frames_.begin(); 106 while(iter != incoming_frames_.end()) { 107 I420VideoFrame* oldest_frame_in_list = *iter; 108 if (oldest_frame_in_list->render_time_ms() <= 109 TickTime::MillisecondTimestamp() + render_delay_ms_) { 110 // This is the oldest one so far and it's OK to render. 111 if (render_frame) { 112 // This one is older than the newly found frame, remove this one. 113 ReturnFrame(render_frame); 114 } 115 render_frame = oldest_frame_in_list; 116 iter = incoming_frames_.erase(iter); 117 } else { 118 // We can't release this one yet, we're done here. 119 break; 120 } 121 } 122 return render_frame; 123 } 124 125 int32_t VideoRenderFrames::ReturnFrame(I420VideoFrame* old_frame) { 126 // No need to reuse texture frames because they do not allocate memory. 127 if (old_frame->native_handle() == NULL) { 128 old_frame->ResetSize(); 129 old_frame->set_timestamp(0); 130 old_frame->set_render_time_ms(0); 131 empty_frames_.push_back(old_frame); 132 } else { 133 delete old_frame; 134 } 135 return 0; 136 } 137 138 int32_t VideoRenderFrames::ReleaseAllFrames() { 139 for (FrameList::iterator iter = incoming_frames_.begin(); 140 iter != incoming_frames_.end(); ++iter) { 141 delete *iter; 142 } 143 incoming_frames_.clear(); 144 145 for (FrameList::iterator iter = empty_frames_.begin(); 146 iter != empty_frames_.end(); ++iter) { 147 delete *iter; 148 } 149 empty_frames_.clear(); 150 return 0; 151 } 152 153 uint32_t VideoRenderFrames::TimeToNextFrameRelease() { 154 if (incoming_frames_.empty()) { 155 return KEventMaxWaitTimeMs; 156 } 157 I420VideoFrame* oldest_frame = incoming_frames_.front(); 158 int64_t time_to_release = oldest_frame->render_time_ms() - render_delay_ms_ 159 - TickTime::MillisecondTimestamp(); 160 if (time_to_release < 0) { 161 time_to_release = 0; 162 } 163 return static_cast<uint32_t>(time_to_release); 164 } 165 166 int32_t VideoRenderFrames::SetRenderDelay( 167 const uint32_t render_delay) { 168 if (render_delay < kMinRenderDelayMs || 169 render_delay > kMaxRenderDelayMs) { 170 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, 171 -1, "%s(%d): Invalid argument.", __FUNCTION__, 172 render_delay); 173 return -1; 174 } 175 176 render_delay_ms_ = render_delay; 177 return 0; 178 } 179 180 } // namespace webrtc 181