blob: 80b3d59af3100a5402ab2b62f20670fe602f9fd5 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mflodman@webrtc.org327ada12012-05-30 10:45:18 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
andrew@webrtc.org9841d922012-10-31 05:22:11 +000011#include "webrtc/modules/video_render//video_render_frames.h"
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000015#include "webrtc/modules/interface/module_common_types.h"
16#include "webrtc/system_wrappers/interface/tick_util.h"
17#include "webrtc/system_wrappers/interface/trace.h"
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000018
niklase@google.com470e71d2011-07-07 08:21:25 +000019namespace webrtc {
20
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +000021const int32_t KEventMaxWaitTimeMs = 200;
22const uint32_t kMinRenderDelayMs = 10;
23const uint32_t kMaxRenderDelayMs= 500;
niklase@google.com470e71d2011-07-07 08:21:25 +000024
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000025VideoRenderFrames::VideoRenderFrames()
26 : incoming_frames_(),
27 render_delay_ms_(10) {
28}
29
30VideoRenderFrames::~VideoRenderFrames() {
31 ReleaseAllFrames();
32}
33
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +000034int32_t VideoRenderFrames::AddFrame(I420VideoFrame* new_frame) {
35 const int64_t time_now = TickTime::MillisecondTimestamp();
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000036
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000037 if (new_frame->render_time_ms() + KOldRenderTimestampMS < time_now) {
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000038 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
hclam@chromium.org0d540c32013-05-21 00:16:01 +000039 "%s: too old frame, timestamp=%u.",
40 __FUNCTION__, new_frame->timestamp());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000041 return -1;
42 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000043 if (new_frame->render_time_ms() > time_now + KFutureRenderTimestampMS) {
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000044 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
hclam@chromium.org0d540c32013-05-21 00:16:01 +000045 "%s: frame too long into the future, timestamp=%u.",
46 __FUNCTION__, new_frame->timestamp());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000047 return -1;
48 }
49
50 // Get an empty frame
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000051 I420VideoFrame* frame_to_add = NULL;
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000052 if (!empty_frames_.Empty()) {
53 ListItem* item = empty_frames_.First();
54 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000055 frame_to_add = static_cast<I420VideoFrame*>(item->GetItem());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000056 empty_frames_.Erase(item);
57 }
58 }
59 if (!frame_to_add) {
60 if (empty_frames_.GetSize() + incoming_frames_.GetSize() >
61 KMaxNumberOfFrames) {
62 // Already allocated too many frames.
63 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer,
hclam@chromium.org0d540c32013-05-21 00:16:01 +000064 -1, "%s: too many frames, timestamp=%u, limit=%d",
65 __FUNCTION__, new_frame->timestamp(), KMaxNumberOfFrames);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000066 return -1;
67 }
68
69 // Allocate new memory.
70 WEBRTC_TRACE(kTraceMemory, kTraceVideoRenderer, -1,
71 "%s: allocating buffer %d", __FUNCTION__,
72 empty_frames_.GetSize() + incoming_frames_.GetSize());
73
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000074 frame_to_add = new I420VideoFrame();
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000075 if (!frame_to_add) {
76 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
77 "%s: could not create new frame for", __FUNCTION__);
78 return -1;
79 }
80 }
81
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000082 frame_to_add->CreateEmptyFrame(new_frame->width(), new_frame->height(),
83 new_frame->stride(kYPlane),
84 new_frame->stride(kUPlane),
85 new_frame->stride(kVPlane));
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000086 // TODO(mflodman) Change this!
87 // Remove const ness. Copying will be costly.
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000088 frame_to_add->SwapFrame(new_frame);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000089 incoming_frames_.PushBack(frame_to_add);
90
91 return incoming_frames_.GetSize();
92}
93
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000094I420VideoFrame* VideoRenderFrames::FrameToRender() {
95 I420VideoFrame* render_frame = NULL;
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000096 while (!incoming_frames_.Empty()) {
97 ListItem* item = incoming_frames_.First();
98 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000099 I420VideoFrame* oldest_frame_in_list =
100 static_cast<I420VideoFrame*>(item->GetItem());
101 if (oldest_frame_in_list->render_time_ms() <=
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000102 TickTime::MillisecondTimestamp() + render_delay_ms_) {
103 // This is the oldest one so far and it's OK to render.
104 if (render_frame) {
105 // This one is older than the newly found frame, remove this one.
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000106 render_frame->ResetSize();
107 render_frame->set_timestamp(0);
108 render_frame->set_render_time_ms(0);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000109 empty_frames_.PushFront(render_frame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 }
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000111 render_frame = oldest_frame_in_list;
112 incoming_frames_.Erase(item);
113 } else {
114 // We can't release this one yet, we're done here.
115 break;
116 }
117 } else {
118 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000119 }
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000120 }
121 return render_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000122}
123
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000124int32_t VideoRenderFrames::ReturnFrame(I420VideoFrame* old_frame) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000125 old_frame->ResetSize();
126 old_frame->set_timestamp(0);
127 old_frame->set_render_time_ms(0);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000128 empty_frames_.PushBack(old_frame);
129 return 0;
130}
131
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000132int32_t VideoRenderFrames::ReleaseAllFrames() {
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000133 while (!incoming_frames_.Empty()) {
134 ListItem* item = incoming_frames_.First();
135 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000136 I420VideoFrame* frame = static_cast<I420VideoFrame*>(item->GetItem());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000137 assert(frame != NULL);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000138 delete frame;
139 }
140 incoming_frames_.Erase(item);
141 }
142 while (!empty_frames_.Empty()) {
143 ListItem* item = empty_frames_.First();
144 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000145 I420VideoFrame* frame = static_cast<I420VideoFrame*>(item->GetItem());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000146 assert(frame != NULL);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000147 delete frame;
148 }
149 empty_frames_.Erase(item);
150 }
151 return 0;
152}
153
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000154uint32_t VideoRenderFrames::TimeToNextFrameRelease() {
155 int64_t time_to_release = 0;
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000156 ListItem* item = incoming_frames_.First();
157 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000158 I420VideoFrame* oldest_frame =
159 static_cast<I420VideoFrame*>(item->GetItem());
160 time_to_release = oldest_frame->render_time_ms() - render_delay_ms_
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000161 - TickTime::MillisecondTimestamp();
162 if (time_to_release < 0) {
163 time_to_release = 0;
164 }
165 } else {
166 time_to_release = KEventMaxWaitTimeMs;
167 }
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000168 return static_cast<uint32_t>(time_to_release);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000169}
170
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000171int32_t VideoRenderFrames::SetRenderDelay(
172 const uint32_t render_delay) {
mflodman@webrtc.orgf4f21452012-09-28 11:27:35 +0000173 if (render_delay < kMinRenderDelayMs ||
174 render_delay > kMaxRenderDelayMs) {
175 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer,
176 -1, "%s(%d): Invalid argument.", __FUNCTION__,
177 render_delay);
178 return -1;
179 }
180
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000181 render_delay_ms_ = render_delay;
182 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000183}
184
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000185} // namespace webrtc