| /* |
| * 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/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 { |
| |
| static void LogCodec(const VideoCodec& codec) { |
| LOG(LS_INFO) << "CodecType " << codec.codecType |
| << ", pl_type " << static_cast<int>(codec.plType) |
| << ", resolution " << codec.width |
| << " x " << codec.height |
| << ", start br " << codec.startBitrate |
| << ", min br " << codec.minBitrate |
| << ", max br " << codec.maxBitrate |
| << ", max fps " << static_cast<int>(codec.maxFramerate) |
| << ", max qp " << codec.qpMax |
| << ", number of streams " |
| << static_cast<int>(codec.numberOfSimulcastStreams); |
| if (codec.codecType == kVideoCodecVP8) { |
| LOG(LS_INFO) << "VP8 specific settings"; |
| LOG(LS_INFO) << "pictureLossIndicationOn " |
| << codec.codecSpecific.VP8.pictureLossIndicationOn |
| << ", feedbackModeOn " |
| << codec.codecSpecific.VP8.feedbackModeOn |
| << ", complexity " |
| << codec.codecSpecific.VP8.complexity |
| << ", resilience " |
| << codec.codecSpecific.VP8.resilience |
| << ", numberOfTemporalLayers " |
| << static_cast<int>( |
| codec.codecSpecific.VP8.numberOfTemporalLayers) |
| << ", keyFrameinterval " |
| << codec.codecSpecific.VP8.keyFrameInterval; |
| for (int idx = 0; idx < codec.numberOfSimulcastStreams; ++idx) { |
| LOG(LS_INFO) << "Stream " << codec.simulcastStream[idx].width |
| << " x " << codec.simulcastStream[idx].height; |
| LOG(LS_INFO) << "Temporal layers " |
| << static_cast<int>( |
| codec.simulcastStream[idx].numberOfTemporalLayers) |
| << ", min br " |
| << codec.simulcastStream[idx].minBitrate |
| << ", target br " |
| << codec.simulcastStream[idx].targetBitrate |
| << ", max br " |
| << codec.simulcastStream[idx].maxBitrate |
| << ", qp max " |
| << codec.simulcastStream[idx].qpMax; |
| } |
| } else if (codec.codecType == kVideoCodecH264) { |
| LOG(LS_INFO) << "H264 specific settings"; |
| LOG(LS_INFO) << "profile: " |
| << codec.codecSpecific.H264.profile |
| << ", framedropping: " |
| << codec.codecSpecific.H264.frameDroppingOn |
| << ", keyFrameInterval: " |
| << codec.codecSpecific.H264.keyFrameInterval |
| << ", spslen: " |
| << codec.codecSpecific.H264.spsLen |
| << ", ppslen: " |
| << codec.codecSpecific.H264.ppsLen; |
| } |
| } |
| |
| |
| 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() { |
| LOG(LS_INFO) << "ViECodec::Release."; |
| // Decrease ref count. |
| (*this)--; |
| |
| int32_t ref_count = GetCount(); |
| if (ref_count < 0) { |
| LOG(LS_WARNING) << "ViECodec released too many times."; |
| shared_data_->SetLastError(kViEAPIDoesNotExist); |
| return -1; |
| } |
| return ref_count; |
| } |
| |
| ViECodecImpl::ViECodecImpl(ViESharedData* shared_data) |
| : shared_data_(shared_data) { |
| } |
| |
| ViECodecImpl::~ViECodecImpl() { |
| } |
| |
| int ViECodecImpl::NumberOfCodecs() const { |
| // +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 { |
| 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) { |
| shared_data_->SetLastError(kViECodecInvalidArgument); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int ViECodecImpl::SetSendCodec(const int video_channel, |
| const VideoCodec& video_codec) { |
| LOG(LS_INFO) << "SetSendCodec for channel " << video_channel; |
| LogCodec(video_codec); |
| 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) { |
| shared_data_->SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| assert(vie_encoder); |
| if (vie_encoder->Owner() != video_channel) { |
| LOG_F(LS_ERROR) << "Receive only 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; |
| LOG(LS_INFO) << "New max bitrate set " << video_codec_internal.maxBitrate; |
| } |
| |
| if (video_codec_internal.startBitrate < video_codec_internal.minBitrate) { |
| video_codec_internal.startBitrate = video_codec_internal.minBitrate; |
| } |
| if (video_codec_internal.startBitrate > video_codec_internal.maxBitrate) { |
| video_codec_internal.startBitrate = 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) { |
| 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) { |
| 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) { |
| LOG_F(LS_ERROR) << "Could not get ssrc."; |
| } |
| 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) { |
| LOG_F(LS_ERROR) << "Could not get ssrc for stream " << 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 { |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| shared_data_->SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| return vie_encoder->GetEncoder(&video_codec); |
| } |
| |
| int ViECodecImpl::SetReceiveCodec(const int video_channel, |
| const VideoCodec& video_codec) { |
| LOG(LS_INFO) << "SetReceiveCodec for channel " << video_channel; |
| LOG(LS_INFO) << "Codec type " << video_codec.codecType |
| << ", payload type " << video_codec.plType; |
| |
| if (CodecValid(video_codec) == false) { |
| shared_data_->SetLastError(kViECodecInvalidCodec); |
| return -1; |
| } |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_channel) { |
| shared_data_->SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| if (vie_channel->SetReceiveCodec(video_codec) != 0) { |
| shared_data_->SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int ViECodecImpl::GetReceiveCodec(const int video_channel, |
| VideoCodec& video_codec) const { |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_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 { |
| LOG(LS_INFO) << "GetCodecConfigParameters " << video_channel; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| 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) { |
| LOG(LS_INFO) << "SetImageScaleStates for channel " << video_channel |
| << ", enable: " << enable; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| 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 { |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| 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 { |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_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 { |
| assert(delay_ms != NULL); |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_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 { |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| shared_data_->SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| return vie_encoder->CodecTargetBitrate(static_cast<uint32_t*>(bitrate)); |
| } |
| |
| unsigned int ViECodecImpl::GetDiscardedPackets(const int video_channel) const { |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_channel) { |
| shared_data_->SetLastError(kViECodecInvalidChannelId); |
| return static_cast<unsigned int>(-1); |
| } |
| return vie_channel->DiscardedPackets(); |
| } |
| |
| int ViECodecImpl::SetKeyFrameRequestCallbackStatus(const int video_channel, |
| const bool enable) { |
| LOG(LS_INFO) << "SetKeyFrameRequestCallbackStatus for " << video_channel |
| << ", enacle " << enable; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_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) { |
| LOG(LS_INFO) << "SetSignalKeyPacketLossStatus for " << video_channel |
| << "enable, " << enable |
| << ", only key frames " << only_key_frames; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_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) { |
| LOG(LS_INFO) << "RegisterEncoderObserver for channel " << video_channel; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| shared_data_->SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vie_encoder->RegisterCodecObserver(&observer) != 0) { |
| shared_data_->SetLastError(kViECodecObserverAlreadyRegistered); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int ViECodecImpl::DeregisterEncoderObserver(const int video_channel) { |
| LOG(LS_INFO) << "DeregisterEncoderObserver for channel " << video_channel; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| 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) { |
| LOG(LS_INFO) << "RegisterDecoderObserver for channel " << video_channel; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_channel) { |
| shared_data_->SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vie_channel->RegisterCodecObserver(&observer) != 0) { |
| shared_data_->SetLastError(kViECodecObserverAlreadyRegistered); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int ViECodecImpl::DeregisterDecoderObserver(const int video_channel) { |
| LOG(LS_INFO) << "DeregisterDecodeObserver for channel " << video_channel; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_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) { |
| LOG(LS_INFO) << "SendKeyFrame on channel " << video_channel; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| 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) { |
| LOG(LS_INFO) << "WaitForFirstKeyFrame for channel " << video_channel |
| << ", wait " << wait; |
| |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_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) { |
| LOG(LS_INFO) << "StartDebugRecording for channel " << video_channel; |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| return -1; |
| } |
| return vie_encoder->StartDebugRecording(file_name_utf8); |
| } |
| |
| int ViECodecImpl::StopDebugRecording(int video_channel) { |
| LOG(LS_INFO) << "StopDebugRecording for channel " << video_channel; |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| return -1; |
| } |
| return vie_encoder->StopDebugRecording(); |
| } |
| |
| void ViECodecImpl::SuspendBelowMinBitrate(int video_channel) { |
| LOG(LS_INFO) << "SuspendBelowMinBitrate for channel " << video_channel; |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEEncoder* vie_encoder = cs.Encoder(video_channel); |
| if (!vie_encoder) { |
| return; |
| } |
| vie_encoder->SuspendBelowMinBitrate(); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_channel) { |
| return; |
| } |
| // Must enable pacing when enabling SuspendBelowMinBitrate. Otherwise, no |
| // padding will be sent when the video is suspended so the video will be |
| // unable to recover. |
| vie_channel->SetTransmissionSmoothingStatus(true); |
| } |
| |
| bool ViECodecImpl::GetSendSideDelay(int video_channel, int* avg_delay_ms, |
| int* max_delay_ms) const { |
| ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); |
| ViEChannel* vie_channel = cs.Channel(video_channel); |
| if (!vie_channel) { |
| shared_data_->SetLastError(kViECodecInvalidChannelId); |
| return false; |
| } |
| return vie_channel->GetSendSideDelay(avg_delay_ms, max_delay_ms); |
| } |
| |
| 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; |
| } |
| LOG_F(LS_ERROR) << "Invalid RED configuration."; |
| 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; |
| } |
| LOG_F(LS_ERROR) << "Invalid ULPFEC configuration."; |
| 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) || |
| (video_codec.codecType == kVideoCodecH264 && |
| strncmp(video_codec.plName, "H264", 4) == 0)) { |
| // OK. |
| } else if (video_codec.codecType != kVideoCodecGeneric) { |
| LOG(LS_ERROR) << "Codec type and name mismatch."; |
| return false; |
| } |
| |
| if (video_codec.plType == 0 || video_codec.plType > 127) { |
| LOG(LS_ERROR) << "Invalif payload type: " << video_codec.plType; |
| return false; |
| } |
| |
| if (video_codec.width > kViEMaxCodecWidth || |
| video_codec.height > kViEMaxCodecHeight) { |
| LOG(LS_ERROR) << "Invalid codec resolution " << video_codec.width |
| << " x " << video_codec.height; |
| return false; |
| } |
| |
| if (video_codec.startBitrate < kViEMinCodecBitrate) { |
| LOG(LS_ERROR) << "Invalid start bitrate."; |
| return false; |
| } |
| if (video_codec.minBitrate < kViEMinCodecBitrate) { |
| LOG(LS_ERROR) << "Invalid min bitrate."; |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace webrtc |