📄 blkenc.cpp
字号:
/*************************************************************************
This software module was originally developed by
Ming-Chieh Lee (mingcl@microsoft.com), Microsoft Corporation
Wei-ge Chen (wchen@microsoft.com), Microsoft Corporation
Bruce Lin (blin@microsoft.com), Microsoft Corporation
Chuang Gu (chuanggu@microsoft.com), Microsoft Corporation
Simon Winder (swinder@microsoft.com), Microsoft Corporation
(date: March, 1996)
and edited by
Wei Wu (weiwu@stallion.risc.rockwell.com) Rockwell Science Center
and also edited by
Fujitsu Laboratories Ltd. (contact: Eishi Morimatsu)
in the course of development of the MPEG-4 Video (ISO/IEC 14496-2).
This software module is an implementation of a part of one or more MPEG-4 Video tools
as specified by the MPEG-4 Video.
ISO/IEC gives users of the MPEG-4 Video free license to this software module or modifications
thereof for use in hardware or software products claiming conformance to the MPEG-4 Video.
Those intending to use this software module in hardware or software products are advised that its use may infringe existing patents.
The original developer of this software module and his/her company,
the subsequent editors and their companies,
and ISO/IEC have no liability for use of this software module or modifications thereof in an implementation.
Copyright is not released for non MPEG-4 Video conforming products.
Microsoft retains full right to use the code for his/her own purpose,
assign or donate the code to a third party and to inhibit third parties from using the code for non <MPEG standard> conforming products.
This copyright notice must be included in all copies or derivative works.
Copyright (c) 1996, 1997.
Module Name:
blkenc.cpp
Abstract:
functions for block-level encoding.
Revision History:
Sep.13 1999 : RRV added by Eishi Morimatsu (Fujitsu Laboratories Ltd.)
*************************************************************************/
#include <stdlib.h>
#include <math.h>
#include "typeapi.h"
#include "codehead.h"
#include "mode.hpp"
#include "global.hpp"
#include "entropy/bitstrm.hpp"
#include "entropy/entropy.hpp"
#include "entropy/huffman.hpp"
#include "dct.hpp"
#include "vopses.hpp"
#include "vopseenc.hpp"
#ifdef __MFC_
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
#endif // __MFC_
// HHI Schueuer: sadct
CScanSelectorForSADCT::CScanSelectorForSADCT(Int **rgiCurrMBCoeffWidth) :
m_rgiCurrMBCoeffWidth(rgiCurrMBCoeffWidth)
{
m_adaptedScan = new Int[BLOCK_SQUARE_SIZE];
}
CScanSelectorForSADCT::~CScanSelectorForSADCT()
{
delete [] m_adaptedScan;
}
Int *CScanSelectorForSADCT::select(Int *scan, Bool bIsBoundary, Int iBlk)
{
if (bIsBoundary) {
// the incoming scan is the zigzag scan for an 8x8 block which must be modified for
// sadct coded boundary blocks.
const Int *pCoeffWidth = m_rgiCurrMBCoeffWidth[iBlk];
int n, iy, ix;
int coeff_count = 0;
int coeff_count_save = 0;
Int scan_save[BLOCK_SQUARE_SIZE];
for (n=0; n<BLOCK_SQUARE_SIZE; n++) {
iy = scan[n]/BLOCK_SIZE;
ix = scan[n] % BLOCK_SIZE;
if (pCoeffWidth[iy] > ix)
m_adaptedScan[coeff_count++] = scan[n];
else
scan_save[coeff_count_save++] = scan[n];
}
coeff_count_save = 0;
for (n=coeff_count; n<BLOCK_SQUARE_SIZE; n++)
m_adaptedScan[coeff_count++] = scan_save[coeff_count_save++];
return(m_adaptedScan);
}
else
return(scan);
}
// end
// 09/19/99 HHI Schueuer
Int *CScanSelectorForSADCT::select_DP(Int *scan, Bool bIsBoundary, Int iBlk, Int** rgiCurrMBCoeffWidth)
{
if (bIsBoundary) {
// the incoming scan is the zigzag scan for an 8x8 block which must be modified for
// sadct coded boundary blocks.
const Int *pCoeffWidth = rgiCurrMBCoeffWidth[iBlk];
int n, iy, ix;
int coeff_count = 0;
int coeff_count_save = 0;
Int scan_save[BLOCK_SQUARE_SIZE];
for (n=0; n<BLOCK_SQUARE_SIZE; n++) {
iy = scan[n]/BLOCK_SIZE;
ix = scan[n] % BLOCK_SIZE;
if (pCoeffWidth[iy] > ix)
m_adaptedScan[coeff_count++] = scan[n];
else
scan_save[coeff_count_save++] = scan[n];
}
coeff_count_save = 0;
for (n=coeff_count; n<BLOCK_SQUARE_SIZE; n++)
m_adaptedScan[coeff_count++] = scan_save[coeff_count_save++];
return(m_adaptedScan);
}
else
return(scan);
}
// end 09/19/99
// HHI Schueuer: added const PixelC *rgpxlcBlkShape, Int iBlkShapeWidth for sadct
Int CVideoObjectEncoder::quantizeIntraBlockTexture (PixelC* ppxlcBlkSrc,
Int iWidthSrc,
PixelC* ppxlcCurrQBlock,
Int iWidthCurrQ,
Int* rgiCoefQ,
Int iQP,
Int iDcScaler,
Int iBlk,
MacroBlockMemory* pmbmLeft,
MacroBlockMemory* pmbmTop,
MacroBlockMemory* pmbmLeftTop,
MacroBlockMemory* pmbmCurr,
CMBMode* pmbmdLeft,
CMBMode* pmbmdTop,
CMBMode* pmbmdLeftTop,
CMBMode* pmbmdCurr,
const PixelC *rgpxlcBlkShape,
Int iBlkShapeWidth,
Int iAuxComp )
{
// m_pentrencSet->m_pentrencDCT->bitstream()->trace (ppxlcCurrQBlock, "BLK_TEXTURE");
// HHI Schueuer: added for sadct
Int *lx = new Int [iBlkShapeWidth];
m_pfdct->apply (ppxlcBlkSrc, iWidthSrc, m_rgiDCTcoef, BLOCK_SIZE, rgpxlcBlkShape, iBlkShapeWidth, lx);
// RRV insertion
if(m_vopmd.RRVmode.iOnOff == 1)
{
cutoffDCTcoef();
}
// ~RRV
quantizeIntraDCcoef (rgiCoefQ, (Float) iDcScaler);
inverseQuantizeIntraDc (rgiCoefQ, iDcScaler); //get the quantized block
if (m_volmd.fQuantizer == Q_H263) {
quantizeIntraDCTcoefH263 (rgiCoefQ, 1, iQP);
// HHI Schueuer: sadct
if (rgpxlcBlkShape && !m_volmd.bSadctDisable) {
// assert(pmbmd->m_rgTranspStatus [iBlk] == PARTIAL);
// brute force method to clean out mispredictions outside the active region
// Int *lx = m_rgiCurrMBCoeffWidth[iBlk];
Int iy, ix;
for (iy = 0; iy < BLOCK_SIZE; iy++) {
for (ix=lx[iy]; ix<BLOCK_SIZE; ix++)
rgiCoefQ[ix + iy * BLOCK_SIZE] = 0;
}
}
//end HHI
inverseQuantizeDCTcoefH263 (rgiCoefQ, 1, iQP); //get the quantized block
}
else {
quantizeIntraDCTcoefMPEG (rgiCoefQ, 1, iQP, (iBlk > V_BLOCK));
// HHI Schueuer: sadct
if (rgpxlcBlkShape && !m_volmd.bSadctDisable) {
// assert(pmbmd->m_rgTranspStatus [iBlk] == PARTIAL);
// brute force method to clean out mispredictions outside the active region
Int *lx = m_rgiCurrMBCoeffWidth[iBlk];
Int iy, ix;
for (iy = 0; iy < BLOCK_SIZE; iy++) {
for (ix=lx[iy]; ix<BLOCK_SIZE; ix++)
rgiCoefQ[ix + iy * BLOCK_SIZE] = 0;
}
}
//end
inverseQuantizeIntraDCTcoefMPEG (rgiCoefQ, 1, iQP, (iBlk > V_BLOCK), 0); //get the quantized block
}
Int i, j;
// pmbmCurr->rgblkm [iBlk - 1] [0] = rgiCoefQ [0]; //save Qcoef in memory
pmbmCurr->rgblkm [iBlk - 1] [0] = m_rgiDCTcoef [0]; //save reconstructed DC but quantized AC in memory
for (i = 1, j = 8; i < BLOCK_SIZE; i++, j += BLOCK_SIZE) {
pmbmCurr->rgblkm [iBlk - 1] [i] = rgiCoefQ [i];
pmbmCurr->rgblkm [iBlk - 1] [i + BLOCK_SIZE - 1] = rgiCoefQ [j];
}
Int iSumErr = 0;
m_rgiQPpred [iBlk - 1] = iQP; //default to current in case no predictor
iSumErr += decideIntraPredDir ( rgiCoefQ,
iBlk,
m_rgblkmCurrMB [iBlk - 1],
pmbmLeft,
pmbmTop,
pmbmLeftTop,
pmbmCurr,
pmbmdLeft,
pmbmdTop,
pmbmdLeftTop,
pmbmdCurr,
m_rgiQPpred [iBlk - 1],
iQP);
if(iBlk < A_BLOCK1 || pmbmdCurr->m_pCODAlpha[iAuxComp] == ALPHA_CODED)
// m_pidct->apply (m_rgiDCTcoef, BLOCK_SIZE, ppxlcCurrQBlock, iWidthCurrQ);
// HHI Schueuer: rgpxlcBlkShape, iBlkShapeWidth added for sadct
m_pidct->apply (m_rgiDCTcoef, BLOCK_SIZE, ppxlcCurrQBlock, iWidthCurrQ, rgpxlcBlkShape, iBlkShapeWidth);
// end HHI
return iSumErr;
}
Void CVideoObjectEncoder::quantizeIntraDCcoef (Int* rgiCoefQ, Float fltDcScaler)
{
if (m_volmd.nBits<=8) { // NBIT: may not valid when nBits>8
assert (fltDcScaler > 0 && fltDcScaler < 128);
}
#ifdef NO_APPENDIXF
Float fltDCquantized = (Float) m_rgiDCTcoef [0] / 8.0F;
#else
Float fltDCquantized = (Float) m_rgiDCTcoef [0] / fltDcScaler;
#endif
assert (fltDCquantized >= 0);
fltDCquantized = fltDCquantized + 0.5F;
Int iMaxDC = (1<<m_volmd.nBits) - 2; // NBIT 1..254
rgiCoefQ [0] = (Int) max (1, min (iMaxDC, fltDCquantized));
}
Void CVideoObjectEncoder::quantizeIntraDCTcoefH263 (Int* rgiCoefQ, Int iStart, Int iQP)
{
Int iLevelBits = 12; // 12 bit FLC (= m_volmd.nBits?)
Int iMaxAC = (1<<(iLevelBits - 1)) - 1; // NBIT 127
for (Int i = iStart; i < BLOCK_SQUARE_SIZE; i++) {
Int ilevel = sign(m_rgiDCTcoef [i]) * (abs (m_rgiDCTcoef [i]) / (2 * iQP));
rgiCoefQ [i] = min(iMaxAC, max(-iMaxAC, ilevel));
}
}
Void CVideoObjectEncoder::quantizeInterDCTcoefH263 (Int* rgiCoefQ, Int iStart, Int iQP)
{
Int iLevelBits = 12; // 12 bit FLC (= m_volmd.nBits?)
Int iMaxAC = (1<<(iLevelBits - 1)) - 1; // NBIT 127
for (Int i = iStart; i < BLOCK_SQUARE_SIZE; i++) {
Int ilevel = sign(m_rgiDCTcoef [i]) * ((abs (m_rgiDCTcoef [i]) - iQP / 2) / (2 * iQP));
rgiCoefQ [i] = min(iMaxAC, max(-iMaxAC, ilevel));
}
}
Void CVideoObjectEncoder::quantizeIntraDCTcoefMPEG (Int* rgiCoefQ, Int iStart, Int iQP,
Bool bUseAlphaMatrix)
{
Float fltScaledCoef;
Int i, iScaledQP, iScaledCoef;
Int *piQuantizerMatrix;
if(bUseAlphaMatrix)
piQuantizerMatrix = m_volmd.rgiIntraQuantizerMatrixAlpha[0];
else
piQuantizerMatrix = m_volmd.rgiIntraQuantizerMatrix;
Int iMaxVal = 1<<(m_volmd.nBits+3); // NBIT 2048
Int iLevelBits = 12; // 12 bit FLC (= m_volmd.nBits?)
Int iMaxAC = (1<<(iLevelBits - 1)) - 1; // NBIT 127
for (i = iStart; i < BLOCK_SQUARE_SIZE; i++) {
fltScaledCoef = 16.0F * m_rgiDCTcoef [i] / piQuantizerMatrix [i];
iScaledCoef = (Int) rounded (fltScaledCoef);
iScaledCoef = checkrange (iScaledCoef, -iMaxVal, iMaxVal - 1);
iScaledQP = (Int) (3.0F * (Float) iQP / 4.0F + 0.5);
assert (iScaledQP >= 0);
iScaledCoef = (iScaledCoef + sign(iScaledCoef) * iScaledQP) / (2 * iQP);
rgiCoefQ [i] = min(iMaxAC, max(-iMaxAC, iScaledCoef ));
}
}
Void CVideoObjectEncoder::quantizeInterDCTcoefMPEG (Int* rgiCoefQ, Int iStart, Int iQP,
Bool bUseAlphaMatrix)
{
Float fltScaledCoef;
Int i, iScaledCoef;
Int *piQuantizerMatrix;
if(bUseAlphaMatrix)
piQuantizerMatrix = m_volmd.rgiInterQuantizerMatrixAlpha[0];
else
piQuantizerMatrix = m_volmd.rgiInterQuantizerMatrix;
Int iLevelBits = 12; // 12 bit FLC (= m_volmd.nBits?)
Int iMaxAC = (1<<(iLevelBits - 1)) - 1; // NBIT 127
for (i = iStart; i < BLOCK_SQUARE_SIZE; i++) {
fltScaledCoef = 16.0F * m_rgiDCTcoef [i] / piQuantizerMatrix [i];
iScaledCoef = (Int) rounded (fltScaledCoef);
iScaledCoef = iScaledCoef / (2 * iQP);
rgiCoefQ [i] = min(iMaxAC, max(-iMaxAC, iScaledCoef ));
}
}
Int CVideoObject::decideIntraPredDir (Int* rgiCoefQ,
Int blkn,
const BlockMemory& blkmRet,
const MacroBlockMemory* pmbmLeft,
const MacroBlockMemory* pmbmTop,
const MacroBlockMemory* pmbmLeftTop,
const MacroBlockMemory* pmbmCurr,
const CMBMode* pmbmdLeft,
const CMBMode* pmbmdTop,
const CMBMode* pmbmdLeftTop,
CMBMode* pmbmdCurr,
Int& iQPpred,
Int iQPcurr,
Bool bDecideDCOnly)
{
UInt nBits = m_volmd.nBits;
Int iDefVal = 1<<(nBits+2);// NBIT: start to calculate default value
Int iRange = (1<<(nBits-1))-1; // 127 for 8-bit
Int iQPpredTop, iQPpredLeftTop, iQPpredLeft;
const BlockMemory blkmTop = findPredictorBlock (blkn, VERTICAL,
pmbmLeft, pmbmTop, pmbmLeftTop, pmbmCurr,
pmbmdLeft, pmbmdTop, pmbmdLeftTop, pmbmdCurr, iQPpredTop);
const BlockMemory blkmLeftTop = findPredictorBlock (blkn, DIAGONAL,
pmbmLeft, pmbmTop, pmbmLeftTop, pmbmCurr,
pmbmdLeft, pmbmdTop, pmbmdLeftTop, pmbmdCurr, iQPpredLeftTop);
const BlockMemory blkmLeft = findPredictorBlock (blkn, HORIZONTAL,
pmbmLeft, pmbmTop, pmbmLeftTop, pmbmCurr,
pmbmdLeft, pmbmdTop, pmbmdLeftTop, pmbmdCurr, iQPpredLeft);
//wchen: changed to 1024 per CD (based on recon instead of Q value now)
/* NBIT: change 1024 to iDefVal
Int iPredLeftTop = (blkmLeftTop == NULL) ? 1024 : blkmLeftTop [0];
Int iHorizontalGrad = ((blkmTop == NULL) ? 1024 : blkmTop [0]) - iPredLeftTop;
Int iVerticalGrad = ((blkmLeft == NULL) ? 1024 : blkmLeft [0]) - iPredLeftTop;
*/
Int iPredLeftTop = (blkmLeftTop == NULL) ? iDefVal : blkmLeftTop [0];
Int iHorizontalGrad = ((blkmTop == NULL) ? iDefVal : blkmTop [0]) - iPredLeftTop;
Int iVerticalGrad = ((blkmLeft == NULL) ? iDefVal : blkmLeft [0]) - iPredLeftTop;
blkmRet = NULL;
UInt i, j;
Int iSumErr = 0; //per vm4.0, p53
if (abs(iVerticalGrad) < abs (iHorizontalGrad)) {
pmbmdCurr->m_preddir [blkn - 1] = VERTICAL;
if (blkmTop != NULL) {
blkmRet = blkmTop;
iQPpred = iQPpredTop;
if (bDecideDCOnly != TRUE) {
for (i = 1; i < BLOCK_SIZE; i++) {
Int iDiff = rgiCoefQ [i] - divroundnearest(blkmTop [i] * iQPpred, iQPcurr);
if (iDiff >= -iRange && iDiff <= iRange) //hack to deal with vm deficiency: ac pred out of range; dc pred is not dealt with
iSumErr += abs (rgiCoefQ [i]) - abs (iDiff);
else
return -100000; //arbitrary negative number to turn off ac pred.
}
}
}
}
else {
pmbmdCurr->m_preddir [blkn - 1] = HORIZONTAL;
if (blkmLeft != NULL) {
blkmRet = blkmLeft;
iQPpred = iQPpredLeft;
if (bDecideDCOnly != TRUE) {
for (i = 8, j = 8; i < BLOCK_SQUARE_SIZE; i += 8, j++) {
Int iDiff = rgiCoefQ [i] - divroundnearest(blkmLeft [j] * iQPpred, iQPcurr);
if (iDiff >= -iRange && iDiff <= iRange) //hack to deal with vm deficiency: ac pred out of range; dc pred is not dealt with
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -