timgfilterpostproc.cpp

来自「从FFMPEG转换而来的H264解码程序,VC下编译..」· C++ 代码 · 共 1,961 行 · 第 1/5 页

CPP
1,961
字号

const uint8_t TimgFilterPostprocSpp::offset[127][2]=
{
 {0,0},
 {0,0}, {4,4},
 {0,0}, {2,2}, {6,4}, {4,6},
 {0,0}, {5,1}, {2,2}, {7,3}, {4,4}, {1,5}, {6,6}, {3,7},

 {0,0}, {4,0}, {1,1}, {5,1}, {3,2}, {7,2}, {2,3}, {6,3},
 {0,4}, {4,4}, {1,5}, {5,5}, {3,6}, {7,6}, {2,7}, {6,7},

 {0,0}, {0,2}, {0,4}, {0,6}, {1,1}, {1,3}, {1,5}, {1,7},
 {2,0}, {2,2}, {2,4}, {2,6}, {3,1}, {3,3}, {3,5}, {3,7},
 {4,0}, {4,2}, {4,4}, {4,6}, {5,1}, {5,3}, {5,5}, {5,7},
 {6,0}, {6,2}, {6,4}, {6,6}, {7,1}, {7,3}, {7,5}, {7,7},

 {0,0}, {4,4}, {0,4}, {4,0}, {2,2}, {6,6}, {2,6}, {6,2},
 {0,2}, {4,6}, {0,6}, {4,2}, {2,0}, {6,4}, {2,4}, {6,0},
 {1,1}, {5,5}, {1,5}, {5,1}, {3,3}, {7,7}, {3,7}, {7,3},
 {1,3}, {5,7}, {1,7}, {5,3}, {3,1}, {7,5}, {3,5}, {7,1},
 {0,1}, {4,5}, {0,5}, {4,1}, {2,3}, {6,7}, {2,7}, {6,3},
 {0,3}, {4,7}, {0,7}, {4,3}, {2,1}, {6,5}, {2,5}, {6,1},
 {1,0}, {5,4}, {1,4}, {5,0}, {3,2}, {7,6}, {3,6}, {7,2},
 {1,2}, {5,6}, {1,6}, {5,2}, {3,0}, {7,4}, {3,4}, {7,0},
};

inline void TimgFilterPostprocSpp::add_block(int16_t *dst, int stride, DCTELEM block[64])
{
 for (int y=0;y<8;y++)
  {
   paddw(*(__m64*)&dst[0+y*stride],*(__m64*)&block[0+y*8]);
   paddw(*(__m64*)&dst[4+y*stride],*(__m64*)&block[4+y*8]);
  }
}

inline void TimgFilterPostprocSpp::get_pixels(DCTELEM *block, const uint8_t *pixels, int line_size)
{
 __m64 mm7=_mm_setzero_si64(),mm0,mm2,mm1,mm3;
 for (int REG_a=-64;REG_a;pixels+=2*line_size,REG_a+=16)
  {
   movq (mm0,pixels);
   movq (mm2,pixels+line_size);
   movq (mm1,mm0);
   movq (mm3,mm2);
   punpcklbw  (mm0,mm7);
   punpckhbw  (mm1,mm7);
   punpcklbw  (mm2,mm7);
   punpckhbw  (mm3,mm7);
   movq ( 0+block+64+REG_a,mm0);
   movq ( 4+block+64+REG_a,mm1);
   movq ( 8+block+64+REG_a,mm2);
   movq (12+block+64+REG_a,mm3);
  }
}

