471e83e592
Only vie_shared_data.* are refactored, all *_impl.cc are only changed due to changed names of members in ViESharedData. These files will be refactored later, so the indentation in these files might be corrupt at this stage. References are not changed to pointers at this stage. Review URL: http://webrtc-codereview.appspot.com/292006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1015 4adac7df-926f-26a2-2b94-8c16560cd09d
993 lines
34 KiB
C++
993 lines
34 KiB
C++
/*
|
|
* 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, instance_id_,
|
|
"ViECodecImpl::Release()");
|
|
(*this)--; // Decrease ref count
|
|
|
|
WebRtc_Word32 refCount = GetCount();
|
|
if (refCount < 0)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, instance_id_,
|
|
"ViECodec released too many times");
|
|
SetLastError(kViEAPIDoesNotExist);
|
|
return -1;
|
|
}
|
|
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, instance_id_,
|
|
"ViECodec reference count: %d", refCount);
|
|
return refCount;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Constructor
|
|
// ----------------------------------------------------------------------------
|
|
|
|
ViECodecImpl::ViECodecImpl()
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, instance_id_,
|
|
"ViECodecImpl::ViECodecImpl() Ctor");
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Destructor
|
|
// ----------------------------------------------------------------------------
|
|
|
|
ViECodecImpl::~ViECodecImpl()
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, instance_id_,
|
|
"ViECodecImpl::~ViECodecImpl() Dtor");
|
|
}
|
|
|
|
// Available codecs
|
|
// ----------------------------------------------------------------------------
|
|
// NumberOfCodecs
|
|
//
|
|
// Returns the number of available codecs
|
|
// ----------------------------------------------------------------------------
|
|
|
|
int ViECodecImpl::NumberOfCodecs() const
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, ViEId(instance_id_), "%s",
|
|
__FUNCTION__);
|
|
// +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(instance_id_),
|
|
"%s(listNumber: %d, codecType: %d)", __FUNCTION__,
|
|
listNumber, videoCodec.codecType);
|
|
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(instance_id_),
|
|
"%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(instance_id_,videoChannel),
|
|
"%s(videoChannel: %d, codecType: %d)", __FUNCTION__,
|
|
videoChannel, videoCodec.codecType);
|
|
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(instance_id_, 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(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_,
|
|
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(instance_id_, 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(instance_id_, videoChannel),
|
|
"%s: Settings differs from other channels using encoder",
|
|
__FUNCTION__);
|
|
SetLastError(kViECodecInUse);
|
|
return -1;
|
|
}
|
|
newRtpStream = true;
|
|
}
|
|
if (videoCodecInternal.numberOfSimulcastStreams > 1)
|
|
{
|
|
if (cs.ChannelUsingViEEncoder(videoChannel))
|
|
{
|
|
// We don't allow simulcast channels to share encoder
|
|
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, videoChannel),
|
|
"%s: Can't share simulcast encoder",
|
|
__FUNCTION__);
|
|
SetLastError(kViECodecInUse);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
ViEInputManagerScoped is(input_manager_);
|
|
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(instance_id_, 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(instance_id_, 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(instance_id_, videoChannel), "%s(videoChannel: %d)",
|
|
__FUNCTION__, videoChannel);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEEncoder* vieEncoder = cs.Encoder(videoChannel);
|
|
if (vieEncoder == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_, videoChannel),
|
|
"%s(videoChannel: %d, codecType: %d)", __FUNCTION__,
|
|
videoChannel, videoCodec.codecType);
|
|
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(instance_id_, 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(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, videoChannel), "%s: No channel %d",
|
|
__FUNCTION__, videoChannel);
|
|
SetLastError(kViECodecInvalidChannelId);
|
|
return -1;
|
|
}
|
|
|
|
if (vieChannel->SetReceiveCodec(videoCodec) != 0)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(instance_id_,
|
|
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(instance_id_, videoChannel),
|
|
"%s(videoChannel: %d, codecType: %d)", __FUNCTION__,
|
|
videoChannel, videoCodec.codecType);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_, videoChannel), "%s(videoChannel: %d)",
|
|
__FUNCTION__, videoChannel);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEEncoder* vieEncoder = cs.Encoder(videoChannel);
|
|
if (vieEncoder == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_, videoChannel),
|
|
"%s(videoChannel: %d, enable: %d)", __FUNCTION__, videoChannel,
|
|
enable);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEEncoder* vieEncoder = cs.Encoder(videoChannel);
|
|
if (vieEncoder == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_, videoChannel), "%s(videoChannel %d)",
|
|
__FUNCTION__, videoChannel);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEEncoder* vieEncoder = cs.Encoder(videoChannel);
|
|
if (vieEncoder == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_, videoChannel),
|
|
"%s(videoChannel: %d, codecType: %d)", __FUNCTION__,
|
|
videoChannel);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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;
|
|
|
|
}
|
|
|
|
unsigned int ViECodecImpl::GetDiscardedPackets(const int videoChannel) const {
|
|
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, videoChannel),
|
|
"%s(videoChannel: %d, codecType: %d)", __FUNCTION__,
|
|
videoChannel);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, videoChannel), "%s: No channel %d",
|
|
__FUNCTION__, videoChannel);
|
|
SetLastError(kViECodecInvalidChannelId);
|
|
return -1;
|
|
}
|
|
return vieChannel->DiscardedPackets();
|
|
}
|
|
|
|
// 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(instance_id_, videoChannel), "%s(videoChannel: %d)",
|
|
__FUNCTION__, videoChannel);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_, videoChannel),
|
|
"%s(videoChannel: %d, enable: %d, onlyKeyFrames: %d)",
|
|
__FUNCTION__, videoChannel, enable);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_), "%s",
|
|
__FUNCTION__);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEEncoder* vieEncoder = cs.Encoder(videoChannel);
|
|
if (vieEncoder == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_, 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(instance_id_), "%s",
|
|
__FUNCTION__);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEEncoder* vieEncoder = cs.Encoder(videoChannel);
|
|
if (vieEncoder == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_), "%s",
|
|
__FUNCTION__);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, videoChannel), "%s: No channel %d",
|
|
__FUNCTION__, videoChannel);
|
|
SetLastError(kViECodecInvalidChannelId);
|
|
return -1;
|
|
}
|
|
if (vieChannel->RegisterCodecObserver(&observer) != 0)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_), "%s",
|
|
__FUNCTION__);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_),
|
|
"%s(videoChannel: %d)", __FUNCTION__, videoChannel);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEEncoder* vieEncoder = cs.Encoder(videoChannel);
|
|
if (vieEncoder == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_),
|
|
"%s(videoChannel: %d, wait: %d)", __FUNCTION__, videoChannel,
|
|
wait);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_, 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(instance_id_),
|
|
"%s(videoChannel: %d)", __FUNCTION__, videoChannel);
|
|
|
|
ViEChannelManagerScoped cs(channel_manager_);
|
|
ViEChannel* vieChannel = cs.Channel(videoChannel);
|
|
if (vieChannel == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
|
|
ViEId(instance_id_,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.numberOfSimulcastStreams == 1)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, -1,
|
|
"Number of Simulcast streams can not be 1");
|
|
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
|