2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-02-06 10:11:25 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
#include "video_engine/vie_capturer.h"
|
|
|
|
|
|
2012-10-24 18:33:04 +00:00
|
|
|
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
2011-12-14 08:36:01 +00:00
|
|
|
#include "modules/interface/module_common_types.h"
|
|
|
|
|
#include "modules/utility/interface/process_thread.h"
|
2012-10-30 21:58:00 +00:00
|
|
|
#include "webrtc/modules/video_capture/include/video_capture_factory.h"
|
2011-12-14 08:36:01 +00:00
|
|
|
#include "modules/video_processing/main/interface/video_processing.h"
|
2012-10-31 05:22:11 +00:00
|
|
|
#include "webrtc/modules/video_render/include/video_render_defines.h"
|
2011-12-14 08:36:01 +00:00
|
|
|
#include "system_wrappers/interface/critical_section_wrapper.h"
|
|
|
|
|
#include "system_wrappers/interface/event_wrapper.h"
|
|
|
|
|
#include "system_wrappers/interface/thread_wrapper.h"
|
|
|
|
|
#include "system_wrappers/interface/trace.h"
|
2013-04-09 19:54:10 +00:00
|
|
|
#include "system_wrappers/interface/trace_event.h"
|
2011-12-22 08:51:52 +00:00
|
|
|
#include "video_engine/include/vie_image_process.h"
|
2011-12-14 08:36:01 +00:00
|
|
|
#include "video_engine/vie_defines.h"
|
|
|
|
|
#include "video_engine/vie_encoder.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
const int kThreadWaitTimeMs = 100;
|
|
|
|
|
const int kMaxDeliverWaitTime = 500;
|
|
|
|
|
|
|
|
|
|
ViECapturer::ViECapturer(int capture_id,
|
|
|
|
|
int engine_id,
|
|
|
|
|
ProcessThread& module_process_thread)
|
|
|
|
|
: ViEFrameProviderBase(capture_id, engine_id),
|
2011-12-22 14:17:53 +00:00
|
|
|
capture_cs_(CriticalSectionWrapper::CreateCriticalSection()),
|
|
|
|
|
deliver_cs_(CriticalSectionWrapper::CreateCriticalSection()),
|
2011-12-14 08:36:01 +00:00
|
|
|
capture_module_(NULL),
|
|
|
|
|
external_capture_module_(NULL),
|
|
|
|
|
module_process_thread_(module_process_thread),
|
|
|
|
|
capture_id_(capture_id),
|
|
|
|
|
capture_thread_(*ThreadWrapper::CreateThread(ViECaptureThreadFunction,
|
|
|
|
|
this, kHighPriority,
|
|
|
|
|
"ViECaptureThread")),
|
|
|
|
|
capture_event_(*EventWrapper::Create()),
|
|
|
|
|
deliver_event_(*EventWrapper::Create()),
|
|
|
|
|
effect_filter_(NULL),
|
|
|
|
|
image_proc_module_(NULL),
|
|
|
|
|
image_proc_module_ref_counter_(0),
|
|
|
|
|
deflicker_frame_stats_(NULL),
|
|
|
|
|
brightness_frame_stats_(NULL),
|
|
|
|
|
current_brightness_level_(Normal),
|
|
|
|
|
reported_brightness_level_(Normal),
|
|
|
|
|
denoising_enabled_(false),
|
2011-12-22 14:17:53 +00:00
|
|
|
observer_cs_(CriticalSectionWrapper::CreateCriticalSection()),
|
2011-12-14 08:36:01 +00:00
|
|
|
observer_(NULL),
|
2011-12-22 14:17:53 +00:00
|
|
|
encoding_cs_(CriticalSectionWrapper::CreateCriticalSection()),
|
2011-12-14 08:36:01 +00:00
|
|
|
capture_encoder_(NULL),
|
|
|
|
|
encode_complete_callback_(NULL),
|
|
|
|
|
vie_encoder_(NULL),
|
|
|
|
|
vcm_(NULL),
|
|
|
|
|
decoder_initialized_(false) {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id, capture_id),
|
|
|
|
|
"ViECapturer::ViECapturer(capture_id: %d, engine_id: %d)",
|
|
|
|
|
capture_id, engine_id);
|
|
|
|
|
unsigned int t_id = 0;
|
|
|
|
|
if (capture_thread_.Start(t_id)) {
|
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id, capture_id),
|
|
|
|
|
"%s: thread started: %u", __FUNCTION__, t_id);
|
|
|
|
|
} else {
|
|
|
|
|
assert(false);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
ViECapturer::~ViECapturer() {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"ViECapturer::~ViECapturer() - capture_id: %d, engine_id: %d",
|
|
|
|
|
capture_id_, engine_id_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
// Stop the thread.
|
2011-12-22 14:17:53 +00:00
|
|
|
deliver_cs_->Enter();
|
|
|
|
|
capture_cs_->Enter();
|
2011-12-14 08:36:01 +00:00
|
|
|
capture_thread_.SetNotAlive();
|
|
|
|
|
capture_event_.Set();
|
2011-12-22 14:17:53 +00:00
|
|
|
capture_cs_->Leave();
|
|
|
|
|
deliver_cs_->Leave();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
provider_cs_->Enter();
|
2011-12-14 08:36:01 +00:00
|
|
|
if (vie_encoder_) {
|
|
|
|
|
vie_encoder_->DeRegisterExternalEncoder(codec_.plType);
|
|
|
|
|
}
|
2011-12-22 14:17:53 +00:00
|
|
|
provider_cs_->Leave();
|
2011-12-14 08:36:01 +00:00
|
|
|
|
|
|
|
|
// Stop the camera input.
|
|
|
|
|
if (capture_module_) {
|
|
|
|
|
module_process_thread_.DeRegisterModule(capture_module_);
|
|
|
|
|
capture_module_->DeRegisterCaptureDataCallback();
|
|
|
|
|
capture_module_->Release();
|
|
|
|
|
capture_module_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (capture_thread_.Stop()) {
|
|
|
|
|
// Thread stopped.
|
|
|
|
|
delete &capture_thread_;
|
|
|
|
|
delete &capture_event_;
|
|
|
|
|
delete &deliver_event_;
|
|
|
|
|
} else {
|
|
|
|
|
assert(false);
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceVideoRenderer,
|
|
|
|
|
ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: Not able to stop capture thread for device %d, leaking",
|
|
|
|
|
__FUNCTION__, capture_id_);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
if (image_proc_module_) {
|
|
|
|
|
VideoProcessingModule::Destroy(image_proc_module_);
|
|
|
|
|
}
|
|
|
|
|
if (deflicker_frame_stats_) {
|
|
|
|
|
delete deflicker_frame_stats_;
|
|
|
|
|
deflicker_frame_stats_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
delete brightness_frame_stats_;
|
|
|
|
|
if (vcm_) {
|
|
|
|
|
delete vcm_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ViECapturer* ViECapturer::CreateViECapture(
|
|
|
|
|
int capture_id,
|
|
|
|
|
int engine_id,
|
2012-06-21 12:11:50 +00:00
|
|
|
VideoCaptureModule* capture_module,
|
2011-12-14 08:36:01 +00:00
|
|
|
ProcessThread& module_process_thread) {
|
|
|
|
|
ViECapturer* capture = new ViECapturer(capture_id, engine_id,
|
|
|
|
|
module_process_thread);
|
|
|
|
|
if (!capture || capture->Init(capture_module) != 0) {
|
|
|
|
|
delete capture;
|
|
|
|
|
capture = NULL;
|
|
|
|
|
}
|
|
|
|
|
return capture;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::Init(VideoCaptureModule* capture_module) {
|
2011-12-14 08:36:01 +00:00
|
|
|
assert(capture_module_ == NULL);
|
2012-06-21 12:11:50 +00:00
|
|
|
capture_module_ = capture_module;
|
2011-12-14 08:36:01 +00:00
|
|
|
capture_module_->RegisterCaptureDataCallback(*this);
|
|
|
|
|
capture_module_->AddRef();
|
|
|
|
|
if (module_process_thread_.RegisterModule(capture_module_) != 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ViECapturer* ViECapturer::CreateViECapture(
|
|
|
|
|
int capture_id,
|
|
|
|
|
int engine_id,
|
2012-03-01 16:30:40 +00:00
|
|
|
const char* device_unique_idUTF8,
|
2013-04-09 13:41:51 +00:00
|
|
|
const uint32_t device_unique_idUTF8Length,
|
2011-12-14 08:36:01 +00:00
|
|
|
ProcessThread& module_process_thread) {
|
|
|
|
|
ViECapturer* capture = new ViECapturer(capture_id, engine_id,
|
|
|
|
|
module_process_thread);
|
|
|
|
|
if (!capture ||
|
|
|
|
|
capture->Init(device_unique_idUTF8, device_unique_idUTF8Length) != 0) {
|
|
|
|
|
delete capture;
|
|
|
|
|
capture = NULL;
|
|
|
|
|
}
|
|
|
|
|
return capture;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::Init(
|
2012-03-01 16:30:40 +00:00
|
|
|
const char* device_unique_idUTF8,
|
2013-04-09 13:41:51 +00:00
|
|
|
const uint32_t device_unique_idUTF8Length) {
|
2011-12-14 08:36:01 +00:00
|
|
|
assert(capture_module_ == NULL);
|
|
|
|
|
if (device_unique_idUTF8 == NULL) {
|
|
|
|
|
capture_module_ = VideoCaptureFactory::Create(
|
|
|
|
|
ViEModuleId(engine_id_, capture_id_), external_capture_module_);
|
|
|
|
|
} else {
|
|
|
|
|
capture_module_ = VideoCaptureFactory::Create(
|
|
|
|
|
ViEModuleId(engine_id_, capture_id_), device_unique_idUTF8);
|
|
|
|
|
}
|
|
|
|
|
if (!capture_module_) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
capture_module_->AddRef();
|
|
|
|
|
capture_module_->RegisterCaptureDataCallback(*this);
|
|
|
|
|
if (module_process_thread_.RegisterModule(capture_module_) != 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ViECapturer::FrameCallbackChanged() {
|
|
|
|
|
if (Started() && !EncoderActive() && !CaptureCapabilityFixed()) {
|
|
|
|
|
// Reconfigure the camera if a new size is required and the capture device
|
|
|
|
|
// does not provide encoded frames.
|
|
|
|
|
int best_width;
|
|
|
|
|
int best_height;
|
|
|
|
|
int best_frame_rate;
|
|
|
|
|
VideoCaptureCapability capture_settings;
|
|
|
|
|
capture_module_->CaptureSettings(capture_settings);
|
2012-06-21 12:11:50 +00:00
|
|
|
GetBestFormat(&best_width, &best_height, &best_frame_rate);
|
2011-12-14 08:36:01 +00:00
|
|
|
if (best_width != 0 && best_height != 0 && best_frame_rate != 0) {
|
|
|
|
|
if (best_width != capture_settings.width ||
|
|
|
|
|
best_height != capture_settings.height ||
|
|
|
|
|
best_frame_rate != capture_settings.maxFPS ||
|
|
|
|
|
capture_settings.codecType != kVideoCodecUnknown) {
|
|
|
|
|
Stop();
|
|
|
|
|
Start(requested_capability_);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::Start(const CaptureCapability& capture_capability) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_), "%s",
|
|
|
|
|
__FUNCTION__);
|
|
|
|
|
int width;
|
|
|
|
|
int height;
|
|
|
|
|
int frame_rate;
|
|
|
|
|
VideoCaptureCapability capability;
|
|
|
|
|
requested_capability_ = capture_capability;
|
|
|
|
|
if (EncoderActive()) {
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(encoding_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
capability.width = codec_.width;
|
|
|
|
|
capability.height = codec_.height;
|
|
|
|
|
capability.maxFPS = codec_.maxFramerate;
|
|
|
|
|
capability.codecType = codec_.codecType;
|
|
|
|
|
capability.rawType = kVideoI420;
|
|
|
|
|
|
|
|
|
|
} else if (!CaptureCapabilityFixed()) {
|
|
|
|
|
// Ask the observers for best size.
|
2012-06-21 12:11:50 +00:00
|
|
|
GetBestFormat(&width, &height, &frame_rate);
|
2011-12-14 08:36:01 +00:00
|
|
|
if (width == 0) {
|
|
|
|
|
width = kViECaptureDefaultWidth;
|
|
|
|
|
}
|
|
|
|
|
if (height == 0) {
|
|
|
|
|
height = kViECaptureDefaultHeight;
|
|
|
|
|
}
|
|
|
|
|
if (frame_rate == 0) {
|
|
|
|
|
frame_rate = kViECaptureDefaultFramerate;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
capability.height = height;
|
|
|
|
|
capability.width = width;
|
|
|
|
|
capability.maxFPS = frame_rate;
|
|
|
|
|
capability.rawType = kVideoI420;
|
|
|
|
|
capability.codecType = kVideoCodecUnknown;
|
|
|
|
|
} else {
|
|
|
|
|
// Width, height and type specified with call to Start, not set by
|
|
|
|
|
// observers.
|
|
|
|
|
capability.width = requested_capability_.width;
|
|
|
|
|
capability.height = requested_capability_.height;
|
|
|
|
|
capability.maxFPS = requested_capability_.maxFPS;
|
|
|
|
|
capability.rawType = requested_capability_.rawType;
|
|
|
|
|
capability.interlaced = requested_capability_.interlaced;
|
|
|
|
|
}
|
|
|
|
|
return capture_module_->StartCapture(capability);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::Stop() {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_), "%s",
|
|
|
|
|
__FUNCTION__);
|
|
|
|
|
requested_capability_ = CaptureCapability();
|
|
|
|
|
return capture_module_->StopCapture();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
bool ViECapturer::Started() {
|
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_), "%s",
|
|
|
|
|
__FUNCTION__);
|
|
|
|
|
return capture_module_->CaptureStarted();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2012-03-01 16:30:40 +00:00
|
|
|
const char* ViECapturer::CurrentDeviceName() const {
|
2011-12-14 08:36:01 +00:00
|
|
|
return capture_module_->CurrentDeviceName();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::SetCaptureDelay(int32_t delay_ms) {
|
2011-12-14 08:36:01 +00:00
|
|
|
return capture_module_->SetCaptureDelay(delay_ms);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::SetRotateCapturedFrames(
|
2011-12-14 08:36:01 +00:00
|
|
|
const RotateCapturedFrame rotation) {
|
|
|
|
|
VideoCaptureRotation converted_rotation = kCameraRotate0;
|
|
|
|
|
switch (rotation) {
|
|
|
|
|
case RotateCapturedFrame_0:
|
|
|
|
|
converted_rotation = kCameraRotate0;
|
|
|
|
|
break;
|
|
|
|
|
case RotateCapturedFrame_90:
|
|
|
|
|
converted_rotation = kCameraRotate90;
|
|
|
|
|
break;
|
|
|
|
|
case RotateCapturedFrame_180:
|
|
|
|
|
converted_rotation = kCameraRotate180;
|
|
|
|
|
break;
|
|
|
|
|
case RotateCapturedFrame_270:
|
|
|
|
|
converted_rotation = kCameraRotate270;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return capture_module_->SetCaptureRotation(converted_rotation);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
int ViECapturer::IncomingFrame(unsigned char* video_frame,
|
|
|
|
|
unsigned int video_frame_length,
|
2012-06-21 12:11:50 +00:00
|
|
|
uint16_t width,
|
|
|
|
|
uint16_t height,
|
2011-12-14 08:36:01 +00:00
|
|
|
RawVideoType video_type,
|
2012-06-21 12:11:50 +00:00
|
|
|
unsigned long long capture_time) { // NOLINT
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
2012-01-12 00:37:07 +00:00
|
|
|
"ExternalCapture::IncomingFrame width %d, height %d, "
|
2011-12-14 08:36:01 +00:00
|
|
|
"capture_time %u", width, height, capture_time);
|
2011-10-14 17:16:04 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
if (!external_capture_module_) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
VideoCaptureCapability capability;
|
|
|
|
|
capability.width = width;
|
|
|
|
|
capability.height = height;
|
|
|
|
|
capability.rawType = video_type;
|
|
|
|
|
return external_capture_module_->IncomingFrame(video_frame,
|
|
|
|
|
video_frame_length,
|
|
|
|
|
capability, capture_time);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ViECapturer::IncomingFrameI420(const ViEVideoFrameI420& video_frame,
|
2012-06-21 12:11:50 +00:00
|
|
|
unsigned long long capture_time) { // NOLINT
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
2012-01-12 00:37:07 +00:00
|
|
|
"ExternalCapture::IncomingFrame width %d, height %d, "
|
2011-12-14 08:36:01 +00:00
|
|
|
" capture_time %u", video_frame.width, video_frame.height,
|
|
|
|
|
capture_time);
|
|
|
|
|
|
|
|
|
|
if (!external_capture_module_) {
|
2011-10-14 17:16:04 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VideoFrameI420 frame;
|
|
|
|
|
frame.width = video_frame.width;
|
|
|
|
|
frame.height = video_frame.height;
|
|
|
|
|
frame.y_plane = video_frame.y_plane;
|
|
|
|
|
frame.u_plane = video_frame.u_plane;
|
|
|
|
|
frame.v_plane = video_frame.v_plane;
|
|
|
|
|
frame.y_pitch = video_frame.y_pitch;
|
|
|
|
|
frame.u_pitch = video_frame.u_pitch;
|
|
|
|
|
frame.v_pitch = video_frame.v_pitch;
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
return external_capture_module_->IncomingFrameI420(frame, capture_time);
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
void ViECapturer::OnIncomingCapturedFrame(const int32_t capture_id,
|
2012-10-29 15:59:40 +00:00
|
|
|
I420VideoFrame& video_frame) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_id: %d)", __FUNCTION__, capture_id);
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(capture_cs_.get());
|
2012-09-11 07:00:42 +00:00
|
|
|
// Make sure we render this frame earlier since we know the render time set
|
|
|
|
|
// is slightly off since it's being set when the frame has been received from
|
|
|
|
|
// the camera, and not when the camera actually captured the frame.
|
2012-10-24 18:33:04 +00:00
|
|
|
video_frame.set_render_time_ms(video_frame.render_time_ms() - FrameDelay());
|
2013-04-09 19:54:10 +00:00
|
|
|
|
|
|
|
|
TRACE_EVENT_INSTANT1("webrtc", "VC::OnIncomingCapturedFrame",
|
|
|
|
|
"render_time", video_frame.render_time_ms());
|
|
|
|
|
|
2012-10-24 18:33:04 +00:00
|
|
|
captured_frame_.SwapFrame(&video_frame);
|
|
|
|
|
capture_event_.Set();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
void ViECapturer::OnIncomingCapturedEncodedFrame(const int32_t capture_id,
|
2012-11-07 17:18:04 +00:00
|
|
|
VideoFrame& video_frame,
|
|
|
|
|
VideoCodecType codec_type) {
|
2012-10-24 18:33:04 +00:00
|
|
|
WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_id: %d)", __FUNCTION__, capture_id);
|
|
|
|
|
CriticalSectionScoped cs(capture_cs_.get());
|
|
|
|
|
// Make sure we render this frame earlier since we know the render time set
|
|
|
|
|
// is slightly off since it's being set when the frame has been received from
|
|
|
|
|
// the camera, and not when the camera actually captured the frame.
|
2012-09-11 07:00:42 +00:00
|
|
|
video_frame.SetRenderTime(video_frame.RenderTimeMs() - FrameDelay());
|
2013-04-09 19:54:10 +00:00
|
|
|
|
|
|
|
|
TRACE_EVENT_INSTANT1("webrtc", "VC::OnIncomingCapturedEncodedFrame",
|
|
|
|
|
"render_time", video_frame.RenderTimeMs());
|
|
|
|
|
|
2012-11-07 17:18:04 +00:00
|
|
|
assert(codec_type != kVideoCodecUnknown);
|
2012-10-29 15:59:40 +00:00
|
|
|
if (encoded_frame_.Length() != 0) {
|
|
|
|
|
// The last encoded frame has not been sent yet. Need to wait.
|
|
|
|
|
deliver_event_.Reset();
|
|
|
|
|
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_id: %d) Last encoded frame not yet delivered.",
|
|
|
|
|
__FUNCTION__, capture_id);
|
|
|
|
|
capture_cs_->Leave();
|
|
|
|
|
// Wait for the coded frame to be sent before unblocking this.
|
|
|
|
|
deliver_event_.Wait(kMaxDeliverWaitTime);
|
|
|
|
|
assert(encoded_frame_.Length() == 0);
|
|
|
|
|
capture_cs_->Enter();
|
|
|
|
|
} else {
|
|
|
|
|
assert(false);
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
2012-10-29 15:59:40 +00:00
|
|
|
encoded_frame_.SwapFrame(video_frame);
|
2011-12-14 08:36:01 +00:00
|
|
|
capture_event_.Set();
|
|
|
|
|
return;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
void ViECapturer::OnCaptureDelayChanged(const int32_t id,
|
|
|
|
|
const int32_t delay) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_id: %d) delay %d", __FUNCTION__, capture_id_,
|
2011-07-07 08:21:25 +00:00
|
|
|
delay);
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
// Deliver the network delay to all registered callbacks.
|
|
|
|
|
ViEFrameProviderBase::SetFrameDelay(delay);
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(encoding_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (vie_encoder_) {
|
|
|
|
|
vie_encoder_->DelayChanged(id, delay);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::RegisterEffectFilter(
|
2011-12-14 08:36:01 +00:00
|
|
|
ViEEffectFilter* effect_filter) {
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(deliver_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
|
|
|
|
|
if (!effect_filter) {
|
|
|
|
|
if (!effect_filter_) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: no effect filter added for capture device %d",
|
|
|
|
|
__FUNCTION__, capture_id_);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: deregister effect filter for device %d", __FUNCTION__,
|
|
|
|
|
capture_id_);
|
|
|
|
|
} else {
|
|
|
|
|
if (effect_filter_) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: effect filter already added for capture device %d",
|
|
|
|
|
__FUNCTION__, capture_id_);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: register effect filter for device %d", __FUNCTION__,
|
|
|
|
|
capture_id_);
|
|
|
|
|
}
|
|
|
|
|
effect_filter_ = effect_filter;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::IncImageProcRefCount() {
|
2011-12-14 08:36:01 +00:00
|
|
|
if (!image_proc_module_) {
|
|
|
|
|
assert(image_proc_module_ref_counter_ == 0);
|
|
|
|
|
image_proc_module_ = VideoProcessingModule::Create(
|
|
|
|
|
ViEModuleId(engine_id_, capture_id_));
|
|
|
|
|
if (!image_proc_module_) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: could not create video processing module",
|
|
|
|
|
__FUNCTION__);
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
image_proc_module_ref_counter_++;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::DecImageProcRefCount() {
|
2011-12-14 08:36:01 +00:00
|
|
|
image_proc_module_ref_counter_--;
|
|
|
|
|
if (image_proc_module_ref_counter_ == 0) {
|
|
|
|
|
// Destroy module.
|
|
|
|
|
VideoProcessingModule::Destroy(image_proc_module_);
|
|
|
|
|
image_proc_module_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::EnableDenoising(bool enable) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d, enable: %d)", __FUNCTION__,
|
|
|
|
|
capture_id_, enable);
|
|
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(deliver_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (enable) {
|
|
|
|
|
if (denoising_enabled_) {
|
2012-04-06 01:01:16 +00:00
|
|
|
// Already enabled, nothing need to be done.
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
denoising_enabled_ = true;
|
|
|
|
|
if (IncImageProcRefCount() != 0) {
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
} else {
|
|
|
|
|
if (denoising_enabled_ == false) {
|
2012-04-06 01:01:16 +00:00
|
|
|
// Already disabled, nothing need to be done.
|
|
|
|
|
return 0;
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
denoising_enabled_ = false;
|
|
|
|
|
DecImageProcRefCount();
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::EnableDeflickering(bool enable) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d, enable: %d)", __FUNCTION__,
|
|
|
|
|
capture_id_, enable);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(deliver_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (enable) {
|
|
|
|
|
if (deflicker_frame_stats_) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: deflickering already enabled", __FUNCTION__);
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
if (IncImageProcRefCount() != 0) {
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
deflicker_frame_stats_ = new VideoProcessingModule::FrameStats();
|
|
|
|
|
} else {
|
|
|
|
|
if (deflicker_frame_stats_ == NULL) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: deflickering not enabled", __FUNCTION__);
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
DecImageProcRefCount();
|
|
|
|
|
delete deflicker_frame_stats_;
|
|
|
|
|
deflicker_frame_stats_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::EnableBrightnessAlarm(bool enable) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d, enable: %d)", __FUNCTION__,
|
|
|
|
|
capture_id_, enable);
|
|
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(deliver_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (enable) {
|
|
|
|
|
if (brightness_frame_stats_) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: BrightnessAlarm already enabled", __FUNCTION__);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (IncImageProcRefCount() != 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
brightness_frame_stats_ = new VideoProcessingModule::FrameStats();
|
|
|
|
|
} else {
|
|
|
|
|
DecImageProcRefCount();
|
|
|
|
|
if (brightness_frame_stats_ == NULL) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: deflickering not enabled", __FUNCTION__);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
delete brightness_frame_stats_;
|
|
|
|
|
brightness_frame_stats_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ViECapturer::ViECaptureThreadFunction(void* obj) {
|
|
|
|
|
return static_cast<ViECapturer*>(obj)->ViECaptureProcess();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ViECapturer::ViECaptureProcess() {
|
|
|
|
|
if (capture_event_.Wait(kThreadWaitTimeMs) == kEventSignaled) {
|
2011-12-22 14:17:53 +00:00
|
|
|
deliver_cs_->Enter();
|
2012-10-24 18:33:04 +00:00
|
|
|
if (!captured_frame_.IsZeroSize()) {
|
2011-12-14 08:36:01 +00:00
|
|
|
// New I420 frame.
|
2011-12-22 14:17:53 +00:00
|
|
|
capture_cs_->Enter();
|
2012-10-24 18:33:04 +00:00
|
|
|
deliver_frame_.SwapFrame(&captured_frame_);
|
|
|
|
|
captured_frame_.ResetSize();
|
2011-12-22 14:17:53 +00:00
|
|
|
capture_cs_->Leave();
|
2012-06-21 12:11:50 +00:00
|
|
|
DeliverI420Frame(&deliver_frame_);
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
if (encoded_frame_.Length() > 0) {
|
2011-12-22 14:17:53 +00:00
|
|
|
capture_cs_->Enter();
|
2012-10-24 18:33:04 +00:00
|
|
|
deliver_encoded_frame_.SwapFrame(encoded_frame_);
|
2011-12-14 08:36:01 +00:00
|
|
|
encoded_frame_.SetLength(0);
|
|
|
|
|
deliver_event_.Set();
|
2011-12-22 14:17:53 +00:00
|
|
|
capture_cs_->Leave();
|
2012-10-24 18:33:04 +00:00
|
|
|
DeliverCodedFrame(&deliver_encoded_frame_);
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
2011-12-22 14:17:53 +00:00
|
|
|
deliver_cs_->Leave();
|
2011-12-14 08:36:01 +00:00
|
|
|
if (current_brightness_level_ != reported_brightness_level_) {
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(observer_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (observer_) {
|
|
|
|
|
observer_->BrightnessAlarm(id_, current_brightness_level_);
|
|
|
|
|
reported_brightness_level_ = current_brightness_level_;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
// We're done!
|
|
|
|
|
return true;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2012-10-24 18:33:04 +00:00
|
|
|
void ViECapturer::DeliverI420Frame(I420VideoFrame* video_frame) {
|
2011-12-14 08:36:01 +00:00
|
|
|
// Apply image enhancement and effect filter.
|
|
|
|
|
if (deflicker_frame_stats_) {
|
2012-10-19 15:43:31 +00:00
|
|
|
if (image_proc_module_->GetFrameStats(deflicker_frame_stats_,
|
2012-06-21 12:11:50 +00:00
|
|
|
*video_frame) == 0) {
|
2012-10-19 15:43:31 +00:00
|
|
|
image_proc_module_->Deflickering(video_frame, deflicker_frame_stats_);
|
2011-12-14 08:36:01 +00:00
|
|
|
} else {
|
|
|
|
|
WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: could not get frame stats for captured frame",
|
|
|
|
|
__FUNCTION__);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
if (denoising_enabled_) {
|
2012-10-19 15:43:31 +00:00
|
|
|
image_proc_module_->Denoising(video_frame);
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
if (brightness_frame_stats_) {
|
2012-10-19 15:43:31 +00:00
|
|
|
if (image_proc_module_->GetFrameStats(brightness_frame_stats_,
|
2012-06-21 12:11:50 +00:00
|
|
|
*video_frame) == 0) {
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t brightness = image_proc_module_->BrightnessDetection(
|
2012-06-21 12:11:50 +00:00
|
|
|
*video_frame, *brightness_frame_stats_);
|
2011-12-14 08:36:01 +00:00
|
|
|
|
|
|
|
|
switch (brightness) {
|
|
|
|
|
case VideoProcessingModule::kNoWarning:
|
|
|
|
|
current_brightness_level_ = Normal;
|
|
|
|
|
break;
|
|
|
|
|
case VideoProcessingModule::kDarkWarning:
|
|
|
|
|
current_brightness_level_ = Dark;
|
|
|
|
|
break;
|
|
|
|
|
case VideoProcessingModule::kBrightWarning:
|
|
|
|
|
current_brightness_level_ = Bright;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s: Brightness detection failed", __FUNCTION__);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
if (effect_filter_) {
|
2012-10-24 18:33:04 +00:00
|
|
|
unsigned int length = CalcBufferSize(kI420,
|
|
|
|
|
video_frame->width(),
|
|
|
|
|
video_frame->height());
|
|
|
|
|
scoped_array<uint8_t> video_buffer(new uint8_t[length]);
|
|
|
|
|
ExtractBuffer(*video_frame, length, video_buffer.get());
|
|
|
|
|
effect_filter_->Transform(length, video_buffer.get(),
|
|
|
|
|
video_frame->timestamp(), video_frame->width(),
|
|
|
|
|
video_frame->height());
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
// Deliver the captured frame to all observers (channels, renderer or file).
|
|
|
|
|
ViEFrameProviderBase::DeliverFrame(video_frame);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2012-06-21 12:11:50 +00:00
|
|
|
void ViECapturer::DeliverCodedFrame(VideoFrame* video_frame) {
|
2011-12-14 08:36:01 +00:00
|
|
|
if (encode_complete_callback_) {
|
2012-06-21 12:11:50 +00:00
|
|
|
EncodedImage encoded_image(video_frame->Buffer(), video_frame->Length(),
|
|
|
|
|
video_frame->Size());
|
|
|
|
|
encoded_image._timeStamp =
|
2013-04-09 13:41:51 +00:00
|
|
|
90 * static_cast<uint32_t>(video_frame->RenderTimeMs());
|
2011-12-14 08:36:01 +00:00
|
|
|
encode_complete_callback_->Encoded(encoded_image);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
if (NumberOfRegisteredFrameCallbacks() > 0 && decoder_initialized_) {
|
2012-06-21 12:11:50 +00:00
|
|
|
video_frame->Swap(decode_buffer_.payloadData, decode_buffer_.bufferSize,
|
2011-12-14 08:36:01 +00:00
|
|
|
decode_buffer_.payloadSize);
|
2012-06-21 12:11:50 +00:00
|
|
|
decode_buffer_.encodedHeight = video_frame->Height();
|
|
|
|
|
decode_buffer_.encodedWidth = video_frame->Width();
|
|
|
|
|
decode_buffer_.renderTimeMs = video_frame->RenderTimeMs();
|
|
|
|
|
const int kMsToRtpTimestamp = 90;
|
|
|
|
|
decode_buffer_.timeStamp = kMsToRtpTimestamp *
|
2013-04-09 13:41:51 +00:00
|
|
|
static_cast<uint32_t>(video_frame->RenderTimeMs());
|
2011-12-14 08:36:01 +00:00
|
|
|
decode_buffer_.payloadType = codec_.plType;
|
|
|
|
|
vcm_->DecodeFromStorage(decode_buffer_);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
int ViECapturer::DeregisterFrameCallback(
|
|
|
|
|
const ViEFrameCallback* callbackObject) {
|
2011-12-22 14:17:53 +00:00
|
|
|
provider_cs_->Enter();
|
2011-12-14 08:36:01 +00:00
|
|
|
if (callbackObject == vie_encoder_) {
|
|
|
|
|
// Don't use this camera as encoder anymore. Need to tell the ViEEncoder.
|
|
|
|
|
ViEEncoder* vie_encoder = NULL;
|
|
|
|
|
vie_encoder = vie_encoder_;
|
|
|
|
|
vie_encoder_ = NULL;
|
2011-12-22 14:17:53 +00:00
|
|
|
provider_cs_->Leave();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
// Need to take this here in order to avoid deadlock with VCM. The reason is
|
|
|
|
|
// that VCM will call ::Release and a deadlock can occur.
|
2011-12-22 14:17:53 +00:00
|
|
|
deliver_cs_->Enter();
|
2011-12-14 08:36:01 +00:00
|
|
|
vie_encoder->DeRegisterExternalEncoder(codec_.plType);
|
2011-12-22 14:17:53 +00:00
|
|
|
deliver_cs_->Leave();
|
2011-07-07 08:21:25 +00:00
|
|
|
return 0;
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
2011-12-22 14:17:53 +00:00
|
|
|
provider_cs_->Leave();
|
2011-12-14 08:36:01 +00:00
|
|
|
return ViEFrameProviderBase::DeregisterFrameCallback(callbackObject);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
bool ViECapturer::IsFrameCallbackRegistered(
|
|
|
|
|
const ViEFrameCallback* callbackObject) {
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(provider_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (callbackObject == vie_encoder_) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return ViEFrameProviderBase::IsFrameCallbackRegistered(callbackObject);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::PreEncodeToViEEncoder(const VideoCodec& codec,
|
|
|
|
|
ViEEncoder& vie_encoder,
|
|
|
|
|
int32_t vie_encoder_id) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d)", __FUNCTION__, capture_id_);
|
|
|
|
|
if (vie_encoder_ && &vie_encoder != vie_encoder_) {
|
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d Capture device already encoding)",
|
|
|
|
|
__FUNCTION__, capture_id_);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(encoding_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
VideoCaptureModule::VideoCaptureEncodeInterface* capture_encoder =
|
|
|
|
|
capture_module_->GetEncodeInterface(codec);
|
|
|
|
|
if (!capture_encoder) {
|
|
|
|
|
// Encoding not supported?
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
capture_encoder_ = capture_encoder;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
// Create VCM module used for decoding frames if needed.
|
|
|
|
|
if (!vcm_) {
|
|
|
|
|
vcm_ = VideoCodingModule::Create(capture_id_);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-01-09 08:35:40 +00:00
|
|
|
if (vie_encoder.RegisterExternalEncoder(this, codec.plType, false) != 0) {
|
2011-12-14 08:36:01 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (vie_encoder.SetEncoder(codec) != 0) {
|
|
|
|
|
vie_encoder.DeRegisterExternalEncoder(codec.plType);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
// Make sure the encoder is not an I420 observer.
|
|
|
|
|
ViEFrameProviderBase::DeregisterFrameCallback(&vie_encoder);
|
|
|
|
|
// Store the vie_encoder using this capture device.
|
|
|
|
|
vie_encoder_ = &vie_encoder;
|
|
|
|
|
vie_encoder_id_ = vie_encoder_id;
|
|
|
|
|
memcpy(&codec_, &codec, sizeof(VideoCodec));
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
bool ViECapturer::EncoderActive() {
|
|
|
|
|
return vie_encoder_ != NULL;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
bool ViECapturer::CaptureCapabilityFixed() {
|
|
|
|
|
return requested_capability_.width != 0 &&
|
|
|
|
|
requested_capability_.height != 0 &&
|
|
|
|
|
requested_capability_.maxFPS != 0;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::Version(char* version, int32_t length) const {
|
2011-12-14 08:36:01 +00:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::InitEncode(const VideoCodec* codec_settings,
|
|
|
|
|
int32_t number_of_cores,
|
|
|
|
|
uint32_t max_payload_size) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d)", __FUNCTION__, capture_id_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(encoding_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (!capture_encoder_ || !codec_settings) {
|
|
|
|
|
return WEBRTC_VIDEO_CODEC_ERROR;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
if (vcm_) {
|
|
|
|
|
// Initialize VCM to be able to decode frames if needed.
|
|
|
|
|
if (vcm_->InitializeReceiver() == 0) {
|
|
|
|
|
if (vcm_->RegisterReceiveCallback(this) == 0) {
|
|
|
|
|
if (vcm_->RegisterReceiveCodec(codec_settings, number_of_cores,
|
|
|
|
|
false) == 0) {
|
|
|
|
|
decoder_initialized_ = true;
|
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d) VCM Decoder initialized",
|
|
|
|
|
__FUNCTION__, capture_id_);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
}
|
|
|
|
|
return capture_encoder_->ConfigureEncoder(*codec_settings, max_payload_size);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::Encode(
|
2012-10-24 18:33:04 +00:00
|
|
|
const I420VideoFrame& input_image,
|
2012-10-08 07:06:53 +00:00
|
|
|
const CodecSpecificInfo* codec_specific_info,
|
|
|
|
|
const std::vector<VideoFrameType>* frame_types) {
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(encoding_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (!capture_encoder_) {
|
|
|
|
|
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
|
|
|
|
}
|
2012-10-08 07:06:53 +00:00
|
|
|
if (frame_types == NULL) {
|
|
|
|
|
return capture_encoder_->EncodeFrameType(kVideoFrameDelta);
|
|
|
|
|
} else if ((*frame_types)[0] == kKeyFrame) {
|
2011-12-14 08:36:01 +00:00
|
|
|
return capture_encoder_->EncodeFrameType(kVideoFrameKey);
|
2012-10-08 07:06:53 +00:00
|
|
|
} else if ((*frame_types)[0] == kSkipFrame) {
|
2011-12-14 08:36:01 +00:00
|
|
|
return capture_encoder_->EncodeFrameType(kFrameEmpty);
|
|
|
|
|
}
|
|
|
|
|
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::RegisterEncodeCompleteCallback(
|
2011-12-14 08:36:01 +00:00
|
|
|
EncodedImageCallback* callback) {
|
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d)", __FUNCTION__, capture_id_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(deliver_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (!capture_encoder_) {
|
|
|
|
|
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
|
|
|
|
}
|
|
|
|
|
encode_complete_callback_ = callback;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::Release() {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d)", __FUNCTION__, capture_id_);
|
|
|
|
|
{
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(deliver_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
encode_complete_callback_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(encoding_cs_.get());
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
decoder_initialized_ = false;
|
|
|
|
|
codec_.codecType = kVideoCodecUnknown;
|
|
|
|
|
// Reset the camera to output I420.
|
|
|
|
|
capture_encoder_->ConfigureEncoder(codec_, 0);
|
|
|
|
|
|
|
|
|
|
if (vie_encoder_) {
|
|
|
|
|
// Need to add the encoder as an observer of I420.
|
|
|
|
|
ViEFrameProviderBase::RegisterFrameCallback(vie_encoder_id_,
|
|
|
|
|
vie_encoder_);
|
|
|
|
|
}
|
|
|
|
|
vie_encoder_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
// Should reset the capture device to the state it was in after the InitEncode
|
|
|
|
|
// function. Current implementation do nothing.
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::Reset() {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d)", __FUNCTION__, capture_id_);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::SetChannelParameters(uint32_t packet_loss, int rtt) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d)", __FUNCTION__, capture_id_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(encoding_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (!capture_encoder_) {
|
|
|
|
|
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
|
|
|
|
}
|
|
|
|
|
return capture_encoder_->SetChannelParameters(packet_loss, rtt);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s(capture_device_id: %d)", __FUNCTION__, capture_id_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(encoding_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (!capture_encoder_) {
|
|
|
|
|
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
|
|
|
|
|
}
|
|
|
|
|
return capture_encoder_->SetRates(new_bit_rate, frame_rate);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::FrameToRender(
|
2012-10-24 18:33:04 +00:00
|
|
|
I420VideoFrame& video_frame) { //NOLINT
|
2011-12-22 14:17:53 +00:00
|
|
|
deliver_cs_->Enter();
|
2012-06-21 12:11:50 +00:00
|
|
|
DeliverI420Frame(&video_frame);
|
2011-12-22 14:17:53 +00:00
|
|
|
deliver_cs_->Leave();
|
2011-12-14 08:36:01 +00:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::RegisterObserver(ViECaptureObserver* observer) {
|
2011-12-14 08:36:01 +00:00
|
|
|
if (observer_) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s Observer already registered", __FUNCTION__, capture_id_);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (capture_module_->RegisterCaptureCallback(*this) != 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
capture_module_->EnableFrameRateCallback(true);
|
|
|
|
|
capture_module_->EnableNoPictureAlarm(true);
|
2012-06-21 12:11:50 +00:00
|
|
|
observer_ = observer;
|
2011-12-14 08:36:01 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
int32_t ViECapturer::DeRegisterObserver() {
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(observer_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
if (!observer_) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"%s No observer registered", __FUNCTION__, capture_id_);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
capture_module_->EnableFrameRateCallback(false);
|
|
|
|
|
capture_module_->EnableNoPictureAlarm(false);
|
|
|
|
|
capture_module_->DeRegisterCaptureCallback();
|
|
|
|
|
observer_ = NULL;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
|
|
|
|
|
bool ViECapturer::IsObserverRegistered() {
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(observer_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
return observer_ != NULL;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-14 08:36:01 +00:00
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
void ViECapturer::OnCaptureFrameRate(const int32_t id,
|
|
|
|
|
const uint32_t frame_rate) {
|
2011-12-14 08:36:01 +00:00
|
|
|
WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"OnCaptureFrameRate %d", frame_rate);
|
|
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(observer_cs_.get());
|
2013-04-09 13:41:51 +00:00
|
|
|
observer_->CapturedFrameRate(id_, static_cast<uint8_t>(frame_rate));
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-09 13:41:51 +00:00
|
|
|
void ViECapturer::OnNoPictureAlarm(const int32_t id,
|
2011-12-14 08:36:01 +00:00
|
|
|
const VideoCaptureAlarm alarm) {
|
|
|
|
|
WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, capture_id_),
|
|
|
|
|
"OnNoPictureAlarm %d", alarm);
|
|
|
|
|
|
2011-12-22 14:17:53 +00:00
|
|
|
CriticalSectionScoped cs(observer_cs_.get());
|
2011-12-14 08:36:01 +00:00
|
|
|
CaptureAlarm vie_alarm = (alarm == Raised) ? AlarmRaised : AlarmCleared;
|
|
|
|
|
observer_->NoPictureAlarm(id, vie_alarm);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 08:36:01 +00:00
|
|
|
} // namespace webrtc
|