Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/webrtc/modules/video_render/video_render_frames.cc @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 6.2 KB
Line 
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
20namespace webrtc {
21
22const int32_t KEventMaxWaitTimeMs = 200;
23const uint32_t kMinRenderDelayMs = 10;
24const uint32_t kMaxRenderDelayMs= 500;
25
26VideoRenderFrames::VideoRenderFrames()
27    : incoming_frames_(),
28      render_delay_ms_(10) {
29}
30
31VideoRenderFrames::~VideoRenderFrames() {
32  ReleaseAllFrames();
33}
34
35int32_t VideoRenderFrames::AddFrame(I420VideoFrame* new_frame) {
36  const int64_t time_now = TickTime::MillisecondTimestamp();
37
38  if (new_frame->render_time_ms() + KOldRenderTimestampMS < time_now) {
39    WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
40                 "%s: too old frame, timestamp=%u.",
41                 __FUNCTION__, new_frame->timestamp());
42    return -1;
43  }
44  if (new_frame->render_time_ms() > time_now + KFutureRenderTimestampMS) {
45    WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
46                 "%s: frame too long into the future, timestamp=%u.",
47                 __FUNCTION__, new_frame->timestamp());
48    return -1;
49  }
50
51  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
61  // Get an empty frame
62  I420VideoFrame* frame_to_add = NULL;
63  if (!empty_frames_.Empty()) {
64    ListItem* item = empty_frames_.First();
65    if (item) {
66      frame_to_add = static_cast<I420VideoFrame*>(item->GetItem());
67      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,
75                   -1, "%s: too many frames, timestamp=%u, limit=%d",
76                   __FUNCTION__, new_frame->timestamp(), KMaxNumberOfFrames);
77      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
85    frame_to_add = new I420VideoFrame();
86    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
93  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));
97  // TODO(mflodman) Change this!
98  // Remove const ness. Copying will be costly.
99  frame_to_add->SwapFrame(new_frame);
100  incoming_frames_.PushBack(frame_to_add);
101
102  return incoming_frames_.GetSize();
103}
104
105I420VideoFrame* VideoRenderFrames::FrameToRender() {
106  I420VideoFrame* render_frame = NULL;
107  while (!incoming_frames_.Empty()) {
108    ListItem* item = incoming_frames_.First();
109    if (item) {
110      I420VideoFrame* oldest_frame_in_list =
111          static_cast<I420VideoFrame*>(item->GetItem());
112      if (oldest_frame_in_list->render_time_ms() <=
113          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.
117          ReturnFrame(render_frame);
118        }
119        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);
127    }
128  }
129  return render_frame;
130}
131
132int32_t VideoRenderFrames::ReturnFrame(I420VideoFrame* old_frame) {
133  // 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  }
142  return 0;
143}
144
145int32_t VideoRenderFrames::ReleaseAllFrames() {
146  while (!incoming_frames_.Empty()) {
147    ListItem* item = incoming_frames_.First();
148    if (item) {
149      I420VideoFrame* frame = static_cast<I420VideoFrame*>(item->GetItem());
150      assert(frame != NULL);
151      delete frame;
152    }
153    incoming_frames_.Erase(item);
154  }
155  while (!empty_frames_.Empty()) {
156    ListItem* item = empty_frames_.First();
157    if (item) {
158      I420VideoFrame* frame = static_cast<I420VideoFrame*>(item->GetItem());
159      assert(frame != NULL);
160      delete frame;
161    }
162    empty_frames_.Erase(item);
163  }
164  return 0;
165}
166
167uint32_t VideoRenderFrames::TimeToNextFrameRelease() {
168  int64_t time_to_release = 0;
169  ListItem* item = incoming_frames_.First();
170  if (item) {
171    I420VideoFrame* oldest_frame =
172        static_cast<I420VideoFrame*>(item->GetItem());
173    time_to_release = oldest_frame->render_time_ms() - render_delay_ms_
174                      - TickTime::MillisecondTimestamp();
175    if (time_to_release < 0) {
176      time_to_release = 0;
177    }
178  } else {
179    time_to_release = KEventMaxWaitTimeMs;
180  }
181  return static_cast<uint32_t>(time_to_release);
182}
183
184int32_t VideoRenderFrames::SetRenderDelay(
185    const uint32_t render_delay) {
186  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
194  render_delay_ms_ = render_delay;
195  return 0;
196}
197
198}  // namespace webrtc
Note: See TracBrowser for help on using the repository browser.