home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2004 March / PCWELT_3_2004.ISO / pcwsoft / flaskmpeg_078_39_src.z.exe / flaskmpeg / Deinterlacer.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-28  |  12.3 KB  |  560 lines

  1. /* 
  2.  *  Deinterlacer.cpp - Original code by Donald Graft
  3.  *                                      neuron2@home.com.
  4.  *
  5.  *    Copyright (C) Alberto Vigata - January 2000
  6.  *
  7.  *  This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
  8.  *    
  9.  *  FlasKMPEG is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation; either version 2, or (at your option)
  12.  *  any later version.
  13.  *   
  14.  *  FlasKMPEG is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public License for more details.
  18.  *   
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with GNU Make; see the file COPYING.  If not, write to
  21.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  22.  *
  23.  */
  24.  
  25. #include "Deinterlacer.h"
  26. #include "debug.h"
  27.  
  28.  
  29. #define ASM_COPY(o,i,runsize)  __asm             \
  30. {                                    \
  31. __asm            mov ecx, runsize    \
  32. __asm            mov esi, i          \
  33. __asm           mov edi, o          \
  34. __asm            rep movsd           \
  35. }
  36.  
  37. typedef ui32 PixDim;
  38.  
  39.  
  40. int FlDeinterlacer::DeInterlaceRGB32(CFrame *source, CFrame *dest) {
  41.  
  42.     const int        bitpitch = m_mfd.bitpitch;
  43.     const long        pitch = source->GetPitch();
  44.   const long    src_pitch = source->GetPitch();
  45.   const long    dst_pitch = dest->GetPitch();
  46.     const PixDim    w = source->GetWidth();
  47.     const PixDim    h = source->GetHeight();
  48.     Pixel32 *        src = (Pixel32 *)source->GetBuffer();
  49.     Pixel32 *        dst = (Pixel32 *)dest->GetBuffer();
  50.  
  51.  
  52.     if(!source || !dest)
  53.         return 0;
  54.  
  55.     int x, y;
  56.     long prevValue;
  57.     Pixel32 p0, p1, p2;
  58.     long r, g, b, r0, g0, b0;
  59.     int *lumptr;
  60.  
  61.     /* If we are shifting field phase by one field... */
  62.     if (m_mfd.fieldShift)
  63.     {
  64.         /* This mode is used typically to clean up PAL video which
  65.            has erroneouslt been digitized with the field phase off by
  66.            one field. The result is that the frames look interlaced,
  67.            but really if we can phase shift by one field, we'll get back
  68.            the original progressive frames. This code does that and then
  69.            skips motion processing. */
  70.         /* Copy the even field of the current frame to the output. */
  71.         for (y = 0; y < h/2; y++)
  72.         {
  73.             //memcpy(dst, src, w*4);
  74.             ASM_COPY(src, dst, w);
  75.  
  76.             src = (Pixel *)((char *)src + 2 * src_pitch);
  77.             dst = (Pixel *)((char *)dst + 2 * src_pitch);
  78.         }
  79.         /* If this is not the first frame, copy the buffered odd field
  80.            of the last frame to the output. This creates a correct progressive
  81.            output frame. If this is the first frame, a buffered field is not
  82.            available, so interpolate the odd field from the current even field. */
  83.         if (m_mfd.first == TRUE)
  84.         {
  85.             src = (Pixel32 *)source->GetBuffer();
  86.             dst = (Pixel *)((char *)dest->GetBuffer() + dst_pitch);
  87.             for (y = 0; y < h/2; y++)
  88.             {
  89.                 //memcpy(dst, src, w*4);
  90.                 
  91.                 ASM_COPY(dst,src , w);
  92.  
  93.                 src = (Pixel *)((char *)src + 2 * src_pitch);
  94.                 dst = (Pixel *)((char *)dst + 2 * src_pitch);
  95.             }
  96.             m_mfd.first = FALSE;
  97.         }
  98.         else
  99.         {
  100.             lumptr = m_mfd.prevFrame + w;
  101.             dst = (Pixel *)((char *)dest->GetBuffer() + dst_pitch);
  102.             for (y = 0; y < h/2; y++)
  103.             {
  104.                 //memcpy(dst, lumptr, w*4);
  105.                 
  106.                 ASM_COPY(dst, lumptr, w);
  107.  
  108.                 lumptr += 2 * w;
  109.                 dst = (Pixel *)((char *)dst + 2 * dst_pitch);
  110.             }
  111.         }
  112.         /* Finally, save the odd field of the current frame in the buffer.
  113.            It will be used to creat the next frame. */
  114.         src = (Pixel *)((char *)source->GetBuffer() + src_pitch);
  115.         lumptr = m_mfd.prevFrame + w;
  116.         for (y = 0; y < h/2; y++)
  117.         {
  118.             //memcpy(lumptr, src, w*4);
  119.             
  120.             ASM_COPY(lumptr, src, w);
  121.  
  122.             lumptr += 2 * w;
  123.             src = (Pixel *)((char *)src + 2 * src_pitch);
  124.         }
  125.         return 0;
  126.     }
  127.  
  128.     /* End special mode code. Doing full motion-adaptive deinterlacing. */
  129.  
  130.     if (h<2) return 0;
  131.  
  132.     // Compute differences for all pixels by comparing each pixel
  133.     // to its corresponding pixel in the previous frame. Then do a threshold
  134.     // test of the difference to decide if the pixel is 'moving'.
  135.     // Then create an array of flags indicating pixels that have moved since
  136.     // the last frame.
  137.  
  138.     lumptr = m_mfd.prevFrame;
  139.     unsigned long *maskptr = m_mfd.moving + m_mfd.bitpitch;
  140.  
  141.     for (y = 1; y < h - 1; y++)
  142.     {
  143.         long pixmask = 0;
  144.  
  145.         src = (Pixel *)((char *)src + src_pitch);
  146.  
  147.         x = 0;
  148.         do
  149.         {
  150.             // Set the moving flag if the diff exceeds the configured
  151.             // threshold.
  152.             pixmask <<= 1;
  153.             prevValue = *lumptr;
  154.             *lumptr++ = src[x];
  155.             b = (src[x] & 0xff);
  156.             b0 = (prevValue & 0xff);
  157.             if (abs(b - b0) > m_mfd.threshold)
  158.                 goto moving;
  159.             r = (src[x] & 0xff0000) >> 16;
  160.             r0 = (prevValue & 0xff0000) >> 16;
  161.             if (abs(r - r0) > m_mfd.threshold)
  162.                 goto moving;
  163.             g = (src[x] & 0xff00)   >> 8;
  164.             g0 = (prevValue & 0xff00)   >> 8;
  165.             if (abs(g - g0) > m_mfd.threshold)
  166.                 goto moving;            
  167.             goto notmoving;
  168. moving:
  169.             pixmask |= 1;
  170. notmoving:
  171.             if (!(++x & 31))
  172.                 *maskptr++ = pixmask;
  173.         } while(x<w);
  174.  
  175.         if (x & 31)
  176.             *maskptr++ = pixmask << (-x&31);
  177.     }
  178.  
  179.     // Remove combing from the motion areas and render.
  180.     // The first line gets a free ride.
  181.     src = (Pixel32 *)source->GetBuffer();
  182.     dst = (Pixel32 *)dest->GetBuffer();
  183.     //memcpy(dst, src, w*4);
  184.  
  185.     ASM_COPY(dst, src, w);
  186.  
  187.     maskptr = m_mfd.moving;
  188.  
  189.     for (y = 1; y < h - 1; y++)
  190.     {
  191.         unsigned long mask;
  192.  
  193.         src = (Pixel *)((char *)src + src_pitch);
  194.         dst = (Pixel *)((char *)dst + dst_pitch);
  195.  
  196.         if (m_mfd.motionOnly) {
  197.             if (m_mfd.Blend) {
  198.                 x = 0;
  199.                 do {
  200.                     if (!(x & 31)) {
  201.                         mask = maskptr[bitpitch] | maskptr[0] | maskptr[bitpitch*2];
  202.                         ++maskptr;
  203.                     }
  204.  
  205.                     if ((signed long)mask >= 0)
  206.                         dst[x] = 0;
  207.                     else {
  208.                         
  209.                         /* Blend fields. */
  210.                         p0 = src[x];
  211.                         p0 &= 0x00fefefe;
  212.  
  213.                         p1 = ((Pixel32 *)(((char *)src)-pitch))[x];
  214.                         p1 &= 0x00fcfcfc;
  215.  
  216.                         p2 = ((Pixel32 *)(((char *)src)+pitch))[x];
  217.                         p2 &= 0x00fcfcfc;
  218.  
  219.                         dst[x] = (p0>>1) + (p1>>2) + (p2>>2);
  220.                     }
  221.                     mask <<= 1;
  222.  
  223.                 } while(++x<w);
  224.             } else {
  225.                 x = 0;
  226.                 do {
  227.                     if (!(x & 31)) {
  228.                         mask = maskptr[bitpitch] | maskptr[0] | maskptr[bitpitch*2];
  229.                         ++maskptr;
  230.                     }
  231.  
  232.                     if ((signed long)mask >= 0)
  233.                         dst[x] = 0x0;
  234.                     else if (y&1) {
  235.                         p1 = ((Pixel32 *)(((char *)src)-pitch))[x];
  236.                         p1 &= 0x00fefefe;
  237.  
  238.                         p2 = ((Pixel32 *)(((char *)src)+pitch))[x];
  239.                         p2 &= 0x00fefefe;
  240.                         dst[x] = (p1>>1) + (p2>>1);
  241.                     } else
  242.                         dst[x] = src[x];
  243.  
  244.                     mask <<= 1;
  245.  
  246.                 } while(++x<w);
  247.             }
  248.         } else {
  249.             if (m_mfd.Blend) {
  250.                 x = 0;
  251.                 do {
  252.                     if (!(x & 31)) {
  253.                         mask = maskptr[bitpitch] | maskptr[0] | maskptr[bitpitch*2];
  254.                         ++maskptr;
  255.                     }
  256.  
  257.                     if ((signed long)mask >= 0)
  258.                         dst[x] = src[x];
  259.                     else {
  260.  
  261.                         /* Blend fields. */
  262.                         p0 = src[x];
  263.                         p0 &= 0x00fefefe;
  264.  
  265.                         p1 = ((Pixel32 *)(((char *)src)-pitch))[x];
  266.                         p1 &= 0x00fcfcfc;
  267.  
  268.                         p2 = ((Pixel32 *)(((char *)src)+pitch))[x];
  269.                         p2 &= 0x00fcfcfc;
  270.  
  271.                         dst[x] = (p0>>1) + (p1>>2) + (p2>>2);
  272.                     }
  273.                     mask <<= 1;
  274.  
  275.                 } while(++x<w);
  276.             } else {
  277.                 // Doing line interpolate. Thus, even lines are going through
  278.                 // for moving and non-moving mode. Odd line pixels will be subject
  279.                 // to the motion test.
  280.                 if (y&1) {
  281.                     x = 0;
  282.                     do {
  283.                         if (!(x & 31)) {
  284.                             mask = maskptr[bitpitch] | maskptr[0] | maskptr[bitpitch*2];
  285.                             ++maskptr;
  286.                         }
  287.  
  288.                         if ((signed long)mask >= 0)
  289.                             dst[x] = src[x];
  290.                         else {
  291.                             p1 = ((Pixel32 *)(((char *)src)-pitch))[x];
  292.                             p1 &= 0x00fefefe;
  293.  
  294.                             p2 = ((Pixel32 *)(((char *)src)+pitch))[x];
  295.                             p2 &= 0x00fefefe;
  296.  
  297.                             dst[x] = (p1>>1) + (p2>>1);
  298.                         }
  299.  
  300.                         mask <<= 1;
  301.  
  302.                     } while(++x<w);
  303.                 } else {
  304.                     // Even line; pass it through.
  305.                     //memcpy(dst, src, w*4);
  306.  
  307.                     ASM_COPY(dst, src, w);
  308.  
  309.                     maskptr += bitpitch;
  310.                 }
  311.             }
  312.         }
  313.  
  314.     }
  315.     
  316.     // The last line gets a free ride.
  317.     src = (Pixel *)((char *)src + src_pitch);
  318.     dst = (Pixel *)((char *)dst + dst_pitch);
  319.     memcpy(dst, src, w*4);
  320.  
  321.     return 0;
  322. }
  323.  
  324. void FlDeinterlacer::BlendFrame(Pixel8 *src, Pixel8 *dst, int w, int h, int pitch)
  325. {
  326.   __asm{
  327.  
  328.     mov esi, src
  329.     mov edi, dst
  330.     mov ebx, pitch
  331.     mov ecx, w
  332.     mov eax, h
  333.  
  334.     dec eax ;
  335.  
  336. row_loop:
  337.     mov ecx, w
  338.     shr ecx, 2 
  339.  
  340.     pxor mm2, mm2
  341.     pxor mm3, mm3
  342.  
  343. col_loop:
  344.  
  345.  
  346.     movd mm0, [esi]      ;grab 4 pixels first line
  347.     movd mm1, [esi + ebx] ;grab 4 pixels next line
  348.  
  349.     punpcklbw mm0, mm2     ;first 4 pels
  350.     punpcklbw mm1, mm3
  351.  
  352.     paddw mm0, mm1
  353.     add esi, 4
  354.  
  355.     psrlw mm0, 1
  356.     packuswb mm0, mm0
  357.  
  358.     movd [edi], mm0
  359.     add edi, 4
  360.  
  361.  
  362.     dec ecx
  363.     jnz col_loop
  364.  
  365.     dec eax
  366.     jnz row_loop
  367.  
  368.  
  369. ; copy the last line
  370.     mov ecx, w
  371.     shr ecx, 2
  372. last_line:
  373.  
  374.     movd mm0, [esi]
  375.     movd [edi], mm0
  376.  
  377.     add esi, 4
  378.     add edi, 4
  379.  
  380.     dec ecx
  381.     jnz last_line
  382.  
  383.     emms
  384.  
  385.   }
  386.   return;
  387. }
  388.  
  389. int FlDeinterlacer::DeInterlaceYV12(CFrame *source, CFrame *dest) 
  390. {
  391.   int w = source->GetWidth();
  392.   int h = source->GetHeight();
  393.   int hw = w>>1;
  394.   int hh = h>>1;
  395.   int ysize = w*h;
  396.   int crsize = hh*hw;
  397.   Pixel8 *pSrc = (Pixel8 *)source->GetBuffer();
  398.   Pixel8 *pDst = (Pixel8 *)dest->GetBuffer();
  399.  
  400.   // Y
  401.   BlendFrame( pSrc, pDst, w, h, w );
  402.   // V
  403.   BlendFrame( pSrc + ysize, 
  404.              pDst + ysize, hw, hh, hw );
  405.   // U
  406.   BlendFrame( pSrc + ysize + crsize,
  407.               pDst + ysize + crsize, 
  408.               hw, hh, hw);
  409.  
  410.  
  411.   return 0;
  412. }
  413.  
  414. int FlDeinterlacer::DeInterlace(CFrame *source, CFrame *dest) 
  415. {
  416.   if(!source || !dest)
  417.     return 0;
  418.  
  419.   switch( source->GetFormat() )
  420.   {
  421.   case FRAME_RGB32:
  422.     return DeInterlaceRGB32(source, dest);
  423.     break;
  424.   case FRAME_YV12:
  425.     return DeInterlaceYV12( source, dest );
  426.     break;
  427.   default:
  428.     dest->SetFrame( source );
  429.     break;
  430.   }
  431.   return 1;
  432. }
  433.  
  434.  
  435. FlDeinterlacer::FlDeinterlacer()
  436. {
  437.   m_bConfigured = false;
  438. }
  439.  
  440. int FlDeinterlacer::Configure(void *conf, int confsize )
  441. {
  442.   FLASSERT( confsize==sizeof(TDeinterlacerConfig) )
  443.   TDeinterlacerConfig *rc = (TDeinterlacerConfig *)conf;
  444.  
  445.   m_cfg = *rc;
  446.   m_bConfigured = true;
  447.   return flfil_ok;
  448. }
  449.  
  450. int FlDeinterlacer::ValFilterConf(flfilter_conf *fc )
  451. {
  452.   if(!m_bConfigured)
  453.   {
  454.     DBG_STR((str, "FlDeinterlacer::Validate - You need to configure first\n"))
  455.       return flfil_error;
  456.   }
  457.   
  458.   // if input is 0,0 is not valid
  459.   if( fc->iw==0 ||
  460.       fc->ih==0 )
  461.       return flfil_error;
  462.  
  463.   // the same delay
  464.   fc->od = fc->id;
  465.  
  466.   // output res
  467.   fc->ow = fc->iw;
  468.   fc->oh = fc->ih;
  469.  
  470.   // no on-place, no lag
  471.   fc->op = 0;
  472.   fc->olag = 0;
  473.   fc->oprovided = 0;
  474.   fc->ocanmodify = 1;
  475.  
  476.   // store this validation data for start
  477.   m_fc = *fc;
  478.   
  479.   return 1;
  480. }
  481.  
  482. int FlDeinterlacer::GetFilterConf( flfilter_conf *fc )
  483. {
  484.   if(!m_bConfigured)
  485.   {
  486.     DBG_STR((str, "FlDeinterlacer::GetConf - You need to configure first\n"))
  487.       return 0;
  488.   }
  489.   
  490.   if(!fc)
  491.     return flfil_error;
  492.   
  493.   *fc = m_fc;
  494.   
  495.   return 1;
  496. }
  497.  
  498. int FlDeinterlacer::StartSimple()
  499. {
  500.     if(!m_bConfigured)
  501.         return 0;
  502.  
  503.   int w = m_fc.iw;
  504.   int h = m_fc.ih;
  505.  
  506.   switch( m_fc.iformat )
  507.   {
  508.     case FRAME_RGB32:
  509.         m_mfd.prevFrame        = new int[ w*h ];
  510.         m_mfd.fieldShift     = 0;
  511.         m_mfd.Blend          = m_cfg.blend;
  512.         m_mfd.threshold      = m_cfg.threshold;
  513.         m_mfd.motionOnly     = 0;
  514.  
  515.         memset(m_mfd.prevFrame, 0, w*h*sizeof(int));
  516.  
  517.  
  518.         m_mfd.bitpitch        = (w + 32 - 1) / 32;
  519.         m_mfd.moving            = new unsigned long[m_mfd.bitpitch * h];
  520.         memset(m_mfd.moving, 0, sizeof(unsigned long)*m_mfd.bitpitch * h);
  521.         m_mfd.skip = FALSE;
  522.         m_mfd.first = TRUE;
  523.       break;
  524.     case FRAME_YV12:
  525.       // nothing to do for YV12
  526.       break;
  527.   }
  528.  
  529.   return flfil_ok;
  530. }
  531.  
  532. int FlDeinterlacer::ProcessSimple(CFrame *in, CFrame *out)
  533. {
  534.   DeInterlace(in, out);
  535.   return flfil_ok;
  536. }
  537.  
  538. int FlDeinterlacer::StopSimple()
  539. {
  540.   switch( m_fc.iformat )
  541.   {
  542.     case FRAME_RGB32:
  543.       if( m_mfd.prevFrame )
  544.       {
  545.         delete[] m_mfd.prevFrame;    
  546.         m_mfd.prevFrame = NULL;
  547.       }
  548.         if( m_mfd.moving )
  549.       {
  550.           delete[] m_mfd.moving;
  551.         m_mfd.moving = NULL;
  552.       }
  553.       break;
  554.     case FRAME_YV12:
  555.       // nothing to do for YV12
  556.       break;
  557.   }
  558.  
  559.   return flfil_ok;
  560. }