63 #define DEFAULT_HEATMAP_W 32
64 #define DEFAULT_HEATMAP_H 16
66 #define M_PI_F ((float)M_PI)
67 #define M_PI_2_F ((float)M_PI_2)
68 #define M_PI_4_F ((float)M_PI_4)
69 #define M_SQRT2_F ((float)M_SQRT2)
71 #define DEFAULT_EXPANSION_COEF 1.01f
73 #define BARREL_THETA_RANGE (DEFAULT_EXPANSION_COEF * 2.0f * M_PI_F)
74 #define BARREL_PHI_RANGE (DEFAULT_EXPANSION_COEF * M_PI_2_F)
77 #define FIXED_POINT_PRECISION 16
80 #define SSIM360_HIST_SIZE 131072
84 1.0, 0.9, 0.8, 0.7, 0.6,
85 0.5, 0.4, 0.3, 0.2, 0.1, 0, -1
195 uint8_t *
main,
int main_stride,
196 uint8_t *
ref,
int ref_stride,
201 #define OFFSET(x) offsetof(SSIM360Context, x)
202 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
205 {
"stats_file",
"Set file where to store per-frame difference information",
207 {
"f",
"Set file where to store per-frame difference information",
211 "Specifies if non-luma channels must be computed",
213 0, 1, .flags =
FLAGS },
215 {
"frame_skip_ratio",
216 "Specifies the number of frames to be skipped from evaluation, for every evaluated frame",
218 0, 1000000, .flags =
FLAGS },
220 {
"ref_projection",
"projection of the reference video",
231 {
"main_projection",
"projection of the main video",
235 {
"ref_stereo",
"stereo format of the reference video",
243 {
"main_stereo",
"stereo format of main video",
248 "Expansion (padding) coefficient for each cube face of the reference video",
252 "Expansion (padding) coeffiecient for each cube face of the main video",
256 "Specifies if the tape based SSIM 360 algorithm must be used independent of the input video types",
258 0, 1, .flags =
FLAGS },
261 "Heatmap data for view-based evaluation. For heatmap file format, please refer to EntSphericalVideoHeatmapData.",
264 {
"default_heatmap_width",
265 "Default heatmap dimension. Will be used when dimension is not specified in heatmap data.",
268 {
"default_heatmap_height",
269 "Default heatmap dimension. Will be used when dimension is not specified in heatmap data.",
342 const uint8_t *ref8, ptrdiff_t ref_stride,
343 int64_t (*sums)[4],
int width)
345 const uint16_t *main16 = (
const uint16_t *)main8;
346 const uint16_t *ref16 = (
const uint16_t *)ref8;
351 for (
int z = 0; z <
width; z++) {
352 uint64_t
s1 = 0,
s2 = 0,
ss = 0, s12 = 0;
354 for (
int y = 0; y < 4; y++) {
355 for (
int x = 0; x < 4; x++) {
356 unsigned a = main16[x + y * main_stride];
357 unsigned b = ref16[x + y * ref_stride];
378 const uint8_t *
ref, ptrdiff_t ref_stride,
379 int (*sums)[4],
int width)
381 for (
int z = 0; z <
width; z++) {
382 uint32_t
s1 = 0,
s2 = 0,
ss = 0, s12 = 0;
384 for (
int y = 0; y < 4; y++) {
385 for (
int x = 0; x < 4; x++) {
386 int a =
main[x + y * main_stride];
387 int b =
ref[x + y * ref_stride];
408 int64_t ssim_c1 = (int64_t)(.01 * .01 *
max *
max * 64 + .5);
409 int64_t ssim_c2 = (int64_t)(.03 * .03 *
max *
max * 64 * 63 + .5);
415 int64_t
vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
416 int64_t covar = fs12 * 64 - fs1 * fs2;
418 return (
float)(2 * fs1 * fs2 + ssim_c1) * (
float)(2 * covar + ssim_c2)
419 / ((
float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (
float)(
vars + ssim_c2));
424 static const int ssim_c1 = (
int)(.01*.01*255*255*64 + .5);
425 static const int ssim_c2 = (
int)(.03*.03*255*255*64*63 + .5);
431 int vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
432 int covar = fs12 * 64 - fs1 * fs2;
434 return (
float)(2 * fs1 * fs2 + ssim_c1) * (
float)(2 * covar + ssim_c2)
435 / ((
float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (
float)(
vars + ssim_c2));
441 double *density_map,
int map_width,
double *total_weight)
443 double ssim360 = 0.0,
weight;
446 weight = density_map ? density_map[(
int) ((0.5 +
i) /
width * map_width)] : 1.0;
448 sum0[
i][0] + sum0[
i + 1][0] + sum1[
i][0] + sum1[
i + 1][0],
449 sum0[
i][1] + sum0[
i + 1][1] + sum1[
i][1] + sum1[
i + 1][1],
450 sum0[
i][2] + sum0[
i + 1][2] + sum1[
i][2] + sum1[
i + 1][2],
451 sum0[
i][3] + sum0[
i + 1][3] + sum1[
i][3] + sum1[
i + 1][3],
460 double *density_map,
int map_width,
double *total_weight)
462 double ssim360 = 0.0,
weight;
465 weight = density_map ? density_map[(
int) ((0.5 +
i) /
width * map_width)] : 1.0;
467 sum0[
i][0] + sum0[
i + 1][0] + sum1[
i][0] + sum1[
i + 1][0],
468 sum0[
i][1] + sum0[
i + 1][1] + sum1[
i][1] + sum1[
i + 1][1],
469 sum0[
i][2] + sum0[
i + 1][2] + sum1[
i][2] + sum1[
i + 1][2],
470 sum0[
i][3] + sum0[
i + 1][3] + sum1[
i][3] + sum1[
i + 1][3]);
478 uint8_t *
ref,
int ref_stride,
483 double ssim360 = 0.0;
484 int64_t (*sum0)[4] =
temp;
485 int64_t (*sum1)[4] = sum0 + (
width >> 2) + 3;
486 double total_weight = 0.0;
491 for (
int y = 1; y <
height; y++) {
492 for (; z <= y; z++) {
493 FFSWAP(
void*, sum0, sum1);
495 &
ref[4 * z * ref_stride], ref_stride,
499 (
const int64_t (*)[4])sum0, (
const int64_t (*)[4])sum1,
502 density.
w, &total_weight);
505 return (
double) (ssim360 / total_weight);
510 uint8_t *
ref,
int ref_stride,
515 double ssim360 = 0.0;
517 int (*sum1)[4] = sum0 + (
width >> 2) + 3;
518 double total_weight = 0.0;
523 for (
int y = 1; y <
height; y++) {
524 for (; z <= y; z++) {
525 FFSWAP(
void*, sum0, sum1);
527 &
main[4 * z * main_stride], main_stride,
528 &
ref[4 * z * ref_stride], ref_stride,
532 (
const int (*)[4])sum0, (
const int (*)[4])sum1,
width - 1,
534 density.
w, &total_weight);
537 return (
double) (ssim360 / total_weight);
548 static const int inv_byte_mask = UINT_MAX << 8;
550 int tl, tr, bl, br, v;
552 if (max_value & inv_byte_mask) {
553 uint16_t *data16 = (uint16_t *)
data;
577 int offset_y,
int max_value,
int (*sums)[4])
582 for (
int z = 0; z < 2; z++) {
583 int s1 = 0,
s2 = 0,
ss = 0, s12 = 0;
586 for (
int y = offset_y; y < offset_y + 4; y++) {
587 int y_stride = y << 3;
588 for (
int x = offset_x; x < offset_x + 4; x++) {
589 int map_index = x + y_stride;
612 int floor_theta_by_2pi, floor_theta_by_pi;
615 floor_theta_by_2pi = (
int)(theta / (2.0
f *
M_PI_F)) - (theta < 0.0
f);
616 theta -= 2.0f *
M_PI_F * floor_theta_by_2pi;
619 floor_theta_by_pi = theta /
M_PI_F;
620 theta -= 2.0f *
M_PI_F * floor_theta_by_pi;
626 float pitch, yaw, norm_pitch, norm_yaw;
632 pitch = asinf(norm_tape_pos*2);
633 yaw =
M_PI_2_F * pitch / angular_resoluation;
637 norm_pitch = 1.0f - (pitch /
M_PI_F + 0.5f);
638 norm_yaw = yaw / 2.0f /
M_PI_F + 0.5f;
649 int tape_length,
int max_value,
void *
temp,
650 double *ssim360_hist,
double *ssim360_hist_net,
653 int horizontal_block_count = 2;
654 int vertical_block_count = tape_length >> 2;
658 double ssim360 = 0.0;
659 double sum_weight = 0.0;
662 int (*sum1)[4] = sum0 + horizontal_block_count + 3;
664 for (y = 1; y < vertical_block_count; y++) {
665 int fs1, fs2, fss, fs12, hist_index;
666 float norm_tape_pos,
weight;
667 double sample_ssim360;
669 for (; z <= y; z++) {
670 FFSWAP(
void*, sum0, sum1);
675 fs1 = sum0[0][0] + sum0[1][0] + sum1[0][0] + sum1[1][0];
676 fs2 = sum0[0][1] + sum0[1][1] + sum1[0][1] + sum1[1][1];
677 fss = sum0[0][2] + sum0[1][2] + sum1[0][2] + sum1[1][2];
678 fs12 = sum0[0][3] + sum0[1][3] + sum1[0][3] + sum1[1][3];
680 if (max_value > 255) {
682 double ssim_c1_d = .01*.01*64*max_value*max_value;
683 double ssim_c2_d = .03*.03*64*63*max_value*max_value;
685 double vars = 64. * fss - 1. * fs1 * fs1 - 1. * fs2 * fs2;
686 double covar = 64. * fs12 - 1.*fs1 * fs2;
687 sample_ssim360 = (2. * fs1 * fs2 + ssim_c1_d) * (2. * covar + ssim_c2_d)
688 / ((1. * fs1 * fs1 + 1. * fs2 * fs2 + ssim_c1_d) * (1. *
vars + ssim_c2_d));
690 static const int ssim_c1 = (
int)(.01*.01*255*255*64 + .5);
691 static const int ssim_c2 = (
int)(.03*.03*255*255*64*63 + .5);
693 int vars = fss * 64 - fs1 * fs1 - fs2 * fs2;
694 int covar = fs12 * 64 - fs1 * fs2;
695 sample_ssim360 = (
double)(2 * fs1 * fs2 + ssim_c1) * (
double)(2 * covar + ssim_c2)
702 norm_tape_pos = (y - 0.5f) / (vertical_block_count - 1.0
f) - 0.5f;
705 ssim360_hist[hist_index] +=
weight;
706 *ssim360_hist_net +=
weight;
708 ssim360 += (sample_ssim360 *
weight);
712 return ssim360 / sum_weight;
724 int x_floor = x_image;
725 int y_floor = y_image;
726 float x_diff = x_image - x_floor;
727 float y_diff = y_image - y_floor;
729 int x_ceil = x_floor + (x_diff > 1e-6);
730 int y_ceil = y_floor + (y_diff > 1e-6);
731 float x_inv_diff = 1.0f - x_diff;
732 float y_inv_diff = 1.0f - y_diff;
741 m->
tlf = x_inv_diff * y_inv_diff * fixed_point_scale;
742 m->
trf = x_diff * y_inv_diff * fixed_point_scale;
743 m->
blf = x_inv_diff * y_diff * fixed_point_scale;
744 m->
brf = x_diff * y_diff * fixed_point_scale;
749 *x = 0.5f + theta / (2.0f *
M_PI_F);
756 float abs_phi =
FFABS(phi);
767 float circle_x = radial_ratio *
sinf(theta);
768 float circle_y = radial_ratio *
cosf(theta);
769 float offset_y = 0.25f;
776 *x = 0.8f + 0.1f * (1.0f + circle_x);
777 *y = offset_y + 0.25f * circle_y;
783 float abs_phi =
FFABS(phi);
787 float radian_pi_theta = theta /
M_PI_F + 0.5f;
790 if (radian_pi_theta < 0.0
f)
791 radian_pi_theta += 2.0f;
794 vFace = radian_pi_theta >= 1.0f;
798 *x = 2.0f / 3.0f * (0.5f + (radian_pi_theta - vFace - 0.5f) / expand_coef);
800 *y = 0.25f + 0.5f * vFace - phi / (
M_PI_F * expand_coef);
804 float radial_ratio =
cosf(abs_phi) / (
sinf(abs_phi) * expand_coef);
805 float circle_x = radial_ratio *
sinf(theta);
806 float circle_y = radial_ratio *
cosf(theta);
807 float offset_y = 0.25f;
812 circle_y = (circle_y >= 0.0f) ? (1 - circle_y) : (-1 - circle_y);
825 *x = 2.0f / 3.0f + 0.5f / 3.0f * (1.0f + circle_x);
826 *y = offset_y + 0.25f * circle_y / expand_coef;
831 static int get_cubemap_face_map(
float axis_vec_x,
float axis_vec_y,
float axis_vec_z,
float *face_x,
float *face_y)
838 if (
FFABS(axis_vec_y) > 0.577
f) {
839 float x_hit = axis_vec_x /
FFABS(axis_vec_y);
840 float z_hit = axis_vec_z / axis_vec_y;
851 if (
FFABS(axis_vec_x) > 0.577
f) {
852 float z_hit = -axis_vec_z / axis_vec_x;
853 float y_hit = axis_vec_y /
FFABS(axis_vec_x);
864 *face_x = axis_vec_x / axis_vec_z;
866 *face_y = -axis_vec_y /
FFABS(axis_vec_z);
877 static const int face_projection_map[] = {
882 float axis_vec_x =
cosf(phi) *
sinf(theta);
883 float axis_vec_y =
sinf(phi);
884 float axis_vec_z =
cosf(phi) *
cosf(theta);
885 float face_x = 0, face_y = 0;
888 float x_offset = 1.f / 3.f * (face_projection_map[face_index] % 3);
889 float y_offset = .5f * (face_projection_map[face_index] / 3);
902 static const int face_projection_map[] = {
908 float axis_yaw_vec_x, axis_yaw_vec_y, axis_yaw_vec_z;
909 float axis_pitch_vec_z, axis_pitch_vec_y;
910 float x_offset, y_offset;
911 float face_x = 0, face_y = 0;
919 axis_yaw_vec_x =
cosf(phi) *
sinf(theta);
920 axis_yaw_vec_y =
sinf(phi);
921 axis_yaw_vec_z =
cosf(phi) *
cosf(theta);
924 axis_pitch_vec_z = (axis_yaw_vec_z - axis_yaw_vec_y) /
M_SQRT2_F;
925 axis_pitch_vec_y = (axis_yaw_vec_y + axis_yaw_vec_z) /
M_SQRT2_F;
927 face_index =
get_cubemap_face_map(axis_yaw_vec_x, axis_pitch_vec_y, axis_pitch_vec_z, &face_x, &face_y);
930 if (face_index ==
LEFT || face_index ==
FRONT || face_index ==
RIGHT) {
932 float upright_y = face_y;
935 }
else if (face_index ==
TOP || face_index ==
BOTTOM) {
941 x_offset = .5f * (face_projection_map[face_index] & 1);
942 y_offset = 1.f / 3.f * (face_projection_map[face_index] >> 1);
944 *x = x_offset + (face_x / expand_coef + 1.f) / 4.
f;
945 *y = y_offset + (face_y / expand_coef + 1.f) / 6.
f;
999 return expand_coef / (
M_SQRT2_F * image_width / 4.f);
1006 return FFMAX((expand_coef *
M_PI_F) / (2.0
f / 3.0
f * image_width),
1007 expand_coef *
M_PI_2_F / (image_height / 2.0
f));
1022 int ref_image_height = ref_sample_params->
y_image_range + 1;
1024 float angular_resolution =
1026 ref_image_width, ref_image_height);
1028 float conversion_factor =
M_PI_2_F / (angular_resolution * angular_resolution);
1029 float start_phi = -
M_PI_2_F + 4.0f * angular_resolution;
1030 float start_x = conversion_factor *
sinf(start_phi);
1031 float end_phi =
M_PI_2_F - 3.0f * angular_resolution;
1032 float end_x = conversion_factor *
sinf(end_phi);
1033 float x_range = end_x - start_x;
1036 int tape_length =
s->tape_length[plane] = ((
int)
ROUNDED_DIV(x_range, 4)) << 2;
1040 if (!
s->ref_tape_map[plane][eye] || !
s->main_tape_map[plane][eye])
1043 s->angular_resolution[plane][eye] = angular_resolution;
1046 for (
int y_index = 0; y_index < tape_length; y_index ++) {
1047 int y_stride = y_index << 3;
1049 float x = start_x + x_range * (y_index / (tape_length - 1.0f));
1051 float mid_phi = asinf(x / conversion_factor);
1053 float theta = mid_phi *
M_PI_2_F / angular_resolution;
1056 for (
int x_index = 0; x_index < 8; x_index ++) {
1057 float phi = mid_phi + angular_resolution * (3.0f - x_index);
1058 int tape_index = y_stride + x_index;
1059 get_projected_map(phi, theta, ref_sample_params, &
s->ref_tape_map [plane][eye][tape_index]);
1060 get_projected_map(phi, theta, main_sample_params, &
s->main_tape_map[plane][eye][tape_index]);
1071 int ref_stereo_format =
s->ref_stereo_format;
1072 int main_stereo_format =
s->main_stereo_format;
1074 int min_eye_count = 1 + are_both_stereo;
1077 for (
int i = 0;
i <
s->nb_components;
i ++) {
1078 int ref_width =
s->ref_planewidth[
i];
1079 int ref_height =
s->ref_planeheight[
i];
1080 int main_width =
s->main_planewidth[
i];
1081 int main_height =
s->main_planeheight[
i];
1088 int ref_image_width = is_ref_LR ? ref_width >> 1 : ref_width;
1089 int ref_image_height = is_ref_TB ? ref_height >> 1 : ref_height;
1090 int main_image_width = is_main_LR ? main_width >> 1 : main_width;
1091 int main_image_height = is_main_TB ? main_height >> 1 : main_height;
1093 for (
int eye = 0; eye < min_eye_count; eye ++) {
1096 .planewidth = ref_width,
1097 .planeheight = ref_height,
1098 .x_image_range = ref_image_width - 1,
1099 .y_image_range = ref_image_height - 1,
1100 .x_image_offset = is_ref_LR * eye * ref_image_width,
1101 .y_image_offset = is_ref_TB * eye * ref_image_height,
1102 .projection =
s->ref_projection,
1103 .expand_coef = 1.f +
s->ref_pad,
1108 .planewidth = main_width,
1109 .planeheight = main_height,
1110 .x_image_range = main_image_width - 1,
1111 .y_image_range = main_image_height - 1,
1112 .x_image_offset = is_main_LR * eye * main_image_width,
1113 .y_image_offset = is_main_TB * eye * main_image_height,
1114 .projection =
s->main_projection,
1115 .expand_coef = 1.f +
s->main_pad,
1133 double c[4], ssim360v = 0.0, ssim360p50 = 0.0;
1135 int need_frame_skip =
s->nb_net_frames % (
s->frame_skip_ratio + 1);
1144 if (need_frame_skip)
1147 metadata = &
master->metadata;
1149 if (
s->use_tape && !
s->tape_length[0]) {
1155 for (
i = 0;
i <
s->nb_components;
i++) {
1158 ref->data[
i],
s->ref_tape_map [
i][0],
1159 s->tape_length[
i],
s->max,
s->temp,
1160 s->ssim360_hist[
i], &
s->ssim360_hist_net[
i],
1161 s->angular_resolution[
i][0],
s->heatmaps);
1163 if (
s->ref_tape_map[
i][1]) {
1165 ref->data[
i],
s->ref_tape_map[
i][1],
1166 s->tape_length[
i],
s->max,
s->temp,
1167 s->ssim360_hist[
i], &
s->ssim360_hist_net[
i],
1168 s->angular_resolution[
i][1],
s->heatmaps);
1174 s->ref_planewidth[
i],
s->ref_planeheight[
i],
1175 s->temp,
s->max,
s->density);
1178 s->ssim360[
i] +=
c[
i];
1179 ssim360v +=
s->coefs[
i] *
c[
i];
1182 s->nb_ssim_frames++;
1185 h_ptr =
s->heatmaps;
1186 s->heatmaps =
s->heatmaps->next;
1189 s->ssim360_total += ssim360v;
1193 int i, p, hist_indices[4];
1194 double hist_weight[4];
1196 for (
i = 0;
i <
s->nb_components;
i++) {
1202 for (
i = 0;
i <
s->nb_components;
i++) {
1203 double target_weight, ssim360p;
1207 target_weight =
FFMAX(target_weight, 1);
1208 while(hist_indices[
i] >= 0 && hist_weight[
i] < target_weight) {
1209 hist_weight[
i] +=
s->ssim360_hist[
i][hist_indices[
i]];
1215 ssim360p50 +=
s->coefs[
i] * ssim360p;
1216 s->ssim360_percentile_sum[
i][p] += ssim360p;
1220 for (
i = 0;
i <
s->nb_components;
i++) {
1222 s->ssim360_hist_net[
i] = 0;
1225 for (
i = 0;
i <
s->nb_components;
i++) {
1226 int cidx =
s->is_rgb ?
s->rgba_map[
i] :
i;
1227 set_meta(metadata,
"lavfi.ssim360.",
s->comps[
i],
c[cidx]);
1231 set_meta(metadata,
"lavfi.ssim360.All", 0, ssim360p50);
1234 if (
s->stats_file) {
1235 fprintf(
s->stats_file,
"n:%"PRId64
" ",
s->nb_ssim_frames);
1237 for (
i = 0;
i <
s->nb_components;
i++) {
1238 int cidx =
s->is_rgb ?
s->rgba_map[
i] :
i;
1239 fprintf(
s->stats_file,
"%c:%f ",
s->comps[
i],
c[cidx]);
1242 fprintf(
s->stats_file,
"All:%f (%f)\n", ssim360p50,
ssim360_db(ssim360p50, 1.0));
1250 const char *
data,
int w,
int h)
1268 char *saveptr, *
val;
1316 if (
s->stats_file_str) {
1317 if (!strcmp(
s->stats_file_str,
"-")) {
1318 s->stats_file = stdout;
1321 if (!
s->stats_file) {
1327 s->stats_file_str, buf);
1333 if (
s->use_tape &&
s->heatmap_str) {
1335 s->default_heatmap_w,
s->default_heatmap_h);
1350 s->main_planeheight[0] =
inlink->h;
1351 s->main_planeheight[3] =
inlink->h;
1355 s->main_planewidth[0] =
inlink->w;
1356 s->main_planewidth[3] =
inlink->w;
1362 s->main_projection =
s->ref_projection;
1366 s->main_stereo_format =
s->ref_stereo_format;
1373 double d, r_square, cos_square;
1380 switch (
s->ref_stereo_format) {
1389 switch (
s->ref_projection) {
1391 for (
int i = 0;
i <
h;
i++) {
1392 d = cos(((0.5 +
i) /
h - 0.5) *
M_PI);
1393 for (
int j = 0; j <
w; j++)
1394 s->density.value[
i *
w + j] =
d;
1399 for (
int i = 0;
i <
h / 4;
i++) {
1400 for (
int j = 0; j <
w / 6; j++) {
1403 (0.5 +
i) / (
h / 2) * (0.5 +
i) / (
h / 2) +
1404 (0.5 + j) / (
w / 3) * (0.5 + j) / (
w / 3);
1406 cos_square = 0.25 / (r_square + 0.25);
1407 d = pow(cos_square, 1.5);
1409 for (
int face = 0; face < 6; face++) {
1422 ow =
w / 6 + 2 *
w / 3;
1434 ow =
w / 6 + 2 *
w / 3;
1437 s->density.value[(oh - 1 -
i) *
w + ow - 1 - j] =
d;
1438 s->density.value[(oh - 1 -
i) *
w + ow + j] =
d;
1439 s->density.value[(oh +
i) *
w + ow - 1 - j] =
d;
1440 s->density.value[(oh +
i) *
w + ow + j] =
d;
1447 for (
int i = 0;
i <
h / 6;
i++) {
1448 for (
int j = 0; j <
w / 4; j++) {
1451 (0.5 +
i) / (
h / 3) * (0.5 +
i) / (
h / 3) +
1452 (0.5 + j) / (
w / 2) * (0.5 + j) / (
w / 2);
1453 r_square /= (1.f +
s->ref_pad) * (1.
f +
s->ref_pad);
1454 cos_square = 0.25 / (r_square + 0.25);
1455 d = pow(cos_square, 1.5);
1457 for (
int face = 0; face < 6; face++) {
1470 oh =
h / 6 + 2 *
h / 3;
1482 oh =
h / 6 + 2 *
h / 3;
1485 s->density.value[(oh - 1 -
i) *
w + ow - 1 - j] =
d;
1486 s->density.value[(oh - 1 -
i) *
w + ow + j] =
d;
1487 s->density.value[(oh +
i) *
w + ow - 1 - j] =
d;
1488 s->density.value[(oh +
i) *
w + ow + j] =
d;
1495 for (
int i = 0;
i <
h;
i++) {
1496 for (
int j = 0; j <
w * 4 / 5; j++) {
1498 s->density.value[
i *
w + j] =
d *
d *
d;
1502 for (
int i = 0;
i <
h;
i++) {
1503 for (
int j =
w * 4 / 5; j <
w; j++) {
1505 double dx_squared = dx * dx;
1508 double top_dy_squared = top_dy * top_dy;
1511 double bottom_dy_squared = bottom_dy * bottom_dy;
1514 r_square = (
i <
h / 2 ? top_dy_squared : bottom_dy_squared) + dx_squared;
1518 cos_square = 1.0 / (r_square + 1.0);
1519 d = pow(cos_square, 1.5);
1520 s->density.value[
i *
w + j] =
d;
1526 for (
int i = 0;
i <
h;
i++) {
1527 for (
int j = 0; j <
w; j++)
1528 s->density.value[
i *
w + j] = 0;
1532 switch (
s->ref_stereo_format) {
1534 for (
int i = 0;
i <
h;
i++) {
1535 for (
int j = 0; j <
w; j++)
1536 s->density.value[(
i +
h) *
w + j] =
s->density.value[
i *
w + j];
1540 for (
int i = 0;
i <
h;
i++) {
1541 for (
int j = 0; j <
w; j++)
1542 s->density.value[
i *
w + j +
w] =
s->density.value[
i *
w + j];
1556 s->nb_components =
desc->nb_components;
1558 s->ref_planeheight[0] =
inlink->h;
1559 s->ref_planeheight[3] =
inlink->h;
1563 s->ref_planewidth[0] =
inlink->w;
1564 s->ref_planewidth[3] =
inlink->w;
1569 s->comps[0] =
s->is_rgb ?
'R' :
'Y';
1570 s->comps[1] =
s->is_rgb ?
'G' :
'U';
1571 s->comps[2] =
s->is_rgb ?
'B' :
'V';
1575 if (!
s->is_rgb && !
s->compute_chroma)
1576 s->nb_components = 1;
1578 s->max = (1 <<
desc->comp[0].depth) - 1;
1582 for (
int i = 0;
i <
s->nb_components;
i++)
1583 sum +=
s->ref_planeheight[
i] *
s->ref_planewidth[
i];
1584 for (
int i = 0;
i <
s->nb_components;
i++)
1585 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,