64 #define DEFAULT_HEATMAP_W 32
65 #define DEFAULT_HEATMAP_H 16
67 #define M_PI_F ((float)M_PI)
68 #define M_PI_2_F ((float)M_PI_2)
69 #define M_PI_4_F ((float)M_PI_4)
70 #define M_SQRT2_F ((float)M_SQRT2)
72 #define DEFAULT_EXPANSION_COEF 1.01f
74 #define BARREL_THETA_RANGE (DEFAULT_EXPANSION_COEF * 2.0f * M_PI_F)
75 #define BARREL_PHI_RANGE (DEFAULT_EXPANSION_COEF * M_PI_2_F)
78 #define FIXED_POINT_PRECISION 16
81 #define SSIM360_HIST_SIZE 131072
85 1.0, 0.9, 0.8, 0.7, 0.6,
86 0.5, 0.4, 0.3, 0.2, 0.1, 0, -1
196 uint8_t *
main,
int main_stride,
197 uint8_t *
ref,
int ref_stride,
202 #define OFFSET(x) offsetof(SSIM360Context, x)
203 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
206 {
"stats_file",
"Set file where to store per-frame difference information",
208 {
"f",
"Set file where to store per-frame difference information",
212 "Specifies if non-luma channels must be computed",
214 0, 1, .flags =
FLAGS },
216 {
"frame_skip_ratio",
217 "Specifies the number of frames to be skipped from evaluation, for every evaluated frame",
219 0, 1000000, .flags =
FLAGS },
221 {
"ref_projection",
"projection of the reference video",
232 {
"main_projection",
"projection of the main video",
236 {
"ref_stereo",
"stereo format of the reference video",
244 {
"main_stereo",
"stereo format of main video",
249 "Expansion (padding) coefficient for each cube face of the reference video",
253 "Expansion (padding) coeffiecient for each cube face of the main video",
257 "Specifies if the tape based SSIM 360 algorithm must be used independent of the input video types",
259 0, 1, .flags =
FLAGS },
262 "Heatmap data for view-based evaluation. For heatmap file format, please refer to EntSphericalVideoHeatmapData.",
265 {
"default_heatmap_width",
266 "Default heatmap dimension. Will be used when dimension is not specified in heatmap data.",
269 {
"default_heatmap_height",
270 "Default heatmap dimension. Will be used when dimension is not specified in heatmap data.",
343 const uint8_t *ref8, ptrdiff_t ref_stride,
346 const uint16_t *main16 = (
const uint16_t *)main8;
347 const uint16_t *ref16 = (
const uint16_t *)ref8;
352 for (
int z = 0; z <
width; z++) {
353 uint64_t s1 = 0, s2 = 0,
ss = 0, s12 = 0;
355 for (
int y = 0; y < 4; y++) {
356 for (
int x = 0; x < 4; x++) {
357 unsigned a = main16[x + y * main_stride];
358 unsigned b = ref16[x + y * ref_stride];
379 const uint8_t *
ref, ptrdiff_t ref_stride,
380 int (*sums)[4],
int width)
382 for (
int z = 0; z <
width; z++) {
383 uint32_t s1 = 0, s2 = 0,
ss = 0, s12 = 0;
385 for (
int y = 0; y < 4; y++) {
386 for (
int x = 0; x < 4; x++) {
387 int a =
main[x + y * main_stride];
388 int b =
ref[x + y * ref_stride];
417 int64_t covar = fs12 * 64 - fs1 * fs2;
419 return (
float)(2 * fs1 * fs2 + ssim_c1) * (
float)(2 * covar + ssim_c2)
420 / ((
float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (
float)(
vars + ssim_c2));
425 static const int ssim_c1 = (int)(.01*.01*255*255*64 + .5);
426 static const int ssim_c2 = (int)(.03*.03*255*255*64*63 + .5);
432 int vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
433 int covar = fs12 * 64 - fs1 * fs2;
435 return (
float)(2 * fs1 * fs2 + ssim_c1) * (
float)(2 * covar + ssim_c2)
436 / ((
float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (
float)(
vars + ssim_c2));
442 double *density_map,
int map_width,
double *total_weight)
444 double ssim360 = 0.0,
weight;
447 weight = density_map ? density_map[(int) ((0.5 +
i) /
width * map_width)] : 1.0;
449 sum0[
i][0] + sum0[
i + 1][0] + sum1[
i][0] + sum1[
i + 1][0],
450 sum0[
i][1] + sum0[
i + 1][1] + sum1[
i][1] + sum1[
i + 1][1],
451 sum0[
i][2] + sum0[
i + 1][2] + sum1[
i][2] + sum1[
i + 1][2],
452 sum0[
i][3] + sum0[
i + 1][3] + sum1[
i][3] + sum1[
i + 1][3],
461 double *density_map,
int map_width,
double *total_weight)
463 double ssim360 = 0.0,
weight;
466 weight = density_map ? density_map[(int) ((0.5 +
i) /
width * map_width)] : 1.0;
468 sum0[
i][0] + sum0[
i + 1][0] + sum1[
i][0] + sum1[
i + 1][0],
469 sum0[
i][1] + sum0[
i + 1][1] + sum1[
i][1] + sum1[
i + 1][1],
470 sum0[
i][2] + sum0[
i + 1][2] + sum1[
i][2] + sum1[
i + 1][2],
471 sum0[
i][3] + sum0[
i + 1][3] + sum1[
i][3] + sum1[
i + 1][3]);
479 uint8_t *
ref,
int ref_stride,
484 double ssim360 = 0.0;
487 double total_weight = 0.0;
492 for (
int y = 1; y <
height; y++) {
493 for (; z <= y; z++) {
494 FFSWAP(
void*, sum0, sum1);
496 &
ref[4 * z * ref_stride], ref_stride,
503 density.
w, &total_weight);
506 return (
double) (ssim360 / total_weight);
511 uint8_t *
ref,
int ref_stride,
516 double ssim360 = 0.0;
517 int (*sum0)[4] =
temp;
518 int (*sum1)[4] = sum0 + (
width >> 2) + 3;
519 double total_weight = 0.0;
524 for (
int y = 1; y <
height; y++) {
525 for (; z <= y; z++) {
526 FFSWAP(
void*, sum0, sum1);
528 &
main[4 * z * main_stride], main_stride,
529 &
ref[4 * z * ref_stride], ref_stride,
533 (
const int (*)[4])sum0, (
const int (*)[4])sum1,
width - 1,
535 density.
w, &total_weight);
538 return (
double) (ssim360 / total_weight);
549 static const int inv_byte_mask = UINT_MAX << 8;
551 int tl, tr, bl, br, v;
553 if (max_value & inv_byte_mask) {
554 uint16_t *data16 = (uint16_t *)
data;
578 int offset_y,
int max_value,
int (*sums)[4])
583 for (
int z = 0; z < 2; z++) {
584 int s1 = 0, s2 = 0,
ss = 0, s12 = 0;
587 for (
int y = offset_y; y < offset_y + 4; y++) {
588 int y_stride = y << 3;
589 for (
int x = offset_x; x < offset_x + 4; x++) {
590 int map_index = x + y_stride;
613 int floor_theta_by_2pi, floor_theta_by_pi;
616 floor_theta_by_2pi = (int)(theta / (2.0
f *
M_PI_F)) - (theta < 0.0
f);
617 theta -= 2.0f *
M_PI_F * floor_theta_by_2pi;
620 floor_theta_by_pi = theta /
M_PI_F;
621 theta -= 2.0f *
M_PI_F * floor_theta_by_pi;
627 float pitch, yaw, norm_pitch, norm_yaw;
633 pitch = asinf(norm_tape_pos*2);
634 yaw =
M_PI_2_F * pitch / angular_resoluation;
638 norm_pitch = 1.0f - (pitch /
M_PI_F + 0.5f);
639 norm_yaw = yaw / 2.0f /
M_PI_F + 0.5f;
650 int tape_length,
int max_value,
void *
temp,
651 double *ssim360_hist,
double *ssim360_hist_net,
654 int horizontal_block_count = 2;
655 int vertical_block_count = tape_length >> 2;
659 double ssim360 = 0.0;
660 double sum_weight = 0.0;
662 int (*sum0)[4] =
temp;
663 int (*sum1)[4] = sum0 + horizontal_block_count + 3;
665 for (y = 1; y < vertical_block_count; y++) {
666 int fs1, fs2, fss, fs12, hist_index;
667 float norm_tape_pos,
weight;
668 double sample_ssim360;
670 for (; z <= y; z++) {
671 FFSWAP(
void*, sum0, sum1);
676 fs1 = sum0[0][0] + sum0[1][0] + sum1[0][0] + sum1[1][0];
677 fs2 = sum0[0][1] + sum0[1][1] + sum1[0][1] + sum1[1][1];
678 fss = sum0[0][2] + sum0[1][2] + sum1[0][2] + sum1[1][2];
679 fs12 = sum0[0][3] + sum0[1][3] + sum1[0][3] + sum1[1][3];
681 if (max_value > 255) {
683 double ssim_c1_d = .01*.01*64*max_value*max_value;
684 double ssim_c2_d = .03*.03*64*63*max_value*max_value;
686 double vars = 64. * fss - 1. * fs1 * fs1 - 1. * fs2 * fs2;
687 double covar = 64. * fs12 - 1.*fs1 * fs2;
688 sample_ssim360 = (2. * fs1 * fs2 + ssim_c1_d) * (2. * covar + ssim_c2_d)
689 / ((1. * fs1 * fs1 + 1. * fs2 * fs2 + ssim_c1_d) * (1. *
vars + ssim_c2_d));
691 static const int ssim_c1 = (int)(.01*.01*255*255*64 + .5);
692 static const int ssim_c2 = (int)(.03*.03*255*255*64*63 + .5);
694 int vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
695 int covar = fs12 * 64 - fs1 * fs2;
696 sample_ssim360 = (
double)(2 * fs1 * fs2 + ssim_c1) * (
double)(2 * covar + ssim_c2)
703 norm_tape_pos = (y - 0.5f) / (vertical_block_count - 1.0
f) - 0.5f;
706 ssim360_hist[hist_index] +=
weight;
707 *ssim360_hist_net +=
weight;
709 ssim360 += (sample_ssim360 *
weight);
713 return ssim360 / sum_weight;
725 int x_floor = x_image;
726 int y_floor = y_image;
727 float x_diff = x_image - x_floor;
728 float y_diff = y_image - y_floor;
730 int x_ceil = x_floor + (x_diff > 1e-6);
731 int y_ceil = y_floor + (y_diff > 1e-6);
732 float x_inv_diff = 1.0f - x_diff;
733 float y_inv_diff = 1.0f - y_diff;
742 m->
tlf = x_inv_diff * y_inv_diff * fixed_point_scale;
743 m->
trf = x_diff * y_inv_diff * fixed_point_scale;
744 m->
blf = x_inv_diff * y_diff * fixed_point_scale;
745 m->
brf = x_diff * y_diff * fixed_point_scale;
750 *x = 0.5f + theta / (2.0f *
M_PI_F);
757 float abs_phi =
FFABS(phi);
768 float circle_x = radial_ratio *
sinf(theta);
769 float circle_y = radial_ratio *
cosf(theta);
770 float offset_y = 0.25f;
777 *x = 0.8f + 0.1f * (1.0f + circle_x);
778 *y = offset_y + 0.25f * circle_y;
784 float abs_phi =
FFABS(phi);
788 float radian_pi_theta = theta /
M_PI_F + 0.5f;
791 if (radian_pi_theta < 0.0
f)
792 radian_pi_theta += 2.0f;
795 vFace = radian_pi_theta >= 1.0f;
799 *x = 2.0f / 3.0f * (0.5f + (radian_pi_theta - vFace - 0.5f) / expand_coef);
801 *y = 0.25f + 0.5f * vFace - phi / (
M_PI_F * expand_coef);
805 float radial_ratio =
cosf(abs_phi) / (
sinf(abs_phi) * expand_coef);
806 float circle_x = radial_ratio *
sinf(theta);
807 float circle_y = radial_ratio *
cosf(theta);
808 float offset_y = 0.25f;
813 circle_y = (circle_y >= 0.0f) ? (1 - circle_y) : (-1 - circle_y);
826 *x = 2.0f / 3.0f + 0.5f / 3.0f * (1.0f + circle_x);
827 *y = offset_y + 0.25f * circle_y / expand_coef;
832 static int get_cubemap_face_map(
float axis_vec_x,
float axis_vec_y,
float axis_vec_z,
float *face_x,
float *face_y)
839 if (
FFABS(axis_vec_y) > 0.577
f) {
840 float x_hit = axis_vec_x /
FFABS(axis_vec_y);
841 float z_hit = axis_vec_z / axis_vec_y;
852 if (
FFABS(axis_vec_x) > 0.577
f) {
853 float z_hit = -axis_vec_z / axis_vec_x;
854 float y_hit = axis_vec_y /
FFABS(axis_vec_x);
865 *face_x = axis_vec_x / axis_vec_z;
867 *face_y = -axis_vec_y /
FFABS(axis_vec_z);
878 static const int face_projection_map[] = {
883 float axis_vec_x =
cosf(phi) *
sinf(theta);
884 float axis_vec_y =
sinf(phi);
885 float axis_vec_z =
cosf(phi) *
cosf(theta);
886 float face_x = 0, face_y = 0;
889 float x_offset = 1.f / 3.f * (face_projection_map[face_index] % 3);
890 float y_offset = .5f * (face_projection_map[face_index] / 3);
903 static const int face_projection_map[] = {
909 float axis_yaw_vec_x, axis_yaw_vec_y, axis_yaw_vec_z;
910 float axis_pitch_vec_z, axis_pitch_vec_y;
911 float x_offset, y_offset;
912 float face_x = 0, face_y = 0;
920 axis_yaw_vec_x =
cosf(phi) *
sinf(theta);
921 axis_yaw_vec_y =
sinf(phi);
922 axis_yaw_vec_z =
cosf(phi) *
cosf(theta);
925 axis_pitch_vec_z = (axis_yaw_vec_z - axis_yaw_vec_y) /
M_SQRT2_F;
926 axis_pitch_vec_y = (axis_yaw_vec_y + axis_yaw_vec_z) /
M_SQRT2_F;
928 face_index =
get_cubemap_face_map(axis_yaw_vec_x, axis_pitch_vec_y, axis_pitch_vec_z, &face_x, &face_y);
931 if (face_index ==
LEFT || face_index ==
FRONT || face_index ==
RIGHT) {
933 float upright_y = face_y;
936 }
else if (face_index ==
TOP || face_index ==
BOTTOM) {
942 x_offset = .5f * (face_projection_map[face_index] & 1);
943 y_offset = 1.f / 3.f * (face_projection_map[face_index] >> 1);
945 *x = x_offset + (face_x / expand_coef + 1.f) / 4.
f;
946 *y = y_offset + (face_y / expand_coef + 1.f) / 6.
f;
1000 return expand_coef / (
M_SQRT2_F * image_width / 4.f);
1007 return FFMAX((expand_coef *
M_PI_F) / (2.0
f / 3.0
f * image_width),
1008 expand_coef *
M_PI_2_F / (image_height / 2.0
f));
1023 int ref_image_height = ref_sample_params->
y_image_range + 1;
1025 float angular_resolution =
1027 ref_image_width, ref_image_height);
1029 float conversion_factor =
M_PI_2_F / (angular_resolution * angular_resolution);
1030 float start_phi = -
M_PI_2_F + 4.0f * angular_resolution;
1031 float start_x = conversion_factor *
sinf(start_phi);
1032 float end_phi =
M_PI_2_F - 3.0f * angular_resolution;
1033 float end_x = conversion_factor *
sinf(end_phi);
1034 float x_range = end_x - start_x;
1037 int tape_length =
s->tape_length[plane] = ((int)
ROUNDED_DIV(x_range, 4)) << 2;
1041 if (!
s->ref_tape_map[plane][eye] || !
s->main_tape_map[plane][eye])
1044 s->angular_resolution[plane][eye] = angular_resolution;
1047 for (
int y_index = 0; y_index < tape_length; y_index ++) {
1048 int y_stride = y_index << 3;
1050 float x = start_x + x_range * (y_index / (tape_length - 1.0f));
1052 float mid_phi = asinf(x / conversion_factor);
1054 float theta = mid_phi *
M_PI_2_F / angular_resolution;
1057 for (
int x_index = 0; x_index < 8; x_index ++) {
1058 float phi = mid_phi + angular_resolution * (3.0f - x_index);
1059 int tape_index = y_stride + x_index;
1060 get_projected_map(phi, theta, ref_sample_params, &
s->ref_tape_map [plane][eye][tape_index]);
1061 get_projected_map(phi, theta, main_sample_params, &
s->main_tape_map[plane][eye][tape_index]);
1072 int ref_stereo_format =
s->ref_stereo_format;
1073 int main_stereo_format =
s->main_stereo_format;
1075 int min_eye_count = 1 + are_both_stereo;
1078 for (
int i = 0;
i <
s->nb_components;
i ++) {
1079 int ref_width =
s->ref_planewidth[
i];
1080 int ref_height =
s->ref_planeheight[
i];
1081 int main_width =
s->main_planewidth[
i];
1082 int main_height =
s->main_planeheight[
i];
1089 int ref_image_width = is_ref_LR ? ref_width >> 1 : ref_width;
1090 int ref_image_height = is_ref_TB ? ref_height >> 1 : ref_height;
1091 int main_image_width = is_main_LR ? main_width >> 1 : main_width;
1092 int main_image_height = is_main_TB ? main_height >> 1 : main_height;
1094 for (
int eye = 0; eye < min_eye_count; eye ++) {
1097 .planewidth = ref_width,
1098 .planeheight = ref_height,
1099 .x_image_range = ref_image_width - 1,
1100 .y_image_range = ref_image_height - 1,
1101 .x_image_offset = is_ref_LR * eye * ref_image_width,
1102 .y_image_offset = is_ref_TB * eye * ref_image_height,
1103 .projection =
s->ref_projection,
1104 .expand_coef = 1.f +
s->ref_pad,
1109 .planewidth = main_width,
1110 .planeheight = main_height,
1111 .x_image_range = main_image_width - 1,
1112 .y_image_range = main_image_height - 1,
1113 .x_image_offset = is_main_LR * eye * main_image_width,
1114 .y_image_offset = is_main_TB * eye * main_image_height,
1115 .projection =
s->main_projection,
1116 .expand_coef = 1.f +
s->main_pad,
1134 double c[4], ssim360v = 0.0, ssim360p50 = 0.0;
1136 int need_frame_skip =
s->nb_net_frames % (
s->frame_skip_ratio + 1);
1145 if (need_frame_skip)
1148 metadata = &
master->metadata;
1150 if (
s->use_tape && !
s->tape_length[0]) {
1156 for (
int i = 0;
i <
s->nb_components;
i++) {
1159 ref->data[
i],
s->ref_tape_map [
i][0],
1160 s->tape_length[
i],
s->max,
s->temp,
1161 s->ssim360_hist[
i], &
s->ssim360_hist_net[
i],
1162 s->angular_resolution[
i][0],
s->heatmaps);
1164 if (
s->ref_tape_map[
i][1]) {
1166 ref->data[
i],
s->ref_tape_map[
i][1],
1167 s->tape_length[
i],
s->max,
s->temp,
1168 s->ssim360_hist[
i], &
s->ssim360_hist_net[
i],
1169 s->angular_resolution[
i][1],
s->heatmaps);
1175 s->ref_planewidth[
i],
s->ref_planeheight[
i],
1176 s->temp,
s->max,
s->density);
1179 s->ssim360[
i] +=
c[
i];
1180 ssim360v +=
s->coefs[
i] *
c[
i];
1183 s->nb_ssim_frames++;
1186 h_ptr =
s->heatmaps;
1187 s->heatmaps =
s->heatmaps->next;
1190 s->ssim360_total += ssim360v;
1194 int hist_indices[4];
1195 double hist_weight[4];
1197 for (
int i = 0;
i <
s->nb_components;
i++) {
1203 for (
int i = 0;
i <
s->nb_components;
i++) {
1204 double target_weight, ssim360p;
1208 target_weight =
FFMAX(target_weight, 1);
1209 while(hist_indices[
i] >= 0 && hist_weight[
i] < target_weight) {
1210 hist_weight[
i] +=
s->ssim360_hist[
i][hist_indices[
i]];
1216 ssim360p50 +=
s->coefs[
i] * ssim360p;
1217 s->ssim360_percentile_sum[
i][p] += ssim360p;
1221 for (
int i = 0;
i <
s->nb_components;
i++) {
1223 s->ssim360_hist_net[
i] = 0;
1226 for (
int i = 0;
i <
s->nb_components;
i++) {
1227 int cidx =
s->is_rgb ?
s->rgba_map[
i] :
i;
1228 set_meta(metadata,
"lavfi.ssim360.",
s->comps[
i],
c[cidx]);
1232 set_meta(metadata,
"lavfi.ssim360.All", 0, ssim360p50);
1235 if (
s->stats_file) {
1236 fprintf(
s->stats_file,
"n:%"PRId64
" ",
s->nb_ssim_frames);
1238 for (
int i = 0;
i <
s->nb_components;
i++) {
1239 int cidx =
s->is_rgb ?
s->rgba_map[
i] :
i;
1240 fprintf(
s->stats_file,
"%c:%f ",
s->comps[
i],
c[cidx]);
1243 fprintf(
s->stats_file,
"All:%f (%f)\n", ssim360p50,
ssim360_db(ssim360p50, 1.0));
1251 const char *
data,
int w,
int h)
1269 char *saveptr, *
val;
1317 if (
s->stats_file_str) {
1318 if (!strcmp(
s->stats_file_str,
"-")) {
1319 s->stats_file = stdout;
1322 if (!
s->stats_file) {
1331 if (
s->use_tape &&
s->heatmap_str) {
1333 s->default_heatmap_w,
s->default_heatmap_h);
1348 s->main_planeheight[0] =
inlink->h;
1349 s->main_planeheight[3] =
inlink->h;
1353 s->main_planewidth[0] =
inlink->w;
1354 s->main_planewidth[3] =
inlink->w;
1360 s->main_projection =
s->ref_projection;
1364 s->main_stereo_format =
s->ref_stereo_format;
1371 double d, r_square, cos_square;
1378 switch (
s->ref_stereo_format) {
1387 switch (
s->ref_projection) {
1389 for (
int i = 0;
i <
h;
i++) {
1390 d = cos(((0.5 +
i) /
h - 0.5) *
M_PI);
1391 for (
int j = 0; j <
w; j++)
1392 s->density.value[
i *
w + j] = d;
1397 for (
int i = 0;
i <
h / 4;
i++) {
1398 for (
int j = 0; j <
w / 6; j++) {
1401 (0.5 +
i) / (
h / 2) * (0.5 +
i) / (
h / 2) +
1402 (0.5 + j) / (
w / 3) * (0.5 + j) / (
w / 3);
1404 cos_square = 0.25 / (r_square + 0.25);
1405 d = pow(cos_square, 1.5);
1407 for (
int face = 0; face < 6; face++) {
1420 ow =
w / 6 + 2 *
w / 3;
1432 ow =
w / 6 + 2 *
w / 3;
1435 s->density.value[(oh - 1 -
i) *
w + ow - 1 - j] = d;
1436 s->density.value[(oh - 1 -
i) *
w + ow + j] = d;
1437 s->density.value[(oh +
i) *
w + ow - 1 - j] = d;
1438 s->density.value[(oh +
i) *
w + ow + j] = d;
1445 for (
int i = 0;
i <
h / 6;
i++) {
1446 for (
int j = 0; j <
w / 4; j++) {
1449 (0.5 +
i) / (
h / 3) * (0.5 +
i) / (
h / 3) +
1450 (0.5 + j) / (
w / 2) * (0.5 + j) / (
w / 2);
1451 r_square /= (1.f +
s->ref_pad) * (1.
f +
s->ref_pad);
1452 cos_square = 0.25 / (r_square + 0.25);
1453 d = pow(cos_square, 1.5);
1455 for (
int face = 0; face < 6; face++) {
1468 oh =
h / 6 + 2 *
h / 3;
1480 oh =
h / 6 + 2 *
h / 3;
1483 s->density.value[(oh - 1 -
i) *
w + ow - 1 - j] = d;
1484 s->density.value[(oh - 1 -
i) *
w + ow + j] = d;
1485 s->density.value[(oh +
i) *
w + ow - 1 - j] = d;
1486 s->density.value[(oh +
i) *
w + ow + j] = d;
1493 for (
int i = 0;
i <
h;
i++) {
1494 for (
int j = 0; j <
w * 4 / 5; j++) {
1496 s->density.value[
i *
w + j] = d * d * d;
1500 for (
int i = 0;
i <
h;
i++) {
1501 for (
int j =
w * 4 / 5; j <
w; j++) {
1503 double dx_squared = dx * dx;
1506 double top_dy_squared = top_dy * top_dy;
1509 double bottom_dy_squared = bottom_dy * bottom_dy;
1512 r_square = (
i <
h / 2 ? top_dy_squared : bottom_dy_squared) + dx_squared;
1516 cos_square = 1.0 / (r_square + 1.0);
1517 d = pow(cos_square, 1.5);
1518 s->density.value[
i *
w + j] = d;
1524 for (
int i = 0;
i <
h;
i++) {
1525 for (
int j = 0; j <
w; j++)
1526 s->density.value[
i *
w + j] = 0;
1530 switch (
s->ref_stereo_format) {
1532 for (
int i = 0;
i <
h;
i++) {
1533 for (
int j = 0; j <
w; j++)
1534 s->density.value[(
i +
h) *
w + j] =
s->density.value[
i *
w + j];
1538 for (
int i = 0;
i <
h;
i++) {
1539 for (
int j = 0; j <
w; j++)
1540 s->density.value[
i *
w + j +
w] =
s->density.value[
i *
w + j];
1554 s->nb_components =
desc->nb_components;
1556 s->ref_planeheight[0] =
inlink->h;
1557 s->ref_planeheight[3] =
inlink->h;
1561 s->ref_planewidth[0] =
inlink->w;
1562 s->ref_planewidth[3] =
inlink->w;
1567 s->comps[0] =
s->is_rgb ?
'R' :
'Y';
1568 s->comps[1] =
s->is_rgb ?
'G' :
'U';
1569 s->comps[2] =
s->is_rgb ?
'B' :
'V';
1573 if (!
s->is_rgb && !
s->compute_chroma)
1574 s->nb_components = 1;
1576 s->max = (1 <<
desc->comp[0].depth) - 1;
1580 for (
int i = 0;
i <
s->nb_components;
i++)
1581 sum +=
s->ref_planeheight[
i] *
s->ref_planewidth[
i];
1582 for (
int i = 0;
i <
s->nb_components;
i++)
1583 s->coefs[
i] = (
double)
s->ref_planeheight[
i] *
s->ref_planewidth[
i] / sum;
1600 if (
ctx->inputs[0]->w !=
ctx->inputs[1]->w ||
ctx->inputs[0]->h !=
ctx->inputs[1]->h ||
1601 s->ref_projection !=
s->main_projection ||
s->ref_stereo_format !=
s->main_stereo_format)
1618 memset(
s->ssim360_percentile_sum, 0,
sizeof(
s->ssim360_percentile_sum));
1620 for (
int i = 0;
i <
s->nb_components;
i++) {
1622 if (!
s->ssim360_hist[
i])
1630 if (!
s->density.value) {
1641 outlink->
w = mainlink->
w;
1642 outlink->
h = mainlink->
h;
1647 s->fs.opt_shortest = 1;
1648 s->fs.opt_repeatlast = 1;
1667 if (
s->nb_ssim_frames > 0) {
1671 for (
int i = 0;
i <
s->nb_components;
i++) {
1672 int c =
s->is_rgb ?
s->rgba_map[
i] :
i;
1673 av_strlcatf(buf,
sizeof(buf),
" %c:%f (%f)",
s->comps[
i],
s->ssim360[
c] /
s->nb_ssim_frames,
1677 s->ssim360_total /
s->nb_ssim_frames,
ssim360_db(
s->ssim360_total,
s->nb_ssim_frames));
1683 for (
int i = 0;
i <
s->nb_components;
i++) {
1684 int c =
s->is_rgb ?
s->rgba_map[
i] :
i;
1685 double ssim360p =
s->ssim360_percentile_sum[
i][p] / (
double)(
s->nb_ssim_frames);
1698 for (
int i = 0;
i <
s->nb_components;
i++) {
1699 for (
int eye = 0; eye < 2; eye++) {
1708 if (
s->stats_file &&
s->stats_file != stdout)
1709 fclose(
s->stats_file);
1714 #define PF(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf, AV_PIX_FMT_GBR##suf
1734 .name =
"reference",
1751 .preinit = ssim360_framesync_preinit,
1756 .priv_class = &ssim360_class,