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.0f *
M_PI_F)) - (theta < 0.0f);
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.0f) - 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.0f)
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;
832static 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.577f) {
840 float x_hit = axis_vec_x /
FFABS(axis_vec_y);
841 float z_hit = axis_vec_z / axis_vec_y;
843 if (
FFABS(x_hit) <= 1.f &&
FFABS(z_hit) <= 1.f) {
852 if (
FFABS(axis_vec_x) > 0.577f) {
853 float z_hit = -axis_vec_z / axis_vec_x;
854 float y_hit = axis_vec_y /
FFABS(axis_vec_x);
856 if (
FFABS(z_hit) <= 1.f &&
FFABS(y_hit) <= 1.f) {
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.0f / 3.0f * image_width),
1008 expand_coef *
M_PI_2_F / (image_height / 2.0f));
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.0f)
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 ++) {
1102 .stride =
ref->linesize[
i],
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,
1114 .stride =
main->linesize[
i],
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,
static double val(void *priv, double ch)
const FFFilter ff_vf_ssim360
static AVFormatContext * ctx
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Main libavfilter public API header.
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
static const uint8_t vars[2][12]
static int FUNC metadata(CodedBitstreamContext *ctx, RWContext *rw, APVRawMetadata *current)
#define i(width, name, range_min, range_max)
#define ss(width, name, subs,...)
#define fs(width, name, subs,...)
#define AV_CEIL_RSHIFT(a, b)
#define ROUNDED_DIV(a, b)
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
int(* init)(AVBSFContext *ctx)
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
#define FRAMESYNC_DEFINE_CLASS(name, context, field)
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
#define AV_LOG_INFO
Standard information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
const VDPAUPixFmtMap * map
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
static int config_output(AVBitStreamFilterLink *outlink)
#define FILTER_INPUTS(array)
#define FILTER_OUTPUTS(array)
#define FILTER_PIXFMTS_ARRAY(array)
static FilterLink * ff_filter_link(AVFilterLink *link)
FILE * avpriv_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
#define FF_ALLOCZ_TYPED_ARRAY(p, nelem)
#define FFSWAP(type, a, b)
void * av_calloc(size_t nmemb, size_t size)
Memory handling functions.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
AVPixelFormat
Pixel format.
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
@ AV_PIX_FMT_YUVJ440P
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
@ AV_PIX_FMT_YUVJ411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor ...
@ AV_PIX_FMT_YUVJ422P
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
@ AV_PIX_FMT_YUVJ420P
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
const h264_weight_func weight
Describe the class of an AVClass context structure.
A link between two filters.
int w
agreed upon image width
int h
agreed upon image height
AVFilterContext * src
source filter
AVRational time_base
Define the time base used by the PTS of the frames/samples which will pass through this link.
AVRational sample_aspect_ratio
agreed upon sample aspect ratio
AVFilterContext * dst
dest filter
int format
agreed upon media format
A filter pad used for either input or output.
This structure describes decoded (raw) audio or video data.
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Link properties exposed to filter code, but not external callers.
AVRational frame_rate
Frame rate of the stream on the link, or 1/0 if unknown or variable.
struct HeatmapList * next
float angular_resolution[4][2]
double ssim360_hist_net[4]
double(* ssim360_plane)(uint8_t *main, int main_stride, uint8_t *ref, int ref_stride, int width, int height, void *temp, int max, Map2D density)
BilinearMap * main_tape_map[4][2]
double ssim360_percentile_sum[4][256]
BilinearMap * ref_tape_map[4][2]
uint64_t frame_skip_ratio
#define av_malloc_array(a, b)
static int ref[MAX_W *MAX_W]
static int config_input_main(AVFilterLink *inlink)
static int config_input_ref(AVFilterLink *inlink)
static void ssim360_4x4xn_8bit(const uint8_t *main, ptrdiff_t main_stride, const uint8_t *ref, ptrdiff_t ref_stride, int(*sums)[4], int width)
#define FIXED_POINT_PRECISION
static const AVOption ssim360_options[]
static void get_rotated_cubemap_map(float phi, float theta, float expand_coef, float *x, float *y)
#define SSIM360_HIST_SIZE
static int generate_density_map(SSIM360Context *s, int w, int h)
static void map_uninit(Map2D *map)
static void ssim360_4x4x2_tape(const uint8_t *main, BilinearMap *main_maps, const uint8_t *ref, BilinearMap *ref_maps, int offset_y, int max_value, int(*sums)[4])
static double ssim360_tape(uint8_t *main, BilinearMap *main_maps, uint8_t *ref, BilinearMap *ref_maps, int tape_length, int max_value, void *temp, double *ssim360_hist, double *ssim360_hist_net, float angular_resolution, HeatmapList *heatmaps)
static double ssim360_plane_16bit(uint8_t *main, int main_stride, uint8_t *ref, int ref_stride, int width, int height, void *temp, int max, Map2D density)
static int get_bilinear_sample(const uint8_t *data, BilinearMap *m, int max_value)
static float ssim360_end1x(int64_t s1, int64_t s2, int64_t ss, int64_t s12, int max)
static const double PERCENTILE_LIST[]
static int map_alloc(HeatmapList **pl, int w, int h)
static int do_ssim360(FFFrameSync *fs)
static void ssim360_4x4xn_16bit(const uint8_t *main8, ptrdiff_t main_stride, const uint8_t *ref8, ptrdiff_t ref_stride, int64_t(*sums)[4], int width)
static int get_cubemap_face_map(float axis_vec_x, float axis_vec_y, float axis_vec_z, float *face_x, float *face_y)
static const AVFilterPad ssim360_outputs[]
static int map_init(Map2D *map, int w, int h)
static void get_projected_map(float phi, float theta, SampleParams *p, BilinearMap *m)
static float get_radius_between_negative_and_positive_pi(float theta)
static int generate_tape_maps(SSIM360Context *s, AVFrame *main, const AVFrame *ref)
static const AVFilterPad ssim360_inputs[]
static int config_input_ref(AVFilterLink *inlink)
static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
static int parse_heatmaps(void *logctx, HeatmapList **proot, const char *data, int w, int h)
@ PROJECTION_BARREL_SPLIT
static double ssim360_db(double ssim360, double weight)
static int config_input_main(AVFilterLink *inlink)
static void get_equirect_map(float phi, float theta, float *x, float *y)
static int activate(AVFilterContext *ctx)
static enum AVPixelFormat ssim360_pixfmts[]
static av_cold void uninit(AVFilterContext *ctx)
static float get_heat(HeatmapList *heatmaps, float angular_resoluation, float norm_tape_pos)
static void map_list_free(HeatmapList **pl)
static float ssim360_end1(int s1, int s2, int ss, int s12)
static double ssim360_endn_16bit(const int64_t(*sum0)[4], const int64_t(*sum1)[4], int width, int max, double *density_map, int map_width, double *total_weight)
static int generate_eye_tape_map(SSIM360Context *s, int plane, int eye, SampleParams *ref_sample_params, SampleParams *main_sample_params)
static void get_cubemap32_map(float phi, float theta, float *x, float *y)
static int config_output(AVFilterLink *outlink)
#define BARREL_THETA_RANGE
#define DEFAULT_EXPANSION_COEF
static int tape_supports_projection(int projection)
static void compute_bilinear_map(SampleParams *p, BilinearMap *m, float x, float y)
static double ssim360_plane_8bit(uint8_t *main, int main_stride, uint8_t *ref, int ref_stride, int width, int height, void *temp, int max, Map2D density)
static void get_barrel_map(float phi, float theta, float *x, float *y)
static void get_barrel_split_map(float phi, float theta, float expand_coef, float *x, float *y)
static double ssim360_endn_8bit(const int(*sum0)[4], const int(*sum1)[4], int width, double *density_map, int map_width, double *total_weight)
static float get_tape_angular_resolution(int projection, float expand_coef, int image_width, int image_height)