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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (view) (download)

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

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