| /* |
| * 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. |
| */ |
| |
| /* |
| * vie_codec_impl.cc |
| */ |
| |
| #include "vie_codec_impl.h" |
| |
| // Defines |
| #include "engine_configurations.h" |
| #include "vie_defines.h" |
| |
| #include "video_coding.h" |
| #include "trace.h" |
| #include "vie_errors.h" |
| #include "vie_impl.h" |
| #include "vie_channel.h" |
| #include "vie_channel_manager.h" |
| #include "vie_encoder.h" |
| #include "vie_input_manager.h" |
| #include "vie_capturer.h" |
| |
| #include <string.h> |
| |
| namespace webrtc |
| { |
| |
| // ---------------------------------------------------------------------------- |
| // GetInterface |
| // ---------------------------------------------------------------------------- |
| |
| ViECodec* ViECodec::GetInterface(VideoEngine* videoEngine) |
| { |
| #ifdef WEBRTC_VIDEO_ENGINE_CODEC_API |
| if (videoEngine == NULL) |
| { |
| return NULL; |
| } |
| VideoEngineImpl* vieImpl = reinterpret_cast<VideoEngineImpl*> (videoEngine); |
| ViECodecImpl* vieCodecImpl = vieImpl; |
| (*vieCodecImpl)++; // Increase ref count |
| |
| return vieCodecImpl; |
| #else |
| return NULL; |
| #endif |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Release |
| // |
| // Releases the interface, i.e. reduces the reference counter. The number of |
| // remaining references is returned, -1 if released too many times. |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::Release() |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, _instanceId, |
| "ViECodecImpl::Release()"); |
| (*this)--; // Decrease ref count |
| |
| WebRtc_Word32 refCount = GetCount(); |
| if (refCount < 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, _instanceId, |
| "ViECodec released too many times"); |
| SetLastError(kViEAPIDoesNotExist); |
| return -1; |
| } |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, _instanceId, |
| "ViECodec reference count: %d", refCount); |
| return refCount; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Constructor |
| // ---------------------------------------------------------------------------- |
| |
| ViECodecImpl::ViECodecImpl() |
| { |
| WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, |
| "ViECodecImpl::ViECodecImpl() Ctor"); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Destructor |
| // ---------------------------------------------------------------------------- |
| |
| ViECodecImpl::~ViECodecImpl() |
| { |
| WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, _instanceId, |
| "ViECodecImpl::~ViECodecImpl() Dtor"); |
| } |
| |
| // Available codecs |
| // ---------------------------------------------------------------------------- |
| // NumberOfCodecs |
| // |
| // Returns the number of available codecs |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::NumberOfCodecs() const |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", |
| __FUNCTION__); |
| |
| if (!IsInitialized()) |
| { |
| SetLastError(kViENotInitialized); |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), |
| "%s - ViE instance %d not initialized", __FUNCTION__, |
| _instanceId); |
| return -1; |
| } |
| // +2 because of FEC(RED and ULPFEC) |
| return (int) (VideoCodingModule::NumberOfCodecs() + 2); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // GetCodec |
| // |
| // Return the video codec with listNumber |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::GetCodec(const unsigned char listNumber, |
| VideoCodec& videoCodec) const |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), |
| "%s(listNumber: %d, codecType: %d)", __FUNCTION__, listNumber); |
| if (!IsInitialized()) |
| { |
| SetLastError(kViENotInitialized); |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId), |
| "%s - ViE instance %d not initialized", __FUNCTION__, |
| _instanceId); |
| return -1; |
| } |
| if (listNumber == VideoCodingModule::NumberOfCodecs()) |
| { |
| memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); |
| strcpy(videoCodec.plName, "RED"); |
| videoCodec.codecType = kVideoCodecRED; |
| videoCodec.plType = VCM_RED_PAYLOAD_TYPE; |
| } |
| else if (listNumber == VideoCodingModule::NumberOfCodecs() + 1) |
| { |
| memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); |
| strcpy(videoCodec.plName, "ULPFEC"); |
| videoCodec.codecType = kVideoCodecULPFEC; |
| videoCodec.plType = VCM_ULPFEC_PAYLOAD_TYPE; |
| } |
| else if (VideoCodingModule::Codec(listNumber, &videoCodec) |
| != VCM_OK) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), |
| "%s: Could not get codec for listNumber: %u", __FUNCTION__, |
| listNumber); |
| SetLastError(kViECodecInvalidArgument); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // Codec settings |
| // ---------------------------------------------------------------------------- |
| // SetSendCodec |
| // |
| // Sets the send codec for videoChannel |
| // This call will affect all channels using the same encoder |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::SetSendCodec(const int videoChannel, |
| const VideoCodec& videoCodec) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId,videoChannel), |
| "%s(videoChannel: %d, codecType: %d)", __FUNCTION__, |
| videoChannel, videoCodec.codecType); |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_instanceId, videoChannel), |
| "%s: codec: %d, plType: %d, width: %d, height: %d, bitrate: %d" |
| "maxBr: %d, minBr: %d, frameRate: %d)", __FUNCTION__, |
| videoCodec.codecType, videoCodec.plType, videoCodec.width, |
| videoCodec.height, videoCodec.startBitrate, |
| videoCodec.maxBitrate, videoCodec.minBitrate, |
| videoCodec.maxFramerate); |
| |
| if (CodecValid(videoCodec) == false) |
| { |
| // Error logged |
| SetLastError(kViECodecInvalidCodec); |
| return -1; |
| } |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| // Set a maxBitrate if the user hasn't... |
| VideoCodec videoCodecInternal; |
| memcpy(&videoCodecInternal, &videoCodec, sizeof(webrtc::VideoCodec)); |
| if (videoCodecInternal.maxBitrate == 0) |
| { |
| // Max is one bit per pixel ... |
| videoCodecInternal.maxBitrate = (videoCodecInternal.width |
| * videoCodecInternal.height * videoCodecInternal.maxFramerate) |
| / 1000; |
| if (videoCodecInternal.startBitrate > videoCodecInternal.maxBitrate) |
| { |
| // ... but should'nt limit the set start bitrate. |
| videoCodecInternal.maxBitrate = videoCodecInternal.startBitrate; |
| } |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_instanceId, |
| videoChannel), |
| "%s: New max bitrate set to %d kbps", __FUNCTION__, |
| videoCodecInternal.maxBitrate); |
| } |
| |
| ViEEncoder* vieEncoder = cs.Encoder(videoChannel); |
| if (vieEncoder == NULL) |
| { |
| assert(false); |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: No encoder found for channel %d", __FUNCTION__); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| // We need to check if the codec settings changed, |
| // then we need a new SSRC |
| bool newRtpStream = false; |
| |
| VideoCodec encoder; |
| vieEncoder->GetEncoder(encoder); |
| if (encoder.codecType != videoCodecInternal.codecType || |
| encoder.width != videoCodecInternal.width || |
| encoder.height != videoCodecInternal.height) |
| { |
| if (cs.ChannelUsingViEEncoder(videoChannel)) |
| { |
| // We don't allow changing codec type or size when several |
| // channels share encoder. |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: Settings differs from other channels using encoder", |
| __FUNCTION__); |
| SetLastError(kViECodecInUse); |
| return -1; |
| } |
| newRtpStream = true; |
| } |
| |
| ViEInputManagerScoped is(_inputManager); |
| ViEFrameProviderBase* frameProvider = NULL; |
| |
| // Stop the media flow while reconfiguring |
| vieEncoder->Pause(); |
| |
| // Check if we have a frame provider that is a camera and can provide this |
| // codec for us. |
| bool useCaptureDeviceAsEncoder = false; |
| frameProvider = is.FrameProvider(vieEncoder); |
| if (frameProvider) |
| { |
| ViECapturer* vieCapture = static_cast<ViECapturer *> (frameProvider); |
| // Try to get preencoded. Nothing to do if it is not supported. |
| if (vieCapture && vieCapture->PreEncodeToViEEncoder(videoCodecInternal, |
| *vieEncoder, |
| videoChannel) == 0) |
| { |
| useCaptureDeviceAsEncoder = true; |
| } |
| } |
| |
| // Update the encoder settings if we are not using a capture device capable |
| // of this codec. |
| if (!useCaptureDeviceAsEncoder |
| && vieEncoder->SetEncoder(videoCodecInternal) != 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: Could not change encoder for channel %d", __FUNCTION__, |
| videoChannel); |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| |
| // Give the channel the new information |
| if (vieChannel->SetSendCodec(videoCodecInternal, newRtpStream) != 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: Could not set send codec for channel %d", __FUNCTION__, |
| videoChannel); |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| |
| // Update the protection mode, we might be switching NACK/FEC |
| vieEncoder->UpdateProtectionMethod(); |
| // Get new best format for frame provider |
| if (frameProvider) |
| { |
| frameProvider->FrameCallbackChanged(); |
| } |
| // Restart the media flow |
| if (newRtpStream) |
| { |
| // Stream settings changed, make sure we get a key frame |
| vieEncoder->SendKeyFrame(); |
| } |
| vieEncoder->Restart(); |
| |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // GetSendCodec |
| // |
| // Gets the current send codec |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::GetSendCodec(const int videoChannel, |
| VideoCodec& videoCodec) const |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", |
| __FUNCTION__, videoChannel); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEEncoder* vieEncoder = cs.Encoder(videoChannel); |
| if (vieEncoder == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: No encoder for channel %d", __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| return vieEncoder->GetEncoder(videoCodec); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // SetReceiveCodec |
| // |
| // Registers a possible receive codec |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::SetReceiveCodec(const int videoChannel, |
| const VideoCodec& videoCodec) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s(videoChannel: %d, codecType: %d)", __FUNCTION__, |
| videoChannel, videoCodec.codecType); |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_instanceId, videoChannel), |
| "%s: codec: %d, plType: %d, width: %d, height: %d, bitrate: %d," |
| "maxBr: %d, minBr: %d, frameRate: %d", __FUNCTION__, |
| videoCodec.codecType, videoCodec.plType, videoCodec.width, |
| videoCodec.height, videoCodec.startBitrate, |
| videoCodec.maxBitrate, videoCodec.minBitrate, |
| videoCodec.maxFramerate); |
| |
| if (CodecValid(videoCodec) == false) |
| { |
| // Error logged |
| SetLastError(kViECodecInvalidCodec); |
| return -1; |
| } |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| if (vieChannel->SetReceiveCodec(videoCodec) != 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_instanceId, |
| videoChannel), |
| "%s: Could not set receive codec for channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // GetReceiveCodec |
| // |
| // Gets the current receive codec |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::GetReceiveCodec(const int videoChannel, |
| VideoCodec& videoCodec) const |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s(videoChannel: %d, codecType: %d)", __FUNCTION__, |
| videoChannel, videoCodec.codecType); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| if (vieChannel->GetReceiveCodec(videoCodec) != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // GetCodecConfigParameters |
| // |
| // Gets the codec config parameters to be sent out-of-band. |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::GetCodecConfigParameters( |
| const int videoChannel, |
| unsigned char configParameters[kConfigParameterSize], |
| unsigned char& configParametersSize) const |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", |
| __FUNCTION__, videoChannel); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEEncoder* vieEncoder = cs.Encoder(videoChannel); |
| if (vieEncoder == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: No encoder for channel %d", __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| if (vieEncoder->GetCodecConfigParameters(configParameters, |
| configParametersSize) != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // SetImageScaleStatus |
| // |
| // Enables scaling of the encoded image instead of padding black border or |
| // cropping |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::SetImageScaleStatus(const int videoChannel, const bool enable) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s(videoChannel: %d, enable: %d)", __FUNCTION__, videoChannel, |
| enable); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEEncoder* vieEncoder = cs.Encoder(videoChannel); |
| if (vieEncoder == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| if (vieEncoder->ScaleInputImage(enable) != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // Codec statistics |
| // ---------------------------------------------------------------------------- |
| // GetSendCodecStastistics |
| // |
| // Get codec statistics for outgoing stream |
| // ---------------------------------------------------------------------------- |
| |
| |
| int ViECodecImpl::GetSendCodecStastistics(const int videoChannel, |
| unsigned int& keyFrames, |
| unsigned int& deltaFrames) const |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s(videoChannel %d)", |
| __FUNCTION__, videoChannel); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEEncoder* vieEncoder = cs.Encoder(videoChannel); |
| if (vieEncoder == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: No send codec for channel %d", __FUNCTION__, |
| videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| |
| if (vieEncoder->SendCodecStatistics((WebRtc_UWord32&) keyFrames, |
| (WebRtc_UWord32&) deltaFrames) != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // GetReceiveCodecStastistics |
| // |
| // Get codec statistics for incoming stream |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::GetReceiveCodecStastistics(const int videoChannel, |
| unsigned int& keyFrames, |
| unsigned int& deltaFrames) const |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s(videoChannel: %d, codecType: %d)", __FUNCTION__, |
| videoChannel); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieChannel->ReceiveCodecStatistics((WebRtc_UWord32&) keyFrames, |
| (WebRtc_UWord32&) deltaFrames) != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| |
| } |
| |
| // Callbacks |
| // ---------------------------------------------------------------------------- |
| // SetKeyFrameRequestCallbackStatus |
| // |
| // Enables a kecallback for keyframe request instead of using RTCP |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::SetKeyFrameRequestCallbackStatus(const int videoChannel, |
| const bool enable) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s(videoChannel: %d)", |
| __FUNCTION__, videoChannel); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieChannel->EnableKeyFrameRequestCallback(enable) != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // SetSignalKeyPacketLossStatus |
| // |
| // Triggers a key frame request when there is packet loss in a received key |
| // frame |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::SetSignalKeyPacketLossStatus(const int videoChannel, |
| const bool enable, |
| const bool onlyKeyFrames) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s(videoChannel: %d, enable: %d, onlyKeyFrames: %d)", |
| __FUNCTION__, videoChannel, enable); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieChannel->SetSignalPacketLossStatus(enable, onlyKeyFrames) != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // RegisterEncoderObserver |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::RegisterEncoderObserver(const int videoChannel, |
| ViEEncoderObserver& observer) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", |
| __FUNCTION__); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEEncoder* vieEncoder = cs.Encoder(videoChannel); |
| if (vieEncoder == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: No encoder for channel %d", __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieEncoder->RegisterCodecObserver(&observer) != 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: Could not register codec observer at channel", |
| __FUNCTION__); |
| SetLastError(kViECodecObserverAlreadyRegistered); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // DeregisterEncoderObserver |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::DeregisterEncoderObserver(const int videoChannel) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", |
| __FUNCTION__); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEEncoder* vieEncoder = cs.Encoder(videoChannel); |
| if (vieEncoder == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: No encoder for channel %d", __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieEncoder->RegisterCodecObserver(NULL) != 0) |
| { |
| SetLastError(kViECodecObserverNotRegistered); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // RegisterDecoderObserver |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::RegisterDecoderObserver(const int videoChannel, |
| ViEDecoderObserver& observer) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", |
| __FUNCTION__); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieChannel->RegisterCodecObserver(&observer) != 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), |
| "%s: Could not register codec observer at channel", |
| __FUNCTION__); |
| SetLastError(kViECodecObserverAlreadyRegistered); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // DeregisterDecoderObserver |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::DeregisterDecoderObserver(const int videoChannel) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), "%s", |
| __FUNCTION__); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieChannel->RegisterCodecObserver(NULL) != 0) |
| { |
| SetLastError(kViECodecObserverNotRegistered); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| // Force a key frame |
| // ---------------------------------------------------------------------------- |
| // SendKeyFrame |
| // |
| // Force the next frame to be a key frame |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::SendKeyFrame(const int videoChannel) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), |
| "%s(videoChannel: %d)", __FUNCTION__, videoChannel); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEEncoder* vieEncoder = cs.Encoder(videoChannel); |
| if (vieEncoder == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieEncoder->SendKeyFrame() != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // WaitForFirstKeyFrame |
| // |
| // Forc the next frame to be a key frame |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::WaitForFirstKeyFrame(const int videoChannel, const bool wait) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), |
| "%s(videoChannel: %d, wait: %d)", __FUNCTION__, videoChannel, |
| wait); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId, videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieChannel->WaitForKeyFrame(wait) != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // H263 Specific |
| // ---------------------------------------------------------------------------- |
| // SetInverseH263Logic |
| // |
| // Used to interoperate with old MS H.263 where key frames are marked as delta |
| // and the oposite. |
| // ---------------------------------------------------------------------------- |
| |
| int ViECodecImpl::SetInverseH263Logic(int videoChannel, bool enable) |
| { |
| WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(_instanceId), |
| "%s(videoChannel: %d)", __FUNCTION__, videoChannel); |
| |
| ViEChannelManagerScoped cs(_channelManager); |
| ViEChannel* vieChannel = cs.Channel(videoChannel); |
| if (vieChannel == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, |
| ViEId(_instanceId,videoChannel), "%s: No channel %d", |
| __FUNCTION__, videoChannel); |
| SetLastError(kViECodecInvalidChannelId); |
| return -1; |
| } |
| if (vieChannel->SetInverseH263Logic(enable) != 0) |
| { |
| SetLastError(kViECodecUnknownError); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // CodecValid |
| // ---------------------------------------------------------------------------- |
| |
| bool ViECodecImpl::CodecValid(const VideoCodec& videoCodec) |
| { |
| // Check plName matches codecType |
| if (videoCodec.codecType == kVideoCodecRED) |
| { |
| #if defined(WIN32) |
| if (_strnicmp(videoCodec.plName, "red", 3) == 0) |
| #elif defined(WEBRTC_MAC_INTEL) || defined(WEBRTC_LINUX) |
| if (strncasecmp(videoCodec.plName, "red",3) == 0) |
| #endif |
| { |
| // We only care about the type and name for red |
| return true; |
| } |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, |
| "Codec type doesn't match plName", videoCodec.plType); |
| return false; |
| } |
| else if (videoCodec.codecType == kVideoCodecULPFEC) |
| { |
| #if defined(WIN32) |
| if (_strnicmp(videoCodec.plName, "ULPFEC", 6) == 0) |
| #elif defined(WEBRTC_MAC_INTEL)|| defined(WEBRTC_LINUX) |
| if (strncasecmp(videoCodec.plName, "ULPFEC",6) == 0) |
| #endif |
| { |
| // We only care about the type and name for ULPFEC |
| return true; |
| } |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, |
| "Codec type doesn't match plName", videoCodec.plType); |
| return false; |
| } |
| else if ((videoCodec.codecType == kVideoCodecH263 && |
| strncmp(videoCodec.plName, "H263", 4) == 0) |
| || (videoCodec.codecType == kVideoCodecH263 |
| && strncmp(videoCodec.plName, "H263-1998", 9) == 0) |
| || (videoCodec.codecType == kVideoCodecVP8 |
| && strncmp(videoCodec.plName, "VP8", 4) == 0) |
| || (videoCodec.codecType == kVideoCodecI420 |
| && strncmp(videoCodec.plName, "I420", 4) == 0) |
| || (videoCodec.codecType == kVideoCodecH264 |
| && strncmp(videoCodec.plName, "H264", 4) == 0)) |
| // || (videoCodec.codecType == kVideoCodecMPEG4 |
| // && strncmp(videoCodec.plName, "MP4V-ES", 7) == 0) |
| { |
| // ok |
| } |
| else |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, |
| "Codec type doesn't match plName", videoCodec.plType); |
| return false; |
| } |
| |
| // pltype |
| if (videoCodec.plType == 0 && videoCodec.plType > 127) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, |
| "Invalid codec payload type: %d", videoCodec.plType); |
| return false; |
| } |
| |
| // Size |
| if (videoCodec.width > kViEMaxCodecWidth || videoCodec.height |
| > kViEMaxCodecHeight) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, |
| "Invalid codec size: %u x %u", videoCodec.width, |
| videoCodec.height); |
| return false; |
| } |
| |
| if (videoCodec.startBitrate < kViEMinCodecBitrate) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, |
| "Invalid startBitrate: %u", videoCodec.startBitrate); |
| return false; |
| } |
| if (videoCodec.minBitrate < kViEMinCodecBitrate) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, |
| "Invalid minBitrate: %u", videoCodec.minBitrate); |
| return false; |
| } |
| if (videoCodec.startBitrate < kViEMinCodecBitrate) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, |
| "Invalid minBitrate: %u", videoCodec.minBitrate); |
| return false; |
| } |
| |
| if (videoCodec.codecType == kVideoCodecH263) |
| { |
| if ((videoCodec.width == 704 && videoCodec.height == 576) |
| || (videoCodec.width == 352 && videoCodec.height == 288) |
| || (videoCodec.width == 176 && videoCodec.height == 144) |
| || (videoCodec.width == 128 && videoCodec.height == 96)) |
| { |
| // ok |
| } |
| else |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1, |
| "Invalid size for H.263"); |
| return false; |
| } |
| } |
| return true; |
| } |
| } // namespace webrtc |