Carl Eugen Hoyospostproc: fix unaligned access2aa21ee10 years agoHistory
1044 lines · 37.1 KB · C
RawDownload
/* * Copyright (C) 2001-2003 Michael Niedermayer (michaelni@gmx.at) * * AltiVec optimizations (C) 2004 Romain Dolbeau <romain@dolbeau.org> * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * postprocessing. */ /*                        C       MMX     MMX2    3DNow   AltiVecisVertDC                Ec      Ec                      EcisVertMinMaxOk          Ec      Ec                      EcdoVertLowPass           E               e       e       EcdoVertDefFilter         Ec      Ec      e       e       EcisHorizDC               Ec      Ec                      EcisHorizMinMaxOk         a       E                       EcdoHorizLowPass          E               e       e       EcdoHorizDefFilter        Ec      Ec      e       e       Ecdo_a_deblock            Ec      E       Ec      EdeRing                  E               e       e*      EcpVertical RKAlgo1        E               a       aHorizontal RKAlgo1                      a       aVertical X1#            a               E       EHorizontal X1#          a               E       ELinIpolDeinterlace      e               E       E*CubicIpolDeinterlace    a               e       e*LinBlendDeinterlace     e               E       E*MedianDeinterlace#      E       Ec      EcTempDeNoiser#           E               e       e       Ec * I do not have a 3DNow! CPU -> it is untested, but no one said it does not work so it seems to work# more or less selfinvented filters so the exactness is not too meaningfulE = Exact implementatione = almost exact implementation (slightly different rounding,...)a = alternative / approximate implc = checked against the other implementations (-vo md5)p = partially optimized, still some work to do*/ /*TODO:reduce the time wasted on the mem transferunroll stuff if instructions depend too much on the prior onemove YScale thing to the end instead of fixing QPwrite a faster and higher quality deblocking filter :)make the mainloop more flexible (variable number of blocks at once        (the if/else stuff per block is slowing things down)compare the quality & speed of all filterssplit this huge fileoptimize c versionstry to unroll inner for(x=0 ... loop to avoid these damn if(x ... checks...*/ //Changelog: use git log #include "config.h"#include "libavutil/avutil.h"#include "libavutil/avassert.h"#include "libavutil/intreadwrite.h"#include <inttypes.h>#include <stdio.h>#include <stdlib.h>#include <string.h>//#undef HAVE_MMXEXT_INLINE//#define HAVE_AMD3DNOW_INLINE//#undef HAVE_MMX_INLINE//#undef ARCH_X86//#define DEBUG_BRIGHTNESS#include "postprocess.h"#include "postprocess_internal.h"#include "libavutil/avstring.h" #include "libavutil/ffversion.h"const char postproc_ffversion[] = "FFmpeg version " FFMPEG_VERSION; unsigned postproc_version(void){    av_assert0(LIBPOSTPROC_VERSION_MICRO >= 100);    return LIBPOSTPROC_VERSION_INT;} const char *postproc_configuration(void){    return FFMPEG_CONFIGURATION;} const char *postproc_license(void){#define LICENSE_PREFIX "libpostproc license: "    return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;} #if HAVE_ALTIVEC_H#include <altivec.h>#endif #define GET_MODE_BUFFER_SIZE 500#define OPTIONS_ARRAY_SIZE 10#define BLOCK_SIZE 8#define TEMP_STRIDE 8//#define NUM_BLOCKS_AT_ONCE 16 //not used yet #if ARCH_X86 && HAVE_INLINE_ASMDECLARE_ASM_CONST(8, uint64_t, w05)= 0x0005000500050005LL;DECLARE_ASM_CONST(8, uint64_t, w04)= 0x0004000400040004LL;DECLARE_ASM_CONST(8, uint64_t, w20)= 0x0020002000200020LL;DECLARE_ASM_CONST(8, uint64_t, b00)= 0x0000000000000000LL;DECLARE_ASM_CONST(8, uint64_t, b01)= 0x0101010101010101LL;DECLARE_ASM_CONST(8, uint64_t, b02)= 0x0202020202020202LL;DECLARE_ASM_CONST(8, uint64_t, b08)= 0x0808080808080808LL;DECLARE_ASM_CONST(8, uint64_t, b80)= 0x8080808080808080LL;#endif DECLARE_ASM_CONST(8, int, deringThreshold)= 20;  static const struct PPFilter filters[]={    {"hb", "hdeblock",              1, 1, 3, H_DEBLOCK},    {"vb", "vdeblock",              1, 2, 4, V_DEBLOCK},/*  {"hr", "rkhdeblock",            1, 1, 3, H_RK1_FILTER},    {"vr", "rkvdeblock",            1, 2, 4, V_RK1_FILTER},*/    {"h1", "x1hdeblock",            1, 1, 3, H_X1_FILTER},    {"v1", "x1vdeblock",            1, 2, 4, V_X1_FILTER},    {"ha", "ahdeblock",             1, 1, 3, H_A_DEBLOCK},    {"va", "avdeblock",             1, 2, 4, V_A_DEBLOCK},    {"dr", "dering",                1, 5, 6, DERING},    {"al", "autolevels",            0, 1, 2, LEVEL_FIX},    {"lb", "linblenddeint",         1, 1, 4, LINEAR_BLEND_DEINT_FILTER},    {"li", "linipoldeint",          1, 1, 4, LINEAR_IPOL_DEINT_FILTER},    {"ci", "cubicipoldeint",        1, 1, 4, CUBIC_IPOL_DEINT_FILTER},    {"md", "mediandeint",           1, 1, 4, MEDIAN_DEINT_FILTER},    {"fd", "ffmpegdeint",           1, 1, 4, FFMPEG_DEINT_FILTER},    {"l5", "lowpass5",              1, 1, 4, LOWPASS5_DEINT_FILTER},    {"tn", "tmpnoise",              1, 7, 8, TEMP_NOISE_FILTER},    {"fq", "forcequant",            1, 0, 0, FORCE_QUANT},    {"be", "bitexact",              1, 0, 0, BITEXACT},    {"vi", "visualize",             1, 0, 0, VISUALIZE},    {NULL, NULL,0,0,0,0} //End Marker}; static const char * const replaceTable[]={    "default",      "hb:a,vb:a,dr:a",    "de",           "hb:a,vb:a,dr:a",    "fast",         "h1:a,v1:a,dr:a",    "fa",           "h1:a,v1:a,dr:a",    "ac",           "ha:a:128:7,va:a,dr:a",    NULL //End Marker}; /* The horizontal functions exist only in C because the MMX * code is faster with vertical filters and transposing. */ /** * Check if the given 8x8 Block is mostly "flat" */static inline int isHorizDC_C(const uint8_t src[], int stride, const PPContext *c){    int numEq= 0;    int y;    const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;    const int dcThreshold= dcOffset*2 + 1;     for(y=0; y<BLOCK_SIZE; y++){        numEq += ((unsigned)(src[0] - src[1] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[1] - src[2] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[2] - src[3] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[3] - src[4] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[4] - src[5] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[5] - src[6] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[6] - src[7] + dcOffset)) < dcThreshold;        src+= stride;    }    return numEq > c->ppMode.flatnessThreshold;} /** * Check if the middle 8x8 Block in the given 8x16 block is flat */static inline int isVertDC_C(const uint8_t src[], int stride, const PPContext *c){    int numEq= 0;    int y;    const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;    const int dcThreshold= dcOffset*2 + 1;     src+= stride*4; // src points to begin of the 8x8 Block    for(y=0; y<BLOCK_SIZE-1; y++){        numEq += ((unsigned)(src[0] - src[0+stride] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[1] - src[1+stride] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[2] - src[2+stride] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[3] - src[3+stride] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[4] - src[4+stride] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[5] - src[5+stride] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[6] - src[6+stride] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[7] - src[7+stride] + dcOffset)) < dcThreshold;        src+= stride;    }    return numEq > c->ppMode.flatnessThreshold;} static inline int isHorizMinMaxOk_C(const uint8_t src[], int stride, int QP){    int i;    for(i=0; i<2; i++){        if((unsigned)(src[0] - src[5] + 2*QP) > 4*QP) return 0;        src += stride;        if((unsigned)(src[2] - src[7] + 2*QP) > 4*QP) return 0;        src += stride;        if((unsigned)(src[4] - src[1] + 2*QP) > 4*QP) return 0;        src += stride;        if((unsigned)(src[6] - src[3] + 2*QP) > 4*QP) return 0;        src += stride;    }    return 1;} static inline int isVertMinMaxOk_C(const uint8_t src[], int stride, int QP){    int x;    src+= stride*4;    for(x=0; x<BLOCK_SIZE; x+=4){        if((unsigned)(src[  x + 0*stride] - src[  x + 5*stride] + 2*QP) > 4*QP) return 0;        if((unsigned)(src[1+x + 2*stride] - src[1+x + 7*stride] + 2*QP) > 4*QP) return 0;        if((unsigned)(src[2+x + 4*stride] - src[2+x + 1*stride] + 2*QP) > 4*QP) return 0;        if((unsigned)(src[3+x + 6*stride] - src[3+x + 3*stride] + 2*QP) > 4*QP) return 0;    }    return 1;} static inline int horizClassify_C(const uint8_t src[], int stride, const PPContext *c){    if( isHorizDC_C(src, stride, c) ){        return isHorizMinMaxOk_C(src, stride, c->QP);    }else{        return 2;    }} static inline int vertClassify_C(const uint8_t src[], int stride, const PPContext *c){    if( isVertDC_C(src, stride, c) ){        return isVertMinMaxOk_C(src, stride, c->QP);    }else{        return 2;    }} static inline void doHorizDefFilter_C(uint8_t dst[], int stride, const PPContext *c){    int y;    for(y=0; y<BLOCK_SIZE; y++){        const int middleEnergy= 5*(dst[4] - dst[3]) + 2*(dst[2] - dst[5]);         if(FFABS(middleEnergy) < 8*c->QP){            const int q=(dst[3] - dst[4])/2;            const int leftEnergy=  5*(dst[2] - dst[1]) + 2*(dst[0] - dst[3]);            const int rightEnergy= 5*(dst[6] - dst[5]) + 2*(dst[4] - dst[7]);             int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );            d= FFMAX(d, 0);             d= (5*d + 32) >> 6;            d*= FFSIGN(-middleEnergy);             if(q>0)            {                d = FFMAX(d, 0);                d = FFMIN(d, q);            }            else            {                d = FFMIN(d, 0);                d = FFMAX(d, q);            }             dst[3]-= d;            dst[4]+= d;        }        dst+= stride;    }} /** * Do a horizontal low pass filter on the 10x8 block (dst points to middle 8x8 Block) * using the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16 (C version) */static inline void doHorizLowPass_C(uint8_t dst[], int stride, const PPContext *c){    int y;    for(y=0; y<BLOCK_SIZE; y++){        const int first= FFABS(dst[-1] - dst[0]) < c->QP ? dst[-1] : dst[0];        const int last= FFABS(dst[8] - dst[7]) < c->QP ? dst[8] : dst[7];         int sums[10];        sums[0] = 4*first + dst[0] + dst[1] + dst[2] + 4;        sums[1] = sums[0] - first  + dst[3];        sums[2] = sums[1] - first  + dst[4];        sums[3] = sums[2] - first  + dst[5];        sums[4] = sums[3] - first  + dst[6];        sums[5] = sums[4] - dst[0] + dst[7];        sums[6] = sums[5] - dst[1] + last;        sums[7] = sums[6] - dst[2] + last;        sums[8] = sums[7] - dst[3] + last;        sums[9] = sums[8] - dst[4] + last;         dst[0]= (sums[0] + sums[2] + 2*dst[0])>>4;        dst[1]= (sums[1] + sums[3] + 2*dst[1])>>4;        dst[2]= (sums[2] + sums[4] + 2*dst[2])>>4;        dst[3]= (sums[3] + sums[5] + 2*dst[3])>>4;        dst[4]= (sums[4] + sums[6] + 2*dst[4])>>4;        dst[5]= (sums[5] + sums[7] + 2*dst[5])>>4;        dst[6]= (sums[6] + sums[8] + 2*dst[6])>>4;        dst[7]= (sums[7] + sums[9] + 2*dst[7])>>4;         dst+= stride;    }} /** * Experimental Filter 1 (Horizontal) * will not damage linear gradients * Flat blocks should look like they were passed through the (1,1,2,2,4,2,2,1,1) 9-Tap filter * can only smooth blocks at the expected locations (it cannot smooth them if they did move) * MMX2 version does correct clipping C version does not * not identical with the vertical one */static inline void horizX1Filter(uint8_t *src, int stride, int QP){    int y;    static uint64_t lut[256];    if(!lut[255])    {        int i;        for(i=0; i<256; i++)        {            int v= i < 128 ? 2*i : 2*(i-256);/*//Simulate 112242211 9-Tap filter            uint64_t a= (v/16)  & 0xFF;            uint64_t b= (v/8)   & 0xFF;            uint64_t c= (v/4)   & 0xFF;            uint64_t d= (3*v/8) & 0xFF;*///Simulate piecewise linear interpolation            uint64_t a= (v/16)   & 0xFF;            uint64_t b= (v*3/16) & 0xFF;            uint64_t c= (v*5/16) & 0xFF;            uint64_t d= (7*v/16) & 0xFF;            uint64_t A= (0x100 - a)&0xFF;            uint64_t B= (0x100 - b)&0xFF;            uint64_t C= (0x100 - c)&0xFF;            uint64_t D= (0x100 - c)&0xFF;             lut[i]   = (a<<56) | (b<<48) | (c<<40) | (d<<32) |                       (D<<24) | (C<<16) | (B<<8)  | (A);            //lut[i] = (v<<32) | (v<<24);        }    }     for(y=0; y<BLOCK_SIZE; y++){        int a= src[1] - src[2];        int b= src[3] - src[4];        int c= src[5] - src[6];         int d= FFMAX(FFABS(b) - (FFABS(a) + FFABS(c))/2, 0);         if(d < QP){            int v = d * FFSIGN(-b);             src[1] +=v/8;            src[2] +=v/4;            src[3] +=3*v/8;            src[4] -=3*v/8;            src[5] -=v/4;            src[6] -=v/8;        }        src+=stride;    }} /** * accurate deblock filter */static av_always_inline void do_a_deblock_C(uint8_t *src, int step,                                            int stride, const PPContext *c, int mode){    int y;    const int QP= c->QP;    const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;    const int dcThreshold= dcOffset*2 + 1;//START_TIMER    src+= step*4; // src points to begin of the 8x8 Block    for(y=0; y<8; y++){        int numEq= 0;         numEq += ((unsigned)(src[-1*step] - src[0*step] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[ 0*step] - src[1*step] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[ 1*step] - src[2*step] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[ 2*step] - src[3*step] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[ 3*step] - src[4*step] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[ 4*step] - src[5*step] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[ 5*step] - src[6*step] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[ 6*step] - src[7*step] + dcOffset)) < dcThreshold;        numEq += ((unsigned)(src[ 7*step] - src[8*step] + dcOffset)) < dcThreshold;        if(numEq > c->ppMode.flatnessThreshold){            int min, max, x;             if(src[0] > src[step]){                max= src[0];                min= src[step];            }else{                max= src[step];                min= src[0];            }            for(x=2; x<8; x+=2){                if(src[x*step] > src[(x+1)*step]){                        if(src[x    *step] > max) max= src[ x   *step];                        if(src[(x+1)*step] < min) min= src[(x+1)*step];                }else{                        if(src[(x+1)*step] > max) max= src[(x+1)*step];                        if(src[ x   *step] < min) min= src[ x   *step];                }            }            if(max-min < 2*QP){                const int first= FFABS(src[-1*step] - src[0]) < QP ? src[-1*step] : src[0];                const int last= FFABS(src[8*step] - src[7*step]) < QP ? src[8*step] : src[7*step];                 int sums[10];                sums[0] = 4*first + src[0*step] + src[1*step] + src[2*step] + 4;                sums[1] = sums[0] - first       + src[3*step];                sums[2] = sums[1] - first       + src[4*step];                sums[3] = sums[2] - first       + src[5*step];                sums[4] = sums[3] - first       + src[6*step];                sums[5] = sums[4] - src[0*step] + src[7*step];                sums[6] = sums[5] - src[1*step] + last;                sums[7] = sums[6] - src[2*step] + last;                sums[8] = sums[7] - src[3*step] + last;                sums[9] = sums[8] - src[4*step] + last;                 if (mode & VISUALIZE) {                    src[0*step] =                    src[1*step] =                    src[2*step] =                    src[3*step] =                    src[4*step] =                    src[5*step] =                    src[6*step] =                    src[7*step] = 128;                }                src[0*step]= (sums[0] + sums[2] + 2*src[0*step])>>4;                src[1*step]= (sums[1] + sums[3] + 2*src[1*step])>>4;                src[2*step]= (sums[2] + sums[4] + 2*src[2*step])>>4;                src[3*step]= (sums[3] + sums[5] + 2*src[3*step])>>4;                src[4*step]= (sums[4] + sums[6] + 2*src[4*step])>>4;                src[5*step]= (sums[5] + sums[7] + 2*src[5*step])>>4;                src[6*step]= (sums[6] + sums[8] + 2*src[6*step])>>4;                src[7*step]= (sums[7] + sums[9] + 2*src[7*step])>>4;            }        }else{            const int middleEnergy= 5*(src[4*step] - src[3*step]) + 2*(src[2*step] - src[5*step]);             if(FFABS(middleEnergy) < 8*QP){                const int q=(src[3*step] - src[4*step])/2;                const int leftEnergy=  5*(src[2*step] - src[1*step]) + 2*(src[0*step] - src[3*step]);                const int rightEnergy= 5*(src[6*step] - src[5*step]) + 2*(src[4*step] - src[7*step]);                 int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );                d= FFMAX(d, 0);                 d= (5*d + 32) >> 6;                d*= FFSIGN(-middleEnergy);                 if(q>0){                    d = FFMAX(d, 0);                    d = FFMIN(d, q);                }else{                    d = FFMIN(d, 0);                    d = FFMAX(d, q);

Lines 1–500 of 1044.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t