#ifndef WIN64
void TimgFilterPostprocSpp::filter(uint8_t *dst, const uint8_t *src0, int dst_stride, int src_stride, unsigned int width, unsigned int height, const int8_t *qp_store, int qp_stride, bool is_luma)
{
 const int count=1<<currentq;
 const int stride=is_luma?temp_stride:((width+16+15)&(~15));
 uint64_t block_align1[32*2],*block_align=(uint64_t*)(((intptr_t)block_align1+16)&(~15));
 DCTELEM *block =(DCTELEM *)block_align;
 DCTELEM *block2=(DCTELEM *)(block_align+16);
 unsigned int y;
 for (y=0;y<height;y++)
  {
   int index=8+8*stride+y*stride;
   memcpy(src+index,src0+y*src_stride,width);
   for(unsigned int x=0;x<8;x++)
    {
     src[index      -x-1]=src[index+      x  ];
     src[index+width+x  ]=src[index+width-x-1];
    }
  }
 for (y=0;y<8;y++)
  {
   memcpy(src+(       7-y)*stride,src+(       y+8)*stride,stride);
   memcpy(src+(height+8+y)*stride,src+(height-y+7)*stride,stride);
  }
 //FIXME (try edge emu)
 for (y=0;y<height+8;y+=8)
  {
   memset(temp+(8+y)*stride,0,8*stride*sizeof(int16_t));
   for (unsigned int x=0;x<width+8;x+=8)
    {
     const int qps=3+is_luma;
     int qp;

     qp=qp_store[(std::min(x,width-1)>>qps)+(std::min(y,height-1)>>qps)*qp_stride];
     //if(p->mpeg2) qp>>=1;
     for (int i=0;i<count;i++)
      {
       const int x1=x+offset[i+count-1][0];
       const int y1=y+offset[i+count-1][1];
       const int index= x1 + y1*stride;
       get_pixels(block,src+index,stride);
       ff_fdct_mmx2(block);
       //dsp->fdct(block);
       requantize(block2,block,qp);
       simple_idct_mmx_P(block2);
       //dsp->idct(block2);
       add_block(temp+index,stride,block2);
      }
    }
   if (y)
    store_slice(dst+(y-8)*dst_stride,temp+8+y*stride,dst_stride,stride,width,std::min(8U,height+8-y),6-currentq);
  }
}
#endif

bool TimgFilterPostprocSpp::is(const TffPictBase &pict,const TfilterSettingsVideo *cfg0)
{
 const TpostprocSettings *cfg=(const TpostprocSettings*)cfg0;
 if (super::is(pict,cfg) && cfg->qual)
  {
   Trect r=pict.getRect(cfg->full,cfg->half);
   return pictRect.dx>=16 && pictRect.dy>=16;
  }
 else
  return false;
}

HRESULT TimgFilterPostprocSpp::process(TfilterQueue::iterator it,TffPict &pict,const TfilterSettingsVideo *cfg0)
{
 const TpostprocSettings *cfg=(const TpostprocSettings*)cfg0;
#ifndef WIN64
 if (prepare(cfg,31,pict.frametype) && currentq)
  {
   init(pict,cfg->full,cfg->half);
   if (pictRect.dx>=16 && pictRect.dy>=16)
    {
     bool cspChanged=false;
     const unsigned char *tempPict1[4];
     cspChanged|=getCur(FF_CSPS_MASK_YUV_PLANAR,pict,cfg->full,tempPict1);
     unsigned char *tempPict2[4];
     cspChanged|=getNext(csp1,pict,cfg->full,tempPict2);
     if (cspChanged || old_sppMode!=cfg->sppMode)
      {
       old_sppMode=cfg->sppMode;
       done();
      }

     if (!temp)
      {
       switch (cfg->sppMode)
        {
         case 0:requantize=hardthresh_mmx;break;
         case 1:requantize=softthresh_mmx;break;
        }
      #ifdef __SSE2__
       if (Tconfig::cpu_flags&FF_CPU_SSE2)
        store_slice=TstoreSlice<Tsse2>::store_slice;
       else
      #endif
       if (Tconfig::cpu_flags&FF_CPU_MMX)
        store_slice=TstoreSlice<Tmmx>::store_slice;
       else
        store_slice=store_slice_c;

       unsigned int h=(dy1[0]+16+15)&(~15);
       temp_stride=(dx1[0]+16+15)&(~15);
       temp=(int16_t*)aligned_malloc(temp_stride*h*sizeof(int16_t));
       src=(uint8_t*)aligned_malloc(temp_stride*h*sizeof(uint8_t));
      }

     for (unsigned int i=0;i<pict.cspInfo.numPlanes;i++)
      filter(tempPict2[i],tempPict1[i],stride2[i],stride1[i],dx1[i],dy1[i],quants,quantsDx,i==0);
     if (Tconfig::cpu_flags&FF_CPU_MMX) _mm_empty();
     if (Tconfig::cpu_flags&FF_CPU_MMXEXT) _mm_sfence();
    }
  }
#endif
 return parent->deliverSample(++it,pict);
}

