800 lines
21 KiB
C++
800 lines
21 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.
|
|
*/
|
|
|
|
#include "codec_database.h"
|
|
#include "../../../../engine_configurations.h"
|
|
#include "internal_defines.h"
|
|
#include "trace.h"
|
|
|
|
#if defined(_WIN32)
|
|
// VS 2005: Don't warn for default initialized arrays. See help for more info.
|
|
// Don't warn for strncpy being unsecure.
|
|
// switch statement contains 'default' but no 'case' labels
|
|
#pragma warning(disable:4351; disable:4996; disable:4065)
|
|
#endif
|
|
|
|
// Supported codecs
|
|
#ifdef VIDEOCODEC_VP8
|
|
#include "vp8.h"
|
|
#endif
|
|
#ifdef VIDEOCODEC_I420
|
|
#include "i420.h"
|
|
#endif
|
|
|
|
namespace webrtc
|
|
{
|
|
|
|
VCMDecoderMapItem::VCMDecoderMapItem(VideoCodec* settings,
|
|
WebRtc_UWord32 numberOfCores,
|
|
bool requireKeyFrame)
|
|
:
|
|
_settings(settings),
|
|
_numberOfCores(numberOfCores),
|
|
_requireKeyFrame(requireKeyFrame)
|
|
{
|
|
}
|
|
|
|
VCMExtDecoderMapItem::VCMExtDecoderMapItem(VideoDecoder* externalDecoderInstance,
|
|
WebRtc_UWord8 payloadType,
|
|
bool internalRenderTiming)
|
|
:
|
|
_payloadType(payloadType),
|
|
_externalDecoderInstance(externalDecoderInstance),
|
|
_internalRenderTiming(internalRenderTiming)
|
|
{
|
|
}
|
|
|
|
VCMCodecDataBase::VCMCodecDataBase(WebRtc_Word32 id):
|
|
_id(id),
|
|
_numberOfCores(0),
|
|
_maxPayloadSize(kDefaultPayloadSize),
|
|
_periodicKeyFrames(false),
|
|
_currentEncIsExternal(false),
|
|
_sendCodec(),
|
|
_receiveCodec(),
|
|
_externalPayloadType(0),
|
|
_externalEncoder(NULL),
|
|
_internalSource(false),
|
|
_ptrEncoder(NULL),
|
|
_ptrDecoder(NULL),
|
|
_currentDecIsExternal(false),
|
|
_decMap(),
|
|
_decExternalMap()
|
|
{
|
|
//
|
|
}
|
|
|
|
VCMCodecDataBase::~VCMCodecDataBase()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::Version(WebRtc_Word8* version,
|
|
WebRtc_UWord32& remainingBufferInBytes,
|
|
WebRtc_UWord32& position) const
|
|
{
|
|
VCMGenericEncoder* encoder = NULL;
|
|
VideoCodec settings;
|
|
WebRtc_Word32 ret;
|
|
for (int i = 0; i < VCMCodecDataBase::NumberOfCodecs(); i++)
|
|
{
|
|
ret = VCMCodecDataBase::Codec(i, &settings);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
encoder = CreateEncoder(settings.codecType);
|
|
if (encoder == NULL)
|
|
{
|
|
return VCM_MEMORY;
|
|
}
|
|
ret = encoder->_encoder.Version(&version[position], remainingBufferInBytes);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
remainingBufferInBytes -= ret;
|
|
position += ret;
|
|
delete &encoder->_encoder;
|
|
delete encoder;
|
|
}
|
|
return VCM_OK;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::Reset()
|
|
{
|
|
WebRtc_Word32 ret = ResetReceiver();
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
ret = ResetSender();
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
return VCM_OK;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::ResetSender()
|
|
{
|
|
DeleteEncoder();
|
|
_periodicKeyFrames = false;
|
|
return VCM_OK;
|
|
}
|
|
|
|
VCMGenericEncoder*
|
|
VCMCodecDataBase::CreateEncoder(VideoCodecType type) const
|
|
{
|
|
switch(type)
|
|
{
|
|
#ifdef VIDEOCODEC_VP8
|
|
case kVideoCodecVP8:
|
|
return new VCMGenericEncoder(*(new VP8Encoder));
|
|
break;
|
|
#endif
|
|
#ifdef VIDEOCODEC_I420
|
|
case kVideoCodecI420:
|
|
return new VCMGenericEncoder(*(new I420Encoder));
|
|
break;
|
|
#endif
|
|
default:
|
|
return NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
VCMCodecDataBase::DeleteEncoder()
|
|
{
|
|
if (_ptrEncoder)
|
|
{
|
|
_ptrEncoder->Release();
|
|
if (!_currentEncIsExternal)
|
|
{
|
|
delete &_ptrEncoder->_encoder;
|
|
}
|
|
delete _ptrEncoder;
|
|
_ptrEncoder = NULL;
|
|
}
|
|
}
|
|
|
|
WebRtc_UWord8
|
|
VCMCodecDataBase::NumberOfCodecs()
|
|
{
|
|
return VCM_NUM_VIDEO_CODECS_AVAILABLE;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::Codec(WebRtc_UWord8 listId, VideoCodec *settings)
|
|
{
|
|
if (settings == NULL)
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
|
|
if (listId >= VCM_NUM_VIDEO_CODECS_AVAILABLE)
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
memset(settings, 0, sizeof(VideoCodec));
|
|
switch (listId)
|
|
{
|
|
#ifdef VIDEOCODEC_VP8
|
|
case VCM_VP8_IDX:
|
|
{
|
|
strncpy(settings->plName, "VP8", 3);
|
|
settings->codecType = kVideoCodecVP8;
|
|
// 96 to 127 dynamic payload types for video codecs
|
|
settings->plType = VCM_VP8_PAYLOAD_TYPE;
|
|
settings->startBitrate = 100;
|
|
settings->minBitrate = VCM_MIN_BITRATE;
|
|
settings->maxBitrate = 0;
|
|
settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
|
|
settings->width = VCM_DEFAULT_CODEC_WIDTH;
|
|
settings->height = VCM_DEFAULT_CODEC_HEIGHT;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef VIDEOCODEC_I420
|
|
case VCM_I420_IDX:
|
|
{
|
|
strncpy(settings->plName, "I420", 4);
|
|
settings->codecType = kVideoCodecI420;
|
|
// 96 to 127 dynamic payload types for video codecs
|
|
settings->plType = VCM_I420_PAYLOAD_TYPE;
|
|
// Bitrate needed for this size and framerate
|
|
settings->startBitrate = 3*VCM_DEFAULT_CODEC_WIDTH*
|
|
VCM_DEFAULT_CODEC_HEIGHT*8*
|
|
VCM_DEFAULT_FRAME_RATE/1000/2;
|
|
settings->maxBitrate = settings->startBitrate;
|
|
settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
|
|
settings->width = VCM_DEFAULT_CODEC_WIDTH;
|
|
settings->height = VCM_DEFAULT_CODEC_HEIGHT;
|
|
settings->minBitrate = VCM_MIN_BITRATE;
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
}
|
|
|
|
return VCM_OK;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::Codec(VideoCodecType codecType, VideoCodec* settings)
|
|
{
|
|
for (int i = 0; i < VCMCodecDataBase::NumberOfCodecs(); i++)
|
|
{
|
|
const WebRtc_Word32 ret = VCMCodecDataBase::Codec(i, settings);
|
|
if (ret != VCM_OK)
|
|
{
|
|
return ret;
|
|
}
|
|
if (codecType == settings->codecType)
|
|
{
|
|
return VCM_OK;
|
|
}
|
|
}
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
|
|
// assuming only one registered encoder - since only one used, no need for more
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::RegisterSendCodec(const VideoCodec* sendCodec,
|
|
WebRtc_UWord32 numberOfCores,
|
|
WebRtc_UWord32 maxPayloadSize)
|
|
{
|
|
if (sendCodec == NULL)
|
|
{
|
|
return VCM_UNINITIALIZED;
|
|
}
|
|
if (maxPayloadSize == 0)
|
|
{
|
|
maxPayloadSize = kDefaultPayloadSize;
|
|
}
|
|
if (numberOfCores > 32)
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
if (strcmp(sendCodec->plName, "H263") == 0 &&
|
|
(sendCodec->plType != 34))
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
if (sendCodec->plType <= 0)
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
// Make sure the start bit rate is sane...
|
|
if (sendCodec->startBitrate > 1000000)
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
if (sendCodec->codecType == kVideoCodecUnknown)
|
|
{
|
|
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
|
|
}
|
|
_numberOfCores = numberOfCores;
|
|
_maxPayloadSize = maxPayloadSize;
|
|
|
|
memcpy(&_sendCodec, sendCodec, sizeof(VideoCodec));
|
|
|
|
if (_sendCodec.maxBitrate == 0)
|
|
{
|
|
// max is one bit per pixel
|
|
_sendCodec.maxBitrate = ((WebRtc_Word32)_sendCodec.height *
|
|
(WebRtc_Word32)_sendCodec.width *
|
|
(WebRtc_Word32)_sendCodec.maxFramerate) / 1000;
|
|
if (_sendCodec.startBitrate > _sendCodec.maxBitrate)
|
|
{
|
|
// but if the customer tries to set a higher start bit rate we will increase
|
|
// the max accordingly
|
|
_sendCodec.maxBitrate = _sendCodec.startBitrate;
|
|
}
|
|
}
|
|
|
|
return VCM_OK;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::SendCodec(VideoCodec* currentSendCodec) const
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, VCMId(_id), "SendCodec");
|
|
|
|
if(_ptrEncoder == NULL)
|
|
{
|
|
return VCM_UNINITIALIZED;
|
|
}
|
|
memcpy(currentSendCodec, &_sendCodec, sizeof(VideoCodec));
|
|
return VCM_OK;
|
|
}
|
|
|
|
VideoCodecType
|
|
VCMCodecDataBase::SendCodec() const
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, VCMId(_id),
|
|
"SendCodec type");
|
|
if (_ptrEncoder == NULL)
|
|
{
|
|
return kVideoCodecUnknown;
|
|
}
|
|
return _sendCodec.codecType;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::DeRegisterExternalEncoder(WebRtc_UWord8 payloadType, bool& wasSendCodec)
|
|
{
|
|
wasSendCodec = false;
|
|
if (_externalPayloadType != payloadType)
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
if (_sendCodec.plType == payloadType)
|
|
{
|
|
//De-register as send codec if needed
|
|
DeleteEncoder();
|
|
memset(&_sendCodec, 0, sizeof(VideoCodec));
|
|
_currentEncIsExternal = false;
|
|
wasSendCodec = true;
|
|
}
|
|
_externalPayloadType = 0;
|
|
_externalEncoder = NULL;
|
|
_internalSource = false;
|
|
return VCM_OK;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::RegisterExternalEncoder(VideoEncoder* externalEncoder,
|
|
WebRtc_UWord8 payloadType,
|
|
bool internalSource)
|
|
{
|
|
// since only one encoder can be used at a given time,
|
|
// only one external encoder can be registered/used
|
|
_externalEncoder = externalEncoder;
|
|
_externalPayloadType = payloadType;
|
|
_internalSource = internalSource;
|
|
|
|
return VCM_OK;
|
|
}
|
|
|
|
VCMGenericEncoder*
|
|
VCMCodecDataBase::SetEncoder(const VideoCodec* settings,
|
|
VCMEncodedFrameCallback* VCMencodedFrameCallback)
|
|
|
|
{
|
|
// if encoder exists, will destroy it and create new one
|
|
DeleteEncoder();
|
|
|
|
if (settings->plType == _externalPayloadType)
|
|
{
|
|
// External encoder
|
|
_ptrEncoder = new VCMGenericEncoder(*_externalEncoder, _internalSource);
|
|
_currentEncIsExternal = true;
|
|
}
|
|
else
|
|
{
|
|
_ptrEncoder = CreateEncoder(settings->codecType);
|
|
_currentEncIsExternal = false;
|
|
}
|
|
|
|
VCMencodedFrameCallback->SetPayloadType(settings->plType);
|
|
|
|
if (_ptrEncoder == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (_ptrEncoder->InitEncode(settings, _numberOfCores, _maxPayloadSize) < 0)
|
|
{
|
|
DeleteEncoder();
|
|
return NULL;
|
|
}
|
|
else if (_ptrEncoder->RegisterEncodeCallback(VCMencodedFrameCallback) < 0)
|
|
{
|
|
DeleteEncoder();
|
|
return NULL;
|
|
}
|
|
// Intentionally don't check return value since the encoder registration
|
|
// shouldn't fail because the codec doesn't support changing the
|
|
// periodic key frame setting.
|
|
_ptrEncoder->SetPeriodicKeyFrames(_periodicKeyFrames);
|
|
return _ptrEncoder;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::SetPeriodicKeyFrames(bool enable)
|
|
{
|
|
_periodicKeyFrames = enable;
|
|
if (_ptrEncoder != NULL)
|
|
{
|
|
return _ptrEncoder->SetPeriodicKeyFrames(_periodicKeyFrames);
|
|
}
|
|
return VCM_OK;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::RegisterReceiveCodec(const VideoCodec* receiveCodec,
|
|
WebRtc_UWord32 numberOfCores,
|
|
bool requireKeyFrame)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCoding, VCMId(_id),
|
|
"Codec: %s, Payload type %d, Height %d, Width %d, Bitrate %d, Framerate %d.",
|
|
receiveCodec->plName, receiveCodec->plType,
|
|
receiveCodec->height, receiveCodec->width,
|
|
receiveCodec->startBitrate, receiveCodec->maxFramerate);
|
|
|
|
// check if payload value already exists, if so - erase old and insert new
|
|
DeRegisterReceiveCodec(receiveCodec->plType);
|
|
if (receiveCodec->codecType == kVideoCodecUnknown)
|
|
{
|
|
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
|
|
}
|
|
VideoCodec* newReceiveCodec = new VideoCodec(*receiveCodec);
|
|
_decMap.Insert(receiveCodec->plType,
|
|
new VCMDecoderMapItem(newReceiveCodec, numberOfCores, requireKeyFrame));
|
|
|
|
return VCM_OK;
|
|
}
|
|
|
|
WebRtc_Word32 VCMCodecDataBase::DeRegisterReceiveCodec(WebRtc_UWord8 payloadType)
|
|
{
|
|
MapItem* item = _decMap.Find(payloadType);
|
|
if (item == NULL)
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
VCMDecoderMapItem* decItem = static_cast<VCMDecoderMapItem*>(item->GetItem());
|
|
delete decItem->_settings;
|
|
delete decItem;
|
|
_decMap.Erase(item);
|
|
if (_receiveCodec.plType == payloadType)
|
|
{
|
|
// This codec is currently in use.
|
|
memset(&_receiveCodec, 0, sizeof(VideoCodec));
|
|
_currentDecIsExternal = false;
|
|
}
|
|
return VCM_OK;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::ResetReceiver()
|
|
{
|
|
ReleaseDecoder(_ptrDecoder);
|
|
_ptrDecoder = NULL;
|
|
memset(&_receiveCodec, 0, sizeof(VideoCodec));
|
|
MapItem* item = _decMap.First();
|
|
while (item != NULL)
|
|
{
|
|
VCMDecoderMapItem* decItem = static_cast<VCMDecoderMapItem*>(item->GetItem());
|
|
if (decItem != NULL)
|
|
{
|
|
if (decItem->_settings != NULL)
|
|
{
|
|
delete decItem->_settings;
|
|
}
|
|
delete decItem;
|
|
}
|
|
_decMap.Erase(item);
|
|
item = _decMap.First();
|
|
}
|
|
item = _decExternalMap.First();
|
|
while (item != NULL)
|
|
{
|
|
VCMExtDecoderMapItem* decItem = static_cast<VCMExtDecoderMapItem*>(item->GetItem());
|
|
if (decItem != NULL)
|
|
{
|
|
delete decItem;
|
|
}
|
|
_decExternalMap.Erase(item);
|
|
item = _decExternalMap.First();
|
|
}
|
|
_currentDecIsExternal = false;
|
|
return VCM_OK;
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::DeRegisterExternalDecoder(WebRtc_UWord8 payloadType)
|
|
{
|
|
MapItem* item = _decExternalMap.Find(payloadType);
|
|
if (item == NULL)
|
|
{
|
|
// Not found
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
if (_receiveCodec.plType == payloadType)
|
|
{
|
|
// Release it if it was registered and in use
|
|
ReleaseDecoder(_ptrDecoder);
|
|
_ptrDecoder = NULL;
|
|
}
|
|
DeRegisterReceiveCodec(payloadType);
|
|
VCMExtDecoderMapItem* decItem = static_cast<VCMExtDecoderMapItem*>(item->GetItem());
|
|
delete decItem;
|
|
_decExternalMap.Erase(item);
|
|
return VCM_OK;
|
|
}
|
|
|
|
// Add the external encoder object to the list of external decoders.
|
|
// Won't be registered as a receive codec until RegisterReceiveCodec is called.
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::RegisterExternalDecoder(VideoDecoder* externalDecoder,
|
|
WebRtc_UWord8 payloadType,
|
|
bool internalRenderTiming)
|
|
{
|
|
// check if payload value already exists, if so - erase old and insert new
|
|
VCMExtDecoderMapItem* extDecoder = new VCMExtDecoderMapItem(externalDecoder,
|
|
payloadType,
|
|
internalRenderTiming);
|
|
if (extDecoder == NULL)
|
|
{
|
|
return VCM_MEMORY;
|
|
}
|
|
DeRegisterExternalDecoder(payloadType);
|
|
_decExternalMap.Insert(payloadType, extDecoder);
|
|
|
|
return VCM_OK;
|
|
}
|
|
|
|
bool
|
|
VCMCodecDataBase::DecoderRegistered() const
|
|
{
|
|
return (_decMap.Size() > 0);
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::ReceiveCodec(VideoCodec* currentReceiveCodec) const
|
|
{
|
|
if (_ptrDecoder == NULL)
|
|
{
|
|
return VCM_NO_FRAME_DECODED;
|
|
}
|
|
memcpy(currentReceiveCodec, &_receiveCodec, sizeof(VideoCodec));
|
|
return VCM_OK;
|
|
}
|
|
|
|
VideoCodecType
|
|
VCMCodecDataBase::ReceiveCodec() const
|
|
{
|
|
if (_ptrDecoder == NULL)
|
|
{
|
|
return kVideoCodecUnknown;
|
|
}
|
|
return _receiveCodec.codecType;
|
|
}
|
|
|
|
VCMGenericDecoder*
|
|
VCMCodecDataBase::SetDecoder(WebRtc_UWord8 payloadType, VCMDecodedFrameCallback& callback)
|
|
{
|
|
if (payloadType == _receiveCodec.plType || payloadType == 0)
|
|
{
|
|
return _ptrDecoder;
|
|
}
|
|
// check for exisitng decoder, if exists - delete
|
|
if (_ptrDecoder)
|
|
{
|
|
ReleaseDecoder(_ptrDecoder);
|
|
_ptrDecoder = NULL;
|
|
memset(&_receiveCodec, 0, sizeof(VideoCodec));
|
|
}
|
|
_ptrDecoder = CreateAndInitDecoder(payloadType, _receiveCodec, _currentDecIsExternal);
|
|
if (_ptrDecoder == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (_ptrDecoder->RegisterDecodeCompleteCallback(&callback) < 0)
|
|
{
|
|
ReleaseDecoder(_ptrDecoder);
|
|
_ptrDecoder = NULL;
|
|
memset(&_receiveCodec, 0, sizeof(VideoCodec));
|
|
return NULL;
|
|
}
|
|
return _ptrDecoder;
|
|
}
|
|
|
|
VCMGenericDecoder*
|
|
VCMCodecDataBase::CreateAndInitDecoder(WebRtc_UWord8 payloadType,
|
|
VideoCodec& newCodec,
|
|
bool &external) const
|
|
{
|
|
VCMDecoderMapItem* decoderItem = FindDecoderItem(payloadType);
|
|
if (decoderItem == NULL)
|
|
{
|
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id),
|
|
"Unknown payload type: %u", payloadType);
|
|
return NULL;
|
|
}
|
|
VCMGenericDecoder* ptrDecoder = NULL;
|
|
VCMExtDecoderMapItem* externalDecItem = FindExternalDecoderItem(payloadType);
|
|
if (externalDecItem != NULL)
|
|
{
|
|
// External codec
|
|
ptrDecoder = new VCMGenericDecoder(*externalDecItem->_externalDecoderInstance, _id,
|
|
true);
|
|
external = true;
|
|
}
|
|
else
|
|
{
|
|
// create decoder
|
|
ptrDecoder = CreateDecoder(decoderItem->_settings->codecType);
|
|
external = false;
|
|
}
|
|
if (ptrDecoder == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (ptrDecoder->InitDecode(decoderItem->_settings,
|
|
decoderItem->_numberOfCores,
|
|
decoderItem->_requireKeyFrame) < 0)
|
|
{
|
|
ReleaseDecoder(ptrDecoder);
|
|
return NULL;
|
|
}
|
|
|
|
SetCodecConfigParameters(*ptrDecoder, *decoderItem->_settings);
|
|
|
|
memcpy(&newCodec, decoderItem->_settings, sizeof(VideoCodec));
|
|
return ptrDecoder;
|
|
}
|
|
|
|
VCMGenericDecoder*
|
|
VCMCodecDataBase::CreateDecoderCopy() const
|
|
{
|
|
if (_ptrDecoder == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
VideoDecoder* decoderCopy = _ptrDecoder->_decoder.Copy();
|
|
if (decoderCopy == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
return new VCMGenericDecoder(*decoderCopy, _id, _ptrDecoder->External());
|
|
}
|
|
|
|
void
|
|
VCMCodecDataBase::CopyDecoder(const VCMGenericDecoder& decoder)
|
|
{
|
|
VideoDecoder* decoderCopy = decoder._decoder.Copy();
|
|
if (decoderCopy != NULL)
|
|
{
|
|
ReleaseDecoder(_ptrDecoder);
|
|
_ptrDecoder = new VCMGenericDecoder(*decoderCopy, _id, decoder.External());
|
|
}
|
|
}
|
|
|
|
bool
|
|
VCMCodecDataBase::RenderTiming() const
|
|
{
|
|
bool renderTiming = true;
|
|
if (_currentDecIsExternal)
|
|
{
|
|
VCMExtDecoderMapItem* extItem = FindExternalDecoderItem(_receiveCodec.plType);
|
|
renderTiming = extItem->_internalRenderTiming;
|
|
}
|
|
return renderTiming;
|
|
}
|
|
|
|
void
|
|
VCMCodecDataBase::ReleaseDecoder(VCMGenericDecoder* decoder) const
|
|
{
|
|
if (decoder != NULL)
|
|
{
|
|
decoder->Release();
|
|
if (!decoder->External() && &decoder->_decoder != NULL)
|
|
{
|
|
delete &decoder->_decoder;
|
|
}
|
|
delete decoder;
|
|
}
|
|
}
|
|
|
|
WebRtc_Word32
|
|
VCMCodecDataBase::SetCodecConfigParameters(WebRtc_UWord8 payloadType,
|
|
const WebRtc_UWord8* buffer,
|
|
WebRtc_Word32 length)
|
|
{
|
|
VCMDecoderMapItem* decItem = FindDecoderItem(payloadType);
|
|
if (decItem == NULL)
|
|
{
|
|
return VCM_PARAMETER_ERROR;
|
|
}
|
|
switch (decItem->_settings->codecType)
|
|
{
|
|
case kVideoCodecMPEG4:
|
|
{
|
|
memcpy(decItem->_settings->codecSpecific.MPEG4.configParameters, buffer, length);
|
|
decItem->_settings->codecSpecific.MPEG4.configParametersSize =
|
|
static_cast<WebRtc_UWord8>(length);
|
|
break;
|
|
}
|
|
default:
|
|
// This codec doesn't have codec config parameters
|
|
return VCM_GENERAL_ERROR;
|
|
}
|
|
if (_ptrDecoder != NULL && _receiveCodec.plType == decItem->_settings->plType)
|
|
{
|
|
return _ptrDecoder->SetCodecConfigParameters(buffer, length);
|
|
}
|
|
return VCM_OK;
|
|
}
|
|
|
|
VCMDecoderMapItem*
|
|
VCMCodecDataBase::FindDecoderItem(WebRtc_UWord8 payloadType) const
|
|
{
|
|
MapItem* item = _decMap.Find(payloadType);
|
|
if (item != NULL)
|
|
{
|
|
return static_cast<VCMDecoderMapItem*>(item->GetItem());
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
VCMExtDecoderMapItem*
|
|
VCMCodecDataBase::FindExternalDecoderItem(WebRtc_UWord8 payloadType) const
|
|
{
|
|
MapItem* item = _decExternalMap.Find(payloadType);
|
|
if (item != NULL)
|
|
{
|
|
return static_cast<VCMExtDecoderMapItem*>(item->GetItem());
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
VCMGenericDecoder*
|
|
VCMCodecDataBase::CreateDecoder(VideoCodecType type) const
|
|
{
|
|
switch(type)
|
|
{
|
|
#ifdef VIDEOCODEC_VP8
|
|
case kVideoCodecVP8:
|
|
return new VCMGenericDecoder(*(new VP8Decoder), _id);
|
|
#endif
|
|
#ifdef VIDEOCODEC_I420
|
|
case kVideoCodecI420:
|
|
return new VCMGenericDecoder(*(new I420Decoder), _id);
|
|
#endif
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
VCMCodecDataBase::SetCodecConfigParameters(VCMGenericDecoder& decoder,
|
|
const VideoCodec& settings)
|
|
{
|
|
switch (settings.codecType)
|
|
{
|
|
case kVideoCodecMPEG4:
|
|
{
|
|
if (settings.codecSpecific.MPEG4.configParametersSize > 0)
|
|
{
|
|
decoder.SetCodecConfigParameters(
|
|
settings.codecSpecific.MPEG4.configParameters,
|
|
settings.codecSpecific.MPEG4.configParametersSize);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
// No codec config parameters for this codec
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
}
|