blob: 8b7bf1f7e190036abd7ac62fc12858032f7c84e2 [file] [log] [blame]
/*
* Copyright (c) 2012 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 <algorithm>
#include "modules/interface/module_common_types.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),
provider_cs_(CriticalSectionWrapper::CreateCriticalSection()),
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 (FrameCallbacks::iterator it = frame_callbacks_.begin();
it != frame_callbacks_.end(); ++it) {
(*it)->ProviderDestroyed(id_);
}
frame_callbacks_.clear();
}
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.
frame_callbacks_.front()->DeliverFrame(id_, video_frame, num_csrcs, CSRC);
} else {
// Make a copy of the frame for all callbacks.callback
for (FrameCallbacks::iterator it = frame_callbacks_.begin();
it != frame_callbacks_.end(); ++it) {
if (!extra_frame_.get()) {
extra_frame_.reset(new VideoFrame());
}
extra_frame_->CopyFrame(video_frame);
(*it)->DeliverFrame(id_, *(extra_frame_.get()), 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 (FrameCallbacks::iterator it = frame_callbacks_.begin();
it != frame_callbacks_.end(); ++it) {
(*it)->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());
for (FrameCallbacks::iterator it = frame_callbacks_.begin();
it != frame_callbacks_.end(); ++it) {
int prefered_width = 0;
int prefered_height = 0;
int prefered_frame_rate = 0;
if ((*it)->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) {
assert(callback_object);
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_), "%s(0x%p)",
__FUNCTION__, callback_object);
{
CriticalSectionScoped cs(provider_cs_.get());
if (std::find(frame_callbacks_.begin(), frame_callbacks_.end(),
callback_object) != frame_callbacks_.end()) {
// This object 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;
}
frame_callbacks_.push_back(callback_object);
}
// 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) {
assert(callback_object);
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_), "%s(0x%p)",
__FUNCTION__, callback_object);
CriticalSectionScoped cs(provider_cs_.get());
FrameCallbacks::iterator it = std::find(frame_callbacks_.begin(),
frame_callbacks_.end(),
callback_object);
if (it == frame_callbacks_.end()) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, id_),
"%s 0x%p not found", __FUNCTION__, callback_object);
return -1;
}
frame_callbacks_.erase(it);
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_),
"%s 0x%p deregistered", __FUNCTION__, callback_object);
// Notify implementer of this class that the callback list have changed.
FrameCallbackChanged();
return 0;
}
bool ViEFrameProviderBase::IsFrameCallbackRegistered(
const ViEFrameCallback* callback_object) {
assert(callback_object);
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, id_),
"%s(0x%p)", __FUNCTION__, callback_object);
CriticalSectionScoped cs(provider_cs_.get());
return std::find(frame_callbacks_.begin(), frame_callbacks_.end(),
callback_object) != frame_callbacks_.end();
}
int ViEFrameProviderBase::NumberOfRegisteredFrameCallbacks() {
CriticalSectionScoped cs(provider_cs_.get());
return frame_callbacks_.size();
}
} // namespac webrtc