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_capturer.h"
12
13 #include "webrtc/common_video/interface/texture_video_frame.h"
14 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
15 #include "webrtc/modules/interface/module_common_types.h"
16 #include "webrtc/modules/utility/interface/process_thread.h"
17 #include "webrtc/modules/video_capture/include/video_capture_factory.h"
18 #include "webrtc/modules/video_processing/main/interface/video_processing.h"
19 #include "webrtc/modules/video_render/include/video_render_defines.h"
20 #include "webrtc/system_wrappers/interface/clock.h"
21 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
22 #include "webrtc/system_wrappers/interface/event_wrapper.h"
23 #include "webrtc/system_wrappers/interface/logging.h"
24 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
25 #include "webrtc/system_wrappers/interface/trace_event.h"
26 #include "webrtc/video_engine/include/vie_image_process.h"
27 #include "webrtc/video_engine/overuse_frame_detector.h"
28 #include "webrtc/video_engine/vie_defines.h"
29 #include "webrtc/video_engine/vie_encoder.h"
30
31 namespace webrtc {
32
33 const int kThreadWaitTimeMs = 100;
34
ViECapturer(int capture_id,int engine_id,const Config & config,ProcessThread & module_process_thread)35 ViECapturer::ViECapturer(int capture_id,
36 int engine_id,
37 const Config& config,
38 ProcessThread& module_process_thread)
39 : ViEFrameProviderBase(capture_id, engine_id),
40 capture_cs_(CriticalSectionWrapper::CreateCriticalSection()),
41 deliver_cs_(CriticalSectionWrapper::CreateCriticalSection()),
42 capture_module_(NULL),
43 external_capture_module_(NULL),
44 module_process_thread_(module_process_thread),
45 capture_id_(capture_id),
46 incoming_frame_cs_(CriticalSectionWrapper::CreateCriticalSection()),
47 capture_thread_(*ThreadWrapper::CreateThread(ViECaptureThreadFunction,
48 this, kHighPriority,
49 "ViECaptureThread")),
50 capture_event_(*EventWrapper::Create()),
51 deliver_event_(*EventWrapper::Create()),
52 effect_filter_(NULL),
53 image_proc_module_(NULL),
54 image_proc_module_ref_counter_(0),
55 deflicker_frame_stats_(NULL),
56 brightness_frame_stats_(NULL),
57 current_brightness_level_(Normal),
58 reported_brightness_level_(Normal),
59 observer_cs_(CriticalSectionWrapper::CreateCriticalSection()),
60 observer_(NULL),
61 overuse_detector_(new OveruseFrameDetector(Clock::GetRealTimeClock())) {
62 unsigned int t_id = 0;
63 if (!capture_thread_.Start(t_id)) {
64 assert(false);
65 }
66 module_process_thread_.RegisterModule(overuse_detector_.get());
67 }
68
~ViECapturer()69 ViECapturer::~ViECapturer() {
70 module_process_thread_.DeRegisterModule(overuse_detector_.get());
71
72 // Stop the thread.
73 deliver_cs_->Enter();
74 capture_cs_->Enter();
75 capture_thread_.SetNotAlive();
76 capture_event_.Set();
77 capture_cs_->Leave();
78 deliver_cs_->Leave();
79
80 // Stop the camera input.
81 if (capture_module_) {
82 module_process_thread_.DeRegisterModule(capture_module_);
83 capture_module_->DeRegisterCaptureDataCallback();
84 capture_module_->Release();
85 capture_module_ = NULL;
86 }
87 if (capture_thread_.Stop()) {
88 // Thread stopped.
89 delete &capture_thread_;
90 delete &capture_event_;
91 delete &deliver_event_;
92 } else {
93 assert(false);
94 }
95
96 if (image_proc_module_) {
97 VideoProcessingModule::Destroy(image_proc_module_);
98 }
99 if (deflicker_frame_stats_) {
100 delete deflicker_frame_stats_;
101 deflicker_frame_stats_ = NULL;
102 }
103 delete brightness_frame_stats_;
104 }
105
CreateViECapture(int capture_id,int engine_id,const Config & config,VideoCaptureModule * capture_module,ProcessThread & module_process_thread)106 ViECapturer* ViECapturer::CreateViECapture(
107 int capture_id,
108 int engine_id,
109 const Config& config,
110 VideoCaptureModule* capture_module,
111 ProcessThread& module_process_thread) {
112 ViECapturer* capture = new ViECapturer(capture_id, engine_id, config,
113 module_process_thread);
114 if (!capture || capture->Init(capture_module) != 0) {
115 delete capture;
116 capture = NULL;
117 }
118 return capture;
119 }
120
Init(VideoCaptureModule * capture_module)121 int32_t ViECapturer::Init(VideoCaptureModule* capture_module) {
122 assert(capture_module_ == NULL);
123 capture_module_ = capture_module;
124 capture_module_->RegisterCaptureDataCallback(*this);
125 capture_module_->AddRef();
126 if (module_process_thread_.RegisterModule(capture_module_) != 0) {
127 return -1;
128 }
129
130 return 0;
131 }
132
CreateViECapture(int capture_id,int engine_id,const Config & config,const char * device_unique_idUTF8,const uint32_t device_unique_idUTF8Length,ProcessThread & module_process_thread)133 ViECapturer* ViECapturer::CreateViECapture(
134 int capture_id,
135 int engine_id,
136 const Config& config,
137 const char* device_unique_idUTF8,
138 const uint32_t device_unique_idUTF8Length,
139 ProcessThread& module_process_thread) {
140 ViECapturer* capture = new ViECapturer(capture_id, engine_id, config,
141 module_process_thread);
142 if (!capture ||
143 capture->Init(device_unique_idUTF8, device_unique_idUTF8Length) != 0) {
144 delete capture;
145 capture = NULL;
146 }
147 return capture;
148 }
149
Init(const char * device_unique_idUTF8,uint32_t device_unique_idUTF8Length)150 int32_t ViECapturer::Init(const char* device_unique_idUTF8,
151 uint32_t device_unique_idUTF8Length) {
152 assert(capture_module_ == NULL);
153 if (device_unique_idUTF8 == NULL) {
154 capture_module_ = VideoCaptureFactory::Create(
155 ViEModuleId(engine_id_, capture_id_), external_capture_module_);
156 } else {
157 capture_module_ = VideoCaptureFactory::Create(
158 ViEModuleId(engine_id_, capture_id_), device_unique_idUTF8);
159 }
160 if (!capture_module_) {
161 return -1;
162 }
163 capture_module_->AddRef();
164 capture_module_->RegisterCaptureDataCallback(*this);
165 if (module_process_thread_.RegisterModule(capture_module_) != 0) {
166 return -1;
167 }
168
169 return 0;
170 }
171
FrameCallbackChanged()172 int ViECapturer::FrameCallbackChanged() {
173 if (Started() && !CaptureCapabilityFixed()) {
174 // Reconfigure the camera if a new size is required and the capture device
175 // does not provide encoded frames.
176 int best_width;
177 int best_height;
178 int best_frame_rate;
179 VideoCaptureCapability capture_settings;
180 capture_module_->CaptureSettings(capture_settings);
181 GetBestFormat(&best_width, &best_height, &best_frame_rate);
182 if (best_width != 0 && best_height != 0 && best_frame_rate != 0) {
183 if (best_width != capture_settings.width ||
184 best_height != capture_settings.height ||
185 best_frame_rate != capture_settings.maxFPS ||
186 capture_settings.codecType != kVideoCodecUnknown) {
187 Stop();
188 Start(requested_capability_);
189 }
190 }
191 }
192 return 0;
193 }
194
Start(const CaptureCapability & capture_capability)195 int32_t ViECapturer::Start(const CaptureCapability& capture_capability) {
196 int width;
197 int height;
198 int frame_rate;
199 VideoCaptureCapability capability;
200 requested_capability_ = capture_capability;
201
202 if (!CaptureCapabilityFixed()) {
203 // Ask the observers for best size.
204 GetBestFormat(&width, &height, &frame_rate);
205 if (width == 0) {
206 width = kViECaptureDefaultWidth;
207 }
208 if (height == 0) {
209 height = kViECaptureDefaultHeight;
210 }
211 if (frame_rate == 0) {
212 frame_rate = kViECaptureDefaultFramerate;
213 }
214 capability.height = height;
215 capability.width = width;
216 capability.maxFPS = frame_rate;
217 capability.rawType = kVideoI420;
218 capability.codecType = kVideoCodecUnknown;
219 } else {
220 // Width, height and type specified with call to Start, not set by
221 // observers.
222 capability.width = requested_capability_.width;
223 capability.height = requested_capability_.height;
224 capability.maxFPS = requested_capability_.maxFPS;
225 capability.rawType = requested_capability_.rawType;
226 capability.interlaced = requested_capability_.interlaced;
227 }
228 return capture_module_->StartCapture(capability);
229 }
230
Stop()231 int32_t ViECapturer::Stop() {
232 requested_capability_ = CaptureCapability();
233 return capture_module_->StopCapture();
234 }
235
Started()236 bool ViECapturer::Started() {
237 return capture_module_->CaptureStarted();
238 }
239
CurrentDeviceName() const240 const char* ViECapturer::CurrentDeviceName() const {
241 return capture_module_->CurrentDeviceName();
242 }
243
RegisterCpuOveruseObserver(CpuOveruseObserver * observer)244 void ViECapturer::RegisterCpuOveruseObserver(CpuOveruseObserver* observer) {
245 overuse_detector_->SetObserver(observer);
246 }
247
SetCpuOveruseOptions(const CpuOveruseOptions & options)248 void ViECapturer::SetCpuOveruseOptions(const CpuOveruseOptions& options) {
249 overuse_detector_->SetOptions(options);
250 }
251
GetCpuOveruseMetrics(CpuOveruseMetrics * metrics) const252 void ViECapturer::GetCpuOveruseMetrics(CpuOveruseMetrics* metrics) const {
253 overuse_detector_->GetCpuOveruseMetrics(metrics);
254 }
255
SetCaptureDelay(int32_t delay_ms)256 int32_t ViECapturer::SetCaptureDelay(int32_t delay_ms) {
257 capture_module_->SetCaptureDelay(delay_ms);
258 return 0;
259 }
260
SetRotateCapturedFrames(const RotateCapturedFrame rotation)261 int32_t ViECapturer::SetRotateCapturedFrames(
262 const RotateCapturedFrame rotation) {
263 VideoCaptureRotation converted_rotation = kCameraRotate0;
264 switch (rotation) {
265 case RotateCapturedFrame_0:
266 converted_rotation = kCameraRotate0;
267 break;
268 case RotateCapturedFrame_90:
269 converted_rotation = kCameraRotate90;
270 break;
271 case RotateCapturedFrame_180:
272 converted_rotation = kCameraRotate180;
273 break;
274 case RotateCapturedFrame_270:
275 converted_rotation = kCameraRotate270;
276 break;
277 }
278 return capture_module_->SetCaptureRotation(converted_rotation);
279 }
280
IncomingFrame(unsigned char * video_frame,unsigned int video_frame_length,uint16_t width,uint16_t height,RawVideoType video_type,unsigned long long capture_time)281 int ViECapturer::IncomingFrame(unsigned char* video_frame,
282 unsigned int video_frame_length,
283 uint16_t width,
284 uint16_t height,
285 RawVideoType video_type,
286 unsigned long long capture_time) { // NOLINT
287 if (!external_capture_module_) {
288 return -1;
289 }
290 VideoCaptureCapability capability;
291 capability.width = width;
292 capability.height = height;
293 capability.rawType = video_type;
294 return external_capture_module_->IncomingFrame(video_frame,
295 video_frame_length,
296 capability, capture_time);
297 }
298
IncomingFrameI420(const ViEVideoFrameI420 & video_frame,unsigned long long capture_time)299 int ViECapturer::IncomingFrameI420(const ViEVideoFrameI420& video_frame,
300 unsigned long long capture_time) { // NOLINT
301 if (!external_capture_module_) {
302 return -1;
303 }
304
305 int size_y = video_frame.height * video_frame.y_pitch;
306 int size_u = video_frame.u_pitch * ((video_frame.height + 1) / 2);
307 int size_v = video_frame.v_pitch * ((video_frame.height + 1) / 2);
308 CriticalSectionScoped cs(incoming_frame_cs_.get());
309 int ret = incoming_frame_.CreateFrame(size_y,
310 video_frame.y_plane,
311 size_u,
312 video_frame.u_plane,
313 size_v,
314 video_frame.v_plane,
315 video_frame.width,
316 video_frame.height,
317 video_frame.y_pitch,
318 video_frame.u_pitch,
319 video_frame.v_pitch);
320
321 if (ret < 0) {
322 LOG_F(LS_ERROR) << "Could not create I420Frame.";
323 return -1;
324 }
325
326 return external_capture_module_->IncomingI420VideoFrame(&incoming_frame_,
327 capture_time);
328 }
329
SwapFrame(I420VideoFrame * frame)330 void ViECapturer::SwapFrame(I420VideoFrame* frame) {
331 external_capture_module_->IncomingI420VideoFrame(frame,
332 frame->render_time_ms());
333 frame->set_timestamp(0);
334 frame->set_ntp_time_ms(0);
335 frame->set_render_time_ms(0);
336 }
337
OnIncomingCapturedFrame(const int32_t capture_id,I420VideoFrame & video_frame)338 void ViECapturer::OnIncomingCapturedFrame(const int32_t capture_id,
339 I420VideoFrame& video_frame) {
340 CriticalSectionScoped cs(capture_cs_.get());
341 // Make sure we render this frame earlier since we know the render time set
342 // is slightly off since it's being set when the frame has been received from
343 // the camera, and not when the camera actually captured the frame.
344 video_frame.set_render_time_ms(video_frame.render_time_ms() - FrameDelay());
345
346 TRACE_EVENT_ASYNC_BEGIN1("webrtc", "Video", video_frame.render_time_ms(),
347 "render_time", video_frame.render_time_ms());
348
349 if (video_frame.native_handle() != NULL) {
350 captured_frame_.reset(video_frame.CloneFrame());
351 } else {
352 if (captured_frame_ == NULL || captured_frame_->native_handle() != NULL)
353 captured_frame_.reset(new I420VideoFrame());
354 captured_frame_->SwapFrame(&video_frame);
355 }
356 capture_event_.Set();
357 overuse_detector_->FrameCaptured(captured_frame_->width(),
358 captured_frame_->height());
359 }
360
OnCaptureDelayChanged(const int32_t id,const int32_t delay)361 void ViECapturer::OnCaptureDelayChanged(const int32_t id,
362 const int32_t delay) {
363 LOG(LS_INFO) << "Capture delayed change to " << delay
364 << " for device " << id;
365
366 // Deliver the network delay to all registered callbacks.
367 ViEFrameProviderBase::SetFrameDelay(delay);
368 }
369
RegisterEffectFilter(ViEEffectFilter * effect_filter)370 int32_t ViECapturer::RegisterEffectFilter(
371 ViEEffectFilter* effect_filter) {
372 CriticalSectionScoped cs(deliver_cs_.get());
373
374 if (effect_filter != NULL && effect_filter_ != NULL) {
375 LOG_F(LS_ERROR) << "Effect filter already registered.";
376 return -1;
377 }
378 effect_filter_ = effect_filter;
379 return 0;
380 }
381
IncImageProcRefCount()382 int32_t ViECapturer::IncImageProcRefCount() {
383 if (!image_proc_module_) {
384 assert(image_proc_module_ref_counter_ == 0);
385 image_proc_module_ = VideoProcessingModule::Create(
386 ViEModuleId(engine_id_, capture_id_));
387 if (!image_proc_module_) {
388 LOG_F(LS_ERROR) << "Could not create video processing module.";
389 return -1;
390 }
391 }
392 image_proc_module_ref_counter_++;
393 return 0;
394 }
395
DecImageProcRefCount()396 int32_t ViECapturer::DecImageProcRefCount() {
397 image_proc_module_ref_counter_--;
398 if (image_proc_module_ref_counter_ == 0) {
399 // Destroy module.
400 VideoProcessingModule::Destroy(image_proc_module_);
401 image_proc_module_ = NULL;
402 }
403 return 0;
404 }
405
EnableDeflickering(bool enable)406 int32_t ViECapturer::EnableDeflickering(bool enable) {
407 CriticalSectionScoped cs(deliver_cs_.get());
408 if (enable) {
409 if (deflicker_frame_stats_) {
410 return -1;
411 }
412 if (IncImageProcRefCount() != 0) {
413 return -1;
414 }
415 deflicker_frame_stats_ = new VideoProcessingModule::FrameStats();
416 } else {
417 if (deflicker_frame_stats_ == NULL) {
418 return -1;
419 }
420 DecImageProcRefCount();
421 delete deflicker_frame_stats_;
422 deflicker_frame_stats_ = NULL;
423 }
424 return 0;
425 }
426
EnableBrightnessAlarm(bool enable)427 int32_t ViECapturer::EnableBrightnessAlarm(bool enable) {
428 CriticalSectionScoped cs(deliver_cs_.get());
429 if (enable) {
430 if (brightness_frame_stats_) {
431 return -1;
432 }
433 if (IncImageProcRefCount() != 0) {
434 return -1;
435 }
436 brightness_frame_stats_ = new VideoProcessingModule::FrameStats();
437 } else {
438 DecImageProcRefCount();
439 if (brightness_frame_stats_ == NULL) {
440 return -1;
441 }
442 delete brightness_frame_stats_;
443 brightness_frame_stats_ = NULL;
444 }
445 return 0;
446 }
447
ViECaptureThreadFunction(void * obj)448 bool ViECapturer::ViECaptureThreadFunction(void* obj) {
449 return static_cast<ViECapturer*>(obj)->ViECaptureProcess();
450 }
451
ViECaptureProcess()452 bool ViECapturer::ViECaptureProcess() {
453 if (capture_event_.Wait(kThreadWaitTimeMs) == kEventSignaled) {
454 overuse_detector_->FrameProcessingStarted();
455 int64_t encode_start_time = -1;
456 deliver_cs_->Enter();
457 if (SwapCapturedAndDeliverFrameIfAvailable()) {
458 encode_start_time = Clock::GetRealTimeClock()->TimeInMilliseconds();
459 DeliverI420Frame(deliver_frame_.get());
460 if (deliver_frame_->native_handle() != NULL)
461 deliver_frame_.reset(); // Release the texture so it can be reused.
462 }
463 deliver_cs_->Leave();
464 if (current_brightness_level_ != reported_brightness_level_) {
465 CriticalSectionScoped cs(observer_cs_.get());
466 if (observer_) {
467 observer_->BrightnessAlarm(id_, current_brightness_level_);
468 reported_brightness_level_ = current_brightness_level_;
469 }
470 }
471 // Update the overuse detector with the duration.
472 if (encode_start_time != -1) {
473 overuse_detector_->FrameEncoded(
474 Clock::GetRealTimeClock()->TimeInMilliseconds() - encode_start_time);
475 }
476 }
477 // We're done!
478 return true;
479 }
480
DeliverI420Frame(I420VideoFrame * video_frame)481 void ViECapturer::DeliverI420Frame(I420VideoFrame* video_frame) {
482 if (video_frame->native_handle() != NULL) {
483 ViEFrameProviderBase::DeliverFrame(video_frame);
484 return;
485 }
486
487 // Apply image enhancement and effect filter.
488 if (deflicker_frame_stats_) {
489 if (image_proc_module_->GetFrameStats(deflicker_frame_stats_,
490 *video_frame) == 0) {
491 image_proc_module_->Deflickering(video_frame, deflicker_frame_stats_);
492 } else {
493 LOG_F(LS_ERROR) << "Could not get frame stats.";
494 }
495 }
496 if (brightness_frame_stats_) {
497 if (image_proc_module_->GetFrameStats(brightness_frame_stats_,
498 *video_frame) == 0) {
499 int32_t brightness = image_proc_module_->BrightnessDetection(
500 *video_frame, *brightness_frame_stats_);
501
502 switch (brightness) {
503 case VideoProcessingModule::kNoWarning:
504 current_brightness_level_ = Normal;
505 break;
506 case VideoProcessingModule::kDarkWarning:
507 current_brightness_level_ = Dark;
508 break;
509 case VideoProcessingModule::kBrightWarning:
510 current_brightness_level_ = Bright;
511 break;
512 default:
513 break;
514 }
515 }
516 }
517 if (effect_filter_) {
518 unsigned int length = CalcBufferSize(kI420,
519 video_frame->width(),
520 video_frame->height());
521 scoped_ptr<uint8_t[]> video_buffer(new uint8_t[length]);
522 ExtractBuffer(*video_frame, length, video_buffer.get());
523 effect_filter_->Transform(length,
524 video_buffer.get(),
525 video_frame->ntp_time_ms(),
526 video_frame->timestamp(),
527 video_frame->width(),
528 video_frame->height());
529 }
530 // Deliver the captured frame to all observers (channels, renderer or file).
531 ViEFrameProviderBase::DeliverFrame(video_frame);
532 }
533
DeregisterFrameCallback(const ViEFrameCallback * callbackObject)534 int ViECapturer::DeregisterFrameCallback(
535 const ViEFrameCallback* callbackObject) {
536 return ViEFrameProviderBase::DeregisterFrameCallback(callbackObject);
537 }
538
IsFrameCallbackRegistered(const ViEFrameCallback * callbackObject)539 bool ViECapturer::IsFrameCallbackRegistered(
540 const ViEFrameCallback* callbackObject) {
541 CriticalSectionScoped cs(provider_cs_.get());
542 return ViEFrameProviderBase::IsFrameCallbackRegistered(callbackObject);
543 }
544
CaptureCapabilityFixed()545 bool ViECapturer::CaptureCapabilityFixed() {
546 return requested_capability_.width != 0 &&
547 requested_capability_.height != 0 &&
548 requested_capability_.maxFPS != 0;
549 }
550
RegisterObserver(ViECaptureObserver * observer)551 int32_t ViECapturer::RegisterObserver(ViECaptureObserver* observer) {
552 {
553 CriticalSectionScoped cs(observer_cs_.get());
554 if (observer_) {
555 LOG_F(LS_ERROR) << "Observer already registered.";
556 return -1;
557 }
558 observer_ = observer;
559 }
560 capture_module_->RegisterCaptureCallback(*this);
561 capture_module_->EnableFrameRateCallback(true);
562 capture_module_->EnableNoPictureAlarm(true);
563 return 0;
564 }
565
DeRegisterObserver()566 int32_t ViECapturer::DeRegisterObserver() {
567 capture_module_->EnableFrameRateCallback(false);
568 capture_module_->EnableNoPictureAlarm(false);
569 capture_module_->DeRegisterCaptureCallback();
570
571 CriticalSectionScoped cs(observer_cs_.get());
572 observer_ = NULL;
573 return 0;
574 }
575
IsObserverRegistered()576 bool ViECapturer::IsObserverRegistered() {
577 CriticalSectionScoped cs(observer_cs_.get());
578 return observer_ != NULL;
579 }
580
OnCaptureFrameRate(const int32_t id,const uint32_t frame_rate)581 void ViECapturer::OnCaptureFrameRate(const int32_t id,
582 const uint32_t frame_rate) {
583 CriticalSectionScoped cs(observer_cs_.get());
584 observer_->CapturedFrameRate(id_, static_cast<uint8_t>(frame_rate));
585 }
586
OnNoPictureAlarm(const int32_t id,const VideoCaptureAlarm alarm)587 void ViECapturer::OnNoPictureAlarm(const int32_t id,
588 const VideoCaptureAlarm alarm) {
589 LOG(LS_WARNING) << "OnNoPictureAlarm " << id;
590
591 CriticalSectionScoped cs(observer_cs_.get());
592 CaptureAlarm vie_alarm = (alarm == Raised) ? AlarmRaised : AlarmCleared;
593 observer_->NoPictureAlarm(id, vie_alarm);
594 }
595
SwapCapturedAndDeliverFrameIfAvailable()596 bool ViECapturer::SwapCapturedAndDeliverFrameIfAvailable() {
597 CriticalSectionScoped cs(capture_cs_.get());
598 if (captured_frame_ == NULL)
599 return false;
600
601 if (captured_frame_->native_handle() != NULL) {
602 deliver_frame_.reset(captured_frame_.release());
603 return true;
604 }
605
606 if (captured_frame_->IsZeroSize())
607 return false;
608
609 if (deliver_frame_ == NULL)
610 deliver_frame_.reset(new I420VideoFrame());
611 deliver_frame_->SwapFrame(captured_frame_.get());
612 captured_frame_->ResetSize();
613 return true;
614 }
615
616 } // namespace webrtc
617