/* * 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 #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(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((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 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(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::SuspendBelowMinBitrate(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->SuspendBelowMinBitrate(); } 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