VideoCodec/Modules/Transform/MacroblockHandler.cpp

#include "MacroblockHandler.h" namespace VideoCodec {    MacroblockHandler::MacroblockHandler() : Module(MACROBLOCK_HANDLER_MODULE_ID)    {    }        MacroblockHandler::~MacroblockHandler()    {    }        ConfigurationStatus MacroblockHandler::Configure(ConfigurationElement* configuration)    {       this->mbLayout = PIXEL_LAYOUT_MB_FOUR_TWO_ZERO;       this->colourResizeFilter = SIMPLE_COLOUR_RESIZE_FILTER;              return MODULE_CONFIGURATION_OK;    }        void MacroblockHandler::ConvertSignedScanToSignedMacroblockLayout(PictureInfo* picture)    {       // See Constants.h for a description of this MB layout.       if (this->mbLayout == PIXEL_LAYOUT_MB_FOUR_TWO_ZERO)       {          // Make sure that the input has the correct dimensions.          if ((picture->GetPixelsX() % 16) != 0             || (picture->GetPixelsY() % 16) != 0)          {             Logger::LogMessage("Error: The image could not be converted into macroblocks; the dimensions are not valid for the configured macroblock size.");             return;          }                    // Make sure the colour space of the input scan data is the correct format.          if (picture->GetColourFormat() != COLOUR_FORMAT_YUV)             Logger::LogMessage("Warning: Unexpected colour format in macroblock handler. Wanted YUV format.");                    BlockCount blockRows = picture->GetPixelsY() >> 4;          BlockCount blockColumns = picture->GetPixelsX() >> 4;                    // Pointer into the scan data.          SignedShort* scanData = picture->GetSignedShortData();          int scanLocation = 0;          PixelCount stride = picture->GetPixelsX();                    // The new frame data.          // For each block in the picture (|blocks| == blockRows * blockColumns)          // store six (4 * luminance, Cb and Cr)          // groups of eight by eight bytes.          SignedShort* values = new SignedShort[blockRows * blockColumns * 6 * 8 * 8];                    // Keep track of the current location.          SignedShort* currentBlock = values;          for (int y = 0; y < blockRows; y++)          {             for (int x = 0; x < blockColumns; x++)             {                scanLocation = ((y << 4) * stride) + (x << 4);                                // Copy pixels from the luminance channel into the first four sets of 8 * 8.                for (int bY = 0; bY < 8; bY++)                   for (int bX = 0; bX < 8; bX++)                   {                      // Luminance 0:                      currentBlock[(0 * 8 * 8) + (bY << 3) + bX] =                         scanData[(scanLocation + (bY * stride) + bX) * 3];                      // Luminance 1:                      currentBlock[(1 * 8 * 8) + (bY << 3) + bX] =                         scanData[(scanLocation + (bY * stride) + (bX + 8)) * 3];                      // Luminance 2:                      currentBlock[(2 * 8 * 8) + (bY << 3) + bX] =                         scanData[(scanLocation + ((bY + 8) * stride) + bX) * 3];                      // Luminance 3:                      currentBlock[(3 * 8 * 8) + (bY << 3) + bX] =                         scanData[(scanLocation + ((bY + 8) * stride) + (bX + 8)) * 3];                                               if (this->colourResizeFilter == SIMPLE_COLOUR_RESIZE_FILTER)                      {                         // In this filter, average out the colour from the four pixels.                         int quadBaseIndex = scanLocation + ((bY << 1) * stride) + (bX << 1);                                                  // Cb:                         currentBlock[(4 * 8 * 8) + (bY << 3) + bX] = (scanData[quadBaseIndex * 3 + 1] + scanData[(quadBaseIndex + 1) * 3 + 1] + scanData[(quadBaseIndex + stride) * 3 + 1] + scanData[(quadBaseIndex + stride + 1) * 3 + 1]) / 4;                                                  // Cr:                         currentBlock[(5 * 8 * 8) + (bY << 3) + bX] = (scanData[quadBaseIndex * 3 + 2] + scanData[(quadBaseIndex + 1) * 3 + 2] + scanData[(quadBaseIndex + stride) * 3 + 2] + scanData[(quadBaseIndex + stride + 1) * 3 + 2]) / 4;                      }                      else                      {                         Logger::LogMessage("Error: Invalid colour channel resizing filter.");                         return;                      }                   }                                currentBlock += (8 * 8 * 6);             }          }                    // Store the new values in the picture. The old data will be deleted.          picture->SetSignedShortData(values, blockRows * blockColumns * 6 * 64);          picture->SetBlockRows(blockRows);          picture->SetBlockColumns(blockColumns);          picture->SetPixelLayout(PIXEL_LAYOUT_MB_FOUR_TWO_ZERO);       }       else       {          Logger::LogMessage("Error: Unsupported macroblock layout selected.");          return;       }    }        void MacroblockHandler::ConvertScanToMacroblockLayout(PictureInfo* picture)    {       // See Constants.h for a description of this MB layout.       if (this->mbLayout == PIXEL_LAYOUT_MB_FOUR_TWO_ZERO)       {          // Make sure that the input has the correct dimensions.          if ((picture->GetPixelsX() % 16) != 0             || (picture->GetPixelsY() % 16) != 0)          {             Logger::LogMessage("Error: The image could not be converted into macroblocks; the dimensions are not valid for the configured macroblock size.");             return;          }                    // Make sure the colour space of the input scan data is the correct format.          if (picture->GetColourFormat() != COLOUR_FORMAT_YUV)             Logger::LogMessage("Warning: Unexpected colour format in macroblock handler. Wanted YUV format.");                    BlockCount blockRows = picture->GetPixelsY() >> 4;          BlockCount blockColumns = picture->GetPixelsX() >> 4;                    // Pointer into the scan data.          UnsignedByte* scanData = picture->GetUnsignedByteData();          int scanLocation = 0;          PixelCount stride = picture->GetPixelsX();                    // The new frame data.          // For each block in the picture (|blocks| == blockRows * blockColumns)          // store six (4 * luminance, Cb and Cr)          // groups of eight by eight bytes.          UnsignedByte* values = new UnsignedByte[blockRows * blockColumns * 6 * 8 * 8];                    // Keep track of the current location.          UnsignedByte* currentBlock = values;          for (int y = 0; y < blockRows; y++)          {             for (int x = 0; x < blockColumns; x++)             {                scanLocation = ((y << 4) * stride) + (x << 4);                                // Copy pixels from the luminance channel into the first four sets of 8 * 8.                for (int bY = 0; bY < 8; bY++)                   for (int bX = 0; bX < 8; bX++)                   {                      // Luminance 0:                      currentBlock[(0 * 8 * 8) + (bY << 3) + bX] =                         scanData[(scanLocation + (bY * stride) + bX) * 3];                      // Luminance 1:                      currentBlock[(1 * 8 * 8) + (bY << 3) + bX] =                         scanData[(scanLocation + (bY * stride) + (bX + 8)) * 3];                      // Luminance 2:                      currentBlock[(2 * 8 * 8) + (bY << 3) + bX] =                         scanData[(scanLocation + ((bY + 8) * stride) + bX) * 3];                      // Luminance 3:                      currentBlock[(3 * 8 * 8) + (bY << 3) + bX] =                         scanData[(scanLocation + ((bY + 8) * stride) + (bX + 8)) * 3];                                               if (this->colourResizeFilter == SIMPLE_COLOUR_RESIZE_FILTER)                      {                         // In this filter, average out the colour from the four pixels.                         int quadBaseIndex = scanLocation + ((bY << 1) * stride) + (bX << 1);                                                  // Cb:                         currentBlock[(4 * 8 * 8) + (bY << 3) + bX] = (scanData[quadBaseIndex * 3 + 1] + scanData[(quadBaseIndex + 1) * 3 + 1] + scanData[(quadBaseIndex + stride) * 3 + 1] + scanData[(quadBaseIndex + stride + 1) * 3 + 1]) >> 2;                                                  // Cr:                         currentBlock[(5 * 8 * 8) + (bY << 3) + bX] = (scanData[quadBaseIndex * 3 + 2] + scanData[(quadBaseIndex + 1) * 3 + 2] + scanData[(quadBaseIndex + stride) * 3 + 2] + scanData[(quadBaseIndex + stride + 1) * 3 + 2]) >> 2;                      }                      else                      {                         Logger::LogMessage("Error: Invalid colour channel resizing filter.");                         return;                      }                   }                                currentBlock += (8 * 8 * 6);             }          }                    // Store the new values in the picture. The old data will be deleted.          picture->SetUnsignedByteData(values, blockRows * blockColumns * 6 * 64);          picture->SetBlockRows(blockRows);          picture->SetBlockColumns(blockColumns);          picture->SetPixelLayout(PIXEL_LAYOUT_MB_FOUR_TWO_ZERO);       }       else       {          Logger::LogMessage("Error: Unsupported macroblock layout selected.");          return;       }    }        void MacroblockHandler::ConvertSignedMacroblockToSignedScanLayout(PictureInfo* picture)    {       if (picture->GetPixelLayout() == PIXEL_LAYOUT_MB_FOUR_TWO_ZERO)       {          SignedShort* blockValues = picture->GetSignedShortData();          BlockCount blockRows = picture->GetBlockRows();          BlockCount blockColumns = picture->GetBlockColumns();                    // Allocate space for the new scan order image.          // Four luminance 8 * 8 blocks go into each 16 * 16 macroblock region.          // Two colour channels are expanded into each 16 * 16 macroblock region.          PixelCount imageWidth = picture->GetBlockColumns() << 4;          PixelCount imageHeight = picture->GetBlockRows() << 4;          SignedShort* scanValues = new SignedShort[imageWidth * imageHeight * 3];                    // Iterate over the stored macroblocks, transferring the information in each one to the scan order picture.          for (int y = 0; y < blockRows; y++)          {             for (int x = 0; x < blockColumns; x++)             {                // Get a pointer to the current macroblock.                SignedShort* mb = blockValues + (x + (y * blockColumns)) * (6 * 8 * 8);                                // Copy the luminance channels in.                for (int bY = 0; bY < 8; bY++)                   for (int bX = 0; bX < 8; bX++)                   {                      // Luminance 0, 1, 2 and 3.                      scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * imageWidth) + bX) * 3] =                         mb[(0 * 8 * 8) + (bY * 8) + bX];                      scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * imageWidth) + (bX + 8)) * 3] =                         mb[(1 * 8 * 8) + (bY * 8) + bX];                      scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY + 8) * imageWidth) + bX) * 3] =                         mb[(2 * 8 * 8) + (bY * 8) + bX];                      scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY + 8) * imageWidth) + (bX + 8)) * 3] =                         mb[(3 * 8 * 8) + (bY * 8) + bX];                   }                                // Expand and copy the colour channels in.                if (this->colourResizeFilter == SIMPLE_COLOUR_RESIZE_FILTER)                {                   for (int bY = 0; bY < 8; bY++)                      for (int bX = 0; bX < 8; bX++)                      {                         // Cb and Cr:                         scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * 2 * imageWidth) + (bX * 2)) * 3 + 1] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * 2 * imageWidth) + (bX * 2 + 1)) * 3 + 1] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY * 2 + 1) * imageWidth) + (bX * 2)) * 3 + 1] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY * 2 + 1) * imageWidth) + (bX * 2 + 1)) * 3 + 1] =                            mb[(4 * 8 * 8) + (bY * 8) + bX];                         scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * 2 * imageWidth) + (bX * 2)) * 3 + 2] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * 2 * imageWidth) + (bX * 2 + 1)) * 3 + 2] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY * 2 + 1) * imageWidth) + (bX * 2)) * 3 + 2] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY * 2 + 1) * imageWidth) + (bX * 2 + 1)) * 3 + 2] =                            mb[(5 * 8 * 8) + (bY * 8) + bX];                      }                }                else                {                   Logger::LogMessage("Error: Invalid colour channel resizing filter.");                   return;                }             }          }                    // Store the scan ordered data back in the picture.          picture->SetSignedShortData(scanValues, 3 * imageWidth * imageHeight);          picture->SetPixelLayout(PIXEL_LAYOUT_SCAN);       }       else       {          Logger::LogMessage("Error: Unsupported macroblock layout selected.");          return;       }    }        void MacroblockHandler::ConvertMacroblockToScanLayout(PictureInfo* picture)    {       if (picture->GetPixelLayout() == PIXEL_LAYOUT_MB_FOUR_TWO_ZERO)       {          UnsignedByte* blockValues = picture->GetUnsignedByteData();          BlockCount blockRows = picture->GetBlockRows();          BlockCount blockColumns = picture->GetBlockColumns();                    // Allocate space for the new scan order image.          // Four luminance 8 * 8 blocks go into each 16 * 16 macroblock region.          // Two colour channels are expanded into each 16 * 16 macroblock region.          PixelCount imageWidth = picture->GetBlockColumns() << 4;          PixelCount imageHeight = picture->GetBlockRows() << 4;          UnsignedByte* scanValues = new UnsignedByte[imageWidth * imageHeight * 3];                    // Iterate over the stored macroblocks, transferring the information in each one to the scan order picture.          for (int y = 0; y < blockRows; y++)          {             for (int x = 0; x < blockColumns; x++)             {                // Get a pointer to the current macroblock.                UnsignedByte* mb = blockValues + (x + (y * blockColumns)) * (6 * 8 * 8);                                // Copy the luminance channels in.                for (int bY = 0; bY < 8; bY++)                   for (int bX = 0; bX < 8; bX++)                   {                      // Luminance 0, 1, 2 and 3.                      scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * imageWidth) + bX) * 3] =                         mb[(0 * 8 * 8) + (bY * 8) + bX];                      scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * imageWidth) + (bX + 8)) * 3] =                         mb[(1 * 8 * 8) + (bY * 8) + bX];                      scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY + 8) * imageWidth) + bX) * 3] =                         mb[(2 * 8 * 8) + (bY * 8) + bX];                      scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY + 8) * imageWidth) + (bX + 8)) * 3] =                         mb[(3 * 8 * 8) + (bY * 8) + bX];                   }                                // Expand and copy the colour channels in.                if (this->colourResizeFilter == SIMPLE_COLOUR_RESIZE_FILTER)                {                   for (int bY = 0; bY < 8; bY++)                      for (int bX = 0; bX < 8; bX++)                      {                         // Cb and Cr:                         scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * 2 * imageWidth) + (bX * 2)) * 3 + 1] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * 2 * imageWidth) + (bX * 2 + 1)) * 3 + 1] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY * 2 + 1) * imageWidth) + (bX * 2)) * 3 + 1] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY * 2 + 1) * imageWidth) + (bX * 2 + 1)) * 3 + 1] =                            mb[(4 * 8 * 8) + (bY * 8) + bX];                         scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * 2 * imageWidth) + (bX * 2)) * 3 + 2] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + (bY * 2 * imageWidth) + (bX * 2 + 1)) * 3 + 2] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY * 2 + 1) * imageWidth) + (bX * 2)) * 3 + 2] =                            scanValues[((y * 16 * imageWidth) + (x * 16) + ((bY * 2 + 1) * imageWidth) + (bX * 2 + 1)) * 3 + 2] =                            mb[(5 * 8 * 8) + (bY * 8) + bX];                      }                }                else                {                   Logger::LogMessage("Error: Invalid colour channel resizing filter.");                   return;                }             }          }                    // Store the scan ordered data back in the picture.          picture->SetUnsignedByteData(scanValues, 3 * imageWidth * imageHeight);          picture->SetPixelLayout(PIXEL_LAYOUT_SCAN);       }       else       {          Logger::LogMessage("Error: Unsupported macroblock layout selected.");          return;       }    } }