blob: e3ec0b0764b74e3c66bece2c113c0c26ac25a08d [file] [log] [blame]
niklase@google.com77ae29b2011-05-30 11:22:19 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#ifdef WEBRTC_MODULE_UTILITY_VIDEO
12#include "frame_scaler.h"
13
14#include "trace.h"
15#include "vplib.h"
16
17#ifndef NO_INTERPOLATOR
18 #include "InterpolatorInterface.h"
19#endif
20
21namespace webrtc {
22FrameScaler::FrameScaler()
23 : _ptrVideoInterpolator(0),
24 _outWidth(0),
25 _outHeight(0),
26 _inWidth(0),
27 _inHeight(0)
28{
29}
30
31FrameScaler::~FrameScaler( )
32{
33#ifndef NO_INTERPOLATOR
34 if( _ptrVideoInterpolator != 0)
35 {
36 deleteInterpolator(_ptrVideoInterpolator);
37 }
38 #endif
39}
40
41WebRtc_Word32 FrameScaler::ResizeFrameIfNeeded(VideoFrame& videoFrame,
42 WebRtc_UWord32 outWidth,
43 WebRtc_UWord32 outHeight)
44{
45 if( videoFrame.Length( ) == 0)
46 {
47 return -1;
48 }
49
50 if((videoFrame.Width() != outWidth) || ( videoFrame.Height() != outHeight))
51 {
52 // Scale down by factor 2-4.
53 if(videoFrame.Width() % outWidth == 0 &&
54 videoFrame.Height() % outHeight == 0 &&
55 (videoFrame.Width() / outWidth) == (videoFrame.Height() / outHeight))
56 {
57 const WebRtc_Word32 multiple = videoFrame.Width() / outWidth;
58 WebRtc_UWord32 scaledWidth;
59 WebRtc_UWord32 scaledHeight;
60 switch(multiple)
61 {
62 case 2:
63 ScaleI420FrameQuarter(videoFrame.Width(), videoFrame.Height(),
64 videoFrame.Buffer());
65
66 videoFrame.SetLength(outWidth * outHeight * 3 / 2);
67 videoFrame.SetWidth( outWidth);
68 videoFrame.SetHeight(outHeight);
69 return 0;
70 case 3:
71 ScaleI420Down1_3(videoFrame.Width(), videoFrame.Height(),
72 videoFrame.Buffer(), videoFrame.Size(),
73 scaledWidth, scaledHeight);
74 videoFrame.SetLength((outWidth * outHeight * 3) / 2);
75 videoFrame.SetWidth(outWidth);
76 videoFrame.SetHeight(outHeight);
77 return 0;
78 case 4:
79 ScaleI420FrameQuarter(videoFrame.Width(), videoFrame.Height(),
80 videoFrame.Buffer());
81
82 ScaleI420FrameQuarter(videoFrame.Width() >> 1,
83 videoFrame.Height() >> 1,
84 videoFrame.Buffer());
85
86 videoFrame.SetLength((outWidth * outHeight * 3)/ 2);
87 videoFrame.SetWidth(outWidth);
88 videoFrame.SetHeight(outHeight);
89 return 0;
90 default:
91 break;
92 }
93 }
94 // Scale up by factor 2-4.
95 if(outWidth % videoFrame.Width() == 0 &&
96 outHeight % videoFrame.Height() == 0 &&
97 (outWidth / videoFrame.Width()) == (outHeight / videoFrame.Height()))
98 {
99 const WebRtc_Word32 multiple = outWidth / videoFrame.Width();
100 WebRtc_UWord32 scaledWidth = 0;
101 WebRtc_UWord32 scaledHeight = 0;
102 switch(multiple)
103 {
104 case 2:
105 videoFrame.VerifyAndAllocate((outHeight * outWidth * 3) / 2);
106 ScaleI420Up2(videoFrame.Width(), videoFrame.Height(),
107 videoFrame.Buffer(), videoFrame.Size(),
108 scaledWidth, scaledHeight);
109 videoFrame.SetLength((outWidth * outHeight * 3) / 2);
110 videoFrame.SetWidth(outWidth);
111 videoFrame.SetHeight(outHeight);
112 return 0;
113 case 3:
114 videoFrame.VerifyAndAllocate((outWidth * outHeight * 3) / 2);
115 ScaleI420Up2(videoFrame.Width(), videoFrame.Height(),
116 videoFrame.Buffer(), videoFrame.Size(),
117 scaledWidth, scaledHeight);
118
119 ScaleI420Up3_2(scaledWidth, scaledHeight, videoFrame.Buffer(),
120 videoFrame.Size(), scaledWidth, scaledHeight);
121 videoFrame.SetLength((outWidth * outHeight * 3) / 2);
122 videoFrame.SetWidth(outWidth);
123 videoFrame.SetHeight(outHeight);
124 return 0;
125 case 4:
126 videoFrame.VerifyAndAllocate((outWidth * outHeight * 3) / 2);
127 ScaleI420Up2(videoFrame.Width(), videoFrame.Height(),
128 videoFrame.Buffer(), videoFrame.Size(),
129 scaledWidth, scaledHeight);
130 ScaleI420Up2(scaledWidth, scaledHeight, videoFrame.Buffer(),
131 videoFrame.Size(), scaledWidth, scaledHeight);
132 videoFrame.SetLength((outWidth * outHeight * 3) / 2);
133 videoFrame.SetWidth(outWidth);
134 videoFrame.SetHeight(outHeight);
135 return 0;
136 default:
137 break;
138 }
139 }
140 // Use interpolator
141#ifdef NO_INTERPOLATOR
142 assert(!"Interpolation not available");
143#else
144 // Create new interpolator if the scaling changed.
145 if((_outWidth != outWidth) || (_outHeight != outHeight) ||
146 (_inWidth != videoFrame.Width()) ||
147 (_inHeight != videoFrame.Height()))
148 {
149 if(_ptrVideoInterpolator != 0)
150 {
151 deleteInterpolator(_ptrVideoInterpolator);
152 _ptrVideoInterpolator = 0;
153 }
154
155 _outWidth = outWidth;
156 _outHeight = outHeight;
157 _inWidth = videoFrame.Width();
158 _inHeight = videoFrame.Height();
159 }
160
161
162 if (!_ptrVideoInterpolator)
163 {
164 InterpolatorType interpolator = BiCubicBSpline;
165
166 if((_inWidth > ( _outWidth * 2)) ||
167 (_inWidth < ( _outWidth / 2)) ||
168 (_inHeight > ( _outHeight * 2)) ||
169 (_inHeight < ( _outHeight / 2)))
170
171 {
172 interpolator = BiCubicSine;
173 }
174
175 VideoFrameFormat inputFormat;
176 VideoFrameFormat outputFormat;
177
178 inputFormat.videoType = YUV420P;
179 inputFormat.xChannels = static_cast<short>(_inWidth);
180 inputFormat.yChannels = static_cast<short>(_inHeight);
181
182 outputFormat.videoType = YUV420P;
183 outputFormat.xChannels = static_cast<short>(_outWidth);
184 outputFormat.yChannels = static_cast<short>(_outHeight);
185
186 _interpolatorBuffer.VerifyAndAllocate(_outWidth * _outHeight *
187 3 / 2);
188
189 _ptrVideoInterpolator = createInterpolator(
190 interpolator,
191 &inputFormat,
192 &outputFormat);
193 if (_ptrVideoInterpolator == NULL)
194 {
195 WEBRTC_TRACE(
196 kTraceError,
197 kTraceVideo,
198 -1,
199 "FrameScaler::ResizeFrame(): Could not create\
200 interpolator");
201 return -1;
202 }
203 }
204
205 interpolateFrame(_ptrVideoInterpolator, videoFrame.Buffer(),
206 _interpolatorBuffer.Buffer());
207
208 videoFrame.VerifyAndAllocate(_interpolatorBuffer.Size());
209 videoFrame.SetLength(_outWidth * _outHeight * 3 / 2);
210 videoFrame.CopyFrame(videoFrame.Length(), _interpolatorBuffer.Buffer());
211 videoFrame.SetWidth(_outWidth);
212 videoFrame.SetHeight(_outHeight);
213#endif // NO_INTERPOLATOR
214 }
215 return 0;
216}
217} // namespace webrtc
218
219#endif // WEBRTC_MODULE_UTILITY_VIDEO