theonlineoasis

VideoCodec/Modules/Quantization/DCTCoefficientQuantizer.cpp

#include "DCTCoefficientQuantizer.h" namespace VideoCodec {    /*     * From JPEG for Luma:     *            *    {16, 11, 10, 16, 24, 40, 51, 61,     * 12, 12, 14, 19, 26, 58, 60, 55,     * 14, 13, 16, 24, 40, 57, 69, 56,     *   14, 17, 22, 29, 51, 87, 80, 62,     *   18, 22, 37, 56, 68, 109, 103, 77,     *   24, 35, 55, 64, 81, 104, 113, 92,     *   49, 64, 78, 87, 103, 121, 120, 101,     *   72, 92, 95, 98,   112, 100, 103, 99};     *     * For chroma:     *     *   {17, 18, 24, 47, 99, 99, 99, 99,     *   18, 21, 26, 66, 99, 99, 99, 99,     *   24, 26, 56, 99, 99, 99, 99, 99,     *   47, 66, 99, 99, 99, 99, 99, 99,     *   99, 99, 99, 99, 99, 99, 99, 99,     *   99, 99, 99, 99, 99, 99, 99, 99,     *   99, 99, 99, 99, 99, 99, 99, 99,     *   99, 99, 99, 99, 99, 99, 99, 99};     *     * The tables below come from the MPEG-4 standard.     */        // Standardized quantization tables.    static int dctStandardQuantizationLumaInteger[64] =        {8, 17, 18, 19, 21, 23, 25, 27,        17, 18, 19, 21, 23, 25, 27, 28,        20, 21, 22, 23, 24, 26, 28, 30,        21, 22, 23, 24, 26, 28, 30, 32,        22, 23, 24, 26, 28, 30, 32, 35,        23, 24, 26, 28, 30, 32, 35, 38,        25, 26, 28, 30, 32, 35, 38, 41,        27, 28, 30, 32, 35, 38, 41, 45};    static int dctStandardQuantizationChromaInteger[64] =        {8, 17, 18, 19, 21, 23, 25, 27,        17, 18, 19, 21, 23, 25, 27, 28,        20, 21, 22, 23, 24, 26, 28, 30,        21, 22, 23, 24, 26, 28, 30, 32,        22, 23, 24, 26, 28, 30, 32, 35,        23, 24, 26, 28, 30, 32, 35, 38,        25, 26, 28, 30, 32, 35, 38, 41,        27, 28, 30, 32, 35, 38, 41, 45};        static int dctInterQuantizationInteger[64] =       {16, 17, 18, 19, 20, 21, 22, 23,       17, 18, 19, 20, 21, 22, 23, 24,       18, 19, 20, 21, 22, 23, 24, 25,       19, 20, 21, 22, 23, 24, 26, 27,       20, 21, 22, 23, 25, 26, 27, 28,       21, 22, 23, 24, 26, 27, 28, 30,       22, 23, 24, 26, 27, 28, 30, 31,       23, 24, 25, 27, 28, 30, 31, 33};        DCTCoefficientQuantizer::DCTCoefficientQuantizer() : Module(DCT_COEFFICIENT_QUANTIZER_MODULE_ID)    {    }        DCTCoefficientQuantizer::~DCTCoefficientQuantizer()    {    }        void DCTCoefficientQuantizer::SetQuantizationMethod(DCTCoefficientQuantizationMethod intraQuantizationMethod, DCTCoefficientQuantizationMethod interQuantizationMethod)    {       this->intraQuantizationMethod = intraQuantizationMethod;       this->interQuantizationMethod = interQuantizationMethod;    }        void DCTCoefficientQuantizer::SetIntraQuantizationMethod(DCTCoefficientQuantizationMethod intraQuantizationMethod)    {       this->intraQuantizationMethod = intraQuantizationMethod;    }        void DCTCoefficientQuantizer::SetInterQuantizationMethod(DCTCoefficientQuantizationMethod interQuantizationMethod)    {       this->interQuantizationMethod = interQuantizationMethod;    }        UnsignedByte DCTCoefficientQuantizer::GetInterQuantizationScale()    {       return this->interQuantizationScale;    }        UnsignedByte DCTCoefficientQuantizer::GetIntraQuantizationScale()    {       return this->intraQuantizationScale;    }        void DCTCoefficientQuantizer::SetInterQuantizationScale(UnsignedByte quantizationScale)    {       this->interQuantizationScale = quantizationScale;    }        void DCTCoefficientQuantizer::SetIntraQuantizationScale(UnsignedByte quantizationScale)    {       this->intraQuantizationScale = quantizationScale;    }        DCTCoefficientQuantizationMethod DCTCoefficientQuantizer::GetIntraQuantizationMethod()    {       return this->intraQuantizationMethod;    }        DCTCoefficientQuantizationMethod DCTCoefficientQuantizer::GetInterQuantizationMethod()    {       return this->interQuantizationMethod;    }        ConfigurationStatus DCTCoefficientQuantizer::Configure(ConfigurationElement* configuration)    {       // Quantization type selection is currently off -- use quantizationScale to set the scaling value for MPEG-4 quantization.       /*       if (configuration == NULL || configuration->GetValue("type") == NULL || *configuration->GetValue("type")->GetString() == string("quality"))       {          // Default quantization.          this->intraQuantizationMethod = DCT_QUANTIZATION_JPEG_STANDARD_QUALITY;          this->interQuantizationMethod = DCT_QUANTIZATION_INTER_STANDARD;          this->quantizerScale = 1;       }       */       // Explicitly specified quantization type overrides scaling.       /*       if (configuration != NULL && configuration->GetValue("type") != NULL && configuration->GetValue("type")->GetType() == CONFIGURATION_STRING && *configuration->GetValue("type")->GetString() == string("normal"))       {          this->intraQuantizationMethod = DCT_QUANTIZATION_JPEG_STANDARD_QUALITY;          this->interQuantizationMethod = DCT_QUANTIZATION_INTER_STANDARD;          this->quantizerScale = 2;       }       */              this->intraQuantizationMethod = DCT_QUANTIZATION_JPEG_STANDARD_QUALITY;       this->interQuantizationMethod = DCT_QUANTIZATION_INTER_STANDARD;              // User defined quantization scaling values for inter and intra frames.       if (configuration != NULL && configuration->GetValue("interQuantizationScale") != NULL && configuration->GetValue("interQuantizationScale")->GetType() == CONFIGURATION_INTEGER)          this->interQuantizationScale = (UnsignedByte)*configuration->GetValue("interQuantizationScale")->GetInteger();       else          this->interQuantizationScale = 1;              if (configuration != NULL && configuration->GetValue("intraQuantizationScale") != NULL && configuration->GetValue("intraQuantizationScale")->GetType() == CONFIGURATION_INTEGER)          this->intraQuantizationScale = (UnsignedByte)*configuration->GetValue("intraQuantizationScale")->GetInteger();       else          this->intraQuantizationScale = 1;       return MODULE_CONFIGURATION_OK;    }        void DCTCoefficientQuantizer::DequantizeDCTCoefficients(PictureInfo* picture, bool isInter)    {       if (picture->GetPixelLayout() != PIXEL_LAYOUT_MB_FOUR_TWO_ZERO)          Logger::LogMessage("Warning: Unexpected macroblock type in DCT coefficient dequantizer.");              if ((isInter && this->interQuantizationMethod == DCT_QUANTIZATION_NONE) || (!isInter && this->intraQuantizationMethod == DCT_QUANTIZATION_NONE))       {          Logger::LogMessage("Warning: No quantization selected.");          return;       }              SignedShort* transformed = picture->GetSignedShortData();       int blockRows = picture->GetBlockRows();       int blockColumns = picture->GetBlockColumns();              // Store the offset of the current macroblock.       if (isInter && this->interQuantizationMethod == DCT_QUANTIZATION_INTER_STANDARD)       {          unsigned char blockIndex = 0;          for (int offset = 0; offset < (blockRows * blockColumns * 64 * 6); offset++)          {             if (transformed[offset] != 0)             {                transformed[offset] = (this->interQuantizationScale * dctInterQuantizationInteger[blockIndex] *                      (2 * transformed[offset] + (transformed[offset] < 0 ? -1 : (transformed[offset] > 0 ? 1 : 0)))                      ) >> 4;                if (transformed[offset] > 2047)                   transformed[offset] = 2047;                else if (transformed[offset] < -2048)                   transformed[offset] = -2048;             }             blockIndex++;             if (blockIndex == 64)                blockIndex = 0;          }       }       else if (!isInter && this->intraQuantizationMethod == DCT_QUANTIZATION_JPEG_STANDARD_QUALITY)       {          for (int offset = 0; offset < (blockRows * blockColumns * 64 * 6); offset += 64 * 6)          {             // Dequantize DC coefficients.             for (int b = 0; b < 6; b++)                transformed[offset + (b << 6)] <<= 3;                          // Dequantize AC coefficients for each block.             this->DequantizeIntraACValues(transformed + offset + (0 << 6), dctStandardQuantizationLumaInteger);             this->DequantizeIntraACValues(transformed + offset + (1 << 6), dctStandardQuantizationLumaInteger);             this->DequantizeIntraACValues(transformed + offset + (2 << 6), dctStandardQuantizationLumaInteger);             this->DequantizeIntraACValues(transformed + offset + (3 << 6), dctStandardQuantizationLumaInteger);             this->DequantizeIntraACValues(transformed + offset + (4 << 6), dctStandardQuantizationChromaInteger);             this->DequantizeIntraACValues(transformed + offset + (5 << 6), dctStandardQuantizationChromaInteger);          }       }       else       {          // Unrecognized quantization method.          Logger::LogMessage("Warning: No dequantizaton was performed.");       }    }        inline void DCTCoefficientQuantizer::DequantizeIntraACValues(SignedShort* block, int* quantizationMatrix)    {       // Skip the DC value.       for (int i = 1; i < 64; i++)       {          // Scale this value up and round to the correct range.          block[i] = ((block[i] << 1) * this->intraQuantizationScale * quantizationMatrix[i]) >> 4;                    if (block[i] > 2047)             block[i] = 2047;          else if (block[i] < -2048)             block[i] = -2048;       }    }        inline void DCTCoefficientQuantizer::QuantizeIntraACValues(SignedShort* block, int* quantizationMatrix)    {       // Skip the DC value.       for (int i = 1; i < 64; i++)       {          SignedShort dct = block[i];          if (dct != 0)             block[i] =                ((dct << 4) + (dct < 0 ? -1 : (dct > 0 ? 1 : 0)) * quantizationMatrix[i] * this->intraQuantizationScale)                   / (this->intraQuantizationScale * quantizationMatrix[i] << 1);       }    }    void DCTCoefficientQuantizer::QuantizeDCTCoefficients(PictureInfo* picture, bool isInter)    {       if (picture->GetPixelLayout() != PIXEL_LAYOUT_MB_FOUR_TWO_ZERO)          Logger::LogMessage("Warning: DCT coefficient quantizer required 4:2:0 MB pixel layout.");              SignedShort* transformed = picture->GetSignedShortData();       int blockRows = picture->GetBlockRows();       int blockColumns = picture->GetBlockColumns();              if (isInter && this->interQuantizationMethod == DCT_QUANTIZATION_INTER_STANDARD)       {          unsigned char blockIndex = 0;                    for (int offset = 0; offset < blockColumns * blockRows * 64 * 6; offset++)          {             if (transformed[offset] != 0)                transformed[offset] = (transformed[offset] << 3) / (dctInterQuantizationInteger[blockIndex] * this->interQuantizationScale);                          blockIndex++;             if (blockIndex == 64)                blockIndex = 0;          }       }       else if (!isInter && this->intraQuantizationMethod == DCT_QUANTIZATION_JPEG_STANDARD_QUALITY)       {          for (int offset = 0; offset < (blockRows * blockColumns * 64 * 6); offset += 64 * 6)          {             // Quantize DC coefficients.             for (int b = 0; b < 6; b++)                transformed[offset + (b << 6)] >>= 3;                          // Quantize AC coefficients for each block.             this->QuantizeIntraACValues(transformed + offset + (0 << 6), dctStandardQuantizationLumaInteger);             this->QuantizeIntraACValues(transformed + offset + (1 << 6), dctStandardQuantizationLumaInteger);             this->QuantizeIntraACValues(transformed + offset + (2 << 6), dctStandardQuantizationLumaInteger);             this->QuantizeIntraACValues(transformed + offset + (3 << 6), dctStandardQuantizationLumaInteger);             this->QuantizeIntraACValues(transformed + offset + (4 << 6), dctStandardQuantizationChromaInteger);             this->QuantizeIntraACValues(transformed + offset + (5 << 6), dctStandardQuantizationChromaInteger);          }       }       else       {          Logger::LogMessage("Warning: No quantization was performed.");       }    } }