webrtc/modules/utility/source/frame_scaler.cc

220 lines
7.8 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.
*/
#ifdef WEBRTC_MODULE_UTILITY_VIDEO
#include "frame_scaler.h"
#include "trace.h"
#include "vplib.h"
#ifndef NO_INTERPOLATOR
#include "InterpolatorInterface.h"
#endif
namespace webrtc {
FrameScaler::FrameScaler()
: _ptrVideoInterpolator(0),
_outWidth(0),
_outHeight(0),
_inWidth(0),
_inHeight(0)
{
}
FrameScaler::~FrameScaler( )
{
#ifndef NO_INTERPOLATOR
if( _ptrVideoInterpolator != 0)
{
deleteInterpolator(_ptrVideoInterpolator);
}
#endif
}
WebRtc_Word32 FrameScaler::ResizeFrameIfNeeded(VideoFrame& videoFrame,
WebRtc_UWord32 outWidth,
WebRtc_UWord32 outHeight)
{
if( videoFrame.Length( ) == 0)
{
return -1;
}
if((videoFrame.Width() != outWidth) || ( videoFrame.Height() != outHeight))
{
// Scale down by factor 2-4.
if(videoFrame.Width() % outWidth == 0 &&
videoFrame.Height() % outHeight == 0 &&
(videoFrame.Width() / outWidth) == (videoFrame.Height() / outHeight))
{
const WebRtc_Word32 multiple = videoFrame.Width() / outWidth;
WebRtc_UWord32 scaledWidth;
WebRtc_UWord32 scaledHeight;
switch(multiple)
{
case 2:
ScaleI420FrameQuarter(videoFrame.Width(), videoFrame.Height(),
videoFrame.Buffer());
videoFrame.SetLength(outWidth * outHeight * 3 / 2);
videoFrame.SetWidth( outWidth);
videoFrame.SetHeight(outHeight);
return 0;
case 3:
ScaleI420Down1_3(videoFrame.Width(), videoFrame.Height(),
videoFrame.Buffer(), videoFrame.Size(),
scaledWidth, scaledHeight);
videoFrame.SetLength((outWidth * outHeight * 3) / 2);
videoFrame.SetWidth(outWidth);
videoFrame.SetHeight(outHeight);
return 0;
case 4:
ScaleI420FrameQuarter(videoFrame.Width(), videoFrame.Height(),
videoFrame.Buffer());
ScaleI420FrameQuarter(videoFrame.Width() >> 1,
videoFrame.Height() >> 1,
videoFrame.Buffer());
videoFrame.SetLength((outWidth * outHeight * 3)/ 2);
videoFrame.SetWidth(outWidth);
videoFrame.SetHeight(outHeight);
return 0;
default:
break;
}
}
// Scale up by factor 2-4.
if(outWidth % videoFrame.Width() == 0 &&
outHeight % videoFrame.Height() == 0 &&
(outWidth / videoFrame.Width()) == (outHeight / videoFrame.Height()))
{
const WebRtc_Word32 multiple = outWidth / videoFrame.Width();
WebRtc_UWord32 scaledWidth = 0;
WebRtc_UWord32 scaledHeight = 0;
switch(multiple)
{
case 2:
videoFrame.VerifyAndAllocate((outHeight * outWidth * 3) / 2);
ScaleI420Up2(videoFrame.Width(), videoFrame.Height(),
videoFrame.Buffer(), videoFrame.Size(),
scaledWidth, scaledHeight);
videoFrame.SetLength((outWidth * outHeight * 3) / 2);
videoFrame.SetWidth(outWidth);
videoFrame.SetHeight(outHeight);
return 0;
case 3:
videoFrame.VerifyAndAllocate((outWidth * outHeight * 3) / 2);
ScaleI420Up2(videoFrame.Width(), videoFrame.Height(),
videoFrame.Buffer(), videoFrame.Size(),
scaledWidth, scaledHeight);
ScaleI420Up3_2(scaledWidth, scaledHeight, videoFrame.Buffer(),
videoFrame.Size(), scaledWidth, scaledHeight);
videoFrame.SetLength((outWidth * outHeight * 3) / 2);
videoFrame.SetWidth(outWidth);
videoFrame.SetHeight(outHeight);
return 0;
case 4:
videoFrame.VerifyAndAllocate((outWidth * outHeight * 3) / 2);
ScaleI420Up2(videoFrame.Width(), videoFrame.Height(),
videoFrame.Buffer(), videoFrame.Size(),
scaledWidth, scaledHeight);
ScaleI420Up2(scaledWidth, scaledHeight, videoFrame.Buffer(),
videoFrame.Size(), scaledWidth, scaledHeight);
videoFrame.SetLength((outWidth * outHeight * 3) / 2);
videoFrame.SetWidth(outWidth);
videoFrame.SetHeight(outHeight);
return 0;
default:
break;
}
}
// Use interpolator
#ifdef NO_INTERPOLATOR
assert(!"Interpolation not available");
#else
// Create new interpolator if the scaling changed.
if((_outWidth != outWidth) || (_outHeight != outHeight) ||
(_inWidth != videoFrame.Width()) ||
(_inHeight != videoFrame.Height()))
{
if(_ptrVideoInterpolator != 0)
{
deleteInterpolator(_ptrVideoInterpolator);
_ptrVideoInterpolator = 0;
}
_outWidth = outWidth;
_outHeight = outHeight;
_inWidth = videoFrame.Width();
_inHeight = videoFrame.Height();
}
if (!_ptrVideoInterpolator)
{
InterpolatorType interpolator = BiCubicBSpline;
if((_inWidth > ( _outWidth * 2)) ||
(_inWidth < ( _outWidth / 2)) ||
(_inHeight > ( _outHeight * 2)) ||
(_inHeight < ( _outHeight / 2)))
{
interpolator = BiCubicSine;
}
VideoFrameFormat inputFormat;
VideoFrameFormat outputFormat;
inputFormat.videoType = YUV420P;
inputFormat.xChannels = static_cast<short>(_inWidth);
inputFormat.yChannels = static_cast<short>(_inHeight);
outputFormat.videoType = YUV420P;
outputFormat.xChannels = static_cast<short>(_outWidth);
outputFormat.yChannels = static_cast<short>(_outHeight);
_interpolatorBuffer.VerifyAndAllocate(_outWidth * _outHeight *
3 / 2);
_ptrVideoInterpolator = createInterpolator(
interpolator,
&inputFormat,
&outputFormat);
if (_ptrVideoInterpolator == NULL)
{
WEBRTC_TRACE(
kTraceError,
kTraceVideo,
-1,
"FrameScaler::ResizeFrame(): Could not create\
interpolator");
return -1;
}
}
interpolateFrame(_ptrVideoInterpolator, videoFrame.Buffer(),
_interpolatorBuffer.Buffer());
videoFrame.VerifyAndAllocate(_interpolatorBuffer.Size());
videoFrame.SetLength(_outWidth * _outHeight * 3 / 2);
videoFrame.CopyFrame(videoFrame.Length(), _interpolatorBuffer.Buffer());
videoFrame.SetWidth(_outWidth);
videoFrame.SetHeight(_outHeight);
#endif // NO_INTERPOLATOR
}
return 0;
}
} // namespace webrtc
#endif // WEBRTC_MODULE_UTILITY_VIDEO