blob: be5cac9aaa6fa198dde72ddf20ad143b98fea459 [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
wu@webrtc.org9dba5252013-08-05 20:36:57 +000015#include "webrtc/common_video/interface/texture_video_frame.h"
pbos@webrtc.org5aa3f1b2013-07-12 08:12:08 +000016#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"
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000019
niklase@google.com470e71d2011-07-07 08:21:25 +000020namespace webrtc {
21
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +000022const int32_t KEventMaxWaitTimeMs = 200;
23const uint32_t kMinRenderDelayMs = 10;
24const uint32_t kMaxRenderDelayMs= 500;
niklase@google.com470e71d2011-07-07 08:21:25 +000025
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000026VideoRenderFrames::VideoRenderFrames()
27 : incoming_frames_(),
28 render_delay_ms_(10) {
29}
30
31VideoRenderFrames::~VideoRenderFrames() {
32 ReleaseAllFrames();
33}
34
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +000035int32_t VideoRenderFrames::AddFrame(I420VideoFrame* new_frame) {
36 const int64_t time_now = TickTime::MillisecondTimestamp();
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000037
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000038 if (new_frame->render_time_ms() + KOldRenderTimestampMS < time_now) {
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000039 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
hclam@chromium.org0d540c32013-05-21 00:16:01 +000040 "%s: too old frame, timestamp=%u.",
41 __FUNCTION__, new_frame->timestamp());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000042 return -1;
43 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000044 if (new_frame->render_time_ms() > time_now + KFutureRenderTimestampMS) {
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000045 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
hclam@chromium.org0d540c32013-05-21 00:16:01 +000046 "%s: frame too long into the future, timestamp=%u.",
47 __FUNCTION__, new_frame->timestamp());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000048 return -1;
49 }
50
wu@webrtc.org9dba5252013-08-05 20:36:57 +000051 if (new_frame->native_handle() != NULL) {
52 incoming_frames_.PushBack(new TextureVideoFrame(
53 static_cast<NativeHandle*>(new_frame->native_handle()),
54 new_frame->width(),
55 new_frame->height(),
56 new_frame->timestamp(),
57 new_frame->render_time_ms()));
58 return incoming_frames_.GetSize();
59 }
60
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000061 // Get an empty frame
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000062 I420VideoFrame* frame_to_add = NULL;
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000063 if (!empty_frames_.Empty()) {
64 ListItem* item = empty_frames_.First();
65 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000066 frame_to_add = static_cast<I420VideoFrame*>(item->GetItem());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000067 empty_frames_.Erase(item);
68 }
69 }
70 if (!frame_to_add) {
71 if (empty_frames_.GetSize() + incoming_frames_.GetSize() >
72 KMaxNumberOfFrames) {
73 // Already allocated too many frames.
74 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer,
hclam@chromium.org0d540c32013-05-21 00:16:01 +000075 -1, "%s: too many frames, timestamp=%u, limit=%d",
76 __FUNCTION__, new_frame->timestamp(), KMaxNumberOfFrames);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000077 return -1;
78 }
79
80 // Allocate new memory.
81 WEBRTC_TRACE(kTraceMemory, kTraceVideoRenderer, -1,
82 "%s: allocating buffer %d", __FUNCTION__,
83 empty_frames_.GetSize() + incoming_frames_.GetSize());
84
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000085 frame_to_add = new I420VideoFrame();
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000086 if (!frame_to_add) {
87 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,
88 "%s: could not create new frame for", __FUNCTION__);
89 return -1;
90 }
91 }
92
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000093 frame_to_add->CreateEmptyFrame(new_frame->width(), new_frame->height(),
94 new_frame->stride(kYPlane),
95 new_frame->stride(kUPlane),
96 new_frame->stride(kVPlane));
mflodman@webrtc.org327ada12012-05-30 10:45:18 +000097 // TODO(mflodman) Change this!
98 // Remove const ness. Copying will be costly.
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000099 frame_to_add->SwapFrame(new_frame);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000100 incoming_frames_.PushBack(frame_to_add);
101
102 return incoming_frames_.GetSize();
103}
104
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000105I420VideoFrame* VideoRenderFrames::FrameToRender() {
106 I420VideoFrame* render_frame = NULL;
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000107 while (!incoming_frames_.Empty()) {
108 ListItem* item = incoming_frames_.First();
109 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000110 I420VideoFrame* oldest_frame_in_list =
111 static_cast<I420VideoFrame*>(item->GetItem());
112 if (oldest_frame_in_list->render_time_ms() <=
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000113 TickTime::MillisecondTimestamp() + render_delay_ms_) {
114 // This is the oldest one so far and it's OK to render.
115 if (render_frame) {
116 // This one is older than the newly found frame, remove this one.
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000117 ReturnFrame(render_frame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 }
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000119 render_frame = oldest_frame_in_list;
120 incoming_frames_.Erase(item);
121 } else {
122 // We can't release this one yet, we're done here.
123 break;
124 }
125 } else {
126 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000127 }
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000128 }
129 return render_frame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000130}
131
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000132int32_t VideoRenderFrames::ReturnFrame(I420VideoFrame* old_frame) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000133 // No need to reuse texture frames because they do not allocate memory.
134 if (old_frame->native_handle() == NULL) {
135 old_frame->ResetSize();
136 old_frame->set_timestamp(0);
137 old_frame->set_render_time_ms(0);
138 empty_frames_.PushBack(old_frame);
139 } else {
140 delete old_frame;
141 }
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000142 return 0;
143}
144
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000145int32_t VideoRenderFrames::ReleaseAllFrames() {
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000146 while (!incoming_frames_.Empty()) {
147 ListItem* item = incoming_frames_.First();
148 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000149 I420VideoFrame* frame = static_cast<I420VideoFrame*>(item->GetItem());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000150 assert(frame != NULL);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000151 delete frame;
152 }
153 incoming_frames_.Erase(item);
154 }
155 while (!empty_frames_.Empty()) {
156 ListItem* item = empty_frames_.First();
157 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000158 I420VideoFrame* frame = static_cast<I420VideoFrame*>(item->GetItem());
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000159 assert(frame != NULL);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000160 delete frame;
161 }
162 empty_frames_.Erase(item);
163 }
164 return 0;
165}
166
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000167uint32_t VideoRenderFrames::TimeToNextFrameRelease() {
168 int64_t time_to_release = 0;
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000169 ListItem* item = incoming_frames_.First();
170 if (item) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000171 I420VideoFrame* oldest_frame =
172 static_cast<I420VideoFrame*>(item->GetItem());
173 time_to_release = oldest_frame->render_time_ms() - render_delay_ms_
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000174 - TickTime::MillisecondTimestamp();
175 if (time_to_release < 0) {
176 time_to_release = 0;
177 }
178 } else {
179 time_to_release = KEventMaxWaitTimeMs;
180 }
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000181 return static_cast<uint32_t>(time_to_release);
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000182}
183
pbos@webrtc.orgddf94e72013-04-10 08:09:04 +0000184int32_t VideoRenderFrames::SetRenderDelay(
185 const uint32_t render_delay) {
mflodman@webrtc.orgf4f21452012-09-28 11:27:35 +0000186 if (render_delay < kMinRenderDelayMs ||
187 render_delay > kMaxRenderDelayMs) {
188 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer,
189 -1, "%s(%d): Invalid argument.", __FUNCTION__,
190 render_delay);
191 return -1;
192 }
193
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000194 render_delay_ms_ = render_delay;
195 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000196}
197
mflodman@webrtc.org327ada12012-05-30 10:45:18 +0000198} // namespace webrtc