1 | /* The copyright in this software is being made available under the BSD |
---|
2 | * License, included below. This software may be subject to other third party |
---|
3 | * and contributor rights, including patent rights, and no such rights are |
---|
4 | * granted under this license. |
---|
5 | * |
---|
6 | * Copyright (c) 2010-2016, ITU/ISO/IEC |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions are met: |
---|
11 | * |
---|
12 | * * Redistributions of source code must retain the above copyright notice, |
---|
13 | * this list of conditions and the following disclaimer. |
---|
14 | * * Redistributions in binary form must reproduce the above copyright notice, |
---|
15 | * this list of conditions and the following disclaimer in the documentation |
---|
16 | * and/or other materials provided with the distribution. |
---|
17 | * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may |
---|
18 | * be used to endorse or promote products derived from this software without |
---|
19 | * specific prior written permission. |
---|
20 | * |
---|
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS |
---|
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
---|
31 | * THE POSSIBILITY OF SUCH DAMAGE. |
---|
32 | */ |
---|
33 | |
---|
34 | #include "DownConvert.h" |
---|
35 | |
---|
36 | #include <cmath> |
---|
37 | #include <cstring> |
---|
38 | |
---|
39 | |
---|
40 | #define TMM_TABLE_SIZE 512 |
---|
41 | |
---|
42 | |
---|
43 | //================================================= |
---|
44 | // |
---|
45 | // G E N E R A L M A I N F U N C T I O N S |
---|
46 | // |
---|
47 | //================================================= |
---|
48 | |
---|
49 | DownConvert::DownConvert() |
---|
50 | : m_iImageStride ( 0 ) |
---|
51 | , m_paiImageBuffer ( 0 ) |
---|
52 | , m_paiTmp1dBuffer ( 0 ) |
---|
53 | { |
---|
54 | } |
---|
55 | |
---|
56 | DownConvert::~DownConvert() |
---|
57 | { |
---|
58 | xDestroy(); |
---|
59 | } |
---|
60 | |
---|
61 | bool |
---|
62 | DownConvert::init( int iMaxWidth, int iMaxHeight, int iMaxMargin ) |
---|
63 | { |
---|
64 | xDestroy(); |
---|
65 | |
---|
66 | iMaxWidth += 2 * iMaxMargin; |
---|
67 | iMaxHeight += 2 * iMaxMargin; |
---|
68 | int iPicSize = iMaxWidth * iMaxHeight; |
---|
69 | int iMaxDim = ( iMaxWidth > iMaxHeight ? iMaxWidth : iMaxHeight ); |
---|
70 | m_iImageStride = iMaxWidth; |
---|
71 | m_paiImageBuffer = new int [ iPicSize ]; |
---|
72 | m_paiTmp1dBuffer = new int [ iMaxDim ]; |
---|
73 | |
---|
74 | ROFRS( m_paiImageBuffer, true ); |
---|
75 | ROFRS( m_paiTmp1dBuffer, true ); |
---|
76 | |
---|
77 | return false; |
---|
78 | } |
---|
79 | |
---|
80 | void |
---|
81 | DownConvert::destroy() |
---|
82 | { |
---|
83 | delete this; |
---|
84 | } |
---|
85 | |
---|
86 | //=========================================================================== |
---|
87 | // |
---|
88 | // M A I N F U N C T I O N S F O R D O W N C O N V E R T T O O L |
---|
89 | // |
---|
90 | //=========================================================================== |
---|
91 | |
---|
92 | |
---|
93 | void |
---|
94 | DownConvert::downsamplingSVC( short* pucBufferY, int iStrideY, |
---|
95 | short* pucBufferU, int iStrideU, |
---|
96 | short* pucBufferV, int iStrideV, |
---|
97 | ResizeParameters* pcParameters, bool bBotCoincided ) |
---|
98 | { |
---|
99 | int iBaseW = pcParameters->m_iFrameWidth; |
---|
100 | int iBaseH = pcParameters->m_iFrameHeight; |
---|
101 | int iCurrW = pcParameters->m_iRefLayerFrmWidth; |
---|
102 | int iCurrH = pcParameters->m_iRefLayerFrmHeight; |
---|
103 | bool bTopAndBottomResampling = ( pcParameters->m_bRefLayerFrameMbsOnlyFlag == false && |
---|
104 | pcParameters->m_bRefLayerFieldPicFlag == false && |
---|
105 | pcParameters->m_bFrameMbsOnlyFlag == false && |
---|
106 | pcParameters->m_bFieldPicFlag == false ); |
---|
107 | bool bVerticalDownsampling = ( pcParameters->m_bFrameMbsOnlyFlag == true && |
---|
108 | pcParameters->m_bRefLayerFieldPicFlag == true ); |
---|
109 | bool bCurrBotField = ( pcParameters->m_bFieldPicFlag == true && |
---|
110 | pcParameters->m_bBotFieldFlag == true ); |
---|
111 | bool bBotFieldFlag = ( pcParameters->m_bRefLayerFrameMbsOnlyFlag ? false |
---|
112 | : pcParameters->m_bFieldPicFlag ? pcParameters->m_bBotFieldFlag |
---|
113 | : pcParameters->m_bRefLayerFieldPicFlag ? pcParameters->m_bRefLayerBotFieldFlag |
---|
114 | : false ); |
---|
115 | int iBaseField = ( pcParameters->m_bRefLayerFrameMbsOnlyFlag ? 0 : 1 ); |
---|
116 | int iCurrField = ( pcParameters->m_bFieldPicFlag ? 1 : 0 ); |
---|
117 | int iBaseBot = ( bBotFieldFlag ? 1 : 0 ); |
---|
118 | int iCurrBot = ( bCurrBotField ? 1 : 0 ); |
---|
119 | |
---|
120 | //==== check bot field coincided parameter for interlaced to progressive resampling ===== |
---|
121 | if( pcParameters->m_bRefLayerFrameMbsOnlyFlag && ! pcParameters->m_bFrameMbsOnlyFlag ) |
---|
122 | { |
---|
123 | bBotFieldFlag = bBotCoincided; |
---|
124 | } |
---|
125 | |
---|
126 | //======================= |
---|
127 | //===== L U M A ===== |
---|
128 | //======================= |
---|
129 | assert( bTopAndBottomResampling == false ); |
---|
130 | if( !bTopAndBottomResampling ) |
---|
131 | { |
---|
132 | short* pSrc = pucBufferY + iStrideY * iCurrBot; |
---|
133 | short* pDes = pucBufferY + iStrideY * iBaseBot; |
---|
134 | xCopyToImageBuffer ( pSrc, iCurrW, iCurrH >> iCurrField, iStrideY << iCurrField ); |
---|
135 | xCompDownsampling ( pcParameters, false, bBotFieldFlag, bVerticalDownsampling ); |
---|
136 | xCopyFromImageBuffer( pDes, iBaseW, iBaseH >> iBaseField, iStrideY << iBaseField ); |
---|
137 | } |
---|
138 | |
---|
139 | iBaseW >>= 1; |
---|
140 | iBaseH >>= 1; |
---|
141 | iCurrW >>= 1; |
---|
142 | iCurrH >>= 1; |
---|
143 | |
---|
144 | //=========================== |
---|
145 | //===== C H R O M A ===== |
---|
146 | //=========================== |
---|
147 | if( !bTopAndBottomResampling ) |
---|
148 | { |
---|
149 | //===== U ===== |
---|
150 | short* pSrc = pucBufferU + iStrideU * iCurrBot; |
---|
151 | short* pDes = pucBufferU + iStrideU * iBaseBot; |
---|
152 | xCopyToImageBuffer ( pSrc, iCurrW, iCurrH >> iCurrField, iStrideU << iCurrField ); |
---|
153 | xCompDownsampling ( pcParameters, true, bBotFieldFlag, bVerticalDownsampling ); |
---|
154 | xCopyFromImageBuffer( pDes, iBaseW, iBaseH >> iBaseField, iStrideU << iBaseField ); |
---|
155 | |
---|
156 | //===== V ===== |
---|
157 | pSrc = pucBufferV + iStrideV * iCurrBot; |
---|
158 | pDes = pucBufferV + iStrideV * iBaseBot; |
---|
159 | xCopyToImageBuffer ( pSrc, iCurrW, iCurrH >> iCurrField, iStrideV << iCurrField ); |
---|
160 | xCompDownsampling ( pcParameters, true, bBotFieldFlag, bVerticalDownsampling ); |
---|
161 | xCopyFromImageBuffer( pDes, iBaseW, iBaseH >> iBaseField, iStrideV << iBaseField ); |
---|
162 | } |
---|
163 | } |
---|
164 | |
---|
165 | |
---|
166 | //====================================================== |
---|
167 | // |
---|
168 | // G E N E R A L H E L P E R F U N C T I O N S |
---|
169 | // |
---|
170 | //====================================================== |
---|
171 | |
---|
172 | void |
---|
173 | DownConvert::xDestroy() |
---|
174 | { |
---|
175 | delete [] m_paiImageBuffer; |
---|
176 | delete [] m_paiTmp1dBuffer; |
---|
177 | m_paiImageBuffer = 0; |
---|
178 | m_paiTmp1dBuffer = 0; |
---|
179 | } |
---|
180 | |
---|
181 | int |
---|
182 | DownConvert::xClip( int iValue, int imin, int imax ) |
---|
183 | { |
---|
184 | ROTRS( iValue < imin, imin ); |
---|
185 | ROTRS( iValue > imax, imax ); |
---|
186 | return iValue; |
---|
187 | } |
---|
188 | |
---|
189 | |
---|
190 | //=============================================================================== |
---|
191 | // |
---|
192 | // H E L P E R F U N C T I O N S F O R D O W N C O N V E R T T O O L |
---|
193 | // |
---|
194 | //=============================================================================== |
---|
195 | |
---|
196 | void |
---|
197 | DownConvert::xCopyToImageBuffer( short* pucSrc, int iWidth, int iHeight, int iStride ) |
---|
198 | { |
---|
199 | int* piDes = m_paiImageBuffer; |
---|
200 | for( int j = 0; j < iHeight; j++ ) |
---|
201 | { |
---|
202 | for( int i = 0; i < iWidth; i++ ) |
---|
203 | { |
---|
204 | piDes[i] = (int)pucSrc[i]; |
---|
205 | } |
---|
206 | piDes += m_iImageStride; |
---|
207 | pucSrc += iStride; |
---|
208 | } |
---|
209 | } |
---|
210 | |
---|
211 | void |
---|
212 | DownConvert::xCopyFromImageBuffer( short* pucDes, int iWidth, int iHeight, int iStride ) |
---|
213 | { |
---|
214 | int* piSrc = m_paiImageBuffer; |
---|
215 | for( int j = 0; j < iHeight; j++ ) |
---|
216 | { |
---|
217 | for( int i = 0; i < iWidth; i++ ) |
---|
218 | { |
---|
219 | pucDes[i] = (short)piSrc[i]; |
---|
220 | } |
---|
221 | pucDes += iStride; |
---|
222 | piSrc += m_iImageStride; |
---|
223 | } |
---|
224 | } |
---|
225 | |
---|
226 | void |
---|
227 | DownConvert::xCompDownsampling( ResizeParameters* pcParameters, bool bChroma, bool bBotFlag, bool bVerticalDownsampling ) |
---|
228 | { |
---|
229 | //===== set general parameters ===== |
---|
230 | int iBotField = ( bBotFlag ? 1 : 0 ); |
---|
231 | int iFactor = ( !bChroma ? 1 : 2 ); |
---|
232 | int iRefPhaseX = ( !bChroma ? 0 : pcParameters->m_iChromaPhaseX ); |
---|
233 | int iRefPhaseY = ( !bChroma ? 0 : pcParameters->m_iChromaPhaseY ); |
---|
234 | int iPhaseX = ( !bChroma ? 0 : pcParameters->m_iRefLayerChromaPhaseX ); |
---|
235 | int iPhaseY = ( !bChroma ? 0 : pcParameters->m_iRefLayerChromaPhaseY ); |
---|
236 | int iRefW = pcParameters->m_iFrameWidth / iFactor; // reference layer frame width |
---|
237 | int iRefH = pcParameters->m_iFrameHeight / iFactor; // reference layer frame height |
---|
238 | int iOutW = pcParameters->m_iScaledRefFrmWidth / iFactor; // scaled reference layer frame width |
---|
239 | int iOutH = pcParameters->m_iScaledRefFrmHeight / iFactor; // scaled reference layer frame height |
---|
240 | int iGlobalW = pcParameters->m_iRefLayerFrmWidth / iFactor; // current frame width |
---|
241 | int iGlobalH = pcParameters->m_iRefLayerFrmHeight / iFactor; // current frame height |
---|
242 | int iLeftOffset = pcParameters->m_iLeftFrmOffset / iFactor; // current left frame offset |
---|
243 | int iTopOffset = pcParameters->m_iTopFrmOffset / iFactor; // current top frame offset |
---|
244 | |
---|
245 | //===== set input/output size ===== |
---|
246 | int iBaseField = ( pcParameters->m_bRefLayerFrameMbsOnlyFlag ? 0 : 1 ); |
---|
247 | int iCurrField = ( pcParameters->m_bRefLayerFrameMbsOnlyFlag && pcParameters->m_bFrameMbsOnlyFlag ? 0 : 1 ); |
---|
248 | int iBaseW = iRefW; |
---|
249 | int iBaseH = iRefH >> iBaseField; |
---|
250 | int iCurrW = iGlobalW; |
---|
251 | int iCurrH = iGlobalH >> iCurrField; |
---|
252 | int iLOffset = iLeftOffset; |
---|
253 | int iTOffset = iTopOffset >> iCurrField; |
---|
254 | int iROffset = iCurrW - iLOffset - iOutW; |
---|
255 | int iBOffset = iCurrH - iTOffset - ( iOutH >> iCurrField ); |
---|
256 | |
---|
257 | //===== set position calculation parameters ===== |
---|
258 | int iScaledW = iOutW; |
---|
259 | int iScaledH = ( ! pcParameters->m_bRefLayerFrameMbsOnlyFlag || pcParameters->m_bFrameMbsOnlyFlag ? iOutH : iOutH / 2 ); |
---|
260 | int iShiftX = ( pcParameters->m_iLevelIdc <= 30 ? 16 : 31 - CeilLog2( iScaledW ) ); |
---|
261 | int iShiftY = ( pcParameters->m_iLevelIdc <= 30 ? 16 : 31 - CeilLog2( iScaledH ) ); |
---|
262 | int iScaleX = ( ( (unsigned int)iScaledW << iShiftX ) + ( iRefW >> 1 ) ) / iRefW; |
---|
263 | int iScaleY = ( ( (unsigned int)iScaledH << iShiftY ) + ( iRefH >> 1 ) ) / iRefH; |
---|
264 | |
---|
265 | int inputBitDepth = pcParameters->inputBitDepth; |
---|
266 | int outputBitDepth = pcParameters->outputBitDepth; |
---|
267 | |
---|
268 | if( ! pcParameters->m_bFrameMbsOnlyFlag || ! pcParameters->m_bRefLayerFrameMbsOnlyFlag ) |
---|
269 | { |
---|
270 | if( pcParameters->m_bRefLayerFrameMbsOnlyFlag ) |
---|
271 | { |
---|
272 | iPhaseY = iPhaseY + 4 * iBotField + ( 3 - iFactor ); |
---|
273 | #if ZERO_PHASE |
---|
274 | iRefPhaseY = 2 * iRefPhaseY + 0; |
---|
275 | #else |
---|
276 | iRefPhaseY = 2 * iRefPhaseY + 2; |
---|
277 | #endif |
---|
278 | } |
---|
279 | else |
---|
280 | { |
---|
281 | iPhaseY = iPhaseY + 4 * iBotField; |
---|
282 | iRefPhaseY = iRefPhaseY + 4 * iBotField; |
---|
283 | } |
---|
284 | } |
---|
285 | #if ZERO_PHASE |
---|
286 | int iAddX = ( ( ( iScaledW * ( 0 + iRefPhaseX ) ) << ( iShiftX - 2 ) ) + ( iRefW >> 1 ) ) / iRefW + ( 1 << ( iShiftX - 5 ) ); |
---|
287 | int iAddY = ( ( ( iScaledH * ( 0 + iRefPhaseY ) ) << ( iShiftY - 2 ) ) + ( iRefH >> 1 ) ) / iRefH + ( 1 << ( iShiftY - 5 ) ); |
---|
288 | int iDeltaX = 4 * ( 0 + iPhaseX ) - ( iLeftOffset << 4 ); |
---|
289 | int iDeltaY = 4 * ( 0 + iPhaseY ) - ( iTopOffset << 4 ); |
---|
290 | #else |
---|
291 | int iAddX = ( ( ( iScaledW * ( 2 + iRefPhaseX ) ) << ( iShiftX - 2 ) ) + ( iRefW >> 1 ) ) / iRefW + ( 1 << ( iShiftX - 5 ) ); |
---|
292 | int iAddY = ( ( ( iScaledH * ( 2 + iRefPhaseY ) ) << ( iShiftY - 2 ) ) + ( iRefH >> 1 ) ) / iRefH + ( 1 << ( iShiftY - 5 ) ); |
---|
293 | int iDeltaX = 4 * ( 2 + iPhaseX ) - ( iLeftOffset << 4 ); |
---|
294 | int iDeltaY = 4 * ( 2 + iPhaseY ) - ( iTopOffset << 4 ); |
---|
295 | #endif |
---|
296 | if( ! pcParameters->m_bFrameMbsOnlyFlag || ! pcParameters->m_bRefLayerFrameMbsOnlyFlag ) |
---|
297 | { |
---|
298 | #if ZERO_PHASE |
---|
299 | iAddY = ( ( ( iScaledH * ( 0 + iRefPhaseY ) ) << ( iShiftY - 3 ) ) + ( iRefH >> 1 ) ) / iRefH + ( 1 << ( iShiftY - 5 ) ); |
---|
300 | iDeltaY = 2 * ( 0 + iPhaseY ) - ( iTopOffset << 3 ); |
---|
301 | #else |
---|
302 | iAddY = ( ( ( iScaledH * ( 2 + iRefPhaseY ) ) << ( iShiftY - 3 ) ) + ( iRefH >> 1 ) ) / iRefH + ( 1 << ( iShiftY - 5 ) ); |
---|
303 | iDeltaY = 2 * ( 2 + iPhaseY ) - ( iTopOffset << 3 ); |
---|
304 | #endif |
---|
305 | } |
---|
306 | |
---|
307 | //===== vertical downsampling to generate a field signal from a progressive frame ===== |
---|
308 | if( bVerticalDownsampling ) |
---|
309 | { |
---|
310 | xVertDownsampling( iCurrW, iCurrH, bBotFlag, inputBitDepth, outputBitDepth); |
---|
311 | } |
---|
312 | |
---|
313 | //===== basic downsampling of a frame or field ===== |
---|
314 | xBasicDownsampling( iBaseW, iBaseH, iCurrW, iCurrH, |
---|
315 | iLOffset, iTOffset, iROffset, iBOffset, |
---|
316 | iShiftX, iShiftY, iScaleX, iScaleY, |
---|
317 | iAddX, iAddY, iDeltaX, iDeltaY, |
---|
318 | inputBitDepth, outputBitDepth); |
---|
319 | } |
---|
320 | |
---|
321 | void |
---|
322 | DownConvert::xVertDownsampling( int iBaseW, |
---|
323 | int iBaseH, |
---|
324 | bool bBotFlag, int inputBitDepth, int outputBitDepth) |
---|
325 | { |
---|
326 | int aiVertFilter[13] = { 2, 0, -4, -3, 5, 19, 26, 19, 5, -3, -4, 0, 2 }; |
---|
327 | int iBotField = ( bBotFlag ? 1 : 0 ); |
---|
328 | int iCurrW = iBaseW; |
---|
329 | int iCurrH = iBaseH << 1; |
---|
330 | |
---|
331 | int shift = 6 + (inputBitDepth - outputBitDepth); |
---|
332 | int shift_round = (1 << (shift -1)); |
---|
333 | |
---|
334 | //===== vertical downsampling ===== |
---|
335 | for( int j = 0; j < iCurrW; j++ ) |
---|
336 | { |
---|
337 | int* piSrc = &m_paiImageBuffer[j]; |
---|
338 | for( int i = 0; i < iBaseH; i++ ) |
---|
339 | { |
---|
340 | m_paiTmp1dBuffer[i] = 0; |
---|
341 | for( int k = 0; k < 13; k++ ) |
---|
342 | { |
---|
343 | int m = xClip( 2 * i + iBotField + k - 6, 0, iCurrH - 1 ); |
---|
344 | m_paiTmp1dBuffer[i] += aiVertFilter[k] * piSrc[m*m_iImageStride]; |
---|
345 | } |
---|
346 | m_paiTmp1dBuffer[i] = ( m_paiTmp1dBuffer[i] + shift_round ) >> shift; |
---|
347 | } |
---|
348 | //--- clip and copy back to image buffer --- |
---|
349 | for( int n = 0; n < iBaseH; n++ ) |
---|
350 | { |
---|
351 | piSrc[n*m_iImageStride] = xClip( m_paiTmp1dBuffer[n], 0, ((1<<outputBitDepth)-1) ); |
---|
352 | } |
---|
353 | } |
---|
354 | } |
---|
355 | |
---|
356 | void |
---|
357 | DownConvert::xBasicDownsampling( int iBaseW, int iBaseH, int iCurrW, int iCurrH, |
---|
358 | int iLOffset, int iTOffset, int iROffset, int iBOffset, |
---|
359 | int iShiftX, int iShiftY, int iScaleX, int iScaleY, |
---|
360 | int iAddX, int iAddY, int iDeltaX, int iDeltaY, int inputBitDepth, int outputBitDepth ) |
---|
361 | { |
---|
362 | const int filter16[8][16][12] = |
---|
363 | { |
---|
364 | { // D = 1 |
---|
365 | { 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0 }, |
---|
366 | { 0, 0, 0, 2, -6, 127, 7, -2, 0, 0, 0, 0 }, |
---|
367 | { 0, 0, 0, 3, -12, 125, 16, -5, 1, 0, 0, 0 }, |
---|
368 | { 0, 0, 0, 4, -16, 120, 26, -7, 1, 0, 0, 0 }, |
---|
369 | { 0, 0, 0, 5, -18, 114, 36, -10, 1, 0, 0, 0 }, |
---|
370 | { 0, 0, 0, 5, -20, 107, 46, -12, 2, 0, 0, 0 }, |
---|
371 | { 0, 0, 0, 5, -21, 99, 57, -15, 3, 0, 0, 0 }, |
---|
372 | { 0, 0, 0, 5, -20, 89, 68, -18, 4, 0, 0, 0 }, |
---|
373 | { 0, 0, 0, 4, -19, 79, 79, -19, 4, 0, 0, 0 }, |
---|
374 | { 0, 0, 0, 4, -18, 68, 89, -20, 5, 0, 0, 0 }, |
---|
375 | { 0, 0, 0, 3, -15, 57, 99, -21, 5, 0, 0, 0 }, |
---|
376 | { 0, 0, 0, 2, -12, 46, 107, -20, 5, 0, 0, 0 }, |
---|
377 | { 0, 0, 0, 1, -10, 36, 114, -18, 5, 0, 0, 0 }, |
---|
378 | { 0, 0, 0, 1, -7, 26, 120, -16, 4, 0, 0, 0 }, |
---|
379 | { 0, 0, 0, 1, -5, 16, 125, -12, 3, 0, 0, 0 }, |
---|
380 | { 0, 0, 0, 0, -2, 7, 127, -6, 2, 0, 0, 0 } |
---|
381 | }, |
---|
382 | { // D = 1.5 |
---|
383 | { 0, 2, 0, -14, 33, 86, 33, -14, 0, 2, 0, 0 }, |
---|
384 | { 0, 1, 1, -14, 29, 85, 38, -13, -1, 2, 0, 0 }, |
---|
385 | { 0, 1, 2, -14, 24, 84, 43, -12, -2, 2, 0, 0 }, |
---|
386 | { 0, 1, 2, -13, 19, 83, 48, -11, -3, 2, 0, 0 }, |
---|
387 | { 0, 0, 3, -13, 15, 81, 53, -10, -4, 3, 0, 0 }, |
---|
388 | { 0, 0, 3, -12, 11, 79, 57, -8, -5, 3, 0, 0 }, |
---|
389 | { 0, 0, 3, -11, 7, 76, 62, -5, -7, 3, 0, 0 }, |
---|
390 | { 0, 0, 3, -10, 3, 73, 65, -2, -7, 3, 0, 0 }, |
---|
391 | { 0, 0, 3, -9, 0, 70, 70, 0, -9, 3, 0, 0 }, |
---|
392 | { 0, 0, 3, -7, -2, 65, 73, 3, -10, 3, 0, 0 }, |
---|
393 | { 0, 0, 3, -7, -5, 62, 76, 7, -11, 3, 0, 0 }, |
---|
394 | { 0, 0, 3, -5, -8, 57, 79, 11, -12, 3, 0, 0 }, |
---|
395 | { 0, 0, 3, -4, -10, 53, 81, 15, -13, 3, 0, 0 }, |
---|
396 | { 0, 0, 2, -3, -11, 48, 83, 19, -13, 2, 1, 0 }, |
---|
397 | { 0, 0, 2, -2, -12, 43, 84, 24, -14, 2, 1, 0 }, |
---|
398 | { 0, 0, 2, -1, -13, 38, 85, 29, -14, 1, 1, 0 } |
---|
399 | }, |
---|
400 | { // D = 2 |
---|
401 | { 0, 5, -6, -10, 37, 76, 37, -10, -6, 5, 0, 0}, //0 |
---|
402 | { 0, 5, -4, -11, 33, 76, 40, -9, -7, 5, 0, 0}, //1 |
---|
403 | //{ 0, 5, -3, -12, 28, 75, 44, -7, -8, 5, 1, 0}, //2 |
---|
404 | { -1, 5, -3, -12, 29, 75, 45, -7, -8, 5, 0, 0}, //2 new coefficients in m24499 |
---|
405 | { -1, 4, -2, -13, 25, 75, 48, -5, -9, 5, 1, 0}, //3 |
---|
406 | { -1, 4, -1, -13, 22, 73, 52, -3, -10, 4, 1, 0}, //4 |
---|
407 | { -1, 4, 0, -13, 18, 72, 55, -1, -11, 4, 2, -1}, //5 |
---|
408 | { -1, 4, 1, -13, 14, 70, 59, 2, -12, 3, 2, -1}, //6 |
---|
409 | { -1, 3, 1, -13, 11, 68, 62, 5, -12, 3, 2, -1}, //7 |
---|
410 | { -1, 3, 2, -13, 8, 65, 65, 8, -13, 2, 3, -1}, //8 |
---|
411 | { -1, 2, 3, -12, 5, 62, 68, 11, -13, 1, 3, -1}, //9 |
---|
412 | { -1, 2, 3, -12, 2, 59, 70, 14, -13, 1, 4, -1}, //10 |
---|
413 | { -1, 2, 4, -11, -1, 55, 72, 18, -13, 0, 4, -1}, //11 |
---|
414 | { 0, 1, 4, -10, -3, 52, 73, 22, -13, -1, 4, -1}, //12 |
---|
415 | { 0, 1, 5, -9, -5, 48, 75, 25, -13, -2, 4, -1}, //13 |
---|
416 | //{ 0, 1, 5, -8, -7, 44, 75, 28, -12, -3, 5, 0}, //14 |
---|
417 | { 0, 0, 5, -8, -7, 45, 75, 29, -12, -3, 5, -1} , //14 new coefficients in m24499 |
---|
418 | { 0, 0, 5, -7, -9, 40, 76, 33, -11, -4, 5, 0}, //15 |
---|
419 | }, |
---|
420 | { // D = 2.5 |
---|
421 | { 2, -3, -9, 6, 39, 58, 39, 6, -9, -3, 2, 0}, // 0 |
---|
422 | { 2, -3, -9, 4, 38, 58, 43, 7, -9, -4, 1, 0}, // 1 |
---|
423 | { 2, -2, -9, 2, 35, 58, 44, 9, -8, -4, 1, 0}, // 2 |
---|
424 | { 1, -2, -9, 1, 34, 58, 46, 11, -8, -5, 1, 0}, // 3 |
---|
425 | //{ 1, -1, -8, -1, 31, 57, 48, 13, -8, -5, 1, 0}, // 4 |
---|
426 | { 1, -1, -8, -1, 31, 57, 47, 13, -7, -5, 1, 0}, // 4 new coefficients in m24499 |
---|
427 | { 1, -1, -8, -2, 29, 56, 49, 15, -7, -6, 1, 1}, // 5 |
---|
428 | { 1, 0, -8, -3, 26, 55, 51, 17, -7, -6, 1, 1}, // 6 |
---|
429 | { 1, 0, -7, -4, 24, 54, 52, 19, -6, -7, 1, 1}, // 7 |
---|
430 | { 1, 0, -7, -5, 22, 53, 53, 22, -5, -7, 0, 1}, // 8 |
---|
431 | { 1, 1, -7, -6, 19, 52, 54, 24, -4, -7, 0, 1}, // 9 |
---|
432 | { 1, 1, -6, -7, 17, 51, 55, 26, -3, -8, 0, 1}, // 10 |
---|
433 | { 1, 1, -6, -7, 15, 49, 56, 29, -2, -8, -1, 1}, // 11 |
---|
434 | //{ 0, 1, -5, -8, 13, 48, 57, 31, -1, -8, -1, 1}, // 12 new coefficients in m24499 |
---|
435 | { 0, 1, -5, -7, 13, 47, 57, 31, -1, -8, -1, 1}, // 12 |
---|
436 | { 0, 1, -5, -8, 11, 46, 58, 34, 1, -9, -2, 1}, // 13 |
---|
437 | { 0, 1, -4, -8, 9, 44, 58, 35, 2, -9, -2, 2}, // 14 |
---|
438 | { 0, 1, -4, -9, 7, 43, 58, 38, 4, -9, -3, 2}, // 15 |
---|
439 | }, |
---|
440 | { // D = 3 |
---|
441 | { -2, -7, 0, 17, 35, 43, 35, 17, 0, -7, -5, 2 }, |
---|
442 | { -2, -7, -1, 16, 34, 43, 36, 18, 1, -7, -5, 2 }, |
---|
443 | { -1, -7, -1, 14, 33, 43, 36, 19, 1, -6, -5, 2 }, |
---|
444 | { -1, -7, -2, 13, 32, 42, 37, 20, 3, -6, -5, 2 }, |
---|
445 | { 0, -7, -3, 12, 31, 42, 38, 21, 3, -6, -5, 2 }, |
---|
446 | { 0, -7, -3, 11, 30, 42, 39, 23, 4, -6, -6, 1 }, |
---|
447 | { 0, -7, -4, 10, 29, 42, 40, 24, 5, -6, -6, 1 }, |
---|
448 | { 1, -7, -4, 9, 27, 41, 40, 25, 6, -5, -6, 1 }, |
---|
449 | { 1, -6, -5, 7, 26, 41, 41, 26, 7, -5, -6, 1 }, |
---|
450 | { 1, -6, -5, 6, 25, 40, 41, 27, 9, -4, -7, 1 }, |
---|
451 | { 1, -6, -6, 5, 24, 40, 42, 29, 10, -4, -7, 0 }, |
---|
452 | { 1, -6, -6, 4, 23, 39, 42, 30, 11, -3, -7, 0 }, |
---|
453 | { 2, -5, -6, 3, 21, 38, 42, 31, 12, -3, -7, 0 }, |
---|
454 | { 2, -5, -6, 3, 20, 37, 42, 32, 13, -2, -7, -1 }, |
---|
455 | { 2, -5, -6, 1, 19, 36, 43, 33, 14, -1, -7, -1 }, |
---|
456 | { 2, -5, -7, 1, 18, 36, 43, 34, 16, -1, -7, -2 } |
---|
457 | }, |
---|
458 | { // D = 3.5 |
---|
459 | { -6, -3, 5, 19, 31, 36, 31, 19, 5, -3, -6, 0 }, |
---|
460 | { -6, -4, 4, 18, 31, 37, 32, 20, 6, -3, -6, -1 }, |
---|
461 | { -6, -4, 4, 17, 30, 36, 33, 21, 7, -3, -6, -1 }, |
---|
462 | { -5, -5, 3, 16, 30, 36, 33, 22, 8, -2, -6, -2 }, |
---|
463 | { -5, -5, 2, 15, 29, 36, 34, 23, 9, -2, -6, -2 }, |
---|
464 | { -5, -5, 2, 15, 28, 36, 34, 24, 10, -2, -6, -3 }, |
---|
465 | { -4, -5, 1, 14, 27, 36, 35, 24, 10, -1, -6, -3 }, |
---|
466 | { -4, -5, 0, 13, 26, 35, 35, 25, 11, 0, -5, -3 }, |
---|
467 | { -4, -6, 0, 12, 26, 36, 36, 26, 12, 0, -6, -4 }, |
---|
468 | { -3, -5, 0, 11, 25, 35, 35, 26, 13, 0, -5, -4 }, |
---|
469 | { -3, -6, -1, 10, 24, 35, 36, 27, 14, 1, -5, -4 }, |
---|
470 | { -3, -6, -2, 10, 24, 34, 36, 28, 15, 2, -5, -5 }, |
---|
471 | { -2, -6, -2, 9, 23, 34, 36, 29, 15, 2, -5, -5 }, |
---|
472 | { -2, -6, -2, 8, 22, 33, 36, 30, 16, 3, -5, -5 }, |
---|
473 | { -1, -6, -3, 7, 21, 33, 36, 30, 17, 4, -4, -6 }, |
---|
474 | { -1, -6, -3, 6, 20, 32, 37, 31, 18, 4, -4, -6 } |
---|
475 | }, |
---|
476 | { // D = 4 |
---|
477 | { -9, 0, 9, 20, 28, 32, 28, 20, 9, 0, -9, 0 }, |
---|
478 | { -9, 0, 8, 19, 28, 32, 29, 20, 10, 0, -4, -5 }, |
---|
479 | { -9, -1, 8, 18, 28, 32, 29, 21, 10, 1, -4, -5 }, |
---|
480 | { -9, -1, 7, 18, 27, 32, 30, 22, 11, 1, -4, -6 }, |
---|
481 | { -8, -2, 6, 17, 27, 32, 30, 22, 12, 2, -4, -6 }, |
---|
482 | { -8, -2, 6, 16, 26, 32, 31, 23, 12, 2, -4, -6 }, |
---|
483 | { -8, -2, 5, 16, 26, 31, 31, 23, 13, 3, -3, -7 }, |
---|
484 | { -8, -3, 5, 15, 25, 31, 31, 24, 14, 4, -3, -7 }, |
---|
485 | { -7, -3, 4, 14, 25, 31, 31, 25, 14, 4, -3, -7 }, |
---|
486 | { -7, -3, 4, 14, 24, 31, 31, 25, 15, 5, -3, -8 }, |
---|
487 | { -7, -3, 3, 13, 23, 31, 31, 26, 16, 5, -2, -8 }, |
---|
488 | { -6, -4, 2, 12, 23, 31, 32, 26, 16, 6, -2, -8 }, |
---|
489 | { -6, -4, 2, 12, 22, 30, 32, 27, 17, 6, -2, -8 }, |
---|
490 | { -6, -4, 1, 11, 22, 30, 32, 27, 18, 7, -1, -9 }, |
---|
491 | { -5, -4, 1, 10, 21, 29, 32, 28, 18, 8, -1, -9 }, |
---|
492 | { -5, -4, 0, 10, 20, 29, 32, 28, 19, 8, 0, -9 } |
---|
493 | }, |
---|
494 | { // D = 5.5 |
---|
495 | { -8, 7, 13, 18, 22, 24, 22, 18, 13, 7, 2, -10 }, |
---|
496 | { -8, 7, 13, 18, 22, 23, 22, 19, 13, 7, 2, -10 }, |
---|
497 | { -8, 6, 12, 18, 22, 23, 22, 19, 14, 8, 2, -10 }, |
---|
498 | { -9, 6, 12, 17, 22, 23, 23, 19, 14, 8, 3, -10 }, |
---|
499 | { -9, 6, 12, 17, 21, 23, 23, 19, 14, 9, 3, -10 }, |
---|
500 | { -9, 5, 11, 17, 21, 23, 23, 20, 15, 9, 3, -10 }, |
---|
501 | { -9, 5, 11, 16, 21, 23, 23, 20, 15, 9, 4, -10 }, |
---|
502 | { -9, 5, 10, 16, 21, 23, 23, 20, 15, 10, 4, -10 }, |
---|
503 | { -10, 5, 10, 16, 20, 23, 23, 20, 16, 10, 5, -10 }, |
---|
504 | { -10, 4, 10, 15, 20, 23, 23, 21, 16, 10, 5, -9 }, |
---|
505 | { -10, 4, 9, 15, 20, 23, 23, 21, 16, 11, 5, -9 }, |
---|
506 | { -10, 3, 9, 15, 20, 23, 23, 21, 17, 11, 5, -9 }, |
---|
507 | { -10, 3, 9, 14, 19, 23, 23, 21, 17, 12, 6, -9 }, |
---|
508 | { -10, 3, 8, 14, 19, 23, 23, 22, 17, 12, 6, -9 }, |
---|
509 | { -10, 2, 8, 14, 19, 22, 23, 22, 18, 12, 6, -8 }, |
---|
510 | { -10, 2, 7, 13, 19, 22, 23, 22, 18, 13, 7, -8 } |
---|
511 | } |
---|
512 | }; |
---|
513 | |
---|
514 | //===== determine filter sets ===== |
---|
515 | int iCropW = iCurrW - iLOffset - iROffset; |
---|
516 | int iCropH = iCurrH - iTOffset - iBOffset; |
---|
517 | int iVerFilter = 0; |
---|
518 | int iHorFilter = 0; |
---|
519 | if ( 4 * iCropH > 15 * iBaseH ) iVerFilter = 7; |
---|
520 | else if ( 7 * iCropH > 20 * iBaseH ) iVerFilter = 6; |
---|
521 | else if ( 2 * iCropH > 5 * iBaseH ) iVerFilter = 5; |
---|
522 | else if ( 1 * iCropH > 2 * iBaseH ) iVerFilter = 4; |
---|
523 | else if ( 3 * iCropH > 5 * iBaseH ) iVerFilter = 3; |
---|
524 | else if ( 4 * iCropH > 5 * iBaseH ) iVerFilter = 2; |
---|
525 | else if ( 19 * iCropH > 20 * iBaseH ) iVerFilter = 1; |
---|
526 | if ( 4 * iCropW > 15 * iBaseW ) iHorFilter = 7; |
---|
527 | else if ( 7 * iCropW > 20 * iBaseW ) iHorFilter = 6; |
---|
528 | else if ( 2 * iCropW > 5 * iBaseW ) iHorFilter = 5; |
---|
529 | else if ( 1 * iCropW > 2 * iBaseW ) iHorFilter = 4; |
---|
530 | else if ( 3 * iCropW > 5 * iBaseW ) iHorFilter = 3; |
---|
531 | else if ( 4 * iCropW > 5 * iBaseW ) iHorFilter = 2; |
---|
532 | else if ( 19 * iCropW > 20 * iBaseW ) iHorFilter = 1; |
---|
533 | |
---|
534 | int iShiftXM4 = iShiftX - 4; |
---|
535 | int iShiftYM4 = iShiftY - 4; |
---|
536 | |
---|
537 | int shift = 14 + (inputBitDepth - outputBitDepth); |
---|
538 | int shift_round = (1 << (shift -1)); |
---|
539 | |
---|
540 | //===== horizontal downsampling ===== |
---|
541 | { |
---|
542 | for( int j = 0; j < iCurrH; j++ ) |
---|
543 | { |
---|
544 | int* piSrc = &m_paiImageBuffer[j*m_iImageStride]; |
---|
545 | for( int i = 0; i < iBaseW; i++ ) |
---|
546 | { |
---|
547 | int iRefPos16 = (int)( (unsigned int)( i * iScaleX + iAddX ) >> iShiftXM4 ) - iDeltaX; |
---|
548 | int iPhase = iRefPos16 & 15; |
---|
549 | int iRefPos = iRefPos16 >> 4; |
---|
550 | |
---|
551 | m_paiTmp1dBuffer[i] = 0; |
---|
552 | for( int k = 0; k < 12; k++ ) |
---|
553 | { |
---|
554 | int m = xClip( iRefPos + k - 5, 0, iCurrW - 1 ); |
---|
555 | m_paiTmp1dBuffer[i] += filter16[iHorFilter][iPhase][k] * piSrc[m]; |
---|
556 | } |
---|
557 | } |
---|
558 | //--- copy row back to image buffer --- |
---|
559 | memcpy( piSrc, m_paiTmp1dBuffer, iBaseW*sizeof(int) ); |
---|
560 | } |
---|
561 | } |
---|
562 | |
---|
563 | //===== vertical downsampling ===== |
---|
564 | { |
---|
565 | for( int i = 0; i < iBaseW; i++ ) |
---|
566 | { |
---|
567 | int* piSrc = &m_paiImageBuffer[i]; |
---|
568 | for( int j = 0; j < iBaseH; j++ ) |
---|
569 | { |
---|
570 | int iRefPos16 = (int)( (unsigned int)( j * iScaleY + iAddY ) >> iShiftYM4 ) - iDeltaY; |
---|
571 | int iPhase = iRefPos16 & 15; |
---|
572 | int iRefPos = iRefPos16 >> 4; |
---|
573 | |
---|
574 | m_paiTmp1dBuffer[j] = 0; |
---|
575 | for( int k = 0; k < 12; k++ ) |
---|
576 | { |
---|
577 | int m = xClip( iRefPos + k - 5, 0, iCurrH - 1 ); |
---|
578 | m_paiTmp1dBuffer[j] += filter16[iVerFilter][iPhase][k] * piSrc[m*m_iImageStride]; |
---|
579 | } |
---|
580 | m_paiTmp1dBuffer[j] = ( m_paiTmp1dBuffer[j] + shift_round ) >> shift; |
---|
581 | } |
---|
582 | //--- clip and copy back to image buffer --- |
---|
583 | for( int n = 0; n < iBaseH; n++ ) |
---|
584 | { |
---|
585 | piSrc[n*m_iImageStride] = xClip( m_paiTmp1dBuffer[n], 0, ((1<<outputBitDepth)-1)); |
---|
586 | } |
---|
587 | } |
---|
588 | } |
---|
589 | } |
---|
590 | |
---|
591 | |
---|
592 | |
---|
593 | |
---|