Home | History | Annotate | Download | only in video_engine
      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/video_engine/vie_renderer.h"
     12 
     13 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
     14 #include "webrtc/modules/video_render/include/video_render.h"
     15 #include "webrtc/modules/video_render/include/video_render_defines.h"
     16 #include "webrtc/video_engine/vie_render_manager.h"
     17 
     18 namespace webrtc {
     19 
     20 ViERenderer* ViERenderer::CreateViERenderer(const int32_t render_id,
     21                                             const int32_t engine_id,
     22                                             VideoRender& render_module,
     23                                             ViERenderManager& render_manager,
     24                                             const uint32_t z_order,
     25                                             const float left,
     26                                             const float top,
     27                                             const float right,
     28                                             const float bottom) {
     29   ViERenderer* self = new ViERenderer(render_id, engine_id, render_module,
     30                                       render_manager);
     31   if (!self || self->Init(z_order, left, top, right, bottom) != 0) {
     32     delete self;
     33     self = NULL;
     34   }
     35   return self;
     36 }
     37 
     38 ViERenderer::~ViERenderer(void) {
     39   if (render_callback_)
     40     render_module_.DeleteIncomingRenderStream(render_id_);
     41 
     42   if (incoming_external_callback_)
     43     delete incoming_external_callback_;
     44 }
     45 
     46 int32_t ViERenderer::StartRender() {
     47   return render_module_.StartRender(render_id_);
     48 }
     49 int32_t ViERenderer::StopRender() {
     50   return render_module_.StopRender(render_id_);
     51 }
     52 
     53 int32_t ViERenderer::GetLastRenderedFrame(const int32_t renderID,
     54                                           I420VideoFrame& video_frame) {
     55   return render_module_.GetLastRenderedFrame(renderID, video_frame);
     56 }
     57 
     58 int ViERenderer::SetExpectedRenderDelay(int render_delay) {
     59   return render_module_.SetExpectedRenderDelay(render_id_, render_delay);
     60 }
     61 
     62 int32_t ViERenderer::ConfigureRenderer(const unsigned int z_order,
     63                                        const float left,
     64                                        const float top,
     65                                        const float right,
     66                                        const float bottom) {
     67   return render_module_.ConfigureRenderer(render_id_, z_order, left, top, right,
     68                                           bottom);
     69 }
     70 
     71 VideoRender& ViERenderer::RenderModule() {
     72   return render_module_;
     73 }
     74 
     75 int32_t ViERenderer::EnableMirroring(const int32_t render_id,
     76                                      const bool enable,
     77                                      const bool mirror_xaxis,
     78                                      const bool mirror_yaxis) {
     79   return render_module_.MirrorRenderStream(render_id, enable, mirror_xaxis,
     80                                            mirror_yaxis);
     81 }
     82 
     83 int32_t ViERenderer::SetTimeoutImage(const I420VideoFrame& timeout_image,
     84                                      const int32_t timeout_value) {
     85   return render_module_.SetTimeoutImage(render_id_, timeout_image,
     86                                         timeout_value);
     87 }
     88 
     89 int32_t  ViERenderer::SetRenderStartImage(
     90     const I420VideoFrame& start_image) {
     91   return render_module_.SetStartImage(render_id_, start_image);
     92 }
     93 
     94 int32_t ViERenderer::SetExternalRenderer(
     95     const int32_t render_id,
     96     RawVideoType video_input_format,
     97     ExternalRenderer* external_renderer) {
     98   if (!incoming_external_callback_)
     99     return -1;
    100 
    101   incoming_external_callback_->SetViEExternalRenderer(external_renderer,
    102                                                       video_input_format);
    103   return render_module_.AddExternalRenderCallback(render_id,
    104                                                   incoming_external_callback_);
    105 }
    106 
    107 int32_t ViERenderer::SetVideoRenderCallback(int32_t render_id,
    108                                             VideoRenderCallback* callback) {
    109   return render_module_.AddExternalRenderCallback(render_id, callback);
    110 }
    111 
    112 ViERenderer::ViERenderer(const int32_t render_id,
    113                          const int32_t engine_id,
    114                          VideoRender& render_module,
    115                          ViERenderManager& render_manager)
    116     : render_id_(render_id),
    117       render_module_(render_module),
    118       render_manager_(render_manager),
    119       render_callback_(NULL),
    120       incoming_external_callback_(new ViEExternalRendererImpl()) {
    121 }
    122 
    123 int32_t ViERenderer::Init(const uint32_t z_order,
    124                           const float left,
    125                           const float top,
    126                           const float right,
    127                           const float bottom) {
    128   render_callback_ =
    129       static_cast<VideoRenderCallback*>(render_module_.AddIncomingRenderStream(
    130           render_id_, z_order, left, top, right, bottom));
    131   if (!render_callback_) {
    132     // Logging done.
    133     return -1;
    134   }
    135   return 0;
    136 }
    137 
    138 void ViERenderer::DeliverFrame(int id,
    139                                I420VideoFrame* video_frame,
    140                                int num_csrcs,
    141                                const uint32_t CSRC[kRtpCsrcSize]) {
    142   render_callback_->RenderFrame(render_id_, *video_frame);
    143 }
    144 
    145 void ViERenderer::DelayChanged(int id, int frame_delay) {}
    146 
    147 int ViERenderer::GetPreferedFrameSettings(int* width,
    148                                           int* height,
    149                                           int* frame_rate) {
    150     return -1;
    151 }
    152 
    153 void ViERenderer::ProviderDestroyed(int id) {
    154   // Remove the render stream since the provider is destroyed.
    155   render_manager_.RemoveRenderStream(render_id_);
    156 }
    157 
    158 ViEExternalRendererImpl::ViEExternalRendererImpl()
    159     : external_renderer_(NULL),
    160       external_renderer_format_(kVideoUnknown),
    161       external_renderer_width_(0),
    162       external_renderer_height_(0),
    163       converted_frame_(new VideoFrame()) {
    164 }
    165 
    166 int ViEExternalRendererImpl::SetViEExternalRenderer(
    167     ExternalRenderer* external_renderer,
    168     RawVideoType video_input_format) {
    169   external_renderer_ = external_renderer;
    170   external_renderer_format_ = video_input_format;
    171   return 0;
    172 }
    173 
    174 int32_t ViEExternalRendererImpl::RenderFrame(
    175     const uint32_t stream_id,
    176     I420VideoFrame&   video_frame) {
    177   if (video_frame.native_handle() != NULL) {
    178     NotifyFrameSizeChange(stream_id, video_frame);
    179 
    180     if (external_renderer_->IsTextureSupported()) {
    181       external_renderer_->DeliverFrame(NULL,
    182                                        0,
    183                                        video_frame.timestamp(),
    184                                        video_frame.ntp_time_ms(),
    185                                        video_frame.render_time_ms(),
    186                                        video_frame.native_handle());
    187     } else {
    188       // TODO(wuchengli): readback the pixels and deliver the frame.
    189     }
    190     return 0;
    191   }
    192 
    193   VideoFrame* out_frame = converted_frame_.get();
    194 
    195   // Convert to requested format.
    196   VideoType type =
    197       RawVideoTypeToCommonVideoVideoType(external_renderer_format_);
    198   int buffer_size = CalcBufferSize(type, video_frame.width(),
    199                                    video_frame.height());
    200   if (buffer_size <= 0) {
    201     // Unsupported video format.
    202     assert(false);
    203     return -1;
    204   }
    205   converted_frame_->VerifyAndAllocate(buffer_size);
    206 
    207   switch (external_renderer_format_) {
    208     case kVideoI420: {
    209       // TODO(mikhal): need to copy the buffer as is.
    210       // can the output here be a I420 frame?
    211       int length = ExtractBuffer(video_frame, out_frame->Size(),
    212                                  out_frame->Buffer());
    213       if (length < 0)
    214         return -1;
    215       out_frame->SetLength(length);
    216       break;
    217     }
    218     case kVideoYV12:
    219     case kVideoYUY2:
    220     case kVideoUYVY:
    221     case kVideoARGB:
    222     case kVideoRGB24:
    223     case kVideoRGB565:
    224     case kVideoARGB4444:
    225     case kVideoARGB1555 :
    226       {
    227         if (ConvertFromI420(video_frame, type, 0,
    228                             converted_frame_->Buffer()) < 0)
    229           return -1;
    230         converted_frame_->SetLength(buffer_size);
    231       }
    232       break;
    233     case kVideoIYUV:
    234       // no conversion available
    235       break;
    236     default:
    237       assert(false);
    238       out_frame = NULL;
    239       break;
    240   }
    241 
    242   NotifyFrameSizeChange(stream_id, video_frame);
    243 
    244   if (out_frame) {
    245     external_renderer_->DeliverFrame(out_frame->Buffer(),
    246                                      out_frame->Length(),
    247                                      video_frame.timestamp(),
    248                                      video_frame.ntp_time_ms(),
    249                                      video_frame.render_time_ms(),
    250                                      NULL);
    251   }
    252   return 0;
    253 }
    254 
    255 void ViEExternalRendererImpl::NotifyFrameSizeChange(
    256     const uint32_t stream_id,
    257     I420VideoFrame& video_frame) {
    258   if (external_renderer_width_ != video_frame.width() ||
    259       external_renderer_height_ != video_frame.height()) {
    260     external_renderer_width_ = video_frame.width();
    261     external_renderer_height_ = video_frame.height();
    262     external_renderer_->FrameSizeChange(
    263         external_renderer_width_, external_renderer_height_, stream_id);
    264   }
    265 }
    266 
    267 }  // namespace webrtc
    268