First implementation of simulcast, adds VP8 simulcast to video engine.
Changed API to RTP module Expanded Auto test with a test for simulcast Made the video codec tests compile Added the vp8_simulcast files to this cl Added missing auto test file Review URL: http://webrtc-codereview.appspot.com/188001 git-svn-id: http://webrtc.googlecode.com/svn/trunk@736 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
// Supported codecs
|
||||
#ifdef VIDEOCODEC_VP8
|
||||
#include "vp8.h"
|
||||
#include "vp8_simulcast.h"
|
||||
#endif
|
||||
#ifdef VIDEOCODEC_I420
|
||||
#include "i420.h"
|
||||
@@ -91,7 +92,7 @@ VCMCodecDataBase::Version(WebRtc_Word8* version,
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
encoder = CreateEncoder(settings.codecType);
|
||||
encoder = CreateEncoder(settings.codecType, false);
|
||||
if (encoder == NULL)
|
||||
{
|
||||
return VCM_MEMORY;
|
||||
@@ -133,24 +134,29 @@ VCMCodecDataBase::ResetSender()
|
||||
return VCM_OK;
|
||||
}
|
||||
|
||||
VCMGenericEncoder*
|
||||
VCMCodecDataBase::CreateEncoder(VideoCodecType type) const
|
||||
{
|
||||
VCMGenericEncoder* VCMCodecDataBase::CreateEncoder(
|
||||
const VideoCodecType type,
|
||||
const bool simulcast) const {
|
||||
|
||||
switch(type)
|
||||
{
|
||||
#ifdef VIDEOCODEC_VP8
|
||||
case kVideoCodecVP8:
|
||||
return new VCMGenericEncoder(*(new VP8Encoder));
|
||||
break;
|
||||
if (simulcast) {
|
||||
return new VCMGenericEncoder(*(new VP8SimulcastEncoder));
|
||||
} else {
|
||||
return new VCMGenericEncoder(*(new VP8Encoder));
|
||||
}
|
||||
#endif
|
||||
#ifdef VIDEOCODEC_I420
|
||||
case kVideoCodecI420:
|
||||
return new VCMGenericEncoder(*(new I420Encoder));
|
||||
break;
|
||||
if (!simulcast) {
|
||||
return new VCMGenericEncoder(*(new I420Encoder));
|
||||
}
|
||||
return NULL;
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
break;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +209,8 @@ VCMCodecDataBase::Codec(WebRtc_UWord8 listId, VideoCodec *settings)
|
||||
settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
|
||||
settings->width = VCM_DEFAULT_CODEC_WIDTH;
|
||||
settings->height = VCM_DEFAULT_CODEC_HEIGHT;
|
||||
settings->numberOfSimulcastStreams = 0;
|
||||
settings->codecSpecific.VP8.numberOfTemporalLayers = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -222,6 +230,7 @@ VCMCodecDataBase::Codec(WebRtc_UWord8 listId, VideoCodec *settings)
|
||||
settings->width = VCM_DEFAULT_CODEC_WIDTH;
|
||||
settings->height = VCM_DEFAULT_CODEC_HEIGHT;
|
||||
settings->minBitrate = VCM_MIN_BITRATE;
|
||||
settings->numberOfSimulcastStreams = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -387,19 +396,32 @@ VCMCodecDataBase::SetEncoder(const VideoCodec* settings,
|
||||
}
|
||||
else
|
||||
{
|
||||
_ptrEncoder = CreateEncoder(settings->codecType);
|
||||
bool simulcast = false;
|
||||
if (settings->numberOfSimulcastStreams > 1)
|
||||
{
|
||||
simulcast = true;
|
||||
}
|
||||
_ptrEncoder = CreateEncoder(settings->codecType, simulcast);
|
||||
_currentEncIsExternal = false;
|
||||
}
|
||||
|
||||
VCMencodedFrameCallback->SetPayloadType(settings->plType);
|
||||
|
||||
if (_ptrEncoder == NULL)
|
||||
{
|
||||
WEBRTC_TRACE(webrtc::kTraceError,
|
||||
webrtc::kTraceVideoCoding,
|
||||
VCMId(_id),
|
||||
"Failed to create encoder: %s.",
|
||||
settings->plName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_ptrEncoder->InitEncode(settings, _numberOfCores, _maxPayloadSize) < 0)
|
||||
{
|
||||
WEBRTC_TRACE(webrtc::kTraceError,
|
||||
webrtc::kTraceVideoCoding,
|
||||
VCMId(_id),
|
||||
"Failed to initialize encoder: %s.",
|
||||
settings->plName);
|
||||
DeleteEncoder();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,8 @@ protected:
|
||||
/**
|
||||
* Create an internal Encoder given a codec type
|
||||
*/
|
||||
VCMGenericEncoder* CreateEncoder(VideoCodecType type) const;
|
||||
VCMGenericEncoder* CreateEncoder(const VideoCodecType type,
|
||||
const bool simulcast) const;
|
||||
|
||||
void DeleteEncoder();
|
||||
/*
|
||||
|
||||
@@ -51,7 +51,9 @@ WebRtc_Word32 VCMGenericEncoder::Release()
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
VCMGenericEncoder::InitEncode(const VideoCodec* settings, WebRtc_Word32 numberOfCores, WebRtc_UWord32 maxPayloadSize)
|
||||
VCMGenericEncoder::InitEncode(const VideoCodec* settings,
|
||||
WebRtc_Word32 numberOfCores,
|
||||
WebRtc_UWord32 maxPayloadSize)
|
||||
{
|
||||
_bitRate = settings->startBitrate;
|
||||
_frameRate = settings->maxFramerate;
|
||||
@@ -66,16 +68,21 @@ VCMGenericEncoder::InitEncode(const VideoCodec* settings, WebRtc_Word32 numberOf
|
||||
WebRtc_Word32
|
||||
VCMGenericEncoder::Encode(const VideoFrame& inputFrame,
|
||||
const CodecSpecificInfo* codecSpecificInfo,
|
||||
FrameType frameType)
|
||||
FrameType* frameType)
|
||||
{
|
||||
RawImage rawImage(inputFrame.Buffer(), inputFrame.Length(), inputFrame.Size());
|
||||
RawImage rawImage(inputFrame.Buffer(),
|
||||
inputFrame.Length(),
|
||||
inputFrame.Size());
|
||||
rawImage._width = inputFrame.Width();
|
||||
rawImage._height = inputFrame.Height();
|
||||
rawImage._timeStamp = inputFrame.TimeStamp();
|
||||
|
||||
WebRtc_Word32 ret = _encoder.Encode(rawImage, codecSpecificInfo, VCMEncodedFrame::ConvertFrameType(frameType));
|
||||
|
||||
return ret;
|
||||
VideoFrameType videoFrameTypes[kMaxSimulcastStreams];
|
||||
for (int i = 0; i < kMaxSimulcastStreams; i++)
|
||||
{
|
||||
videoFrameTypes[i] = VCMEncodedFrame::ConvertFrameType(frameType[i]);
|
||||
}
|
||||
return _encoder.Encode(rawImage, codecSpecificInfo, videoFrameTypes);
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
@@ -125,10 +132,15 @@ VCMGenericEncoder::SetPeriodicKeyFrames(bool enable)
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
VCMGenericEncoder::RequestFrame(FrameType frameType)
|
||||
VCMGenericEncoder::RequestFrame(FrameType* frameTypes)
|
||||
{
|
||||
RawImage image;
|
||||
return _encoder.Encode(image, NULL, VCMEncodedFrame::ConvertFrameType(frameType));
|
||||
VideoFrameType videoFrameTypes[kMaxSimulcastStreams];
|
||||
for (int i = 0; i < kMaxSimulcastStreams; i++)
|
||||
{
|
||||
videoFrameTypes[i] = VCMEncodedFrame::ConvertFrameType(frameTypes[i]);
|
||||
}
|
||||
return _encoder.Encode(image, NULL, videoFrameTypes);
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
@@ -186,22 +198,22 @@ VCMEncodedFrameCallback::Encoded(
|
||||
WebRtc_UWord32 encodedBytes = 0;
|
||||
if (_sendCallback != NULL)
|
||||
{
|
||||
encodedBytes = encodedImage._length;
|
||||
encodedBytes = encodedImage._length;
|
||||
|
||||
if (_bitStreamAfterEncoder != NULL)
|
||||
{
|
||||
fwrite(encodedImage._buffer, 1, encodedImage._length, _bitStreamAfterEncoder);
|
||||
}
|
||||
|
||||
RTPVideoTypeHeader rtpTypeHeader;
|
||||
RTPVideoTypeHeader* rtpTypeHeaderPtr = &rtpTypeHeader;
|
||||
RTPVideoHeader rtpVideoHeader;
|
||||
RTPVideoHeader* rtpVideoHeaderPtr = &rtpVideoHeader;
|
||||
if (codecSpecificInfo)
|
||||
{
|
||||
CopyCodecSpecific(*codecSpecificInfo, &rtpTypeHeaderPtr);
|
||||
CopyCodecSpecific(*codecSpecificInfo, &rtpVideoHeaderPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
rtpTypeHeaderPtr = NULL;
|
||||
rtpVideoHeaderPtr = NULL;
|
||||
}
|
||||
|
||||
WebRtc_Word32 callbackReturn = _sendCallback->SendData(
|
||||
@@ -211,7 +223,7 @@ VCMEncodedFrameCallback::Encoded(
|
||||
encodedImage._buffer,
|
||||
encodedBytes,
|
||||
*fragmentationHeader,
|
||||
rtpTypeHeaderPtr);
|
||||
rtpVideoHeaderPtr);
|
||||
if (callbackReturn < 0)
|
||||
{
|
||||
return callbackReturn;
|
||||
@@ -227,7 +239,6 @@ VCMEncodedFrameCallback::Encoded(
|
||||
{
|
||||
return _mediaOpt->DropFrame(); // Signal to encoder to drop next frame
|
||||
}
|
||||
|
||||
return VCM_OK;
|
||||
}
|
||||
|
||||
@@ -244,13 +255,17 @@ VCMEncodedFrameCallback::SetMediaOpt(VCMMediaOptimization *mediaOpt)
|
||||
}
|
||||
|
||||
void VCMEncodedFrameCallback::CopyCodecSpecific(const CodecSpecificInfo& info,
|
||||
RTPVideoTypeHeader** rtp) {
|
||||
switch (info.codecType)
|
||||
{
|
||||
RTPVideoHeader** rtp) {
|
||||
switch (info.codecType) {
|
||||
case kVideoCodecVP8: {
|
||||
(*rtp)->VP8.InitRTPVideoHeaderVP8();
|
||||
(*rtp)->VP8.pictureId = info.codecSpecific.VP8.pictureId;
|
||||
(*rtp)->VP8.nonReference = info.codecSpecific.VP8.nonReference;
|
||||
(*rtp)->codecHeader.VP8.InitRTPVideoHeaderVP8();
|
||||
(*rtp)->codecHeader.VP8.pictureId =
|
||||
info.codecSpecific.VP8.pictureId;
|
||||
(*rtp)->codecHeader.VP8.nonReference =
|
||||
info.codecSpecific.VP8.nonReference;
|
||||
(*rtp)->codecHeader.VP8.temporalIdx =
|
||||
info.codecSpecific.VP8.temporalIdx;
|
||||
(*rtp)->simulcastIdx = info.codecSpecific.VP8.simulcastIdx;
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
@@ -258,8 +273,6 @@ void VCMEncodedFrameCallback::CopyCodecSpecific(const CodecSpecificInfo& info,
|
||||
*rtp = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@@ -59,7 +59,7 @@ private:
|
||||
* in info, rtp is set to NULL.
|
||||
*/
|
||||
static void CopyCodecSpecific(const CodecSpecificInfo& info,
|
||||
RTPVideoTypeHeader** rtp);
|
||||
RTPVideoHeader** rtp);
|
||||
|
||||
VCMPacketizationCallback* _sendCallback;
|
||||
VCMMediaOptimization* _mediaOpt;
|
||||
@@ -103,7 +103,7 @@ public:
|
||||
*/
|
||||
WebRtc_Word32 Encode(const VideoFrame& inputFrame,
|
||||
const CodecSpecificInfo* codecSpecificInfo,
|
||||
FrameType frameType);
|
||||
FrameType* frameType);
|
||||
/**
|
||||
* Set new target bit rate and frame rate
|
||||
* Return Value: new bit rate if OK, otherwise <0s
|
||||
@@ -129,7 +129,7 @@ public:
|
||||
|
||||
WebRtc_Word32 SetPeriodicKeyFrames(bool enable);
|
||||
|
||||
WebRtc_Word32 RequestFrame(FrameType frameType);
|
||||
WebRtc_Word32 RequestFrame(FrameType* frameTypes);
|
||||
|
||||
bool InternalSource() const;
|
||||
|
||||
|
||||
@@ -67,7 +67,6 @@ _scheduleKeyRequest(false),
|
||||
_sendCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
|
||||
_encoder(),
|
||||
_encodedFrameCallback(),
|
||||
_nextFrameType(kVideoFrameDelta),
|
||||
_mediaOpt(id),
|
||||
_sendCodecType(kVideoCodecUnknown),
|
||||
_sendStatsCallback(NULL),
|
||||
@@ -79,6 +78,10 @@ _sendStatsTimer(1000),
|
||||
_retransmissionTimer(10),
|
||||
_keyRequestTimer(500)
|
||||
{
|
||||
for (int i = 0; i < kMaxSimulcastStreams; i++)
|
||||
{
|
||||
_nextFrameType[i] = kVideoFrameDelta;
|
||||
}
|
||||
#ifdef DEBUG_DECODER_BIT_STREAM
|
||||
_bitStreamBeforeDecoder = fopen("decoderBitStream.bit", "wb");
|
||||
#endif
|
||||
@@ -786,7 +789,7 @@ VideoCodingModuleImpl::SetVideoProtection(VCMVideoProtection videoProtection,
|
||||
// Add one raw video frame to the encoder, blocking.
|
||||
WebRtc_Word32
|
||||
VideoCodingModuleImpl::AddVideoFrame(const VideoFrame& videoFrame,
|
||||
const VideoContentMetrics* _contentMetrics,
|
||||
const VideoContentMetrics* contentMetrics,
|
||||
const CodecSpecificInfo* codecSpecificInfo)
|
||||
{
|
||||
WEBRTC_TRACE(webrtc::kTraceModuleCall,
|
||||
@@ -799,12 +802,10 @@ VideoCodingModuleImpl::AddVideoFrame(const VideoFrame& videoFrame,
|
||||
{
|
||||
return VCM_UNINITIALIZED;
|
||||
}
|
||||
|
||||
if (_nextFrameType == kFrameEmpty)
|
||||
if (_nextFrameType[0] == kFrameEmpty)
|
||||
{
|
||||
return VCM_OK;
|
||||
}
|
||||
|
||||
_mediaOpt.UpdateIncomingFrameRate();
|
||||
|
||||
if (_mediaOpt.DropFrame())
|
||||
@@ -816,12 +817,10 @@ VideoCodingModuleImpl::AddVideoFrame(const VideoFrame& videoFrame,
|
||||
}
|
||||
else
|
||||
{
|
||||
_mediaOpt.updateContentData(_contentMetrics);
|
||||
const FrameType requestedFrameType = _nextFrameType;
|
||||
_nextFrameType = kVideoFrameDelta; // default frame type
|
||||
_mediaOpt.updateContentData(contentMetrics);
|
||||
WebRtc_Word32 ret = _encoder->Encode(videoFrame,
|
||||
codecSpecificInfo,
|
||||
requestedFrameType);
|
||||
_nextFrameType);
|
||||
if (_encoderInputFile != NULL)
|
||||
{
|
||||
fwrite(videoFrame.Buffer(), 1, videoFrame.Length(),
|
||||
@@ -829,36 +828,42 @@ VideoCodingModuleImpl::AddVideoFrame(const VideoFrame& videoFrame,
|
||||
}
|
||||
if (ret < 0)
|
||||
{
|
||||
_nextFrameType = requestedFrameType;
|
||||
WEBRTC_TRACE(webrtc::kTraceError,
|
||||
webrtc::kTraceVideoCoding,
|
||||
VCMId(_id),
|
||||
"Encode error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
for (int i = 0; i < kMaxSimulcastStreams; i++)
|
||||
{
|
||||
_nextFrameType[i] = kVideoFrameDelta; // default frame type
|
||||
}
|
||||
}
|
||||
|
||||
return VCM_OK;
|
||||
}
|
||||
|
||||
// Next frame encoded should be of the type frameType
|
||||
// Good for only one frame
|
||||
WebRtc_Word32
|
||||
VideoCodingModuleImpl::FrameTypeRequest(FrameType frameType)
|
||||
VideoCodingModuleImpl::FrameTypeRequest(FrameType frameType,
|
||||
WebRtc_UWord8 simulcastIdx)
|
||||
{
|
||||
assert(simulcastIdx < kMaxSimulcastStreams);
|
||||
|
||||
WEBRTC_TRACE(webrtc::kTraceModuleCall,
|
||||
webrtc::kTraceVideoCoding,
|
||||
VCMId(_id),
|
||||
"FrameTypeRequest()");
|
||||
|
||||
CriticalSectionScoped cs(_sendCritSect);
|
||||
_nextFrameType = frameType;
|
||||
_nextFrameType[simulcastIdx] = frameType;
|
||||
if (_encoder != NULL && _encoder->InternalSource())
|
||||
{
|
||||
// Try to request the frame if we have an external encoder with
|
||||
// internal source since AddVideoFrame never will be called.
|
||||
if (_encoder->RequestFrame(_nextFrameType) == WEBRTC_VIDEO_CODEC_OK)
|
||||
{
|
||||
_nextFrameType = kVideoFrameDelta;
|
||||
_nextFrameType[simulcastIdx] = kVideoFrameDelta;
|
||||
}
|
||||
}
|
||||
return VCM_OK;
|
||||
|
||||
@@ -150,7 +150,8 @@ public:
|
||||
const CodecSpecificInfo* codecSpecificInfo = NULL);
|
||||
|
||||
// Next frame encoded should be of the type frameType.
|
||||
virtual WebRtc_Word32 FrameTypeRequest(FrameType frameType);
|
||||
virtual WebRtc_Word32 FrameTypeRequest(FrameType frameType,
|
||||
WebRtc_UWord8 simulcastIdx);
|
||||
|
||||
//Enable frame dropper
|
||||
virtual WebRtc_Word32 EnableFrameDropper(bool enable);
|
||||
@@ -277,10 +278,10 @@ private:
|
||||
VCMKeyRequestMode _keyRequestMode;
|
||||
bool _scheduleKeyRequest;
|
||||
|
||||
CriticalSectionWrapper& _sendCritSect;
|
||||
CriticalSectionWrapper& _sendCritSect; // Critical section for send side
|
||||
VCMGenericEncoder* _encoder;
|
||||
VCMEncodedFrameCallback _encodedFrameCallback;
|
||||
FrameType _nextFrameType;
|
||||
FrameType _nextFrameType[kMaxSimulcastStreams];
|
||||
VCMMediaOptimization _mediaOpt;
|
||||
VideoCodecType _sendCodecType;
|
||||
VCMSendStatisticsCallback* _sendStatsCallback;
|
||||
@@ -292,7 +293,5 @@ private:
|
||||
VCMProcessTimer _retransmissionTimer;
|
||||
VCMProcessTimer _keyRequestTimer;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_VIDEO_CODING_VIDEO_CODING_IMPL_H_
|
||||
|
||||
Reference in New Issue
Block a user