blob: 8ed092b71884a39721f880cf015b1c87420b0b46 [file] [log] [blame]
/*
* Copyright (c) 2011 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 "video_engine/vie_frame_provider_base.h"
#include "system_wrappers/interface/critical_section_wrapper.h"
#include "system_wrappers/interface/tick_util.h"
#include "system_wrappers/interface/trace.h"
#include "video_engine/vie_defines.h"
namespace webrtc {
ViEFrameProviderBase::ViEFrameProviderBase(int Id, int engine_id)
: id_(Id),
engine_id_(engine_id),
frame_callbacks_(),
provider_cs_(CriticalSectionWrapper::CreateCriticalSection()),
extra_frame_(NULL),
frame_delay_(0) {
}
ViEFrameProviderBase::~ViEFrameProviderBase() {
if (frame_callbacks_.Size() > 0) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, id_),
"FrameCallbacks still exist when Provider deleted %d",
frame_callbacks_.Size());
}
for (MapItem* item = frame_callbacks_.First(); item != NULL;
item = frame_callbacks_.Next(item)) {
static_cast<ViEFrameCallback*>(item->GetItem())->ProviderDestroyed(id_);
}
while (frame_callbacks_.Erase(frame_callbacks_.First()) == 0) {
}
delete extra_frame_;
}
int ViEFrameProviderBase::Id() {
return id_;
}
void ViEFrameProviderBase::DeliverFrame(
VideoFrame& video_frame,
int num_csrcs,
const WebRtc_UWord32 CSRC[kRtpCsrcSize]) {
#ifdef DEBUG_
const TickTime start_process_time = TickTime::Now();
#endif
CriticalSectionScoped cs(provider_cs_.get());
// Deliver the frame to all registered callbacks.
if (frame_callbacks_.Size() > 0) {
if (frame_callbacks_.Size() == 1) {
// We don't have to copy the frame.
ViEFrameCallback* frame_observer =
static_cast<ViEFrameCallback*>(frame_callbacks_.First()->GetItem());
frame_observer->DeliverFrame(id_, video_frame, num_csrcs, CSRC);
} else {
// Make a copy of the frame for all callbacks.
for (MapItem* map_item = frame_callbacks_.First(); map_item != NULL;
map_item = frame_callbacks_.Next(map_item)) {
if (extra_frame_ == NULL) {
extra_frame_ = new VideoFrame();
}
if (map_item != NULL) {
ViEFrameCallback* frame_observer =
static_cast<ViEFrameCallback*>(map_item->GetItem());
if (frame_observer != NULL) {
// We must copy the frame each time since the previous receiver
// might swap it to avoid a copy.
extra_frame_->CopyFrame(video_frame);
frame_observer->DeliverFrame(id_, *extra_frame_, num_csrcs, CSRC);
}
}
}
}
}
#ifdef DEBUG_
const int process_time =
static_cast<int>((TickTime::Now() - start_process_time).Milliseconds());
if (process_time > 25) {
// Warn if the delivery time is too long.
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, id_),
"%s Too long time: %ums", __FUNCTION__, process_time);
}
#endif
}
void ViEFrameProviderBase::SetFrameDelay(int frame_delay) {
CriticalSectionScoped cs(provider_cs_.get());
frame_delay_ = frame_delay;
for (MapItem* map_item = frame_callbacks_.First(); map_item != NULL;
map_item = frame_callbacks_.Next(map_item)) {
ViEFrameCallback* frame_observer =
static_cast<ViEFrameCallback*>(map_item->GetItem());
assert(frame_observer);
frame_observer->DelayChanged(id_, frame_delay);
}
}
int ViEFrameProviderBase::FrameDelay() {
return frame_delay_;
}
int ViEFrameProviderBase::GetBestFormat(int& best_width,
int& best_height,
int& best_frame_rate) {
int largest_width = 0;
int largest_height = 0;
int highest_frame_rate = 0;
CriticalSectionScoped cs(provider_cs_.get());
// Check if this one already exists.
for (MapItem* map_item = frame_callbacks_.First(); map_item != NULL;
map_item = frame_callbacks_.Next(map_item)) {
int prefered_width = 0;
int prefered_height = 0;
int prefered_frame_rate = 0;
ViEFrameCallback* callback_object =
static_cast<ViEFrameCallback*>(map_item->GetItem());
assert(callback_object);
if (callback_object->GetPreferedFrameSettings(prefered_width,
prefered_height,
prefered_frame_rate) == 0) {
if (prefered_width > largest_width) {
largest_width = prefered_width;
}
if (prefered_height > largest_height) {
largest_height = prefered_height;
}
if (prefered_frame_rate > highest_frame_rate) {
highest_frame_rate = prefered_frame_rate;
}
}
}
best_width = largest_width;
best_height = largest_height;
best_frame_rate = highest_frame_rate;
return 0;
}
int ViEFrameProviderBase::RegisterFrameCallback(
int observer_id, ViEFrameCallback* callback_object) {
if (callback_object == NULL) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, id_),
"%s: No argument", __FUNCTION__);
return -1;
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_), "%s(0x%p)",
__FUNCTION__, callback_object);
{
CriticalSectionScoped cs(provider_cs_.get());
// Check if the callback already exists.
for (MapItem* map_item = frame_callbacks_.First();
map_item != NULL;
map_item = frame_callbacks_.Next(map_item)) {
const ViEFrameCallback* observer =
static_cast<ViEFrameCallback*>(map_item->GetItem());
if (observer == callback_object) {
// This callback is already registered.
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, id_),
"%s 0x%p already registered", __FUNCTION__,
callback_object);
assert("!frameObserver already registered");
return -1;
}
}
if (frame_callbacks_.Insert(observer_id, callback_object) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, id_),
"%s: Could not add 0x%p to list", __FUNCTION__,
callback_object);
return -1;
}
}
// Report current capture delay
callback_object->DelayChanged(id_, frame_delay_);
// Notify implementer of this class that the callback list have changed.
FrameCallbackChanged();
return 0;
}
int ViEFrameProviderBase::DeregisterFrameCallback(
const ViEFrameCallback* callback_object) {
if (!callback_object) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, id_),
"%s: No argument", __FUNCTION__);
return -1;
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_), "%s(0x%p)",
__FUNCTION__, callback_object);
{
CriticalSectionScoped cs(provider_cs_.get());
bool item_found = false;
// Try to find the callback in our list.
for (MapItem* map_item = frame_callbacks_.First(); map_item != NULL;
map_item = frame_callbacks_.Next(map_item)) {
const ViEFrameCallback* observer =
static_cast<ViEFrameCallback*>(map_item->GetItem());
if (observer == callback_object) {
// We found it, remove it!
frame_callbacks_.Erase(map_item);
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_),
"%s 0x%p deregistered", __FUNCTION__, callback_object);
item_found = true;
break;
}
}
if (!item_found) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, id_),
"%s 0x%p not found", __FUNCTION__, callback_object);
return -1;
}
}
// Notify implementer of this class that the callback list have changed.
FrameCallbackChanged();
return 0;
}
bool ViEFrameProviderBase::IsFrameCallbackRegistered(
const ViEFrameCallback* callback_object) {
if (!callback_object) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, id_),
"%s: No argument", __FUNCTION__);
return false;
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_),
"%s(0x%p)", __FUNCTION__, callback_object);
for (MapItem* map_item = frame_callbacks_.First(); map_item != NULL;
map_item = frame_callbacks_.Next(map_item)) {
if (callback_object == map_item->GetItem()) {
// We found the callback.
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_),
"%s 0x%p is registered", __FUNCTION__, callback_object);
return true;
}
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_),
"%s 0x%p not registered", __FUNCTION__, callback_object);
return false;
}
int ViEFrameProviderBase::NumberOfRegisteredFrameCallbacks() {
CriticalSectionScoped cs(provider_cs_.get());
return frame_callbacks_.Size();
}
} // namespac webrtc