webrtc_m130/webrtc/video_engine/vie_codec_impl.cc
henrik.lundin@webrtc.org 1a3a6e5340 Removing the threshold from the auto-mute APIs
The threshold is now set equal to the minimum bitrate of the
encoder. The test is also changed to have the REMB values
depend on the minimum bitrate from the encoder.

BUG=2436
R=pbos@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/2919004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5040 4adac7df-926f-26a2-2b94-8c16560cd09d
2013-10-28 10:16:14 +00:00

794 lines
30 KiB
C++

/*
* 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_codec_impl.h"
#include <list>
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/video_engine/include/vie_errors.h"
#include "webrtc/video_engine/vie_capturer.h"
#include "webrtc/video_engine/vie_channel.h"
#include "webrtc/video_engine/vie_channel_manager.h"
#include "webrtc/video_engine/vie_defines.h"
#include "webrtc/video_engine/vie_encoder.h"
#include "webrtc/video_engine/vie_impl.h"
#include "webrtc/video_engine/vie_input_manager.h"
#include "webrtc/video_engine/vie_shared_data.h"
namespace webrtc {
ViECodec* ViECodec::GetInterface(VideoEngine* video_engine) {
#ifdef WEBRTC_VIDEO_ENGINE_CODEC_API
if (!video_engine) {
return NULL;
}
VideoEngineImpl* vie_impl = static_cast<VideoEngineImpl*>(video_engine);
ViECodecImpl* vie_codec_impl = vie_impl;
// Increase ref count.
(*vie_codec_impl)++;
return vie_codec_impl;
#else
return NULL;
#endif
}
int ViECodecImpl::Release() {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_->instance_id(),
"ViECodecImpl::Release()");
// Decrease ref count.
(*this)--;
int32_t ref_count = GetCount();
if (ref_count < 0) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo, shared_data_->instance_id(),
"ViECodec released too many times");
shared_data_->SetLastError(kViEAPIDoesNotExist);
return -1;
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo, shared_data_->instance_id(),
"ViECodec reference count: %d", ref_count);
return ref_count;
}
ViECodecImpl::ViECodecImpl(ViESharedData* shared_data)
: shared_data_(shared_data) {
WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_->instance_id(),
"ViECodecImpl::ViECodecImpl() Ctor");
}
ViECodecImpl::~ViECodecImpl() {
WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_->instance_id(),
"ViECodecImpl::~ViECodecImpl() Dtor");
}
int ViECodecImpl::NumberOfCodecs() const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s", __FUNCTION__);
// +2 because of FEC(RED and ULPFEC)
return static_cast<int>((VideoCodingModule::NumberOfCodecs() + 2));
}
int ViECodecImpl::GetCodec(const unsigned char list_number,
VideoCodec& video_codec) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s(list_number: %d)", __FUNCTION__, list_number);
if (list_number == VideoCodingModule::NumberOfCodecs()) {
memset(&video_codec, 0, sizeof(VideoCodec));
strcpy(video_codec.plName, "red");
video_codec.codecType = kVideoCodecRED;
video_codec.plType = VCM_RED_PAYLOAD_TYPE;
} else if (list_number == VideoCodingModule::NumberOfCodecs() + 1) {
memset(&video_codec, 0, sizeof(VideoCodec));
strcpy(video_codec.plName, "ulpfec");
video_codec.codecType = kVideoCodecULPFEC;
video_codec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
} else if (VideoCodingModule::Codec(list_number, &video_codec) != VCM_OK) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s: Could not get codec for list_number: %u", __FUNCTION__,
list_number);
shared_data_->SetLastError(kViECodecInvalidArgument);
return -1;
}
return 0;
}
int ViECodecImpl::SetSendCodec(const int video_channel,
const VideoCodec& video_codec) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d, codec_type: %d)", __FUNCTION__,
video_channel, video_codec.codecType);
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: codec: %d, pl_type: %d, width: %d, height: %d, bitrate: %d"
"maxBr: %d, min_br: %d, frame_rate: %d, qpMax: %u,"
"numberOfSimulcastStreams: %u )", __FUNCTION__,
video_codec.codecType, video_codec.plType, video_codec.width,
video_codec.height, video_codec.startBitrate,
video_codec.maxBitrate, video_codec.minBitrate,
video_codec.maxFramerate, video_codec.qpMax,
video_codec.numberOfSimulcastStreams);
if (video_codec.codecType == kVideoCodecVP8) {
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"pictureLossIndicationOn: %d, feedbackModeOn: %d, "
"complexity: %d, resilience: %d, numberOfTemporalLayers: %u"
"keyFrameInterval %d",
video_codec.codecSpecific.VP8.pictureLossIndicationOn,
video_codec.codecSpecific.VP8.feedbackModeOn,
video_codec.codecSpecific.VP8.complexity,
video_codec.codecSpecific.VP8.resilience,
video_codec.codecSpecific.VP8.numberOfTemporalLayers,
video_codec.codecSpecific.VP8.keyFrameInterval);
}
if (!CodecValid(video_codec)) {
// Error logged.
shared_data_->SetLastError(kViECodecInvalidCodec);
return -1;
}
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
assert(vie_encoder);
if (vie_encoder->Owner() != video_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Receive only channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecReceiveOnlyChannel);
return -1;
}
// Set a max_bitrate if the user hasn't set one.
VideoCodec video_codec_internal;
memcpy(&video_codec_internal, &video_codec, sizeof(VideoCodec));
if (video_codec_internal.maxBitrate == 0) {
// Max is one bit per pixel.
video_codec_internal.maxBitrate = (video_codec_internal.width *
video_codec_internal.height *
video_codec_internal.maxFramerate)
/ 1000;
if (video_codec_internal.startBitrate > video_codec_internal.maxBitrate) {
// Don't limit the set start bitrate.
video_codec_internal.maxBitrate = video_codec_internal.startBitrate;
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: New max bitrate set to %d kbps", __FUNCTION__,
video_codec_internal.maxBitrate);
}
VideoCodec encoder;
vie_encoder->GetEncoder(&encoder);
// Make sure to generate a new SSRC if the codec type and/or resolution has
// changed. This won't have any effect if the user has set an SSRC.
bool new_rtp_stream = false;
if (encoder.codecType != video_codec_internal.codecType) {
new_rtp_stream = true;
}
ViEInputManagerScoped is(*(shared_data_->input_manager()));
// Stop the media flow while reconfiguring.
vie_encoder->Pause();
if (vie_encoder->SetEncoder(video_codec_internal) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Could not change encoder for channel %d", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
// Give the channel(s) the new information.
ChannelList channels;
cs.ChannelsUsingViEEncoder(video_channel, &channels);
for (ChannelList::iterator it = channels.begin(); it != channels.end();
++it) {
bool ret = true;
if ((*it)->SetSendCodec(video_codec_internal, new_rtp_stream) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Could not set send codec for channel %d", __FUNCTION__,
video_channel);
ret = false;
}
if (!ret) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
}
// TODO(mflodman) Break out this part in GetLocalSsrcList().
// Update all SSRCs to ViEEncoder.
std::list<unsigned int> ssrcs;
if (video_codec_internal.numberOfSimulcastStreams == 0) {
unsigned int ssrc = 0;
if (vie_channel->GetLocalSSRC(0, &ssrc) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Could not get ssrc", __FUNCTION__);
}
ssrcs.push_back(ssrc);
} else {
for (int idx = 0; idx < video_codec_internal.numberOfSimulcastStreams;
++idx) {
unsigned int ssrc = 0;
if (vie_channel->GetLocalSSRC(idx, &ssrc) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Could not get ssrc for idx %d", __FUNCTION__, idx);
}
ssrcs.push_back(ssrc);
}
}
vie_encoder->SetSsrcs(ssrcs);
shared_data_->channel_manager()->UpdateSsrcs(video_channel, ssrcs);
// Update the protection mode, we might be switching NACK/FEC.
vie_encoder->UpdateProtectionMethod(vie_encoder->nack_enabled());
// Get new best format for frame provider.
ViEFrameProviderBase* frame_provider = is.FrameProvider(vie_encoder);
if (frame_provider) {
frame_provider->FrameCallbackChanged();
}
// Restart the media flow
if (new_rtp_stream) {
// Stream settings changed, make sure we get a key frame.
vie_encoder->SendKeyFrame();
}
vie_encoder->Restart();
return 0;
}
int ViECodecImpl::GetSendCodec(const int video_channel,
VideoCodec& video_codec) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No encoder for channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
return vie_encoder->GetEncoder(&video_codec);
}
int ViECodecImpl::SetReceiveCodec(const int video_channel,
const VideoCodec& video_codec) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d, codec_type: %d)", __FUNCTION__,
video_channel, video_codec.codecType);
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: codec: %d, pl_type: %d, width: %d, height: %d, bitrate: %d,"
"maxBr: %d, min_br: %d, frame_rate: %d", __FUNCTION__,
video_codec.codecType, video_codec.plType, video_codec.width,
video_codec.height, video_codec.startBitrate,
video_codec.maxBitrate, video_codec.minBitrate,
video_codec.maxFramerate);
if (CodecValid(video_codec) == false) {
// Error logged.
shared_data_->SetLastError(kViECodecInvalidCodec);
return -1;
}
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_channel->SetReceiveCodec(video_codec) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Could not set receive codec for channel %d",
__FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::GetReceiveCodec(const int video_channel,
VideoCodec& video_codec) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d, codec_type: %d)", __FUNCTION__,
video_channel, video_codec.codecType);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_channel->GetReceiveCodec(&video_codec) != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::GetCodecConfigParameters(
const int video_channel,
unsigned char config_parameters[kConfigParameterSize],
unsigned char& config_parameters_size) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No encoder for channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_encoder->GetCodecConfigParameters(config_parameters,
config_parameters_size) != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::SetImageScaleStatus(const int video_channel,
const bool enable) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d, enable: %d)", __FUNCTION__, video_channel,
enable);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_encoder->ScaleInputImage(enable) != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::GetSendCodecStastistics(const int video_channel,
unsigned int& key_frames,
unsigned int& delta_frames) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No send codec for channel %d", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_encoder->SendCodecStatistics(&key_frames, &delta_frames) != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::GetReceiveCodecStastistics(const int video_channel,
unsigned int& key_frames,
unsigned int& delta_frames) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d)", __FUNCTION__,
video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_channel->ReceiveCodecStatistics(&key_frames, &delta_frames) != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::GetReceiveSideDelay(const int video_channel,
int* delay_ms) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
if (delay_ms == NULL) {
LOG_F(LS_ERROR) << "NULL pointer argument.";
return -1;
}
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
*delay_ms = vie_channel->ReceiveDelay();
if (*delay_ms < 0) {
return -1;
}
return 0;
}
int ViECodecImpl::GetCodecTargetBitrate(const int video_channel,
unsigned int* bitrate) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d, codec_type: %d)", __FUNCTION__,
video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No send codec for channel %d", __FUNCTION__,
video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
return vie_encoder->CodecTargetBitrate(static_cast<uint32_t*>(bitrate));
}
unsigned int ViECodecImpl::GetDiscardedPackets(const int video_channel) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d, codec_type: %d)", __FUNCTION__,
video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
return vie_channel->DiscardedPackets();
}
int ViECodecImpl::SetKeyFrameRequestCallbackStatus(const int video_channel,
const bool enable) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_channel->EnableKeyFrameRequestCallback(enable) != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::SetSignalKeyPacketLossStatus(const int video_channel,
const bool enable,
const bool only_key_frames) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s(video_channel: %d, enable: %d, only_key_frames: %d)",
__FUNCTION__, video_channel, enable);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_channel->SetSignalPacketLossStatus(enable, only_key_frames) != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::RegisterEncoderObserver(const int video_channel,
ViEEncoderObserver& observer) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s", __FUNCTION__);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No encoder for channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_encoder->RegisterCodecObserver(&observer) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Could not register codec observer at channel",
__FUNCTION__);
shared_data_->SetLastError(kViECodecObserverAlreadyRegistered);
return -1;
}
return 0;
}
int ViECodecImpl::DeregisterEncoderObserver(const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s", __FUNCTION__);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No encoder for channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_encoder->RegisterCodecObserver(NULL) != 0) {
shared_data_->SetLastError(kViECodecObserverNotRegistered);
return -1;
}
return 0;
}
int ViECodecImpl::RegisterDecoderObserver(const int video_channel,
ViEDecoderObserver& observer) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s", __FUNCTION__);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_channel->RegisterCodecObserver(&observer) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Could not register codec observer at channel",
__FUNCTION__);
shared_data_->SetLastError(kViECodecObserverAlreadyRegistered);
return -1;
}
return 0;
}
int ViECodecImpl::DeregisterDecoderObserver(const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id()), "%s",
__FUNCTION__);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_channel->RegisterCodecObserver(NULL) != 0) {
shared_data_->SetLastError(kViECodecObserverNotRegistered);
return -1;
}
return 0;
}
int ViECodecImpl::SendKeyFrame(const int video_channel) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(shared_data_->instance_id()),
"%s(video_channel: %d)", __FUNCTION__, video_channel);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_encoder->SendKeyFrame() != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::WaitForFirstKeyFrame(const int video_channel,
const bool wait) {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
ViEId(shared_data_->instance_id()),
"%s(video_channel: %d, wait: %d)", __FUNCTION__, video_channel,
wait);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
if (vie_channel->WaitForKeyFrame(wait) != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
return -1;
}
return 0;
}
int ViECodecImpl::StartDebugRecording(int video_channel,
const char* file_name_utf8) {
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No encoder %d", __FUNCTION__, video_channel);
return -1;
}
return vie_encoder->StartDebugRecording(file_name_utf8);
}
int ViECodecImpl::StopDebugRecording(int video_channel) {
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No encoder %d", __FUNCTION__, video_channel);
return -1;
}
return vie_encoder->StopDebugRecording();
}
void ViECodecImpl::EnableAutoMuting(int video_channel) {
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No encoder %d", __FUNCTION__, video_channel);
return;
}
return vie_encoder->EnableAutoMuting();
}
bool ViECodecImpl::CodecValid(const VideoCodec& video_codec) {
// Check pl_name matches codec_type.
if (video_codec.codecType == kVideoCodecRED) {
#if defined(WIN32)
if (_strnicmp(video_codec.plName, "red", 3) == 0) {
#else
if (strncasecmp(video_codec.plName, "red", 3) == 0) {
#endif
// We only care about the type and name for red.
return true;
}
WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
"Codec type doesn't match pl_name", video_codec.plType);
return false;
} else if (video_codec.codecType == kVideoCodecULPFEC) {
#if defined(WIN32)
if (_strnicmp(video_codec.plName, "ULPFEC", 6) == 0) {
#else
if (strncasecmp(video_codec.plName, "ULPFEC", 6) == 0) {
#endif
// We only care about the type and name for ULPFEC.
return true;
}
WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
"Codec type doesn't match pl_name", video_codec.plType);
return false;
} else if ((video_codec.codecType == kVideoCodecVP8 &&
strncmp(video_codec.plName, "VP8", 4) == 0) ||
(video_codec.codecType == kVideoCodecI420 &&
strncmp(video_codec.plName, "I420", 4) == 0)) {
// OK.
} else if (video_codec.codecType != kVideoCodecGeneric) {
WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
"Codec type doesn't match pl_name", video_codec.plType);
return false;
}
if (video_codec.plType == 0 || video_codec.plType > 127) {
WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
"Invalid codec payload type: %d", video_codec.plType);
return false;
}
if (video_codec.width > kViEMaxCodecWidth ||
video_codec.height > kViEMaxCodecHeight) {
WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Invalid codec size: %u x %u",
video_codec.width, video_codec.height);
return false;
}
if (video_codec.startBitrate < kViEMinCodecBitrate) {
WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Invalid start_bitrate: %u",
video_codec.startBitrate);
return false;
}
if (video_codec.minBitrate < kViEMinCodecBitrate) {
WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Invalid min_bitrate: %u",
video_codec.minBitrate);
return false;
}
return true;
}
} // namespace webrtc