23 |
* |
* |
24 |
****************************************************************************/ |
****************************************************************************/ |
25 |
|
|
26 |
#include <malloc.h> |
#include <stdlib.h> |
27 |
#include <stdio.h> |
#include <stdio.h> |
28 |
#include <math.h> |
#include <math.h> |
29 |
#include "../portab.h" |
#include "../portab.h" |
37 |
|
|
38 |
typedef struct framestat_t framestat_t; |
typedef struct framestat_t framestat_t; |
39 |
|
|
40 |
|
/*dev 1.0 gaussian weighting. the weight for the pixel x,y is w(x)*w(y)*/ |
41 |
|
static float mask8[8] = { |
42 |
|
0.0069815f, 0.1402264f, 1.0361408f, 2.8165226f, |
43 |
|
2.8165226f, 1.0361408f, 0.1402264f, 0.0069815f |
44 |
|
}; |
45 |
|
|
46 |
|
/* integer version. Norm: coeffs sums up to 4096. |
47 |
|
Define USE_INT_GAUSSIAN to use it as replacement to float version */ |
48 |
|
|
49 |
|
/* #define USE_INT_GAUSSIAN */ |
50 |
|
static const uint16_t imask8[8] = { |
51 |
|
4, 72, 530, 1442, 1442, 530, 72, 4 |
52 |
|
}; |
53 |
|
#define GACCUM(X) ( ((X)+(1<<11)) >> 12 ) |
54 |
|
|
55 |
|
|
56 |
struct framestat_t{ |
struct framestat_t{ |
57 |
int type; |
int type; |
58 |
int quant; |
int quant; |
132 |
fprintf(out,"SSIM Error Metric\n"); |
fprintf(out,"SSIM Error Metric\n"); |
133 |
fprintf(out,"quant avg min max\n"); |
fprintf(out,"quant avg min max\n"); |
134 |
while(tmp->next->next != NULL){ |
while(tmp->next->next != NULL){ |
135 |
fprintf(out,"%3d %1.4f %1.4f %1.4f\n",tmp->quant,tmp->ssim_avg,tmp->ssim_min,tmp->ssim_max); |
fprintf(out,"%3d %1.3f %1.3f %1.3f\n",tmp->quant,tmp->ssim_avg,tmp->ssim_min,tmp->ssim_max); |
136 |
tmp = tmp->next; |
tmp = tmp->next; |
137 |
} |
} |
138 |
fclose(out); |
fclose(out); |
237 |
return mean; |
return mean; |
238 |
} |
} |
239 |
|
|
240 |
|
int lum_8x8_gaussian(uint8_t* ptr, int stride){ |
241 |
|
float mean=0,sum; |
242 |
|
int i,j; |
243 |
|
for(i=0;i<8;i++){ |
244 |
|
sum = 0; |
245 |
|
for(j=0;j<8;j++) |
246 |
|
sum += ptr[i*stride + j]*mask8[j]; |
247 |
|
|
248 |
|
sum *=mask8[i]; |
249 |
|
mean += sum; |
250 |
|
} |
251 |
|
return (int) (mean + 0.5); |
252 |
|
} |
253 |
|
|
254 |
|
int lum_8x8_gaussian_int(uint8_t* ptr, int stride){ |
255 |
|
uint32_t mean; |
256 |
|
int i,j; |
257 |
|
mean = 0; |
258 |
|
for(i=0;i<8;i++){ |
259 |
|
uint32_t sum = 0; |
260 |
|
for(j=0;j<8;j++) |
261 |
|
sum += ptr[i*stride + j]*imask8[j]; |
262 |
|
|
263 |
|
sum = GACCUM(sum) * imask8[i]; |
264 |
|
mean += sum; |
265 |
|
} |
266 |
|
return (int)GACCUM(mean); |
267 |
|
} |
268 |
|
|
269 |
/*calculate the difference between two blocks next to each other on a row*/ |
/*calculate the difference between two blocks next to each other on a row*/ |
270 |
int lum_2x8_c(uint8_t* ptr, int stride){ |
int lum_2x8_c(uint8_t* ptr, int stride){ |
271 |
int mean=0,i; |
int mean=0,i; |
279 |
} |
} |
280 |
|
|
281 |
/*calculate contrast and correlation of the two blocks*/ |
/*calculate contrast and correlation of the two blocks*/ |
282 |
|
void consim_gaussian(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr){ |
283 |
|
unsigned int valo, valc,i,j,str; |
284 |
|
float devo=0, devc=0, corr=0,sumo,sumc,sumcorr; |
285 |
|
str = stride - 8; |
286 |
|
for(i=0;i< 8;i++){ |
287 |
|
sumo = 0; |
288 |
|
sumc = 0; |
289 |
|
sumcorr = 0; |
290 |
|
for(j=0;j< 8;j++){ |
291 |
|
valo = *ptro; |
292 |
|
valc = *ptrc; |
293 |
|
sumo += valo*valo*mask8[j]; |
294 |
|
sumc += valc*valc*mask8[j]; |
295 |
|
sumcorr += valo*valc*mask8[j]; |
296 |
|
ptro++; |
297 |
|
ptrc++; |
298 |
|
} |
299 |
|
|
300 |
|
devo += sumo*mask8[i]; |
301 |
|
devc += sumc*mask8[i]; |
302 |
|
corr += sumcorr*mask8[i]; |
303 |
|
ptro += str; |
304 |
|
ptrc += str; |
305 |
|
} |
306 |
|
|
307 |
|
*pdevo = (int) ((devo - ((lumo*lumo + 32) >> 6)) + 0.5); |
308 |
|
*pdevc = (int) ((devc - ((lumc*lumc + 32) >> 6)) + 0.5); |
309 |
|
*pcorr = (int) ((corr - ((lumo*lumc + 32) >> 6)) + 0.5); |
310 |
|
}; |
311 |
|
|
312 |
|
void consim_gaussian_int(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr) |
313 |
|
{ |
314 |
|
unsigned int valo, valc,i,j,str; |
315 |
|
uint32_t devo=0, devc=0, corr=0; |
316 |
|
str = stride - 8; |
317 |
|
for(i=0;i< 8;i++){ |
318 |
|
uint32_t sumo = 0; |
319 |
|
uint32_t sumc = 0; |
320 |
|
uint32_t sumcorr = 0; |
321 |
|
for(j=0;j< 8;j++){ |
322 |
|
valo = *ptro; |
323 |
|
valc = *ptrc; |
324 |
|
sumo += valo*valo*imask8[j]; |
325 |
|
sumc += valc*valc*imask8[j]; |
326 |
|
sumcorr += valo*valc*imask8[j]; |
327 |
|
ptro++; |
328 |
|
ptrc++; |
329 |
|
} |
330 |
|
|
331 |
|
devo += GACCUM(sumo)*imask8[i]; |
332 |
|
devc += GACCUM(sumc)*imask8[i]; |
333 |
|
corr += GACCUM(sumcorr)*imask8[i]; |
334 |
|
ptro += str; |
335 |
|
ptrc += str; |
336 |
|
} |
337 |
|
|
338 |
|
devo = GACCUM(devo); |
339 |
|
devc = GACCUM(devc); |
340 |
|
corr = GACCUM(corr); |
341 |
|
*pdevo = (int) ((devo - ((lumo*lumo + 32) >> 6)) + 0.5); |
342 |
|
*pdevc = (int) ((devc - ((lumc*lumc + 32) >> 6)) + 0.5); |
343 |
|
*pcorr = (int) ((corr - ((lumo*lumc + 32) >> 6)) + 0.5); |
344 |
|
}; |
345 |
|
|
346 |
|
/*calculate contrast and correlation of the two blocks*/ |
347 |
void consim_c(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr){ |
void consim_c(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr){ |
348 |
unsigned int valo, valc, devo=0, devc=0, corr=0,i,j,str; |
unsigned int valo, valc, devo=0, devc=0, corr=0,i,j,str; |
349 |
str = stride - 8; |
str = stride - 8; |
367 |
}; |
}; |
368 |
|
|
369 |
/*calculate the final ssim value*/ |
/*calculate the final ssim value*/ |
370 |
static float calc_ssim(int meano, int meanc, int devo, int devc, int corr){ |
static float calc_ssim(float meano, float meanc, float devo, float devc, float corr){ |
371 |
static const float c1 = (0.01*255)*(0.01*255); |
static const float c1 = (0.01f*255)*(0.01f*255); |
372 |
static const float c2 = (0.03*255)*(0.03*255); |
static const float c2 = (0.03f*255)*(0.03f*255); |
373 |
float fmeano,fmeanc,fdevo,fdevc,fcorr; |
/*printf("meano: %f meanc: %f devo: %f devc: %f corr: %f\n",meano,meanc,devo,devc,corr);*/ |
374 |
fmeanc = (float) meanc; |
return ((2.0f*meano*meanc + c1)*(corr/32.0f + c2))/((meano*meano + meanc*meanc + c1)*(devc/64.0f + devo/64.0f + c2)); |
|
fmeano = (float) meano; |
|
|
fdevo = (float) devo; |
|
|
fdevc = (float) devc; |
|
|
fcorr = (float) corr; |
|
|
/* printf("meano: %f meanc: %f devo: %f devc: %f corr: %f\n",fmeano,fmeanc,fdevo,fdevc,fcorr); */ |
|
|
return ((2.0*fmeano*fmeanc + c1)*(fcorr/32.0 + c2))/((fmeano*fmeano + fmeanc*fmeanc + c1)*(fdevc/64.0 + fdevo/64.0 + c2)); |
|
375 |
} |
} |
376 |
|
|
377 |
static void ssim_after(xvid_plg_data_t* data, ssim_data_t* ssim){ |
static void ssim_after(xvid_plg_data_t* data, ssim_data_t* ssim){ |
378 |
int i,j,c=0; |
int i,j,c=0,opt; |
379 |
int width,height,str,ovr; |
int width,height,str,ovr; |
380 |
unsigned char * ptr1,*ptr2; |
unsigned char * ptr1,*ptr2; |
381 |
float isum=0, min=1.00,max=0.00, val; |
float isum=0, min=1.00,max=0.00, val; |
391 |
ptr1 = (unsigned char*) data->original.plane[0]; |
ptr1 = (unsigned char*) data->original.plane[0]; |
392 |
ptr2 = (unsigned char*) data->current.plane[0]; |
ptr2 = (unsigned char*) data->current.plane[0]; |
393 |
|
|
394 |
|
opt = ssim->grid == 1 && ssim->param->acc != 0; |
395 |
|
|
396 |
/*TODO: Thread*/ |
/*TODO: Thread*/ |
397 |
for(i=0;i<height;i+=ssim->grid){ |
for(i=0;i<height;i+=ssim->grid){ |
402 |
ssim->consim(ptr1,ptr2,str,meano,meanc,&devo,&devc,&corr); |
ssim->consim(ptr1,ptr2,str,meano,meanc,&devo,&devc,&corr); |
403 |
emms(); |
emms(); |
404 |
|
|
405 |
val = calc_ssim(meano,meanc,devo,devc,corr); |
val = calc_ssim((float) meano,(float) meanc,(float) devo,(float) devc,(float) corr); |
406 |
isum += val; |
isum += val; |
407 |
c++; |
c++; |
408 |
/* for visualisation |
/* for visualisation |
417 |
ptr2+=ssim->grid; |
ptr2+=ssim->grid; |
418 |
/*rest of each row*/ |
/*rest of each row*/ |
419 |
for(j=ssim->grid;j<width;j+=ssim->grid){ |
for(j=ssim->grid;j<width;j+=ssim->grid){ |
420 |
if(ssim->grid == 1){ |
if(opt){ |
421 |
meano += ssim->func2x8(ptr1,str); |
meano += ssim->func2x8(ptr1,str); |
422 |
meanc += ssim->func2x8(ptr2,str); |
meanc += ssim->func2x8(ptr2,str); |
423 |
} else { |
} else { |
427 |
ssim->consim(ptr1,ptr2,str,meano,meanc,&devo,&devc,&corr); |
ssim->consim(ptr1,ptr2,str,meano,meanc,&devo,&devc,&corr); |
428 |
emms(); |
emms(); |
429 |
|
|
430 |
val = calc_ssim(meano,meanc,devo,devc,corr); |
val = calc_ssim((float) meano,(float) meanc,(float) devo,(float) devc,(float) corr); |
431 |
isum += val; |
isum += val; |
432 |
c++; |
c++; |
433 |
/* for visualisation |
/* for visualisation |
458 |
} |
} |
459 |
*/ |
*/ |
460 |
if(ssim->param->b_printstat){ |
if(ssim->param->b_printstat){ |
461 |
printf(" SSIM: avg: %f min: %f max: %f\n",isum,min,max); |
printf(" SSIM: avg: %1.3f min: %1.3f max: %1.3f\n",isum,min,max); |
462 |
} |
} |
463 |
|
|
464 |
} |
} |
466 |
static int ssim_create(xvid_plg_create_t* create, void** handle){ |
static int ssim_create(xvid_plg_create_t* create, void** handle){ |
467 |
ssim_data_t* ssim; |
ssim_data_t* ssim; |
468 |
plg_ssim_param_t* param; |
plg_ssim_param_t* param; |
|
int cpu_flags; |
|
469 |
param = (plg_ssim_param_t*) malloc(sizeof(plg_ssim_param_t)); |
param = (plg_ssim_param_t*) malloc(sizeof(plg_ssim_param_t)); |
470 |
*param = *((plg_ssim_param_t*) create->param); |
*param = *((plg_ssim_param_t*) create->param); |
471 |
ssim = (ssim_data_t*) malloc(sizeof(ssim_data_t)); |
ssim = (ssim_data_t*) malloc(sizeof(ssim_data_t)); |
472 |
|
|
|
cpu_flags = check_cpu_features(); |
|
|
|
|
473 |
ssim->func8x8 = lum_8x8_c; |
ssim->func8x8 = lum_8x8_c; |
474 |
ssim->func2x8 = lum_2x8_c; |
ssim->func2x8 = lum_2x8_c; |
475 |
ssim->consim = consim_c; |
ssim->consim = consim_c; |
478 |
|
|
479 |
ssim->grid = param->acc; |
ssim->grid = param->acc; |
480 |
|
|
481 |
/*gaussian weigthing not implemented*/ |
#if defined(ARCH_IS_IA32) || defined(ARCH_IS_X86_64) |
482 |
if(ssim->grid == 0) ssim->grid = 1; |
{ |
483 |
if(ssim->grid > 4) ssim->grid = 4; |
int cpu_flags = param->cpu_flags; |
|
|
|
|
printf("Grid: %d\n",ssim->grid); |
|
484 |
|
|
|
#if defined(ARCH_IS_IA32) |
|
485 |
if((cpu_flags & XVID_CPU_MMX) && (param->acc > 0)){ |
if((cpu_flags & XVID_CPU_MMX) && (param->acc > 0)){ |
486 |
ssim->func8x8 = lum_8x8_mmx; |
ssim->func8x8 = lum_8x8_mmx; |
487 |
ssim->consim = consim_mmx; |
ssim->consim = consim_mmx; |
489 |
if((cpu_flags & XVID_CPU_SSE2) && (param->acc > 0)){ |
if((cpu_flags & XVID_CPU_SSE2) && (param->acc > 0)){ |
490 |
ssim->consim = consim_sse2; |
ssim->consim = consim_sse2; |
491 |
} |
} |
492 |
|
} |
493 |
#endif |
#endif |
494 |
|
|
495 |
|
/*gaussian weigthing not implemented*/ |
496 |
|
#if !defined(USE_INT_GAUSSIAN) |
497 |
|
if(ssim->grid == 0){ |
498 |
|
ssim->grid = 1; |
499 |
|
ssim->func8x8 = lum_8x8_gaussian; |
500 |
|
ssim->func2x8 = NULL; |
501 |
|
ssim->consim = consim_gaussian; |
502 |
|
} |
503 |
|
#else |
504 |
|
if(ssim->grid == 0){ |
505 |
|
ssim->grid = 1; |
506 |
|
ssim->func8x8 = lum_8x8_gaussian_int; |
507 |
|
ssim->func2x8 = NULL; |
508 |
|
ssim->consim = consim_gaussian_int; |
509 |
|
} |
510 |
|
#endif |
511 |
|
if(ssim->grid > 4) ssim->grid = 4; |
512 |
|
|
513 |
ssim->ssim_sum = 0.0; |
ssim->ssim_sum = 0.0; |
514 |
ssim->frame_cnt = 0; |
ssim->frame_cnt = 0; |
515 |
|
|