/* * 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(_inWidth); inputFormat.yChannels = static_cast(_inHeight); outputFormat.videoType = YUV420P; outputFormat.xChannels = static_cast(_outWidth); outputFormat.yChannels = static_cast(_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