Logo Search packages:      
Sourcecode: camstream version File versions  Download package

DCTPanel.cc

/**
  \class CDCTPanel
  \brief This class will compress or decompress a YUV panel using the DCT
  
  This class does both forward and inverse DCT conversion of a YUV panel;
  the direction is specified at creation time in the constructor. In theory
  InverseDCT(ForwardDCT(yuv)) = yuv, that is, an image can be converted to
  DCT and back to its original.
*/

#include <stdio.h>

#include "DCTPanel.h"

/**
  \brief Constructor.
  \param base_panel The yuv panel we use as our basis for calculation.
  \param inv When true, this class performs the IDCT, otherwise FDCT
  \param name Name for this panel
  \param desc Description for this panel
  
 */  
00023 CDCTPanel::CDCTPanel(CCamPanel *base_panel, bool inv, const char *name, const char *desc)
      : CCamPanel(name, desc, YUV420)
{
   pBasePanel = NULL;
   pTilesY = NULL;
   pTilesUV = NULL;
   TilesDefault = true;

   Inverse = inv;
   pBasePanel = base_panel;
   if (pBasePanel == NULL)
     return;
   if (pBasePanel->GetPanelType() != YUV420) {
     pBasePanel = NULL;
     return;
   }
   
   ConnectUsage(pBasePanel);
   ConnectResizes(pBasePanel);
   SetSize(pBasePanel->GetImageSize());
}

/**
  \brief Destructor

  Cleans up tiles.
*/

00051 CDCTPanel::~CDCTPanel()
{
   if (TilesDefault) {
     delete pTilesY;
     delete pTilesUV;
   }
}

// private

/** 
  \brief Initialize CCamTile structures depending on image size
  
  The function creates the Tiles and initializes the image offsets.

  Each tile is 8x8 pixels; the input pixels are positioned in a linear
  block of 8x8 pixels, and so are the output pixels. You can set your own 
  coordinates by using SetTiles()

*/
00071 void CDCTPanel::CreateTiles()
{
   int i, k, l, x, y;
   int w8, h8;

printf("CDCTPanel::CreateTiles(%d, %d)\n", image_w, image_h);
   tiles_y = (image_w * image_h) / 64;
   tiles_uv = tiles_y >> 2;

   delete pTilesY; // Clean up old tiles
   delete pTilesUV;
   pTilesY = new CCamTile[tiles_y];
   pTilesUV = new CCamTile[tiles_uv];
   if (pTilesY == NULL || pTilesUV == NULL)
     return;

   i = 0;
   w8 = image_w >> 3; // 1/8th
   h8 = image_h >> 3;
   for (y = 0; y < h8; y++) {
      for (x = 0; x < w8; x++) {
         /* Record location */ 
         pTilesY[i].x = x << 3;
         pTilesY[i].y = y << 3;
         /* Calculate offsets */
         for (l = 0; l < 8; l++) {
            for (k = 0; k < 8; k++) {
               /* 8x8 blocks */
               pTilesY[i].out_offsets[l][k] = pTilesY[i].in_offsets[l][k]  = ((y << 3) + l) * image_w + (x << 3) + k;
            }
         }
         i++;
      }
   }

   // Repeat for U/V tiles, which are only quarter size   
   i = 0;
   w8 = half_w >> 3; // 1/8th
   h8 = half_h >> 3;
   for (y = 0; y < h8; y++) {
      for (x = 0; x < w8; x++) {
         /* Record location */ 
         pTilesUV[i].x = x << 3;
         pTilesUV[i].y = y << 3;
         /* Calculate offsets */
         for (l = 0; l < 8; l++) {
            for (k = 0; k < 8; k++) {
               /* 8x8 blocks */
               pTilesUV[i].out_offsets[l][k] = pTilesUV[i].in_offsets[l][k]  = ((y << 3) + l) * half_w + (x << 3) + k;
            }
         }
         i++;
      }
   }
}



// public

/**
  \brief Set tiles coordinates
  
  In case you want your own ordering of input-output pixels, or want to 
  share the arrays, use this function to set two arrays of CCamTiles
  for the Y and UV panels resp. If you supply two NULL pointers CDCTPanel
  switches back to its default tiles.
*/
  
00140 void CDCTPanel::SetTiles(CCamTile *tilesy, CCamTile *tilesuv)
{
   TilesDefault = false;
   delete pTilesY;
   delete pTilesUV;
   pTilesY = tilesy;
   pTilesUV = tilesuv;
   if (pTilesY == NULL && pTilesUV == NULL) {
     TilesDefault = true;
     CreateTiles();
   }
}


// public slots

/**
  \brief Called when the base panel image is updated. Starts DCT calculation.
 */

00160 void CDCTPanel::UpdatePanel()
{
   int t;
   CCamTile *pCurrent;
   uchar *src_buffer, *dst_buffer;

   if (pBasePanel == NULL)
     return;

   if (IsVisible() || IsUsed()) {
     /* Y panel */ 
     src_buffer = pBasePanel->GetImage(0).bits();
     dst_buffer = ImgY.bits();
     pCurrent = pTilesY;
     for (t = 0; t < tiles_y; t++) {
        if (Inverse)
          pCurrent->CalculateInverse(dst_buffer, src_buffer);
        else
          pCurrent->CalculateForward(dst_buffer, src_buffer);
        pCurrent++;
     }

     /* U panel */   
     src_buffer = pBasePanel->GetImage(1).bits();
     dst_buffer = ImgU.bits();
     pCurrent = pTilesUV;
     for (t = 0; t < tiles_uv; t++) {
        if (Inverse)
          pCurrent->CalculateInverse(dst_buffer, src_buffer);
        else
          pCurrent->CalculateForward(dst_buffer, src_buffer);
        pCurrent++;
     }

     /* V panel */
     src_buffer = pBasePanel->GetImage(2).bits();
     dst_buffer = ImgV.bits();
     pCurrent = pTilesUV;
     for (t = 0; t < tiles_uv; t++) {
        if (Inverse)
          pCurrent->CalculateInverse(dst_buffer, src_buffer);
        else
          pCurrent->CalculateForward(dst_buffer, src_buffer);
        pCurrent++;
     }
     
     emit Updated();
   }
}


/** 
  \brief [overloaded] Set size, create tiles
 */
00214 void CDCTPanel::SetSize(const QSize &ns)
{
   CCamPanel::SetSize(ns);
   if (TilesDefault)
     CreateTiles();
}

Generated by  Doxygen 1.6.0   Back to index