Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/jxr/image/decode/postprocess.c
4393 views
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
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
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
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
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
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
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
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
/* | */
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
290