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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (view) (download)

1 : Isibaar 1.1 /*****************************************************************************
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 : Isibaar 1.3 * $Id: plugin_psnrhvsm.c,v 1.2 2010/11/08 20:20:39 Isibaar Exp $
23 : Isibaar 1.1 *
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 : Isibaar 1.3 uint64_t mse_sum_y; /* for avrg psnr-hvs-m */
52 :     uint64_t mse_sum_u;
53 :     uint64_t mse_sum_v;
54 :    
55 : Isibaar 1.1 long frame_cnt;
56 :    
57 :     } psnrhvsm_data_t; /* internal plugin data */
58 :    
59 :     static const float CSF_Coeff[64] =
60 :     { 1.608443f, 2.339554f, 2.573509f, 1.608443f, 1.072295f, 0.643377f, 0.504610f, 0.421887f,
61 :     2.144591f, 2.144591f, 1.838221f, 1.354478f, 0.989811f, 0.443708f, 0.428918f, 0.467911f,
62 :     1.838221f, 1.979622f, 1.608443f, 1.072295f, 0.643377f, 0.451493f, 0.372972f, 0.459555f,
63 :     1.838221f, 1.513829f, 1.169777f, 0.887417f, 0.504610f, 0.295806f, 0.321689f, 0.415082f,
64 :     1.429727f, 1.169777f, 0.695543f, 0.459555f, 0.378457f, 0.236102f, 0.249855f, 0.334222f,
65 :     1.072295f, 0.735288f, 0.467911f, 0.402111f, 0.317717f, 0.247453f, 0.227744f, 0.279729f,
66 :     0.525206f, 0.402111f, 0.329937f, 0.295806f, 0.249855f, 0.212687f, 0.214459f, 0.254803f,
67 :     0.357432f, 0.279729f, 0.270896f, 0.262603f, 0.229778f, 0.257351f, 0.249855f, 0.259950f
68 :     };
69 :    
70 :     static const float Mask_Coeff[64] =
71 :     { 0.000000f, 0.826446f, 1.000000f, 0.390625f, 0.173611f, 0.062500f, 0.038447f, 0.026874f,
72 :     0.694444f, 0.694444f, 0.510204f, 0.277008f, 0.147929f, 0.029727f, 0.027778f, 0.033058f,
73 :     0.510204f, 0.591716f, 0.390625f, 0.173611f, 0.062500f, 0.030779f, 0.021004f, 0.031888f,
74 :     0.510204f, 0.346021f, 0.206612f, 0.118906f, 0.038447f, 0.013212f, 0.015625f, 0.026015f,
75 :     0.308642f, 0.206612f, 0.073046f, 0.031888f, 0.021626f, 0.008417f, 0.009426f, 0.016866f,
76 :     0.173611f, 0.081633f, 0.033058f, 0.024414f, 0.015242f, 0.009246f, 0.007831f, 0.011815f,
77 :     0.041649f, 0.024414f, 0.016437f, 0.013212f, 0.009426f, 0.006830f, 0.006944f, 0.009803f,
78 :     0.019290f, 0.011815f, 0.011080f, 0.010412f, 0.007972f, 0.010000f, 0.009426f, 0.010203f
79 :     };
80 :    
81 : Isibaar 1.2 #if 0 /* Floating-point implementation */
82 : Isibaar 1.1
83 :     static uint32_t Calc_MSE_H(int16_t *DCT_A, int16_t *DCT_B, uint8_t *IMG_A, uint8_t *IMG_B, int stride)
84 :     {
85 :     int x, y, i, j;
86 :     uint32_t Global_A, Global_B, Sum_A = 0, Sum_B = 0;
87 :     uint32_t Local[8] = {0, 0, 0, 0, 0, 0, 0, 0};
88 :     uint32_t Local_Square[8] = {0, 0, 0, 0, 0, 0, 0, 0};
89 :     float MASK_A = 0.f, MASK_B = 0.f;
90 : Isibaar 1.2 float Mult1 = 1.f, Mult2 = 1.f;
91 : Isibaar 1.1 uint32_t MSE_H = 0;
92 :    
93 :     /* Step 1: Calculate CSF weighted energy of DCT coefficients */
94 :     for (y = 0; y < 8; y++) {
95 :     for (x = 0; x < 8; x++) {
96 :     MASK_A += (float)(DCT_A[y*8 + x]*DCT_A[y*8 + x])*Mask_Coeff[y*8 + x];
97 :     MASK_B += (float)(DCT_B[y*8 + x]*DCT_B[y*8 + x])*Mask_Coeff[y*8 + x];
98 :     }
99 :     }
100 :    
101 :     /* Step 2: Determine local variances compared to entire block variance */
102 :     for (y = 0; y < 2; y++) {
103 :     for (x = 0; x < 2; x++) {
104 : Isibaar 1.2 for (j = 0; j < 4; j++) {
105 :     for (i = 0; i < 4; i++) {
106 :     uint8_t A = IMG_A[(y*4+j)*stride + 4*x + i];
107 :     uint8_t B = IMG_B[(y*4+j)*stride + 4*x + i];
108 :    
109 :     Local[y*2 + x] += A;
110 :     Local[y*2 + x + 4] += B;
111 :     Local_Square[y*2 + x] += A*A;
112 :     Local_Square[y*2 + x + 4] += B*B;
113 :     }
114 : Isibaar 1.1 }
115 :     }
116 :     }
117 :    
118 :     Global_A = Local[0] + Local[1] + Local[2] + Local[3];
119 :     Global_B = Local[4] + Local[5] + Local[6] + Local[7];
120 :    
121 :     for (i = 0; i < 8; i++)
122 :     Local[i] = (Local_Square[i]<<4) - (Local[i]*Local[i]); /* 16*Var(Di) */
123 :    
124 :     Local_Square[0] += (Local_Square[1] + Local_Square[2] + Local_Square[3]);
125 :     Local_Square[4] += (Local_Square[5] + Local_Square[6] + Local_Square[7]);
126 :    
127 :     Global_A = (Local_Square[0]<<6) - Global_A*Global_A; /* 64*Var(D) */
128 :     Global_B = (Local_Square[4]<<6) - Global_B*Global_B; /* 64*Var(D) */
129 :    
130 :     /* Step 3: Calculate contrast masking threshold */
131 : Isibaar 1.2 if (Global_A)
132 :     Mult1 = (float)(Local[0]+Local[1]+Local[2]+Local[3])/((float)(Global_A)/4.f);
133 :    
134 :     if (Global_B)
135 :     Mult2 = (float)(Local[4]+Local[5]+Local[6]+Local[7])/((float)(Global_B)/4.f);
136 :    
137 :     MASK_A = (float)sqrt(MASK_A * Mult1) / 32.f;
138 :     MASK_B = (float)sqrt(MASK_B * Mult2) / 32.f;
139 : Isibaar 1.1
140 :     if (MASK_B > MASK_A) MASK_A = MASK_B; /* MAX(MASK_A, MASK_B) */
141 :    
142 :     /* Step 4: Calculate MSE of DCT coeffs reduced by masking effect */
143 :     for (j = 0; j < 8; j++) {
144 :     for (i = 0; i < 8; i++) {
145 :     float u = (float)abs(DCT_A[j*8 + i] - DCT_B[j*8 + i]);
146 :    
147 :     if ((i|j)>0) {
148 :     if (u < (MASK_A / Mask_Coeff[j*8 + i]))
149 :     u = 0; /* The error is not perceivable */
150 :     else
151 :     u -= (MASK_A / Mask_Coeff[j*8 + i]);
152 :     }
153 :    
154 :     MSE_H += (uint32_t) ((256.f*(u * CSF_Coeff[j*8 + i])*(u * CSF_Coeff[j*8 + i])) + 0.5f);
155 :     }
156 :     }
157 :     return MSE_H; /* Fixed-point value right-shifted by eight */
158 :     }
159 :    
160 : Isibaar 1.3 #else
161 :    
162 :     /* First draft of a fixed-point implementation.
163 :     Might serve as a template for MMX/SSE code */
164 : Isibaar 1.1
165 :     static const uint16_t iMask_Coeff[64] =
166 :     { 0, 59577, 65535, 40959, 27306, 16384, 12850, 10743,
167 :     54612, 54612, 46811, 34492, 25206, 11299, 10923, 11915,
168 :     46811, 50412, 40959, 27306, 16384, 11497, 9498, 11703,
169 :     46811, 38550, 29789, 22598, 12850, 7533, 8192, 10570,
170 :     36408, 29789, 17712, 11703, 9637, 6012, 6363, 8511,
171 :     27306, 18724, 11915, 10240, 8091, 6302, 5799, 7123,
172 :     13374, 10240, 8402, 7533, 6363, 5416, 5461, 6489,
173 :     9102, 7123, 6898, 6687, 5851, 6553, 6363, 6620
174 :     };
175 :    
176 :     static const uint16_t Inv_iMask_Coeff[64] =
177 :     { 0, 310, 256, 655, 1475, 4096, 6659, 9526,
178 :     369, 369, 502, 924, 1731, 8612, 9216, 7744,
179 :     502, 433, 655, 1475, 4096, 8317, 12188, 8028,
180 :     502, 740, 1239, 2153, 6659, 19376, 16384, 9840,
181 :     829, 1239, 3505, 8028, 11838, 30415, 27159, 15178,
182 :     1475, 3136, 7744, 10486, 16796, 27688, 32691, 21667,
183 :     6147, 10486, 15575, 19376, 27159, 37482, 36866, 26114,
184 :     13271, 21667, 23105, 24587, 32112, 25600, 27159, 25091
185 :     };
186 :    
187 :     static const uint16_t iCSF_Coeff[64] =
188 :     { 1647, 2396, 2635, 1647, 1098, 659, 517, 432,
189 :     2196, 2196, 1882, 1387, 1014, 454, 439, 479,
190 :     1882, 2027, 1647, 1098, 659, 462, 382, 471,
191 :     1882, 1550, 1198, 909, 517, 303, 329, 425,
192 :     1464, 1198, 712, 471, 388, 242, 256, 342,
193 :     1098, 753, 479, 412, 325, 253, 233, 286,
194 :     538, 412, 338, 303, 256, 218, 220, 261,
195 :     366, 286, 277, 269, 235, 264, 256, 266
196 :     };
197 :    
198 : Isibaar 1.2 static __inline uint32_t isqrt(unsigned long n)
199 :     {
200 :     uint32_t c = 0x8000;
201 :     uint32_t g = 0x8000;
202 :    
203 :     for(;;) {
204 :     if(g*g > n)
205 :     g ^= c;
206 :     c >>= 1;
207 :     if(c == 0)
208 :     return g;
209 :     g |= c;
210 :     }
211 :     }
212 :    
213 : Isibaar 1.1 static uint32_t Calc_MSE_H(int16_t *DCT_A, int16_t *DCT_B, uint8_t *IMG_A, uint8_t *IMG_B, int stride)
214 :     {
215 :     int x, y, i, j;
216 :     uint32_t Global_A, Global_B, Sum_A = 0, Sum_B = 0;
217 :     uint32_t Local[8] = {0, 0, 0, 0, 0, 0, 0, 0};
218 :     uint32_t Local_Square[8] = {0, 0, 0, 0, 0, 0, 0, 0};
219 :     uint32_t MASK;
220 :     uint32_t MSE_H = 0;
221 :    
222 :     /* Step 1: Calculate CSF weighted energy of DCT coefficients */
223 :     for (y = 0; y < 8; y++) {
224 :     for (x = 0; x < 8; x++) {
225 :     uint16_t A = (abs(DCT_A[y*8 + x]) * iMask_Coeff[y*8 + x] + 4096) >> 13;
226 :     uint16_t B = (abs(DCT_B[y*8 + x]) * iMask_Coeff[y*8 + x] + 4096) >> 13;
227 :    
228 :     Sum_A += ((A*A) >> 3); /* PMADDWD */
229 :     Sum_B += ((B*B) >> 3);
230 :     }
231 :     }
232 :    
233 :     /* Step 2: Determine local variances compared to entire block variance */
234 :     for (y = 0; y < 2; y++) {
235 :     for (x = 0; x < 2; x++) {
236 : Isibaar 1.2 for (j = 0; j < 4; j++) {
237 :     for (i = 0; i < 4; i++) {
238 :     uint8_t A = IMG_A[(y*4+j)*stride + 4*x + i];
239 :     uint8_t B = IMG_B[(y*4+j)*stride + 4*x + i];
240 :    
241 :     Local[y*2 + x] += A;
242 :     Local[y*2 + x + 4] += B;
243 :     Local_Square[y*2 + x] += A*A;
244 :     Local_Square[y*2 + x + 4] += B*B;
245 :     }
246 : Isibaar 1.1 }
247 :     }
248 :     }
249 :    
250 :     Global_A = Local[0] + Local[1] + Local[2] + Local[3];
251 :     Global_B = Local[4] + Local[5] + Local[6] + Local[7];
252 :    
253 :     for (i = 0; i < 8; i++)
254 :     Local[i] = (Local_Square[i]<<4) - (Local[i]*Local[i]); /* 16*Var(Di) */
255 :    
256 :     Local_Square[0] += (Local_Square[1] + Local_Square[2] + Local_Square[3]);
257 :     Local_Square[4] += (Local_Square[5] + Local_Square[6] + Local_Square[7]);
258 :    
259 :     Global_A = (Local_Square[0]<<6) - Global_A*Global_A; /* 64*Var(D) */
260 :     Global_B = (Local_Square[4]<<6) - Global_B*Global_B; /* 64*Var(D) */
261 :    
262 :     /* Step 3: Calculate contrast masking threshold */
263 :     {
264 : Isibaar 1.2 uint32_t MASK_A, MASK_B;
265 :     uint32_t Mult1 = 64, Mult2 = 64;
266 :    
267 :     if (Global_A)
268 :     Mult1 = ((Local[0]+Local[1]+Local[2]+Local[3])<<8) / Global_A;
269 : Isibaar 1.1
270 : Isibaar 1.2 if (Global_B)
271 :     Mult2 = ((Local[4]+Local[5]+Local[6]+Local[7])<<8) / Global_B;
272 : Isibaar 1.1
273 : Isibaar 1.2 MASK_A = isqrt(2*Sum_A*Mult1) + 16;
274 :     MASK_B = isqrt(2*Sum_B*Mult2) + 16;
275 : Isibaar 1.1
276 :     if (MASK_B > MASK_A) /* MAX(MASK_A, MASK_B) */
277 : Isibaar 1.2 MASK = (uint32_t) MASK_B;
278 : Isibaar 1.1 else
279 : Isibaar 1.2 MASK = (uint32_t) MASK_A;
280 : Isibaar 1.1 }
281 :    
282 :     /* Step 4: Calculate MSE of DCT coeffs reduced by masking effect */
283 :     for (j = 0; j < 8; j++) {
284 :     for (i = 0; i < 8; i++) {
285 :     uint32_t Thresh = (MASK * Inv_iMask_Coeff[j*8 + i] + 128) >> 8;
286 :     uint32_t u = abs(DCT_A[j*8 + i] - DCT_B[j*8 + i]) << 10;
287 :    
288 :     if ((i|j)>0) {
289 :     if (u < Thresh)
290 :     u = 0; /* The error is not perceivable */
291 :     else
292 :     u -= Thresh;
293 :     }
294 :    
295 :     {
296 :     uint64_t tmp = (u * iCSF_Coeff[j*8 + i] + 512) >> 10;
297 :     MSE_H += (uint32_t) ((tmp * tmp) >> 12);
298 :     }
299 :     }
300 :     }
301 :     return MSE_H;
302 :     }
303 :    
304 :     #endif
305 :    
306 :     static void psnrhvsm_after(xvid_plg_data_t *data, psnrhvsm_data_t *psnrhvsm)
307 :     {
308 :     DECLARE_ALIGNED_MATRIX(DCT, 2, 64, int16_t, CACHE_LINE);
309 : Isibaar 1.3 int32_t x, y, u, v;
310 : Isibaar 1.1 int16_t *DCT_A = &DCT[0], *DCT_B = &DCT[64];
311 : Isibaar 1.3 uint64_t sse_y = 0, sse_u = 0, sse_v = 0;
312 :    
313 :     for (y = 0; y < data->height>>3; y++) {
314 :     uint8_t *IMG_A = (uint8_t *) data->original.plane[0];
315 :     uint8_t *IMG_B = (uint8_t *) data->current.plane[0];
316 :     uint32_t stride = data->original.stride[0];
317 :    
318 :     for (x = 0; x < data->width>>3; x++) { /* non multiple of 8 handling ?? */
319 :     int offset = (y<<3)*stride + (x<<3);
320 : Isibaar 1.1
321 :     emms();
322 :    
323 :     /* Transfer data */
324 :     transfer_8to16copy(DCT_A, IMG_A + offset, stride);
325 :     transfer_8to16copy(DCT_B, IMG_B + offset, stride);
326 :    
327 :     /* Perform DCT */
328 :     fdct(DCT_A);
329 :     fdct(DCT_B);
330 :    
331 :     emms();
332 :    
333 :     /* Calculate MSE_H reduced by contrast masking effect */
334 : Isibaar 1.3 sse_y += Calc_MSE_H(DCT_A, DCT_B, IMG_A + offset, IMG_B + offset, stride);
335 : Isibaar 1.1 }
336 :     }
337 :    
338 : Isibaar 1.3 for (y = 0; y < data->height>>4; y++) {
339 :     uint8_t *U_A = (uint8_t *) data->original.plane[1];
340 :     uint8_t *V_A = (uint8_t *) data->original.plane[2];
341 :     uint8_t *U_B = (uint8_t *) data->current.plane[1];
342 :     uint8_t *V_B = (uint8_t *) data->current.plane[2];
343 :     uint32_t stride_uv = data->current.stride[1];
344 :    
345 :     for (x = 0; x < data->width>>4; x++) { /* non multiple of 8 handling ?? */
346 :     int offset = (y<<3)*stride_uv + (x<<3);
347 :    
348 :     emms();
349 :    
350 :     /* Transfer data */
351 :     transfer_8to16copy(DCT_A, U_A + offset, stride_uv);
352 :     transfer_8to16copy(DCT_B, U_B + offset, stride_uv);
353 :    
354 :     /* Perform DCT */
355 :     fdct(DCT_A);
356 :     fdct(DCT_B);
357 :    
358 :     emms();
359 :    
360 :     /* Calculate MSE_H reduced by contrast masking effect */
361 :     sse_u += Calc_MSE_H(DCT_A, DCT_B, U_A + offset, U_B + offset, stride_uv);
362 :    
363 :     emms();
364 :    
365 :     /* Transfer data */
366 :     transfer_8to16copy(DCT_A, V_A + offset, stride_uv);
367 :     transfer_8to16copy(DCT_B, V_B + offset, stride_uv);
368 :    
369 :     /* Perform DCT */
370 :     fdct(DCT_A);
371 :     fdct(DCT_B);
372 :    
373 :     emms();
374 :    
375 :     /* Calculate MSE_H reduced by contrast masking effect */
376 :     sse_v += Calc_MSE_H(DCT_A, DCT_B, V_A + offset, V_B + offset, stride_uv);
377 :     }
378 :     }
379 :    
380 :     y = (int32_t) ( 4*sse_y / (data->width * data->height));
381 :     u = (int32_t) (16*sse_u / (data->width * data->height));
382 :     v = (int32_t) (16*sse_v / (data->width * data->height));
383 :    
384 :     psnrhvsm->mse_sum_y += y;
385 :     psnrhvsm->mse_sum_u += u;
386 :     psnrhvsm->mse_sum_v += v;
387 : Isibaar 1.1 psnrhvsm->frame_cnt++;
388 :    
389 : Isibaar 1.3 printf(" psnrhvsm y: %2.2f, psnrhvsm u: %2.2f, psnrhvsm v: %2.2f\n", sse_to_PSNR(y, 1024), sse_to_PSNR(u, 1024), sse_to_PSNR(v, 1024));
390 : Isibaar 1.1 }
391 :    
392 :     static int psnrhvsm_create(xvid_plg_create_t *create, void **handle)
393 :     {
394 :     psnrhvsm_data_t *psnrhvsm;
395 :     psnrhvsm = (psnrhvsm_data_t *) malloc(sizeof(psnrhvsm_data_t));
396 :    
397 : Isibaar 1.3 psnrhvsm->mse_sum_y = 0;
398 :     psnrhvsm->mse_sum_u = 0;
399 :     psnrhvsm->mse_sum_v = 0;
400 :    
401 : Isibaar 1.1 psnrhvsm->frame_cnt = 0;
402 :    
403 :     *(handle) = (void*) psnrhvsm;
404 :     return 0;
405 :     }
406 :    
407 :     int xvid_plugin_psnrhvsm(void *handle, int opt, void *param1, void *param2)
408 :     {
409 :     switch(opt) {
410 :     case(XVID_PLG_INFO):
411 :     ((xvid_plg_info_t *)param1)->flags = XVID_REQORIGINAL;
412 :     break;
413 :     case(XVID_PLG_CREATE):
414 :     psnrhvsm_create((xvid_plg_create_t *)param1,(void **)param2);
415 :     break;
416 :     case(XVID_PLG_BEFORE):
417 :     case(XVID_PLG_FRAME):
418 :     break;
419 :     case(XVID_PLG_AFTER):
420 :     psnrhvsm_after((xvid_plg_data_t *)param1, (psnrhvsm_data_t *)handle);
421 :     break;
422 :     case(XVID_PLG_DESTROY):
423 :     {
424 : Isibaar 1.3 uint32_t y, u, v;
425 : Isibaar 1.1 psnrhvsm_data_t *psnrhvsm = (psnrhvsm_data_t *)handle;
426 :    
427 :     if (psnrhvsm) {
428 : Isibaar 1.3 y = (uint32_t) (psnrhvsm->mse_sum_y / psnrhvsm->frame_cnt);
429 :     u = (uint32_t) (psnrhvsm->mse_sum_u / psnrhvsm->frame_cnt);
430 :     v = (uint32_t) (psnrhvsm->mse_sum_v / psnrhvsm->frame_cnt);
431 : Isibaar 1.1
432 :     emms();
433 : Isibaar 1.3 printf("Average psnrhvsm y: %2.2f, psnrhvsm u: %2.2f, psnrhvsm v: %2.2f\n",
434 :     sse_to_PSNR(y, 1024), sse_to_PSNR(u, 1024), sse_to_PSNR(v, 1024));
435 : Isibaar 1.1 free(psnrhvsm);
436 :     }
437 :     }
438 :     break;
439 :     default:
440 :     break;
441 :     }
442 :     return 0;
443 :     };

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