//============================== TimgFilterPostprocNic ===============================
// postprocessing routines by Nic (http://nic.dnsalias.com/)
TimgFilterPostprocNic::TimgFilterPostprocNic(IffdshowBase *Ideci,Tfilters *Iparent):TimgFilterPostprocBase(Ideci,Iparent,false)
{
 nic_dering=getNic_dering();
}

bool TimgFilterPostprocNic::is(const TffPictBase &pict,const TfilterSettingsVideo *cfg0)
{
 const TpostprocSettings *cfg=(const TpostprocSettings*)cfg0;
 if (super::is(pict,cfg) && Tlibmplayer::getPPmode(cfg,cfg->qual)&~(LUM_LEVEL_FIX|CHROM_LEVEL_FIX))
  {
   Trect r=pict.getRect(cfg->full,cfg->half);
   return pictRect.dx>=16 && pictRect.dy>=16;
  }
 else
  return false;
}

HRESULT TimgFilterPostprocNic::process(TfilterQueue::iterator it,TffPict &pict,const TfilterSettingsVideo *cfg0)
{
 const TpostprocSettings *cfg=(const TpostprocSettings*)cfg0;
 if (int ppmode=prepare(cfg,31,pict.frametype))
  {
   init(pict,cfg->full,cfg->half);
   if (pictRect.dx>=16 && pictRect.dy>=16)
    {
     unsigned char *tempPict[4];
     getCurNext(/*FF_CSPS_MASK_YUV_PLANAR*/FF_CSP_420P,pict,cfg->full,COPYMODE_DEF,tempPict);
     nic_postprocess(tempPict,stride2,
                     pict.cspInfo.shiftX[1],pict.cspInfo.shiftY[1],
                     dx1[0],dy1[0],
                     quants,quantsDx,ppmode,cfg->nicXthresh,cfg->nicYthresh);
     if (ppmode&LUM_DERING)
      nic_dering(tempPict[0],dx1[0],dy1[0],stride2[0],quants,quantsDx,pict.cspInfo.shiftX[0],pict.cspInfo.shiftY[0]);
     if (ppmode&CHROM_DERING)
      {
       nic_dering(tempPict[1],dx1[1],dy1[1],stride2[1],quants,quantsDx,pict.cspInfo.shiftX[1],pict.cspInfo.shiftY[1]);
       nic_dering(tempPict[2],dx1[2],dy1[2],stride2[2],quants,quantsDx,pict.cspInfo.shiftX[2],pict.cspInfo.shiftY[2]);
      }
    }
  }
 return parent->deliverSample(++it,pict);
}

