1 //*@@@+++@@@@******************************************************************
2 //
3 // Copyright � Microsoft Corp.
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 //
9 // � Redistributions of source code must retain the above copyright notice,
10 //   this list of conditions and the following disclaimer.
11 // � Redistributions in binary form must reproduce the above copyright notice,
12 //   this list of conditions and the following disclaimer in the documentation
13 //   and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 // POSSIBILITY OF SUCH DAMAGE.
26 //
27 //*@@@---@@@@******************************************************************
28 
29 #include "windowsmediaphoto.h"
30 #include "strcodec.h"
31 
smoothMB(PixelI * p1,PixelI * p0,PixelI * q0,PixelI * q1)32 Void smoothMB(PixelI * p1, PixelI * p0, PixelI * q0, PixelI * q1)
33 {
34     //  p1 p0 | q0 q1
35     PixelI delta = ((((*q0 - *p0) << 2) + (*p1 - *q1)) >> 3);
36 
37     *q0 -= delta;
38     *p0 += delta;
39 }
40 
smooth(PixelI * p2,PixelI * p1,PixelI * p0,PixelI * q0,PixelI * q1,PixelI * q2)41 Void smooth(PixelI * p2, PixelI * p1, PixelI * p0, PixelI * q0, PixelI * q1, PixelI * q2)
42 {
43     //    p2 p1 p0 | q0 q1 q2
44     PixelI delta = ((((*q0 - *p0) << 2) + (*p1 - *q1)) >> 3);
45 
46     *q0 -= delta;
47     *p0 += delta;
48 
49     *p1 = (*p1 >> 1) + ((*p0 + *p2) >> 2);
50     *q1 = (*q1 >> 1) + ((*q0 + *q2) >> 2);
51 }
52 
initPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2],size_t mbWidth,size_t iNumChannels)53 Int initPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t mbWidth, size_t iNumChannels)
54 {
55     size_t i, j, k, l;
56     Bool b32bit = sizeof(int) == 4;
57 
58     for(j = 0; j < iNumChannels; j ++){
59         for(i = 0; i < 2; i ++){
60             // 2 more are allocated to avoid boundary check
61             if(b32bit) // integer overlow/underflow check for 32-bit system
62                 if((((mbWidth + 2) >> 16) * sizeof(struct tagPostProcInfo)) & 0xffff0000)
63                     return ICERR_ERROR;
64             strPostProcInfo[j][i] = (struct tagPostProcInfo *)malloc((mbWidth + 2) * sizeof(struct tagPostProcInfo));
65             assert(strPostProcInfo[j][i] != NULL);
66             if(strPostProcInfo[j][i] == NULL){
67                 return ICERR_ERROR;
68             }
69             strPostProcInfo[j][i] ++;
70 
71             // initialize out-of-bound MBs as bumpy (no post at all) to avoid boundary check
72             // left boundary
73             strPostProcInfo[j][i][-1].ucMBTexture = 3;
74             for(l = 0; l < 4; l ++){
75                 for(k = 0; k < 4; k ++){
76                     strPostProcInfo[j][i][-1].ucBlockTexture[l][k] = 3;
77                 }
78             }
79             // right boundary
80             strPostProcInfo[j][i][mbWidth] = strPostProcInfo[j][i][-1];
81         }
82     }
83 
84     return ICERR_OK;
85 }
86 
termPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2],size_t iNumChannels)87 Void termPostProc(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels)
88 {
89     size_t i, j;
90 
91     for(j = 0; j < iNumChannels; j ++){
92         for(i = 0; i < 2; i ++){
93             if(strPostProcInfo[j][i] != NULL){
94                 free(strPostProcInfo[j][i] - 1);
95             }
96         }
97     }
98 }
99 
slideOneMBRow(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2],size_t iNumChannels,size_t mbWidth,Bool top,Bool bottom)100 Void slideOneMBRow(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], size_t iNumChannels, size_t mbWidth, Bool top, Bool bottom)
101 {
102     size_t i, j;
103     struct tagPostProcInfo * bar;
104 
105     for(i = 0; i < iNumChannels; i ++){
106         // swap previous row and current row
107         bar = strPostProcInfo[i][0];
108         strPostProcInfo[i][0] = strPostProcInfo[i][1];
109         strPostProcInfo[i][1] = bar;
110 
111         if(top){ // if top row, previous row is out of boundary
112             for(j = 0; j < mbWidth; j ++){
113                 strPostProcInfo[i][0][j] = strPostProcInfo[i][0][-1]; // set as bumpy
114             }
115         }
116 
117         if(bottom){ // if bottom bottom row, set current row of MBs (out of boundary) as bumpy
118             for(j = 0; j < mbWidth; j ++){
119                 strPostProcInfo[i][1][j] = strPostProcInfo[i][1][-1]; // set as bumpy
120             }
121         }
122     }
123 }
124 
125 // get DC and texture infomation right before transform
updatePostProcInfo(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2],PixelI * pMB,size_t mbX,size_t cc)126 Void updatePostProcInfo(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * pMB, size_t mbX, size_t cc)
127 {
128     size_t i, j;
129     struct tagPostProcInfo * pMBInfo = strPostProcInfo[cc][1] + mbX;
130 
131     // DC of MB
132     pMBInfo->iMBDC = pMB[0];
133 
134     // texture of MB
135     pMBInfo->ucMBTexture = 0; // smooth
136     for(i = 16; i < 256; i += 16){
137         if(pMB[i] != 0){
138             pMBInfo->ucMBTexture = 3; // bumpy
139             break;
140         }
141     }
142 
143     // DCs of blocks not available yet, will collect after demacroblocking
144 
145     // textures of blocks
146     for(j = 0; j < 4; j ++)
147         for(i = 0; i < 4; i ++){
148             PixelI * p = pMB + i * 64 + j * 16;
149             size_t k;
150 
151             for(k = 1, pMBInfo->ucBlockTexture[j][i] = 0; k < 16; k ++){
152                 if(p[k] != 0){
153                     pMBInfo->ucBlockTexture[j][i] = 3;
154                     break;
155                 }
156             }
157         }
158 }
159 
160 // demacroblock critirion: two MBs have same texture other than bumpy and DCs differ less than 1
161 #define DMB(a, b) (a->ucMBTexture + b->ucMBTexture == 0) && (abs(a->iMBDC - b->iMBDC) <= threshold)
162 
163 // demacroblock and get DCs of blocks
postProcMB(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2],PixelI * p0,PixelI * p1,size_t mbX,size_t cc,Int threshold)164 Void postProcMB(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold)
165 {
166     /* 4 MBs involved, current MB is d, we have 4 2-pixel boundary segments */
167     /*    |     */
168     /*  a | b   */
169     /* - - + +  */
170     /*  c ! d   */
171     /*    !     */
172     struct tagPostProcInfo * pMBb = strPostProcInfo[cc][0] + mbX, * pMBa = pMBb - 1, * pMBd = strPostProcInfo[cc][1] + mbX, * pMBc = pMBd - 1;
173 
174     // demacroblock segment --
175    if(DMB(pMBa, pMBc)){
176         smoothMB(p0 - 256 + 10 * 16, p0 - 256 + 11 * 16, p1 - 256 +  8 * 16, p1 - 256 +  9 * 16);
177         smoothMB(p0 - 256 + 14 * 16, p0 - 256 + 15 * 16, p1 - 256 + 12 * 16, p1 - 256 + 13 * 16);
178     }
179 
180     // demacroblock segment ++
181     if(DMB(pMBb, pMBd)){
182         smoothMB(p0 + 2 * 16, p0 + 3 * 16, p1 + 0 * 16, p1 + 1 * 16);
183         smoothMB(p0 + 6 * 16, p0 + 7 * 16, p1 + 4 * 16, p1 + 5 * 16);
184     }
185 
186     // demacroblock segment |
187     if(DMB(pMBa, pMBb)){
188         smoothMB(p0 - 256 + 10 * 16, p0 - 256 + 14 * 16, p0 + 2 * 16, p0 + 6 * 16);
189         smoothMB(p0 - 256 + 11 * 16, p0 - 256 + 15 * 16, p0 + 3 * 16, p0 + 7 * 16);
190     }
191 
192     // demacroblock segment !
193     if(DMB(pMBc, pMBd)){
194         smoothMB(p1 - 256 + 8 * 16, p1 - 256 + 12 * 16, p1 + 0 * 16, p1 + 4 * 16);
195         smoothMB(p1 - 256 + 9 * 16, p1 - 256 + 13 * 16, p1 + 1 * 16, p1 + 5 * 16);
196     }
197 
198     /* update DCs of blocks */
199     // MB d
200     pMBd->iBlockDC[0][0] = p1[0 * 16];
201     pMBd->iBlockDC[0][1] = p1[4 * 16];
202     pMBd->iBlockDC[1][0] = p1[1 * 16];
203     pMBd->iBlockDC[1][1] = p1[5 * 16];
204 
205     // MB b
206     pMBb->iBlockDC[2][0] = p0[2 * 16];
207     pMBb->iBlockDC[2][1] = p0[6 * 16];
208     pMBb->iBlockDC[3][0] = p0[3 * 16];
209     pMBb->iBlockDC[3][1] = p0[7 * 16];
210 
211     // MB c
212     pMBc->iBlockDC[0][2] = p1[ 8 * 16 - 256];
213     pMBc->iBlockDC[0][3] = p1[12 * 16 - 256];
214     pMBc->iBlockDC[1][2] = p1[ 9 * 16 - 256];
215     pMBc->iBlockDC[1][3] = p1[13 * 16 - 256];
216 
217     // MB a
218     pMBa->iBlockDC[2][2] = p0[10 * 16 - 256];
219     pMBa->iBlockDC[2][3] = p0[14 * 16 - 256];
220     pMBa->iBlockDC[3][2] = p0[11 * 16 - 256];
221     pMBa->iBlockDC[3][3] = p0[15 * 16 - 256];
222 }
223 
224 /* deblock and destair blocks */
225 /* 4 MBs involved, need to process 16 blocks of a */
226 /*    |     */
227 /*  a | b   */
228 /* - - - -  */
229 /*  c | d   */
230 /*    |     */
postProcBlock(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2],PixelI * p0,PixelI * p1,size_t mbX,size_t cc,Int threshold)231 Void postProcBlock(struct tagPostProcInfo * strPostProcInfo[MAX_CHANNELS][2], PixelI * p0, PixelI * p1, size_t mbX, size_t cc, Int threshold)
232 {
233     size_t i, j, k;
234     Int dc[5][5];
235     U8 texture[5][5];
236     struct tagPostProcInfo * pMBb = strPostProcInfo[cc][0] + mbX, * pMBa = pMBb - 1, * pMBd = strPostProcInfo[cc][1] + mbX, * pMBc = pMBd - 1;
237     PixelI * pc, * pt;
238 
239     /* copy DC and Texture info, can be optimized out */
240     for(j = 0; j < 4; j ++){
241         // from MB a
242         for(i = 0; i < 4; i ++){
243             dc[j][i] = pMBa->iBlockDC[j][i];
244             texture[j][i] = pMBa->ucBlockTexture[j][i];
245         }
246 
247         // 4 blocks from MB c
248         dc[4][j] = pMBc->iBlockDC[0][j];
249         texture[4][j] = pMBc->ucBlockTexture[0][j];
250 
251         // 4 blocks from MB b
252         dc[j][4] = pMBb->iBlockDC[j][0];
253         texture[j][4] = pMBb->ucBlockTexture[j][0];
254     }
255     // 1 block from MB d
256     dc[4][4] = pMBd->iBlockDC[0][0];
257     texture[4][4] = pMBd->ucBlockTexture[0][0];
258 
259     /* block boundaries */
260     /*     | */
261     /*     | */
262     /*  ---  */
263 
264     for(j = 0; j < 4; j ++){
265         for(i = 0; i < 4; i ++){
266             pc = p0 - 256 + i * 64 + j * 16;
267 
268             // deblock
269             if(texture[j][i] + texture[j + 1][i] < 3 && abs(dc[j][i] - dc[j + 1][i]) <= threshold){
270                 // smooth horizontal boundary ----
271                 pt = (j < 3 ? pc + 16 : p1 - 256 + i * 64);
272                 for(k = 0; k < 4; k ++){
273                     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]);
274                 }
275             }
276 
277             // two horizontally adjacent blocks have same texture and similiar DCs
278             if(texture[j][i] + texture[j][i + 1] < 3 && abs(dc[j][i] - dc[j][i + 1]) <= threshold){
279                 // smooth vertical boundary |
280                 pt = pc + 64;
281                 for(k = 0; k < 4; k ++){
282                     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]);
283                 }
284             }
285         }
286     }
287 }
288 
289