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) coefficient 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;
722 float x_image =
av_clipf(x *
p->x_image_range, 0,
p->x_image_range) +
p->x_image_offset;
723 float y_image =
av_clipf(y *
p->y_image_range, 0,
p->y_image_range) +
p->y_image_offset;
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;
736 m->
tli = x_floor + y_floor *
p->stride;
737 m->
tri = x_ceil + y_floor *
p->stride;
738 m->
bli = x_floor + y_ceil *
p->stride;
739 m->
bri = x_ceil + y_ceil *
p->stride;
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;
952 switch(
p->projection) {
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;
1040 if (!(tape_length_f > 0.
f) || tape_length_f > INT_MAX / 4.0
f)
1043 tape_length =
s->tape_length[plane] = (int)tape_length_f << 2;
1047 if (!
s->ref_tape_map[plane][eye] || !
s->main_tape_map[plane][eye])
1050 s->angular_resolution[plane][eye] = angular_resolution;
1053 for (
int y_index = 0; y_index < tape_length; y_index ++) {
1054 int y_stride = y_index << 3;
1056 float x = start_x + x_range * (y_index / (tape_length - 1.0f));
1058 float mid_phi = asinf(x / conversion_factor);
1060 float theta = mid_phi *
M_PI_2_F / angular_resolution;
1063 for (
int x_index = 0; x_index < 8; x_index ++) {
1064 float phi = mid_phi + angular_resolution * (3.0f - x_index);
1065 int tape_index = y_stride + x_index;
1066 get_projected_map(phi, theta, ref_sample_params, &
s->ref_tape_map [plane][eye][tape_index]);
1067 get_projected_map(phi, theta, main_sample_params, &
s->main_tape_map[plane][eye][tape_index]);
1078 int ref_stereo_format =
s->ref_stereo_format;
1079 int main_stereo_format =
s->main_stereo_format;
1081 int min_eye_count = 1 + are_both_stereo;
1084 for (
int i = 0;
i <
s->nb_components;
i ++) {
1085 int ref_width =
s->ref_planewidth[
i];
1086 int ref_height =
s->ref_planeheight[
i];
1087 int main_width =
s->main_planewidth[
i];
1088 int main_height =
s->main_planeheight[
i];
1095 int ref_image_width = is_ref_LR ? ref_width >> 1 : ref_width;
1096 int ref_image_height = is_ref_TB ? ref_height >> 1 : ref_height;
1097 int main_image_width = is_main_LR ? main_width >> 1 : main_width;
1098 int main_image_height = is_main_TB ? main_height >> 1 : main_height;
1100 for (
int eye = 0; eye < min_eye_count; eye ++) {
1103 .planewidth = ref_width,
1104 .planeheight = ref_height,
1105 .x_image_range = ref_image_width - 1,
1106 .y_image_range = ref_image_height - 1,
1107 .x_image_offset = is_ref_LR * eye * ref_image_width,
1108 .y_image_offset = is_ref_TB * eye * ref_image_height,
1109 .projection =
s->ref_projection,
1110 .expand_coef = 1.f +
s->ref_pad,
1115 .planewidth = main_width,
1116 .planeheight = main_height,
1117 .x_image_range = main_image_width - 1,
1118 .y_image_range = main_image_height - 1,
1119 .x_image_offset = is_main_LR * eye * main_image_width,
1120 .y_image_offset = is_main_TB * eye * main_image_height,
1121 .projection =
s->main_projection,
1122 .expand_coef = 1.f +
s->main_pad,
1140 double c[4], ssim360v = 0.0, ssim360p50 = 0.0;
1142 int need_frame_skip =
s->nb_net_frames % (
s->frame_skip_ratio + 1);
1151 if (need_frame_skip)
1156 if (
s->use_tape && !
s->tape_length[0]) {
1162 for (
int i = 0;
i <
s->nb_components;
i++) {
1165 ref->data[
i],
s->ref_tape_map [
i][0],
1166 s->tape_length[
i],
s->max,
s->temp,
1167 s->ssim360_hist[
i], &
s->ssim360_hist_net[
i],
1168 s->angular_resolution[
i][0],
s->heatmaps);
1170 if (
s->ref_tape_map[
i][1]) {
1172 ref->data[
i],
s->ref_tape_map[
i][1],
1173 s->tape_length[
i],
s->max,
s->temp,
1174 s->ssim360_hist[
i], &
s->ssim360_hist_net[
i],
1175 s->angular_resolution[
i][1],
s->heatmaps);
1181 s->ref_planewidth[
i],
s->ref_planeheight[
i],
1182 s->temp,
s->max,
s->density);
1185 s->ssim360[
i] +=
c[
i];
1186 ssim360v +=
s->coefs[
i] *
c[
i];
1189 s->nb_ssim_frames++;
1192 h_ptr =
s->heatmaps;
1193 s->heatmaps =
s->heatmaps->next;
1196 s->ssim360_total += ssim360v;
1200 int hist_indices[4];
1201 double hist_weight[4];
1203 for (
int i = 0;
i <
s->nb_components;
i++) {
1209 for (
int i = 0;
i <
s->nb_components;
i++) {
1210 double target_weight, ssim360p;
1214 target_weight =
FFMAX(target_weight, 1);
1215 while(hist_indices[
i] >= 0 && hist_weight[
i] < target_weight) {
1216 hist_weight[
i] +=
s->ssim360_hist[
i][hist_indices[
i]];
1222 ssim360p50 +=
s->coefs[
i] * ssim360p;
1223 s->ssim360_percentile_sum[
i][
p] += ssim360p;
1227 for (
int i = 0;
i <
s->nb_components;
i++) {
1229 s->ssim360_hist_net[
i] = 0;
1232 for (
int i = 0;
i <
s->nb_components;
i++) {
1233 int cidx =
s->is_rgb ?
s->rgba_map[
i] :
i;
1241 if (
s->stats_file) {
1242 fprintf(
s->stats_file,
"n:%"PRId64
" ",
s->nb_ssim_frames);
1244 for (
int i = 0;
i <
s->nb_components;
i++) {
1245 int cidx =
s->is_rgb ?
s->rgba_map[
i] :
i;
1246 fprintf(
s->stats_file,
"%c:%f ",
s->comps[
i],
c[cidx]);
1249 fprintf(
s->stats_file,
"All:%f (%f)\n", ssim360p50,
ssim360_db(ssim360p50, 1.0));
1257 const char *
data,
int w,
int h)
1275 char *saveptr, *
val;
1323 if (
s->stats_file_str) {
1324 if (!strcmp(
s->stats_file_str,
"-")) {
1325 s->stats_file = stdout;
1328 if (!
s->stats_file) {
1337 if (
s->use_tape &&
s->heatmap_str) {
1339 s->default_heatmap_w,
s->default_heatmap_h);
1354 s->main_planeheight[0] =
inlink->h;
1355 s->main_planeheight[3] =
inlink->h;
1359 s->main_planewidth[0] =
inlink->w;
1360 s->main_planewidth[3] =
inlink->w;
1366 s->main_projection =
s->ref_projection;
1370 s->main_stereo_format =
s->ref_stereo_format;
1377 double d, r_square, cos_square;
1384 switch (
s->ref_stereo_format) {
1393 switch (
s->ref_projection) {
1395 for (
int i = 0;
i <
h;
i++) {
1396 d = cos(((0.5 +
i) /
h - 0.5) *
M_PI);
1397 for (
int j = 0; j <
w; j++)
1398 s->density.value[
i *
w + j] = d;
1403 for (
int i = 0;
i <
h / 4;
i++) {
1404 for (
int j = 0; j <
w / 6; j++) {
1407 (0.5 +
i) / (
h / 2) * (0.5 +
i) / (
h / 2) +
1408 (0.5 + j) / (
w / 3) * (0.5 + j) / (
w / 3);
1410 cos_square = 0.25 / (r_square + 0.25);
1411 d = pow(cos_square, 1.5);
1413 for (
int face = 0; face < 6; face++) {
1426 ow =
w / 6 + 2 *
w / 3;
1438 ow =
w / 6 + 2 *
w / 3;
1441 s->density.value[(oh - 1 -
i) *
w + ow - 1 - j] = d;
1442 s->density.value[(oh - 1 -
i) *
w + ow + j] = d;
1443 s->density.value[(oh +
i) *
w + ow - 1 - j] = d;
1444 s->density.value[(oh +
i) *
w + ow + j] = d;
1451 for (
int i = 0;
i <
h / 6;
i++) {
1452 for (
int j = 0; j <
w / 4; j++) {
1455 (0.5 +
i) / (
h / 3) * (0.5 +
i) / (
h / 3) +
1456 (0.5 + j) / (
w / 2) * (0.5 + j) / (
w / 2);
1457 r_square /= (1.f +
s->ref_pad) * (1.
f +
s->ref_pad);
1458 cos_square = 0.25 / (r_square + 0.25);
1459 d = pow(cos_square, 1.5);
1461 for (
int face = 0; face < 6; face++) {
1474 oh =
h / 6 + 2 *
h / 3;
1486 oh =
h / 6 + 2 *
h / 3;
1489 s->density.value[(oh - 1 -
i) *
w + ow - 1 - j] = d;
1490 s->density.value[(oh - 1 -
i) *
w + ow + j] = d;
1491 s->density.value[(oh +
i) *
w + ow - 1 - j] = d;
1492 s->density.value[(oh +
i) *
w + ow + j] = d;
1499 for (
int i = 0;
i <
h;
i++) {
1500 for (
int j = 0; j <
w * 4 / 5; j++) {
1502 s->density.value[
i *
w + j] = d * d * d;
1506 for (
int i = 0;
i <
h;
i++) {
1507 for (
int j =
w * 4 / 5; j <
w; j++) {
1509 double dx_squared = dx * dx;
1512 double top_dy_squared = top_dy * top_dy;
1515 double bottom_dy_squared = bottom_dy * bottom_dy;
1518 r_square = (
i <
h / 2 ? top_dy_squared : bottom_dy_squared) + dx_squared;
1522 cos_square = 1.0 / (r_square + 1.0);
1523 d = pow(cos_square, 1.5);
1524 s->density.value[
i *
w + j] = d;
1530 for (
int i = 0;
i <
h;
i++) {
1531 for (
int j = 0; j <
w; j++)
1532 s->density.value[
i *
w + j] = 0;
1536 switch (
s->ref_stereo_format) {
1538 for (
int i = 0;
i <
h;
i++) {
1539 for (
int j = 0; j <
w; j++)
1540 s->density.value[(
i +
h) *
w + j] =
s->density.value[
i *
w + j];
1544 for (
int i = 0;
i <
h;
i++) {
1545 for (
int j = 0; j <
w; j++)
1546 s->density.value[
i *
w + j +
w] =
s->density.value[
i *
w + j];
1560 s->nb_components =
desc->nb_components;
1562 s->ref_planeheight[0] =
inlink->h;
1563 s->ref_planeheight[3] =
inlink->h;
1567 s->ref_planewidth[0] =
inlink->w;
1568 s->ref_planewidth[3] =
inlink->w;
1573 s->comps[0] =
s->is_rgb ?
'R' :
'Y';
1574 s->comps[1] =
s->is_rgb ?
'G' :
'U';
1575 s->comps[2] =
s->is_rgb ?
'B' :
'V';
1579 if (!
s->is_rgb && !
s->compute_chroma)
1580 s->nb_components = 1;
1582 s->max = (1 <<
desc->comp[0].depth) - 1;
1586 for (
int i = 0;
i <
s->nb_components;
i++)
1587 sum +=
s->ref_planeheight[
i] *
s->ref_planewidth[
i];
1588 for (
int i = 0;
i <
s->nb_components;
i++)
1589 s->coefs[
i] = (
double)
s->ref_planeheight[
i] *
s->ref_planewidth[
i] / sum;
1606 if (
ctx->inputs[0]->w !=
ctx->inputs[1]->w ||
ctx->inputs[0]->h !=
ctx->inputs[1]->h ||
1607 s->ref_projection !=
s->main_projection ||
s->ref_stereo_format !=
s->main_stereo_format)
1624 memset(
s->ssim360_percentile_sum, 0,
sizeof(
s->ssim360_percentile_sum));
1626 for (
int i = 0;
i <
s->nb_components;
i++) {
1628 if (!
s->ssim360_hist[
i])
1636 if (!
s->density.value) {
1647 outlink->
w = mainlink->
w;
1648 outlink->
h = mainlink->
h;
1653 s->fs.opt_shortest = 1;
1654 s->fs.opt_repeatlast = 1;
1673 if (
s->nb_ssim_frames > 0) {
1677 for (
int i = 0;
i <
s->nb_components;
i++) {
1678 int c =
s->is_rgb ?
s->rgba_map[
i] :
i;
1679 av_strlcatf(buf,
sizeof(buf),
" %c:%f (%f)",
s->comps[
i],
s->ssim360[
c] /
s->nb_ssim_frames,
1683 s->ssim360_total /
s->nb_ssim_frames,
ssim360_db(
s->ssim360_total,
s->nb_ssim_frames));
1689 for (
int i = 0;
i <
s->nb_components;
i++) {
1690 int c =
s->is_rgb ?
s->rgba_map[
i] :
i;
1691 double ssim360p =
s->ssim360_percentile_sum[
i][
p] / (
double)(
s->nb_ssim_frames);
1704 for (
int i = 0;
i <
s->nb_components;
i++) {
1705 for (
int eye = 0; eye < 2; eye++) {
1714 if (
s->stats_file &&
s->stats_file != stdout)
1715 fclose(
s->stats_file);
1720 #define PF(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf, AV_PIX_FMT_GBR##suf
1740 .name =
"reference",
1755 .
p.
name =
"ssim360",
1757 .p.priv_class = &ssim360_class,
1758 .preinit = ssim360_framesync_preinit,