//============================ TimgFilterPostprocFspp ===============================
void TimgFilterPostprocFspp::filter(uint8_t *dst, const uint8_t *src0,
		            stride_t dst_stride, stride_t src_stride,
		            int width, int height,
		            int8_t *qp_store, int qp_stride, int is_luma)
{
    int x, x0, y, es, qy, t;
    const int stride= is_luma ? temp_stride : (width+16);//((width+16+15)&(~15))
    const int step=6-log2_count;
    const int qps= 3 + is_luma;
    int32_t __attribute__((aligned(32))) block_align[4*8*BLOCKSZ+ 4*8*BLOCKSZ];
    DCTELEM *block= (DCTELEM *)block_align;
    DCTELEM *block3=(DCTELEM *)(block_align+4*8*BLOCKSZ);

    memset(block3, 0, 4*8*BLOCKSZ);

    //src=src-src_stride*8-8;//!
    if (!src0 || !dst) return; // HACK avoid crash for Y8 colourspace
    for(y=0; y<height; y++){
        int index= 8 + 8*stride + y*stride;
        memcpy(src + index, src0 + y*src_stride, width);//this line can be avoided by using DR & user fr.buffers
        for(x=0; x<8; x++){
            src[index         - x - 1]= src[index +         x    ];
            src[index + width + x    ]= src[index + width - x - 1];
        }
    }
    for(y=0; y<8; y++){
        memcpy(src + (      7-y)*stride, src + (      y+8)*stride, stride);
        memcpy(src + (height+8+y)*stride, src + (height-y+7)*stride, stride);
    }
    //FIXME (try edge emu)

    for(y=8; y<24; y++)
        memset(temp+ 8 +y*stride, 0,width*sizeof(int16_t));

    for(y=step; y<height+8; y+=step){    //step= 1,2
        qy=y-4;
        if (qy>height-1) qy=height-1;
        if (qy<0) qy=0;
        qy=(qy>>qps)*qp_stride;
        row_fdct_s(block, src + y*stride +2-(y&1), stride, 2);
        for(x0=0; x0<width+8-8*(BLOCKSZ-1); x0+=8*(BLOCKSZ-1)){
            row_fdct_s(block+8*8, src + y*stride+8+x0 +2-(y&1), stride, 2*(BLOCKSZ-1));
            if(qp)
                column_fidct_s((int16_t*)(&threshold_mtx[0]), block+0*8, block3+0*8, 8*(BLOCKSZ-1)); //yes, this is a HOTSPOT
            else
                for (x=0; x<8*(BLOCKSZ-1); x+=8) {
                    t=x+x0-2; //correct t=x+x0-2-(y&1), but its the same
                    if (t<0) t=0;//t always < width-2
                    t=qp_store[qy+(t>>qps)];
                    //if(mpeg2) t>>=1; //copy mpeg2,prev_q to locals?
                    if (t!=prev_q) prev_q=t, mul_thrmat_s(t);
                    column_fidct_s((int16_t*)(&threshold_mtx[0]), block+x*8, block3+x*8, 8); //yes, this is a HOTSPOT
                }
            row_idct_s(block3+0*8, temp + (y&15)*stride+x0+2-(y&1), stride, 2*(BLOCKSZ-1));
            memcpy(block, block+(BLOCKSZ-1)*64, 8*8*sizeof(DCTELEM)); //cycling
            memcpy(block3, block3+(BLOCKSZ-1)*64, 6*8*sizeof(DCTELEM));
        }
        //
        es=width+8-x0; //  8, ...
        if (es>8)
            row_fdct_s(block+8*8, src + y*stride+8+x0 +2-(y&1), stride, (es-4)>>2);
        column_fidct_s((int16_t*)(&threshold_mtx[0]), block, block3, es-0);
        row_idct_s(block3+0*8, temp + (y&15)*stride+x0+2-(y&1), stride, es>>2);
        {const int y1=y-8+step;//l5-7  l4-6
            if (!(y1&7) && y1) {
                if (y1&8) store_slice_s(dst + (y1-8)*dst_stride, temp+ 8 +8*stride,
                                        dst_stride, stride, width, 8, 5-log2_count);
                else store_slice2_s(dst + (y1-8)*dst_stride, temp+ 8 +0*stride,
                                    dst_stride, stride, width, 8, 5-log2_count);
            } }
    }

    if (y&7) {  // == height & 7
        if (y&8) store_slice_s(dst + ((y-8)&~7)*dst_stride, temp+ 8 +8*stride,
                               dst_stride, stride, width, y&7, 5-log2_count);
        else store_slice2_s(dst + ((y-8)&~7)*dst_stride, temp+ 8 +0*stride,
                            dst_stride, stride, width, y&7, 5-log2_count);
    }
}

