1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/* 2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Use of this source code is governed by a BSD-style license 5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * that can be found in the LICENSE file in the root of the source 6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * tree. An additional intellectual property rights grant can be found 7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * in the file PATENTS. All contributing project authors may 8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * be found in the AUTHORS file in the root of the source tree. 9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 11083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org#include "webrtc/modules/video_render/video_render_frames.h" 12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 133f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <assert.h> 14b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 15ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org#include "webrtc/common_video/interface/texture_video_frame.h" 167e5dc8741fbd5f07a709e6fd4d2cd8b08b7cee94pbos@webrtc.org#include "webrtc/modules/interface/module_common_types.h" 177e5dc8741fbd5f07a709e6fd4d2cd8b08b7cee94pbos@webrtc.org#include "webrtc/system_wrappers/interface/tick_util.h" 187e5dc8741fbd5f07a709e6fd4d2cd8b08b7cee94pbos@webrtc.org#include "webrtc/system_wrappers/interface/trace.h" 19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc { 21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 22083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.orgconst uint32_t KEventMaxWaitTimeMs = 200; 23e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.orgconst uint32_t kMinRenderDelayMs = 10; 24e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.orgconst uint32_t kMaxRenderDelayMs= 500; 25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVideoRenderFrames::VideoRenderFrames() 27083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org : render_delay_ms_(10) { 28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVideoRenderFrames::~VideoRenderFrames() { 31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ReleaseAllFrames(); 32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 34e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.orgint32_t VideoRenderFrames::AddFrame(I420VideoFrame* new_frame) { 35e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.org const int64_t time_now = TickTime::MillisecondTimestamp(); 36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 37d60137ff1b936534b04396298b7d2f2ebbc1da82pbos@webrtc.org // Drop old frames only when there are other frames in the queue, otherwise, a 38d60137ff1b936534b04396298b7d2f2ebbc1da82pbos@webrtc.org // really slow system never renders any frames. 39083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org if (!incoming_frames_.empty() && 40d60137ff1b936534b04396298b7d2f2ebbc1da82pbos@webrtc.org new_frame->render_time_ms() + KOldRenderTimestampMS < time_now) { 41d60137ff1b936534b04396298b7d2f2ebbc1da82pbos@webrtc.org WEBRTC_TRACE(kTraceWarning, 42d60137ff1b936534b04396298b7d2f2ebbc1da82pbos@webrtc.org kTraceVideoRenderer, 43d60137ff1b936534b04396298b7d2f2ebbc1da82pbos@webrtc.org -1, 4415bdfdfd464bfb1226ada48219890e3139d820afhclam@chromium.org "%s: too old frame, timestamp=%u.", 45d60137ff1b936534b04396298b7d2f2ebbc1da82pbos@webrtc.org __FUNCTION__, 46d60137ff1b936534b04396298b7d2f2ebbc1da82pbos@webrtc.org new_frame->timestamp()); 47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 49d60137ff1b936534b04396298b7d2f2ebbc1da82pbos@webrtc.org 503bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org if (new_frame->render_time_ms() > time_now + KFutureRenderTimestampMS) { 51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1, 5215bdfdfd464bfb1226ada48219890e3139d820afhclam@chromium.org "%s: frame too long into the future, timestamp=%u.", 5315bdfdfd464bfb1226ada48219890e3139d820afhclam@chromium.org __FUNCTION__, new_frame->timestamp()); 54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 57ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org if (new_frame->native_handle() != NULL) { 581bdf186e6ae8d2f1a7d055237a75c0d7fd189624wuchengli@chromium.org incoming_frames_.push_back(new_frame->CloneFrame()); 59083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org return static_cast<int32_t>(incoming_frames_.size()); 60ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org } 61ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org 62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Get an empty frame 633bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org I420VideoFrame* frame_to_add = NULL; 64083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org if (!empty_frames_.empty()) { 65083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org frame_to_add = empty_frames_.front(); 66083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org empty_frames_.pop_front(); 67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!frame_to_add) { 69083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org if (empty_frames_.size() + incoming_frames_.size() > 70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org KMaxNumberOfFrames) { 71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Already allocated too many frames. 72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, 7315bdfdfd464bfb1226ada48219890e3139d820afhclam@chromium.org -1, "%s: too many frames, timestamp=%u, limit=%d", 7415bdfdfd464bfb1226ada48219890e3139d820afhclam@chromium.org __FUNCTION__, new_frame->timestamp(), KMaxNumberOfFrames); 75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Allocate new memory. 79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceMemory, kTraceVideoRenderer, -1, 80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "%s: allocating buffer %d", __FUNCTION__, 81083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org empty_frames_.size() + incoming_frames_.size()); 82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 833bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org frame_to_add = new I420VideoFrame(); 84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (!frame_to_add) { 85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1, 86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "%s: could not create new frame for", __FUNCTION__); 87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 913bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org frame_to_add->CreateEmptyFrame(new_frame->width(), new_frame->height(), 923bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org new_frame->stride(kYPlane), 933bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org new_frame->stride(kUPlane), 943bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org new_frame->stride(kVPlane)); 95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(mflodman) Change this! 96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Remove const ness. Copying will be costly. 973bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org frame_to_add->SwapFrame(new_frame); 98083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org incoming_frames_.push_back(frame_to_add); 99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 100083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org return static_cast<int32_t>(incoming_frames_.size()); 101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1033bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.orgI420VideoFrame* VideoRenderFrames::FrameToRender() { 1043bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org I420VideoFrame* render_frame = NULL; 105083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org FrameList::iterator iter = incoming_frames_.begin(); 106083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org while(iter != incoming_frames_.end()) { 107083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org I420VideoFrame* oldest_frame_in_list = *iter; 108083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org if (oldest_frame_in_list->render_time_ms() <= 109083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org TickTime::MillisecondTimestamp() + render_delay_ms_) { 110083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org // This is the oldest one so far and it's OK to render. 111083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org if (render_frame) { 112083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org // This one is older than the newly found frame, remove this one. 113083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org ReturnFrame(render_frame); 114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 115083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org render_frame = oldest_frame_in_list; 116083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org iter = incoming_frames_.erase(iter); 117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else { 118083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org // We can't release this one yet, we're done here. 119083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org break; 120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return render_frame; 123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 125e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.orgint32_t VideoRenderFrames::ReturnFrame(I420VideoFrame* old_frame) { 126ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org // No need to reuse texture frames because they do not allocate memory. 127ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org if (old_frame->native_handle() == NULL) { 128ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org old_frame->ResetSize(); 129ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org old_frame->set_timestamp(0); 130ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org old_frame->set_render_time_ms(0); 131083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org empty_frames_.push_back(old_frame); 132ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org } else { 133ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org delete old_frame; 134ea7b33ee032bd2d1528384e26ba079dee0d280fbwu@webrtc.org } 135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 138e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.orgint32_t VideoRenderFrames::ReleaseAllFrames() { 139083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org for (FrameList::iterator iter = incoming_frames_.begin(); 140083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org iter != incoming_frames_.end(); ++iter) { 141083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org delete *iter; 142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 143083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org incoming_frames_.clear(); 144083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org 145083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org for (FrameList::iterator iter = empty_frames_.begin(); 146083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org iter != empty_frames_.end(); ++iter) { 147083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org delete *iter; 148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 149083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org empty_frames_.clear(); 150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 153e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.orguint32_t VideoRenderFrames::TimeToNextFrameRelease() { 154083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org if (incoming_frames_.empty()) { 155083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org return KEventMaxWaitTimeMs; 156083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org } 157083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org I420VideoFrame* oldest_frame = incoming_frames_.front(); 158083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org int64_t time_to_release = oldest_frame->render_time_ms() - render_delay_ms_ 159083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org - TickTime::MillisecondTimestamp(); 160083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org if (time_to_release < 0) { 161083049f2945b2924203b25c8428300d40d994f35henrike@webrtc.org time_to_release = 0; 162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 163e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.org return static_cast<uint32_t>(time_to_release); 164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 166e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.orgint32_t VideoRenderFrames::SetRenderDelay( 167e1ca446434022ad0d05ebd5ed2feafb08ae940e3pbos@webrtc.org const uint32_t render_delay) { 168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (render_delay < kMinRenderDelayMs || 169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org render_delay > kMaxRenderDelayMs) { 170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, 171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org -1, "%s(%d): Invalid argument.", __FUNCTION__, 172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org render_delay); 173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org render_delay_ms_ = render_delay; 177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} // namespace webrtc 181