/* * 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_); if (incoming_external_callback_) delete incoming_external_callback_; } int32_t ViERenderer::StartRender() { return render_module_.StartRender(render_id_); } int32_t ViERenderer::StopRender() { return render_module_.StopRender(render_id_); } int32_t ViERenderer::GetLastRenderedFrame(const int32_t renderID, I420VideoFrame& video_frame) { return render_module_.GetLastRenderedFrame(renderID, video_frame); } 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::EnableMirroring(const int32_t render_id, const bool enable, const bool mirror_xaxis, const bool mirror_yaxis) { return render_module_.MirrorRenderStream(render_id, enable, mirror_xaxis, mirror_yaxis); } 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, I420VideoFrame* video_frame, int num_csrcs, const uint32_t CSRC[kRtpCsrcSize]) { 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), converted_frame_(new VideoFrame()) { } 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, 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.render_time_ms(), video_frame.native_handle()); } else { // TODO(wuchengli): readback the pixels and deliver the frame. } return 0; } VideoFrame* out_frame = converted_frame_.get(); // Convert to requested format. VideoType type = RawVideoTypeToCommonVideoVideoType(external_renderer_format_); int buffer_size = CalcBufferSize(type, video_frame.width(), video_frame.height()); if (buffer_size <= 0) { // Unsupported video format. assert(false); return -1; } converted_frame_->VerifyAndAllocate(buffer_size); switch (external_renderer_format_) { case kVideoI420: { // TODO(mikhal): need to copy the buffer as is. // can the output here be a I420 frame? int length = ExtractBuffer(video_frame, out_frame->Size(), out_frame->Buffer()); if (length < 0) return -1; out_frame->SetLength(length); break; } case kVideoYV12: case kVideoYUY2: case kVideoUYVY: case kVideoARGB: case kVideoRGB24: case kVideoRGB565: case kVideoARGB4444: case kVideoARGB1555 : { if (ConvertFromI420(video_frame, type, 0, converted_frame_->Buffer()) < 0) return -1; converted_frame_->SetLength(buffer_size); } 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->Buffer(), out_frame->Length(), video_frame.timestamp(), video_frame.render_time_ms(), NULL); } return 0; } void ViEExternalRendererImpl::NotifyFrameSizeChange( const uint32_t stream_id, 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