/* * 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_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(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((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(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; } 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