[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 1730 - (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 :     #include <stdint.h>
30 :     #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 :     FILE* out = fopen(path,"w");
111 :     if(out==NULL) printf("Cannot open %s in plugin_ssim\n",path);
112 :     framestat_t* tmp = ssim->head;
113 :    
114 :     fprintf(out,"SSIM Error Metric\n");
115 :     fprintf(out,"quant avg min max");
116 :     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 :    
126 :     FILE* out = fopen(path,"w");
127 :     if(out==NULL) printf("Cannot open %s in plugin_ssim\n",path);
128 :     framestat_t* tmp;
129 :    
130 :     fprintf(out,"quant = [");
131 :     tmp = ssim->head;
132 :     while(tmp->next->next != NULL){
133 :     fprintf(out,"%d, ",tmp->quant);
134 :     tmp = tmp->next;
135 :     }
136 :     fprintf(out,"%d];\n\n",tmp->quant);
137 :    
138 :     fprintf(out,"ssim_min = [");
139 :     tmp = ssim->head;
140 :     while(tmp->next->next != NULL){
141 :     fprintf(out,"%f, ",tmp->ssim_min);
142 :     tmp = tmp->next;
143 :     }
144 :     fprintf(out,"%f];\n\n",tmp->ssim_min);
145 :    
146 :     fprintf(out,"ssim_max = [");
147 :     tmp = ssim->head;
148 :     while(tmp->next->next != NULL){
149 :     fprintf(out,"%f, ",tmp->ssim_max);
150 :     tmp = tmp->next;
151 :     }
152 :     fprintf(out,"%f];\n\n",tmp->ssim_max);
153 :    
154 :     fprintf(out,"ssim_avg = [");
155 :     tmp = ssim->head;
156 :     while(tmp->next->next != NULL){
157 :     fprintf(out,"%f, ",tmp->ssim_avg);
158 :     tmp = tmp->next;
159 :     }
160 :     fprintf(out,"%f];\n\n",tmp->ssim_avg);
161 :    
162 :     fprintf(out,"ivop = [");
163 :     tmp = ssim->head;
164 :     while(tmp->next->next != NULL){
165 :     if(tmp->type == XVID_TYPE_IVOP){
166 :     fprintf(out,"%d, ",tmp->quant);
167 :     fprintf(out,"%f, ",tmp->ssim_avg);
168 :     fprintf(out,"%f, ",tmp->ssim_min);
169 :     fprintf(out,"%f; ",tmp->ssim_max);
170 :     }
171 :     tmp = tmp->next;
172 :     }
173 :     fprintf(out,"%d, ",tmp->quant);
174 :     fprintf(out,"%f, ",tmp->ssim_avg);
175 :     fprintf(out,"%f, ",tmp->ssim_min);
176 :     fprintf(out,"%f];\n\n",tmp->ssim_max);
177 :    
178 :     fprintf(out,"pvop = [");
179 :     tmp = ssim->head;
180 :     while(tmp->next->next != NULL){
181 :     if(tmp->type == XVID_TYPE_PVOP){
182 :     fprintf(out,"%d, ",tmp->quant);
183 :     fprintf(out,"%f, ",tmp->ssim_avg);
184 :     fprintf(out,"%f, ",tmp->ssim_min);
185 :     fprintf(out,"%f; ",tmp->ssim_max);
186 :     }
187 :     tmp = tmp->next;
188 :     }
189 :     fprintf(out,"%d, ",tmp->quant);
190 :     fprintf(out,"%f, ",tmp->ssim_avg);
191 :     fprintf(out,"%f, ",tmp->ssim_min);
192 :     fprintf(out,"%f];\n\n",tmp->ssim_max);
193 :    
194 :     fprintf(out,"bvop = [");
195 :     tmp = ssim->head;
196 :     while(tmp->next->next != NULL){
197 :     if(tmp->type == XVID_TYPE_BVOP){
198 :     fprintf(out,"%d, ",tmp->quant);
199 :     fprintf(out,"%f, ",tmp->ssim_avg);
200 :     fprintf(out,"%f, ",tmp->ssim_min);
201 :     fprintf(out,"%f; ",tmp->ssim_max);
202 :     }
203 :     tmp = tmp->next;
204 :     }
205 :     fprintf(out,"%d, ",tmp->quant);
206 :     fprintf(out,"%f, ",tmp->ssim_avg);
207 :     fprintf(out,"%f, ",tmp->ssim_min);
208 :     fprintf(out,"%f];\n\n",tmp->ssim_max);
209 :    
210 :     fclose(out);
211 :     }
212 :    
213 :     /*calculate the luminance of a 8x8 block*/
214 :     int lum_8x8_c(uint8_t* ptr, int stride){
215 :     int mean=0,i,j;
216 :     for(i=0;i< 8;i++)
217 :     for(j=0;j< 8;j++){
218 :     mean += ptr[i*stride + j];
219 :     }
220 :     return mean;
221 :     }
222 :    
223 :     /*calculate the difference between two blocks next to each other on a row*/
224 :     int lum_2x8_c(uint8_t* ptr, int stride){
225 :     int mean=0,i;
226 :     /*Luminance*/
227 :     for(i=0;i< 8;i++){
228 :     mean -= *(ptr-1);
229 :     mean += *(ptr+ 8 - 1);
230 :     ptr+=stride;
231 :     }
232 :     return mean;
233 :     }
234 :    
235 :     /*calculate contrast and correlation of the two blocks*/
236 :     void iconsim_c(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr){
237 :     int valo, valc, devo =0, devc=0, corr=0;
238 :     int i,j;
239 :     for(i=0;i< 8;i++){
240 :     for(j=0;j< 8;j++){
241 :     valo = *ptro - lumo;
242 :     valc = *ptrc - lumc;
243 :     devo += valo*valo;
244 :     ptro++;
245 :     devc += valc*valc;
246 :     ptrc++;
247 :     corr += valo*valc;
248 :     }
249 :     ptro += stride -8;
250 :     ptrc += stride -8;
251 :     }
252 :     *pdevo = devo;
253 :     *pdevc = devc;
254 :     *pcorr = corr;
255 :     };
256 :    
257 :     /*calculate the final ssim value*/
258 :     static float calc_ssim(int meano, int meanc, int devo, int devc, int corr){
259 :     static const float c1 = (0.01*255)*(0.01*255);
260 :     static const float c2 = (0.03*255)*(0.03*255);
261 :     float fmeano,fmeanc,fdevo,fdevc,fcorr;
262 :     fmeanc = (float) meanc;
263 :     fmeano = (float) meano;
264 :     fdevo = (float) devo;
265 :     fdevc = (float) devc;
266 :     fcorr = (float) corr;
267 :     // printf("meano: %f meanc: %f devo: %f devc: %f corr: %f\n",fmeano,fmeanc,fdevo,fdevc,fcorr);
268 :     return ((2.0*fmeano*fmeanc + c1)*(fcorr/32.0 + c2))/((fmeano*fmeano + fmeanc*fmeanc + c1)*(fdevc/64.0 + fdevo/64.0 + c2));
269 :     }
270 :    
271 :     static void ssim_after(xvid_plg_data_t* data, ssim_data_t* ssim){
272 :     int i,j,c=0;
273 :     int width,height,str,ovr;
274 :     unsigned char * ptr1,*ptr2;
275 :     float isum=0, min=1.00,max=0.00, val;
276 :     int meanc, meano;
277 :     int devc, devo, corr;
278 :    
279 :     #define GRID 1
280 :    
281 :     width = data->width - 8;
282 :     height = data->height - 8;
283 :     str = data->original.stride[0];
284 :     if(str != data->current.stride[0]) printf("WARNING: Different strides in plugin_ssim original: %d current: %d\n",str,data->current.stride[0]);
285 :     ovr = str - width + (width % GRID);
286 :    
287 :     ptr1 = (unsigned char*) data->original.plane[0];
288 :     ptr2 = (unsigned char*) data->current.plane[0];
289 :    
290 :    
291 :    
292 :     /*TODO: Thread*/
293 :     for(i=0;i<height;i+=GRID){
294 :     /*begin of each row*/
295 :     meano = meanc = devc = devo = corr = 0;
296 :     meano = ssim->func8x8(ptr1,str);
297 :     meanc = ssim->func8x8(ptr2,str);
298 :     ssim->consim(ptr1,ptr2,str,meano>>6,meanc>>6,&devo,&devc,&corr);
299 :    
300 :     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 :     for(j=1;j<width;j+=GRID){
314 :     /* 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 :     val = calc_ssim(meano,meanc,devo,devc,corr);
322 :     isum += val;
323 :     c++;
324 :     /* for visualisation
325 :     if(ssim->param->b_visualize)
326 :     ssim->errmap[i*width +j] = (uint8_t) 255*val;
327 :     */
328 :     if(val < min) min = val;
329 :     if(val > max) max = val;
330 :     ptr1+=GRID;
331 :     ptr2+=GRID;
332 :     }
333 :     ptr1 +=ovr;
334 :     ptr2 +=ovr;
335 :     }
336 :     isum/=c;
337 :     ssim->ssim_sum += isum;
338 :     ssim->frame_cnt++;
339 :    
340 :     if(ssim->param->stat_path != NULL)
341 :     framestat_append(ssim,data->type,data->quant,min,max,isum);
342 :    
343 :     /* for visualization
344 :     if(ssim->param->b_visualize){
345 :     disp_gray(0,ssim->errmap,width,height,width, "Error-Map");
346 :     disp_gray(1,data->original.plane[0],data->width,data->height,data->original.stride[0],"Original");
347 :     disp_gray(2,data->current.plane[0],data->width,data->height,data->original.stride[0],"Compressed");
348 :     disp_sync();
349 :     }
350 :     */
351 :     if(ssim->param->b_printstat){
352 :     printf("SSIM: avg: %f min: %f max: %f\n",isum,min,max);
353 :     }
354 :    
355 :     }
356 :    
357 :     static int ssim_create(xvid_plg_create_t* create, void** handle){
358 :     ssim_data_t* ssim;
359 :     plg_ssim_param_t* param;
360 :     int cpu_flags;
361 :     param = (plg_ssim_param_t*) malloc(sizeof(plg_ssim_param_t));
362 :     *param = *((plg_ssim_param_t*) create->param);
363 :     ssim = (ssim_data_t*) malloc(sizeof(ssim_data_t));
364 :    
365 :     cpu_flags = check_cpu_features();
366 :    
367 :     ssim->func8x8 = lum_8x8_c;
368 :     ssim->func2x8 = lum_2x8_c;
369 :     ssim->consim = iconsim_c;
370 :    
371 :     ssim->param = param;
372 :    
373 :     if(cpu_flags & XVID_CPU_MMX){
374 :     ssim->func8x8 = lum_8x8_mmx;
375 :     ssim->consim = consim_mmx;
376 :     }
377 :     if(cpu_flags & XVID_CPU_SSE2){
378 :     ssim->consim = consim_sse2;
379 :     }
380 :    
381 :     ssim->ssim_sum = 0.0;
382 :     ssim->frame_cnt = 0;
383 :    
384 :     /* for visualization
385 :     if(param->b_visualize){
386 :     //error map
387 :     ssim->errmap = (uint8_t*) malloc(sizeof(uint8_t)*(create->width-8)*(create->height-8));
388 :     } else {
389 :     ssim->errmap = NULL;
390 :     };
391 :     */
392 :    
393 :     /*stats*/
394 :     ssim->head=NULL;
395 :     ssim->tail=NULL;
396 :    
397 :     *(handle) = (void*) ssim;
398 :    
399 :     return 0;
400 :     }
401 :    
402 :     int xvid_plugin_ssim(void * handle, int opt, void * param1, void * param2){
403 :     ssim_data_t* ssim;
404 :     switch(opt){
405 :     case(XVID_PLG_INFO):
406 :     ((xvid_plg_info_t*) param1)->flags = XVID_REQORIGINAL;
407 :     break;
408 :     case(XVID_PLG_CREATE):
409 :     ssim_create((xvid_plg_create_t*) param1,(void**) param2);
410 :     break;
411 :     case(XVID_PLG_BEFORE):
412 :     case(XVID_PLG_FRAME):
413 :     break;
414 :     case(XVID_PLG_AFTER):
415 :     ssim_after((xvid_plg_data_t*) param1, (ssim_data_t*) handle);
416 :     break;
417 :     case(XVID_PLG_DESTROY):
418 :     ssim = (ssim_data_t*) handle;
419 :     printf("Average SSIM: %f\n",ssim->ssim_sum/ssim->frame_cnt);
420 :     if(ssim->param->stat_path != NULL)
421 :     framestat_write(ssim,ssim->param->stat_path);
422 :     framestat_free(ssim->head);
423 :     //free(ssim->errmap);
424 :     free(ssim->param);
425 :     free(ssim);
426 :     break;
427 :     default:
428 :     break;
429 :     }
430 :     return 0;
431 :     };

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