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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1757 - (view) (download)

1 : Skal 1730 /*****************************************************************************
2 :     *
3 :     * XVID MPEG-4 VIDEO CODEC
4 :     * - SSIM plugin: computes the SSIM metric -
5 :     *
6 :     * Copyright(C) 2005 Johannes Reinhardt <Johannes.Reinhardt@gmx.de>
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 :     *
23 :     *
24 :     ****************************************************************************/
25 :    
26 :     #include <malloc.h>
27 :     #include <stdio.h>
28 :     #include <math.h>
29 : Isibaar 1734 #include "../portab.h"
30 : Skal 1730 #include "../xvid.h"
31 :     #include "plugin_ssim.h"
32 :     #include "../utils/emms.h"
33 :    
34 :     /* needed for visualisation of the error map with X
35 :     display.h borrowed from x264
36 :     #include "display.h"*/
37 :    
38 :     typedef struct framestat_t framestat_t;
39 :    
40 : Skal 1757 /*dev 1.0 gaussian weighting. the weight for the pixel x,y is w(x)*w(y)*/
41 :     static float mask8[8] = {
42 :     0.0069815, 0.1402264, 1.0361408, 2.8165226,
43 :     2.8165226, 1.0361408, 0.1402264, 0.0069815
44 :     };
45 :    
46 : Skal 1730 struct framestat_t{
47 :     int type;
48 :     int quant;
49 :     float ssim_min;
50 :     float ssim_max;
51 :     float ssim_avg;
52 :     framestat_t* next;
53 :     };
54 :    
55 :    
56 :     typedef int (*lumfunc)(uint8_t* ptr, int stride);
57 :     typedef void (*csfunc)(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr);
58 :    
59 :     int lum_8x8_mmx(uint8_t* ptr, int stride);
60 :     void consim_mmx(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr);
61 :     void consim_sse2(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr);
62 :    
63 :     typedef struct{
64 :    
65 :     plg_ssim_param_t* param;
66 :    
67 :     /* for error map visualisation
68 :     uint8_t* errmap;
69 :     */
70 :    
71 : Skal 1743 int grid;
72 :    
73 : Skal 1730 /*for average SSIM*/
74 :     float ssim_sum;
75 :     int frame_cnt;
76 :    
77 :     /*function pointers*/
78 :     lumfunc func8x8;
79 :     lumfunc func2x8;
80 :     csfunc consim;
81 :    
82 :     /*stats - for debugging*/
83 :     framestat_t* head;
84 :     framestat_t* tail;
85 :     } ssim_data_t;
86 :    
87 :     /* append the stats for another frame to the linked list*/
88 :     void framestat_append(ssim_data_t* ssim,int type, int quant, float min, float max, float avg){
89 :     framestat_t* act;
90 :     act = (framestat_t*) malloc(sizeof(framestat_t));
91 :     act->type = type;
92 :     act->quant = quant;
93 :     act->ssim_min = min;
94 :     act->ssim_max = max;
95 :     act->ssim_avg = avg;
96 :     act->next = NULL;
97 :    
98 :     if(ssim->head == NULL){
99 :     ssim->head = act;
100 :     ssim->tail = act;
101 :     } else {
102 :     ssim->tail->next = act;
103 :     ssim->tail = act;
104 :     }
105 :     }
106 :    
107 :     /* destroy the whole list*/
108 :     void framestat_free(framestat_t* stat){
109 :     if(stat != NULL){
110 :     if(stat->next != NULL) framestat_free(stat->next);
111 :     free(stat);
112 :     }
113 :     return;
114 :     }
115 :    
116 :     /*writeout the collected stats*/
117 :     void framestat_write(ssim_data_t* ssim, char* path){
118 : Isibaar 1734 framestat_t* tmp = ssim->head;
119 : Skal 1730 FILE* out = fopen(path,"w");
120 :     if(out==NULL) printf("Cannot open %s in plugin_ssim\n",path);
121 :    
122 :     fprintf(out,"SSIM Error Metric\n");
123 : Skal 1737 fprintf(out,"quant avg min max\n");
124 : Skal 1730 while(tmp->next->next != NULL){
125 : Skal 1757 fprintf(out,"%3d %1.3f %1.3f %1.3f\n",tmp->quant,tmp->ssim_avg,tmp->ssim_min,tmp->ssim_max);
126 : Skal 1730 tmp = tmp->next;
127 :     }
128 :     fclose(out);
129 :     }
130 :    
131 :     /*writeout the collected stats in octave readable format*/
132 :     void framestat_write_oct(ssim_data_t* ssim, char* path){
133 : Isibaar 1734 framestat_t* tmp;
134 : Skal 1730 FILE* out = fopen(path,"w");
135 :     if(out==NULL) printf("Cannot open %s in plugin_ssim\n",path);
136 :    
137 :     fprintf(out,"quant = [");
138 :     tmp = ssim->head;
139 :     while(tmp->next->next != NULL){
140 :     fprintf(out,"%d, ",tmp->quant);
141 :     tmp = tmp->next;
142 :     }
143 :     fprintf(out,"%d];\n\n",tmp->quant);
144 :    
145 :     fprintf(out,"ssim_min = [");
146 :     tmp = ssim->head;
147 :     while(tmp->next->next != NULL){
148 :     fprintf(out,"%f, ",tmp->ssim_min);
149 :     tmp = tmp->next;
150 :     }
151 :     fprintf(out,"%f];\n\n",tmp->ssim_min);
152 :    
153 :     fprintf(out,"ssim_max = [");
154 :     tmp = ssim->head;
155 :     while(tmp->next->next != NULL){
156 :     fprintf(out,"%f, ",tmp->ssim_max);
157 :     tmp = tmp->next;
158 :     }
159 :     fprintf(out,"%f];\n\n",tmp->ssim_max);
160 :    
161 :     fprintf(out,"ssim_avg = [");
162 :     tmp = ssim->head;
163 :     while(tmp->next->next != NULL){
164 :     fprintf(out,"%f, ",tmp->ssim_avg);
165 :     tmp = tmp->next;
166 :     }
167 :     fprintf(out,"%f];\n\n",tmp->ssim_avg);
168 :    
169 :     fprintf(out,"ivop = [");
170 :     tmp = ssim->head;
171 :     while(tmp->next->next != NULL){
172 :     if(tmp->type == XVID_TYPE_IVOP){
173 :     fprintf(out,"%d, ",tmp->quant);
174 :     fprintf(out,"%f, ",tmp->ssim_avg);
175 :     fprintf(out,"%f, ",tmp->ssim_min);
176 :     fprintf(out,"%f; ",tmp->ssim_max);
177 :     }
178 :     tmp = tmp->next;
179 :     }
180 :     fprintf(out,"%d, ",tmp->quant);
181 :     fprintf(out,"%f, ",tmp->ssim_avg);
182 :     fprintf(out,"%f, ",tmp->ssim_min);
183 :     fprintf(out,"%f];\n\n",tmp->ssim_max);
184 :    
185 :     fprintf(out,"pvop = [");
186 :     tmp = ssim->head;
187 :     while(tmp->next->next != NULL){
188 :     if(tmp->type == XVID_TYPE_PVOP){
189 :     fprintf(out,"%d, ",tmp->quant);
190 :     fprintf(out,"%f, ",tmp->ssim_avg);
191 :     fprintf(out,"%f, ",tmp->ssim_min);
192 :     fprintf(out,"%f; ",tmp->ssim_max);
193 :     }
194 :     tmp = tmp->next;
195 :     }
196 :     fprintf(out,"%d, ",tmp->quant);
197 :     fprintf(out,"%f, ",tmp->ssim_avg);
198 :     fprintf(out,"%f, ",tmp->ssim_min);
199 :     fprintf(out,"%f];\n\n",tmp->ssim_max);
200 :    
201 :     fprintf(out,"bvop = [");
202 :     tmp = ssim->head;
203 :     while(tmp->next->next != NULL){
204 :     if(tmp->type == XVID_TYPE_BVOP){
205 :     fprintf(out,"%d, ",tmp->quant);
206 :     fprintf(out,"%f, ",tmp->ssim_avg);
207 :     fprintf(out,"%f, ",tmp->ssim_min);
208 :     fprintf(out,"%f; ",tmp->ssim_max);
209 :     }
210 :     tmp = tmp->next;
211 :     }
212 :     fprintf(out,"%d, ",tmp->quant);
213 :     fprintf(out,"%f, ",tmp->ssim_avg);
214 :     fprintf(out,"%f, ",tmp->ssim_min);
215 :     fprintf(out,"%f];\n\n",tmp->ssim_max);
216 :    
217 :     fclose(out);
218 :     }
219 :    
220 :     /*calculate the luminance of a 8x8 block*/
221 :     int lum_8x8_c(uint8_t* ptr, int stride){
222 :     int mean=0,i,j;
223 :     for(i=0;i< 8;i++)
224 :     for(j=0;j< 8;j++){
225 :     mean += ptr[i*stride + j];
226 :     }
227 :     return mean;
228 :     }
229 :    
230 : Skal 1757 int lum_8x8_gaussian(uint8_t* ptr, int stride){
231 :     float mean=0,sum;
232 :     int i,j;
233 :     for(i=0;i<8;i++){
234 :     sum = 0;
235 :     for(j=0;j<8;j++)
236 :     sum += ptr[i*stride + j]*mask8[j];
237 :    
238 :     sum *=mask8[i];
239 :     mean += sum;
240 :     }
241 :     return (int) mean + 0.5;
242 :     }
243 :    
244 : Skal 1730 /*calculate the difference between two blocks next to each other on a row*/
245 :     int lum_2x8_c(uint8_t* ptr, int stride){
246 :     int mean=0,i;
247 :     /*Luminance*/
248 :     for(i=0;i< 8;i++){
249 :     mean -= *(ptr-1);
250 :     mean += *(ptr+ 8 - 1);
251 :     ptr+=stride;
252 :     }
253 :     return mean;
254 :     }
255 :    
256 :     /*calculate contrast and correlation of the two blocks*/
257 : Skal 1757 void consim_gaussian(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr){
258 :     unsigned int valo, valc,i,j,str;
259 :     float devo=0, devc=0, corr=0,sumo,sumc,sumcorr;
260 :     str = stride - 8;
261 :     for(i=0;i< 8;i++){
262 :     sumo = 0;
263 :     sumc = 0;
264 :     sumcorr = 0;
265 :     for(j=0;j< 8;j++){
266 :     valo = *ptro;
267 :     valc = *ptrc;
268 :     sumo += valo*valo*mask8[j];
269 :     sumc += valc*valc*mask8[j];
270 :     sumcorr += valo*valc*mask8[j];
271 :     ptro++;
272 :     ptrc++;
273 :     }
274 :    
275 :     devo += sumo*mask8[i];
276 :     devc += sumc*mask8[i];
277 :     corr += sumcorr*mask8[i];
278 :     ptro += str;
279 :     ptrc += str;
280 :     }
281 :    
282 :     *pdevo = (int) (devo - ((lumo*lumo + 32) >> 6)) + 0.5;
283 :     *pdevc = (int) (devc - ((lumc*lumc + 32) >> 6)) + 0.5;
284 :     *pcorr = (int) (corr - ((lumo*lumc + 32) >> 6)) + 0.5;
285 :     };
286 :    
287 :     /*calculate contrast and correlation of the two blocks*/
288 : Skal 1743 void consim_c(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr){
289 :     unsigned int valo, valc, devo=0, devc=0, corr=0,i,j,str;
290 :     str = stride - 8;
291 : Skal 1730 for(i=0;i< 8;i++){
292 :     for(j=0;j< 8;j++){
293 : Skal 1743 valo = *ptro;
294 :     valc = *ptrc;
295 : Skal 1730 devo += valo*valo;
296 : Skal 1743 devc += valc*valc;
297 :     corr += valo*valc;
298 : Skal 1730 ptro++;
299 :     ptrc++;
300 :     }
301 : Skal 1743 ptro += str;
302 :     ptrc += str;
303 : Skal 1730 }
304 : Skal 1743
305 :     *pdevo = devo - ((lumo*lumo + 32) >> 6);
306 :     *pdevc = devc - ((lumc*lumc + 32) >> 6);
307 :     *pcorr = corr - ((lumo*lumc + 32) >> 6);
308 : Skal 1730 };
309 :    
310 :     /*calculate the final ssim value*/
311 : Skal 1757 static float calc_ssim(float meano, float meanc, float devo, float devc, float corr){
312 : Skal 1730 static const float c1 = (0.01*255)*(0.01*255);
313 :     static const float c2 = (0.03*255)*(0.03*255);
314 : Skal 1757 /*printf("meano: %f meanc: %f devo: %f devc: %f corr: %f\n",meano,meanc,devo,devc,corr);*/
315 :     return ((2.0*meano*meanc + c1)*(corr/32.0 + c2))/((meano*meano + meanc*meanc + c1)*(devc/64.0 + devo/64.0 + c2));
316 : Skal 1730 }
317 :    
318 :     static void ssim_after(xvid_plg_data_t* data, ssim_data_t* ssim){
319 : Skal 1757 int i,j,c=0,opt;
320 : Skal 1730 int width,height,str,ovr;
321 :     unsigned char * ptr1,*ptr2;
322 :     float isum=0, min=1.00,max=0.00, val;
323 :     int meanc, meano;
324 :     int devc, devo, corr;
325 :    
326 :     width = data->width - 8;
327 :     height = data->height - 8;
328 :     str = data->original.stride[0];
329 :     if(str != data->current.stride[0]) printf("WARNING: Different strides in plugin_ssim original: %d current: %d\n",str,data->current.stride[0]);
330 : Skal 1743 ovr = str - width + (width % ssim->grid);
331 : Skal 1730
332 :     ptr1 = (unsigned char*) data->original.plane[0];
333 :     ptr2 = (unsigned char*) data->current.plane[0];
334 :    
335 : Skal 1757 opt = ssim->grid == 1 && ssim->param->acc != 0;
336 : Skal 1730
337 :     /*TODO: Thread*/
338 : Skal 1743 for(i=0;i<height;i+=ssim->grid){
339 : Skal 1730 /*begin of each row*/
340 :     meano = meanc = devc = devo = corr = 0;
341 :     meano = ssim->func8x8(ptr1,str);
342 :     meanc = ssim->func8x8(ptr2,str);
343 : Skal 1743 ssim->consim(ptr1,ptr2,str,meano,meanc,&devo,&devc,&corr);
344 : Skal 1732 emms();
345 :    
346 : Skal 1757 val = calc_ssim((float) meano,(float) meanc,(float) devo,(float) devc,(float) corr);
347 : Skal 1730 isum += val;
348 :     c++;
349 :     /* for visualisation
350 :     if(ssim->param->b_visualize)
351 :     ssim->errmap[i*width] = (uint8_t) 127*val;
352 :     */
353 :    
354 : Skal 1743
355 : Skal 1730 if(val < min) min = val;
356 :     if(val > max) max = val;
357 : Skal 1743 ptr1+=ssim->grid;
358 :     ptr2+=ssim->grid;
359 : Skal 1730 /*rest of each row*/
360 : Skal 1743 for(j=ssim->grid;j<width;j+=ssim->grid){
361 : Skal 1757 if(opt){
362 :     meano += ssim->func2x8(ptr1,str);
363 :     meanc += ssim->func2x8(ptr2,str);
364 :     } else {
365 :     meano = ssim->func8x8(ptr1,str);
366 :     meanc = ssim->func8x8(ptr2,str);
367 : Skal 1743 }
368 :     ssim->consim(ptr1,ptr2,str,meano,meanc,&devo,&devc,&corr);
369 : Skal 1732 emms();
370 :    
371 : Skal 1757 val = calc_ssim((float) meano,(float) meanc,(float) devo,(float) devc,(float) corr);
372 : Skal 1730 isum += val;
373 :     c++;
374 :     /* for visualisation
375 :     if(ssim->param->b_visualize)
376 :     ssim->errmap[i*width +j] = (uint8_t) 255*val;
377 :     */
378 :     if(val < min) min = val;
379 :     if(val > max) max = val;
380 : Skal 1743 ptr1+=ssim->grid;
381 :     ptr2+=ssim->grid;
382 : Skal 1730 }
383 :     ptr1 +=ovr;
384 :     ptr2 +=ovr;
385 :     }
386 :     isum/=c;
387 :     ssim->ssim_sum += isum;
388 :     ssim->frame_cnt++;
389 :    
390 :     if(ssim->param->stat_path != NULL)
391 :     framestat_append(ssim,data->type,data->quant,min,max,isum);
392 :    
393 :     /* for visualization
394 :     if(ssim->param->b_visualize){
395 :     disp_gray(0,ssim->errmap,width,height,width, "Error-Map");
396 :     disp_gray(1,data->original.plane[0],data->width,data->height,data->original.stride[0],"Original");
397 :     disp_gray(2,data->current.plane[0],data->width,data->height,data->original.stride[0],"Compressed");
398 :     disp_sync();
399 :     }
400 :     */
401 :     if(ssim->param->b_printstat){
402 : Skal 1757 printf(" SSIM: avg: %1.3f min: %1.3f max: %1.3f\n",isum,min,max);
403 : Skal 1730 }
404 :    
405 :     }
406 :    
407 :     static int ssim_create(xvid_plg_create_t* create, void** handle){
408 :     ssim_data_t* ssim;
409 :     plg_ssim_param_t* param;
410 :     int cpu_flags;
411 :     param = (plg_ssim_param_t*) malloc(sizeof(plg_ssim_param_t));
412 :     *param = *((plg_ssim_param_t*) create->param);
413 :     ssim = (ssim_data_t*) malloc(sizeof(ssim_data_t));
414 :    
415 :     cpu_flags = check_cpu_features();
416 :    
417 :     ssim->func8x8 = lum_8x8_c;
418 :     ssim->func2x8 = lum_2x8_c;
419 : Skal 1743 ssim->consim = consim_c;
420 : Skal 1730
421 :     ssim->param = param;
422 :    
423 : Skal 1743 ssim->grid = param->acc;
424 :    
425 : Skal 1732 #if defined(ARCH_IS_IA32)
426 : Skal 1743 if((cpu_flags & XVID_CPU_MMX) && (param->acc > 0)){
427 : Skal 1730 ssim->func8x8 = lum_8x8_mmx;
428 :     ssim->consim = consim_mmx;
429 :     }
430 : Skal 1743 if((cpu_flags & XVID_CPU_SSE2) && (param->acc > 0)){
431 : Skal 1730 ssim->consim = consim_sse2;
432 :     }
433 : Skal 1732 #endif
434 : Skal 1730
435 : Skal 1757 /*gaussian weigthing not implemented*/
436 :     if(ssim->grid == 0){
437 :     ssim->grid = 1;
438 :     ssim->func8x8 = lum_8x8_gaussian;
439 :     ssim->func2x8 = NULL;
440 :     ssim->consim = consim_gaussian;
441 :     }
442 :     if(ssim->grid > 4) ssim->grid = 4;
443 :    
444 : Skal 1730 ssim->ssim_sum = 0.0;
445 :     ssim->frame_cnt = 0;
446 :    
447 :     /* for visualization
448 :     if(param->b_visualize){
449 :     //error map
450 :     ssim->errmap = (uint8_t*) malloc(sizeof(uint8_t)*(create->width-8)*(create->height-8));
451 :     } else {
452 :     ssim->errmap = NULL;
453 :     };
454 :     */
455 :    
456 :     /*stats*/
457 :     ssim->head=NULL;
458 :     ssim->tail=NULL;
459 :    
460 :     *(handle) = (void*) ssim;
461 :    
462 :     return 0;
463 :     }
464 :    
465 :     int xvid_plugin_ssim(void * handle, int opt, void * param1, void * param2){
466 :     ssim_data_t* ssim;
467 :     switch(opt){
468 :     case(XVID_PLG_INFO):
469 :     ((xvid_plg_info_t*) param1)->flags = XVID_REQORIGINAL;
470 :     break;
471 :     case(XVID_PLG_CREATE):
472 :     ssim_create((xvid_plg_create_t*) param1,(void**) param2);
473 :     break;
474 :     case(XVID_PLG_BEFORE):
475 :     case(XVID_PLG_FRAME):
476 :     break;
477 :     case(XVID_PLG_AFTER):
478 :     ssim_after((xvid_plg_data_t*) param1, (ssim_data_t*) handle);
479 :     break;
480 :     case(XVID_PLG_DESTROY):
481 :     ssim = (ssim_data_t*) handle;
482 :     printf("Average SSIM: %f\n",ssim->ssim_sum/ssim->frame_cnt);
483 :     if(ssim->param->stat_path != NULL)
484 :     framestat_write(ssim,ssim->param->stat_path);
485 :     framestat_free(ssim->head);
486 : Skal 1737 /*free(ssim->errmap);*/
487 : Skal 1730 free(ssim->param);
488 :     free(ssim);
489 :     break;
490 :     default:
491 :     break;
492 :     }
493 :     return 0;
494 :     };

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