webrtc/video_engine/main/source/vie_codec_impl.cc

978 lines
34 KiB
C++
Raw Normal View History

/*
* 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