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