blob: f99511790001bd39e119003b1fb2cd194d43cd37 [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_codec_impl.h"
#include "engine_configurations.h"
#include "modules/video_coding/main/interface/video_coding.h"
#include "system_wrappers/interface/trace.h"
#include "video_engine/include/vie_errors.h"
#include "video_engine/vie_capturer.h"
#include "video_engine/vie_channel.h"
#include "video_engine/vie_channel_manager.h"
#include "video_engine/vie_defines.h"
#include "video_engine/vie_encoder.h"
#include "video_engine/vie_impl.h"
#include "video_engine/vie_input_manager.h"
#include "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 = reinterpret_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)--;
WebRtc_Word32 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, codec_type: %d)", __FUNCTION__,
list_number, video_codec.codecType);
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",
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);
}
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;
}
// 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);
}
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
assert(false);
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No encoder found for channel %d", __FUNCTION__);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
VideoCodec encoder;
vie_encoder->GetEncoder(encoder);
if (encoder.codecType != video_codec_internal.codecType &&
cs.ChannelUsingViEEncoder(video_channel)) {
// We don't allow changing codec type when several channels share encoder.
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Settings differs from other channels using encoder",
__FUNCTION__);
shared_data_->SetLastError(kViECodecInUse);
return -1;
}
// 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 ||
encoder.width != video_codec_internal.width ||
encoder.height != video_codec_internal.height) {
new_rtp_stream = true;
}
if (video_codec_internal.numberOfSimulcastStreams > 1) {
if (cs.ChannelUsingViEEncoder(video_channel)) {
// We don't allow simulcast channels to share encoder.
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Can't share simulcast encoder",
__FUNCTION__);
shared_data_->SetLastError(kViECodecInUse);
return -1;
}
}
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFrameProviderBase* frame_provider = NULL;
// Stop the media flow while reconfiguring.
vie_encoder->Pause();
// Check if we have a frame provider that is a camera and can provide this
// codec for us.
bool use_capture_device_as_encoder = false;
frame_provider = is.FrameProvider(vie_encoder);
if (frame_provider) {
if (frame_provider->Id() >= kViECaptureIdBase &&
frame_provider->Id() <= kViECaptureIdMax) {
ViECapturer* vie_capture = static_cast<ViECapturer*>(frame_provider);
// Try to get preencoded. Nothing to do if it is not supported.
if (vie_capture && vie_capture->PreEncodeToViEEncoder(
video_codec_internal,
*vie_encoder,
video_channel) == 0) {
use_capture_device_as_encoder = true;
}
}
}
// Update the encoder settings if we are not using a capture device capable
// of this codec.
if (!use_capture_device_as_encoder &&
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;
}
}
// Update the protection mode, we might be switching NACK/FEC.
vie_encoder->UpdateProtectionMethod();
// Get new best format for frame provider.
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, 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;
}
if (vie_channel->ReceiveCodecStatistics(key_frames, delta_frames) != 0) {
shared_data_->SetLastError(kViECodecUnknownError);
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<WebRtc_UWord32*>(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;
}
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 {
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;
}
if (video_codec.numberOfSimulcastStreams == 1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
"Number of Simulcast streams can not be 1");
return false;
}
return true;
}
} // namespace webrtc