//*@@@+++@@@@****************************************************************** // // Copyright © Microsoft Corp. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // • Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // • Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // //*@@@---@@@@****************************************************************** #include "windowsmediaphoto.h" #include "strcodec.h" Void smoothMB(PixelI * p1, PixelI * p0, PixelI * q0, PixelI * q1) { // p1 p0 | q0 q1 PixelI delta = ((((*q0 - *p0) << 2) + (*p1 - *q1)) >> 3); *q0 -= delta; *p0 += delta; } Void smooth(PixelI * p2, PixelI * p1, PixelI * p0, PixelI * q0, PixelI * q1, PixelI * q2) { // p2 p1 p0 | q0 q1 q2 PixelI delta = ((((*q0 - *p0) << 2) + (*p1 - *q1)) >> 3); *q0 -= delta; *p0 += delta; *p1 = (*p1 >> 1) + ((*p0 + *p2) >> 2); *q1 = (*q1 >> 1) + ((*q0 + *q2) >> 2); } Int initPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t mbWidth, size_t iNumChannels) { size_t i, j, k, l; Bool b32bit = sizeof(int) == 4; for(j = 0; j < iNumChannels; j ++){ for(i = 0; i < 2; i ++){ // 2 more are allocated to avoid boundary check if(b32bit) // integer overlow/underflow check for 32-bit system if((((mbWidth + 2) >> 16) * sizeof(struct tagPostProcInfo)) & 0xffff0000) return ICERR_ERROR; strPostProcInfo[j][i] = (struct tagPostProcInfo *)malloc((mbWidth + 2) * sizeof(struct tagPostProcInfo)); assert(strPostProcInfo[j][i] != NULL); if(strPostProcInfo[j][i] == NULL){ return ICERR_ERROR; } strPostProcInfo[j][i] ++; // initialize out-of-bound MBs as bumpy (no post at all) to avoid boundary check // left boundary strPostProcInfo[j][i][-1].ucMBTexture = 3; for(l = 0; l < 4; l ++){ for(k = 0; k < 4; k ++){ strPostProcInfo[j][i][-1].ucBlockTexture[l][k] = 3; } } // right boundary strPostProcInfo[j][i][mbWidth] = strPostProcInfo[j][i][-1]; } } return ICERR_OK; } Void termPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels) { size_t i, j; for(j = 0; j < iNumChannels; j ++){ for(i = 0; i < 2; i ++){ if(strPostProcInfo[j][i] != NULL){ free(strPostProcInfo[j][i] - 1); } } } } Void slideOneMBRow(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels, size_t mbWidth, Bool top, Bool bottom) { size_t i, j; struct tagPostProcInfo * bar; for(i = 0; i < iNumChannels; i ++){ // swap previous row and current row bar = strPostProcInfo[i][0]; strPostProcInfo[i][0] = strPostProcInfo[i][1]; strPostProcInfo[i][1] = bar; if(top){ // if top row, previous row is out of boundary for(j = 0; j < mbWidth; j ++){ strPostProcInfo[i][0][j] = strPostProcInfo[i][0][-1]; // set as bumpy } } if(bottom){ // if bottom bottom row, set current row of MBs (out of boundary) as bumpy for(j = 0; j < mbWidth; j ++){ strPostProcInfo[i][1][j] = strPostProcInfo[i][1][-1]; // set as bumpy } } } } // get DC and texture infomation right before transform Void updatePostProcInfo(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * pMB, size_t mbX, size_t cc) { size_t i, j; struct tagPostProcInfo * pMBInfo = strPostProcInfo[cc][1] + mbX; // DC of MB pMBInfo->iMBDC = pMB[0]; // texture of MB pMBInfo->ucMBTexture = 0; // smooth for(i = 16; i < 256; i += 16){ if(pMB[i] != 0){ pMBInfo->ucMBTexture = 3; // bumpy break; } } // DCs of blocks not available yet, will collect after demacroblocking // textures of blocks for(j = 0; j < 4; j ++) for(i = 0; i < 4; i ++){ PixelI * p = pMB + i * 64 + j * 16; size_t k; for(k = 1, pMBInfo->ucBlockTexture[j][i] = 0; k < 16; k ++){ if(p[k] != 0){ pMBInfo->ucBlockTexture[j][i] = 3; break; } } } } // demacroblock critirion: two MBs have same texture other than bumpy and DCs differ less than 1 #define DMB(a, b) (a->ucMBTexture + b->ucMBTexture == 0) && (abs(a->iMBDC - b->iMBDC) <= threshold) // demacroblock and get DCs of blocks Void postProcMB(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold) { /* 4 MBs involved, current MB is d, we have 4 2-pixel boundary segments */ /* | */ /* a | b */ /* - - + + */ /* c ! d */ /* ! */ struct tagPostProcInfo * pMBb = strPostProcInfo[cc][0] + mbX, * pMBa = pMBb - 1, * pMBd = strPostProcInfo[cc][1] + mbX, * pMBc = pMBd - 1; // demacroblock segment -- if(DMB(pMBa, pMBc)){ smoothMB(p0 - 256 + 10 * 16, p0 - 256 + 11 * 16, p1 - 256 + 8 * 16, p1 - 256 + 9 * 16); smoothMB(p0 - 256 + 14 * 16, p0 - 256 + 15 * 16, p1 - 256 + 12 * 16, p1 - 256 + 13 * 16); } // demacroblock segment ++ if(DMB(pMBb, pMBd)){ smoothMB(p0 + 2 * 16, p0 + 3 * 16, p1 + 0 * 16, p1 + 1 * 16); smoothMB(p0 + 6 * 16, p0 + 7 * 16, p1 + 4 * 16, p1 + 5 * 16); } // demacroblock segment | if(DMB(pMBa, pMBb)){ smoothMB(p0 - 256 + 10 * 16, p0 - 256 + 14 * 16, p0 + 2 * 16, p0 + 6 * 16); smoothMB(p0 - 256 + 11 * 16, p0 - 256 + 15 * 16, p0 + 3 * 16, p0 + 7 * 16); } // demacroblock segment ! if(DMB(pMBc, pMBd)){ smoothMB(p1 - 256 + 8 * 16, p1 - 256 + 12 * 16, p1 + 0 * 16, p1 + 4 * 16); smoothMB(p1 - 256 + 9 * 16, p1 - 256 + 13 * 16, p1 + 1 * 16, p1 + 5 * 16); } /* update DCs of blocks */ // MB d pMBd->iBlockDC[0][0] = p1[0 * 16]; pMBd->iBlockDC[0][1] = p1[4 * 16]; pMBd->iBlockDC[1][0] = p1[1 * 16]; pMBd->iBlockDC[1][1] = p1[5 * 16]; // MB b pMBb->iBlockDC[2][0] = p0[2 * 16]; pMBb->iBlockDC[2][1] = p0[6 * 16]; pMBb->iBlockDC[3][0] = p0[3 * 16]; pMBb->iBlockDC[3][1] = p0[7 * 16]; // MB c pMBc->iBlockDC[0][2] = p1[ 8 * 16 - 256]; pMBc->iBlockDC[0][3] = p1[12 * 16 - 256]; pMBc->iBlockDC[1][2] = p1[ 9 * 16 - 256]; pMBc->iBlockDC[1][3] = p1[13 * 16 - 256]; // MB a pMBa->iBlockDC[2][2] = p0[10 * 16 - 256]; pMBa->iBlockDC[2][3] = p0[14 * 16 - 256]; pMBa->iBlockDC[3][2] = p0[11 * 16 - 256]; pMBa->iBlockDC[3][3] = p0[15 * 16 - 256]; } /* deblock and destair blocks */ /* 4 MBs involved, need to process 16 blocks of a */ /* | */ /* a | b */ /* - - - - */ /* c | d */ /* | */ Void postProcBlock(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold) { size_t i, j, k; Int dc[5][5]; U8 texture[5][5]; struct tagPostProcInfo * pMBb = strPostProcInfo[cc][0] + mbX, * pMBa = pMBb - 1, * pMBd = strPostProcInfo[cc][1] + mbX, * pMBc = pMBd - 1; PixelI * pc, * pt; /* copy DC and Texture info, can be optimized out */ for(j = 0; j < 4; j ++){ // from MB a for(i = 0; i < 4; i ++){ dc[j][i] = pMBa->iBlockDC[j][i]; texture[j][i] = pMBa->ucBlockTexture[j][i]; } // 4 blocks from MB c dc[4][j] = pMBc->iBlockDC[0][j]; texture[4][j] = pMBc->ucBlockTexture[0][j]; // 4 blocks from MB b dc[j][4] = pMBb->iBlockDC[j][0]; texture[j][4] = pMBb->ucBlockTexture[j][0]; } // 1 block from MB d dc[4][4] = pMBd->iBlockDC[0][0]; texture[4][4] = pMBd->ucBlockTexture[0][0]; /* block boundaries */ /* | */ /* | */ /* --- */ for(j = 0; j < 4; j ++){ for(i = 0; i < 4; i ++){ pc = p0 - 256 + i * 64 + j * 16; // deblock if(texture[j][i] + texture[j + 1][i] < 3 && abs(dc[j][i] - dc[j + 1][i]) <= threshold){ // smooth horizontal boundary ---- pt = (j < 3 ? pc + 16 : p1 - 256 + i * 64); for(k = 0; k < 4; k ++){ smooth(pc + idxCC[1][k], pc + idxCC[2][k], pc + idxCC[3][k], pt + idxCC[0][k], pt + idxCC[1][k], pt + idxCC[2][k]); } } // two horizontally adjacent blocks have same texture and similiar DCs if(texture[j][i] + texture[j][i + 1] < 3 && abs(dc[j][i] - dc[j][i + 1]) <= threshold){ // smooth vertical boundary | pt = pc + 64; for(k = 0; k < 4; k ++){ smooth(pc + idxCC[k][1], pc + idxCC[k][2], pc + idxCC[k][3], pt + idxCC[k][0], pt + idxCC[k][1], pt + idxCC[k][2]); } } } } }