| /* | 
 |  *  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<VideoRenderCallback*>(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, | 
 |                                const std::vector<uint32_t>& 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), | 
 |       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.ntp_time_ms(), | 
 |                                        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_); | 
 |   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_->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.ntp_time_ms(), | 
 |                                      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 |