//This func reads from 1 slice, 1 and clears 0 & 1
void TimgFilterPostprocFspp::store_slice_s(uint8_t *dst, int16_t *src_, stride_t dst_stride, stride_t src_stride, long width, long height, long log2_scale)
{
 uint8_t *src=(uint8_t*)src_;
    const uint8_t *od=&TimgFilterPostprocSpp::TstoreSlice<Tmmx>::dither[0][0];
    const uint8_t *end=&TimgFilterPostprocSpp::TstoreSlice<Tmmx>::dither[height][0];
    width = (width+7)&~7;
    dst_stride-=width;
    //src_stride=(src_stride-width)*2;
        int REG_d_=log2_scale;
        uint8_t *REG_S=src;
        uint8_t *REG_D=dst;
        stride_t REG_a=src_stride;
        __m64 mm5;
        csimd::movd( REG_d_, mm5             );
        REG_d_^=-1;
        stride_t REG_c=REG_a;
        REG_d_+=7;
        REG_a=-REG_a;
        REG_c-=width;
        REG_c+= REG_c;
        __m64 mm2;
        csimd::movd( REG_d_, mm2);
        src_stride=REG_c;
        const uint8_t *REG_d=od;
        REG_a<<=4;
        __m64 mm3,mm4,mm7,mm0,mm1;
       label2:
        csimd::movq (REG_d, mm3);
        csimd::movq (mm3, mm4 );
        csimd::pxor (mm7, mm7);
        csimd::punpcklbw( mm7, mm3 );
        csimd::punpckhbw( mm7, mm4);
        REG_c=width;
        csimd::psraw (mm5, mm3);
        csimd::psraw (mm5, mm4);
       label1:
        csimd::movq (mm7, REG_S+REG_a);
        csimd::movq (REG_S, mm0  );
        csimd::movq (8+REG_S, mm1);

        csimd::movq (mm7, 8+REG_S+REG_a);
        csimd::paddw (mm3, mm0);
        csimd::paddw (mm4, mm1);

        csimd::movq (mm7, REG_S);
        csimd::psraw (mm2, mm0);
        csimd::psraw (mm2, mm1);

        csimd::movq (mm7, 8+REG_S);
        csimd::packuswb (mm1, mm0);
        REG_S+=16;

        csimd::movq (mm0, REG_D);
        REG_D+=8;
        REG_c-=8;
        if (REG_c>0) //jg
         goto label1;//1b
        REG_S+=src_stride;
        REG_d+=8;
        REG_D+=dst_stride;
        if (end>REG_d)// cmp end, REG_d
         goto label2;//jl 2b
}

//This func reads from 2 slices, 0 & 2  and clears 2-nd
void TimgFilterPostprocFspp::store_slice2_s(uint8_t *dst, int16_t *src_, stride_t dst_stride, stride_t src_stride, long width, long height, long log2_scale)
{
 uint8_t *src=(uint8_t*)src_;
    const uint8_t *od=&TimgFilterPostprocSpp::TstoreSlice<Tmmx>::dither[0][0];
    const uint8_t *end=&TimgFilterPostprocSpp::TstoreSlice<Tmmx>::dither[height][0];
    width = (width+7)&~7;
    dst_stride-=width;
    //src_stride=(src_stride-width)*2;
        int REG_d_= log2_scale;
        uint8_t*REG_S= src;
        uint8_t*REG_D= dst;
        stride_t REG_a= src_stride;
        __m64 mm5;
        csimd::movd( REG_d_, mm5);
        REG_d_^=-1;
        stride_t REG_c=REG_a;
        REG_d_+=7;
        REG_c-=width;
        REG_c+=REG_c;
        __m64 mm2;
        csimd::movd (REG_d_, mm2);
        src_stride=REG_c;
        const uint8_t *REG_d= od;
        REG_a<<=5;
        __m64 mm3,mm4,mm7,mm0,mm1,mm6;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?