/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/video_engine/vie_renderer.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" #include "webrtc/modules/video_render/include/video_render.h" #include "webrtc/modules/video_render/include/video_render_defines.h" #include "webrtc/video_engine/vie_render_manager.h" namespace webrtc { ViERenderer* ViERenderer::CreateViERenderer(const int32_t render_id, const int32_t engine_id, VideoRender& render_module, ViERenderManager& render_manager, const uint32_t z_order, const float left, const float top, const float right, const float bottom) { ViERenderer* self = new ViERenderer(render_id, engine_id, render_module, render_manager); if (!self || self->Init(z_order, left, top, right, bottom) != 0) { delete self; self = NULL; } return self; } ViERenderer::~ViERenderer(void) { if (render_callback_) render_module_.DeleteIncomingRenderStream(render_id_); delete incoming_external_callback_; } int32_t ViERenderer::StartRender() { return render_module_.StartRender(render_id_); } int32_t ViERenderer::StopRender() { return render_module_.StopRender(render_id_); } int ViERenderer::SetExpectedRenderDelay(int render_delay) { return render_module_.SetExpectedRenderDelay(render_id_, render_delay); } int32_t ViERenderer::ConfigureRenderer(const unsigned int z_order, const float left, const float top, const float right, const float bottom) { return render_module_.ConfigureRenderer(render_id_, z_order, left, top, right, bottom); } VideoRender& ViERenderer::RenderModule() { return render_module_; } int32_t ViERenderer::SetTimeoutImage(const I420VideoFrame& timeout_image, const int32_t timeout_value) { return render_module_.SetTimeoutImage(render_id_, timeout_image, timeout_value); } int32_t ViERenderer::SetRenderStartImage( const I420VideoFrame& start_image) { return render_module_.SetStartImage(render_id_, start_image); } int32_t ViERenderer::SetExternalRenderer( const int32_t render_id, RawVideoType video_input_format, ExternalRenderer* external_renderer) { if (!incoming_external_callback_) return -1; incoming_external_callback_->SetViEExternalRenderer(external_renderer, video_input_format); return render_module_.AddExternalRenderCallback(render_id, incoming_external_callback_); } int32_t ViERenderer::SetVideoRenderCallback(int32_t render_id, VideoRenderCallback* callback) { return render_module_.AddExternalRenderCallback(render_id, callback); } ViERenderer::ViERenderer(const int32_t render_id, const int32_t engine_id, VideoRender& render_module, ViERenderManager& render_manager) : render_id_(render_id), render_module_(render_module), render_manager_(render_manager), render_callback_(NULL), incoming_external_callback_(new ViEExternalRendererImpl()) { } int32_t ViERenderer::Init(const uint32_t z_order, const float left, const float top, const float right, const float bottom) { render_callback_ = static_cast(render_module_.AddIncomingRenderStream( render_id_, z_order, left, top, right, bottom)); if (!render_callback_) { // Logging done. return -1; } return 0; } void ViERenderer::DeliverFrame(int id, const I420VideoFrame& video_frame, const std::vector& csrcs) { render_callback_->RenderFrame(render_id_, video_frame); } void ViERenderer::DelayChanged(int id, int frame_delay) {} int ViERenderer::GetPreferedFrameSettings(int* width, int* height, int* frame_rate) { return -1; } void ViERenderer::ProviderDestroyed(int id) { // Remove the render stream since the provider is destroyed. render_manager_.RemoveRenderStream(render_id_); } ViEExternalRendererImpl::ViEExternalRendererImpl() : external_renderer_(NULL), external_renderer_format_(kVideoUnknown), external_renderer_width_(0), external_renderer_height_(0) { } int ViEExternalRendererImpl::SetViEExternalRenderer( ExternalRenderer* external_renderer, RawVideoType video_input_format) { external_renderer_ = external_renderer; external_renderer_format_ = video_input_format; return 0; } int32_t ViEExternalRendererImpl::RenderFrame( const uint32_t stream_id, const I420VideoFrame& video_frame) { if (external_renderer_format_ != kVideoI420) return ConvertAndRenderFrame(stream_id, video_frame); // Fast path for I420 without frame copy. NotifyFrameSizeChange(stream_id, video_frame); if (video_frame.native_handle() == NULL || external_renderer_->IsTextureSupported()) { external_renderer_->DeliverI420Frame(video_frame); } else { // TODO(wuchengli): readback the pixels and deliver the frame. } return 0; } int32_t ViEExternalRendererImpl::ConvertAndRenderFrame( uint32_t stream_id, const I420VideoFrame& video_frame) { if (video_frame.native_handle() != NULL) { NotifyFrameSizeChange(stream_id, video_frame); if (external_renderer_->IsTextureSupported()) { external_renderer_->DeliverFrame(NULL, 0, video_frame.timestamp(), video_frame.ntp_time_ms(), video_frame.render_time_ms(), video_frame.native_handle()); } else { // TODO(wuchengli): readback the pixels and deliver the frame. } return 0; } // Convert to requested format. VideoType type = RawVideoTypeToCommonVideoVideoType(external_renderer_format_); size_t buffer_size = CalcBufferSize(type, video_frame.width(), video_frame.height()); if (buffer_size == 0) { // Unsupported video format. assert(false); return -1; } converted_frame_.resize(buffer_size); uint8_t* out_frame = &converted_frame_[0]; switch (external_renderer_format_) { case kVideoYV12: case kVideoYUY2: case kVideoUYVY: case kVideoARGB: case kVideoRGB24: case kVideoRGB565: case kVideoARGB4444: case kVideoARGB1555: if (ConvertFromI420(video_frame, type, 0, out_frame) < 0) return -1; break; case kVideoIYUV: // no conversion available break; default: assert(false); out_frame = NULL; break; } NotifyFrameSizeChange(stream_id, video_frame); if (out_frame) { external_renderer_->DeliverFrame(out_frame, converted_frame_.size(), video_frame.timestamp(), video_frame.ntp_time_ms(), video_frame.render_time_ms(), NULL); } return 0; } void ViEExternalRendererImpl::NotifyFrameSizeChange( const uint32_t stream_id, const I420VideoFrame& video_frame) { if (external_renderer_width_ != video_frame.width() || external_renderer_height_ != video_frame.height()) { external_renderer_width_ = video_frame.width(); external_renderer_height_ = video_frame.height(); external_renderer_->FrameSizeChange( external_renderer_width_, external_renderer_height_, stream_id); } } } // namespace webrtc