1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (C) 2001-2003 Michael Niedermayer (michaelni@gmx.at)
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * AltiVec optimizations (C) 2004 Romain Dolbeau <romain@dolbeau.org>
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or modify
9cabdff1aSopenharmony_ci * it under the terms of the GNU General Public License as published by
10cabdff1aSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
11cabdff1aSopenharmony_ci * (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16cabdff1aSopenharmony_ci * GNU General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU General Public License
19cabdff1aSopenharmony_ci * along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci/**
24cabdff1aSopenharmony_ci * @file
25cabdff1aSopenharmony_ci * postprocessing.
26cabdff1aSopenharmony_ci */
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci/*
29cabdff1aSopenharmony_ci                        C       MMX     MMX2    3DNow   AltiVec
30cabdff1aSopenharmony_ciisVertDC                Ec      Ec                      Ec
31cabdff1aSopenharmony_ciisVertMinMaxOk          Ec      Ec                      Ec
32cabdff1aSopenharmony_cidoVertLowPass           E               e       e       Ec
33cabdff1aSopenharmony_cidoVertDefFilter         Ec      Ec      e       e       Ec
34cabdff1aSopenharmony_ciisHorizDC               Ec      Ec                      Ec
35cabdff1aSopenharmony_ciisHorizMinMaxOk         a       E                       Ec
36cabdff1aSopenharmony_cidoHorizLowPass          E               e       e       Ec
37cabdff1aSopenharmony_cidoHorizDefFilter        Ec      Ec      e       e       Ec
38cabdff1aSopenharmony_cido_a_deblock            Ec      E       Ec      E
39cabdff1aSopenharmony_cideRing                  E               e       e*      Ecp
40cabdff1aSopenharmony_ciVertical RKAlgo1        E               a       a
41cabdff1aSopenharmony_ciHorizontal RKAlgo1                      a       a
42cabdff1aSopenharmony_ciVertical X1#            a               E       E
43cabdff1aSopenharmony_ciHorizontal X1#          a               E       E
44cabdff1aSopenharmony_ciLinIpolDeinterlace      e               E       E*
45cabdff1aSopenharmony_ciCubicIpolDeinterlace    a               e       e*
46cabdff1aSopenharmony_ciLinBlendDeinterlace     e               E       E*
47cabdff1aSopenharmony_ciMedianDeinterlace#      E       Ec      Ec
48cabdff1aSopenharmony_ciTempDeNoiser#           E               e       e       Ec
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_ci* I do not have a 3DNow! CPU -> it is untested, but no one said it does not work so it seems to work
51cabdff1aSopenharmony_ci# more or less selfinvented filters so the exactness is not too meaningful
52cabdff1aSopenharmony_ciE = Exact implementation
53cabdff1aSopenharmony_cie = almost exact implementation (slightly different rounding,...)
54cabdff1aSopenharmony_cia = alternative / approximate impl
55cabdff1aSopenharmony_cic = checked against the other implementations (-vo md5)
56cabdff1aSopenharmony_cip = partially optimized, still some work to do
57cabdff1aSopenharmony_ci*/
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_ci/*
60cabdff1aSopenharmony_ciTODO:
61cabdff1aSopenharmony_cireduce the time wasted on the mem transfer
62cabdff1aSopenharmony_ciunroll stuff if instructions depend too much on the prior one
63cabdff1aSopenharmony_cimove YScale thing to the end instead of fixing QP
64cabdff1aSopenharmony_ciwrite a faster and higher quality deblocking filter :)
65cabdff1aSopenharmony_cimake the mainloop more flexible (variable number of blocks at once
66cabdff1aSopenharmony_ci        (the if/else stuff per block is slowing things down)
67cabdff1aSopenharmony_cicompare the quality & speed of all filters
68cabdff1aSopenharmony_cisplit this huge file
69cabdff1aSopenharmony_cioptimize c versions
70cabdff1aSopenharmony_citry to unroll inner for(x=0 ... loop to avoid these damn if(x ... checks
71cabdff1aSopenharmony_ci...
72cabdff1aSopenharmony_ci*/
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci//Changelog: use git log
75cabdff1aSopenharmony_ci
76cabdff1aSopenharmony_ci#include "config.h"
77cabdff1aSopenharmony_ci#include "libavutil/avutil.h"
78cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
79cabdff1aSopenharmony_ci#include "libavutil/cpu.h"
80cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
81cabdff1aSopenharmony_ci#include <inttypes.h>
82cabdff1aSopenharmony_ci#include <stdio.h>
83cabdff1aSopenharmony_ci#include <stdlib.h>
84cabdff1aSopenharmony_ci#include <string.h>
85cabdff1aSopenharmony_ci//#undef HAVE_MMXEXT_INLINE
86cabdff1aSopenharmony_ci//#define HAVE_AMD3DNOW_INLINE
87cabdff1aSopenharmony_ci//#undef HAVE_MMX_INLINE
88cabdff1aSopenharmony_ci//#undef ARCH_X86
89cabdff1aSopenharmony_ci//#define DEBUG_BRIGHTNESS
90cabdff1aSopenharmony_ci#include "postprocess.h"
91cabdff1aSopenharmony_ci#include "postprocess_internal.h"
92cabdff1aSopenharmony_ci#include "libavutil/avstring.h"
93cabdff1aSopenharmony_ci#include "libavutil/ppc/util_altivec.h"
94cabdff1aSopenharmony_ci
95cabdff1aSopenharmony_ci#define GET_MODE_BUFFER_SIZE 500
96cabdff1aSopenharmony_ci#define OPTIONS_ARRAY_SIZE 10
97cabdff1aSopenharmony_ci#define BLOCK_SIZE 8
98cabdff1aSopenharmony_ci#define TEMP_STRIDE 8
99cabdff1aSopenharmony_ci//#define NUM_BLOCKS_AT_ONCE 16 //not used yet
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci#if ARCH_X86 && HAVE_INLINE_ASM
102cabdff1aSopenharmony_ciDECLARE_ASM_CONST(8, uint64_t, w05)= 0x0005000500050005LL;
103cabdff1aSopenharmony_ciDECLARE_ASM_CONST(8, uint64_t, w04)= 0x0004000400040004LL;
104cabdff1aSopenharmony_ciDECLARE_ASM_CONST(8, uint64_t, w20)= 0x0020002000200020LL;
105cabdff1aSopenharmony_ciDECLARE_ASM_CONST(8, uint64_t, b00)= 0x0000000000000000LL;
106cabdff1aSopenharmony_ciDECLARE_ASM_CONST(8, uint64_t, b01)= 0x0101010101010101LL;
107cabdff1aSopenharmony_ciDECLARE_ASM_CONST(8, uint64_t, b02)= 0x0202020202020202LL;
108cabdff1aSopenharmony_ciDECLARE_ASM_CONST(8, uint64_t, b08)= 0x0808080808080808LL;
109cabdff1aSopenharmony_ciDECLARE_ASM_CONST(8, uint64_t, b80)= 0x8080808080808080LL;
110cabdff1aSopenharmony_ci#endif
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ciDECLARE_ASM_CONST(8, int, deringThreshold)= 20;
113cabdff1aSopenharmony_ci
114cabdff1aSopenharmony_ci
115cabdff1aSopenharmony_cistatic const struct PPFilter filters[]=
116cabdff1aSopenharmony_ci{
117cabdff1aSopenharmony_ci    {"hb", "hdeblock",              1, 1, 3, H_DEBLOCK},
118cabdff1aSopenharmony_ci    {"vb", "vdeblock",              1, 2, 4, V_DEBLOCK},
119cabdff1aSopenharmony_ci/*  {"hr", "rkhdeblock",            1, 1, 3, H_RK1_FILTER},
120cabdff1aSopenharmony_ci    {"vr", "rkvdeblock",            1, 2, 4, V_RK1_FILTER},*/
121cabdff1aSopenharmony_ci    {"h1", "x1hdeblock",            1, 1, 3, H_X1_FILTER},
122cabdff1aSopenharmony_ci    {"v1", "x1vdeblock",            1, 2, 4, V_X1_FILTER},
123cabdff1aSopenharmony_ci    {"ha", "ahdeblock",             1, 1, 3, H_A_DEBLOCK},
124cabdff1aSopenharmony_ci    {"va", "avdeblock",             1, 2, 4, V_A_DEBLOCK},
125cabdff1aSopenharmony_ci    {"dr", "dering",                1, 5, 6, DERING},
126cabdff1aSopenharmony_ci    {"al", "autolevels",            0, 1, 2, LEVEL_FIX},
127cabdff1aSopenharmony_ci    {"lb", "linblenddeint",         1, 1, 4, LINEAR_BLEND_DEINT_FILTER},
128cabdff1aSopenharmony_ci    {"li", "linipoldeint",          1, 1, 4, LINEAR_IPOL_DEINT_FILTER},
129cabdff1aSopenharmony_ci    {"ci", "cubicipoldeint",        1, 1, 4, CUBIC_IPOL_DEINT_FILTER},
130cabdff1aSopenharmony_ci    {"md", "mediandeint",           1, 1, 4, MEDIAN_DEINT_FILTER},
131cabdff1aSopenharmony_ci    {"fd", "ffmpegdeint",           1, 1, 4, FFMPEG_DEINT_FILTER},
132cabdff1aSopenharmony_ci    {"l5", "lowpass5",              1, 1, 4, LOWPASS5_DEINT_FILTER},
133cabdff1aSopenharmony_ci    {"tn", "tmpnoise",              1, 7, 8, TEMP_NOISE_FILTER},
134cabdff1aSopenharmony_ci    {"fq", "forcequant",            1, 0, 0, FORCE_QUANT},
135cabdff1aSopenharmony_ci    {"be", "bitexact",              1, 0, 0, BITEXACT},
136cabdff1aSopenharmony_ci    {"vi", "visualize",             1, 0, 0, VISUALIZE},
137cabdff1aSopenharmony_ci    {NULL, NULL,0,0,0,0} //End Marker
138cabdff1aSopenharmony_ci};
139cabdff1aSopenharmony_ci
140cabdff1aSopenharmony_cistatic const char * const replaceTable[]=
141cabdff1aSopenharmony_ci{
142cabdff1aSopenharmony_ci    "default",      "hb:a,vb:a,dr:a",
143cabdff1aSopenharmony_ci    "de",           "hb:a,vb:a,dr:a",
144cabdff1aSopenharmony_ci    "fast",         "h1:a,v1:a,dr:a",
145cabdff1aSopenharmony_ci    "fa",           "h1:a,v1:a,dr:a",
146cabdff1aSopenharmony_ci    "ac",           "ha:a:128:7,va:a,dr:a",
147cabdff1aSopenharmony_ci    NULL //End Marker
148cabdff1aSopenharmony_ci};
149cabdff1aSopenharmony_ci
150cabdff1aSopenharmony_ci/* The horizontal functions exist only in C because the MMX
151cabdff1aSopenharmony_ci * code is faster with vertical filters and transposing. */
152cabdff1aSopenharmony_ci
153cabdff1aSopenharmony_ci/**
154cabdff1aSopenharmony_ci * Check if the given 8x8 Block is mostly "flat"
155cabdff1aSopenharmony_ci */
156cabdff1aSopenharmony_cistatic inline int isHorizDC_C(const uint8_t src[], int stride, const PPContext *c)
157cabdff1aSopenharmony_ci{
158cabdff1aSopenharmony_ci    int numEq= 0;
159cabdff1aSopenharmony_ci    int y;
160cabdff1aSopenharmony_ci    const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
161cabdff1aSopenharmony_ci    const int dcThreshold= dcOffset*2 + 1;
162cabdff1aSopenharmony_ci
163cabdff1aSopenharmony_ci    for(y=0; y<BLOCK_SIZE; y++){
164cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[0] - src[1] + dcOffset)) < dcThreshold;
165cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[1] - src[2] + dcOffset)) < dcThreshold;
166cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[2] - src[3] + dcOffset)) < dcThreshold;
167cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[3] - src[4] + dcOffset)) < dcThreshold;
168cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[4] - src[5] + dcOffset)) < dcThreshold;
169cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[5] - src[6] + dcOffset)) < dcThreshold;
170cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[6] - src[7] + dcOffset)) < dcThreshold;
171cabdff1aSopenharmony_ci        src+= stride;
172cabdff1aSopenharmony_ci    }
173cabdff1aSopenharmony_ci    return numEq > c->ppMode.flatnessThreshold;
174cabdff1aSopenharmony_ci}
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_ci/**
177cabdff1aSopenharmony_ci * Check if the middle 8x8 Block in the given 8x16 block is flat
178cabdff1aSopenharmony_ci */
179cabdff1aSopenharmony_cistatic inline int isVertDC_C(const uint8_t src[], int stride, const PPContext *c)
180cabdff1aSopenharmony_ci{
181cabdff1aSopenharmony_ci    int numEq= 0;
182cabdff1aSopenharmony_ci    int y;
183cabdff1aSopenharmony_ci    const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
184cabdff1aSopenharmony_ci    const int dcThreshold= dcOffset*2 + 1;
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci    src+= stride*4; // src points to begin of the 8x8 Block
187cabdff1aSopenharmony_ci    for(y=0; y<BLOCK_SIZE-1; y++){
188cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[0] - src[0+stride] + dcOffset)) < dcThreshold;
189cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[1] - src[1+stride] + dcOffset)) < dcThreshold;
190cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[2] - src[2+stride] + dcOffset)) < dcThreshold;
191cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[3] - src[3+stride] + dcOffset)) < dcThreshold;
192cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[4] - src[4+stride] + dcOffset)) < dcThreshold;
193cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[5] - src[5+stride] + dcOffset)) < dcThreshold;
194cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[6] - src[6+stride] + dcOffset)) < dcThreshold;
195cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[7] - src[7+stride] + dcOffset)) < dcThreshold;
196cabdff1aSopenharmony_ci        src+= stride;
197cabdff1aSopenharmony_ci    }
198cabdff1aSopenharmony_ci    return numEq > c->ppMode.flatnessThreshold;
199cabdff1aSopenharmony_ci}
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_cistatic inline int isHorizMinMaxOk_C(const uint8_t src[], int stride, int QP)
202cabdff1aSopenharmony_ci{
203cabdff1aSopenharmony_ci    int i;
204cabdff1aSopenharmony_ci    for(i=0; i<2; i++){
205cabdff1aSopenharmony_ci        if((unsigned)(src[0] - src[5] + 2*QP) > 4*QP) return 0;
206cabdff1aSopenharmony_ci        src += stride;
207cabdff1aSopenharmony_ci        if((unsigned)(src[2] - src[7] + 2*QP) > 4*QP) return 0;
208cabdff1aSopenharmony_ci        src += stride;
209cabdff1aSopenharmony_ci        if((unsigned)(src[4] - src[1] + 2*QP) > 4*QP) return 0;
210cabdff1aSopenharmony_ci        src += stride;
211cabdff1aSopenharmony_ci        if((unsigned)(src[6] - src[3] + 2*QP) > 4*QP) return 0;
212cabdff1aSopenharmony_ci        src += stride;
213cabdff1aSopenharmony_ci    }
214cabdff1aSopenharmony_ci    return 1;
215cabdff1aSopenharmony_ci}
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_cistatic inline int isVertMinMaxOk_C(const uint8_t src[], int stride, int QP)
218cabdff1aSopenharmony_ci{
219cabdff1aSopenharmony_ci    int x;
220cabdff1aSopenharmony_ci    src+= stride*4;
221cabdff1aSopenharmony_ci    for(x=0; x<BLOCK_SIZE; x+=4){
222cabdff1aSopenharmony_ci        if((unsigned)(src[  x + 0*stride] - src[  x + 5*stride] + 2*QP) > 4*QP) return 0;
223cabdff1aSopenharmony_ci        if((unsigned)(src[1+x + 2*stride] - src[1+x + 7*stride] + 2*QP) > 4*QP) return 0;
224cabdff1aSopenharmony_ci        if((unsigned)(src[2+x + 4*stride] - src[2+x + 1*stride] + 2*QP) > 4*QP) return 0;
225cabdff1aSopenharmony_ci        if((unsigned)(src[3+x + 6*stride] - src[3+x + 3*stride] + 2*QP) > 4*QP) return 0;
226cabdff1aSopenharmony_ci    }
227cabdff1aSopenharmony_ci    return 1;
228cabdff1aSopenharmony_ci}
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_cistatic inline int horizClassify_C(const uint8_t src[], int stride, const PPContext *c)
231cabdff1aSopenharmony_ci{
232cabdff1aSopenharmony_ci    if( isHorizDC_C(src, stride, c) ){
233cabdff1aSopenharmony_ci        return isHorizMinMaxOk_C(src, stride, c->QP);
234cabdff1aSopenharmony_ci    }else{
235cabdff1aSopenharmony_ci        return 2;
236cabdff1aSopenharmony_ci    }
237cabdff1aSopenharmony_ci}
238cabdff1aSopenharmony_ci
239cabdff1aSopenharmony_cistatic inline int vertClassify_C(const uint8_t src[], int stride, const PPContext *c)
240cabdff1aSopenharmony_ci{
241cabdff1aSopenharmony_ci    if( isVertDC_C(src, stride, c) ){
242cabdff1aSopenharmony_ci        return isVertMinMaxOk_C(src, stride, c->QP);
243cabdff1aSopenharmony_ci    }else{
244cabdff1aSopenharmony_ci        return 2;
245cabdff1aSopenharmony_ci    }
246cabdff1aSopenharmony_ci}
247cabdff1aSopenharmony_ci
248cabdff1aSopenharmony_cistatic inline void doHorizDefFilter_C(uint8_t dst[], int stride, const PPContext *c)
249cabdff1aSopenharmony_ci{
250cabdff1aSopenharmony_ci    int y;
251cabdff1aSopenharmony_ci    for(y=0; y<BLOCK_SIZE; y++){
252cabdff1aSopenharmony_ci        const int middleEnergy= 5*(dst[4] - dst[3]) + 2*(dst[2] - dst[5]);
253cabdff1aSopenharmony_ci
254cabdff1aSopenharmony_ci        if(FFABS(middleEnergy) < 8*c->QP){
255cabdff1aSopenharmony_ci            const int q=(dst[3] - dst[4])/2;
256cabdff1aSopenharmony_ci            const int leftEnergy=  5*(dst[2] - dst[1]) + 2*(dst[0] - dst[3]);
257cabdff1aSopenharmony_ci            const int rightEnergy= 5*(dst[6] - dst[5]) + 2*(dst[4] - dst[7]);
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_ci            int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
260cabdff1aSopenharmony_ci            d= FFMAX(d, 0);
261cabdff1aSopenharmony_ci
262cabdff1aSopenharmony_ci            d= (5*d + 32) >> 6;
263cabdff1aSopenharmony_ci            d*= FFSIGN(-middleEnergy);
264cabdff1aSopenharmony_ci
265cabdff1aSopenharmony_ci            if(q>0)
266cabdff1aSopenharmony_ci            {
267cabdff1aSopenharmony_ci                d = FFMAX(d, 0);
268cabdff1aSopenharmony_ci                d = FFMIN(d, q);
269cabdff1aSopenharmony_ci            }
270cabdff1aSopenharmony_ci            else
271cabdff1aSopenharmony_ci            {
272cabdff1aSopenharmony_ci                d = FFMIN(d, 0);
273cabdff1aSopenharmony_ci                d = FFMAX(d, q);
274cabdff1aSopenharmony_ci            }
275cabdff1aSopenharmony_ci
276cabdff1aSopenharmony_ci            dst[3]-= d;
277cabdff1aSopenharmony_ci            dst[4]+= d;
278cabdff1aSopenharmony_ci        }
279cabdff1aSopenharmony_ci        dst+= stride;
280cabdff1aSopenharmony_ci    }
281cabdff1aSopenharmony_ci}
282cabdff1aSopenharmony_ci
283cabdff1aSopenharmony_ci/**
284cabdff1aSopenharmony_ci * Do a horizontal low pass filter on the 10x8 block (dst points to middle 8x8 Block)
285cabdff1aSopenharmony_ci * using the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16 (C version)
286cabdff1aSopenharmony_ci */
287cabdff1aSopenharmony_cistatic inline void doHorizLowPass_C(uint8_t dst[], int stride, const PPContext *c)
288cabdff1aSopenharmony_ci{
289cabdff1aSopenharmony_ci    int y;
290cabdff1aSopenharmony_ci    for(y=0; y<BLOCK_SIZE; y++){
291cabdff1aSopenharmony_ci        const int first= FFABS(dst[-1] - dst[0]) < c->QP ? dst[-1] : dst[0];
292cabdff1aSopenharmony_ci        const int last= FFABS(dst[8] - dst[7]) < c->QP ? dst[8] : dst[7];
293cabdff1aSopenharmony_ci
294cabdff1aSopenharmony_ci        int sums[10];
295cabdff1aSopenharmony_ci        sums[0] = 4*first + dst[0] + dst[1] + dst[2] + 4;
296cabdff1aSopenharmony_ci        sums[1] = sums[0] - first  + dst[3];
297cabdff1aSopenharmony_ci        sums[2] = sums[1] - first  + dst[4];
298cabdff1aSopenharmony_ci        sums[3] = sums[2] - first  + dst[5];
299cabdff1aSopenharmony_ci        sums[4] = sums[3] - first  + dst[6];
300cabdff1aSopenharmony_ci        sums[5] = sums[4] - dst[0] + dst[7];
301cabdff1aSopenharmony_ci        sums[6] = sums[5] - dst[1] + last;
302cabdff1aSopenharmony_ci        sums[7] = sums[6] - dst[2] + last;
303cabdff1aSopenharmony_ci        sums[8] = sums[7] - dst[3] + last;
304cabdff1aSopenharmony_ci        sums[9] = sums[8] - dst[4] + last;
305cabdff1aSopenharmony_ci
306cabdff1aSopenharmony_ci        dst[0]= (sums[0] + sums[2] + 2*dst[0])>>4;
307cabdff1aSopenharmony_ci        dst[1]= (sums[1] + sums[3] + 2*dst[1])>>4;
308cabdff1aSopenharmony_ci        dst[2]= (sums[2] + sums[4] + 2*dst[2])>>4;
309cabdff1aSopenharmony_ci        dst[3]= (sums[3] + sums[5] + 2*dst[3])>>4;
310cabdff1aSopenharmony_ci        dst[4]= (sums[4] + sums[6] + 2*dst[4])>>4;
311cabdff1aSopenharmony_ci        dst[5]= (sums[5] + sums[7] + 2*dst[5])>>4;
312cabdff1aSopenharmony_ci        dst[6]= (sums[6] + sums[8] + 2*dst[6])>>4;
313cabdff1aSopenharmony_ci        dst[7]= (sums[7] + sums[9] + 2*dst[7])>>4;
314cabdff1aSopenharmony_ci
315cabdff1aSopenharmony_ci        dst+= stride;
316cabdff1aSopenharmony_ci    }
317cabdff1aSopenharmony_ci}
318cabdff1aSopenharmony_ci
319cabdff1aSopenharmony_ci/**
320cabdff1aSopenharmony_ci * Experimental Filter 1 (Horizontal)
321cabdff1aSopenharmony_ci * will not damage linear gradients
322cabdff1aSopenharmony_ci * Flat blocks should look like they were passed through the (1,1,2,2,4,2,2,1,1) 9-Tap filter
323cabdff1aSopenharmony_ci * can only smooth blocks at the expected locations (it cannot smooth them if they did move)
324cabdff1aSopenharmony_ci * MMX2 version does correct clipping C version does not
325cabdff1aSopenharmony_ci * not identical with the vertical one
326cabdff1aSopenharmony_ci */
327cabdff1aSopenharmony_cistatic inline void horizX1Filter(uint8_t *src, int stride, int QP)
328cabdff1aSopenharmony_ci{
329cabdff1aSopenharmony_ci    int y;
330cabdff1aSopenharmony_ci    static uint64_t lut[256];
331cabdff1aSopenharmony_ci    if(!lut[255])
332cabdff1aSopenharmony_ci    {
333cabdff1aSopenharmony_ci        int i;
334cabdff1aSopenharmony_ci        for(i=0; i<256; i++)
335cabdff1aSopenharmony_ci        {
336cabdff1aSopenharmony_ci            int v= i < 128 ? 2*i : 2*(i-256);
337cabdff1aSopenharmony_ci/*
338cabdff1aSopenharmony_ci//Simulate 112242211 9-Tap filter
339cabdff1aSopenharmony_ci            uint64_t a= (v/16)  & 0xFF;
340cabdff1aSopenharmony_ci            uint64_t b= (v/8)   & 0xFF;
341cabdff1aSopenharmony_ci            uint64_t c= (v/4)   & 0xFF;
342cabdff1aSopenharmony_ci            uint64_t d= (3*v/8) & 0xFF;
343cabdff1aSopenharmony_ci*/
344cabdff1aSopenharmony_ci//Simulate piecewise linear interpolation
345cabdff1aSopenharmony_ci            uint64_t a= (v/16)   & 0xFF;
346cabdff1aSopenharmony_ci            uint64_t b= (v*3/16) & 0xFF;
347cabdff1aSopenharmony_ci            uint64_t c= (v*5/16) & 0xFF;
348cabdff1aSopenharmony_ci            uint64_t d= (7*v/16) & 0xFF;
349cabdff1aSopenharmony_ci            uint64_t A= (0x100 - a)&0xFF;
350cabdff1aSopenharmony_ci            uint64_t B= (0x100 - b)&0xFF;
351cabdff1aSopenharmony_ci            uint64_t C= (0x100 - c)&0xFF;
352cabdff1aSopenharmony_ci            uint64_t D= (0x100 - c)&0xFF;
353cabdff1aSopenharmony_ci
354cabdff1aSopenharmony_ci            lut[i]   = (a<<56) | (b<<48) | (c<<40) | (d<<32) |
355cabdff1aSopenharmony_ci                       (D<<24) | (C<<16) | (B<<8)  | (A);
356cabdff1aSopenharmony_ci            //lut[i] = (v<<32) | (v<<24);
357cabdff1aSopenharmony_ci        }
358cabdff1aSopenharmony_ci    }
359cabdff1aSopenharmony_ci
360cabdff1aSopenharmony_ci    for(y=0; y<BLOCK_SIZE; y++){
361cabdff1aSopenharmony_ci        int a= src[1] - src[2];
362cabdff1aSopenharmony_ci        int b= src[3] - src[4];
363cabdff1aSopenharmony_ci        int c= src[5] - src[6];
364cabdff1aSopenharmony_ci
365cabdff1aSopenharmony_ci        int d= FFMAX(FFABS(b) - (FFABS(a) + FFABS(c))/2, 0);
366cabdff1aSopenharmony_ci
367cabdff1aSopenharmony_ci        if(d < QP){
368cabdff1aSopenharmony_ci            int v = d * FFSIGN(-b);
369cabdff1aSopenharmony_ci
370cabdff1aSopenharmony_ci            src[1] +=v/8;
371cabdff1aSopenharmony_ci            src[2] +=v/4;
372cabdff1aSopenharmony_ci            src[3] +=3*v/8;
373cabdff1aSopenharmony_ci            src[4] -=3*v/8;
374cabdff1aSopenharmony_ci            src[5] -=v/4;
375cabdff1aSopenharmony_ci            src[6] -=v/8;
376cabdff1aSopenharmony_ci        }
377cabdff1aSopenharmony_ci        src+=stride;
378cabdff1aSopenharmony_ci    }
379cabdff1aSopenharmony_ci}
380cabdff1aSopenharmony_ci
381cabdff1aSopenharmony_ci/**
382cabdff1aSopenharmony_ci * accurate deblock filter
383cabdff1aSopenharmony_ci */
384cabdff1aSopenharmony_cistatic av_always_inline void do_a_deblock_C(uint8_t *src, int step,
385cabdff1aSopenharmony_ci                                            int stride, const PPContext *c, int mode)
386cabdff1aSopenharmony_ci{
387cabdff1aSopenharmony_ci    int y;
388cabdff1aSopenharmony_ci    const int QP= c->QP;
389cabdff1aSopenharmony_ci    const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
390cabdff1aSopenharmony_ci    const int dcThreshold= dcOffset*2 + 1;
391cabdff1aSopenharmony_ci
392cabdff1aSopenharmony_ci    src+= step*4; // src points to begin of the 8x8 Block
393cabdff1aSopenharmony_ci    for(y=0; y<8; y++){
394cabdff1aSopenharmony_ci        int numEq= 0;
395cabdff1aSopenharmony_ci
396cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[-1*step] - src[0*step] + dcOffset)) < dcThreshold;
397cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[ 0*step] - src[1*step] + dcOffset)) < dcThreshold;
398cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[ 1*step] - src[2*step] + dcOffset)) < dcThreshold;
399cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[ 2*step] - src[3*step] + dcOffset)) < dcThreshold;
400cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[ 3*step] - src[4*step] + dcOffset)) < dcThreshold;
401cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[ 4*step] - src[5*step] + dcOffset)) < dcThreshold;
402cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[ 5*step] - src[6*step] + dcOffset)) < dcThreshold;
403cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[ 6*step] - src[7*step] + dcOffset)) < dcThreshold;
404cabdff1aSopenharmony_ci        numEq += ((unsigned)(src[ 7*step] - src[8*step] + dcOffset)) < dcThreshold;
405cabdff1aSopenharmony_ci        if(numEq > c->ppMode.flatnessThreshold){
406cabdff1aSopenharmony_ci            int min, max, x;
407cabdff1aSopenharmony_ci
408cabdff1aSopenharmony_ci            if(src[0] > src[step]){
409cabdff1aSopenharmony_ci                max= src[0];
410cabdff1aSopenharmony_ci                min= src[step];
411cabdff1aSopenharmony_ci            }else{
412cabdff1aSopenharmony_ci                max= src[step];
413cabdff1aSopenharmony_ci                min= src[0];
414cabdff1aSopenharmony_ci            }
415cabdff1aSopenharmony_ci            for(x=2; x<8; x+=2){
416cabdff1aSopenharmony_ci                if(src[x*step] > src[(x+1)*step]){
417cabdff1aSopenharmony_ci                        if(src[x    *step] > max) max= src[ x   *step];
418cabdff1aSopenharmony_ci                        if(src[(x+1)*step] < min) min= src[(x+1)*step];
419cabdff1aSopenharmony_ci                }else{
420cabdff1aSopenharmony_ci                        if(src[(x+1)*step] > max) max= src[(x+1)*step];
421cabdff1aSopenharmony_ci                        if(src[ x   *step] < min) min= src[ x   *step];
422cabdff1aSopenharmony_ci                }
423cabdff1aSopenharmony_ci            }
424cabdff1aSopenharmony_ci            if(max-min < 2*QP){
425cabdff1aSopenharmony_ci                const int first= FFABS(src[-1*step] - src[0]) < QP ? src[-1*step] : src[0];
426cabdff1aSopenharmony_ci                const int last= FFABS(src[8*step] - src[7*step]) < QP ? src[8*step] : src[7*step];
427cabdff1aSopenharmony_ci
428cabdff1aSopenharmony_ci                int sums[10];
429cabdff1aSopenharmony_ci                sums[0] = 4*first + src[0*step] + src[1*step] + src[2*step] + 4;
430cabdff1aSopenharmony_ci                sums[1] = sums[0] - first       + src[3*step];
431cabdff1aSopenharmony_ci                sums[2] = sums[1] - first       + src[4*step];
432cabdff1aSopenharmony_ci                sums[3] = sums[2] - first       + src[5*step];
433cabdff1aSopenharmony_ci                sums[4] = sums[3] - first       + src[6*step];
434cabdff1aSopenharmony_ci                sums[5] = sums[4] - src[0*step] + src[7*step];
435cabdff1aSopenharmony_ci                sums[6] = sums[5] - src[1*step] + last;
436cabdff1aSopenharmony_ci                sums[7] = sums[6] - src[2*step] + last;
437cabdff1aSopenharmony_ci                sums[8] = sums[7] - src[3*step] + last;
438cabdff1aSopenharmony_ci                sums[9] = sums[8] - src[4*step] + last;
439cabdff1aSopenharmony_ci
440cabdff1aSopenharmony_ci                if (mode & VISUALIZE) {
441cabdff1aSopenharmony_ci                    src[0*step] =
442cabdff1aSopenharmony_ci                    src[1*step] =
443cabdff1aSopenharmony_ci                    src[2*step] =
444cabdff1aSopenharmony_ci                    src[3*step] =
445cabdff1aSopenharmony_ci                    src[4*step] =
446cabdff1aSopenharmony_ci                    src[5*step] =
447cabdff1aSopenharmony_ci                    src[6*step] =
448cabdff1aSopenharmony_ci                    src[7*step] = 128;
449cabdff1aSopenharmony_ci                }
450cabdff1aSopenharmony_ci                src[0*step]= (sums[0] + sums[2] + 2*src[0*step])>>4;
451cabdff1aSopenharmony_ci                src[1*step]= (sums[1] + sums[3] + 2*src[1*step])>>4;
452cabdff1aSopenharmony_ci                src[2*step]= (sums[2] + sums[4] + 2*src[2*step])>>4;
453cabdff1aSopenharmony_ci                src[3*step]= (sums[3] + sums[5] + 2*src[3*step])>>4;
454cabdff1aSopenharmony_ci                src[4*step]= (sums[4] + sums[6] + 2*src[4*step])>>4;
455cabdff1aSopenharmony_ci                src[5*step]= (sums[5] + sums[7] + 2*src[5*step])>>4;
456cabdff1aSopenharmony_ci                src[6*step]= (sums[6] + sums[8] + 2*src[6*step])>>4;
457cabdff1aSopenharmony_ci                src[7*step]= (sums[7] + sums[9] + 2*src[7*step])>>4;
458cabdff1aSopenharmony_ci            }
459cabdff1aSopenharmony_ci        }else{
460cabdff1aSopenharmony_ci            const int middleEnergy= 5*(src[4*step] - src[3*step]) + 2*(src[2*step] - src[5*step]);
461cabdff1aSopenharmony_ci
462cabdff1aSopenharmony_ci            if(FFABS(middleEnergy) < 8*QP){
463cabdff1aSopenharmony_ci                const int q=(src[3*step] - src[4*step])/2;
464cabdff1aSopenharmony_ci                const int leftEnergy=  5*(src[2*step] - src[1*step]) + 2*(src[0*step] - src[3*step]);
465cabdff1aSopenharmony_ci                const int rightEnergy= 5*(src[6*step] - src[5*step]) + 2*(src[4*step] - src[7*step]);
466cabdff1aSopenharmony_ci
467cabdff1aSopenharmony_ci                int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
468cabdff1aSopenharmony_ci                d= FFMAX(d, 0);
469cabdff1aSopenharmony_ci
470cabdff1aSopenharmony_ci                d= (5*d + 32) >> 6;
471cabdff1aSopenharmony_ci                d*= FFSIGN(-middleEnergy);
472cabdff1aSopenharmony_ci
473cabdff1aSopenharmony_ci                if(q>0){
474cabdff1aSopenharmony_ci                    d = FFMAX(d, 0);
475cabdff1aSopenharmony_ci                    d = FFMIN(d, q);
476cabdff1aSopenharmony_ci                }else{
477cabdff1aSopenharmony_ci                    d = FFMIN(d, 0);
478cabdff1aSopenharmony_ci                    d = FFMAX(d, q);
479cabdff1aSopenharmony_ci                }
480cabdff1aSopenharmony_ci
481cabdff1aSopenharmony_ci                if ((mode & VISUALIZE) && d) {
482cabdff1aSopenharmony_ci                    d= (d < 0) ? 32 : -32;
483cabdff1aSopenharmony_ci                    src[3*step]= av_clip_uint8(src[3*step] - d);
484cabdff1aSopenharmony_ci                    src[4*step]= av_clip_uint8(src[4*step] + d);
485cabdff1aSopenharmony_ci                    d = 0;
486cabdff1aSopenharmony_ci                }
487cabdff1aSopenharmony_ci
488cabdff1aSopenharmony_ci                src[3*step]-= d;
489cabdff1aSopenharmony_ci                src[4*step]+= d;
490cabdff1aSopenharmony_ci            }
491cabdff1aSopenharmony_ci        }
492cabdff1aSopenharmony_ci
493cabdff1aSopenharmony_ci        src += stride;
494cabdff1aSopenharmony_ci    }
495cabdff1aSopenharmony_ci}
496cabdff1aSopenharmony_ci
497cabdff1aSopenharmony_ci//Note: we have C, MMX, MMX2, 3DNOW version there is no 3DNOW+MMX2 one
498cabdff1aSopenharmony_ci//Plain C versions
499cabdff1aSopenharmony_ci//we always compile C for testing which needs bitexactness
500cabdff1aSopenharmony_ci#define TEMPLATE_PP_C 1
501cabdff1aSopenharmony_ci#include "postprocess_template.c"
502cabdff1aSopenharmony_ci
503cabdff1aSopenharmony_ci#if HAVE_ALTIVEC
504cabdff1aSopenharmony_ci#   define TEMPLATE_PP_ALTIVEC 1
505cabdff1aSopenharmony_ci#   include "postprocess_altivec_template.c"
506cabdff1aSopenharmony_ci#   include "postprocess_template.c"
507cabdff1aSopenharmony_ci#endif
508cabdff1aSopenharmony_ci
509cabdff1aSopenharmony_ci#if ARCH_X86 && HAVE_INLINE_ASM
510cabdff1aSopenharmony_ci#    if CONFIG_RUNTIME_CPUDETECT
511cabdff1aSopenharmony_ci#        define TEMPLATE_PP_MMX 1
512cabdff1aSopenharmony_ci#        include "postprocess_template.c"
513cabdff1aSopenharmony_ci#        define TEMPLATE_PP_MMXEXT 1
514cabdff1aSopenharmony_ci#        include "postprocess_template.c"
515cabdff1aSopenharmony_ci#        define TEMPLATE_PP_3DNOW 1
516cabdff1aSopenharmony_ci#        include "postprocess_template.c"
517cabdff1aSopenharmony_ci#        define TEMPLATE_PP_SSE2 1
518cabdff1aSopenharmony_ci#        include "postprocess_template.c"
519cabdff1aSopenharmony_ci#    else
520cabdff1aSopenharmony_ci#        if HAVE_SSE2_INLINE
521cabdff1aSopenharmony_ci#            define TEMPLATE_PP_SSE2 1
522cabdff1aSopenharmony_ci#            include "postprocess_template.c"
523cabdff1aSopenharmony_ci#        elif HAVE_MMXEXT_INLINE
524cabdff1aSopenharmony_ci#            define TEMPLATE_PP_MMXEXT 1
525cabdff1aSopenharmony_ci#            include "postprocess_template.c"
526cabdff1aSopenharmony_ci#        elif HAVE_AMD3DNOW_INLINE
527cabdff1aSopenharmony_ci#            define TEMPLATE_PP_3DNOW 1
528cabdff1aSopenharmony_ci#            include "postprocess_template.c"
529cabdff1aSopenharmony_ci#        elif HAVE_MMX_INLINE
530cabdff1aSopenharmony_ci#            define TEMPLATE_PP_MMX 1
531cabdff1aSopenharmony_ci#            include "postprocess_template.c"
532cabdff1aSopenharmony_ci#        endif
533cabdff1aSopenharmony_ci#    endif
534cabdff1aSopenharmony_ci#endif
535cabdff1aSopenharmony_ci
536cabdff1aSopenharmony_citypedef void (*pp_fn)(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
537cabdff1aSopenharmony_ci                      const int8_t QPs[], int QPStride, int isColor, PPContext *c2);
538cabdff1aSopenharmony_ci
539cabdff1aSopenharmony_cistatic inline void postProcess(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
540cabdff1aSopenharmony_ci        const int8_t QPs[], int QPStride, int isColor, pp_mode *vm, pp_context *vc)
541cabdff1aSopenharmony_ci{
542cabdff1aSopenharmony_ci    pp_fn pp = postProcess_C;
543cabdff1aSopenharmony_ci    PPContext *c= (PPContext *)vc;
544cabdff1aSopenharmony_ci    PPMode *ppMode= (PPMode *)vm;
545cabdff1aSopenharmony_ci    c->ppMode= *ppMode; //FIXME
546cabdff1aSopenharmony_ci
547cabdff1aSopenharmony_ci    if (!(ppMode->lumMode & BITEXACT)) {
548cabdff1aSopenharmony_ci#if CONFIG_RUNTIME_CPUDETECT
549cabdff1aSopenharmony_ci#if ARCH_X86 && HAVE_INLINE_ASM
550cabdff1aSopenharmony_ci        // ordered per speed fastest first
551cabdff1aSopenharmony_ci        if      (c->cpuCaps & AV_CPU_FLAG_SSE2)     pp = postProcess_SSE2;
552cabdff1aSopenharmony_ci        else if (c->cpuCaps & AV_CPU_FLAG_MMXEXT)   pp = postProcess_MMX2;
553cabdff1aSopenharmony_ci        else if (c->cpuCaps & AV_CPU_FLAG_3DNOW)    pp = postProcess_3DNow;
554cabdff1aSopenharmony_ci        else if (c->cpuCaps & AV_CPU_FLAG_MMX)      pp = postProcess_MMX;
555cabdff1aSopenharmony_ci#elif HAVE_ALTIVEC
556cabdff1aSopenharmony_ci        if      (c->cpuCaps & AV_CPU_FLAG_ALTIVEC)  pp = postProcess_altivec;
557cabdff1aSopenharmony_ci#endif
558cabdff1aSopenharmony_ci#else /* CONFIG_RUNTIME_CPUDETECT */
559cabdff1aSopenharmony_ci#if     HAVE_SSE2_INLINE
560cabdff1aSopenharmony_ci        pp = postProcess_SSE2;
561cabdff1aSopenharmony_ci#elif   HAVE_MMXEXT_INLINE
562cabdff1aSopenharmony_ci        pp = postProcess_MMX2;
563cabdff1aSopenharmony_ci#elif HAVE_AMD3DNOW_INLINE
564cabdff1aSopenharmony_ci        pp = postProcess_3DNow;
565cabdff1aSopenharmony_ci#elif HAVE_MMX_INLINE
566cabdff1aSopenharmony_ci        pp = postProcess_MMX;
567cabdff1aSopenharmony_ci#elif HAVE_ALTIVEC
568cabdff1aSopenharmony_ci        pp = postProcess_altivec;
569cabdff1aSopenharmony_ci#endif
570cabdff1aSopenharmony_ci#endif /* !CONFIG_RUNTIME_CPUDETECT */
571cabdff1aSopenharmony_ci    }
572cabdff1aSopenharmony_ci
573cabdff1aSopenharmony_ci    pp(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
574cabdff1aSopenharmony_ci}
575cabdff1aSopenharmony_ci
576cabdff1aSopenharmony_ci/* -pp Command line Help
577cabdff1aSopenharmony_ci*/
578cabdff1aSopenharmony_ciconst char pp_help[] =
579cabdff1aSopenharmony_ci"Available postprocessing filters:\n"
580cabdff1aSopenharmony_ci"Filters                        Options\n"
581cabdff1aSopenharmony_ci"short  long name       short   long option     Description\n"
582cabdff1aSopenharmony_ci"*      *               a       autoq           CPU power dependent enabler\n"
583cabdff1aSopenharmony_ci"                       c       chrom           chrominance filtering enabled\n"
584cabdff1aSopenharmony_ci"                       y       nochrom         chrominance filtering disabled\n"
585cabdff1aSopenharmony_ci"                       n       noluma          luma filtering disabled\n"
586cabdff1aSopenharmony_ci"hb     hdeblock        (2 threshold)           horizontal deblocking filter\n"
587cabdff1aSopenharmony_ci"       1. difference factor: default=32, higher -> more deblocking\n"
588cabdff1aSopenharmony_ci"       2. flatness threshold: default=39, lower -> more deblocking\n"
589cabdff1aSopenharmony_ci"                       the h & v deblocking filters share these\n"
590cabdff1aSopenharmony_ci"                       so you can't set different thresholds for h / v\n"
591cabdff1aSopenharmony_ci"vb     vdeblock        (2 threshold)           vertical deblocking filter\n"
592cabdff1aSopenharmony_ci"ha     hadeblock       (2 threshold)           horizontal deblocking filter\n"
593cabdff1aSopenharmony_ci"va     vadeblock       (2 threshold)           vertical deblocking filter\n"
594cabdff1aSopenharmony_ci"h1     x1hdeblock                              experimental h deblock filter 1\n"
595cabdff1aSopenharmony_ci"v1     x1vdeblock                              experimental v deblock filter 1\n"
596cabdff1aSopenharmony_ci"dr     dering                                  deringing filter\n"
597cabdff1aSopenharmony_ci"al     autolevels                              automatic brightness / contrast\n"
598cabdff1aSopenharmony_ci"                       f        fullyrange     stretch luminance to (0..255)\n"
599cabdff1aSopenharmony_ci"lb     linblenddeint                           linear blend deinterlacer\n"
600cabdff1aSopenharmony_ci"li     linipoldeint                            linear interpolating deinterlace\n"
601cabdff1aSopenharmony_ci"ci     cubicipoldeint                          cubic interpolating deinterlacer\n"
602cabdff1aSopenharmony_ci"md     mediandeint                             median deinterlacer\n"
603cabdff1aSopenharmony_ci"fd     ffmpegdeint                             ffmpeg deinterlacer\n"
604cabdff1aSopenharmony_ci"l5     lowpass5                                FIR lowpass deinterlacer\n"
605cabdff1aSopenharmony_ci"de     default                                 hb:a,vb:a,dr:a\n"
606cabdff1aSopenharmony_ci"fa     fast                                    h1:a,v1:a,dr:a\n"
607cabdff1aSopenharmony_ci"ac                                             ha:a:128:7,va:a,dr:a\n"
608cabdff1aSopenharmony_ci"tn     tmpnoise        (3 threshold)           temporal noise reducer\n"
609cabdff1aSopenharmony_ci"                     1. <= 2. <= 3.            larger -> stronger filtering\n"
610cabdff1aSopenharmony_ci"fq     forceQuant      <quantizer>             force quantizer\n"
611cabdff1aSopenharmony_ci"Usage:\n"
612cabdff1aSopenharmony_ci"<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n"
613cabdff1aSopenharmony_ci"long form example:\n"
614cabdff1aSopenharmony_ci"vdeblock:autoq/hdeblock:autoq/linblenddeint    default,-vdeblock\n"
615cabdff1aSopenharmony_ci"short form example:\n"
616cabdff1aSopenharmony_ci"vb:a/hb:a/lb                                   de,-vb\n"
617cabdff1aSopenharmony_ci"more examples:\n"
618cabdff1aSopenharmony_ci"tn:64:128:256\n"
619cabdff1aSopenharmony_ci"\n"
620cabdff1aSopenharmony_ci;
621cabdff1aSopenharmony_ci
622cabdff1aSopenharmony_cipp_mode *pp_get_mode_by_name_and_quality(const char *name, int quality)
623cabdff1aSopenharmony_ci{
624cabdff1aSopenharmony_ci    char temp[GET_MODE_BUFFER_SIZE];
625cabdff1aSopenharmony_ci    char *p= temp;
626cabdff1aSopenharmony_ci    static const char filterDelimiters[] = ",/";
627cabdff1aSopenharmony_ci    static const char optionDelimiters[] = ":|";
628cabdff1aSopenharmony_ci    struct PPMode *ppMode;
629cabdff1aSopenharmony_ci    char *filterToken;
630cabdff1aSopenharmony_ci
631cabdff1aSopenharmony_ci    if (!name)  {
632cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "pp: Missing argument\n");
633cabdff1aSopenharmony_ci        return NULL;
634cabdff1aSopenharmony_ci    }
635cabdff1aSopenharmony_ci
636cabdff1aSopenharmony_ci    if (!strcmp(name, "help")) {
637cabdff1aSopenharmony_ci        const char *p;
638cabdff1aSopenharmony_ci        for (p = pp_help; strchr(p, '\n'); p = strchr(p, '\n') + 1) {
639cabdff1aSopenharmony_ci            av_strlcpy(temp, p, FFMIN(sizeof(temp), strchr(p, '\n') - p + 2));
640cabdff1aSopenharmony_ci            av_log(NULL, AV_LOG_INFO, "%s", temp);
641cabdff1aSopenharmony_ci        }
642cabdff1aSopenharmony_ci        return NULL;
643cabdff1aSopenharmony_ci    }
644cabdff1aSopenharmony_ci
645cabdff1aSopenharmony_ci    ppMode= av_malloc(sizeof(PPMode));
646cabdff1aSopenharmony_ci    if (!ppMode)
647cabdff1aSopenharmony_ci        return NULL;
648cabdff1aSopenharmony_ci
649cabdff1aSopenharmony_ci    ppMode->lumMode= 0;
650cabdff1aSopenharmony_ci    ppMode->chromMode= 0;
651cabdff1aSopenharmony_ci    ppMode->maxTmpNoise[0]= 700;
652cabdff1aSopenharmony_ci    ppMode->maxTmpNoise[1]= 1500;
653cabdff1aSopenharmony_ci    ppMode->maxTmpNoise[2]= 3000;
654cabdff1aSopenharmony_ci    ppMode->maxAllowedY= 234;
655cabdff1aSopenharmony_ci    ppMode->minAllowedY= 16;
656cabdff1aSopenharmony_ci    ppMode->baseDcDiff= 256/8;
657cabdff1aSopenharmony_ci    ppMode->flatnessThreshold= 56-16-1;
658cabdff1aSopenharmony_ci    ppMode->maxClippedThreshold= (AVRational){1,100};
659cabdff1aSopenharmony_ci    ppMode->error=0;
660cabdff1aSopenharmony_ci
661cabdff1aSopenharmony_ci    memset(temp, 0, GET_MODE_BUFFER_SIZE);
662cabdff1aSopenharmony_ci    av_strlcpy(temp, name, GET_MODE_BUFFER_SIZE - 1);
663cabdff1aSopenharmony_ci
664cabdff1aSopenharmony_ci    av_log(NULL, AV_LOG_DEBUG, "pp: %s\n", name);
665cabdff1aSopenharmony_ci
666cabdff1aSopenharmony_ci    for(;;){
667cabdff1aSopenharmony_ci        const char *filterName;
668cabdff1aSopenharmony_ci        int q= 1000000; //PP_QUALITY_MAX;
669cabdff1aSopenharmony_ci        int chrom=-1;
670cabdff1aSopenharmony_ci        int luma=-1;
671cabdff1aSopenharmony_ci        const char *option;
672cabdff1aSopenharmony_ci        const char *options[OPTIONS_ARRAY_SIZE];
673cabdff1aSopenharmony_ci        int i;
674cabdff1aSopenharmony_ci        int filterNameOk=0;
675cabdff1aSopenharmony_ci        int numOfUnknownOptions=0;
676cabdff1aSopenharmony_ci        int enable=1; //does the user want us to enabled or disabled the filter
677cabdff1aSopenharmony_ci        char *tokstate;
678cabdff1aSopenharmony_ci
679cabdff1aSopenharmony_ci        filterToken= av_strtok(p, filterDelimiters, &tokstate);
680cabdff1aSopenharmony_ci        if(!filterToken) break;
681cabdff1aSopenharmony_ci        p+= strlen(filterToken) + 1; // p points to next filterToken
682cabdff1aSopenharmony_ci        filterName= av_strtok(filterToken, optionDelimiters, &tokstate);
683cabdff1aSopenharmony_ci        if (!filterName) {
684cabdff1aSopenharmony_ci            ppMode->error++;
685cabdff1aSopenharmony_ci            break;
686cabdff1aSopenharmony_ci        }
687cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_DEBUG, "pp: %s::%s\n", filterToken, filterName);
688cabdff1aSopenharmony_ci
689cabdff1aSopenharmony_ci        if(*filterName == '-'){
690cabdff1aSopenharmony_ci            enable=0;
691cabdff1aSopenharmony_ci            filterName++;
692cabdff1aSopenharmony_ci        }
693cabdff1aSopenharmony_ci
694cabdff1aSopenharmony_ci        for(;;){ //for all options
695cabdff1aSopenharmony_ci            option= av_strtok(NULL, optionDelimiters, &tokstate);
696cabdff1aSopenharmony_ci            if(!option) break;
697cabdff1aSopenharmony_ci
698cabdff1aSopenharmony_ci            av_log(NULL, AV_LOG_DEBUG, "pp: option: %s\n", option);
699cabdff1aSopenharmony_ci            if(!strcmp("autoq", option) || !strcmp("a", option)) q= quality;
700cabdff1aSopenharmony_ci            else if(!strcmp("nochrom", option) || !strcmp("y", option)) chrom=0;
701cabdff1aSopenharmony_ci            else if(!strcmp("chrom", option) || !strcmp("c", option)) chrom=1;
702cabdff1aSopenharmony_ci            else if(!strcmp("noluma", option) || !strcmp("n", option)) luma=0;
703cabdff1aSopenharmony_ci            else{
704cabdff1aSopenharmony_ci                options[numOfUnknownOptions] = option;
705cabdff1aSopenharmony_ci                numOfUnknownOptions++;
706cabdff1aSopenharmony_ci            }
707cabdff1aSopenharmony_ci            if(numOfUnknownOptions >= OPTIONS_ARRAY_SIZE-1) break;
708cabdff1aSopenharmony_ci        }
709cabdff1aSopenharmony_ci        options[numOfUnknownOptions] = NULL;
710cabdff1aSopenharmony_ci
711cabdff1aSopenharmony_ci        /* replace stuff from the replace Table */
712cabdff1aSopenharmony_ci        for(i=0; replaceTable[2*i]; i++){
713cabdff1aSopenharmony_ci            if(!strcmp(replaceTable[2*i], filterName)){
714cabdff1aSopenharmony_ci                size_t newlen = strlen(replaceTable[2*i + 1]);
715cabdff1aSopenharmony_ci                int plen;
716cabdff1aSopenharmony_ci                int spaceLeft;
717cabdff1aSopenharmony_ci
718cabdff1aSopenharmony_ci                p--, *p=',';
719cabdff1aSopenharmony_ci
720cabdff1aSopenharmony_ci                plen= strlen(p);
721cabdff1aSopenharmony_ci                spaceLeft= p - temp + plen;
722cabdff1aSopenharmony_ci                if(spaceLeft + newlen  >= GET_MODE_BUFFER_SIZE - 1){
723cabdff1aSopenharmony_ci                    ppMode->error++;
724cabdff1aSopenharmony_ci                    break;
725cabdff1aSopenharmony_ci                }
726cabdff1aSopenharmony_ci                memmove(p + newlen, p, plen+1);
727cabdff1aSopenharmony_ci                memcpy(p, replaceTable[2*i + 1], newlen);
728cabdff1aSopenharmony_ci                filterNameOk=1;
729cabdff1aSopenharmony_ci            }
730cabdff1aSopenharmony_ci        }
731cabdff1aSopenharmony_ci
732cabdff1aSopenharmony_ci        for(i=0; filters[i].shortName; i++){
733cabdff1aSopenharmony_ci            if(   !strcmp(filters[i].longName, filterName)
734cabdff1aSopenharmony_ci               || !strcmp(filters[i].shortName, filterName)){
735cabdff1aSopenharmony_ci                ppMode->lumMode &= ~filters[i].mask;
736cabdff1aSopenharmony_ci                ppMode->chromMode &= ~filters[i].mask;
737cabdff1aSopenharmony_ci
738cabdff1aSopenharmony_ci                filterNameOk=1;
739cabdff1aSopenharmony_ci                if(!enable) break; // user wants to disable it
740cabdff1aSopenharmony_ci
741cabdff1aSopenharmony_ci                if(q >= filters[i].minLumQuality && luma)
742cabdff1aSopenharmony_ci                    ppMode->lumMode|= filters[i].mask;
743cabdff1aSopenharmony_ci                if(chrom==1 || (chrom==-1 && filters[i].chromDefault))
744cabdff1aSopenharmony_ci                    if(q >= filters[i].minChromQuality)
745cabdff1aSopenharmony_ci                            ppMode->chromMode|= filters[i].mask;
746cabdff1aSopenharmony_ci
747cabdff1aSopenharmony_ci                if(filters[i].mask == LEVEL_FIX){
748cabdff1aSopenharmony_ci                    int o;
749cabdff1aSopenharmony_ci                    ppMode->minAllowedY= 16;
750cabdff1aSopenharmony_ci                    ppMode->maxAllowedY= 234;
751cabdff1aSopenharmony_ci                    for(o=0; options[o]; o++){
752cabdff1aSopenharmony_ci                        if(  !strcmp(options[o],"fullyrange")
753cabdff1aSopenharmony_ci                           ||!strcmp(options[o],"f")){
754cabdff1aSopenharmony_ci                            ppMode->minAllowedY= 0;
755cabdff1aSopenharmony_ci                            ppMode->maxAllowedY= 255;
756cabdff1aSopenharmony_ci                            numOfUnknownOptions--;
757cabdff1aSopenharmony_ci                        }
758cabdff1aSopenharmony_ci                    }
759cabdff1aSopenharmony_ci                }
760cabdff1aSopenharmony_ci                else if(filters[i].mask == TEMP_NOISE_FILTER)
761cabdff1aSopenharmony_ci                {
762cabdff1aSopenharmony_ci                    int o;
763cabdff1aSopenharmony_ci                    int numOfNoises=0;
764cabdff1aSopenharmony_ci
765cabdff1aSopenharmony_ci                    for(o=0; options[o]; o++){
766cabdff1aSopenharmony_ci                        char *tail;
767cabdff1aSopenharmony_ci                        ppMode->maxTmpNoise[numOfNoises]=
768cabdff1aSopenharmony_ci                            strtol(options[o], &tail, 0);
769cabdff1aSopenharmony_ci                        if(tail!=options[o]){
770cabdff1aSopenharmony_ci                            numOfNoises++;
771cabdff1aSopenharmony_ci                            numOfUnknownOptions--;
772cabdff1aSopenharmony_ci                            if(numOfNoises >= 3) break;
773cabdff1aSopenharmony_ci                        }
774cabdff1aSopenharmony_ci                    }
775cabdff1aSopenharmony_ci                }
776cabdff1aSopenharmony_ci                else if(filters[i].mask == V_DEBLOCK   || filters[i].mask == H_DEBLOCK
777cabdff1aSopenharmony_ci                     || filters[i].mask == V_A_DEBLOCK || filters[i].mask == H_A_DEBLOCK){
778cabdff1aSopenharmony_ci                    int o;
779cabdff1aSopenharmony_ci
780cabdff1aSopenharmony_ci                    for(o=0; options[o] && o<2; o++){
781cabdff1aSopenharmony_ci                        char *tail;
782cabdff1aSopenharmony_ci                        int val= strtol(options[o], &tail, 0);
783cabdff1aSopenharmony_ci                        if(tail==options[o]) break;
784cabdff1aSopenharmony_ci
785cabdff1aSopenharmony_ci                        numOfUnknownOptions--;
786cabdff1aSopenharmony_ci                        if(o==0) ppMode->baseDcDiff= val;
787cabdff1aSopenharmony_ci                        else ppMode->flatnessThreshold= val;
788cabdff1aSopenharmony_ci                    }
789cabdff1aSopenharmony_ci                }
790cabdff1aSopenharmony_ci                else if(filters[i].mask == FORCE_QUANT){
791cabdff1aSopenharmony_ci                    int o;
792cabdff1aSopenharmony_ci                    ppMode->forcedQuant= 15;
793cabdff1aSopenharmony_ci
794cabdff1aSopenharmony_ci                    for(o=0; options[o] && o<1; o++){
795cabdff1aSopenharmony_ci                        char *tail;
796cabdff1aSopenharmony_ci                        int val= strtol(options[o], &tail, 0);
797cabdff1aSopenharmony_ci                        if(tail==options[o]) break;
798cabdff1aSopenharmony_ci
799cabdff1aSopenharmony_ci                        numOfUnknownOptions--;
800cabdff1aSopenharmony_ci                        ppMode->forcedQuant= val;
801cabdff1aSopenharmony_ci                    }
802cabdff1aSopenharmony_ci                }
803cabdff1aSopenharmony_ci            }
804cabdff1aSopenharmony_ci        }
805cabdff1aSopenharmony_ci        if(!filterNameOk) ppMode->error++;
806cabdff1aSopenharmony_ci        ppMode->error += numOfUnknownOptions;
807cabdff1aSopenharmony_ci    }
808cabdff1aSopenharmony_ci
809cabdff1aSopenharmony_ci    av_log(NULL, AV_LOG_DEBUG, "pp: lumMode=%X, chromMode=%X\n", ppMode->lumMode, ppMode->chromMode);
810cabdff1aSopenharmony_ci    if(ppMode->error){
811cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "%d errors in postprocess string \"%s\"\n", ppMode->error, name);
812cabdff1aSopenharmony_ci        av_free(ppMode);
813cabdff1aSopenharmony_ci        return NULL;
814cabdff1aSopenharmony_ci    }
815cabdff1aSopenharmony_ci    return ppMode;
816cabdff1aSopenharmony_ci}
817cabdff1aSopenharmony_ci
818cabdff1aSopenharmony_civoid pp_free_mode(pp_mode *mode){
819cabdff1aSopenharmony_ci    av_free(mode);
820cabdff1aSopenharmony_ci}
821cabdff1aSopenharmony_ci
822cabdff1aSopenharmony_cistatic void reallocAlign(void **p, int size){
823cabdff1aSopenharmony_ci    av_free(*p);
824cabdff1aSopenharmony_ci    *p= av_mallocz(size);
825cabdff1aSopenharmony_ci}
826cabdff1aSopenharmony_ci
827cabdff1aSopenharmony_cistatic void reallocBuffers(PPContext *c, int width, int height, int stride, int qpStride){
828cabdff1aSopenharmony_ci    int mbWidth = (width+15)>>4;
829cabdff1aSopenharmony_ci    int mbHeight= (height+15)>>4;
830cabdff1aSopenharmony_ci    int i;
831cabdff1aSopenharmony_ci
832cabdff1aSopenharmony_ci    c->stride= stride;
833cabdff1aSopenharmony_ci    c->qpStride= qpStride;
834cabdff1aSopenharmony_ci
835cabdff1aSopenharmony_ci    reallocAlign((void **)&c->tempDst, stride*24+32);
836cabdff1aSopenharmony_ci    reallocAlign((void **)&c->tempSrc, stride*24);
837cabdff1aSopenharmony_ci    reallocAlign((void **)&c->tempBlocks, 2*16*8);
838cabdff1aSopenharmony_ci    reallocAlign((void **)&c->yHistogram, 256*sizeof(uint64_t));
839cabdff1aSopenharmony_ci    for(i=0; i<256; i++)
840cabdff1aSopenharmony_ci            c->yHistogram[i]= width*height/64*15/256;
841cabdff1aSopenharmony_ci
842cabdff1aSopenharmony_ci    for(i=0; i<3; i++){
843cabdff1aSopenharmony_ci        //Note: The +17*1024 is just there so I do not have to worry about r/w over the end.
844cabdff1aSopenharmony_ci        reallocAlign((void **)&c->tempBlurred[i], stride*mbHeight*16 + 17*1024);
845cabdff1aSopenharmony_ci        reallocAlign((void **)&c->tempBlurredPast[i], 256*((height+7)&(~7))/2 + 17*1024);//FIXME size
846cabdff1aSopenharmony_ci    }
847cabdff1aSopenharmony_ci
848cabdff1aSopenharmony_ci    reallocAlign((void **)&c->deintTemp, 2*width+32);
849cabdff1aSopenharmony_ci    reallocAlign((void **)&c->nonBQPTable, qpStride*mbHeight*sizeof(int8_t));
850cabdff1aSopenharmony_ci    reallocAlign((void **)&c->stdQPTable, qpStride*mbHeight*sizeof(int8_t));
851cabdff1aSopenharmony_ci    reallocAlign((void **)&c->forcedQPTable, mbWidth*sizeof(int8_t));
852cabdff1aSopenharmony_ci}
853cabdff1aSopenharmony_ci
854cabdff1aSopenharmony_cistatic const char * context_to_name(void * ptr) {
855cabdff1aSopenharmony_ci    return "postproc";
856cabdff1aSopenharmony_ci}
857cabdff1aSopenharmony_ci
858cabdff1aSopenharmony_cistatic const AVClass av_codec_context_class = { "Postproc", context_to_name, NULL };
859cabdff1aSopenharmony_ci
860cabdff1aSopenharmony_ciav_cold pp_context *pp_get_context(int width, int height, int cpuCaps){
861cabdff1aSopenharmony_ci    PPContext *c= av_mallocz(sizeof(PPContext));
862cabdff1aSopenharmony_ci    int stride= FFALIGN(width, 16);  //assumed / will realloc if needed
863cabdff1aSopenharmony_ci    int qpStride= (width+15)/16 + 2; //assumed / will realloc if needed
864cabdff1aSopenharmony_ci
865cabdff1aSopenharmony_ci    if (!c)
866cabdff1aSopenharmony_ci        return NULL;
867cabdff1aSopenharmony_ci
868cabdff1aSopenharmony_ci    c->av_class = &av_codec_context_class;
869cabdff1aSopenharmony_ci    if(cpuCaps&PP_FORMAT){
870cabdff1aSopenharmony_ci        c->hChromaSubSample= cpuCaps&0x3;
871cabdff1aSopenharmony_ci        c->vChromaSubSample= (cpuCaps>>4)&0x3;
872cabdff1aSopenharmony_ci    }else{
873cabdff1aSopenharmony_ci        c->hChromaSubSample= 1;
874cabdff1aSopenharmony_ci        c->vChromaSubSample= 1;
875cabdff1aSopenharmony_ci    }
876cabdff1aSopenharmony_ci    if (cpuCaps & PP_CPU_CAPS_AUTO) {
877cabdff1aSopenharmony_ci        c->cpuCaps = av_get_cpu_flags();
878cabdff1aSopenharmony_ci    } else {
879cabdff1aSopenharmony_ci        c->cpuCaps = 0;
880cabdff1aSopenharmony_ci        if (cpuCaps & PP_CPU_CAPS_MMX)      c->cpuCaps |= AV_CPU_FLAG_MMX;
881cabdff1aSopenharmony_ci        if (cpuCaps & PP_CPU_CAPS_MMX2)     c->cpuCaps |= AV_CPU_FLAG_MMXEXT;
882cabdff1aSopenharmony_ci        if (cpuCaps & PP_CPU_CAPS_3DNOW)    c->cpuCaps |= AV_CPU_FLAG_3DNOW;
883cabdff1aSopenharmony_ci        if (cpuCaps & PP_CPU_CAPS_ALTIVEC)  c->cpuCaps |= AV_CPU_FLAG_ALTIVEC;
884cabdff1aSopenharmony_ci    }
885cabdff1aSopenharmony_ci
886cabdff1aSopenharmony_ci    reallocBuffers(c, width, height, stride, qpStride);
887cabdff1aSopenharmony_ci
888cabdff1aSopenharmony_ci    c->frameNum=-1;
889cabdff1aSopenharmony_ci
890cabdff1aSopenharmony_ci    return c;
891cabdff1aSopenharmony_ci}
892cabdff1aSopenharmony_ci
893cabdff1aSopenharmony_ciav_cold void pp_free_context(void *vc){
894cabdff1aSopenharmony_ci    PPContext *c = (PPContext*)vc;
895cabdff1aSopenharmony_ci    int i;
896cabdff1aSopenharmony_ci
897cabdff1aSopenharmony_ci    for(i=0; i<FF_ARRAY_ELEMS(c->tempBlurred); i++)
898cabdff1aSopenharmony_ci        av_free(c->tempBlurred[i]);
899cabdff1aSopenharmony_ci    for(i=0; i<FF_ARRAY_ELEMS(c->tempBlurredPast); i++)
900cabdff1aSopenharmony_ci        av_free(c->tempBlurredPast[i]);
901cabdff1aSopenharmony_ci
902cabdff1aSopenharmony_ci    av_free(c->tempBlocks);
903cabdff1aSopenharmony_ci    av_free(c->yHistogram);
904cabdff1aSopenharmony_ci    av_free(c->tempDst);
905cabdff1aSopenharmony_ci    av_free(c->tempSrc);
906cabdff1aSopenharmony_ci    av_free(c->deintTemp);
907cabdff1aSopenharmony_ci    av_free(c->stdQPTable);
908cabdff1aSopenharmony_ci    av_free(c->nonBQPTable);
909cabdff1aSopenharmony_ci    av_free(c->forcedQPTable);
910cabdff1aSopenharmony_ci
911cabdff1aSopenharmony_ci    memset(c, 0, sizeof(PPContext));
912cabdff1aSopenharmony_ci
913cabdff1aSopenharmony_ci    av_free(c);
914cabdff1aSopenharmony_ci}
915cabdff1aSopenharmony_ci
916cabdff1aSopenharmony_civoid  pp_postprocess(const uint8_t * src[3], const int srcStride[3],
917cabdff1aSopenharmony_ci                     uint8_t * dst[3], const int dstStride[3],
918cabdff1aSopenharmony_ci                     int width, int height,
919cabdff1aSopenharmony_ci                     const int8_t *QP_store,  int QPStride,
920cabdff1aSopenharmony_ci                     pp_mode *vm,  void *vc, int pict_type)
921cabdff1aSopenharmony_ci{
922cabdff1aSopenharmony_ci    int mbWidth = (width+15)>>4;
923cabdff1aSopenharmony_ci    int mbHeight= (height+15)>>4;
924cabdff1aSopenharmony_ci    PPMode *mode = vm;
925cabdff1aSopenharmony_ci    PPContext *c = vc;
926cabdff1aSopenharmony_ci    int minStride= FFMAX(FFABS(srcStride[0]), FFABS(dstStride[0]));
927cabdff1aSopenharmony_ci    int absQPStride = FFABS(QPStride);
928cabdff1aSopenharmony_ci
929cabdff1aSopenharmony_ci    // c->stride and c->QPStride are always positive
930cabdff1aSopenharmony_ci    if(c->stride < minStride || c->qpStride < absQPStride)
931cabdff1aSopenharmony_ci        reallocBuffers(c, width, height,
932cabdff1aSopenharmony_ci                       FFMAX(minStride, c->stride),
933cabdff1aSopenharmony_ci                       FFMAX(c->qpStride, absQPStride));
934cabdff1aSopenharmony_ci
935cabdff1aSopenharmony_ci    if(!QP_store || (mode->lumMode & FORCE_QUANT)){
936cabdff1aSopenharmony_ci        int i;
937cabdff1aSopenharmony_ci        QP_store= c->forcedQPTable;
938cabdff1aSopenharmony_ci        absQPStride = QPStride = 0;
939cabdff1aSopenharmony_ci        if(mode->lumMode & FORCE_QUANT)
940cabdff1aSopenharmony_ci            for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= mode->forcedQuant;
941cabdff1aSopenharmony_ci        else
942cabdff1aSopenharmony_ci            for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= 1;
943cabdff1aSopenharmony_ci    }
944cabdff1aSopenharmony_ci
945cabdff1aSopenharmony_ci    if(pict_type & PP_PICT_TYPE_QP2){
946cabdff1aSopenharmony_ci        int i;
947cabdff1aSopenharmony_ci        const int count= FFMAX(mbHeight * absQPStride, mbWidth);
948cabdff1aSopenharmony_ci        for(i=0; i<(count>>2); i++){
949cabdff1aSopenharmony_ci            AV_WN32(c->stdQPTable + (i<<2), AV_RN32(QP_store + (i<<2)) >> 1 & 0x7F7F7F7F);
950cabdff1aSopenharmony_ci        }
951cabdff1aSopenharmony_ci        for(i<<=2; i<count; i++){
952cabdff1aSopenharmony_ci            c->stdQPTable[i] = QP_store[i]>>1;
953cabdff1aSopenharmony_ci        }
954cabdff1aSopenharmony_ci        QP_store= c->stdQPTable;
955cabdff1aSopenharmony_ci        QPStride= absQPStride;
956cabdff1aSopenharmony_ci    }
957cabdff1aSopenharmony_ci
958cabdff1aSopenharmony_ci    if(0){
959cabdff1aSopenharmony_ci        int x,y;
960cabdff1aSopenharmony_ci        for(y=0; y<mbHeight; y++){
961cabdff1aSopenharmony_ci            for(x=0; x<mbWidth; x++){
962cabdff1aSopenharmony_ci                av_log(c, AV_LOG_INFO, "%2d ", QP_store[x + y*QPStride]);
963cabdff1aSopenharmony_ci            }
964cabdff1aSopenharmony_ci            av_log(c, AV_LOG_INFO, "\n");
965cabdff1aSopenharmony_ci        }
966cabdff1aSopenharmony_ci        av_log(c, AV_LOG_INFO, "\n");
967cabdff1aSopenharmony_ci    }
968cabdff1aSopenharmony_ci
969cabdff1aSopenharmony_ci    if((pict_type&7)!=3){
970cabdff1aSopenharmony_ci        if (QPStride >= 0){
971cabdff1aSopenharmony_ci            int i;
972cabdff1aSopenharmony_ci            const int count= FFMAX(mbHeight * QPStride, mbWidth);
973cabdff1aSopenharmony_ci            for(i=0; i<(count>>2); i++){
974cabdff1aSopenharmony_ci                AV_WN32(c->nonBQPTable + (i<<2), AV_RN32(QP_store + (i<<2)) & 0x3F3F3F3F);
975cabdff1aSopenharmony_ci            }
976cabdff1aSopenharmony_ci            for(i<<=2; i<count; i++){
977cabdff1aSopenharmony_ci                c->nonBQPTable[i] = QP_store[i] & 0x3F;
978cabdff1aSopenharmony_ci            }
979cabdff1aSopenharmony_ci        } else {
980cabdff1aSopenharmony_ci            int i,j;
981cabdff1aSopenharmony_ci            for(i=0; i<mbHeight; i++) {
982cabdff1aSopenharmony_ci                for(j=0; j<absQPStride; j++) {
983cabdff1aSopenharmony_ci                    c->nonBQPTable[i*absQPStride+j] = QP_store[i*QPStride+j] & 0x3F;
984cabdff1aSopenharmony_ci                }
985cabdff1aSopenharmony_ci            }
986cabdff1aSopenharmony_ci        }
987cabdff1aSopenharmony_ci    }
988cabdff1aSopenharmony_ci
989cabdff1aSopenharmony_ci    av_log(c, AV_LOG_DEBUG, "using npp filters 0x%X/0x%X\n",
990cabdff1aSopenharmony_ci           mode->lumMode, mode->chromMode);
991cabdff1aSopenharmony_ci
992cabdff1aSopenharmony_ci    postProcess(src[0], srcStride[0], dst[0], dstStride[0],
993cabdff1aSopenharmony_ci                width, height, QP_store, QPStride, 0, mode, c);
994cabdff1aSopenharmony_ci
995cabdff1aSopenharmony_ci    if (!(src[1] && src[2] && dst[1] && dst[2]))
996cabdff1aSopenharmony_ci        return;
997cabdff1aSopenharmony_ci
998cabdff1aSopenharmony_ci    width  = (width )>>c->hChromaSubSample;
999cabdff1aSopenharmony_ci    height = (height)>>c->vChromaSubSample;
1000cabdff1aSopenharmony_ci
1001cabdff1aSopenharmony_ci    if(mode->chromMode){
1002cabdff1aSopenharmony_ci        postProcess(src[1], srcStride[1], dst[1], dstStride[1],
1003cabdff1aSopenharmony_ci                    width, height, QP_store, QPStride, 1, mode, c);
1004cabdff1aSopenharmony_ci        postProcess(src[2], srcStride[2], dst[2], dstStride[2],
1005cabdff1aSopenharmony_ci                    width, height, QP_store, QPStride, 2, mode, c);
1006cabdff1aSopenharmony_ci    }
1007cabdff1aSopenharmony_ci    else if(srcStride[1] == dstStride[1] && srcStride[2] == dstStride[2]){
1008cabdff1aSopenharmony_ci        linecpy(dst[1], src[1], height, srcStride[1]);
1009cabdff1aSopenharmony_ci        linecpy(dst[2], src[2], height, srcStride[2]);
1010cabdff1aSopenharmony_ci    }else{
1011cabdff1aSopenharmony_ci        int y;
1012cabdff1aSopenharmony_ci        for(y=0; y<height; y++){
1013cabdff1aSopenharmony_ci            memcpy(&(dst[1][y*dstStride[1]]), &(src[1][y*srcStride[1]]), width);
1014cabdff1aSopenharmony_ci            memcpy(&(dst[2][y*dstStride[2]]), &(src[2][y*srcStride[2]]), width);
1015cabdff1aSopenharmony_ci        }
1016cabdff1aSopenharmony_ci    }
1017cabdff1aSopenharmony_ci}
1018