diff --git a/doc/filters.texi b/doc/filters.texi index f3bbbe0f32..b2a955113c 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -18006,7 +18006,10 @@ Format specific options: @table @option @item h_fov @item v_fov -Set horizontal/vertical field of view. Values in degrees. +@item d_fov +Set horizontal/vertical/diagonal field of view. Values in degrees. + +If diagonal field of view is set it overrides horizontal and vertical field of view. @end table @item dfisheye @@ -18040,7 +18043,10 @@ Format specific options: @table @option @item h_fov @item v_fov -Set horizontal/vertical field of view. Values in degrees. +@item d_fov +Set horizontal/vertical/diagonal field of view. Values in degrees. + +If diagonal field of view is set it overrides horizontal and vertical field of view. @end table @end table diff --git a/libavfilter/v360.h b/libavfilter/v360.h index 85d87e7755..11c1e27e4b 100644 --- a/libavfilter/v360.h +++ b/libavfilter/v360.h @@ -103,7 +103,7 @@ typedef struct V360Context { int h_flip, v_flip, d_flip; int in_transpose, out_transpose; - float h_fov, v_fov; + float h_fov, v_fov, d_fov; float flat_range[3]; float input_mirror_modifier[2]; diff --git a/libavfilter/vf_v360.c b/libavfilter/vf_v360.c index 7cd6aa9f6d..98cef5902e 100644 --- a/libavfilter/vf_v360.c +++ b/libavfilter/vf_v360.c @@ -102,6 +102,7 @@ static const AVOption v360_options[] = { { "rorder", "rotation order", OFFSET(rorder), AV_OPT_TYPE_STRING, {.str="ypr"}, 0, 0, FLAGS, "rorder"}, { "h_fov", "horizontal field of view", OFFSET(h_fov), AV_OPT_TYPE_FLOAT, {.dbl=90.f}, 0.00001f, 360.f, FLAGS, "h_fov"}, { "v_fov", "vertical field of view", OFFSET(v_fov), AV_OPT_TYPE_FLOAT, {.dbl=45.f}, 0.00001f, 360.f, FLAGS, "v_fov"}, + { "d_fov", "diagonal field of view", OFFSET(d_fov), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 360.f, FLAGS, "d_fov"}, { "h_flip", "flip out video horizontally", OFFSET(h_flip), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS, "h_flip"}, { "v_flip", "flip out video vertically", OFFSET(v_flip), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS, "v_flip"}, { "d_flip", "flip out video indepth", OFFSET(d_flip), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS, "d_flip"}, @@ -2139,6 +2140,20 @@ static int allocate_plane(V360Context *s, int sizeof_uv, int sizeof_ker, int p) return 0; } +static void fov_from_dfov(V360Context *s, float w, float h) +{ + const float d_angle = 0.5 * FFMIN(s->d_fov, 359.f) * M_PI / 180.f; + const float d = hypotf(w, h); + + s->h_fov = atan2f(tanf(d_angle) * w, d) * 360.f / M_PI; + s->v_fov = atan2f(tanf(d_angle) * h, d) * 360.f / M_PI; + + if (s->h_fov < 0.f) + s->h_fov += 360.f; + if (s->v_fov < 0.f) + s->v_fov += 360.f; +} + static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; @@ -2161,6 +2176,7 @@ static int config_output(AVFilterLink *outlink) float *vec); void (*calculate_kernel)(float du, float dv, const XYRemap *r_tmp, uint16_t *u, uint16_t *v, int16_t *ker); + int (*prepare_out)(AVFilterContext *ctx); float rot_mat[3][3]; s->input_mirror_modifier[0] = s->ih_flip ? -1.f : 1.f; @@ -2285,55 +2301,55 @@ static int config_output(AVFilterLink *outlink) switch (s->out) { case EQUIRECTANGULAR: out_transform = equirect_to_xyz; - err = 0; + prepare_out = NULL; w = roundf(wf); h = roundf(hf); break; case CUBEMAP_3_2: out_transform = cube3x2_to_xyz; - err = prepare_cube_out(ctx); + prepare_out = prepare_cube_out; w = roundf(wf / 4.f * 3.f); h = roundf(hf); break; case CUBEMAP_1_6: out_transform = cube1x6_to_xyz; - err = prepare_cube_out(ctx); + prepare_out = prepare_cube_out; w = roundf(wf / 4.f); h = roundf(hf * 3.f); break; case CUBEMAP_6_1: out_transform = cube6x1_to_xyz; - err = prepare_cube_out(ctx); + prepare_out = prepare_cube_out; w = roundf(wf / 2.f * 3.f); h = roundf(hf / 2.f); break; case EQUIANGULAR: out_transform = eac_to_xyz; - err = prepare_eac_out(ctx); + prepare_out = prepare_eac_out; w = roundf(wf); h = roundf(hf / 8.f * 9.f); break; case FLAT: out_transform = flat_to_xyz; - err = prepare_flat_out(ctx); + prepare_out = prepare_flat_out; w = roundf(wf); h = roundf(hf); break; case DUAL_FISHEYE: out_transform = dfisheye_to_xyz; - err = 0; + prepare_out = NULL; w = roundf(wf); h = roundf(hf); break; case BARREL: out_transform = barrel_to_xyz; - err = 0; + prepare_out = NULL; w = roundf(wf / 4.f * 5.f); h = roundf(hf); break; case STEREOGRAPHIC: out_transform = stereographic_to_xyz; - err = prepare_stereographic_out(ctx); + prepare_out = prepare_stereographic_out; w = roundf(wf); h = roundf(hf * 2.f); break; @@ -2342,10 +2358,6 @@ static int config_output(AVFilterLink *outlink) return AVERROR_BUG; } - if (err != 0) { - return err; - } - // Override resolution with user values if specified if (s->width > 0 && s->height > 0) { w = s->width; @@ -2361,6 +2373,15 @@ static int config_output(AVFilterLink *outlink) FFSWAP(int, w, h); } + if (s->d_fov > 0.f) + fov_from_dfov(s, w, h); + + if (prepare_out) { + err = prepare_out(ctx); + if (err != 0) + return err; + } + s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(h, desc->log2_chroma_h); s->planeheight[0] = s->planeheight[3] = h; s->planewidth[1] = s->planewidth[2] = FF_CEIL_RSHIFT(w, desc->log2_chroma_w);