X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Fvf_v360.c;h=a0f3c52d9351e265721db3bd887b48dbd2e12562;hb=b85dcd8586e2a64356f1d9aac035aa3f63b72501;hp=79415efd6c69cccd8fb653d61d5bc26e4bde4706;hpb=9def7efdbf6e469f822654fecca9bad8ea239f8b;p=ffmpeg diff --git a/libavfilter/vf_v360.c b/libavfilter/vf_v360.c index 79415efd6c6..a0f3c52d935 100644 --- a/libavfilter/vf_v360.c +++ b/libavfilter/vf_v360.c @@ -67,6 +67,8 @@ static const AVOption v360_options[] = { { "sg", "stereographic", 0, AV_OPT_TYPE_CONST, {.i64=STEREOGRAPHIC}, 0, 0, FLAGS, "in" }, { "mercator", "mercator", 0, AV_OPT_TYPE_CONST, {.i64=MERCATOR}, 0, 0, FLAGS, "in" }, { "ball", "ball", 0, AV_OPT_TYPE_CONST, {.i64=BALL}, 0, 0, FLAGS, "in" }, + { "hammer", "hammer", 0, AV_OPT_TYPE_CONST, {.i64=HAMMER}, 0, 0, FLAGS, "in" }, + {"sinusoidal", "sinusoidal", 0, AV_OPT_TYPE_CONST, {.i64=SINUSOIDAL}, 0, 0, FLAGS, "in" }, { "output", "set output projection", OFFSET(out), AV_OPT_TYPE_INT, {.i64=CUBEMAP_3_2}, 0, NB_PROJECTIONS-1, FLAGS, "out" }, { "e", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "out" }, { "equirect", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "out" }, @@ -83,6 +85,8 @@ static const AVOption v360_options[] = { { "sg", "stereographic", 0, AV_OPT_TYPE_CONST, {.i64=STEREOGRAPHIC}, 0, 0, FLAGS, "out" }, { "mercator", "mercator", 0, AV_OPT_TYPE_CONST, {.i64=MERCATOR}, 0, 0, FLAGS, "out" }, { "ball", "ball", 0, AV_OPT_TYPE_CONST, {.i64=BALL}, 0, 0, FLAGS, "out" }, + { "hammer", "hammer", 0, AV_OPT_TYPE_CONST, {.i64=HAMMER}, 0, 0, FLAGS, "out" }, + {"sinusoidal", "sinusoidal", 0, AV_OPT_TYPE_CONST, {.i64=SINUSOIDAL}, 0, 0, FLAGS, "out" }, { "interp", "set interpolation method", OFFSET(interp), AV_OPT_TYPE_INT, {.i64=BILINEAR}, 0, NB_INTERP_METHODS-1, FLAGS, "interp" }, { "near", "nearest neighbour", 0, AV_OPT_TYPE_CONST, {.i64=NEAREST}, 0, 0, FLAGS, "interp" }, { "nearest", "nearest neighbour", 0, AV_OPT_TYPE_CONST, {.i64=NEAREST}, 0, 0, FLAGS, "interp" }, @@ -103,8 +107,10 @@ static const AVOption v360_options[] = { {"out_forder", "output cubemap face order", OFFSET(out_forder), AV_OPT_TYPE_STRING, {.str="rludfb"}, 0, NB_DIRECTIONS-1, FLAGS, "out_forder"}, { "in_frot", "input cubemap face rotation", OFFSET(in_frot), AV_OPT_TYPE_STRING, {.str="000000"}, 0, NB_DIRECTIONS-1, FLAGS, "in_frot"}, { "out_frot", "output cubemap face rotation",OFFSET(out_frot), AV_OPT_TYPE_STRING, {.str="000000"}, 0, NB_DIRECTIONS-1, FLAGS, "out_frot"}, - { "in_pad", "input cubemap pads", OFFSET(in_pad), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 1.f, FLAGS, "in_pad"}, - { "out_pad", "output cubemap pads", OFFSET(out_pad), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 1.f, FLAGS, "out_pad"}, + { "in_pad", "percent input cubemap pads", OFFSET(in_pad), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 1.f, FLAGS, "in_pad"}, + { "out_pad", "percent output cubemap pads", OFFSET(out_pad), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 1.f, FLAGS, "out_pad"}, + { "fin_pad", "fixed input cubemap pads", OFFSET(fin_pad), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS, "fin_pad"}, + { "fout_pad", "fixed output cubemap pads", OFFSET(fout_pad), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS, "fout_pad"}, { "yaw", "yaw rotation", OFFSET(yaw), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, -180.f, 180.f, FLAGS, "yaw"}, { "pitch", "pitch rotation", OFFSET(pitch), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, -180.f, 180.f, FLAGS, "pitch"}, { "roll", "roll rotation", OFFSET(roll), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, -180.f, 180.f, FLAGS, "roll"}, @@ -220,7 +226,7 @@ DEFINE_REMAP1_LINE(16, 2) #define DEFINE_REMAP(ws, bits) \ static int remap##ws##_##bits##bit_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \ { \ - ThreadData *td = (ThreadData*)arg; \ + ThreadData *td = arg; \ const V360Context *s = ctx->priv; \ const AVFrame *in = td->in; \ AVFrame *out = td->out; \ @@ -353,10 +359,10 @@ static void bilinear_kernel(float du, float dv, const XYRemap *rmap, } } - ker[0] = (1.f - du) * (1.f - dv) * 16385; - ker[1] = du * (1.f - dv) * 16385; - ker[2] = (1.f - du) * dv * 16385; - ker[3] = du * dv * 16385; + ker[0] = lrintf((1.f - du) * (1.f - dv) * 16385.f); + ker[1] = lrintf( du * (1.f - dv) * 16385.f); + ker[2] = lrintf((1.f - du) * dv * 16385.f); + ker[3] = lrintf( du * dv * 16385.f); } /** @@ -399,7 +405,7 @@ static void bicubic_kernel(float du, float dv, const XYRemap *rmap, for (int j = 0; j < 4; j++) { u[i * 4 + j] = rmap->u[i][j]; v[i * 4 + j] = rmap->v[i][j]; - ker[i * 4 + j] = du_coeffs[j] * dv_coeffs[i] * 16385; + ker[i * 4 + j] = lrintf(du_coeffs[j] * dv_coeffs[i] * 16385.f); } } } @@ -452,7 +458,7 @@ static void lanczos_kernel(float du, float dv, const XYRemap *rmap, for (int j = 0; j < 4; j++) { u[i * 4 + j] = rmap->u[i][j]; v[i * 4 + j] = rmap->v[i][j]; - ker[i * 4 + j] = du_coeffs[j] * dv_coeffs[i] * 16385; + ker[i * 4 + j] = lrintf(du_coeffs[j] * dv_coeffs[i] * 16385.f); } } } @@ -722,16 +728,18 @@ static void normalize_vector(float *vec) * @param vf vertical cubemap coordinate [0, 1) * @param face face of cubemap * @param vec coordinates on sphere + * @param scalew scale for uf + * @param scaleh scale for vf */ static void cube_to_xyz(const V360Context *s, float uf, float vf, int face, - float *vec) + float *vec, float scalew, float scaleh) { const int direction = s->out_cubemap_direction_order[face]; float l_x, l_y, l_z; - uf /= (1.f - s->out_pad); - vf /= (1.f - s->out_pad); + uf /= scalew; + vf /= scaleh; rotate_cube_face_inverse(&uf, &vf, s->out_cubemap_face_rotation[face]); @@ -1061,6 +1069,9 @@ static void cube3x2_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec) { + const float scalew = s->fout_pad > 0 ? 1.f - s->fout_pad / (s->out_width / 3.f) : 1.f - s->out_pad; + const float scaleh = s->fout_pad > 0 ? 1.f - s->fout_pad / (s->out_height / 2.f) : 1.f - s->out_pad; + const float ew = width / 3.f; const float eh = height / 2.f; @@ -1076,7 +1087,7 @@ static void cube3x2_to_xyz(const V360Context *s, const float uf = 2.f * (i - u_shift + 0.5f) / ewi - 1.f; const float vf = 2.f * (j - v_shift + 0.5f) / ehi - 1.f; - cube_to_xyz(s, uf, vf, face, vec); + cube_to_xyz(s, uf, vf, face, vec, scalew, scaleh); } /** @@ -1095,6 +1106,8 @@ static void xyz_to_cube3x2(const V360Context *s, const float *vec, int width, int height, uint16_t us[4][4], uint16_t vs[4][4], float *du, float *dv) { + const float scalew = s->fin_pad > 0 ? 1.f - s->fin_pad / (s->in_width / 3.f) : 1.f - s->in_pad; + const float scaleh = s->fin_pad > 0 ? 1.f - s->fin_pad / (s->in_height / 2.f) : 1.f - s->in_pad; const float ew = width / 3.f; const float eh = height / 2.f; float uf, vf; @@ -1105,8 +1118,8 @@ static void xyz_to_cube3x2(const V360Context *s, xyz_to_cube(s, vec, &uf, &vf, &direction); - uf *= (1.f - s->in_pad); - vf *= (1.f - s->in_pad); + uf *= scalew; + vf *= scaleh; face = s->in_cubemap_face_order[direction]; u_face = face % 3; @@ -1141,13 +1154,13 @@ static void xyz_to_cube3x2(const V360Context *s, uf = 2.f * new_ui / ewi - 1.f; vf = 2.f * new_vi / ehi - 1.f; - uf /= (1.f - s->in_pad); - vf /= (1.f - s->in_pad); + uf /= scalew; + vf /= scaleh; process_cube_coordinates(s, uf, vf, direction, &uf, &vf, &face); - uf *= (1.f - s->in_pad); - vf *= (1.f - s->in_pad); + uf *= scalew; + vf *= scaleh; u_face = face % 3; v_face = face / 3; @@ -1180,6 +1193,9 @@ static void cube1x6_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec) { + const float scalew = s->fout_pad > 0 ? 1.f - (float)(s->fout_pad) / s->out_width : 1.f - s->out_pad; + const float scaleh = s->fout_pad > 0 ? 1.f - s->fout_pad / (s->out_height / 6.f) : 1.f - s->out_pad; + const float ew = width; const float eh = height / 6.f; @@ -1191,7 +1207,7 @@ static void cube1x6_to_xyz(const V360Context *s, const float uf = 2.f * (i + 0.5f) / ew - 1.f; const float vf = 2.f * (j - v_shift + 0.5f) / ehi - 1.f; - cube_to_xyz(s, uf, vf, face, vec); + cube_to_xyz(s, uf, vf, face, vec, scalew, scaleh); } /** @@ -1208,6 +1224,9 @@ static void cube6x1_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec) { + const float scalew = s->fout_pad > 0 ? 1.f - s->fout_pad / (s->out_width / 6.f) : 1.f - s->out_pad; + const float scaleh = s->fout_pad > 0 ? 1.f - (float)(s->fout_pad) / s->out_height : 1.f - s->out_pad; + const float ew = width / 6.f; const float eh = height; @@ -1219,7 +1238,7 @@ static void cube6x1_to_xyz(const V360Context *s, const float uf = 2.f * (i - u_shift + 0.5f) / ewi - 1.f; const float vf = 2.f * (j + 0.5f) / eh - 1.f; - cube_to_xyz(s, uf, vf, face, vec); + cube_to_xyz(s, uf, vf, face, vec, scalew, scaleh); } /** @@ -1238,6 +1257,8 @@ static void xyz_to_cube1x6(const V360Context *s, const float *vec, int width, int height, uint16_t us[4][4], uint16_t vs[4][4], float *du, float *dv) { + const float scalew = s->fin_pad > 0 ? 1.f - (float)(s->fin_pad) / s->in_width : 1.f - s->in_pad; + const float scaleh = s->fin_pad > 0 ? 1.f - s->fin_pad / (s->in_height / 6.f) : 1.f - s->in_pad; const float eh = height / 6.f; const int ewi = width; float uf, vf; @@ -1247,8 +1268,8 @@ static void xyz_to_cube1x6(const V360Context *s, xyz_to_cube(s, vec, &uf, &vf, &direction); - uf *= (1.f - s->in_pad); - vf *= (1.f - s->in_pad); + uf *= scalew; + vf *= scaleh; face = s->in_cubemap_face_order[direction]; ehi = ceilf(eh * (face + 1)) - ceilf(eh * face); @@ -1277,13 +1298,13 @@ static void xyz_to_cube1x6(const V360Context *s, uf = 2.f * new_ui / ewi - 1.f; vf = 2.f * new_vi / ehi - 1.f; - uf /= (1.f - s->in_pad); - vf /= (1.f - s->in_pad); + uf /= scalew; + vf /= scaleh; process_cube_coordinates(s, uf, vf, direction, &uf, &vf, &face); - uf *= (1.f - s->in_pad); - vf *= (1.f - s->in_pad); + uf *= scalew; + vf *= scaleh; v_shift = ceilf(eh * face); new_ehi = ceilf(eh * (face + 1)) - v_shift; @@ -1314,6 +1335,8 @@ static void xyz_to_cube6x1(const V360Context *s, const float *vec, int width, int height, uint16_t us[4][4], uint16_t vs[4][4], float *du, float *dv) { + const float scalew = s->fin_pad > 0 ? 1.f - s->fin_pad / (s->in_width / 6.f) : 1.f - s->in_pad; + const float scaleh = s->fin_pad > 0 ? 1.f - (float)(s->fin_pad) / s->in_height : 1.f - s->in_pad; const float ew = width / 6.f; const int ehi = height; float uf, vf; @@ -1323,8 +1346,8 @@ static void xyz_to_cube6x1(const V360Context *s, xyz_to_cube(s, vec, &uf, &vf, &direction); - uf *= (1.f - s->in_pad); - vf *= (1.f - s->in_pad); + uf *= scalew; + vf *= scaleh; face = s->in_cubemap_face_order[direction]; ewi = ceilf(ew * (face + 1)) - ceilf(ew * face); @@ -1353,13 +1376,13 @@ static void xyz_to_cube6x1(const V360Context *s, uf = 2.f * new_ui / ewi - 1.f; vf = 2.f * new_vi / ehi - 1.f; - uf /= (1.f - s->in_pad); - vf /= (1.f - s->in_pad); + uf /= scalew; + vf /= scaleh; process_cube_coordinates(s, uf, vf, direction, &uf, &vf, &face); - uf *= (1.f - s->in_pad); - vf *= (1.f - s->in_pad); + uf *= scalew; + vf *= scaleh; u_shift = ceilf(ew * face); new_ewi = ceilf(ew * (face + 1)) - u_shift; @@ -1412,11 +1435,8 @@ static int prepare_stereographic_out(AVFilterContext *ctx) { V360Context *s = ctx->priv; - const float h_angle = tanf(FFMIN(s->h_fov, 359.f) * M_PI / 720.f); - const float v_angle = tanf(FFMIN(s->v_fov, 359.f) * M_PI / 720.f); - - s->flat_range[0] = h_angle; - s->flat_range[1] = v_angle; + s->flat_range[0] = tanf(FFMIN(s->h_fov, 359.f) * M_PI / 720.f); + s->flat_range[1] = tanf(FFMIN(s->v_fov, 359.f) * M_PI / 720.f); return 0; } @@ -1537,12 +1557,12 @@ static void xyz_to_mercator(const V360Context *s, uint16_t us[4][4], uint16_t vs[4][4], float *du, float *dv) { const float phi = atan2f(vec[0], -vec[2]) * s->input_mirror_modifier[0]; - const float theta = 0.5f * asinhf(vec[1] / sqrtf(1.f - vec[1] * vec[1])) * s->input_mirror_modifier[1]; + const float theta = -vec[1] * s->input_mirror_modifier[1]; float uf, vf; int ui, vi; - uf = (phi / M_PI + 1.f) * width / 2.f; - vf = (theta / M_PI + 1.f) * height / 2.f; + uf = (phi / M_PI + 1.f) * width / 2.f; + vf = (av_clipf(logf((1.f + theta) / (1.f - theta)) / (2.f * M_PI), -1.f, 1.f) + 1.f) * height / 2.f; ui = floorf(uf); vi = floorf(vf); @@ -1551,7 +1571,7 @@ static void xyz_to_mercator(const V360Context *s, for (int i = -1; i < 3; i++) { for (int j = -1; j < 3; j++) { - us[i + 1][j + 1] = mod(ui + j, width); + us[i + 1][j + 1] = av_clip(ui + j, 0, width - 1); vs[i + 1][j + 1] = av_clip(vi + i, 0, height - 1); } } @@ -1571,17 +1591,18 @@ static void mercator_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec) { - const float phi = ((2.f * i) / width - 1.f) * M_PI; - const float theta = atanf(sinhf(((2.f * j) / height - 1.f) * 2.f * M_PI)); + const float phi = ((2.f * i) / width - 1.f) * M_PI + M_PI_2; + const float y = ((2.f * j) / height - 1.f) * M_PI; + const float div = expf(2.f * y) + 1.f; const float sin_phi = sinf(phi); const float cos_phi = cosf(phi); - const float sin_theta = sinf(theta); - const float cos_theta = cosf(theta); + const float sin_theta = -2.f * expf(y) / div; + const float cos_theta = -(expf(2.f * y) - 1.f) / div; - vec[0] = cos_theta * sin_phi; - vec[1] = -sin_theta; - vec[2] = -cos_theta * cos_phi; + vec[0] = sin_theta * cos_phi; + vec[1] = cos_theta; + vec[2] = sin_theta * sin_phi; } /** @@ -1601,12 +1622,13 @@ static void xyz_to_ball(const V360Context *s, uint16_t us[4][4], uint16_t vs[4][4], float *du, float *dv) { const float l = hypotf(vec[0], vec[1]); - const float r = sinf(acosf(-vec[2]) * 0.5f); + const float r = sqrtf(1.f + vec[2]) / M_SQRT2; float uf, vf; int ui, vi; - uf = (1.f - r * vec[0] / l) * width / 2.f; - vf = (1.f + r * vec[1] / l) * height / 2.f; + uf = (1.f + r * vec[0] * s->input_mirror_modifier[0] / (l > 0.f ? l : 1.f)) * width * 0.5f; + vf = (1.f - r * vec[1] * s->input_mirror_modifier[1] / (l > 0.f ? l : 1.f)) * height * 0.5f; + ui = floorf(uf); vi = floorf(vf); @@ -1615,7 +1637,7 @@ static void xyz_to_ball(const V360Context *s, for (int i = -1; i < 3; i++) { for (int j = -1; j < 3; j++) { - us[i + 1][j + 1] = mod(ui + j, width); + us[i + 1][j + 1] = av_clip(ui + j, 0, width - 1); vs[i + 1][j + 1] = av_clip(vi + i, 0, height - 1); } } @@ -1640,17 +1662,11 @@ static void ball_to_xyz(const V360Context *s, const float l = hypotf(x, y); if (l <= 1.f) { - const float phi = atan2f(x, y); - const float theta = 2.f * asinf(l); - - const float sin_phi = sinf(phi); - const float cos_phi = cosf(phi); - const float sin_theta = sinf(theta); - const float cos_theta = cosf(theta); + const float z = 2.f * l * sqrtf(1.f - l * l); - vec[0] = sin_theta * sin_phi; - vec[1] = -sin_theta * cos_phi; - vec[2] = -cos_theta; + vec[0] = z * x / (l > 0.f ? l : 1.f); + vec[1] = -z * y / (l > 0.f ? l : 1.f); + vec[2] = -1.f + 2.f * l * l; } else { vec[0] = 0.f; vec[1] = -1.f; @@ -1658,6 +1674,149 @@ static void ball_to_xyz(const V360Context *s, } } +/** + * Calculate 3D coordinates on sphere for corresponding frame position in hammer format. + * + * @param s filter private context + * @param i horizontal position on frame [0, width) + * @param j vertical position on frame [0, height) + * @param width frame width + * @param height frame height + * @param vec coordinates on sphere + */ +static void hammer_to_xyz(const V360Context *s, + int i, int j, int width, int height, + float *vec) +{ + const float x = ((2.f * i) / width - 1.f); + const float y = ((2.f * j) / height - 1.f); + + const float xx = x * x; + const float yy = y * y; + + const float z = sqrtf(1.f - xx * 0.5f - yy * 0.5f); + + const float a = M_SQRT2 * x * z; + const float b = 2.f * z * z - 1.f; + + const float aa = a * a; + const float bb = b * b; + + const float w = sqrtf(1.f - 2.f * yy * z * z); + + vec[0] = w * 2.f * a * b / (aa + bb); + vec[1] = -M_SQRT2 * y * z; + vec[2] = -w * (bb - aa) / (aa + bb); + + normalize_vector(vec); +} + +/** + * Calculate frame position in hammer format for corresponding 3D coordinates on sphere. + * + * @param s filter private context + * @param vec coordinates on sphere + * @param width frame width + * @param height frame height + * @param us horizontal coordinates for interpolation window + * @param vs vertical coordinates for interpolation window + * @param du horizontal relative coordinate + * @param dv vertical relative coordinate + */ +static void xyz_to_hammer(const V360Context *s, + const float *vec, int width, int height, + uint16_t us[4][4], uint16_t vs[4][4], float *du, float *dv) +{ + const float theta = atan2f(vec[0], -vec[2]) * s->input_mirror_modifier[0]; + + const float z = sqrtf(1.f + sqrtf(1.f - vec[1] * vec[1]) * cosf(theta * 0.5f)); + const float x = sqrtf(1.f - vec[1] * vec[1]) * sinf(theta * 0.5f) / z; + const float y = -vec[1] / z * s->input_mirror_modifier[1]; + float uf, vf; + int ui, vi; + + uf = (x + 1.f) * width / 2.f; + vf = (y + 1.f) * height / 2.f; + ui = floorf(uf); + vi = floorf(vf); + + *du = uf - ui; + *dv = vf - vi; + + for (int i = -1; i < 3; i++) { + for (int j = -1; j < 3; j++) { + us[i + 1][j + 1] = av_clip(ui + j, 0, width - 1); + vs[i + 1][j + 1] = av_clip(vi + i, 0, height - 1); + } + } +} + +/** + * Calculate 3D coordinates on sphere for corresponding frame position in sinusoidal format. + * + * @param s filter private context + * @param i horizontal position on frame [0, width) + * @param j vertical position on frame [0, height) + * @param width frame width + * @param height frame height + * @param vec coordinates on sphere + */ +static void sinusoidal_to_xyz(const V360Context *s, + int i, int j, int width, int height, + float *vec) +{ + const float theta = ((2.f * j) / height - 1.f) * M_PI_2; + const float phi = ((2.f * i) / width - 1.f) * M_PI / cosf(theta); + + const float sin_phi = sinf(phi); + const float cos_phi = cosf(phi); + const float sin_theta = sinf(theta); + const float cos_theta = cosf(theta); + + vec[0] = cos_theta * sin_phi; + vec[1] = -sin_theta; + vec[2] = -cos_theta * cos_phi; + + normalize_vector(vec); +} + +/** + * Calculate frame position in sinusoidal format for corresponding 3D coordinates on sphere. + * + * @param s filter private context + * @param vec coordinates on sphere + * @param width frame width + * @param height frame height + * @param us horizontal coordinates for interpolation window + * @param vs vertical coordinates for interpolation window + * @param du horizontal relative coordinate + * @param dv vertical relative coordinate + */ +static void xyz_to_sinusoidal(const V360Context *s, + const float *vec, int width, int height, + uint16_t us[4][4], uint16_t vs[4][4], float *du, float *dv) +{ + const float theta = asinf(-vec[1]) * s->input_mirror_modifier[1]; + const float phi = atan2f(vec[0], -vec[2]) * s->input_mirror_modifier[0] * cosf(theta); + float uf, vf; + int ui, vi; + + uf = (phi / M_PI + 1.f) * width / 2.f; + vf = (theta / M_PI_2 + 1.f) * height / 2.f; + ui = floorf(uf); + vi = floorf(vf); + + *du = uf - ui; + *dv = vf - vi; + + for (int i = -1; i < 3; i++) { + for (int j = -1; j < 3; j++) { + us[i + 1][j + 1] = av_clip(ui + j, 0, width - 1); + vs[i + 1][j + 1] = av_clip(vi + i, 0, height - 1); + } + } +} + /** * Prepare data for processing equi-angular cubemap input format. * @@ -1768,8 +1927,8 @@ static void eac_to_xyz(const V360Context *s, float l_x, l_y, l_z; - float uf = (float)i / width; - float vf = (float)j / height; + float uf = (i + 0.5f) / width; + float vf = (j + 0.5f) / height; // EAC has 2-pixel padding on faces except between faces on the same row // Padding pixels seems not to be stretched with tangent as regular pixels @@ -1888,6 +2047,9 @@ static void xyz_to_eac(const V360Context *s, uf *= width; vf *= height; + uf -= 0.5f; + vf -= 0.5f; + ui = floorf(uf); vi = floorf(vf); @@ -1913,12 +2075,8 @@ static int prepare_flat_out(AVFilterContext *ctx) { V360Context *s = ctx->priv; - const float h_angle = 0.5f * s->h_fov * M_PI / 180.f; - const float v_angle = 0.5f * s->v_fov * M_PI / 180.f; - - s->flat_range[0] = tanf(h_angle); - s->flat_range[1] = tanf(v_angle); - s->flat_range[2] = -1.f; + s->flat_range[0] = tanf(0.5f * s->h_fov * M_PI / 180.f); + s->flat_range[1] = tanf(0.5f * s->v_fov * M_PI / 180.f); return 0; } @@ -1939,11 +2097,10 @@ static void flat_to_xyz(const V360Context *s, { const float l_x = s->flat_range[0] * (2.f * i / width - 1.f); const float l_y = -s->flat_range[1] * (2.f * j / height - 1.f); - const float l_z = s->flat_range[2]; - vec[0] = l_x; - vec[1] = l_y; - vec[2] = l_z; + vec[0] = l_x; + vec[1] = l_y; + vec[2] = -1.f; normalize_vector(vec); } @@ -1973,16 +2130,15 @@ static void dfisheye_to_xyz(const V360Context *s, const float uf = ((2.f * ei) / ew - 1.f) * scale; const float vf = ((2.f * j) / eh - 1.f) * scale; - const float phi = M_PI + atan2f(vf, uf * m); - const float theta = m * M_PI_2 * (1.f - hypotf(uf, vf)); + const float h = hypotf(uf, vf); + const float lh = h > 0.f ? h : 1.f; + const float theta = m * M_PI_2 * (1.f - h); - const float sin_phi = sinf(phi); - const float cos_phi = cosf(phi); const float sin_theta = sinf(theta); const float cos_theta = cosf(theta); - vec[0] = cos_theta * cos_phi; - vec[1] = cos_theta * sin_phi; + vec[0] = cos_theta * m * -uf / lh; + vec[1] = cos_theta * -vf / lh; vec[2] = sin_theta; normalize_vector(vec); @@ -2009,16 +2165,17 @@ static void xyz_to_dfisheye(const V360Context *s, const float ew = width / 2.f; const float eh = height; - const float phi = atan2f(-vec[1], -vec[0]) * s->input_mirror_modifier[0]; - const float theta = acosf(fabsf(vec[2])) / M_PI * s->input_mirror_modifier[1]; + const float h = hypotf(vec[0], vec[1]); + const float lh = h > 0.f ? h : 1.f; + const float theta = acosf(fabsf(vec[2])) / M_PI; - float uf = (theta * cosf(phi) * scale + 0.5f) * ew; - float vf = (theta * sinf(phi) * scale + 0.5f) * eh; + float uf = (theta * (-vec[0] / lh) * s->input_mirror_modifier[0] * scale + 0.5f) * ew; + float vf = (theta * (-vec[1] / lh) * s->input_mirror_modifier[1] * scale + 0.5f) * eh; int ui, vi; int u_shift; - if (vec[2] >= 0) { + if (vec[2] >= 0.f) { u_shift = 0; } else { u_shift = ceilf(ew); @@ -2447,6 +2604,12 @@ static int config_output(AVFilterLink *outlink) set_dimensions(s->inplanewidth, s->inplaneheight, w, h, desc); set_dimensions(s->in_offset_w, s->in_offset_h, in_offset_w, in_offset_h, desc); + s->in_width = s->inplanewidth[0]; + s->in_height = s->inplaneheight[0]; + + if (s->in_transpose) + FFSWAP(int, s->in_width, s->in_height); + switch (s->in) { case EQUIRECTANGULAR: s->in_transform = xyz_to_equirect; @@ -2503,7 +2666,7 @@ static int config_output(AVFilterLink *outlink) s->in_transform = xyz_to_mercator; err = 0; wf = w; - hf = h; + hf = h / 2.f; break; case BALL: s->in_transform = xyz_to_ball; @@ -2511,6 +2674,18 @@ static int config_output(AVFilterLink *outlink) wf = w; hf = h / 2.f; break; + case HAMMER: + s->in_transform = xyz_to_hammer; + err = 0; + wf = w; + hf = h; + break; + case SINUSOIDAL: + s->in_transform = xyz_to_sinusoidal; + err = 0; + wf = w; + hf = h; + break; default: av_log(ctx, AV_LOG_ERROR, "Specified input format is not handled.\n"); return AVERROR_BUG; @@ -2579,7 +2754,7 @@ static int config_output(AVFilterLink *outlink) s->out_transform = mercator_to_xyz; prepare_out = NULL; w = roundf(wf); - h = roundf(hf); + h = roundf(hf * 2.f); break; case BALL: s->out_transform = ball_to_xyz; @@ -2587,6 +2762,18 @@ static int config_output(AVFilterLink *outlink) w = roundf(wf); h = roundf(hf * 2.f); break; + case HAMMER: + s->out_transform = hammer_to_xyz; + prepare_out = NULL; + w = roundf(wf); + h = roundf(hf); + break; + case SINUSOIDAL: + s->out_transform = sinusoidal_to_xyz; + prepare_out = NULL; + w = roundf(wf); + h = roundf(hf); + break; default: av_log(ctx, AV_LOG_ERROR, "Specified output format is not handled.\n"); return AVERROR_BUG; @@ -2618,6 +2805,12 @@ static int config_output(AVFilterLink *outlink) set_dimensions(s->pr_width, s->pr_height, w, h, desc); + s->out_width = s->pr_width[0]; + s->out_height = s->pr_height[0]; + + if (s->out_transpose) + FFSWAP(int, s->out_width, s->out_height); + switch (s->out_stereo) { case STEREO_2D: out_offset_w = out_offset_h = 0;