[svn] / trunk / xvidcore / src / plugins / plugin_psnrhvsm.c Repository:
ViewVC logotype

Annotation of /trunk/xvidcore/src/plugins/plugin_psnrhvsm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1894 - (view) (download)

1 : Isibaar 1894 /*****************************************************************************
2 :     *
3 :     * XVID MPEG-4 VIDEO CODEC
4 :     * - PSNR-HVS-M plugin: computes the PSNR-HVS-M metric -
5 :     *
6 :     * Copyright(C) 2010 Michael Militzer <michael@xvid.org>
7 :     *
8 :     * This program is free software ; you can redistribute it and/or modify
9 :     * it under the terms of the GNU General Public License as published by
10 :     * the Free Software Foundation ; either version 2 of the License, or
11 :     * (at your option) any later version.
12 :     *
13 :     * This program is distributed in the hope that it will be useful,
14 :     * but WITHOUT ANY WARRANTY ; without even the implied warranty of
15 :     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 :     * GNU General Public License for more details.
17 :     *
18 :     * You should have received a copy of the GNU General Public License
19 :     * along with this program ; if not, write to the Free Software
20 :     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 :     *
22 :     * $Id: plugin_psnrhvsm.c,v 1.1 2010-10-10 19:19:46 Isibaar Exp $
23 :     *
24 :     ****************************************************************************/
25 :    
26 :     /*****************************************************************************
27 :     *
28 :     * The PSNR-HVS-M metric is described in the following paper:
29 :     *
30 :     * "On between-coefficient contrast masking of DCT basis functions", by
31 :     * N. Ponomarenko, F. Silvestri, K. Egiazarian, M. Carli, J. Astola, V. Lukin,
32 :     * in Proceedings of the Third International Workshop on Video Processing and
33 :     * Quality Metrics for Consumer Electronics VPQM-07, January, 2007, 4 p.
34 :     *
35 :     * http://www.ponomarenko.info/psnrhvsm.htm
36 :     *
37 :     ****************************************************************************/
38 :    
39 :     #include <stdlib.h>
40 :     #include <stdio.h>
41 :     #include <math.h>
42 :     #include "../portab.h"
43 :     #include "../xvid.h"
44 :     #include "../dct/fdct.h"
45 :     #include "../image/image.h"
46 :     #include "../utils/mem_transfer.h"
47 :     #include "../utils/emms.h"
48 :    
49 :     typedef struct {
50 :    
51 :     int pixels; /* width*height */
52 :     uint64_t mse_sum; /* for avrg psnrhvsm */
53 :     long frame_cnt;
54 :    
55 :     } psnrhvsm_data_t; /* internal plugin data */
56 :    
57 :     static const float CSF_Coeff[64] =
58 :     { 1.608443f, 2.339554f, 2.573509f, 1.608443f, 1.072295f, 0.643377f, 0.504610f, 0.421887f,
59 :     2.144591f, 2.144591f, 1.838221f, 1.354478f, 0.989811f, 0.443708f, 0.428918f, 0.467911f,
60 :     1.838221f, 1.979622f, 1.608443f, 1.072295f, 0.643377f, 0.451493f, 0.372972f, 0.459555f,
61 :     1.838221f, 1.513829f, 1.169777f, 0.887417f, 0.504610f, 0.295806f, 0.321689f, 0.415082f,
62 :     1.429727f, 1.169777f, 0.695543f, 0.459555f, 0.378457f, 0.236102f, 0.249855f, 0.334222f,
63 :     1.072295f, 0.735288f, 0.467911f, 0.402111f, 0.317717f, 0.247453f, 0.227744f, 0.279729f,
64 :     0.525206f, 0.402111f, 0.329937f, 0.295806f, 0.249855f, 0.212687f, 0.214459f, 0.254803f,
65 :     0.357432f, 0.279729f, 0.270896f, 0.262603f, 0.229778f, 0.257351f, 0.249855f, 0.259950f
66 :     };
67 :    
68 :     static const float Mask_Coeff[64] =
69 :     { 0.000000f, 0.826446f, 1.000000f, 0.390625f, 0.173611f, 0.062500f, 0.038447f, 0.026874f,
70 :     0.694444f, 0.694444f, 0.510204f, 0.277008f, 0.147929f, 0.029727f, 0.027778f, 0.033058f,
71 :     0.510204f, 0.591716f, 0.390625f, 0.173611f, 0.062500f, 0.030779f, 0.021004f, 0.031888f,
72 :     0.510204f, 0.346021f, 0.206612f, 0.118906f, 0.038447f, 0.013212f, 0.015625f, 0.026015f,
73 :     0.308642f, 0.206612f, 0.073046f, 0.031888f, 0.021626f, 0.008417f, 0.009426f, 0.016866f,
74 :     0.173611f, 0.081633f, 0.033058f, 0.024414f, 0.015242f, 0.009246f, 0.007831f, 0.011815f,
75 :     0.041649f, 0.024414f, 0.016437f, 0.013212f, 0.009426f, 0.006830f, 0.006944f, 0.009803f,
76 :     0.019290f, 0.011815f, 0.011080f, 0.010412f, 0.007972f, 0.010000f, 0.009426f, 0.010203f
77 :     };
78 :    
79 :     #if 1 /* Floating-point implementation */
80 :    
81 :     static uint32_t Calc_MSE_H(int16_t *DCT_A, int16_t *DCT_B, uint8_t *IMG_A, uint8_t *IMG_B, int stride)
82 :     {
83 :     int x, y, i, j;
84 :     uint32_t Global_A, Global_B, Sum_A = 0, Sum_B = 0;
85 :     uint32_t Local[8] = {0, 0, 0, 0, 0, 0, 0, 0};
86 :     uint32_t Local_Square[8] = {0, 0, 0, 0, 0, 0, 0, 0};
87 :     float MASK_A = 0.f, MASK_B = 0.f;
88 :     uint32_t MSE_H = 0;
89 :    
90 :     /* Step 1: Calculate CSF weighted energy of DCT coefficients */
91 :     for (y = 0; y < 8; y++) {
92 :     for (x = 0; x < 8; x++) {
93 :     MASK_A += (float)(DCT_A[y*8 + x]*DCT_A[y*8 + x])*Mask_Coeff[y*8 + x];
94 :     MASK_B += (float)(DCT_B[y*8 + x]*DCT_B[y*8 + x])*Mask_Coeff[y*8 + x];
95 :     }
96 :     }
97 :    
98 :     /* Step 2: Determine local variances compared to entire block variance */
99 :     for (y = 0; y < 2; y++) {
100 :     for (x = 0; x < 2; x++) {
101 :     for (i = 0; i < 4; i++) {
102 :     uint8_t A = IMG_A[y*4*stride + 4*x + i];
103 :     uint8_t B = IMG_B[y*4*stride + 4*x + i];
104 :    
105 :     Local[y*2 + x] += A;
106 :     Local[y*2 + x + 4] += B;
107 :     Local_Square[y*2 + x] += A*A;
108 :     Local_Square[y*2 + x + 4] += B*B;
109 :     }
110 :     }
111 :     }
112 :    
113 :     Global_A = Local[0] + Local[1] + Local[2] + Local[3];
114 :     Global_B = Local[4] + Local[5] + Local[6] + Local[7];
115 :    
116 :     for (i = 0; i < 8; i++)
117 :     Local[i] = (Local_Square[i]<<4) - (Local[i]*Local[i]); /* 16*Var(Di) */
118 :    
119 :     Local_Square[0] += (Local_Square[1] + Local_Square[2] + Local_Square[3]);
120 :     Local_Square[4] += (Local_Square[5] + Local_Square[6] + Local_Square[7]);
121 :    
122 :     Global_A = (Local_Square[0]<<6) - Global_A*Global_A; /* 64*Var(D) */
123 :     Global_B = (Local_Square[4]<<6) - Global_B*Global_B; /* 64*Var(D) */
124 :    
125 :     /* Step 3: Calculate contrast masking threshold */
126 :     MASK_A = (float)sqrt(MASK_A*((float)(Local[0]+Local[1]+Local[2]+Local[3])/((float)Global_A/4.f)))/32.f;
127 :     MASK_B = (float)sqrt(MASK_B*((float)(Local[4]+Local[5]+Local[6]+Local[7])/((float)Global_B/4.f)))/32.f;
128 :    
129 :     if (MASK_B > MASK_A) MASK_A = MASK_B; /* MAX(MASK_A, MASK_B) */
130 :    
131 :     /* Step 4: Calculate MSE of DCT coeffs reduced by masking effect */
132 :     for (j = 0; j < 8; j++) {
133 :     for (i = 0; i < 8; i++) {
134 :     float u = (float)abs(DCT_A[j*8 + i] - DCT_B[j*8 + i]);
135 :    
136 :     if ((i|j)>0) {
137 :     if (u < (MASK_A / Mask_Coeff[j*8 + i]))
138 :     u = 0; /* The error is not perceivable */
139 :     else
140 :     u -= (MASK_A / Mask_Coeff[j*8 + i]);
141 :     }
142 :    
143 :     MSE_H += (uint32_t) ((256.f*(u * CSF_Coeff[j*8 + i])*(u * CSF_Coeff[j*8 + i])) + 0.5f);
144 :     }
145 :     }
146 :     return MSE_H; /* Fixed-point value right-shifted by eight */
147 :     }
148 :    
149 :     #else /* First draft of a fixed-point implementation.
150 :     Might serve as a template for MMX/SSE code */
151 :    
152 :     static const uint16_t iMask_Coeff[64] =
153 :     { 0, 59577, 65535, 40959, 27306, 16384, 12850, 10743,
154 :     54612, 54612, 46811, 34492, 25206, 11299, 10923, 11915,
155 :     46811, 50412, 40959, 27306, 16384, 11497, 9498, 11703,
156 :     46811, 38550, 29789, 22598, 12850, 7533, 8192, 10570,
157 :     36408, 29789, 17712, 11703, 9637, 6012, 6363, 8511,
158 :     27306, 18724, 11915, 10240, 8091, 6302, 5799, 7123,
159 :     13374, 10240, 8402, 7533, 6363, 5416, 5461, 6489,
160 :     9102, 7123, 6898, 6687, 5851, 6553, 6363, 6620
161 :     };
162 :    
163 :     static const uint16_t Inv_iMask_Coeff[64] =
164 :     { 0, 310, 256, 655, 1475, 4096, 6659, 9526,
165 :     369, 369, 502, 924, 1731, 8612, 9216, 7744,
166 :     502, 433, 655, 1475, 4096, 8317, 12188, 8028,
167 :     502, 740, 1239, 2153, 6659, 19376, 16384, 9840,
168 :     829, 1239, 3505, 8028, 11838, 30415, 27159, 15178,
169 :     1475, 3136, 7744, 10486, 16796, 27688, 32691, 21667,
170 :     6147, 10486, 15575, 19376, 27159, 37482, 36866, 26114,
171 :     13271, 21667, 23105, 24587, 32112, 25600, 27159, 25091
172 :     };
173 :    
174 :     static const uint16_t iCSF_Coeff[64] =
175 :     { 1647, 2396, 2635, 1647, 1098, 659, 517, 432,
176 :     2196, 2196, 1882, 1387, 1014, 454, 439, 479,
177 :     1882, 2027, 1647, 1098, 659, 462, 382, 471,
178 :     1882, 1550, 1198, 909, 517, 303, 329, 425,
179 :     1464, 1198, 712, 471, 388, 242, 256, 342,
180 :     1098, 753, 479, 412, 325, 253, 233, 286,
181 :     538, 412, 338, 303, 256, 218, 220, 261,
182 :     366, 286, 277, 269, 235, 264, 256, 266
183 :     };
184 :    
185 :     static uint32_t Calc_MSE_H(int16_t *DCT_A, int16_t *DCT_B, uint8_t *IMG_A, uint8_t *IMG_B, int stride)
186 :     {
187 :     int x, y, i, j;
188 :     uint32_t Global_A, Global_B, Sum_A = 0, Sum_B = 0;
189 :     uint32_t Local[8] = {0, 0, 0, 0, 0, 0, 0, 0};
190 :     uint32_t Local_Square[8] = {0, 0, 0, 0, 0, 0, 0, 0};
191 :     uint32_t MASK;
192 :     uint32_t MSE_H = 0;
193 :    
194 :     /* Step 1: Calculate CSF weighted energy of DCT coefficients */
195 :     for (y = 0; y < 8; y++) {
196 :     for (x = 0; x < 8; x++) {
197 :     uint16_t A = (abs(DCT_A[y*8 + x]) * iMask_Coeff[y*8 + x] + 4096) >> 13;
198 :     uint16_t B = (abs(DCT_B[y*8 + x]) * iMask_Coeff[y*8 + x] + 4096) >> 13;
199 :    
200 :     Sum_A += ((A*A) >> 3); /* PMADDWD */
201 :     Sum_B += ((B*B) >> 3);
202 :     }
203 :     }
204 :    
205 :     /* Step 2: Determine local variances compared to entire block variance */
206 :     for (y = 0; y < 2; y++) {
207 :     for (x = 0; x < 2; x++) {
208 :     for (i = 0; i < 4; i++) {
209 :     uint8_t A = IMG_A[y*4*stride + 4*x + i];
210 :     uint8_t B = IMG_B[y*4*stride + 4*x + i];
211 :    
212 :     Local[y*2 + x] += A;
213 :     Local[y*2 + x + 4] += B;
214 :     Local_Square[y*2 + x] += A*A;
215 :     Local_Square[y*2 + x + 4] += B*B;
216 :     }
217 :     }
218 :     }
219 :    
220 :     Global_A = Local[0] + Local[1] + Local[2] + Local[3];
221 :     Global_B = Local[4] + Local[5] + Local[6] + Local[7];
222 :    
223 :     for (i = 0; i < 8; i++)
224 :     Local[i] = (Local_Square[i]<<4) - (Local[i]*Local[i]); /* 16*Var(Di) */
225 :    
226 :     Local_Square[0] += (Local_Square[1] + Local_Square[2] + Local_Square[3]);
227 :     Local_Square[4] += (Local_Square[5] + Local_Square[6] + Local_Square[7]);
228 :    
229 :     Global_A = (Local_Square[0]<<6) - Global_A*Global_A; /* 64*Var(D) */
230 :     Global_B = (Local_Square[4]<<6) - Global_B*Global_B; /* 64*Var(D) */
231 :    
232 :     /* Step 3: Calculate contrast masking threshold */
233 :     {
234 :     float MASK_A, MASK_B; /* TODO */
235 :    
236 :     MASK_A = (float)((double)(Sum_A + 4) / 8.);
237 :     MASK_B = (float)((double)(Sum_B + 4) / 8.);
238 :    
239 :     MASK_A = sqrt(MASK_A*((float)(Local[0]+Local[1]+Local[2]+Local[3])/((float)Global_A/4.f)))/32.f;
240 :     MASK_B = sqrt(MASK_B*((float)(Local[4]+Local[5]+Local[6]+Local[7])/((float)Global_B/4.f)))/32.f;
241 :    
242 :     if (MASK_B > MASK_A) /* MAX(MASK_A, MASK_B) */
243 :     MASK = (uint32_t) (MASK_B * 1024.f + 0.5f);
244 :     else
245 :     MASK = (uint32_t) (MASK_A * 1024.f + 0.5f);
246 :     }
247 :    
248 :     /* Step 4: Calculate MSE of DCT coeffs reduced by masking effect */
249 :     for (j = 0; j < 8; j++) {
250 :     for (i = 0; i < 8; i++) {
251 :     uint32_t Thresh = (MASK * Inv_iMask_Coeff[j*8 + i] + 128) >> 8;
252 :     uint32_t u = abs(DCT_A[j*8 + i] - DCT_B[j*8 + i]) << 10;
253 :    
254 :     if ((i|j)>0) {
255 :     if (u < Thresh)
256 :     u = 0; /* The error is not perceivable */
257 :     else
258 :     u -= Thresh;
259 :     }
260 :    
261 :     {
262 :     uint64_t tmp = (u * iCSF_Coeff[j*8 + i] + 512) >> 10;
263 :     MSE_H += (uint32_t) ((tmp * tmp) >> 12);
264 :     }
265 :     }
266 :     }
267 :     return MSE_H;
268 :     }
269 :    
270 :     #endif
271 :    
272 :     static void psnrhvsm_after(xvid_plg_data_t *data, psnrhvsm_data_t *psnrhvsm)
273 :     {
274 :     DECLARE_ALIGNED_MATRIX(DCT, 2, 64, int16_t, CACHE_LINE);
275 :     int x, y, stride = data->original.stride[0];
276 :     int16_t *DCT_A = &DCT[0], *DCT_B = &DCT[64];
277 :     uint8_t *IMG_A = (uint8_t *) data->original.plane[0];
278 :     uint8_t *IMG_B = (uint8_t *) data->current.plane[0];
279 :     uint32_t MSE_H = 0;
280 :    
281 :     psnrhvsm->pixels = data->width * data->height;
282 :    
283 :     for (y = 0; y < data->height; y += 8) {
284 :     for (x = 0; x < data->width; x += 8) {
285 :     int offset = y*stride + x;
286 :    
287 :     emms();
288 :    
289 :     /* Transfer data */
290 :     transfer_8to16copy(DCT_A, IMG_A + offset, stride);
291 :     transfer_8to16copy(DCT_B, IMG_B + offset, stride);
292 :    
293 :     /* Perform DCT */
294 :     fdct(DCT_A);
295 :     fdct(DCT_B);
296 :    
297 :     emms();
298 :    
299 :     /* Calculate MSE_H reduced by contrast masking effect */
300 :     MSE_H += Calc_MSE_H(DCT_A, DCT_B, IMG_A + offset, IMG_B + offset, stride);
301 :     }
302 :     }
303 :    
304 :     psnrhvsm->mse_sum += MSE_H;
305 :     psnrhvsm->frame_cnt++;
306 :    
307 :     printf(" psnrhvsm: %2.2f\n", sse_to_PSNR(MSE_H, 256*psnrhvsm->pixels));
308 :     }
309 :    
310 :     static int psnrhvsm_create(xvid_plg_create_t *create, void **handle)
311 :     {
312 :     psnrhvsm_data_t *psnrhvsm;
313 :     psnrhvsm = (psnrhvsm_data_t *) malloc(sizeof(psnrhvsm_data_t));
314 :    
315 :     psnrhvsm->mse_sum = 0;
316 :     psnrhvsm->frame_cnt = 0;
317 :    
318 :     psnrhvsm->pixels = 0;
319 :    
320 :     *(handle) = (void*) psnrhvsm;
321 :     return 0;
322 :     }
323 :    
324 :     int xvid_plugin_psnrhvsm(void *handle, int opt, void *param1, void *param2)
325 :     {
326 :     switch(opt) {
327 :     case(XVID_PLG_INFO):
328 :     ((xvid_plg_info_t *)param1)->flags = XVID_REQORIGINAL;
329 :     break;
330 :     case(XVID_PLG_CREATE):
331 :     psnrhvsm_create((xvid_plg_create_t *)param1,(void **)param2);
332 :     break;
333 :     case(XVID_PLG_BEFORE):
334 :     case(XVID_PLG_FRAME):
335 :     break;
336 :     case(XVID_PLG_AFTER):
337 :     psnrhvsm_after((xvid_plg_data_t *)param1, (psnrhvsm_data_t *)handle);
338 :     break;
339 :     case(XVID_PLG_DESTROY):
340 :     {
341 :     uint32_t MSE_H;
342 :     psnrhvsm_data_t *psnrhvsm = (psnrhvsm_data_t *)handle;
343 :    
344 :     if (psnrhvsm) {
345 :     MSE_H = (uint32_t) (psnrhvsm->mse_sum / psnrhvsm->frame_cnt);
346 :    
347 :     emms();
348 :     printf("Average psnrhvsm: %2.2f\n", sse_to_PSNR(MSE_H, 256*psnrhvsm->pixels));
349 :     free(psnrhvsm);
350 :     }
351 :     }
352 :     break;
353 :     default:
354 :     break;
355 :     }
356 :     return 0;
357 :     };

No admin address has been configured
ViewVC Help
Powered by ViewVC 1.0.4