blob: ec2249e869481a6a94e2c9f25eef56b21c241a14 [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 "webrtc/video_engine/vie_frame_provider_base.h"
#include <algorithm>
#include "webrtc/base/checks.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
#include "webrtc/video_engine/vie_defines.h"
#include "webrtc/video_frame.h"
namespace webrtc {
ViEFrameProviderBase::ViEFrameProviderBase(int Id, int engine_id)
: id_(Id),
engine_id_(engine_id),
provider_cs_(CriticalSectionWrapper::CreateCriticalSection()),
frame_delay_(0) {
frame_delivery_thread_checker_.DetachFromThread();
}
ViEFrameProviderBase::~ViEFrameProviderBase() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(frame_callbacks_.empty());
// TODO(tommi): Remove this when we're confident we've fixed the places where
// cleanup wasn't being done.
for (ViEFrameCallback* callback : frame_callbacks_) {
LOG_F(LS_WARNING) << "FrameCallback still registered.";
callback->ProviderDestroyed(id_);
}
}
int ViEFrameProviderBase::Id() const {
return id_;
}
void ViEFrameProviderBase::DeliverFrame(const I420VideoFrame& video_frame,
const std::vector<uint32_t>& csrcs) {
DCHECK(frame_delivery_thread_checker_.CalledOnValidThread());
#ifdef DEBUG_
const TickTime start_process_time = TickTime::Now();
#endif
CriticalSectionScoped cs(provider_cs_.get());
// Deliver the frame to all registered callbacks.
for (ViEFrameCallback* callback : frame_callbacks_)
callback->DeliverFrame(id_, video_frame, csrcs);
#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.
LOG(LS_WARNING) << "Too long time delivering frame " << process_time;
}
#endif
}
void ViEFrameProviderBase::SetFrameDelay(int frame_delay) {
// Called on the capture thread (see OnIncomingCapturedFrame).
// To test, run ViEStandardIntegrationTest.RunsBaseTestWithoutErrors
// in vie_auto_tests.
// In the same test, it appears that it's also called on a thread that's
// neither the ctor thread nor the capture thread.
CriticalSectionScoped cs(provider_cs_.get());
frame_delay_ = frame_delay;
for (ViEFrameCallback* callback : frame_callbacks_) {
callback->DelayChanged(id_, frame_delay);
}
}
int ViEFrameProviderBase::FrameDelay() {
// Called on the default thread in WebRtcVideoMediaChannelTest.SetSend
// (libjingle_media_unittest).
// Called on neither the ctor thread nor the capture thread in
// BitrateEstimatorTest.ImmediatelySwitchToAST (video_engine_tests).
// Most of the time Called on the capture thread (see OnCaptureDelayChanged).
// To test, run ViEStandardIntegrationTest.RunsBaseTestWithoutErrors
// in vie_auto_tests.
return frame_delay_;
}
int ViEFrameProviderBase::GetBestFormat(int* best_width,
int* best_height,
int* best_frame_rate) {
DCHECK(thread_checker_.CalledOnValidThread());
int largest_width = 0;
int largest_height = 0;
int highest_frame_rate = 0;
// Here we don't need to grab the provider_cs_ lock to run through the list
// of callbacks. The reason is that we know that we're currently on the same
// thread that is the only thread that will modify the callback list and
// we can be sure that the thread won't race with itself.
for (ViEFrameCallback* callback : frame_callbacks_) {
int prefered_width = 0;
int prefered_height = 0;
int prefered_frame_rate = 0;
if (callback->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) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(callback_object);
{
CriticalSectionScoped cs(provider_cs_.get());
if (std::find(frame_callbacks_.begin(), frame_callbacks_.end(),
callback_object) != frame_callbacks_.end()) {
DCHECK(false && "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) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(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()) {
return -1;
}
frame_callbacks_.erase(it);
}
// Notify implementer of this class that the callback list have changed.
FrameCallbackChanged();
return 0;
}
bool ViEFrameProviderBase::IsFrameCallbackRegistered(
const ViEFrameCallback* callback_object) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(callback_object);
// Here we don't need to grab the lock to do this lookup.
// The reason is that we know that we're currently on the same thread that
// is the only thread that will modify the callback list and subsequently the
// thread doesn't race with itself.
return std::find(frame_callbacks_.begin(), frame_callbacks_.end(),
callback_object) != frame_callbacks_.end();
}
} // namespac webrtc