FFmpeg
vf_v360.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Eugene Lyapustin
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * 360 video conversion filter.
24  * Principle of operation:
25  *
26  * (for each pixel in output frame)
27  * 1) Calculate OpenGL-like coordinates (x, y, z) for pixel position (i, j)
28  * 2) Apply 360 operations (rotation, mirror) to (x, y, z)
29  * 3) Calculate pixel position (u, v) in input frame
30  * 4) Calculate interpolation window and weight for each pixel
31  *
32  * (for each frame)
33  * 5) Remap input frame to output frame using precalculated data
34  */
35 
36 #include <math.h>
37 
38 #include "libavutil/avassert.h"
39 #include "libavutil/mem.h"
40 #include "libavutil/pixdesc.h"
41 #include "libavutil/opt.h"
42 #include "avfilter.h"
43 #include "filters.h"
44 #include "formats.h"
45 #include "video.h"
46 #include "v360.h"
47 
48 typedef struct ThreadData {
49  AVFrame *in;
50  AVFrame *out;
51 } ThreadData;
52 
53 #define OFFSET(x) offsetof(V360Context, x)
54 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
55 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
56 
57 static const AVOption v360_options[] = {
58  { "input", "set input projection", OFFSET(in), AV_OPT_TYPE_INT, {.i64=EQUIRECTANGULAR}, 0, NB_PROJECTIONS-1, FLAGS, .unit = "in" },
59  { "e", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, .unit = "in" },
60  { "equirect", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, .unit = "in" },
61  { "c3x2", "cubemap 3x2", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_3_2}, 0, 0, FLAGS, .unit = "in" },
62  { "c6x1", "cubemap 6x1", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_6_1}, 0, 0, FLAGS, .unit = "in" },
63  { "eac", "equi-angular cubemap", 0, AV_OPT_TYPE_CONST, {.i64=EQUIANGULAR}, 0, 0, FLAGS, .unit = "in" },
64  { "dfisheye", "dual fisheye", 0, AV_OPT_TYPE_CONST, {.i64=DUAL_FISHEYE}, 0, 0, FLAGS, .unit = "in" },
65  { "flat", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, .unit = "in" },
66  {"rectilinear", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, .unit = "in" },
67  { "gnomonic", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, .unit = "in" },
68  { "barrel", "barrel facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL}, 0, 0, FLAGS, .unit = "in" },
69  { "fb", "barrel facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL}, 0, 0, FLAGS, .unit = "in" },
70  { "c1x6", "cubemap 1x6", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_1_6}, 0, 0, FLAGS, .unit = "in" },
71  { "sg", "stereographic", 0, AV_OPT_TYPE_CONST, {.i64=STEREOGRAPHIC}, 0, 0, FLAGS, .unit = "in" },
72  { "mercator", "mercator", 0, AV_OPT_TYPE_CONST, {.i64=MERCATOR}, 0, 0, FLAGS, .unit = "in" },
73  { "ball", "ball", 0, AV_OPT_TYPE_CONST, {.i64=BALL}, 0, 0, FLAGS, .unit = "in" },
74  { "hammer", "hammer", 0, AV_OPT_TYPE_CONST, {.i64=HAMMER}, 0, 0, FLAGS, .unit = "in" },
75  {"sinusoidal", "sinusoidal", 0, AV_OPT_TYPE_CONST, {.i64=SINUSOIDAL}, 0, 0, FLAGS, .unit = "in" },
76  { "fisheye", "fisheye", 0, AV_OPT_TYPE_CONST, {.i64=FISHEYE}, 0, 0, FLAGS, .unit = "in" },
77  { "pannini", "pannini", 0, AV_OPT_TYPE_CONST, {.i64=PANNINI}, 0, 0, FLAGS, .unit = "in" },
78  {"cylindrical", "cylindrical", 0, AV_OPT_TYPE_CONST, {.i64=CYLINDRICAL}, 0, 0, FLAGS, .unit = "in" },
79  {"tetrahedron", "tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=TETRAHEDRON}, 0, 0, FLAGS, .unit = "in" },
80  {"barrelsplit", "barrel split facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL_SPLIT}, 0, 0, FLAGS, .unit = "in" },
81  { "tsp", "truncated square pyramid", 0, AV_OPT_TYPE_CONST, {.i64=TSPYRAMID}, 0, 0, FLAGS, .unit = "in" },
82  { "hequirect", "half equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=HEQUIRECTANGULAR},0, 0, FLAGS, .unit = "in" },
83  { "he", "half equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=HEQUIRECTANGULAR},0, 0, FLAGS, .unit = "in" },
84  { "equisolid", "equisolid", 0, AV_OPT_TYPE_CONST, {.i64=EQUISOLID}, 0, 0, FLAGS, .unit = "in" },
85  { "og", "orthographic", 0, AV_OPT_TYPE_CONST, {.i64=ORTHOGRAPHIC}, 0, 0, FLAGS, .unit = "in" },
86  {"octahedron", "octahedron", 0, AV_OPT_TYPE_CONST, {.i64=OCTAHEDRON}, 0, 0, FLAGS, .unit = "in" },
87  {"cylindricalea", "cylindrical equal area", 0, AV_OPT_TYPE_CONST, {.i64=CYLINDRICALEA}, 0, 0, FLAGS, .unit = "in" },
88  { "output", "set output projection", OFFSET(out), AV_OPT_TYPE_INT, {.i64=CUBEMAP_3_2}, 0, NB_PROJECTIONS-1, FLAGS, .unit = "out" },
89  { "e", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, .unit = "out" },
90  { "equirect", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, .unit = "out" },
91  { "c3x2", "cubemap 3x2", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_3_2}, 0, 0, FLAGS, .unit = "out" },
92  { "c6x1", "cubemap 6x1", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_6_1}, 0, 0, FLAGS, .unit = "out" },
93  { "eac", "equi-angular cubemap", 0, AV_OPT_TYPE_CONST, {.i64=EQUIANGULAR}, 0, 0, FLAGS, .unit = "out" },
94  { "dfisheye", "dual fisheye", 0, AV_OPT_TYPE_CONST, {.i64=DUAL_FISHEYE}, 0, 0, FLAGS, .unit = "out" },
95  { "flat", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, .unit = "out" },
96  {"rectilinear", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, .unit = "out" },
97  { "gnomonic", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, .unit = "out" },
98  { "barrel", "barrel facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL}, 0, 0, FLAGS, .unit = "out" },
99  { "fb", "barrel facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL}, 0, 0, FLAGS, .unit = "out" },
100  { "c1x6", "cubemap 1x6", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_1_6}, 0, 0, FLAGS, .unit = "out" },
101  { "sg", "stereographic", 0, AV_OPT_TYPE_CONST, {.i64=STEREOGRAPHIC}, 0, 0, FLAGS, .unit = "out" },
102  { "mercator", "mercator", 0, AV_OPT_TYPE_CONST, {.i64=MERCATOR}, 0, 0, FLAGS, .unit = "out" },
103  { "ball", "ball", 0, AV_OPT_TYPE_CONST, {.i64=BALL}, 0, 0, FLAGS, .unit = "out" },
104  { "hammer", "hammer", 0, AV_OPT_TYPE_CONST, {.i64=HAMMER}, 0, 0, FLAGS, .unit = "out" },
105  {"sinusoidal", "sinusoidal", 0, AV_OPT_TYPE_CONST, {.i64=SINUSOIDAL}, 0, 0, FLAGS, .unit = "out" },
106  { "fisheye", "fisheye", 0, AV_OPT_TYPE_CONST, {.i64=FISHEYE}, 0, 0, FLAGS, .unit = "out" },
107  { "pannini", "pannini", 0, AV_OPT_TYPE_CONST, {.i64=PANNINI}, 0, 0, FLAGS, .unit = "out" },
108  {"cylindrical", "cylindrical", 0, AV_OPT_TYPE_CONST, {.i64=CYLINDRICAL}, 0, 0, FLAGS, .unit = "out" },
109  {"perspective", "perspective", 0, AV_OPT_TYPE_CONST, {.i64=PERSPECTIVE}, 0, 0, FLAGS, .unit = "out" },
110  {"tetrahedron", "tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=TETRAHEDRON}, 0, 0, FLAGS, .unit = "out" },
111  {"barrelsplit", "barrel split facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL_SPLIT}, 0, 0, FLAGS, .unit = "out" },
112  { "tsp", "truncated square pyramid", 0, AV_OPT_TYPE_CONST, {.i64=TSPYRAMID}, 0, 0, FLAGS, .unit = "out" },
113  { "hequirect", "half equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=HEQUIRECTANGULAR},0, 0, FLAGS, .unit = "out" },
114  { "he", "half equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=HEQUIRECTANGULAR},0, 0, FLAGS, .unit = "out" },
115  { "equisolid", "equisolid", 0, AV_OPT_TYPE_CONST, {.i64=EQUISOLID}, 0, 0, FLAGS, .unit = "out" },
116  { "og", "orthographic", 0, AV_OPT_TYPE_CONST, {.i64=ORTHOGRAPHIC}, 0, 0, FLAGS, .unit = "out" },
117  {"octahedron", "octahedron", 0, AV_OPT_TYPE_CONST, {.i64=OCTAHEDRON}, 0, 0, FLAGS, .unit = "out" },
118  {"cylindricalea", "cylindrical equal area", 0, AV_OPT_TYPE_CONST, {.i64=CYLINDRICALEA}, 0, 0, FLAGS, .unit = "out" },
119  { "interp", "set interpolation method", OFFSET(interp), AV_OPT_TYPE_INT, {.i64=BILINEAR}, 0, NB_INTERP_METHODS-1, FLAGS, .unit = "interp" },
120  { "near", "nearest neighbour", 0, AV_OPT_TYPE_CONST, {.i64=NEAREST}, 0, 0, FLAGS, .unit = "interp" },
121  { "nearest", "nearest neighbour", 0, AV_OPT_TYPE_CONST, {.i64=NEAREST}, 0, 0, FLAGS, .unit = "interp" },
122  { "line", "bilinear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=BILINEAR}, 0, 0, FLAGS, .unit = "interp" },
123  { "linear", "bilinear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=BILINEAR}, 0, 0, FLAGS, .unit = "interp" },
124  { "lagrange9", "lagrange9 interpolation", 0, AV_OPT_TYPE_CONST, {.i64=LAGRANGE9}, 0, 0, FLAGS, .unit = "interp" },
125  { "cube", "bicubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=BICUBIC}, 0, 0, FLAGS, .unit = "interp" },
126  { "cubic", "bicubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=BICUBIC}, 0, 0, FLAGS, .unit = "interp" },
127  { "lanc", "lanczos interpolation", 0, AV_OPT_TYPE_CONST, {.i64=LANCZOS}, 0, 0, FLAGS, .unit = "interp" },
128  { "lanczos", "lanczos interpolation", 0, AV_OPT_TYPE_CONST, {.i64=LANCZOS}, 0, 0, FLAGS, .unit = "interp" },
129  { "sp16", "spline16 interpolation", 0, AV_OPT_TYPE_CONST, {.i64=SPLINE16}, 0, 0, FLAGS, .unit = "interp" },
130  { "spline16", "spline16 interpolation", 0, AV_OPT_TYPE_CONST, {.i64=SPLINE16}, 0, 0, FLAGS, .unit = "interp" },
131  { "gauss", "gaussian interpolation", 0, AV_OPT_TYPE_CONST, {.i64=GAUSSIAN}, 0, 0, FLAGS, .unit = "interp" },
132  { "gaussian", "gaussian interpolation", 0, AV_OPT_TYPE_CONST, {.i64=GAUSSIAN}, 0, 0, FLAGS, .unit = "interp" },
133  { "mitchell", "mitchell interpolation", 0, AV_OPT_TYPE_CONST, {.i64=MITCHELL}, 0, 0, FLAGS, .unit = "interp" },
134  { "w", "output width", OFFSET(width), AV_OPT_TYPE_INT, {.i64=0}, 0, INT16_MAX, FLAGS, .unit = "w"},
135  { "h", "output height", OFFSET(height), AV_OPT_TYPE_INT, {.i64=0}, 0, INT16_MAX, FLAGS, .unit = "h"},
136  { "in_stereo", "input stereo format", OFFSET(in_stereo), AV_OPT_TYPE_INT, {.i64=STEREO_2D}, 0, NB_STEREO_FMTS-1, FLAGS, .unit = "stereo" },
137  {"out_stereo", "output stereo format", OFFSET(out_stereo), AV_OPT_TYPE_INT, {.i64=STEREO_2D}, 0, NB_STEREO_FMTS-1, FLAGS, .unit = "stereo" },
138  { "2d", "2d mono", 0, AV_OPT_TYPE_CONST, {.i64=STEREO_2D}, 0, 0, FLAGS, .unit = "stereo" },
139  { "sbs", "side by side", 0, AV_OPT_TYPE_CONST, {.i64=STEREO_SBS}, 0, 0, FLAGS, .unit = "stereo" },
140  { "tb", "top bottom", 0, AV_OPT_TYPE_CONST, {.i64=STEREO_TB}, 0, 0, FLAGS, .unit = "stereo" },
141  { "in_forder", "input cubemap face order", OFFSET(in_forder), AV_OPT_TYPE_STRING, {.str="rludfb"}, 0, NB_DIRECTIONS-1, FLAGS, .unit = "in_forder"},
142  {"out_forder", "output cubemap face order", OFFSET(out_forder), AV_OPT_TYPE_STRING, {.str="rludfb"}, 0, NB_DIRECTIONS-1, FLAGS, .unit = "out_forder"},
143  { "in_frot", "input cubemap face rotation", OFFSET(in_frot), AV_OPT_TYPE_STRING, {.str="000000"}, 0, NB_DIRECTIONS-1, FLAGS, .unit = "in_frot"},
144  { "out_frot", "output cubemap face rotation",OFFSET(out_frot), AV_OPT_TYPE_STRING, {.str="000000"}, 0, NB_DIRECTIONS-1, FLAGS, .unit = "out_frot"},
145  { "in_pad", "percent input cubemap pads", OFFSET(in_pad), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 0.1,TFLAGS, .unit = "in_pad"},
146  { "out_pad", "percent output cubemap pads", OFFSET(out_pad), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 0.1,TFLAGS, .unit = "out_pad"},
147  { "fin_pad", "fixed input cubemap pads", OFFSET(fin_pad), AV_OPT_TYPE_INT, {.i64=0}, 0, 100,TFLAGS, .unit = "fin_pad"},
148  { "fout_pad", "fixed output cubemap pads", OFFSET(fout_pad), AV_OPT_TYPE_INT, {.i64=0}, 0, 100,TFLAGS, .unit = "fout_pad"},
149  { "yaw", "yaw rotation", OFFSET(yaw), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, -180.f, 180.f,TFLAGS, .unit = "yaw"},
150  { "pitch", "pitch rotation", OFFSET(pitch), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, -180.f, 180.f,TFLAGS, .unit = "pitch"},
151  { "roll", "roll rotation", OFFSET(roll), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, -180.f, 180.f,TFLAGS, .unit = "roll"},
152  { "rorder", "rotation order", OFFSET(rorder), AV_OPT_TYPE_STRING, {.str="ypr"}, 0, 0,TFLAGS, .unit = "rorder"},
153  { "h_fov", "output horizontal field of view",OFFSET(h_fov), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 360.f,TFLAGS, .unit = "h_fov"},
154  { "v_fov", "output vertical field of view", OFFSET(v_fov), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 360.f,TFLAGS, .unit = "v_fov"},
155  { "d_fov", "output diagonal field of view", OFFSET(d_fov), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 360.f,TFLAGS, .unit = "d_fov"},
156  { "h_flip", "flip out video horizontally", OFFSET(h_flip), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1,TFLAGS, .unit = "h_flip"},
157  { "v_flip", "flip out video vertically", OFFSET(v_flip), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1,TFLAGS, .unit = "v_flip"},
158  { "d_flip", "flip out video indepth", OFFSET(d_flip), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1,TFLAGS, .unit = "d_flip"},
159  { "ih_flip", "flip in video horizontally", OFFSET(ih_flip), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1,TFLAGS, .unit = "ih_flip"},
160  { "iv_flip", "flip in video vertically", OFFSET(iv_flip), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1,TFLAGS, .unit = "iv_flip"},
161  { "in_trans", "transpose video input", OFFSET(in_transpose), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS, .unit = "in_transpose"},
162  { "out_trans", "transpose video output", OFFSET(out_transpose), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS, .unit = "out_transpose"},
163  { "ih_fov", "input horizontal field of view",OFFSET(ih_fov), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 360.f,TFLAGS, .unit = "ih_fov"},
164  { "iv_fov", "input vertical field of view", OFFSET(iv_fov), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 360.f,TFLAGS, .unit = "iv_fov"},
165  { "id_fov", "input diagonal field of view", OFFSET(id_fov), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 360.f,TFLAGS, .unit = "id_fov"},
166  { "h_offset", "output horizontal off-axis offset",OFFSET(h_offset), AV_OPT_TYPE_FLOAT,{.dbl=0.f}, -1.f, 1.f,TFLAGS, .unit = "h_offset"},
167  { "v_offset", "output vertical off-axis offset", OFFSET(v_offset), AV_OPT_TYPE_FLOAT,{.dbl=0.f}, -1.f, 1.f,TFLAGS, .unit = "v_offset"},
168  {"alpha_mask", "build mask in alpha plane", OFFSET(alpha), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS, .unit = "alpha"},
169  { "reset_rot", "reset rotation", OFFSET(reset_rot), AV_OPT_TYPE_BOOL, {.i64=0}, -1, 1,TFLAGS, .unit = "reset_rot"},
170  { NULL }
171 };
172 
174 
176  AVFilterFormatsConfig **cfg_in,
177  AVFilterFormatsConfig **cfg_out)
178 {
179  const V360Context *s = ctx->priv;
180  static const enum AVPixelFormat pix_fmts[] = {
181  // YUVA444
185 
186  // YUVA422
190 
191  // YUVA420
194 
195  // YUVJ
199 
200  // YUV444
204 
205  // YUV440
208 
209  // YUV422
213 
214  // YUV420
218 
219  // YUV411
221 
222  // YUV410
224 
225  // GBR
229 
230  // GBRA
233 
234  // GRAY
238 
240  };
241  static const enum AVPixelFormat alpha_pix_fmts[] = {
253  };
254 
255  return ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out,
256  s->alpha ? alpha_pix_fmts : pix_fmts);
257 }
258 
259 #define DEFINE_REMAP1_LINE(bits, div) \
260 static void remap1_##bits##bit_line_c(uint8_t *dst, int width, const uint8_t *const src, \
261  ptrdiff_t in_linesize, \
262  const int16_t *const u, const int16_t *const v, \
263  const int16_t *const ker) \
264 { \
265  const uint##bits##_t *const s = (const uint##bits##_t *const)src; \
266  uint##bits##_t *d = (uint##bits##_t *)dst; \
267  \
268  in_linesize /= div; \
269  \
270  for (int x = 0; x < width; x++) \
271  d[x] = s[v[x] * in_linesize + u[x]]; \
272 }
273 
274 DEFINE_REMAP1_LINE( 8, 1)
275 DEFINE_REMAP1_LINE(16, 2)
276 
277 /**
278  * Generate remapping function with a given window size and pixel depth.
279  *
280  * @param ws size of interpolation window
281  * @param bits number of bits per pixel
282  */
283 #define DEFINE_REMAP(ws, bits) \
284 static int remap##ws##_##bits##bit_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
285 { \
286  ThreadData *td = arg; \
287  const V360Context *s = ctx->priv; \
288  const SliceXYRemap *r = &s->slice_remap[jobnr]; \
289  const AVFrame *in = td->in; \
290  AVFrame *out = td->out; \
291  \
292  av_assert1(s->nb_planes <= AV_VIDEO_MAX_PLANES); \
293  \
294  for (int stereo = 0; stereo < 1 + s->out_stereo > STEREO_2D; stereo++) { \
295  for (int plane = 0; plane < s->nb_planes; plane++) { \
296  const unsigned map = s->map[plane]; \
297  const int in_linesize = in->linesize[plane]; \
298  const int out_linesize = out->linesize[plane]; \
299  const int uv_linesize = s->uv_linesize[plane]; \
300  const int in_offset_w = stereo ? s->in_offset_w[plane] : 0; \
301  const int in_offset_h = stereo ? s->in_offset_h[plane] : 0; \
302  const int out_offset_w = stereo ? s->out_offset_w[plane] : 0; \
303  const int out_offset_h = stereo ? s->out_offset_h[plane] : 0; \
304  const uint8_t *const src = in->data[plane] + \
305  in_offset_h * in_linesize + in_offset_w * (bits >> 3); \
306  uint8_t *dst = out->data[plane] + out_offset_h * out_linesize + out_offset_w * (bits >> 3); \
307  const uint8_t *mask = plane == 3 ? r->mask : NULL; \
308  const int width = s->pr_width[plane]; \
309  const int height = s->pr_height[plane]; \
310  \
311  const int slice_start = (height * jobnr ) / nb_jobs; \
312  const int slice_end = (height * (jobnr + 1)) / nb_jobs; \
313  \
314  for (int y = slice_start; y < slice_end && !mask; y++) { \
315  const int16_t *const u = r->u[map] + (y - slice_start) * uv_linesize * ws * ws; \
316  const int16_t *const v = r->v[map] + (y - slice_start) * uv_linesize * ws * ws; \
317  const int16_t *const ker = r->ker[map] + (y - slice_start) * uv_linesize * ws * ws; \
318  \
319  s->remap_line(dst + y * out_linesize, width, src, in_linesize, u, v, ker); \
320  } \
321  \
322  for (int y = slice_start; y < slice_end && mask; y++) { \
323  memcpy(dst + y * out_linesize, mask + \
324  (y - slice_start) * width * (bits >> 3), width * (bits >> 3)); \
325  } \
326  } \
327  } \
328  \
329  return 0; \
330 }
331 
332 DEFINE_REMAP(1, 8)
333 DEFINE_REMAP(2, 8)
334 DEFINE_REMAP(3, 8)
335 DEFINE_REMAP(4, 8)
336 DEFINE_REMAP(1, 16)
337 DEFINE_REMAP(2, 16)
338 DEFINE_REMAP(3, 16)
339 DEFINE_REMAP(4, 16)
340 
341 #define DEFINE_REMAP_LINE(ws, bits, div) \
342 static void remap##ws##_##bits##bit_line_c(uint8_t *dst, int width, const uint8_t *const src, \
343  ptrdiff_t in_linesize, \
344  const int16_t *const u, const int16_t *const v, \
345  const int16_t *const ker) \
346 { \
347  const uint##bits##_t *const s = (const uint##bits##_t *const)src; \
348  uint##bits##_t *d = (uint##bits##_t *)dst; \
349  \
350  in_linesize /= div; \
351  \
352  for (int x = 0; x < width; x++) { \
353  const int16_t *const uu = u + x * ws * ws; \
354  const int16_t *const vv = v + x * ws * ws; \
355  const int16_t *const kker = ker + x * ws * ws; \
356  int tmp = 0; \
357  \
358  for (int i = 0; i < ws; i++) { \
359  const int iws = i * ws; \
360  for (int j = 0; j < ws; j++) { \
361  tmp += kker[iws + j] * s[vv[iws + j] * in_linesize + uu[iws + j]]; \
362  } \
363  } \
364  \
365  d[x] = av_clip_uint##bits(tmp >> 14); \
366  } \
367 }
368 
369 DEFINE_REMAP_LINE(2, 8, 1)
370 DEFINE_REMAP_LINE(3, 8, 1)
371 DEFINE_REMAP_LINE(4, 8, 1)
372 DEFINE_REMAP_LINE(2, 16, 2)
373 DEFINE_REMAP_LINE(3, 16, 2)
374 DEFINE_REMAP_LINE(4, 16, 2)
375 
376 void ff_v360_init(V360Context *s, int depth)
377 {
378  switch (s->interp) {
379  case NEAREST:
380  s->remap_line = depth <= 8 ? remap1_8bit_line_c : remap1_16bit_line_c;
381  break;
382  case BILINEAR:
383  s->remap_line = depth <= 8 ? remap2_8bit_line_c : remap2_16bit_line_c;
384  break;
385  case LAGRANGE9:
386  s->remap_line = depth <= 8 ? remap3_8bit_line_c : remap3_16bit_line_c;
387  break;
388  case BICUBIC:
389  case LANCZOS:
390  case SPLINE16:
391  case GAUSSIAN:
392  case MITCHELL:
393  s->remap_line = depth <= 8 ? remap4_8bit_line_c : remap4_16bit_line_c;
394  break;
395  }
396 
397 #if ARCH_X86
398  ff_v360_init_x86(s, depth);
399 #endif
400 }
401 
402 /**
403  * Save nearest pixel coordinates for remapping.
404  *
405  * @param du horizontal relative coordinate
406  * @param dv vertical relative coordinate
407  * @param rmap calculated 4x4 window
408  * @param u u remap data
409  * @param v v remap data
410  * @param ker ker remap data
411  */
412 static void nearest_kernel(float du, float dv, const XYRemap *rmap,
413  int16_t *u, int16_t *v, int16_t *ker)
414 {
415  const int i = lrintf(dv) + 1;
416  const int j = lrintf(du) + 1;
417 
418  u[0] = rmap->u[i][j];
419  v[0] = rmap->v[i][j];
420 }
421 
422 /**
423  * Calculate kernel for bilinear interpolation.
424  *
425  * @param du horizontal relative coordinate
426  * @param dv vertical relative coordinate
427  * @param rmap calculated 4x4 window
428  * @param u u remap data
429  * @param v v remap data
430  * @param ker ker remap data
431  */
432 static void bilinear_kernel(float du, float dv, const XYRemap *rmap,
433  int16_t *u, int16_t *v, int16_t *ker)
434 {
435  for (int i = 0; i < 2; i++) {
436  for (int j = 0; j < 2; j++) {
437  u[i * 2 + j] = rmap->u[i + 1][j + 1];
438  v[i * 2 + j] = rmap->v[i + 1][j + 1];
439  }
440  }
441 
442  ker[0] = lrintf((1.f - du) * (1.f - dv) * 16385.f);
443  ker[1] = lrintf( du * (1.f - dv) * 16385.f);
444  ker[2] = lrintf((1.f - du) * dv * 16385.f);
445  ker[3] = lrintf( du * dv * 16385.f);
446 }
447 
448 /**
449  * Calculate 1-dimensional lagrange coefficients.
450  *
451  * @param t relative coordinate
452  * @param coeffs coefficients
453  */
454 static inline void calculate_lagrange_coeffs(float t, float *coeffs)
455 {
456  coeffs[0] = (t - 1.f) * (t - 2.f) * 0.5f;
457  coeffs[1] = -t * (t - 2.f);
458  coeffs[2] = t * (t - 1.f) * 0.5f;
459 }
460 
461 /**
462  * Calculate kernel for lagrange interpolation.
463  *
464  * @param du horizontal relative coordinate
465  * @param dv vertical relative coordinate
466  * @param rmap calculated 4x4 window
467  * @param u u remap data
468  * @param v v remap data
469  * @param ker ker remap data
470  */
471 static void lagrange_kernel(float du, float dv, const XYRemap *rmap,
472  int16_t *u, int16_t *v, int16_t *ker)
473 {
474  float du_coeffs[3];
475  float dv_coeffs[3];
476 
477  calculate_lagrange_coeffs(du, du_coeffs);
478  calculate_lagrange_coeffs(dv, dv_coeffs);
479 
480  for (int i = 0; i < 3; i++) {
481  for (int j = 0; j < 3; j++) {
482  u[i * 3 + j] = rmap->u[i + 1][j + 1];
483  v[i * 3 + j] = rmap->v[i + 1][j + 1];
484  ker[i * 3 + j] = lrintf(du_coeffs[j] * dv_coeffs[i] * 16385.f);
485  }
486  }
487 }
488 
489 /**
490  * Calculate 1-dimensional cubic coefficients.
491  *
492  * @param t relative coordinate
493  * @param coeffs coefficients
494  */
495 static inline void calculate_bicubic_coeffs(float t, float *coeffs)
496 {
497  const float tt = t * t;
498  const float ttt = t * t * t;
499 
500  coeffs[0] = - t / 3.f + tt / 2.f - ttt / 6.f;
501  coeffs[1] = 1.f - t / 2.f - tt + ttt / 2.f;
502  coeffs[2] = t + tt / 2.f - ttt / 2.f;
503  coeffs[3] = - t / 6.f + ttt / 6.f;
504 }
505 
506 /**
507  * Calculate kernel for bicubic interpolation.
508  *
509  * @param du horizontal relative coordinate
510  * @param dv vertical relative coordinate
511  * @param rmap calculated 4x4 window
512  * @param u u remap data
513  * @param v v remap data
514  * @param ker ker remap data
515  */
516 static void bicubic_kernel(float du, float dv, const XYRemap *rmap,
517  int16_t *u, int16_t *v, int16_t *ker)
518 {
519  float du_coeffs[4];
520  float dv_coeffs[4];
521 
522  calculate_bicubic_coeffs(du, du_coeffs);
523  calculate_bicubic_coeffs(dv, dv_coeffs);
524 
525  for (int i = 0; i < 4; i++) {
526  for (int j = 0; j < 4; j++) {
527  u[i * 4 + j] = rmap->u[i][j];
528  v[i * 4 + j] = rmap->v[i][j];
529  ker[i * 4 + j] = lrintf(du_coeffs[j] * dv_coeffs[i] * 16385.f);
530  }
531  }
532 }
533 
534 /**
535  * Calculate 1-dimensional lanczos coefficients.
536  *
537  * @param t relative coordinate
538  * @param coeffs coefficients
539  */
540 static inline void calculate_lanczos_coeffs(float t, float *coeffs)
541 {
542  float sum = 0.f;
543 
544  for (int i = 0; i < 4; i++) {
545  const float x = M_PI * (t - i + 1);
546  if (x == 0.f) {
547  coeffs[i] = 1.f;
548  } else {
549  coeffs[i] = sinf(x) * sinf(x / 2.f) / (x * x / 2.f);
550  }
551  sum += coeffs[i];
552  }
553 
554  for (int i = 0; i < 4; i++) {
555  coeffs[i] /= sum;
556  }
557 }
558 
559 /**
560  * Calculate kernel for lanczos interpolation.
561  *
562  * @param du horizontal relative coordinate
563  * @param dv vertical relative coordinate
564  * @param rmap calculated 4x4 window
565  * @param u u remap data
566  * @param v v remap data
567  * @param ker ker remap data
568  */
569 static void lanczos_kernel(float du, float dv, const XYRemap *rmap,
570  int16_t *u, int16_t *v, int16_t *ker)
571 {
572  float du_coeffs[4];
573  float dv_coeffs[4];
574 
575  calculate_lanczos_coeffs(du, du_coeffs);
576  calculate_lanczos_coeffs(dv, dv_coeffs);
577 
578  for (int i = 0; i < 4; i++) {
579  for (int j = 0; j < 4; j++) {
580  u[i * 4 + j] = rmap->u[i][j];
581  v[i * 4 + j] = rmap->v[i][j];
582  ker[i * 4 + j] = lrintf(du_coeffs[j] * dv_coeffs[i] * 16385.f);
583  }
584  }
585 }
586 
587 /**
588  * Calculate 1-dimensional spline16 coefficients.
589  *
590  * @param t relative coordinate
591  * @param coeffs coefficients
592  */
593 static void calculate_spline16_coeffs(float t, float *coeffs)
594 {
595  coeffs[0] = ((-1.f / 3.f * t + 0.8f) * t - 7.f / 15.f) * t;
596  coeffs[1] = ((t - 9.f / 5.f) * t - 0.2f) * t + 1.f;
597  coeffs[2] = ((6.f / 5.f - t) * t + 0.8f) * t;
598  coeffs[3] = ((1.f / 3.f * t - 0.2f) * t - 2.f / 15.f) * t;
599 }
600 
601 /**
602  * Calculate kernel for spline16 interpolation.
603  *
604  * @param du horizontal relative coordinate
605  * @param dv vertical relative coordinate
606  * @param rmap calculated 4x4 window
607  * @param u u remap data
608  * @param v v remap data
609  * @param ker ker remap data
610  */
611 static void spline16_kernel(float du, float dv, const XYRemap *rmap,
612  int16_t *u, int16_t *v, int16_t *ker)
613 {
614  float du_coeffs[4];
615  float dv_coeffs[4];
616 
617  calculate_spline16_coeffs(du, du_coeffs);
618  calculate_spline16_coeffs(dv, dv_coeffs);
619 
620  for (int i = 0; i < 4; i++) {
621  for (int j = 0; j < 4; j++) {
622  u[i * 4 + j] = rmap->u[i][j];
623  v[i * 4 + j] = rmap->v[i][j];
624  ker[i * 4 + j] = lrintf(du_coeffs[j] * dv_coeffs[i] * 16385.f);
625  }
626  }
627 }
628 
629 /**
630  * Calculate 1-dimensional gaussian coefficients.
631  *
632  * @param t relative coordinate
633  * @param coeffs coefficients
634  */
635 static void calculate_gaussian_coeffs(float t, float *coeffs)
636 {
637  float sum = 0.f;
638 
639  for (int i = 0; i < 4; i++) {
640  const float x = t - (i - 1);
641  if (x == 0.f) {
642  coeffs[i] = 1.f;
643  } else {
644  coeffs[i] = expf(-2.f * x * x) * expf(-x * x / 2.f);
645  }
646  sum += coeffs[i];
647  }
648 
649  for (int i = 0; i < 4; i++) {
650  coeffs[i] /= sum;
651  }
652 }
653 
654 /**
655  * Calculate kernel for gaussian interpolation.
656  *
657  * @param du horizontal relative coordinate
658  * @param dv vertical relative coordinate
659  * @param rmap calculated 4x4 window
660  * @param u u remap data
661  * @param v v remap data
662  * @param ker ker remap data
663  */
664 static void gaussian_kernel(float du, float dv, const XYRemap *rmap,
665  int16_t *u, int16_t *v, int16_t *ker)
666 {
667  float du_coeffs[4];
668  float dv_coeffs[4];
669 
670  calculate_gaussian_coeffs(du, du_coeffs);
671  calculate_gaussian_coeffs(dv, dv_coeffs);
672 
673  for (int i = 0; i < 4; i++) {
674  for (int j = 0; j < 4; j++) {
675  u[i * 4 + j] = rmap->u[i][j];
676  v[i * 4 + j] = rmap->v[i][j];
677  ker[i * 4 + j] = lrintf(du_coeffs[j] * dv_coeffs[i] * 16385.f);
678  }
679  }
680 }
681 
682 /**
683  * Calculate 1-dimensional cubic_bc_spline coefficients.
684  *
685  * @param t relative coordinate
686  * @param coeffs coefficients
687  */
688 static void calculate_cubic_bc_coeffs(float t, float *coeffs,
689  float b, float c)
690 {
691  float sum = 0.f;
692  float p0 = (6.f - 2.f * b) / 6.f,
693  p2 = (-18.f + 12.f * b + 6.f * c) / 6.f,
694  p3 = (12.f - 9.f * b - 6.f * c) / 6.f,
695  q0 = (8.f * b + 24.f * c) / 6.f,
696  q1 = (-12.f * b - 48.f * c) / 6.f,
697  q2 = (6.f * b + 30.f * c) / 6.f,
698  q3 = (-b - 6.f * c) / 6.f;
699 
700  for (int i = 0; i < 4; i++) {
701  const float x = fabsf(t - i + 1.f);
702  if (x < 1.f) {
703  coeffs[i] = (p0 + x * x * (p2 + x * p3)) *
704  (p0 + x * x * (p2 + x * p3 / 2.f) / 4.f);
705  } else if (x < 2.f) {
706  coeffs[i] = (q0 + x * (q1 + x * (q2 + x * q3))) *
707  (q0 + x * (q1 + x * (q2 + x / 2.f * q3) / 2.f) / 2.f);
708  } else {
709  coeffs[i] = 0.f;
710  }
711  sum += coeffs[i];
712  }
713 
714  for (int i = 0; i < 4; i++) {
715  coeffs[i] /= sum;
716  }
717 }
718 
719 /**
720  * Calculate kernel for mitchell interpolation.
721  *
722  * @param du horizontal relative coordinate
723  * @param dv vertical relative coordinate
724  * @param rmap calculated 4x4 window
725  * @param u u remap data
726  * @param v v remap data
727  * @param ker ker remap data
728  */
729 static void mitchell_kernel(float du, float dv, const XYRemap *rmap,
730  int16_t *u, int16_t *v, int16_t *ker)
731 {
732  float du_coeffs[4];
733  float dv_coeffs[4];
734 
735  calculate_cubic_bc_coeffs(du, du_coeffs, 1.f / 3.f, 1.f / 3.f);
736  calculate_cubic_bc_coeffs(dv, dv_coeffs, 1.f / 3.f, 1.f / 3.f);
737 
738  for (int i = 0; i < 4; i++) {
739  for (int j = 0; j < 4; j++) {
740  u[i * 4 + j] = rmap->u[i][j];
741  v[i * 4 + j] = rmap->v[i][j];
742  ker[i * 4 + j] = lrintf(du_coeffs[j] * dv_coeffs[i] * 16385.f);
743  }
744  }
745 }
746 
747 /**
748  * Modulo operation with only positive remainders.
749  *
750  * @param a dividend
751  * @param b divisor
752  *
753  * @return positive remainder of (a / b)
754  */
755 static inline int mod(int a, int b)
756 {
757  const int res = a % b;
758  if (res < 0) {
759  return res + b;
760  } else {
761  return res;
762  }
763 }
764 
765 /**
766  * Reflect y operation.
767  *
768  * @param y input vertical position
769  * @param h input height
770  */
771 static inline int reflecty(int y, int h)
772 {
773  if (y < 0) {
774  y = -y;
775  } else if (y >= h) {
776  y = 2 * h - 1 - y;
777  }
778 
779  return av_clip(y, 0, h - 1);
780 }
781 
782 /**
783  * Reflect x operation for equirect.
784  *
785  * @param x input horizontal position
786  * @param y input vertical position
787  * @param w input width
788  * @param h input height
789  */
790 static inline int ereflectx(int x, int y, int w, int h)
791 {
792  if (y < 0 || y >= h)
793  x += w / 2;
794 
795  return mod(x, w);
796 }
797 
798 /**
799  * Reflect x operation.
800  *
801  * @param x input horizontal position
802  * @param y input vertical position
803  * @param w input width
804  * @param h input height
805  */
806 static inline int reflectx(int x, int y, int w, int h)
807 {
808  if (y < 0 || y >= h)
809  return w - 1 - x;
810 
811  return mod(x, w);
812 }
813 
814 /**
815  * Convert char to corresponding direction.
816  * Used for cubemap options.
817  */
818 static int get_direction(char c)
819 {
820  switch (c) {
821  case 'r':
822  return RIGHT;
823  case 'l':
824  return LEFT;
825  case 'u':
826  return UP;
827  case 'd':
828  return DOWN;
829  case 'f':
830  return FRONT;
831  case 'b':
832  return BACK;
833  default:
834  return -1;
835  }
836 }
837 
838 /**
839  * Convert char to corresponding rotation angle.
840  * Used for cubemap options.
841  */
842 static int get_rotation(char c)
843 {
844  switch (c) {
845  case '0':
846  return ROT_0;
847  case '1':
848  return ROT_90;
849  case '2':
850  return ROT_180;
851  case '3':
852  return ROT_270;
853  default:
854  return -1;
855  }
856 }
857 
858 /**
859  * Convert char to corresponding rotation order.
860  */
861 static int get_rorder(char c)
862 {
863  switch (c) {
864  case 'Y':
865  case 'y':
866  return YAW;
867  case 'P':
868  case 'p':
869  return PITCH;
870  case 'R':
871  case 'r':
872  return ROLL;
873  default:
874  return -1;
875  }
876 }
877 
878 /**
879  * Prepare data for processing cubemap input format.
880  *
881  * @param ctx filter context
882  *
883  * @return error code
884  */
886 {
887  V360Context *s = ctx->priv;
888 
889  for (int face = 0; face < NB_FACES; face++) {
890  const char c = s->in_forder[face];
891  int direction;
892 
893  if (c == '\0') {
895  "Incomplete in_forder option. Direction for all 6 faces should be specified.\n");
896  return AVERROR(EINVAL);
897  }
898 
899  direction = get_direction(c);
900  if (direction == -1) {
902  "Incorrect direction symbol '%c' in in_forder option.\n", c);
903  return AVERROR(EINVAL);
904  }
905 
906  s->in_cubemap_face_order[direction] = face;
907  }
908 
909  for (int face = 0; face < NB_FACES; face++) {
910  const char c = s->in_frot[face];
911  int rotation;
912 
913  if (c == '\0') {
915  "Incomplete in_frot option. Rotation for all 6 faces should be specified.\n");
916  return AVERROR(EINVAL);
917  }
918 
919  rotation = get_rotation(c);
920  if (rotation == -1) {
922  "Incorrect rotation symbol '%c' in in_frot option.\n", c);
923  return AVERROR(EINVAL);
924  }
925 
926  s->in_cubemap_face_rotation[face] = rotation;
927  }
928 
929  return 0;
930 }
931 
932 /**
933  * Prepare data for processing cubemap output format.
934  *
935  * @param ctx filter context
936  *
937  * @return error code
938  */
940 {
941  V360Context *s = ctx->priv;
942 
943  for (int face = 0; face < NB_FACES; face++) {
944  const char c = s->out_forder[face];
945  int direction;
946 
947  if (c == '\0') {
949  "Incomplete out_forder option. Direction for all 6 faces should be specified.\n");
950  return AVERROR(EINVAL);
951  }
952 
953  direction = get_direction(c);
954  if (direction == -1) {
956  "Incorrect direction symbol '%c' in out_forder option.\n", c);
957  return AVERROR(EINVAL);
958  }
959 
960  s->out_cubemap_direction_order[face] = direction;
961  }
962 
963  for (int face = 0; face < NB_FACES; face++) {
964  const char c = s->out_frot[face];
965  int rotation;
966 
967  if (c == '\0') {
969  "Incomplete out_frot option. Rotation for all 6 faces should be specified.\n");
970  return AVERROR(EINVAL);
971  }
972 
973  rotation = get_rotation(c);
974  if (rotation == -1) {
976  "Incorrect rotation symbol '%c' in out_frot option.\n", c);
977  return AVERROR(EINVAL);
978  }
979 
980  s->out_cubemap_face_rotation[face] = rotation;
981  }
982 
983  return 0;
984 }
985 
986 static inline void rotate_cube_face(float *uf, float *vf, int rotation)
987 {
988  float tmp;
989 
990  switch (rotation) {
991  case ROT_0:
992  break;
993  case ROT_90:
994  tmp = *uf;
995  *uf = -*vf;
996  *vf = tmp;
997  break;
998  case ROT_180:
999  *uf = -*uf;
1000  *vf = -*vf;
1001  break;
1002  case ROT_270:
1003  tmp = -*uf;
1004  *uf = *vf;
1005  *vf = tmp;
1006  break;
1007  default:
1008  av_assert0(0);
1009  }
1010 }
1011 
1012 static inline void rotate_cube_face_inverse(float *uf, float *vf, int rotation)
1013 {
1014  float tmp;
1015 
1016  switch (rotation) {
1017  case ROT_0:
1018  break;
1019  case ROT_90:
1020  tmp = -*uf;
1021  *uf = *vf;
1022  *vf = tmp;
1023  break;
1024  case ROT_180:
1025  *uf = -*uf;
1026  *vf = -*vf;
1027  break;
1028  case ROT_270:
1029  tmp = *uf;
1030  *uf = -*vf;
1031  *vf = tmp;
1032  break;
1033  default:
1034  av_assert0(0);
1035  }
1036 }
1037 
1038 /**
1039  * Offset vector.
1040  *
1041  * @param vec vector
1042  */
1043 static void offset_vector(float *vec, float h_offset, float v_offset)
1044 {
1045  vec[0] += h_offset;
1046  vec[1] += v_offset;
1047 }
1048 
1049 /**
1050  * Normalize vector.
1051  *
1052  * @param vec vector
1053  */
1054 static void normalize_vector(float *vec)
1055 {
1056  const float norm = sqrtf(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
1057 
1058  vec[0] /= norm;
1059  vec[1] /= norm;
1060  vec[2] /= norm;
1061 }
1062 
1063 /**
1064  * Calculate 3D coordinates on sphere for corresponding cubemap position.
1065  * Common operation for every cubemap.
1066  *
1067  * @param s filter private context
1068  * @param uf horizontal cubemap coordinate [0, 1)
1069  * @param vf vertical cubemap coordinate [0, 1)
1070  * @param face face of cubemap
1071  * @param vec coordinates on sphere
1072  * @param scalew scale for uf
1073  * @param scaleh scale for vf
1074  */
1075 static void cube_to_xyz(const V360Context *s,
1076  float uf, float vf, int face,
1077  float *vec, float scalew, float scaleh)
1078 {
1079  const int direction = s->out_cubemap_direction_order[face];
1080  float l_x, l_y, l_z;
1081 
1082  uf /= scalew;
1083  vf /= scaleh;
1084 
1085  rotate_cube_face_inverse(&uf, &vf, s->out_cubemap_face_rotation[face]);
1086 
1087  switch (direction) {
1088  case RIGHT:
1089  l_x = 1.f;
1090  l_y = vf;
1091  l_z = -uf;
1092  break;
1093  case LEFT:
1094  l_x = -1.f;
1095  l_y = vf;
1096  l_z = uf;
1097  break;
1098  case UP:
1099  l_x = uf;
1100  l_y = -1.f;
1101  l_z = vf;
1102  break;
1103  case DOWN:
1104  l_x = uf;
1105  l_y = 1.f;
1106  l_z = -vf;
1107  break;
1108  case FRONT:
1109  l_x = uf;
1110  l_y = vf;
1111  l_z = 1.f;
1112  break;
1113  case BACK:
1114  l_x = -uf;
1115  l_y = vf;
1116  l_z = -1.f;
1117  break;
1118  default:
1119  av_assert0(0);
1120  }
1121 
1122  vec[0] = l_x;
1123  vec[1] = l_y;
1124  vec[2] = l_z;
1125 }
1126 
1127 /**
1128  * Calculate cubemap position for corresponding 3D coordinates on sphere.
1129  * Common operation for every cubemap.
1130  *
1131  * @param s filter private context
1132  * @param vec coordinated on sphere
1133  * @param uf horizontal cubemap coordinate [0, 1)
1134  * @param vf vertical cubemap coordinate [0, 1)
1135  * @param direction direction of view
1136  */
1137 static void xyz_to_cube(const V360Context *s,
1138  const float *vec,
1139  float *uf, float *vf, int *direction)
1140 {
1141  const float phi = atan2f(vec[0], vec[2]);
1142  const float theta = asinf(vec[1]);
1143  float phi_norm, theta_threshold;
1144  int face;
1145 
1146  if (phi >= -M_PI_4 && phi < M_PI_4) {
1147  *direction = FRONT;
1148  phi_norm = phi;
1149  } else if (phi >= -(M_PI_2 + M_PI_4) && phi < -M_PI_4) {
1150  *direction = LEFT;
1151  phi_norm = phi + M_PI_2;
1152  } else if (phi >= M_PI_4 && phi < M_PI_2 + M_PI_4) {
1153  *direction = RIGHT;
1154  phi_norm = phi - M_PI_2;
1155  } else {
1156  *direction = BACK;
1157  phi_norm = phi + ((phi > 0.f) ? -M_PI : M_PI);
1158  }
1159 
1160  theta_threshold = atanf(cosf(phi_norm));
1161  if (theta > theta_threshold) {
1162  *direction = DOWN;
1163  } else if (theta < -theta_threshold) {
1164  *direction = UP;
1165  }
1166 
1167  switch (*direction) {
1168  case RIGHT:
1169  *uf = -vec[2] / vec[0];
1170  *vf = vec[1] / vec[0];
1171  break;
1172  case LEFT:
1173  *uf = -vec[2] / vec[0];
1174  *vf = -vec[1] / vec[0];
1175  break;
1176  case UP:
1177  *uf = -vec[0] / vec[1];
1178  *vf = -vec[2] / vec[1];
1179  break;
1180  case DOWN:
1181  *uf = vec[0] / vec[1];
1182  *vf = -vec[2] / vec[1];
1183  break;
1184  case FRONT:
1185  *uf = vec[0] / vec[2];
1186  *vf = vec[1] / vec[2];
1187  break;
1188  case BACK:
1189  *uf = vec[0] / vec[2];
1190  *vf = -vec[1] / vec[2];
1191  break;
1192  default:
1193  av_assert0(0);
1194  }
1195 
1196  face = s->in_cubemap_face_order[*direction];
1197  rotate_cube_face(uf, vf, s->in_cubemap_face_rotation[face]);
1198 }
1199 
1200 /**
1201  * Find position on another cube face in case of overflow/underflow.
1202  * Used for calculation of interpolation window.
1203  *
1204  * @param s filter private context
1205  * @param uf horizontal cubemap coordinate
1206  * @param vf vertical cubemap coordinate
1207  * @param direction direction of view
1208  * @param new_uf new horizontal cubemap coordinate
1209  * @param new_vf new vertical cubemap coordinate
1210  * @param face face position on cubemap
1211  */
1213  float uf, float vf, int direction,
1214  float *new_uf, float *new_vf, int *face)
1215 {
1216  /*
1217  * Cubemap orientation
1218  *
1219  * width
1220  * <------->
1221  * +-------+
1222  * | | U
1223  * | up | h ------->
1224  * +-------+-------+-------+-------+ ^ e |
1225  * | | | | | | i V |
1226  * | left | front | right | back | | g |
1227  * +-------+-------+-------+-------+ v h v
1228  * | | t
1229  * | down |
1230  * +-------+
1231  */
1232 
1233  *face = s->in_cubemap_face_order[direction];
1234  rotate_cube_face_inverse(&uf, &vf, s->in_cubemap_face_rotation[*face]);
1235 
1236  if ((uf < -1.f || uf >= 1.f) && (vf < -1.f || vf >= 1.f)) {
1237  // There are no pixels to use in this case
1238  *new_uf = uf;
1239  *new_vf = vf;
1240  } else if (uf < -1.f) {
1241  uf += 2.f;
1242  switch (direction) {
1243  case RIGHT:
1244  direction = FRONT;
1245  *new_uf = uf;
1246  *new_vf = vf;
1247  break;
1248  case LEFT:
1249  direction = BACK;
1250  *new_uf = uf;
1251  *new_vf = vf;
1252  break;
1253  case UP:
1254  direction = LEFT;
1255  *new_uf = vf;
1256  *new_vf = -uf;
1257  break;
1258  case DOWN:
1259  direction = LEFT;
1260  *new_uf = -vf;
1261  *new_vf = uf;
1262  break;
1263  case FRONT:
1264  direction = LEFT;
1265  *new_uf = uf;
1266  *new_vf = vf;
1267  break;
1268  case BACK:
1269  direction = RIGHT;
1270  *new_uf = uf;
1271  *new_vf = vf;
1272  break;
1273  default:
1274  av_assert0(0);
1275  }
1276  } else if (uf >= 1.f) {
1277  uf -= 2.f;
1278  switch (direction) {
1279  case RIGHT:
1280  direction = BACK;
1281  *new_uf = uf;
1282  *new_vf = vf;
1283  break;
1284  case LEFT:
1285  direction = FRONT;
1286  *new_uf = uf;
1287  *new_vf = vf;
1288  break;
1289  case UP:
1290  direction = RIGHT;
1291  *new_uf = -vf;
1292  *new_vf = uf;
1293  break;
1294  case DOWN:
1295  direction = RIGHT;
1296  *new_uf = vf;
1297  *new_vf = -uf;
1298  break;
1299  case FRONT:
1300  direction = RIGHT;
1301  *new_uf = uf;
1302  *new_vf = vf;
1303  break;
1304  case BACK:
1305  direction = LEFT;
1306  *new_uf = uf;
1307  *new_vf = vf;
1308  break;
1309  default:
1310  av_assert0(0);
1311  }
1312  } else if (vf < -1.f) {
1313  vf += 2.f;
1314  switch (direction) {
1315  case RIGHT:
1316  direction = UP;
1317  *new_uf = vf;
1318  *new_vf = -uf;
1319  break;
1320  case LEFT:
1321  direction = UP;
1322  *new_uf = -vf;
1323  *new_vf = uf;
1324  break;
1325  case UP:
1326  direction = BACK;
1327  *new_uf = -uf;
1328  *new_vf = -vf;
1329  break;
1330  case DOWN:
1331  direction = FRONT;
1332  *new_uf = uf;
1333  *new_vf = vf;
1334  break;
1335  case FRONT:
1336  direction = UP;
1337  *new_uf = uf;
1338  *new_vf = vf;
1339  break;
1340  case BACK:
1341  direction = UP;
1342  *new_uf = -uf;
1343  *new_vf = -vf;
1344  break;
1345  default:
1346  av_assert0(0);
1347  }
1348  } else if (vf >= 1.f) {
1349  vf -= 2.f;
1350  switch (direction) {
1351  case RIGHT:
1352  direction = DOWN;
1353  *new_uf = -vf;
1354  *new_vf = uf;
1355  break;
1356  case LEFT:
1357  direction = DOWN;
1358  *new_uf = vf;
1359  *new_vf = -uf;
1360  break;
1361  case UP:
1362  direction = FRONT;
1363  *new_uf = uf;
1364  *new_vf = vf;
1365  break;
1366  case DOWN:
1367  direction = BACK;
1368  *new_uf = -uf;
1369  *new_vf = -vf;
1370  break;
1371  case FRONT:
1372  direction = DOWN;
1373  *new_uf = uf;
1374  *new_vf = vf;
1375  break;
1376  case BACK:
1377  direction = DOWN;
1378  *new_uf = -uf;
1379  *new_vf = -vf;
1380  break;
1381  default:
1382  av_assert0(0);
1383  }
1384  } else {
1385  // Inside cube face
1386  *new_uf = uf;
1387  *new_vf = vf;
1388  }
1389 
1390  *face = s->in_cubemap_face_order[direction];
1391  rotate_cube_face(new_uf, new_vf, s->in_cubemap_face_rotation[*face]);
1392 }
1393 
1394 static av_always_inline float scale(float x, float s)
1395 {
1396  return (0.5f * x + 0.5f) * (s - 1.f);
1397 }
1398 
1399 static av_always_inline float rescale(int x, float s)
1400 {
1401  return (2.f * x + 1.f) / s - 1.f;
1402 }
1403 
1404 /**
1405  * Calculate 3D coordinates on sphere for corresponding frame position in cubemap3x2 format.
1406  *
1407  * @param s filter private context
1408  * @param i horizontal position on frame [0, width)
1409  * @param j vertical position on frame [0, height)
1410  * @param width frame width
1411  * @param height frame height
1412  * @param vec coordinates on sphere
1413  */
1414 static int cube3x2_to_xyz(const V360Context *s,
1415  int i, int j, int width, int height,
1416  float *vec)
1417 {
1418  const float scalew = s->fout_pad > 0 ? 1.f - s->fout_pad / (width / 3.f) : 1.f - s->out_pad;
1419  const float scaleh = s->fout_pad > 0 ? 1.f - s->fout_pad / (height / 2.f) : 1.f - s->out_pad;
1420 
1421  const float ew = width / 3.f;
1422  const float eh = height / 2.f;
1423 
1424  const int u_face = floorf(i / ew);
1425  const int v_face = floorf(j / eh);
1426  const int face = u_face + 3 * v_face;
1427 
1428  const int u_shift = ceilf(ew * u_face);
1429  const int v_shift = ceilf(eh * v_face);
1430  const int ewi = ceilf(ew * (u_face + 1)) - u_shift;
1431  const int ehi = ceilf(eh * (v_face + 1)) - v_shift;
1432 
1433  const float uf = rescale(i - u_shift, ewi);
1434  const float vf = rescale(j - v_shift, ehi);
1435 
1436  cube_to_xyz(s, uf, vf, face, vec, scalew, scaleh);
1437 
1438  return 1;
1439 }
1440 
1441 /**
1442  * Calculate frame position in cubemap3x2 format for corresponding 3D coordinates on sphere.
1443  *
1444  * @param s filter private context
1445  * @param vec coordinates on sphere
1446  * @param width frame width
1447  * @param height frame height
1448  * @param us horizontal coordinates for interpolation window
1449  * @param vs vertical coordinates for interpolation window
1450  * @param du horizontal relative coordinate
1451  * @param dv vertical relative coordinate
1452  */
1453 static int xyz_to_cube3x2(const V360Context *s,
1454  const float *vec, int width, int height,
1455  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
1456 {
1457  const float scalew = s->fin_pad > 0 ? 1.f - s->fin_pad / (width / 3.f) : 1.f - s->in_pad;
1458  const float scaleh = s->fin_pad > 0 ? 1.f - s->fin_pad / (height / 2.f) : 1.f - s->in_pad;
1459  const float ew = width / 3.f;
1460  const float eh = height / 2.f;
1461  float uf, vf;
1462  int ui, vi;
1463  int ewi, ehi;
1464  int direction, face;
1465  int u_face, v_face;
1466 
1467  xyz_to_cube(s, vec, &uf, &vf, &direction);
1468 
1469  uf *= scalew;
1470  vf *= scaleh;
1471 
1472  face = s->in_cubemap_face_order[direction];
1473  u_face = face % 3;
1474  v_face = face / 3;
1475  ewi = ceilf(ew * (u_face + 1)) - ceilf(ew * u_face);
1476  ehi = ceilf(eh * (v_face + 1)) - ceilf(eh * v_face);
1477 
1478  uf = 0.5f * ewi * (uf + 1.f) - 0.5f;
1479  vf = 0.5f * ehi * (vf + 1.f) - 0.5f;
1480 
1481  ui = floorf(uf);
1482  vi = floorf(vf);
1483 
1484  *du = uf - ui;
1485  *dv = vf - vi;
1486 
1487  for (int i = 0; i < 4; i++) {
1488  for (int j = 0; j < 4; j++) {
1489  int new_ui = ui + j - 1;
1490  int new_vi = vi + i - 1;
1491  int u_shift, v_shift;
1492  int new_ewi, new_ehi;
1493 
1494  if (new_ui >= 0 && new_ui < ewi && new_vi >= 0 && new_vi < ehi) {
1495  face = s->in_cubemap_face_order[direction];
1496 
1497  u_face = face % 3;
1498  v_face = face / 3;
1499  u_shift = ceilf(ew * u_face);
1500  v_shift = ceilf(eh * v_face);
1501  } else {
1502  uf = 2.f * new_ui / ewi - 1.f;
1503  vf = 2.f * new_vi / ehi - 1.f;
1504 
1505  uf /= scalew;
1506  vf /= scaleh;
1507 
1508  process_cube_coordinates(s, uf, vf, direction, &uf, &vf, &face);
1509 
1510  uf *= scalew;
1511  vf *= scaleh;
1512 
1513  u_face = face % 3;
1514  v_face = face / 3;
1515  u_shift = ceilf(ew * u_face);
1516  v_shift = ceilf(eh * v_face);
1517  new_ewi = ceilf(ew * (u_face + 1)) - u_shift;
1518  new_ehi = ceilf(eh * (v_face + 1)) - v_shift;
1519 
1520  new_ui = av_clip(lrintf(0.5f * new_ewi * (uf + 1.f)), 0, new_ewi - 1);
1521  new_vi = av_clip(lrintf(0.5f * new_ehi * (vf + 1.f)), 0, new_ehi - 1);
1522  }
1523 
1524  us[i][j] = u_shift + new_ui;
1525  vs[i][j] = v_shift + new_vi;
1526  }
1527  }
1528 
1529  return 1;
1530 }
1531 
1532 /**
1533  * Calculate 3D coordinates on sphere for corresponding frame position in cubemap1x6 format.
1534  *
1535  * @param s filter private context
1536  * @param i horizontal position on frame [0, width)
1537  * @param j vertical position on frame [0, height)
1538  * @param width frame width
1539  * @param height frame height
1540  * @param vec coordinates on sphere
1541  */
1542 static int cube1x6_to_xyz(const V360Context *s,
1543  int i, int j, int width, int height,
1544  float *vec)
1545 {
1546  const float scalew = s->fout_pad > 0 ? 1.f - (float)(s->fout_pad) / width : 1.f - s->out_pad;
1547  const float scaleh = s->fout_pad > 0 ? 1.f - s->fout_pad / (height / 6.f) : 1.f - s->out_pad;
1548 
1549  const float ew = width;
1550  const float eh = height / 6.f;
1551 
1552  const int face = floorf(j / eh);
1553 
1554  const int v_shift = ceilf(eh * face);
1555  const int ehi = ceilf(eh * (face + 1)) - v_shift;
1556 
1557  const float uf = rescale(i, ew);
1558  const float vf = rescale(j - v_shift, ehi);
1559 
1560  cube_to_xyz(s, uf, vf, face, vec, scalew, scaleh);
1561 
1562  return 1;
1563 }
1564 
1565 /**
1566  * Calculate 3D coordinates on sphere for corresponding frame position in cubemap6x1 format.
1567  *
1568  * @param s filter private context
1569  * @param i horizontal position on frame [0, width)
1570  * @param j vertical position on frame [0, height)
1571  * @param width frame width
1572  * @param height frame height
1573  * @param vec coordinates on sphere
1574  */
1575 static int cube6x1_to_xyz(const V360Context *s,
1576  int i, int j, int width, int height,
1577  float *vec)
1578 {
1579  const float scalew = s->fout_pad > 0 ? 1.f - s->fout_pad / (width / 6.f) : 1.f - s->out_pad;
1580  const float scaleh = s->fout_pad > 0 ? 1.f - (float)(s->fout_pad) / height : 1.f - s->out_pad;
1581 
1582  const float ew = width / 6.f;
1583  const float eh = height;
1584 
1585  const int face = floorf(i / ew);
1586 
1587  const int u_shift = ceilf(ew * face);
1588  const int ewi = ceilf(ew * (face + 1)) - u_shift;
1589 
1590  const float uf = rescale(i - u_shift, ewi);
1591  const float vf = rescale(j, eh);
1592 
1593  cube_to_xyz(s, uf, vf, face, vec, scalew, scaleh);
1594 
1595  return 1;
1596 }
1597 
1598 /**
1599  * Calculate frame position in cubemap1x6 format for corresponding 3D coordinates on sphere.
1600  *
1601  * @param s filter private context
1602  * @param vec coordinates on sphere
1603  * @param width frame width
1604  * @param height frame height
1605  * @param us horizontal coordinates for interpolation window
1606  * @param vs vertical coordinates for interpolation window
1607  * @param du horizontal relative coordinate
1608  * @param dv vertical relative coordinate
1609  */
1610 static int xyz_to_cube1x6(const V360Context *s,
1611  const float *vec, int width, int height,
1612  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
1613 {
1614  const float scalew = s->fin_pad > 0 ? 1.f - (float)(s->fin_pad) / width : 1.f - s->in_pad;
1615  const float scaleh = s->fin_pad > 0 ? 1.f - s->fin_pad / (height / 6.f) : 1.f - s->in_pad;
1616  const float eh = height / 6.f;
1617  const int ewi = width;
1618  float uf, vf;
1619  int ui, vi;
1620  int ehi;
1621  int direction, face;
1622 
1623  xyz_to_cube(s, vec, &uf, &vf, &direction);
1624 
1625  uf *= scalew;
1626  vf *= scaleh;
1627 
1628  face = s->in_cubemap_face_order[direction];
1629  ehi = ceilf(eh * (face + 1)) - ceilf(eh * face);
1630 
1631  uf = 0.5f * ewi * (uf + 1.f) - 0.5f;
1632  vf = 0.5f * ehi * (vf + 1.f) - 0.5f;
1633 
1634  ui = floorf(uf);
1635  vi = floorf(vf);
1636 
1637  *du = uf - ui;
1638  *dv = vf - vi;
1639 
1640  for (int i = 0; i < 4; i++) {
1641  for (int j = 0; j < 4; j++) {
1642  int new_ui = ui + j - 1;
1643  int new_vi = vi + i - 1;
1644  int v_shift;
1645  int new_ehi;
1646 
1647  if (new_ui >= 0 && new_ui < ewi && new_vi >= 0 && new_vi < ehi) {
1648  face = s->in_cubemap_face_order[direction];
1649 
1650  v_shift = ceilf(eh * face);
1651  } else {
1652  uf = 2.f * new_ui / ewi - 1.f;
1653  vf = 2.f * new_vi / ehi - 1.f;
1654 
1655  uf /= scalew;
1656  vf /= scaleh;
1657 
1658  process_cube_coordinates(s, uf, vf, direction, &uf, &vf, &face);
1659 
1660  uf *= scalew;
1661  vf *= scaleh;
1662 
1663  v_shift = ceilf(eh * face);
1664  new_ehi = ceilf(eh * (face + 1)) - v_shift;
1665 
1666  new_ui = av_clip(lrintf(0.5f * ewi * (uf + 1.f)), 0, ewi - 1);
1667  new_vi = av_clip(lrintf(0.5f * new_ehi * (vf + 1.f)), 0, new_ehi - 1);
1668  }
1669 
1670  us[i][j] = new_ui;
1671  vs[i][j] = v_shift + new_vi;
1672  }
1673  }
1674 
1675  return 1;
1676 }
1677 
1678 /**
1679  * Calculate frame position in cubemap6x1 format for corresponding 3D coordinates on sphere.
1680  *
1681  * @param s filter private context
1682  * @param vec coordinates on sphere
1683  * @param width frame width
1684  * @param height frame height
1685  * @param us horizontal coordinates for interpolation window
1686  * @param vs vertical coordinates for interpolation window
1687  * @param du horizontal relative coordinate
1688  * @param dv vertical relative coordinate
1689  */
1690 static int xyz_to_cube6x1(const V360Context *s,
1691  const float *vec, int width, int height,
1692  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
1693 {
1694  const float scalew = s->fin_pad > 0 ? 1.f - s->fin_pad / (width / 6.f) : 1.f - s->in_pad;
1695  const float scaleh = s->fin_pad > 0 ? 1.f - (float)(s->fin_pad) / height : 1.f - s->in_pad;
1696  const float ew = width / 6.f;
1697  const int ehi = height;
1698  float uf, vf;
1699  int ui, vi;
1700  int ewi;
1701  int direction, face;
1702 
1703  xyz_to_cube(s, vec, &uf, &vf, &direction);
1704 
1705  uf *= scalew;
1706  vf *= scaleh;
1707 
1708  face = s->in_cubemap_face_order[direction];
1709  ewi = ceilf(ew * (face + 1)) - ceilf(ew * face);
1710 
1711  uf = 0.5f * ewi * (uf + 1.f) - 0.5f;
1712  vf = 0.5f * ehi * (vf + 1.f) - 0.5f;
1713 
1714  ui = floorf(uf);
1715  vi = floorf(vf);
1716 
1717  *du = uf - ui;
1718  *dv = vf - vi;
1719 
1720  for (int i = 0; i < 4; i++) {
1721  for (int j = 0; j < 4; j++) {
1722  int new_ui = ui + j - 1;
1723  int new_vi = vi + i - 1;
1724  int u_shift;
1725  int new_ewi;
1726 
1727  if (new_ui >= 0 && new_ui < ewi && new_vi >= 0 && new_vi < ehi) {
1728  face = s->in_cubemap_face_order[direction];
1729 
1730  u_shift = ceilf(ew * face);
1731  } else {
1732  uf = 2.f * new_ui / ewi - 1.f;
1733  vf = 2.f * new_vi / ehi - 1.f;
1734 
1735  uf /= scalew;
1736  vf /= scaleh;
1737 
1738  process_cube_coordinates(s, uf, vf, direction, &uf, &vf, &face);
1739 
1740  uf *= scalew;
1741  vf *= scaleh;
1742 
1743  u_shift = ceilf(ew * face);
1744  new_ewi = ceilf(ew * (face + 1)) - u_shift;
1745 
1746  new_ui = av_clip(lrintf(0.5f * new_ewi * (uf + 1.f)), 0, new_ewi - 1);
1747  new_vi = av_clip(lrintf(0.5f * ehi * (vf + 1.f)), 0, ehi - 1);
1748  }
1749 
1750  us[i][j] = u_shift + new_ui;
1751  vs[i][j] = new_vi;
1752  }
1753  }
1754 
1755  return 1;
1756 }
1757 
1758 /**
1759  * Prepare data for processing equirectangular output format.
1760  *
1761  * @param ctx filter context
1762  *
1763  * @return error code
1764  */
1766 {
1767  V360Context *s = ctx->priv;
1768 
1769  s->flat_range[0] = s->h_fov * M_PI / 360.f;
1770  s->flat_range[1] = s->v_fov * M_PI / 360.f;
1771 
1772  return 0;
1773 }
1774 
1775 /**
1776  * Calculate 3D coordinates on sphere for corresponding frame position in equirectangular format.
1777  *
1778  * @param s filter private context
1779  * @param i horizontal position on frame [0, width)
1780  * @param j vertical position on frame [0, height)
1781  * @param width frame width
1782  * @param height frame height
1783  * @param vec coordinates on sphere
1784  */
1785 static int equirect_to_xyz(const V360Context *s,
1786  int i, int j, int width, int height,
1787  float *vec)
1788 {
1789  const float phi = rescale(i, width) * s->flat_range[0];
1790  const float theta = rescale(j, height) * s->flat_range[1];
1791 
1792  const float sin_phi = sinf(phi);
1793  const float cos_phi = cosf(phi);
1794  const float sin_theta = sinf(theta);
1795  const float cos_theta = cosf(theta);
1796 
1797  vec[0] = cos_theta * sin_phi;
1798  vec[1] = sin_theta;
1799  vec[2] = cos_theta * cos_phi;
1800 
1801  return 1;
1802 }
1803 
1804 /**
1805  * Calculate 3D coordinates on sphere for corresponding frame position in half equirectangular format.
1806  *
1807  * @param s filter private context
1808  * @param i horizontal position on frame [0, width)
1809  * @param j vertical position on frame [0, height)
1810  * @param width frame width
1811  * @param height frame height
1812  * @param vec coordinates on sphere
1813  */
1814 static int hequirect_to_xyz(const V360Context *s,
1815  int i, int j, int width, int height,
1816  float *vec)
1817 {
1818  const float phi = rescale(i, width) * M_PI_2;
1819  const float theta = rescale(j, height) * M_PI_2;
1820 
1821  const float sin_phi = sinf(phi);
1822  const float cos_phi = cosf(phi);
1823  const float sin_theta = sinf(theta);
1824  const float cos_theta = cosf(theta);
1825 
1826  vec[0] = cos_theta * sin_phi;
1827  vec[1] = sin_theta;
1828  vec[2] = cos_theta * cos_phi;
1829 
1830  return 1;
1831 }
1832 
1833 /**
1834  * Prepare data for processing stereographic output format.
1835  *
1836  * @param ctx filter context
1837  *
1838  * @return error code
1839  */
1841 {
1842  V360Context *s = ctx->priv;
1843 
1844  s->flat_range[0] = tanf(FFMIN(s->h_fov, 359.f) * M_PI / 720.f);
1845  s->flat_range[1] = tanf(FFMIN(s->v_fov, 359.f) * M_PI / 720.f);
1846 
1847  return 0;
1848 }
1849 
1850 /**
1851  * Calculate 3D coordinates on sphere for corresponding frame position in stereographic format.
1852  *
1853  * @param s filter private context
1854  * @param i horizontal position on frame [0, width)
1855  * @param j vertical position on frame [0, height)
1856  * @param width frame width
1857  * @param height frame height
1858  * @param vec coordinates on sphere
1859  */
1861  int i, int j, int width, int height,
1862  float *vec)
1863 {
1864  const float x = rescale(i, width) * s->flat_range[0];
1865  const float y = rescale(j, height) * s->flat_range[1];
1866  const float r = hypotf(x, y);
1867  const float theta = atanf(r) * 2.f;
1868  const float sin_theta = sinf(theta);
1869 
1870  vec[0] = x / r * sin_theta;
1871  vec[1] = y / r * sin_theta;
1872  vec[2] = cosf(theta);
1873 
1874  return 1;
1875 }
1876 
1877 /**
1878  * Prepare data for processing stereographic input format.
1879  *
1880  * @param ctx filter context
1881  *
1882  * @return error code
1883  */
1885 {
1886  V360Context *s = ctx->priv;
1887 
1888  s->iflat_range[0] = tanf(FFMIN(s->ih_fov, 359.f) * M_PI / 720.f);
1889  s->iflat_range[1] = tanf(FFMIN(s->iv_fov, 359.f) * M_PI / 720.f);
1890 
1891  return 0;
1892 }
1893 
1894 /**
1895  * Calculate frame position in stereographic format for corresponding 3D coordinates on sphere.
1896  *
1897  * @param s filter private context
1898  * @param vec coordinates on sphere
1899  * @param width frame width
1900  * @param height frame height
1901  * @param us horizontal coordinates for interpolation window
1902  * @param vs vertical coordinates for interpolation window
1903  * @param du horizontal relative coordinate
1904  * @param dv vertical relative coordinate
1905  */
1907  const float *vec, int width, int height,
1908  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
1909 {
1910  const float theta = acosf(vec[2]);
1911  const float r = tanf(theta * 0.5f);
1912  const float c = r / hypotf(vec[0], vec[1]);
1913  const float x = vec[0] * c / s->iflat_range[0];
1914  const float y = vec[1] * c / s->iflat_range[1];
1915 
1916  const float uf = scale(x, width);
1917  const float vf = scale(y, height);
1918 
1919  const int ui = floorf(uf);
1920  const int vi = floorf(vf);
1921 
1922  const int visible = isfinite(x) && isfinite(y) && vi >= 0 && vi < height && ui >= 0 && ui < width;
1923 
1924  *du = visible ? uf - ui : 0.f;
1925  *dv = visible ? vf - vi : 0.f;
1926 
1927  for (int i = 0; i < 4; i++) {
1928  for (int j = 0; j < 4; j++) {
1929  us[i][j] = visible ? av_clip(ui + j - 1, 0, width - 1) : 0;
1930  vs[i][j] = visible ? av_clip(vi + i - 1, 0, height - 1) : 0;
1931  }
1932  }
1933 
1934  return visible;
1935 }
1936 
1937 /**
1938  * Prepare data for processing equisolid output format.
1939  *
1940  * @param ctx filter context
1941  *
1942  * @return error code
1943  */
1945 {
1946  V360Context *s = ctx->priv;
1947 
1948  s->flat_range[0] = sinf(s->h_fov * M_PI / 720.f);
1949  s->flat_range[1] = sinf(s->v_fov * M_PI / 720.f);
1950 
1951  return 0;
1952 }
1953 
1954 /**
1955  * Calculate 3D coordinates on sphere for corresponding frame position in equisolid format.
1956  *
1957  * @param s filter private context
1958  * @param i horizontal position on frame [0, width)
1959  * @param j vertical position on frame [0, height)
1960  * @param width frame width
1961  * @param height frame height
1962  * @param vec coordinates on sphere
1963  */
1964 static int equisolid_to_xyz(const V360Context *s,
1965  int i, int j, int width, int height,
1966  float *vec)
1967 {
1968  const float x = rescale(i, width) * s->flat_range[0];
1969  const float y = rescale(j, height) * s->flat_range[1];
1970  const float r = hypotf(x, y);
1971  const float theta = asinf(r) * 2.f;
1972  const float sin_theta = sinf(theta);
1973 
1974  vec[0] = x / r * sin_theta;
1975  vec[1] = y / r * sin_theta;
1976  vec[2] = cosf(theta);
1977 
1978  return 1;
1979 }
1980 
1981 /**
1982  * Prepare data for processing equisolid input format.
1983  *
1984  * @param ctx filter context
1985  *
1986  * @return error code
1987  */
1989 {
1990  V360Context *s = ctx->priv;
1991 
1992  s->iflat_range[0] = sinf(FFMIN(s->ih_fov, 359.f) * M_PI / 720.f);
1993  s->iflat_range[1] = sinf(FFMIN(s->iv_fov, 359.f) * M_PI / 720.f);
1994 
1995  return 0;
1996 }
1997 
1998 /**
1999  * Calculate frame position in equisolid format for corresponding 3D coordinates on sphere.
2000  *
2001  * @param s filter private context
2002  * @param vec coordinates on sphere
2003  * @param width frame width
2004  * @param height frame height
2005  * @param us horizontal coordinates for interpolation window
2006  * @param vs vertical coordinates for interpolation window
2007  * @param du horizontal relative coordinate
2008  * @param dv vertical relative coordinate
2009  */
2010 static int xyz_to_equisolid(const V360Context *s,
2011  const float *vec, int width, int height,
2012  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2013 {
2014  const float theta = acosf(vec[2]);
2015  const float r = sinf(theta * 0.5f);
2016  const float c = r / hypotf(vec[0], vec[1]);
2017  const float x = vec[0] * c / s->iflat_range[0];
2018  const float y = vec[1] * c / s->iflat_range[1];
2019 
2020  const float uf = scale(x, width);
2021  const float vf = scale(y, height);
2022 
2023  const int ui = floorf(uf);
2024  const int vi = floorf(vf);
2025 
2026  const int visible = isfinite(x) && isfinite(y) && vi >= 0 && vi < height && ui >= 0 && ui < width;
2027 
2028  *du = visible ? uf - ui : 0.f;
2029  *dv = visible ? vf - vi : 0.f;
2030 
2031  for (int i = 0; i < 4; i++) {
2032  for (int j = 0; j < 4; j++) {
2033  us[i][j] = visible ? av_clip(ui + j - 1, 0, width - 1) : 0;
2034  vs[i][j] = visible ? av_clip(vi + i - 1, 0, height - 1) : 0;
2035  }
2036  }
2037 
2038  return visible;
2039 }
2040 
2041 /**
2042  * Prepare data for processing orthographic output format.
2043  *
2044  * @param ctx filter context
2045  *
2046  * @return error code
2047  */
2049 {
2050  V360Context *s = ctx->priv;
2051 
2052  s->flat_range[0] = sinf(FFMIN(s->h_fov, 180.f) * M_PI / 360.f);
2053  s->flat_range[1] = sinf(FFMIN(s->v_fov, 180.f) * M_PI / 360.f);
2054 
2055  return 0;
2056 }
2057 
2058 /**
2059  * Calculate 3D coordinates on sphere for corresponding frame position in orthographic format.
2060  *
2061  * @param s filter private context
2062  * @param i horizontal position on frame [0, width)
2063  * @param j vertical position on frame [0, height)
2064  * @param width frame width
2065  * @param height frame height
2066  * @param vec coordinates on sphere
2067  */
2069  int i, int j, int width, int height,
2070  float *vec)
2071 {
2072  const float x = rescale(i, width) * s->flat_range[0];
2073  const float y = rescale(j, height) * s->flat_range[1];
2074  const float r = hypotf(x, y);
2075  const float theta = asinf(r);
2076 
2077  vec[2] = cosf(theta);
2078  if (vec[2] > 0) {
2079  vec[0] = x;
2080  vec[1] = y;
2081 
2082  return 1;
2083  } else {
2084  vec[0] = 0.f;
2085  vec[1] = 0.f;
2086  vec[2] = 1.f;
2087 
2088  return 0;
2089  }
2090 }
2091 
2092 /**
2093  * Prepare data for processing orthographic input format.
2094  *
2095  * @param ctx filter context
2096  *
2097  * @return error code
2098  */
2100 {
2101  V360Context *s = ctx->priv;
2102 
2103  s->iflat_range[0] = sinf(FFMIN(s->ih_fov, 180.f) * M_PI / 360.f);
2104  s->iflat_range[1] = sinf(FFMIN(s->iv_fov, 180.f) * M_PI / 360.f);
2105 
2106  return 0;
2107 }
2108 
2109 /**
2110  * Calculate frame position in orthographic format for corresponding 3D coordinates on sphere.
2111  *
2112  * @param s filter private context
2113  * @param vec coordinates on sphere
2114  * @param width frame width
2115  * @param height frame height
2116  * @param us horizontal coordinates for interpolation window
2117  * @param vs vertical coordinates for interpolation window
2118  * @param du horizontal relative coordinate
2119  * @param dv vertical relative coordinate
2120  */
2122  const float *vec, int width, int height,
2123  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2124 {
2125  const float theta = acosf(vec[2]);
2126  const float r = sinf(theta);
2127  const float c = r / hypotf(vec[0], vec[1]);
2128  const float x = vec[0] * c / s->iflat_range[0];
2129  const float y = vec[1] * c / s->iflat_range[1];
2130 
2131  const float uf = scale(x, width);
2132  const float vf = scale(y, height);
2133 
2134  const int ui = floorf(uf);
2135  const int vi = floorf(vf);
2136 
2137  const int visible = vec[2] >= 0.f && isfinite(x) && isfinite(y) && vi >= 0 && vi < height && ui >= 0 && ui < width;
2138 
2139  *du = visible ? uf - ui : 0.f;
2140  *dv = visible ? vf - vi : 0.f;
2141 
2142  for (int i = 0; i < 4; i++) {
2143  for (int j = 0; j < 4; j++) {
2144  us[i][j] = visible ? av_clip(ui + j - 1, 0, width - 1) : 0;
2145  vs[i][j] = visible ? av_clip(vi + i - 1, 0, height - 1) : 0;
2146  }
2147  }
2148 
2149  return visible;
2150 }
2151 
2152 /**
2153  * Prepare data for processing equirectangular input format.
2154  *
2155  * @param ctx filter context
2156  *
2157  * @return error code
2158  */
2160 {
2161  V360Context *s = ctx->priv;
2162 
2163  s->iflat_range[0] = s->ih_fov * M_PI / 360.f;
2164  s->iflat_range[1] = s->iv_fov * M_PI / 360.f;
2165 
2166  return 0;
2167 }
2168 
2169 /**
2170  * Calculate frame position in equirectangular format for corresponding 3D coordinates on sphere.
2171  *
2172  * @param s filter private context
2173  * @param vec coordinates on sphere
2174  * @param width frame width
2175  * @param height frame height
2176  * @param us horizontal coordinates for interpolation window
2177  * @param vs vertical coordinates for interpolation window
2178  * @param du horizontal relative coordinate
2179  * @param dv vertical relative coordinate
2180  */
2181 static int xyz_to_equirect(const V360Context *s,
2182  const float *vec, int width, int height,
2183  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2184 {
2185  const float phi = atan2f(vec[0], vec[2]) / s->iflat_range[0];
2186  const float theta = asinf(vec[1]) / s->iflat_range[1];
2187 
2188  const float uf = scale(phi, width);
2189  const float vf = scale(theta, height);
2190 
2191  const int ui = floorf(uf);
2192  const int vi = floorf(vf);
2193  int visible;
2194 
2195  *du = uf - ui;
2196  *dv = vf - vi;
2197 
2198  visible = vi >= 0 && vi < height && ui >= 0 && ui < width;
2199 
2200  for (int i = 0; i < 4; i++) {
2201  for (int j = 0; j < 4; j++) {
2202  us[i][j] = ereflectx(ui + j - 1, vi + i - 1, width, height);
2203  vs[i][j] = reflecty(vi + i - 1, height);
2204  }
2205  }
2206 
2207  return visible;
2208 }
2209 
2210 /**
2211  * Calculate frame position in half equirectangular format for corresponding 3D coordinates on sphere.
2212  *
2213  * @param s filter private context
2214  * @param vec coordinates on sphere
2215  * @param width frame width
2216  * @param height frame height
2217  * @param us horizontal coordinates for interpolation window
2218  * @param vs vertical coordinates for interpolation window
2219  * @param du horizontal relative coordinate
2220  * @param dv vertical relative coordinate
2221  */
2222 static int xyz_to_hequirect(const V360Context *s,
2223  const float *vec, int width, int height,
2224  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2225 {
2226  const float phi = atan2f(vec[0], vec[2]) / M_PI_2;
2227  const float theta = asinf(vec[1]) / M_PI_2;
2228 
2229  const float uf = scale(phi, width);
2230  const float vf = scale(theta, height);
2231 
2232  const int ui = floorf(uf);
2233  const int vi = floorf(vf);
2234 
2235  const int visible = phi >= -M_PI_2 && phi <= M_PI_2;
2236 
2237  *du = uf - ui;
2238  *dv = vf - vi;
2239 
2240  for (int i = 0; i < 4; i++) {
2241  for (int j = 0; j < 4; j++) {
2242  us[i][j] = av_clip(ui + j - 1, 0, width - 1);
2243  vs[i][j] = av_clip(vi + i - 1, 0, height - 1);
2244  }
2245  }
2246 
2247  return visible;
2248 }
2249 
2250 /**
2251  * Prepare data for processing flat input format.
2252  *
2253  * @param ctx filter context
2254  *
2255  * @return error code
2256  */
2258 {
2259  V360Context *s = ctx->priv;
2260 
2261  s->iflat_range[0] = tanf(0.5f * s->ih_fov * M_PI / 180.f);
2262  s->iflat_range[1] = tanf(0.5f * s->iv_fov * M_PI / 180.f);
2263 
2264  return 0;
2265 }
2266 
2267 /**
2268  * Calculate frame position in flat format for corresponding 3D coordinates on sphere.
2269  *
2270  * @param s filter private context
2271  * @param vec coordinates on sphere
2272  * @param width frame width
2273  * @param height frame height
2274  * @param us horizontal coordinates for interpolation window
2275  * @param vs vertical coordinates for interpolation window
2276  * @param du horizontal relative coordinate
2277  * @param dv vertical relative coordinate
2278  */
2279 static int xyz_to_flat(const V360Context *s,
2280  const float *vec, int width, int height,
2281  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2282 {
2283  const float theta = acosf(vec[2]);
2284  const float r = tanf(theta);
2285  const float rr = fabsf(r) < 1e+6f ? r : hypotf(width, height);
2286  const float zf = vec[2];
2287  const float h = hypotf(vec[0], vec[1]);
2288  const float c = h <= 1e-6f ? 1.f : rr / h;
2289  float uf = vec[0] * c / s->iflat_range[0];
2290  float vf = vec[1] * c / s->iflat_range[1];
2291  int visible, ui, vi;
2292 
2293  uf = zf >= 0.f ? scale(uf, width) : 0.f;
2294  vf = zf >= 0.f ? scale(vf, height) : 0.f;
2295 
2296  ui = floorf(uf);
2297  vi = floorf(vf);
2298 
2299  visible = vi >= 0 && vi < height && ui >= 0 && ui < width && zf >= 0.f;
2300 
2301  *du = uf - ui;
2302  *dv = vf - vi;
2303 
2304  for (int i = 0; i < 4; i++) {
2305  for (int j = 0; j < 4; j++) {
2306  us[i][j] = visible ? av_clip(ui + j - 1, 0, width - 1) : 0;
2307  vs[i][j] = visible ? av_clip(vi + i - 1, 0, height - 1) : 0;
2308  }
2309  }
2310 
2311  return visible;
2312 }
2313 
2314 /**
2315  * Calculate frame position in mercator format for corresponding 3D coordinates on sphere.
2316  *
2317  * @param s filter private context
2318  * @param vec coordinates on sphere
2319  * @param width frame width
2320  * @param height frame height
2321  * @param us horizontal coordinates for interpolation window
2322  * @param vs vertical coordinates for interpolation window
2323  * @param du horizontal relative coordinate
2324  * @param dv vertical relative coordinate
2325  */
2326 static int xyz_to_mercator(const V360Context *s,
2327  const float *vec, int width, int height,
2328  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2329 {
2330  const float phi = atan2f(vec[0], vec[2]) / M_PI;
2331  const float theta = av_clipf(logf((1.f + vec[1]) / (1.f - vec[1])) / (2.f * M_PI), -1.f, 1.f);
2332 
2333  const float uf = scale(phi, width);
2334  const float vf = scale(theta, height);
2335 
2336  const int ui = floorf(uf);
2337  const int vi = floorf(vf);
2338 
2339  *du = uf - ui;
2340  *dv = vf - vi;
2341 
2342  for (int i = 0; i < 4; i++) {
2343  for (int j = 0; j < 4; j++) {
2344  us[i][j] = av_clip(ui + j - 1, 0, width - 1);
2345  vs[i][j] = av_clip(vi + i - 1, 0, height - 1);
2346  }
2347  }
2348 
2349  return 1;
2350 }
2351 
2352 /**
2353  * Calculate 3D coordinates on sphere for corresponding frame position in mercator format.
2354  *
2355  * @param s filter private context
2356  * @param i horizontal position on frame [0, width)
2357  * @param j vertical position on frame [0, height)
2358  * @param width frame width
2359  * @param height frame height
2360  * @param vec coordinates on sphere
2361  */
2362 static int mercator_to_xyz(const V360Context *s,
2363  int i, int j, int width, int height,
2364  float *vec)
2365 {
2366  const float phi = rescale(i, width) * M_PI + M_PI_2;
2367  const float y = rescale(j, height) * M_PI;
2368  const float div = expf(2.f * y) + 1.f;
2369 
2370  const float sin_phi = sinf(phi);
2371  const float cos_phi = cosf(phi);
2372  const float sin_theta = 2.f * expf(y) / div;
2373  const float cos_theta = (expf(2.f * y) - 1.f) / div;
2374 
2375  vec[0] = -sin_theta * cos_phi;
2376  vec[1] = cos_theta;
2377  vec[2] = sin_theta * sin_phi;
2378 
2379  return 1;
2380 }
2381 
2382 /**
2383  * Calculate frame position in ball format for corresponding 3D coordinates on sphere.
2384  *
2385  * @param s filter private context
2386  * @param vec coordinates on sphere
2387  * @param width frame width
2388  * @param height frame height
2389  * @param us horizontal coordinates for interpolation window
2390  * @param vs vertical coordinates for interpolation window
2391  * @param du horizontal relative coordinate
2392  * @param dv vertical relative coordinate
2393  */
2394 static int xyz_to_ball(const V360Context *s,
2395  const float *vec, int width, int height,
2396  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2397 {
2398  const float l = hypotf(vec[0], vec[1]);
2399  const float r = sqrtf(1.f - vec[2]) / M_SQRT2;
2400  const float d = l > 0.f ? l : 1.f;
2401 
2402  const float uf = scale(r * vec[0] / d, width);
2403  const float vf = scale(r * vec[1] / d, height);
2404 
2405  const int ui = floorf(uf);
2406  const int vi = floorf(vf);
2407 
2408  *du = uf - ui;
2409  *dv = vf - vi;
2410 
2411  for (int i = 0; i < 4; i++) {
2412  for (int j = 0; j < 4; j++) {
2413  us[i][j] = av_clip(ui + j - 1, 0, width - 1);
2414  vs[i][j] = av_clip(vi + i - 1, 0, height - 1);
2415  }
2416  }
2417 
2418  return 1;
2419 }
2420 
2421 /**
2422  * Calculate 3D coordinates on sphere for corresponding frame position in ball format.
2423  *
2424  * @param s filter private context
2425  * @param i horizontal position on frame [0, width)
2426  * @param j vertical position on frame [0, height)
2427  * @param width frame width
2428  * @param height frame height
2429  * @param vec coordinates on sphere
2430  */
2431 static int ball_to_xyz(const V360Context *s,
2432  int i, int j, int width, int height,
2433  float *vec)
2434 {
2435  const float x = rescale(i, width);
2436  const float y = rescale(j, height);
2437  const float l = hypotf(x, y);
2438 
2439  if (l <= 1.f) {
2440  const float z = 2.f * l * sqrtf(1.f - l * l);
2441 
2442  vec[0] = z * x / (l > 0.f ? l : 1.f);
2443  vec[1] = z * y / (l > 0.f ? l : 1.f);
2444  vec[2] = 1.f - 2.f * l * l;
2445  } else {
2446  vec[0] = 0.f;
2447  vec[1] = 1.f;
2448  vec[2] = 0.f;
2449  return 0;
2450  }
2451 
2452  return 1;
2453 }
2454 
2455 /**
2456  * Calculate 3D coordinates on sphere for corresponding frame position in hammer format.
2457  *
2458  * @param s filter private context
2459  * @param i horizontal position on frame [0, width)
2460  * @param j vertical position on frame [0, height)
2461  * @param width frame width
2462  * @param height frame height
2463  * @param vec coordinates on sphere
2464  */
2465 static int hammer_to_xyz(const V360Context *s,
2466  int i, int j, int width, int height,
2467  float *vec)
2468 {
2469  const float x = rescale(i, width);
2470  const float y = rescale(j, height);
2471 
2472  const float xx = x * x;
2473  const float yy = y * y;
2474 
2475  const float z = sqrtf(1.f - xx * 0.5f - yy * 0.5f);
2476 
2477  const float a = M_SQRT2 * x * z;
2478  const float b = 2.f * z * z - 1.f;
2479 
2480  const float aa = a * a;
2481  const float bb = b * b;
2482 
2483  const float w = sqrtf(1.f - 2.f * yy * z * z);
2484 
2485  vec[0] = w * 2.f * a * b / (aa + bb);
2486  vec[1] = M_SQRT2 * y * z;
2487  vec[2] = w * (bb - aa) / (aa + bb);
2488 
2489  return 1;
2490 }
2491 
2492 /**
2493  * Calculate frame position in hammer format for corresponding 3D coordinates on sphere.
2494  *
2495  * @param s filter private context
2496  * @param vec coordinates on sphere
2497  * @param width frame width
2498  * @param height frame height
2499  * @param us horizontal coordinates for interpolation window
2500  * @param vs vertical coordinates for interpolation window
2501  * @param du horizontal relative coordinate
2502  * @param dv vertical relative coordinate
2503  */
2504 static int xyz_to_hammer(const V360Context *s,
2505  const float *vec, int width, int height,
2506  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2507 {
2508  const float theta = atan2f(vec[0], vec[2]);
2509 
2510  const float z = sqrtf(1.f + sqrtf(1.f - vec[1] * vec[1]) * cosf(theta * 0.5f));
2511  const float x = sqrtf(1.f - vec[1] * vec[1]) * sinf(theta * 0.5f) / z;
2512  const float y = vec[1] / z;
2513 
2514  const float uf = (x + 1.f) * width / 2.f;
2515  const float vf = (y + 1.f) * height / 2.f;
2516 
2517  const int ui = floorf(uf);
2518  const int vi = floorf(vf);
2519 
2520  *du = uf - ui;
2521  *dv = vf - vi;
2522 
2523  for (int i = 0; i < 4; i++) {
2524  for (int j = 0; j < 4; j++) {
2525  us[i][j] = av_clip(ui + j - 1, 0, width - 1);
2526  vs[i][j] = av_clip(vi + i - 1, 0, height - 1);
2527  }
2528  }
2529 
2530  return 1;
2531 }
2532 
2533 /**
2534  * Calculate 3D coordinates on sphere for corresponding frame position in sinusoidal format.
2535  *
2536  * @param s filter private context
2537  * @param i horizontal position on frame [0, width)
2538  * @param j vertical position on frame [0, height)
2539  * @param width frame width
2540  * @param height frame height
2541  * @param vec coordinates on sphere
2542  */
2543 static int sinusoidal_to_xyz(const V360Context *s,
2544  int i, int j, int width, int height,
2545  float *vec)
2546 {
2547  const float theta = rescale(j, height) * M_PI_2;
2548  const float phi = rescale(i, width) * M_PI / cosf(theta);
2549 
2550  const float sin_phi = sinf(phi);
2551  const float cos_phi = cosf(phi);
2552  const float sin_theta = sinf(theta);
2553  const float cos_theta = cosf(theta);
2554 
2555  vec[0] = cos_theta * sin_phi;
2556  vec[1] = sin_theta;
2557  vec[2] = cos_theta * cos_phi;
2558 
2559  return 1;
2560 }
2561 
2562 /**
2563  * Calculate frame position in sinusoidal format for corresponding 3D coordinates on sphere.
2564  *
2565  * @param s filter private context
2566  * @param vec coordinates on sphere
2567  * @param width frame width
2568  * @param height frame height
2569  * @param us horizontal coordinates for interpolation window
2570  * @param vs vertical coordinates for interpolation window
2571  * @param du horizontal relative coordinate
2572  * @param dv vertical relative coordinate
2573  */
2574 static int xyz_to_sinusoidal(const V360Context *s,
2575  const float *vec, int width, int height,
2576  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2577 {
2578  const float theta = asinf(vec[1]);
2579  const float phi = atan2f(vec[0], vec[2]) * cosf(theta);
2580 
2581  const float uf = scale(phi / M_PI, width);
2582  const float vf = scale(theta / M_PI_2, height);
2583 
2584  const int ui = floorf(uf);
2585  const int vi = floorf(vf);
2586 
2587  *du = uf - ui;
2588  *dv = vf - vi;
2589 
2590  for (int i = 0; i < 4; i++) {
2591  for (int j = 0; j < 4; j++) {
2592  us[i][j] = av_clip(ui + j - 1, 0, width - 1);
2593  vs[i][j] = av_clip(vi + i - 1, 0, height - 1);
2594  }
2595  }
2596 
2597  return 1;
2598 }
2599 
2600 /**
2601  * Prepare data for processing equi-angular cubemap input format.
2602  *
2603  * @param ctx filter context
2604  *
2605  * @return error code
2606  */
2608 {
2609  V360Context *s = ctx->priv;
2610 
2611  s->in_cubemap_face_order[RIGHT] = TOP_RIGHT;
2612  s->in_cubemap_face_order[LEFT] = TOP_LEFT;
2613  s->in_cubemap_face_order[UP] = BOTTOM_RIGHT;
2614  s->in_cubemap_face_order[DOWN] = BOTTOM_LEFT;
2615  s->in_cubemap_face_order[FRONT] = TOP_MIDDLE;
2616  s->in_cubemap_face_order[BACK] = BOTTOM_MIDDLE;
2617 
2618  s->in_cubemap_face_rotation[TOP_LEFT] = ROT_0;
2619  s->in_cubemap_face_rotation[TOP_MIDDLE] = ROT_0;
2620  s->in_cubemap_face_rotation[TOP_RIGHT] = ROT_0;
2621  s->in_cubemap_face_rotation[BOTTOM_LEFT] = ROT_270;
2622  s->in_cubemap_face_rotation[BOTTOM_MIDDLE] = ROT_90;
2623  s->in_cubemap_face_rotation[BOTTOM_RIGHT] = ROT_270;
2624 
2625  return 0;
2626 }
2627 
2628 /**
2629  * Prepare data for processing equi-angular cubemap output format.
2630  *
2631  * @param ctx filter context
2632  *
2633  * @return error code
2634  */
2636 {
2637  V360Context *s = ctx->priv;
2638 
2639  s->out_cubemap_direction_order[TOP_LEFT] = LEFT;
2640  s->out_cubemap_direction_order[TOP_MIDDLE] = FRONT;
2641  s->out_cubemap_direction_order[TOP_RIGHT] = RIGHT;
2642  s->out_cubemap_direction_order[BOTTOM_LEFT] = DOWN;
2643  s->out_cubemap_direction_order[BOTTOM_MIDDLE] = BACK;
2644  s->out_cubemap_direction_order[BOTTOM_RIGHT] = UP;
2645 
2646  s->out_cubemap_face_rotation[TOP_LEFT] = ROT_0;
2647  s->out_cubemap_face_rotation[TOP_MIDDLE] = ROT_0;
2648  s->out_cubemap_face_rotation[TOP_RIGHT] = ROT_0;
2649  s->out_cubemap_face_rotation[BOTTOM_LEFT] = ROT_270;
2650  s->out_cubemap_face_rotation[BOTTOM_MIDDLE] = ROT_90;
2651  s->out_cubemap_face_rotation[BOTTOM_RIGHT] = ROT_270;
2652 
2653  return 0;
2654 }
2655 
2656 /**
2657  * Calculate 3D coordinates on sphere for corresponding frame position in equi-angular cubemap format.
2658  *
2659  * @param s filter private context
2660  * @param i horizontal position on frame [0, width)
2661  * @param j vertical position on frame [0, height)
2662  * @param width frame width
2663  * @param height frame height
2664  * @param vec coordinates on sphere
2665  */
2666 static int eac_to_xyz(const V360Context *s,
2667  int i, int j, int width, int height,
2668  float *vec)
2669 {
2670  const float pixel_pad = 2;
2671  const float u_pad = pixel_pad / width;
2672  const float v_pad = pixel_pad / height;
2673 
2674  int u_face, v_face, face;
2675 
2676  float l_x, l_y, l_z;
2677 
2678  float uf = (i + 0.5f) / width;
2679  float vf = (j + 0.5f) / height;
2680 
2681  // EAC has 2-pixel padding on faces except between faces on the same row
2682  // Padding pixels seems not to be stretched with tangent as regular pixels
2683  // Formulas below approximate original padding as close as I could get experimentally
2684 
2685  // Horizontal padding
2686  uf = 3.f * (uf - u_pad) / (1.f - 2.f * u_pad);
2687  if (uf < 0.f) {
2688  u_face = 0;
2689  uf -= 0.5f;
2690  } else if (uf >= 3.f) {
2691  u_face = 2;
2692  uf -= 2.5f;
2693  } else {
2694  u_face = floorf(uf);
2695  uf = fmodf(uf, 1.f) - 0.5f;
2696  }
2697 
2698  // Vertical padding
2699  v_face = floorf(vf * 2.f);
2700  vf = (vf - v_pad - 0.5f * v_face) / (0.5f - 2.f * v_pad) - 0.5f;
2701 
2702  if (uf >= -0.5f && uf < 0.5f) {
2703  uf = tanf(M_PI_2 * uf);
2704  } else {
2705  uf = 2.f * uf;
2706  }
2707  if (vf >= -0.5f && vf < 0.5f) {
2708  vf = tanf(M_PI_2 * vf);
2709  } else {
2710  vf = 2.f * vf;
2711  }
2712 
2713  face = u_face + 3 * v_face;
2714 
2715  switch (face) {
2716  case TOP_LEFT:
2717  l_x = -1.f;
2718  l_y = vf;
2719  l_z = uf;
2720  break;
2721  case TOP_MIDDLE:
2722  l_x = uf;
2723  l_y = vf;
2724  l_z = 1.f;
2725  break;
2726  case TOP_RIGHT:
2727  l_x = 1.f;
2728  l_y = vf;
2729  l_z = -uf;
2730  break;
2731  case BOTTOM_LEFT:
2732  l_x = -vf;
2733  l_y = 1.f;
2734  l_z = -uf;
2735  break;
2736  case BOTTOM_MIDDLE:
2737  l_x = -vf;
2738  l_y = -uf;
2739  l_z = -1.f;
2740  break;
2741  case BOTTOM_RIGHT:
2742  l_x = -vf;
2743  l_y = -1.f;
2744  l_z = uf;
2745  break;
2746  default:
2747  av_assert0(0);
2748  }
2749 
2750  vec[0] = l_x;
2751  vec[1] = l_y;
2752  vec[2] = l_z;
2753 
2754  return 1;
2755 }
2756 
2757 /**
2758  * Calculate frame position in equi-angular cubemap format for corresponding 3D coordinates on sphere.
2759  *
2760  * @param s filter private context
2761  * @param vec coordinates on sphere
2762  * @param width frame width
2763  * @param height frame height
2764  * @param us horizontal coordinates for interpolation window
2765  * @param vs vertical coordinates for interpolation window
2766  * @param du horizontal relative coordinate
2767  * @param dv vertical relative coordinate
2768  */
2769 static int xyz_to_eac(const V360Context *s,
2770  const float *vec, int width, int height,
2771  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2772 {
2773  const float pixel_pad = 2;
2774  const float u_pad = pixel_pad / width;
2775  const float v_pad = pixel_pad / height;
2776 
2777  float uf, vf;
2778  int ui, vi;
2779  int direction, face;
2780  int u_face, v_face;
2781 
2782  xyz_to_cube(s, vec, &uf, &vf, &direction);
2783 
2784  face = s->in_cubemap_face_order[direction];
2785  u_face = face % 3;
2786  v_face = face / 3;
2787 
2788  uf = M_2_PI * atanf(uf) + 0.5f;
2789  vf = M_2_PI * atanf(vf) + 0.5f;
2790 
2791  // These formulas are inversed from eac_to_xyz ones
2792  uf = (uf + u_face) * (1.f - 2.f * u_pad) / 3.f + u_pad;
2793  vf = vf * (0.5f - 2.f * v_pad) + v_pad + 0.5f * v_face;
2794 
2795  uf *= width;
2796  vf *= height;
2797 
2798  uf -= 0.5f;
2799  vf -= 0.5f;
2800 
2801  ui = floorf(uf);
2802  vi = floorf(vf);
2803 
2804  *du = uf - ui;
2805  *dv = vf - vi;
2806 
2807  for (int i = 0; i < 4; i++) {
2808  for (int j = 0; j < 4; j++) {
2809  us[i][j] = av_clip(ui + j - 1, 0, width - 1);
2810  vs[i][j] = av_clip(vi + i - 1, 0, height - 1);
2811  }
2812  }
2813 
2814  return 1;
2815 }
2816 
2817 /**
2818  * Prepare data for processing flat output format.
2819  *
2820  * @param ctx filter context
2821  *
2822  * @return error code
2823  */
2825 {
2826  V360Context *s = ctx->priv;
2827 
2828  s->flat_range[0] = tanf(0.5f * s->h_fov * M_PI / 180.f);
2829  s->flat_range[1] = tanf(0.5f * s->v_fov * M_PI / 180.f);
2830 
2831  return 0;
2832 }
2833 
2834 /**
2835  * Calculate 3D coordinates on sphere for corresponding frame position in flat format.
2836  *
2837  * @param s filter private context
2838  * @param i horizontal position on frame [0, width)
2839  * @param j vertical position on frame [0, height)
2840  * @param width frame width
2841  * @param height frame height
2842  * @param vec coordinates on sphere
2843  */
2844 static int flat_to_xyz(const V360Context *s,
2845  int i, int j, int width, int height,
2846  float *vec)
2847 {
2848  const float l_x = s->flat_range[0] * rescale(i, width);
2849  const float l_y = s->flat_range[1] * rescale(j, height);
2850 
2851  vec[0] = l_x;
2852  vec[1] = l_y;
2853  vec[2] = 1.f;
2854 
2855  return 1;
2856 }
2857 
2858 /**
2859  * Prepare data for processing fisheye output format.
2860  *
2861  * @param ctx filter context
2862  *
2863  * @return error code
2864  */
2866 {
2867  V360Context *s = ctx->priv;
2868 
2869  s->flat_range[0] = s->h_fov / 180.f;
2870  s->flat_range[1] = s->v_fov / 180.f;
2871 
2872  return 0;
2873 }
2874 
2875 /**
2876  * Calculate 3D coordinates on sphere for corresponding frame position in fisheye format.
2877  *
2878  * @param s filter private context
2879  * @param i horizontal position on frame [0, width)
2880  * @param j vertical position on frame [0, height)
2881  * @param width frame width
2882  * @param height frame height
2883  * @param vec coordinates on sphere
2884  */
2885 static int fisheye_to_xyz(const V360Context *s,
2886  int i, int j, int width, int height,
2887  float *vec)
2888 {
2889  const float uf = s->flat_range[0] * rescale(i, width);
2890  const float vf = s->flat_range[1] * rescale(j, height);
2891 
2892  const float phi = atan2f(vf, uf);
2893  const float theta = M_PI_2 * (1.f - hypotf(uf, vf));
2894 
2895  const float sin_phi = sinf(phi);
2896  const float cos_phi = cosf(phi);
2897  const float sin_theta = sinf(theta);
2898  const float cos_theta = cosf(theta);
2899 
2900  vec[0] = cos_theta * cos_phi;
2901  vec[1] = cos_theta * sin_phi;
2902  vec[2] = sin_theta;
2903 
2904  return 1;
2905 }
2906 
2907 /**
2908  * Prepare data for processing fisheye input format.
2909  *
2910  * @param ctx filter context
2911  *
2912  * @return error code
2913  */
2915 {
2916  V360Context *s = ctx->priv;
2917 
2918  s->iflat_range[0] = s->ih_fov / 180.f;
2919  s->iflat_range[1] = s->iv_fov / 180.f;
2920 
2921  return 0;
2922 }
2923 
2924 /**
2925  * Calculate frame position in fisheye format for corresponding 3D coordinates on sphere.
2926  *
2927  * @param s filter private context
2928  * @param vec coordinates on sphere
2929  * @param width frame width
2930  * @param height frame height
2931  * @param us horizontal coordinates for interpolation window
2932  * @param vs vertical coordinates for interpolation window
2933  * @param du horizontal relative coordinate
2934  * @param dv vertical relative coordinate
2935  */
2936 static int xyz_to_fisheye(const V360Context *s,
2937  const float *vec, int width, int height,
2938  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
2939 {
2940  const float h = hypotf(vec[0], vec[1]);
2941  const float lh = h > 0.f ? h : 1.f;
2942  const float phi = atan2f(h, vec[2]) / M_PI;
2943 
2944  float uf = vec[0] / lh * phi / s->iflat_range[0];
2945  float vf = vec[1] / lh * phi / s->iflat_range[1];
2946 
2947  const int visible = -0.5f < uf && uf < 0.5f && -0.5f < vf && vf < 0.5f;
2948  int ui, vi;
2949 
2950  uf = scale(uf * 2.f, width);
2951  vf = scale(vf * 2.f, height);
2952 
2953  ui = floorf(uf);
2954  vi = floorf(vf);
2955 
2956  *du = visible ? uf - ui : 0.f;
2957  *dv = visible ? vf - vi : 0.f;
2958 
2959  for (int i = 0; i < 4; i++) {
2960  for (int j = 0; j < 4; j++) {
2961  us[i][j] = visible ? av_clip(ui + j - 1, 0, width - 1) : 0;
2962  vs[i][j] = visible ? av_clip(vi + i - 1, 0, height - 1) : 0;
2963  }
2964  }
2965 
2966  return visible;
2967 }
2968 
2969 /**
2970  * Calculate 3D coordinates on sphere for corresponding frame position in pannini format.
2971  *
2972  * @param s filter private context
2973  * @param i horizontal position on frame [0, width)
2974  * @param j vertical position on frame [0, height)
2975  * @param width frame width
2976  * @param height frame height
2977  * @param vec coordinates on sphere
2978  */
2979 static int pannini_to_xyz(const V360Context *s,
2980  int i, int j, int width, int height,
2981  float *vec)
2982 {
2983  const float uf = rescale(i, width);
2984  const float vf = rescale(j, height);
2985 
2986  const float d = s->h_fov;
2987  const float k = uf * uf / ((d + 1.f) * (d + 1.f));
2988  const float dscr = k * k * d * d - (k + 1.f) * (k * d * d - 1.f);
2989  const float clon = (-k * d + sqrtf(dscr)) / (k + 1.f);
2990  const float S = (d + 1.f) / (d + clon);
2991  const float lon = atan2f(uf, S * clon);
2992  const float lat = atan2f(vf, S);
2993 
2994  vec[0] = sinf(lon) * cosf(lat);
2995  vec[1] = sinf(lat);
2996  vec[2] = cosf(lon) * cosf(lat);
2997 
2998  return 1;
2999 }
3000 
3001 /**
3002  * Calculate frame position in pannini format for corresponding 3D coordinates on sphere.
3003  *
3004  * @param s filter private context
3005  * @param vec coordinates on sphere
3006  * @param width frame width
3007  * @param height frame height
3008  * @param us horizontal coordinates for interpolation window
3009  * @param vs vertical coordinates for interpolation window
3010  * @param du horizontal relative coordinate
3011  * @param dv vertical relative coordinate
3012  */
3013 static int xyz_to_pannini(const V360Context *s,
3014  const float *vec, int width, int height,
3015  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3016 {
3017  const float phi = atan2f(vec[0], vec[2]);
3018  const float theta = asinf(vec[1]);
3019 
3020  const float d = s->ih_fov;
3021  const float S = (d + 1.f) / (d + cosf(phi));
3022 
3023  const float x = S * sinf(phi);
3024  const float y = S * tanf(theta);
3025 
3026  const float uf = scale(x, width);
3027  const float vf = scale(y, height);
3028 
3029  const int ui = floorf(uf);
3030  const int vi = floorf(vf);
3031 
3032  const int visible = vi >= 0 && vi < height && ui >= 0 && ui < width && vec[2] >= 0.f;
3033 
3034  *du = uf - ui;
3035  *dv = vf - vi;
3036 
3037  for (int i = 0; i < 4; i++) {
3038  for (int j = 0; j < 4; j++) {
3039  us[i][j] = visible ? av_clip(ui + j - 1, 0, width - 1) : 0;
3040  vs[i][j] = visible ? av_clip(vi + i - 1, 0, height - 1) : 0;
3041  }
3042  }
3043 
3044  return visible;
3045 }
3046 
3047 /**
3048  * Prepare data for processing cylindrical output format.
3049  *
3050  * @param ctx filter context
3051  *
3052  * @return error code
3053  */
3055 {
3056  V360Context *s = ctx->priv;
3057 
3058  s->flat_range[0] = M_PI * s->h_fov / 360.f;
3059  s->flat_range[1] = tanf(0.5f * s->v_fov * M_PI / 180.f);
3060 
3061  return 0;
3062 }
3063 
3064 /**
3065  * Calculate 3D coordinates on sphere for corresponding frame position in cylindrical format.
3066  *
3067  * @param s filter private context
3068  * @param i horizontal position on frame [0, width)
3069  * @param j vertical position on frame [0, height)
3070  * @param width frame width
3071  * @param height frame height
3072  * @param vec coordinates on sphere
3073  */
3075  int i, int j, int width, int height,
3076  float *vec)
3077 {
3078  const float uf = s->flat_range[0] * rescale(i, width);
3079  const float vf = s->flat_range[1] * rescale(j, height);
3080 
3081  const float phi = uf;
3082  const float theta = atanf(vf);
3083 
3084  const float sin_phi = sinf(phi);
3085  const float cos_phi = cosf(phi);
3086  const float sin_theta = sinf(theta);
3087  const float cos_theta = cosf(theta);
3088 
3089  vec[0] = cos_theta * sin_phi;
3090  vec[1] = sin_theta;
3091  vec[2] = cos_theta * cos_phi;
3092 
3093  return 1;
3094 }
3095 
3096 /**
3097  * Prepare data for processing cylindrical input format.
3098  *
3099  * @param ctx filter context
3100  *
3101  * @return error code
3102  */
3104 {
3105  V360Context *s = ctx->priv;
3106 
3107  s->iflat_range[0] = M_PI * s->ih_fov / 360.f;
3108  s->iflat_range[1] = tanf(0.5f * s->iv_fov * M_PI / 180.f);
3109 
3110  return 0;
3111 }
3112 
3113 /**
3114  * Calculate frame position in cylindrical format for corresponding 3D coordinates on sphere.
3115  *
3116  * @param s filter private context
3117  * @param vec coordinates on sphere
3118  * @param width frame width
3119  * @param height frame height
3120  * @param us horizontal coordinates for interpolation window
3121  * @param vs vertical coordinates for interpolation window
3122  * @param du horizontal relative coordinate
3123  * @param dv vertical relative coordinate
3124  */
3126  const float *vec, int width, int height,
3127  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3128 {
3129  const float phi = atan2f(vec[0], vec[2]) / s->iflat_range[0];
3130  const float theta = asinf(vec[1]);
3131 
3132  const float uf = scale(phi, width);
3133  const float vf = scale(tanf(theta) / s->iflat_range[1], height);
3134 
3135  const int ui = floorf(uf);
3136  const int vi = floorf(vf);
3137 
3138  const int visible = vi >= 0 && vi < height && ui >= 0 && ui < width &&
3139  theta <= M_PI * s->iv_fov / 180.f &&
3140  theta >= -M_PI * s->iv_fov / 180.f;
3141 
3142  *du = uf - ui;
3143  *dv = vf - vi;
3144 
3145  for (int i = 0; i < 4; i++) {
3146  for (int j = 0; j < 4; j++) {
3147  us[i][j] = visible ? av_clip(ui + j - 1, 0, width - 1) : 0;
3148  vs[i][j] = visible ? av_clip(vi + i - 1, 0, height - 1) : 0;
3149  }
3150  }
3151 
3152  return visible;
3153 }
3154 
3155 /**
3156  * Prepare data for processing cylindrical equal area output format.
3157  *
3158  * @param ctx filter context
3159  *
3160  * @return error code
3161  */
3163 {
3164  V360Context *s = ctx->priv;
3165 
3166  s->flat_range[0] = s->h_fov * M_PI / 360.f;
3167  s->flat_range[1] = s->v_fov / 180.f;
3168 
3169  return 0;
3170 }
3171 
3172 /**
3173  * Prepare data for processing cylindrical equal area input format.
3174  *
3175  * @param ctx filter context
3176  *
3177  * @return error code
3178  */
3180 {
3181  V360Context *s = ctx->priv;
3182 
3183  s->iflat_range[0] = M_PI * s->ih_fov / 360.f;
3184  s->iflat_range[1] = s->iv_fov / 180.f;
3185 
3186  return 0;
3187 }
3188 
3189 /**
3190  * Calculate 3D coordinates on sphere for corresponding frame position in cylindrical equal area format.
3191  *
3192  * @param s filter private context
3193  * @param i horizontal position on frame [0, width)
3194  * @param j vertical position on frame [0, height)
3195  * @param width frame width
3196  * @param height frame height
3197  * @param vec coordinates on sphere
3198  */
3200  int i, int j, int width, int height,
3201  float *vec)
3202 {
3203  const float uf = s->flat_range[0] * rescale(i, width);
3204  const float vf = s->flat_range[1] * rescale(j, height);
3205 
3206  const float phi = uf;
3207  const float theta = asinf(vf);
3208 
3209  const float sin_phi = sinf(phi);
3210  const float cos_phi = cosf(phi);
3211  const float sin_theta = sinf(theta);
3212  const float cos_theta = cosf(theta);
3213 
3214  vec[0] = cos_theta * sin_phi;
3215  vec[1] = sin_theta;
3216  vec[2] = cos_theta * cos_phi;
3217 
3218  return 1;
3219 }
3220 
3221 /**
3222  * Calculate frame position in cylindrical equal area format for corresponding 3D coordinates on sphere.
3223  *
3224  * @param s filter private context
3225  * @param vec coordinates on sphere
3226  * @param width frame width
3227  * @param height frame height
3228  * @param us horizontal coordinates for interpolation window
3229  * @param vs vertical coordinates for interpolation window
3230  * @param du horizontal relative coordinate
3231  * @param dv vertical relative coordinate
3232  */
3234  const float *vec, int width, int height,
3235  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3236 {
3237  const float phi = atan2f(vec[0], vec[2]) / s->iflat_range[0];
3238  const float theta = asinf(vec[1]);
3239 
3240  const float uf = scale(phi, width);
3241  const float vf = scale(sinf(theta) / s->iflat_range[1], height);
3242 
3243  const int ui = floorf(uf);
3244  const int vi = floorf(vf);
3245 
3246  const int visible = vi >= 0 && vi < height && ui >= 0 && ui < width &&
3247  theta <= M_PI * s->iv_fov / 180.f &&
3248  theta >= -M_PI * s->iv_fov / 180.f;
3249 
3250  *du = uf - ui;
3251  *dv = vf - vi;
3252 
3253  for (int i = 0; i < 4; i++) {
3254  for (int j = 0; j < 4; j++) {
3255  us[i][j] = visible ? av_clip(ui + j - 1, 0, width - 1) : 0;
3256  vs[i][j] = visible ? av_clip(vi + i - 1, 0, height - 1) : 0;
3257  }
3258  }
3259 
3260  return visible;
3261 }
3262 
3263 /**
3264  * Calculate 3D coordinates on sphere for corresponding frame position in perspective format.
3265  *
3266  * @param s filter private context
3267  * @param i horizontal position on frame [0, width)
3268  * @param j vertical position on frame [0, height)
3269  * @param width frame width
3270  * @param height frame height
3271  * @param vec coordinates on sphere
3272  */
3274  int i, int j, int width, int height,
3275  float *vec)
3276 {
3277  const float uf = rescale(i, width);
3278  const float vf = rescale(j, height);
3279  const float rh = hypotf(uf, vf);
3280  const float sinzz = 1.f - rh * rh;
3281  const float h = 1.f + s->v_fov;
3282  const float sinz = (h - sqrtf(sinzz)) / (h / rh + rh / h);
3283  const float sinz2 = sinz * sinz;
3284 
3285  if (sinz2 <= 1.f) {
3286  const float cosz = sqrtf(1.f - sinz2);
3287 
3288  const float theta = asinf(cosz);
3289  const float phi = atan2f(uf, vf);
3290 
3291  const float sin_phi = sinf(phi);
3292  const float cos_phi = cosf(phi);
3293  const float sin_theta = sinf(theta);
3294  const float cos_theta = cosf(theta);
3295 
3296  vec[0] = cos_theta * sin_phi;
3297  vec[1] = cos_theta * cos_phi;
3298  vec[2] = sin_theta;
3299  } else {
3300  vec[0] = 0.f;
3301  vec[1] = 1.f;
3302  vec[2] = 0.f;
3303  return 0;
3304  }
3305 
3306  return 1;
3307 }
3308 
3309 /**
3310  * Calculate 3D coordinates on sphere for corresponding frame position in tetrahedron format.
3311  *
3312  * @param s filter private context
3313  * @param i horizontal position on frame [0, width)
3314  * @param j vertical position on frame [0, height)
3315  * @param width frame width
3316  * @param height frame height
3317  * @param vec coordinates on sphere
3318  */
3320  int i, int j, int width, int height,
3321  float *vec)
3322 {
3323  const float uf = ((float)i + 0.5f) / width;
3324  const float vf = ((float)j + 0.5f) / height;
3325 
3326  vec[0] = uf < 0.5f ? uf * 4.f - 1.f : 3.f - uf * 4.f;
3327  vec[1] = 1.f - vf * 2.f;
3328  vec[2] = 2.f * fabsf(1.f - fabsf(1.f - uf * 2.f + vf)) - 1.f;
3329 
3330  return 1;
3331 }
3332 
3333 /**
3334  * Calculate frame position in tetrahedron format for corresponding 3D coordinates on sphere.
3335  *
3336  * @param s filter private context
3337  * @param vec coordinates on sphere
3338  * @param width frame width
3339  * @param height frame height
3340  * @param us horizontal coordinates for interpolation window
3341  * @param vs vertical coordinates for interpolation window
3342  * @param du horizontal relative coordinate
3343  * @param dv vertical relative coordinate
3344  */
3346  const float *vec, int width, int height,
3347  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3348 {
3349  const float d0 = vec[0] * 1.f + vec[1] * 1.f + vec[2] *-1.f;
3350  const float d1 = vec[0] *-1.f + vec[1] *-1.f + vec[2] *-1.f;
3351  const float d2 = vec[0] * 1.f + vec[1] *-1.f + vec[2] * 1.f;
3352  const float d3 = vec[0] *-1.f + vec[1] * 1.f + vec[2] * 1.f;
3353  const float d = FFMAX(d0, FFMAX3(d1, d2, d3));
3354 
3355  float uf, vf, x, y, z;
3356  int ui, vi;
3357 
3358  x = vec[0] / d;
3359  y = vec[1] / d;
3360  z = -vec[2] / d;
3361 
3362  vf = 0.5f - y * 0.5f;
3363 
3364  if ((x + y >= 0.f && y + z >= 0.f && -z - x <= 0.f) ||
3365  (x + y <= 0.f && -y + z >= 0.f && z - x >= 0.f)) {
3366  uf = 0.25f * x + 0.25f;
3367  } else {
3368  uf = 0.75f - 0.25f * x;
3369  }
3370 
3371  uf *= width;
3372  vf *= height;
3373 
3374  ui = floorf(uf);
3375  vi = floorf(vf);
3376 
3377  *du = uf - ui;
3378  *dv = vf - vi;
3379 
3380  for (int i = 0; i < 4; i++) {
3381  for (int j = 0; j < 4; j++) {
3382  us[i][j] = reflectx(ui + j - 1, vi + i - 1, width, height);
3383  vs[i][j] = reflecty(vi + i - 1, height);
3384  }
3385  }
3386 
3387  return 1;
3388 }
3389 
3390 /**
3391  * Prepare data for processing double fisheye input format.
3392  *
3393  * @param ctx filter context
3394  *
3395  * @return error code
3396  */
3398 {
3399  V360Context *s = ctx->priv;
3400 
3401  s->iflat_range[0] = s->ih_fov / 360.f;
3402  s->iflat_range[1] = s->iv_fov / 360.f;
3403 
3404  return 0;
3405 }
3406 
3407 /**
3408  * Calculate 3D coordinates on sphere for corresponding frame position in dual fisheye format.
3409  *
3410  * @param s filter private context
3411  * @param i horizontal position on frame [0, width)
3412  * @param j vertical position on frame [0, height)
3413  * @param width frame width
3414  * @param height frame height
3415  * @param vec coordinates on sphere
3416  */
3417 static int dfisheye_to_xyz(const V360Context *s,
3418  int i, int j, int width, int height,
3419  float *vec)
3420 {
3421  const float ew = width * 0.5f;
3422  const float eh = height;
3423 
3424  const int ei = i >= ew ? i - ew : i;
3425  const float m = i >= ew ? 1.f : -1.f;
3426 
3427  const float uf = s->flat_range[0] * rescale(ei, ew);
3428  const float vf = s->flat_range[1] * rescale(j, eh);
3429 
3430  const float h = hypotf(uf, vf);
3431  const float lh = h > 0.f ? h : 1.f;
3432  const float theta = m * M_PI_2 * (1.f - h);
3433 
3434  const float sin_theta = sinf(theta);
3435  const float cos_theta = cosf(theta);
3436 
3437  vec[0] = cos_theta * m * uf / lh;
3438  vec[1] = cos_theta * vf / lh;
3439  vec[2] = sin_theta;
3440 
3441  return 1;
3442 }
3443 
3444 /**
3445  * Calculate frame position in dual fisheye format for corresponding 3D coordinates on sphere.
3446  *
3447  * @param s filter private context
3448  * @param vec coordinates on sphere
3449  * @param width frame width
3450  * @param height frame height
3451  * @param us horizontal coordinates for interpolation window
3452  * @param vs vertical coordinates for interpolation window
3453  * @param du horizontal relative coordinate
3454  * @param dv vertical relative coordinate
3455  */
3456 static int xyz_to_dfisheye(const V360Context *s,
3457  const float *vec, int width, int height,
3458  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3459 {
3460  const float ew = width * 0.5f;
3461  const float eh = height;
3462 
3463  const float h = hypotf(vec[0], vec[1]);
3464  const float lh = h > 0.f ? h : 1.f;
3465  const float theta = acosf(fabsf(vec[2])) / M_PI;
3466 
3467  float uf = scale(theta * (vec[0] / lh) / s->iflat_range[0], ew);
3468  float vf = scale(theta * (vec[1] / lh) / s->iflat_range[1], eh);
3469 
3470  int ui, vi;
3471  int u_shift;
3472 
3473  if (vec[2] >= 0.f) {
3474  u_shift = ceilf(ew);
3475  } else {
3476  u_shift = 0;
3477  uf = ew - uf - 1.f;
3478  }
3479 
3480  ui = floorf(uf);
3481  vi = floorf(vf);
3482 
3483  *du = uf - ui;
3484  *dv = vf - vi;
3485 
3486  for (int i = 0; i < 4; i++) {
3487  for (int j = 0; j < 4; j++) {
3488  us[i][j] = u_shift + av_clip(ui + j - 1, 0, ew - 1);
3489  vs[i][j] = av_clip( vi + i - 1, 0, height - 1);
3490  }
3491  }
3492 
3493  return 1;
3494 }
3495 
3496 /**
3497  * Calculate 3D coordinates on sphere for corresponding frame position in barrel facebook's format.
3498  *
3499  * @param s filter private context
3500  * @param i horizontal position on frame [0, width)
3501  * @param j vertical position on frame [0, height)
3502  * @param width frame width
3503  * @param height frame height
3504  * @param vec coordinates on sphere
3505  */
3506 static int barrel_to_xyz(const V360Context *s,
3507  int i, int j, int width, int height,
3508  float *vec)
3509 {
3510  const float scale = 0.99f;
3511  float l_x, l_y, l_z;
3512 
3513  if (i < 4 * width / 5) {
3514  const float theta_range = M_PI_4;
3515 
3516  const int ew = 4 * width / 5;
3517  const int eh = height;
3518 
3519  const float phi = rescale(i, ew) * M_PI / scale;
3520  const float theta = rescale(j, eh) * theta_range / scale;
3521 
3522  const float sin_phi = sinf(phi);
3523  const float cos_phi = cosf(phi);
3524  const float sin_theta = sinf(theta);
3525  const float cos_theta = cosf(theta);
3526 
3527  l_x = cos_theta * sin_phi;
3528  l_y = sin_theta;
3529  l_z = cos_theta * cos_phi;
3530  } else {
3531  const int ew = width / 5;
3532  const int eh = height / 2;
3533 
3534  float uf, vf;
3535 
3536  if (j < eh) { // UP
3537  uf = rescale(i - 4 * ew, ew);
3538  vf = rescale(j, eh);
3539 
3540  uf /= scale;
3541  vf /= scale;
3542 
3543  l_x = uf;
3544  l_y = -1.f;
3545  l_z = vf;
3546  } else { // DOWN
3547  uf = rescale(i - 4 * ew, ew);
3548  vf = rescale(j - eh, eh);
3549 
3550  uf /= scale;
3551  vf /= scale;
3552 
3553  l_x = uf;
3554  l_y = 1.f;
3555  l_z = -vf;
3556  }
3557  }
3558 
3559  vec[0] = l_x;
3560  vec[1] = l_y;
3561  vec[2] = l_z;
3562 
3563  return 1;
3564 }
3565 
3566 /**
3567  * Calculate frame position in barrel facebook's format for corresponding 3D coordinates on sphere.
3568  *
3569  * @param s filter private context
3570  * @param vec coordinates on sphere
3571  * @param width frame width
3572  * @param height frame height
3573  * @param us horizontal coordinates for interpolation window
3574  * @param vs vertical coordinates for interpolation window
3575  * @param du horizontal relative coordinate
3576  * @param dv vertical relative coordinate
3577  */
3578 static int xyz_to_barrel(const V360Context *s,
3579  const float *vec, int width, int height,
3580  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3581 {
3582  const float scale = 0.99f;
3583 
3584  const float phi = atan2f(vec[0], vec[2]);
3585  const float theta = asinf(vec[1]);
3586  const float theta_range = M_PI_4;
3587 
3588  int ew, eh;
3589  int u_shift, v_shift;
3590  float uf, vf;
3591  int ui, vi;
3592 
3593  if (theta > -theta_range && theta < theta_range) {
3594  ew = 4 * width / 5;
3595  eh = height;
3596 
3597  u_shift = 0;
3598  v_shift = 0;
3599 
3600  uf = (phi / M_PI * scale + 1.f) * ew / 2.f;
3601  vf = (theta / theta_range * scale + 1.f) * eh / 2.f;
3602  } else {
3603  ew = width / 5;
3604  eh = height / 2;
3605 
3606  u_shift = 4 * ew;
3607 
3608  if (theta < 0.f) { // UP
3609  uf = -vec[0] / vec[1];
3610  vf = -vec[2] / vec[1];
3611  v_shift = 0;
3612  } else { // DOWN
3613  uf = vec[0] / vec[1];
3614  vf = -vec[2] / vec[1];
3615  v_shift = eh;
3616  }
3617 
3618  uf = 0.5f * ew * (uf * scale + 1.f);
3619  vf = 0.5f * eh * (vf * scale + 1.f);
3620  }
3621 
3622  ui = floorf(uf);
3623  vi = floorf(vf);
3624 
3625  *du = uf - ui;
3626  *dv = vf - vi;
3627 
3628  for (int i = 0; i < 4; i++) {
3629  for (int j = 0; j < 4; j++) {
3630  us[i][j] = u_shift + av_clip(ui + j - 1, 0, ew - 1);
3631  vs[i][j] = v_shift + av_clip(vi + i - 1, 0, eh - 1);
3632  }
3633  }
3634 
3635  return 1;
3636 }
3637 
3638 /**
3639  * Calculate frame position in barrel split facebook's format for corresponding 3D coordinates on sphere.
3640  *
3641  * @param s filter private context
3642  * @param vec coordinates on sphere
3643  * @param width frame width
3644  * @param height frame height
3645  * @param us horizontal coordinates for interpolation window
3646  * @param vs vertical coordinates for interpolation window
3647  * @param du horizontal relative coordinate
3648  * @param dv vertical relative coordinate
3649  */
3651  const float *vec, int width, int height,
3652  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3653 {
3654  const float phi = atan2f(vec[0], vec[2]);
3655  const float theta = asinf(vec[1]);
3656 
3657  const float theta_range = M_PI_4;
3658 
3659  int ew, eh;
3660  int u_shift, v_shift;
3661  float uf, vf;
3662  int ui, vi;
3663 
3664  if (theta >= -theta_range && theta <= theta_range) {
3665  const float scalew = s->fin_pad > 0 ? 1.f - s->fin_pad / (width * 2.f / 3.f) : 1.f - s->in_pad;
3666  const float scaleh = s->fin_pad > 0 ? 1.f - s->fin_pad / (height / 2.f) : 1.f - s->in_pad;
3667 
3668  ew = width / 3 * 2;
3669  eh = height / 2;
3670 
3671  u_shift = 0;
3672  v_shift = phi >= M_PI_2 || phi < -M_PI_2 ? eh : 0;
3673 
3674  uf = fmodf(phi, M_PI_2) / M_PI_2;
3675  vf = theta / M_PI_4;
3676 
3677  if (v_shift)
3678  uf = uf >= 0.f ? fmodf(uf - 1.f, 1.f) : fmodf(uf + 1.f, 1.f);
3679 
3680  uf = (uf * scalew + 1.f) * width / 3.f;
3681  vf = (vf * scaleh + 1.f) * height / 4.f;
3682  } else {
3683  const float scalew = s->fin_pad > 0 ? 1.f - s->fin_pad / (width / 3.f) : 1.f - s->in_pad;
3684  const float scaleh = s->fin_pad > 0 ? 1.f - s->fin_pad / (height / 4.f) : 1.f - s->in_pad;
3685 
3686  ew = width / 3;
3687  eh = height / 4;
3688 
3689  u_shift = 2 * ew;
3690 
3691  uf = vec[0] / vec[1] * scalew;
3692  vf = vec[2] / vec[1] * scaleh;
3693 
3694  if (theta <= 0.f && theta >= -M_PI_2 &&
3695  phi <= M_PI_2 && phi >= -M_PI_2) {
3696  // front top
3697  uf *= -1.0f;
3698  vf = -(vf + 1.f) * scaleh + 1.f;
3699  v_shift = 0;
3700  } else if (theta >= 0.f && theta <= M_PI_2 &&
3701  phi <= M_PI_2 && phi >= -M_PI_2) {
3702  // front bottom
3703  vf = -(vf - 1.f) * scaleh;
3704  v_shift = height * 0.25f;
3705  } else if (theta <= 0.f && theta >= -M_PI_2) {
3706  // back top
3707  vf = (vf - 1.f) * scaleh + 1.f;
3708  v_shift = height * 0.5f;
3709  } else {
3710  // back bottom
3711  uf *= -1.0f;
3712  vf = (vf + 1.f) * scaleh;
3713  v_shift = height * 0.75f;
3714  }
3715 
3716  uf = 0.5f * width / 3.f * (uf + 1.f);
3717  vf *= height * 0.25f;
3718  }
3719 
3720  ui = floorf(uf);
3721  vi = floorf(vf);
3722 
3723  *du = uf - ui;
3724  *dv = vf - vi;
3725 
3726  for (int i = 0; i < 4; i++) {
3727  for (int j = 0; j < 4; j++) {
3728  us[i][j] = u_shift + av_clip(ui + j - 1, 0, ew - 1);
3729  vs[i][j] = v_shift + av_clip(vi + i - 1, 0, eh - 1);
3730  }
3731  }
3732 
3733  return 1;
3734 }
3735 
3736 /**
3737  * Calculate 3D coordinates on sphere for corresponding frame position in barrel split facebook's format.
3738  *
3739  * @param s filter private context
3740  * @param i horizontal position on frame [0, width)
3741  * @param j vertical position on frame [0, height)
3742  * @param width frame width
3743  * @param height frame height
3744  * @param vec coordinates on sphere
3745  */
3747  int i, int j, int width, int height,
3748  float *vec)
3749 {
3750  const float x = (i + 0.5f) / width;
3751  const float y = (j + 0.5f) / height;
3752  float l_x, l_y, l_z;
3753  int ret;
3754 
3755  if (x < 2.f / 3.f) {
3756  const float scalew = s->fout_pad > 0 ? 1.f - s->fout_pad / (width * 2.f / 3.f) : 1.f - s->out_pad;
3757  const float scaleh = s->fout_pad > 0 ? 1.f - s->fout_pad / (height / 2.f) : 1.f - s->out_pad;
3758 
3759  const float back = floorf(y * 2.f);
3760 
3761  const float phi = ((3.f / 2.f * x - 0.5f) / scalew - back) * M_PI;
3762  const float theta = (y - 0.25f - 0.5f * back) / scaleh * M_PI;
3763 
3764  const float sin_phi = sinf(phi);
3765  const float cos_phi = cosf(phi);
3766  const float sin_theta = sinf(theta);
3767  const float cos_theta = cosf(theta);
3768 
3769  l_x = cos_theta * sin_phi;
3770  l_y = sin_theta;
3771  l_z = cos_theta * cos_phi;
3772 
3773  ret = 1;
3774  } else {
3775  const float scalew = s->fout_pad > 0 ? 1.f - s->fout_pad / (width / 3.f) : 1.f - s->out_pad;
3776  const float scaleh = s->fout_pad > 0 ? 1.f - s->fout_pad / (height / 4.f) : 1.f - s->out_pad;
3777 
3778  const float facef = floorf(y * 4.f);
3779  const int face = facef;
3780  const float dir_vert = (face == 1 || face == 3) ? 1.0f : -1.0f;
3781  float uf, vf;
3782 
3783  uf = x * 3.f - 2.f;
3784 
3785  switch (face) {
3786  case 0: // front top
3787  case 1: // front bottom
3788  uf = 1.f - uf;
3789  vf = (0.5f - 2.f * y) / scaleh + facef;
3790  break;
3791  case 2: // back top
3792  case 3: // back bottom
3793  vf = (y * 2.f - 1.5f) / scaleh + 3.f - facef;
3794  break;
3795  default:
3796  av_assert0(0);
3797  }
3798  l_x = (0.5f - uf) / scalew;
3799  l_y = 0.5f * dir_vert;
3800  l_z = (vf - 0.5f) * dir_vert / scaleh;
3801  ret = (l_x * l_x * scalew * scalew + l_z * l_z * scaleh * scaleh) < 0.5f * 0.5f;
3802  }
3803 
3804  vec[0] = l_x;
3805  vec[1] = l_y;
3806  vec[2] = l_z;
3807 
3808  return ret;
3809 }
3810 
3811 /**
3812  * Calculate 3D coordinates on sphere for corresponding frame position in tspyramid format.
3813  *
3814  * @param s filter private context
3815  * @param i horizontal position on frame [0, width)
3816  * @param j vertical position on frame [0, height)
3817  * @param width frame width
3818  * @param height frame height
3819  * @param vec coordinates on sphere
3820  */
3821 static int tspyramid_to_xyz(const V360Context *s,
3822  int i, int j, int width, int height,
3823  float *vec)
3824 {
3825  const float x = (i + 0.5f) / width;
3826  const float y = (j + 0.5f) / height;
3827 
3828  if (x < 0.5f) {
3829  vec[0] = x * 4.f - 1.f;
3830  vec[1] = (y * 2.f - 1.f);
3831  vec[2] = 1.f;
3832  } else if (x >= 0.6875f && x < 0.8125f &&
3833  y >= 0.375f && y < 0.625f) {
3834  vec[0] = -(x - 0.6875f) * 16.f + 1.f;
3835  vec[1] = (y - 0.375f) * 8.f - 1.f;
3836  vec[2] = -1.f;
3837  } else if (0.5f <= x && x < 0.6875f &&
3838  ((0.f <= y && y < 0.375f && y >= 2.f * (x - 0.5f)) ||
3839  (0.375f <= y && y < 0.625f) ||
3840  (0.625f <= y && y < 1.f && y <= 2.f * (1.f - x)))) {
3841  vec[0] = 1.f;
3842  vec[1] = 2.f * (y - 2.f * x + 1.f) / (3.f - 4.f * x) - 1.f;
3843  vec[2] = -2.f * (x - 0.5f) / 0.1875f + 1.f;
3844  } else if (0.8125f <= x && x < 1.f &&
3845  ((0.f <= y && y < 0.375f && x >= (1.f - y / 2.f)) ||
3846  (0.375f <= y && y < 0.625f) ||
3847  (0.625f <= y && y < 1.f && y <= (2.f * x - 1.f)))) {
3848  vec[0] = -1.f;
3849  vec[1] = 2.f * (y + 2.f * x - 2.f) / (4.f * x - 3.f) - 1.f;
3850  vec[2] = 2.f * (x - 0.8125f) / 0.1875f - 1.f;
3851  } else if (0.f <= y && y < 0.375f &&
3852  ((0.5f <= x && x < 0.8125f && y < 2.f * (x - 0.5f)) ||
3853  (0.6875f <= x && x < 0.8125f) ||
3854  (0.8125f <= x && x < 1.f && x < (1.f - y / 2.f)))) {
3855  vec[0] = 2.f * (1.f - x - 0.5f * y) / (0.5f - y) - 1.f;
3856  vec[1] = -1.f;
3857  vec[2] = 2.f * (0.375f - y) / 0.375f - 1.f;
3858  } else {
3859  vec[0] = 2.f * (0.5f - x + 0.5f * y) / (y - 0.5f) - 1.f;
3860  vec[1] = 1.f;
3861  vec[2] = -2.f * (1.f - y) / 0.375f + 1.f;
3862  }
3863 
3864  return 1;
3865 }
3866 
3867 /**
3868  * Calculate frame position in tspyramid format for corresponding 3D coordinates on sphere.
3869  *
3870  * @param s filter private context
3871  * @param vec coordinates on sphere
3872  * @param width frame width
3873  * @param height frame height
3874  * @param us horizontal coordinates for interpolation window
3875  * @param vs vertical coordinates for interpolation window
3876  * @param du horizontal relative coordinate
3877  * @param dv vertical relative coordinate
3878  */
3879 static int xyz_to_tspyramid(const V360Context *s,
3880  const float *vec, int width, int height,
3881  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3882 {
3883  float uf, vf;
3884  int ui, vi;
3885  int face;
3886 
3887  xyz_to_cube(s, vec, &uf, &vf, &face);
3888 
3889  uf = (uf + 1.f) * 0.5f;
3890  vf = (vf + 1.f) * 0.5f;
3891 
3892  switch (face) {
3893  case UP:
3894  uf = 0.1875f * vf - 0.375f * uf * vf - 0.125f * uf + 0.8125f;
3895  vf = 0.375f - 0.375f * vf;
3896  break;
3897  case FRONT:
3898  uf = 0.5f * uf;
3899  break;
3900  case DOWN:
3901  uf = 1.f - 0.1875f * vf - 0.5f * uf + 0.375f * uf * vf;
3902  vf = 1.f - 0.375f * vf;
3903  break;
3904  case LEFT:
3905  vf = 0.25f * vf + 0.75f * uf * vf - 0.375f * uf + 0.375f;
3906  uf = 0.1875f * uf + 0.8125f;
3907  break;
3908  case RIGHT:
3909  vf = 0.375f * uf - 0.75f * uf * vf + vf;
3910  uf = 0.1875f * uf + 0.5f;
3911  break;
3912  case BACK:
3913  uf = 0.125f * uf + 0.6875f;
3914  vf = 0.25f * vf + 0.375f;
3915  break;
3916  }
3917 
3918  uf *= width;
3919  vf *= height;
3920 
3921  ui = floorf(uf);
3922  vi = floorf(vf);
3923 
3924  *du = uf - ui;
3925  *dv = vf - vi;
3926 
3927  for (int i = 0; i < 4; i++) {
3928  for (int j = 0; j < 4; j++) {
3929  us[i][j] = reflectx(ui + j - 1, vi + i - 1, width, height);
3930  vs[i][j] = reflecty(vi + i - 1, height);
3931  }
3932  }
3933 
3934  return 1;
3935 }
3936 
3937 /**
3938  * Calculate 3D coordinates on sphere for corresponding frame position in octahedron format.
3939  *
3940  * @param s filter private context
3941  * @param i horizontal position on frame [0, width)
3942  * @param j vertical position on frame [0, height)
3943  * @param width frame width
3944  * @param height frame height
3945  * @param vec coordinates on sphere
3946  */
3947 static int octahedron_to_xyz(const V360Context *s,
3948  int i, int j, int width, int height,
3949  float *vec)
3950 {
3951  const float x = rescale(i, width);
3952  const float y = rescale(j, height);
3953  const float ax = fabsf(x);
3954  const float ay = fabsf(y);
3955 
3956  vec[2] = 1.f - (ax + ay);
3957  if (ax + ay > 1.f) {
3958  vec[0] = (1.f - ay) * FFSIGN(x);
3959  vec[1] = (1.f - ax) * FFSIGN(y);
3960  } else {
3961  vec[0] = x;
3962  vec[1] = y;
3963  }
3964 
3965  return 1;
3966 }
3967 
3968 /**
3969  * Calculate frame position in octahedron format for corresponding 3D coordinates on sphere.
3970  *
3971  * @param s filter private context
3972  * @param vec coordinates on sphere
3973  * @param width frame width
3974  * @param height frame height
3975  * @param us horizontal coordinates for interpolation window
3976  * @param vs vertical coordinates for interpolation window
3977  * @param du horizontal relative coordinate
3978  * @param dv vertical relative coordinate
3979  */
3980 static int xyz_to_octahedron(const V360Context *s,
3981  const float *vec, int width, int height,
3982  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3983 {
3984  float uf, vf, zf;
3985  int ui, vi;
3986  float div = fabsf(vec[0]) + fabsf(vec[1]) + fabsf(vec[2]);
3987 
3988  uf = vec[0] / div;
3989  vf = vec[1] / div;
3990  zf = vec[2];
3991 
3992  if (zf < 0.f) {
3993  zf = vf;
3994  vf = (1.f - fabsf(uf)) * FFSIGN(zf);
3995  uf = (1.f - fabsf(zf)) * FFSIGN(uf);
3996  }
3997 
3998  uf = scale(uf, width);
3999  vf = scale(vf, height);
4000 
4001  ui = floorf(uf);
4002  vi = floorf(vf);
4003 
4004  *du = uf - ui;
4005  *dv = vf - vi;
4006 
4007  for (int i = 0; i < 4; i++) {
4008  for (int j = 0; j < 4; j++) {
4009  us[i][j] = av_clip(ui + j - 1, 0, width - 1);
4010  vs[i][j] = av_clip(vi + i - 1, 0, height - 1);
4011  }
4012  }
4013 
4014  return 1;
4015 }
4016 
4017 static void multiply_quaternion(float c[4], const float a[4], const float b[4])
4018 {
4019  c[0] = a[0] * b[0] - a[1] * b[1] - a[2] * b[2] - a[3] * b[3];
4020  c[1] = a[1] * b[0] + a[0] * b[1] + a[2] * b[3] - a[3] * b[2];
4021  c[2] = a[2] * b[0] + a[0] * b[2] + a[3] * b[1] - a[1] * b[3];
4022  c[3] = a[3] * b[0] + a[0] * b[3] + a[1] * b[2] - a[2] * b[1];
4023 }
4024 
4025 static void conjugate_quaternion(float d[4], const float q[4])
4026 {
4027  d[0] = q[0];
4028  d[1] = -q[1];
4029  d[2] = -q[2];
4030  d[3] = -q[3];
4031 }
4032 
4033 /**
4034  * Calculate rotation quaternion for yaw/pitch/roll angles.
4035  */
4036 static inline void calculate_rotation(float yaw, float pitch, float roll,
4037  float rot_quaternion[2][4],
4038  const int rotation_order[3])
4039 {
4040  const float yaw_rad = yaw * M_PI / 180.f;
4041  const float pitch_rad = pitch * M_PI / 180.f;
4042  const float roll_rad = roll * M_PI / 180.f;
4043 
4044  const float sin_yaw = sinf(yaw_rad * 0.5f);
4045  const float cos_yaw = cosf(yaw_rad * 0.5f);
4046  const float sin_pitch = sinf(pitch_rad * 0.5f);
4047  const float cos_pitch = cosf(pitch_rad * 0.5f);
4048  const float sin_roll = sinf(roll_rad * 0.5f);
4049  const float cos_roll = cosf(roll_rad * 0.5f);
4050 
4051  float m[3][4];
4052  float tmp[2][4];
4053 
4054  m[0][0] = cos_yaw; m[0][1] = 0.f; m[0][2] = sin_yaw; m[0][3] = 0.f;
4055  m[1][0] = cos_pitch; m[1][1] = sin_pitch; m[1][2] = 0.f; m[1][3] = 0.f;
4056  m[2][0] = cos_roll; m[2][1] = 0.f; m[2][2] = 0.f; m[2][3] = sin_roll;
4057 
4058  multiply_quaternion(tmp[0], rot_quaternion[0], m[rotation_order[0]]);
4059  multiply_quaternion(tmp[1], tmp[0], m[rotation_order[1]]);
4060  multiply_quaternion(rot_quaternion[0], tmp[1], m[rotation_order[2]]);
4061 
4062  conjugate_quaternion(rot_quaternion[1], rot_quaternion[0]);
4063 }
4064 
4065 /**
4066  * Rotate vector with given rotation quaternion.
4067  *
4068  * @param rot_quaternion rotation quaternion
4069  * @param vec vector
4070  */
4071 static inline void rotate(const float rot_quaternion[2][4],
4072  float *vec)
4073 {
4074  float qv[4], temp[4], rqv[4];
4075 
4076  qv[0] = 0.f;
4077  qv[1] = vec[0];
4078  qv[2] = vec[1];
4079  qv[3] = vec[2];
4080 
4081  multiply_quaternion(temp, rot_quaternion[0], qv);
4082  multiply_quaternion(rqv, temp, rot_quaternion[1]);
4083 
4084  vec[0] = rqv[1];
4085  vec[1] = rqv[2];
4086  vec[2] = rqv[3];
4087 }
4088 
4089 static inline void set_mirror_modifier(int h_flip, int v_flip, int d_flip,
4090  float *modifier)
4091 {
4092  modifier[0] = h_flip ? -1.f : 1.f;
4093  modifier[1] = v_flip ? -1.f : 1.f;
4094  modifier[2] = d_flip ? -1.f : 1.f;
4095 }
4096 
4097 static inline void mirror(const float *modifier, float *vec)
4098 {
4099  vec[0] *= modifier[0];
4100  vec[1] *= modifier[1];
4101  vec[2] *= modifier[2];
4102 }
4103 
4104 static inline void input_flip(int16_t u[4][4], int16_t v[4][4], int w, int h, int hflip, int vflip)
4105 {
4106  if (hflip) {
4107  for (int i = 0; i < 4; i++) {
4108  for (int j = 0; j < 4; j++)
4109  u[i][j] = w - 1 - u[i][j];
4110  }
4111  }
4112 
4113  if (vflip) {
4114  for (int i = 0; i < 4; i++) {
4115  for (int j = 0; j < 4; j++)
4116  v[i][j] = h - 1 - v[i][j];
4117  }
4118  }
4119 }
4120 
4121 static int allocate_plane(V360Context *s, int sizeof_uv, int sizeof_ker, int sizeof_mask, int p)
4122 {
4123  const int pr_height = s->pr_height[p];
4124 
4125  for (int n = 0; n < s->nb_threads; n++) {
4126  SliceXYRemap *r = &s->slice_remap[n];
4127  const int slice_start = (pr_height * n ) / s->nb_threads;
4128  const int slice_end = (pr_height * (n + 1)) / s->nb_threads;
4129  const int height = slice_end - slice_start;
4130 
4131  if (!r->u[p])
4132  r->u[p] = av_calloc(s->uv_linesize[p] * height, sizeof_uv);
4133  if (!r->v[p])
4134  r->v[p] = av_calloc(s->uv_linesize[p] * height, sizeof_uv);
4135  if (!r->u[p] || !r->v[p])
4136  return AVERROR(ENOMEM);
4137  if (sizeof_ker) {
4138  if (!r->ker[p])
4139  r->ker[p] = av_calloc(s->uv_linesize[p] * height, sizeof_ker);
4140  if (!r->ker[p])
4141  return AVERROR(ENOMEM);
4142  }
4143 
4144  if (sizeof_mask && !p) {
4145  if (!r->mask)
4146  r->mask = av_calloc(s->pr_width[p] * height, sizeof_mask);
4147  if (!r->mask)
4148  return AVERROR(ENOMEM);
4149  }
4150  }
4151 
4152  return 0;
4153 }
4154 
4155 static void fov_from_dfov(int format, float d_fov, float w, float h, float *h_fov, float *v_fov)
4156 {
4157  switch (format) {
4158  case EQUIRECTANGULAR:
4159  *h_fov = d_fov;
4160  *v_fov = d_fov * 0.5f;
4161  break;
4162  case ORTHOGRAPHIC:
4163  {
4164  const float d = 0.5f * hypotf(w, h);
4165  const float l = sinf(d_fov * M_PI / 360.f) / d;
4166 
4167  *h_fov = asinf(w * 0.5f * l) * 360.f / M_PI;
4168  *v_fov = asinf(h * 0.5f * l) * 360.f / M_PI;
4169 
4170  if (d_fov > 180.f) {
4171  *h_fov = 180.f - *h_fov;
4172  *v_fov = 180.f - *v_fov;
4173  }
4174  }
4175  break;
4176  case EQUISOLID:
4177  {
4178  const float d = 0.5f * hypotf(w, h);
4179  const float l = d / (sinf(d_fov * M_PI / 720.f));
4180 
4181  *h_fov = 2.f * asinf(w * 0.5f / l) * 360.f / M_PI;
4182  *v_fov = 2.f * asinf(h * 0.5f / l) * 360.f / M_PI;
4183  }
4184  break;
4185  case STEREOGRAPHIC:
4186  {
4187  const float d = 0.5f * hypotf(w, h);
4188  const float l = d / (tanf(d_fov * M_PI / 720.f));
4189 
4190  *h_fov = 2.f * atan2f(w * 0.5f, l) * 360.f / M_PI;
4191  *v_fov = 2.f * atan2f(h * 0.5f, l) * 360.f / M_PI;
4192  }
4193  break;
4194  case DUAL_FISHEYE:
4195  {
4196  const float d = hypotf(w * 0.5f, h);
4197 
4198  *h_fov = 0.5f * w / d * d_fov;
4199  *v_fov = h / d * d_fov;
4200  }
4201  break;
4202  case FISHEYE:
4203  {
4204  const float d = hypotf(w, h);
4205 
4206  *h_fov = w / d * d_fov;
4207  *v_fov = h / d * d_fov;
4208  }
4209  break;
4210  case FLAT:
4211  default:
4212  {
4213  const float da = tanf(0.5f * FFMIN(d_fov, 359.f) * M_PI / 180.f);
4214  const float d = hypotf(w, h);
4215 
4216  *h_fov = atan2f(da * w, d) * 360.f / M_PI;
4217  *v_fov = atan2f(da * h, d) * 360.f / M_PI;
4218 
4219  if (*h_fov < 0.f)
4220  *h_fov += 360.f;
4221  if (*v_fov < 0.f)
4222  *v_fov += 360.f;
4223  }
4224  break;
4225  }
4226 }
4227 
4228 static void set_dimensions(int *outw, int *outh, int w, int h, const AVPixFmtDescriptor *desc)
4229 {
4230  outw[1] = outw[2] = AV_CEIL_RSHIFT(w, desc->log2_chroma_w);
4231  outw[0] = outw[3] = w;
4232  outh[1] = outh[2] = AV_CEIL_RSHIFT(h, desc->log2_chroma_h);
4233  outh[0] = outh[3] = h;
4234 }
4235 
4236 // Calculate remap data
4237 static int v360_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
4238 {
4239  V360Context *s = ctx->priv;
4240  SliceXYRemap *r = &s->slice_remap[jobnr];
4241 
4242  for (int p = 0; p < s->nb_allocated; p++) {
4243  const int max_value = s->max_value;
4244  const int width = s->pr_width[p];
4245  const int uv_linesize = s->uv_linesize[p];
4246  const int height = s->pr_height[p];
4247  const int in_width = s->inplanewidth[p];
4248  const int in_height = s->inplaneheight[p];
4249  const int slice_start = (height * jobnr ) / nb_jobs;
4250  const int slice_end = (height * (jobnr + 1)) / nb_jobs;
4251  const int elements = s->elements;
4252  float du, dv;
4253  float vec[3];
4254  XYRemap rmap;
4255 
4256  for (int j = slice_start; j < slice_end; j++) {
4257  for (int i = 0; i < width; i++) {
4258  int16_t *u = r->u[p] + ((j - slice_start) * uv_linesize + i) * elements;
4259  int16_t *v = r->v[p] + ((j - slice_start) * uv_linesize + i) * elements;
4260  int16_t *ker = r->ker[p] + ((j - slice_start) * uv_linesize + i) * elements;
4261  uint8_t *mask8 = p ? NULL : r->mask + ((j - slice_start) * s->pr_width[0] + i);
4262  uint16_t *mask16 = p ? NULL : (uint16_t *)r->mask + ((j - slice_start) * s->pr_width[0] + i);
4263  int in_mask, out_mask;
4264 
4265  if (s->out_transpose)
4266  out_mask = s->out_transform(s, j, i, height, width, vec);
4267  else
4268  out_mask = s->out_transform(s, i, j, width, height, vec);
4269  offset_vector(vec, s->h_offset, s->v_offset);
4270  normalize_vector(vec);
4271  av_assert1(!isnan(vec[0]) && !isnan(vec[1]) && !isnan(vec[2]));
4272  rotate(s->rot_quaternion, vec);
4273  av_assert1(!isnan(vec[0]) && !isnan(vec[1]) && !isnan(vec[2]));
4274  normalize_vector(vec);
4275  mirror(s->output_mirror_modifier, vec);
4276  if (s->in_transpose)
4277  in_mask = s->in_transform(s, vec, in_height, in_width, rmap.v, rmap.u, &du, &dv);
4278  else
4279  in_mask = s->in_transform(s, vec, in_width, in_height, rmap.u, rmap.v, &du, &dv);
4280  input_flip(rmap.u, rmap.v, in_width, in_height, s->ih_flip, s->iv_flip);
4281  av_assert1(!isnan(du) && !isnan(dv));
4282  s->calculate_kernel(du, dv, &rmap, u, v, ker);
4283 
4284  if (!p && r->mask) {
4285  if (s->mask_size == 1) {
4286  mask8[0] = 255 * (out_mask & in_mask);
4287  } else {
4288  mask16[0] = max_value * (out_mask & in_mask);
4289  }
4290  }
4291  }
4292  }
4293  }
4294 
4295  return 0;
4296 }
4297 
4298 static int config_output(AVFilterLink *outlink)
4299 {
4300  AVFilterContext *ctx = outlink->src;
4301  AVFilterLink *inlink = ctx->inputs[0];
4302  V360Context *s = ctx->priv;
4304  const int depth = desc->comp[0].depth;
4305  const int sizeof_mask = s->mask_size = (depth + 7) >> 3;
4306  float default_h_fov = 360.f;
4307  float default_v_fov = 180.f;
4308  float default_ih_fov = 360.f;
4309  float default_iv_fov = 180.f;
4310  int sizeof_uv;
4311  int sizeof_ker;
4312  int err;
4313  int h, w;
4314  int in_offset_h, in_offset_w;
4315  int out_offset_h, out_offset_w;
4316  float hf, wf;
4317  int (*prepare_out)(AVFilterContext *ctx);
4318  int have_alpha;
4319 
4320  s->max_value = (1 << depth) - 1;
4321 
4322  switch (s->interp) {
4323  case NEAREST:
4324  s->calculate_kernel = nearest_kernel;
4325  s->remap_slice = depth <= 8 ? remap1_8bit_slice : remap1_16bit_slice;
4326  s->elements = 1;
4327  sizeof_uv = sizeof(int16_t) * s->elements;
4328  sizeof_ker = 0;
4329  break;
4330  case BILINEAR:
4331  s->calculate_kernel = bilinear_kernel;
4332  s->remap_slice = depth <= 8 ? remap2_8bit_slice : remap2_16bit_slice;
4333  s->elements = 2 * 2;
4334  sizeof_uv = sizeof(int16_t) * s->elements;
4335  sizeof_ker = sizeof(int16_t) * s->elements;
4336  break;
4337  case LAGRANGE9:
4338  s->calculate_kernel = lagrange_kernel;
4339  s->remap_slice = depth <= 8 ? remap3_8bit_slice : remap3_16bit_slice;
4340  s->elements = 3 * 3;
4341  sizeof_uv = sizeof(int16_t) * s->elements;
4342  sizeof_ker = sizeof(int16_t) * s->elements;
4343  break;
4344  case BICUBIC:
4345  s->calculate_kernel = bicubic_kernel;
4346  s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice;
4347  s->elements = 4 * 4;
4348  sizeof_uv = sizeof(int16_t) * s->elements;
4349  sizeof_ker = sizeof(int16_t) * s->elements;
4350  break;
4351  case LANCZOS:
4352  s->calculate_kernel = lanczos_kernel;
4353  s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice;
4354  s->elements = 4 * 4;
4355  sizeof_uv = sizeof(int16_t) * s->elements;
4356  sizeof_ker = sizeof(int16_t) * s->elements;
4357  break;
4358  case SPLINE16:
4359  s->calculate_kernel = spline16_kernel;
4360  s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice;
4361  s->elements = 4 * 4;
4362  sizeof_uv = sizeof(int16_t) * s->elements;
4363  sizeof_ker = sizeof(int16_t) * s->elements;
4364  break;
4365  case GAUSSIAN:
4366  s->calculate_kernel = gaussian_kernel;
4367  s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice;
4368  s->elements = 4 * 4;
4369  sizeof_uv = sizeof(int16_t) * s->elements;
4370  sizeof_ker = sizeof(int16_t) * s->elements;
4371  break;
4372  case MITCHELL:
4373  s->calculate_kernel = mitchell_kernel;
4374  s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice;
4375  s->elements = 4 * 4;
4376  sizeof_uv = sizeof(int16_t) * s->elements;
4377  sizeof_ker = sizeof(int16_t) * s->elements;
4378  break;
4379  default:
4380  av_assert0(0);
4381  }
4382 
4383  ff_v360_init(s, depth);
4384 
4385  for (int order = 0; order < NB_RORDERS; order++) {
4386  const char c = s->rorder[order];
4387  int rorder;
4388 
4389  if (c == '\0') {
4391  "Incomplete rorder option. Direction for all 3 rotation orders should be specified. Switching to default rorder.\n");
4392  s->rotation_order[0] = YAW;
4393  s->rotation_order[1] = PITCH;
4394  s->rotation_order[2] = ROLL;
4395  break;
4396  }
4397 
4398  rorder = get_rorder(c);
4399  if (rorder == -1) {
4401  "Incorrect rotation order symbol '%c' in rorder option. Switching to default rorder.\n", c);
4402  s->rotation_order[0] = YAW;
4403  s->rotation_order[1] = PITCH;
4404  s->rotation_order[2] = ROLL;
4405  break;
4406  }
4407 
4408  s->rotation_order[order] = rorder;
4409  }
4410 
4411  switch (s->in_stereo) {
4412  case STEREO_2D:
4413  w = inlink->w;
4414  h = inlink->h;
4415  in_offset_w = in_offset_h = 0;
4416  break;
4417  case STEREO_SBS:
4418  w = inlink->w / 2;
4419  h = inlink->h;
4420  in_offset_w = w;
4421  in_offset_h = 0;
4422  break;
4423  case STEREO_TB:
4424  w = inlink->w;
4425  h = inlink->h / 2;
4426  in_offset_w = 0;
4427  in_offset_h = h;
4428  break;
4429  default:
4430  av_assert0(0);
4431  }
4432 
4433  set_dimensions(s->inplanewidth, s->inplaneheight, w, h, desc);
4434  set_dimensions(s->in_offset_w, s->in_offset_h, in_offset_w, in_offset_h, desc);
4435 
4436  s->in_width = s->inplanewidth[0];
4437  s->in_height = s->inplaneheight[0];
4438 
4439  switch (s->in) {
4440  case CYLINDRICAL:
4441  case FLAT:
4442  default_ih_fov = 90.f;
4443  default_iv_fov = 45.f;
4444  break;
4445  case EQUISOLID:
4446  case ORTHOGRAPHIC:
4447  case STEREOGRAPHIC:
4448  case DUAL_FISHEYE:
4449  case FISHEYE:
4450  default_ih_fov = 180.f;
4451  default_iv_fov = 180.f;
4452  default:
4453  break;
4454  }
4455 
4456  if (s->ih_fov == 0.f)
4457  s->ih_fov = default_ih_fov;
4458 
4459  if (s->iv_fov == 0.f)
4460  s->iv_fov = default_iv_fov;
4461 
4462  if (s->id_fov > 0.f)
4463  fov_from_dfov(s->in, s->id_fov, w, h, &s->ih_fov, &s->iv_fov);
4464 
4465  if (s->in_transpose)
4466  FFSWAP(int, s->in_width, s->in_height);
4467 
4468  switch (s->in) {
4469  case EQUIRECTANGULAR:
4470  s->in_transform = xyz_to_equirect;
4471  err = prepare_equirect_in(ctx);
4472  wf = w;
4473  hf = h;
4474  break;
4475  case CUBEMAP_3_2:
4476  s->in_transform = xyz_to_cube3x2;
4477  err = prepare_cube_in(ctx);
4478  wf = w / 3.f * 4.f;
4479  hf = h;
4480  break;
4481  case CUBEMAP_1_6:
4482  s->in_transform = xyz_to_cube1x6;
4483  err = prepare_cube_in(ctx);
4484  wf = w * 4.f;
4485  hf = h / 3.f;
4486  break;
4487  case CUBEMAP_6_1:
4488  s->in_transform = xyz_to_cube6x1;
4489  err = prepare_cube_in(ctx);
4490  wf = w / 3.f * 2.f;
4491  hf = h * 2.f;
4492  break;
4493  case EQUIANGULAR:
4494  s->in_transform = xyz_to_eac;
4495  err = prepare_eac_in(ctx);
4496  wf = w;
4497  hf = h / 9.f * 8.f;
4498  break;
4499  case FLAT:
4500  s->in_transform = xyz_to_flat;
4501  err = prepare_flat_in(ctx);
4502  wf = w;
4503  hf = h;
4504  break;
4505  case PERSPECTIVE:
4506  av_log(ctx, AV_LOG_ERROR, "Supplied format is not accepted as input.\n");
4507  return AVERROR(EINVAL);
4508  case DUAL_FISHEYE:
4509  s->in_transform = xyz_to_dfisheye;
4510  err = prepare_dfisheye_in(ctx);
4511  wf = w;
4512  hf = h;
4513  break;
4514  case BARREL:
4515  s->in_transform = xyz_to_barrel;
4516  err = 0;
4517  wf = w / 5.f * 4.f;
4518  hf = h;
4519  break;
4520  case STEREOGRAPHIC:
4521  s->in_transform = xyz_to_stereographic;
4523  wf = w;
4524  hf = h / 2.f;
4525  break;
4526  case MERCATOR:
4527  s->in_transform = xyz_to_mercator;
4528  err = 0;
4529  wf = w;
4530  hf = h / 2.f;
4531  break;
4532  case BALL:
4533  s->in_transform = xyz_to_ball;
4534  err = 0;
4535  wf = w;
4536  hf = h / 2.f;
4537  break;
4538  case HAMMER:
4539  s->in_transform = xyz_to_hammer;
4540  err = 0;
4541  wf = w;
4542  hf = h;
4543  break;
4544  case SINUSOIDAL:
4545  s->in_transform = xyz_to_sinusoidal;
4546  err = 0;
4547  wf = w;
4548  hf = h;
4549  break;
4550  case FISHEYE:
4551  s->in_transform = xyz_to_fisheye;
4552  err = prepare_fisheye_in(ctx);
4553  wf = w * 2;
4554  hf = h;
4555  break;
4556  case PANNINI:
4557  s->in_transform = xyz_to_pannini;
4558  err = 0;
4559  wf = w;
4560  hf = h;
4561  break;
4562  case CYLINDRICAL:
4563  s->in_transform = xyz_to_cylindrical;
4564  err = prepare_cylindrical_in(ctx);
4565  wf = w;
4566  hf = h * 2.f;
4567  break;
4568  case CYLINDRICALEA:
4569  s->in_transform = xyz_to_cylindricalea;
4571  wf = w;
4572  hf = h;
4573  break;
4574  case TETRAHEDRON:
4575  s->in_transform = xyz_to_tetrahedron;
4576  err = 0;
4577  wf = w;
4578  hf = h;
4579  break;
4580  case BARREL_SPLIT:
4581  s->in_transform = xyz_to_barrelsplit;
4582  err = 0;
4583  wf = w * 4.f / 3.f;
4584  hf = h;
4585  break;
4586  case TSPYRAMID:
4587  s->in_transform = xyz_to_tspyramid;
4588  err = 0;
4589  wf = w;
4590  hf = h;
4591  break;
4592  case HEQUIRECTANGULAR:
4593  s->in_transform = xyz_to_hequirect;
4594  err = 0;
4595  wf = w * 2.f;
4596  hf = h;
4597  break;
4598  case EQUISOLID:
4599  s->in_transform = xyz_to_equisolid;
4600  err = prepare_equisolid_in(ctx);
4601  wf = w;
4602  hf = h / 2.f;
4603  break;
4604  case ORTHOGRAPHIC:
4605  s->in_transform = xyz_to_orthographic;
4607  wf = w;
4608  hf = h / 2.f;
4609  break;
4610  case OCTAHEDRON:
4611  s->in_transform = xyz_to_octahedron;
4612  err = 0;
4613  wf = w;
4614  hf = h / 2.f;
4615  break;
4616  default:
4617  av_log(ctx, AV_LOG_ERROR, "Specified input format is not handled.\n");
4618  return AVERROR_BUG;
4619  }
4620 
4621  if (err != 0) {
4622  return err;
4623  }
4624 
4625  switch (s->out) {
4626  case EQUIRECTANGULAR:
4627  s->out_transform = equirect_to_xyz;
4628  prepare_out = prepare_equirect_out;
4629  w = lrintf(wf);
4630  h = lrintf(hf);
4631  break;
4632  case CUBEMAP_3_2:
4633  s->out_transform = cube3x2_to_xyz;
4634  prepare_out = prepare_cube_out;
4635  w = lrintf(wf / 4.f * 3.f);
4636  h = lrintf(hf);
4637  break;
4638  case CUBEMAP_1_6:
4639  s->out_transform = cube1x6_to_xyz;
4640  prepare_out = prepare_cube_out;
4641  w = lrintf(wf / 4.f);
4642  h = lrintf(hf * 3.f);
4643  break;
4644  case CUBEMAP_6_1:
4645  s->out_transform = cube6x1_to_xyz;
4646  prepare_out = prepare_cube_out;
4647  w = lrintf(wf / 2.f * 3.f);
4648  h = lrintf(hf / 2.f);
4649  break;
4650  case EQUIANGULAR:
4651  s->out_transform = eac_to_xyz;
4652  prepare_out = prepare_eac_out;
4653  w = lrintf(wf);
4654  h = lrintf(hf / 8.f * 9.f);
4655  break;
4656  case FLAT:
4657  s->out_transform = flat_to_xyz;
4658  prepare_out = prepare_flat_out;
4659  w = lrintf(wf);
4660  h = lrintf(hf);
4661  break;
4662  case DUAL_FISHEYE:
4663  s->out_transform = dfisheye_to_xyz;
4664  prepare_out = prepare_fisheye_out;
4665  w = lrintf(wf);
4666  h = lrintf(hf);
4667  break;
4668  case BARREL:
4669  s->out_transform = barrel_to_xyz;
4670  prepare_out = NULL;
4671  w = lrintf(wf / 4.f * 5.f);
4672  h = lrintf(hf);
4673  break;
4674  case STEREOGRAPHIC:
4675  s->out_transform = stereographic_to_xyz;
4676  prepare_out = prepare_stereographic_out;
4677  w = lrintf(wf);
4678  h = lrintf(hf * 2.f);
4679  break;
4680  case MERCATOR:
4681  s->out_transform = mercator_to_xyz;
4682  prepare_out = NULL;
4683  w = lrintf(wf);
4684  h = lrintf(hf * 2.f);
4685  break;
4686  case BALL:
4687  s->out_transform = ball_to_xyz;
4688  prepare_out = NULL;
4689  w = lrintf(wf);
4690  h = lrintf(hf * 2.f);
4691  break;
4692  case HAMMER:
4693  s->out_transform = hammer_to_xyz;
4694  prepare_out = NULL;
4695  w = lrintf(wf);
4696  h = lrintf(hf);
4697  break;
4698  case SINUSOIDAL:
4699  s->out_transform = sinusoidal_to_xyz;
4700  prepare_out = NULL;
4701  w = lrintf(wf);
4702  h = lrintf(hf);
4703  break;
4704  case FISHEYE:
4705  s->out_transform = fisheye_to_xyz;
4706  prepare_out = prepare_fisheye_out;
4707  w = lrintf(wf * 0.5f);
4708  h = lrintf(hf);
4709  break;
4710  case PANNINI:
4711  s->out_transform = pannini_to_xyz;
4712  prepare_out = NULL;
4713  w = lrintf(wf);
4714  h = lrintf(hf);
4715  break;
4716  case CYLINDRICAL:
4717  s->out_transform = cylindrical_to_xyz;
4718  prepare_out = prepare_cylindrical_out;
4719  w = lrintf(wf);
4720  h = lrintf(hf * 0.5f);
4721  break;
4722  case CYLINDRICALEA:
4723  s->out_transform = cylindricalea_to_xyz;
4724  prepare_out = prepare_cylindricalea_out;
4725  w = lrintf(wf);
4726  h = lrintf(hf);
4727  break;
4728  case PERSPECTIVE:
4729  s->out_transform = perspective_to_xyz;
4730  prepare_out = NULL;
4731  w = lrintf(wf / 2.f);
4732  h = lrintf(hf);
4733  break;
4734  case TETRAHEDRON:
4735  s->out_transform = tetrahedron_to_xyz;
4736  prepare_out = NULL;
4737  w = lrintf(wf);
4738  h = lrintf(hf);
4739  break;
4740  case BARREL_SPLIT:
4741  s->out_transform = barrelsplit_to_xyz;
4742  prepare_out = NULL;
4743  w = lrintf(wf / 4.f * 3.f);
4744  h = lrintf(hf);
4745  break;
4746  case TSPYRAMID:
4747  s->out_transform = tspyramid_to_xyz;
4748  prepare_out = NULL;
4749  w = lrintf(wf);
4750  h = lrintf(hf);
4751  break;
4752  case HEQUIRECTANGULAR:
4753  s->out_transform = hequirect_to_xyz;
4754  prepare_out = NULL;
4755  w = lrintf(wf / 2.f);
4756  h = lrintf(hf);
4757  break;
4758  case EQUISOLID:
4759  s->out_transform = equisolid_to_xyz;
4760  prepare_out = prepare_equisolid_out;
4761  w = lrintf(wf);
4762  h = lrintf(hf * 2.f);
4763  break;
4764  case ORTHOGRAPHIC:
4765  s->out_transform = orthographic_to_xyz;
4766  prepare_out = prepare_orthographic_out;
4767  w = lrintf(wf);
4768  h = lrintf(hf * 2.f);
4769  break;
4770  case OCTAHEDRON:
4771  s->out_transform = octahedron_to_xyz;
4772  prepare_out = NULL;
4773  w = lrintf(wf);
4774  h = lrintf(hf * 2.f);
4775  break;
4776  default:
4777  av_log(ctx, AV_LOG_ERROR, "Specified output format is not handled.\n");
4778  return AVERROR_BUG;
4779  }
4780 
4781  // Override resolution with user values if specified
4782  if (s->width > 0 && s->height <= 0 && s->h_fov > 0.f && s->v_fov > 0.f &&
4783  s->out == FLAT && s->d_fov == 0.f) {
4784  w = s->width;
4785  h = w / tanf(s->h_fov * M_PI / 360.f) * tanf(s->v_fov * M_PI / 360.f);
4786  } else if (s->width <= 0 && s->height > 0 && s->h_fov > 0.f && s->v_fov > 0.f &&
4787  s->out == FLAT && s->d_fov == 0.f) {
4788  h = s->height;
4789  w = h / tanf(s->v_fov * M_PI / 360.f) * tanf(s->h_fov * M_PI / 360.f);
4790  } else if (s->width > 0 && s->height > 0) {
4791  w = s->width;
4792  h = s->height;
4793  } else if (s->width > 0 || s->height > 0) {
4794  av_log(ctx, AV_LOG_ERROR, "Both width and height values should be specified.\n");
4795  return AVERROR(EINVAL);
4796  } else {
4797  if (s->out_transpose)
4798  FFSWAP(int, w, h);
4799 
4800  if (s->in_transpose)
4801  FFSWAP(int, w, h);
4802  }
4803 
4804  s->width = w;
4805  s->height = h;
4806 
4807  switch (s->out) {
4808  case CYLINDRICAL:
4809  case FLAT:
4810  default_h_fov = 90.f;
4811  default_v_fov = 45.f;
4812  break;
4813  case EQUISOLID:
4814  case ORTHOGRAPHIC:
4815  case STEREOGRAPHIC:
4816  case DUAL_FISHEYE:
4817  case FISHEYE:
4818  default_h_fov = 180.f;
4819  default_v_fov = 180.f;
4820  break;
4821  default:
4822  break;
4823  }
4824 
4825  if (s->h_fov == 0.f)
4826  s->h_fov = default_h_fov;
4827 
4828  if (s->v_fov == 0.f)
4829  s->v_fov = default_v_fov;
4830 
4831  if (s->d_fov > 0.f)
4832  fov_from_dfov(s->out, s->d_fov, w, h, &s->h_fov, &s->v_fov);
4833 
4834  if (prepare_out) {
4835  err = prepare_out(ctx);
4836  if (err != 0)
4837  return err;
4838  }
4839 
4840  set_dimensions(s->pr_width, s->pr_height, w, h, desc);
4841 
4842  switch (s->out_stereo) {
4843  case STEREO_2D:
4844  out_offset_w = out_offset_h = 0;
4845  break;
4846  case STEREO_SBS:
4847  out_offset_w = w;
4848  out_offset_h = 0;
4849  w *= 2;
4850  break;
4851  case STEREO_TB:
4852  out_offset_w = 0;
4853  out_offset_h = h;
4854  h *= 2;
4855  break;
4856  default:
4857  av_assert0(0);
4858  }
4859 
4860  set_dimensions(s->out_offset_w, s->out_offset_h, out_offset_w, out_offset_h, desc);
4861  set_dimensions(s->planewidth, s->planeheight, w, h, desc);
4862 
4863  for (int i = 0; i < 4; i++)
4864  s->uv_linesize[i] = FFALIGN(s->pr_width[i], 8);
4865 
4866  outlink->h = h;
4867  outlink->w = w;
4868 
4869  s->nb_threads = FFMIN(outlink->h, ff_filter_get_nb_threads(ctx));
4870  s->nb_planes = av_pix_fmt_count_planes(inlink->format);
4871  have_alpha = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA);
4872 
4873  if (desc->log2_chroma_h == desc->log2_chroma_w && desc->log2_chroma_h == 0) {
4874  s->nb_allocated = 1;
4875  s->map[0] = s->map[1] = s->map[2] = s->map[3] = 0;
4876  } else {
4877  s->nb_allocated = 2;
4878  s->map[0] = s->map[3] = 0;
4879  s->map[1] = s->map[2] = 1;
4880  }
4881 
4882  if (!s->slice_remap)
4883  s->slice_remap = av_calloc(s->nb_threads, sizeof(*s->slice_remap));
4884  if (!s->slice_remap)
4885  return AVERROR(ENOMEM);
4886 
4887  for (int i = 0; i < s->nb_allocated; i++) {
4888  err = allocate_plane(s, sizeof_uv, sizeof_ker, sizeof_mask * have_alpha * s->alpha, i);
4889  if (err < 0)
4890  return err;
4891  }
4892 
4893  calculate_rotation(s->yaw, s->pitch, s->roll,
4894  s->rot_quaternion, s->rotation_order);
4895 
4896  set_mirror_modifier(s->h_flip, s->v_flip, s->d_flip, s->output_mirror_modifier);
4897 
4898  ff_filter_execute(ctx, v360_slice, NULL, NULL, s->nb_threads);
4899 
4900  return 0;
4901 }
4902 
4904 {
4905  AVFilterContext *ctx = inlink->dst;
4906  AVFilterLink *outlink = ctx->outputs[0];
4907  V360Context *s = ctx->priv;
4908  AVFrame *out;
4909  ThreadData td;
4910 
4911  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
4912  if (!out) {
4913  av_frame_free(&in);
4914  return AVERROR(ENOMEM);
4915  }
4916  av_frame_copy_props(out, in);
4917 
4918  td.in = in;
4919  td.out = out;
4920 
4921  ff_filter_execute(ctx, s->remap_slice, &td, NULL, s->nb_threads);
4922 
4923  av_frame_free(&in);
4924  return ff_filter_frame(outlink, out);
4925 }
4926 
4927 static void reset_rot(V360Context *s)
4928 {
4929  s->rot_quaternion[0][0] = 1.f;
4930  s->rot_quaternion[0][1] = s->rot_quaternion[0][2] = s->rot_quaternion[0][3] = 0.f;
4931 }
4932 
4933 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
4934  char *res, int res_len, int flags)
4935 {
4936  V360Context *s = ctx->priv;
4937  int ret;
4938 
4939  if (s->reset_rot <= 0)
4940  s->yaw = s->pitch = s->roll = 0.f;
4941  if (s->reset_rot < 0)
4942  s->reset_rot = 0;
4943 
4944  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
4945  if (ret < 0)
4946  return ret;
4947 
4948  if (s->reset_rot)
4949  reset_rot(s);
4950 
4951  return config_output(ctx->outputs[0]);
4952 }
4953 
4955 {
4956  V360Context *s = ctx->priv;
4957 
4958  reset_rot(s);
4959 
4960  return 0;
4961 }
4962 
4964 {
4965  V360Context *s = ctx->priv;
4966 
4967  for (int n = 0; n < s->nb_threads && s->slice_remap; n++) {
4968  SliceXYRemap *r = &s->slice_remap[n];
4969 
4970  for (int p = 0; p < s->nb_allocated; p++) {
4971  av_freep(&r->u[p]);
4972  av_freep(&r->v[p]);
4973  av_freep(&r->ker[p]);
4974  }
4975 
4976  av_freep(&r->mask);
4977  }
4978 
4979  av_freep(&s->slice_remap);
4980 }
4981 
4982 static const AVFilterPad inputs[] = {
4983  {
4984  .name = "default",
4985  .type = AVMEDIA_TYPE_VIDEO,
4986  .filter_frame = filter_frame,
4987  },
4988 };
4989 
4990 static const AVFilterPad outputs[] = {
4991  {
4992  .name = "default",
4993  .type = AVMEDIA_TYPE_VIDEO,
4994  .config_props = config_output,
4995  },
4996 };
4997 
4999  .name = "v360",
5000  .description = NULL_IF_CONFIG_SMALL("Convert 360 projection of video."),
5001  .priv_size = sizeof(V360Context),
5002  .init = init,
5003  .uninit = uninit,
5007  .priv_class = &v360_class,
5008  .flags = AVFILTER_FLAG_SLICE_THREADS,
5009  .process_command = process_command,
5010 };
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:116
AV_PIX_FMT_YUVA422P16
#define AV_PIX_FMT_YUVA422P16
Definition: pixfmt.h:546
M_2_PI
#define M_2_PI
Definition: mathematics.h:91
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:525
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
q1
static const uint8_t q1[256]
Definition: twofish.c:100
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
av_clip
#define av_clip
Definition: common.h:100
process_cube_coordinates
static void process_cube_coordinates(const V360Context *s, float uf, float vf, int direction, float *new_uf, float *new_vf, int *face)
Find position on another cube face in case of overflow/underflow.
Definition: vf_v360.c:1212
r
const char * r
Definition: vf_curves.c:127
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
xyz_to_mercator
static int xyz_to_mercator(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in mercator format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2326
opt.h
prepare_stereographic_in
static int prepare_stereographic_in(AVFilterContext *ctx)
Prepare data for processing stereographic input format.
Definition: vf_v360.c:1884
xyz_to_eac
static int xyz_to_eac(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in equi-angular cubemap format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2769
XYRemap::u
int16_t u[4][4]
Definition: v360.h:109
out
FILE * out
Definition: movenc.c:55
elements
static const ElemCat * elements[ELEMENT_COUNT]
Definition: signature.h:565
ROT_180
@ ROT_180
Definition: v360.h:96
u
#define u(width, name, range_min, range_max)
Definition: cbs_h2645.c:251
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1062
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3170
EQUIANGULAR
@ EQUIANGULAR
Definition: v360.h:36
ORTHOGRAPHIC
@ ORTHOGRAPHIC
Definition: v360.h:55
gaussian_kernel
static void gaussian_kernel(float du, float dv, const XYRemap *rmap, int16_t *u, int16_t *v, int16_t *ker)
Calculate kernel for gaussian interpolation.
Definition: vf_v360.c:664
floorf
static __device__ float floorf(float a)
Definition: cuda_runtime.h:172
outputs
static const AVFilterPad outputs[]
Definition: vf_v360.c:4990
ff_v360_init_x86
void ff_v360_init_x86(V360Context *s, int depth)
Definition: vf_v360_init.c:44
atan2f
#define atan2f(y, x)
Definition: libm.h:45
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
DOWN
@ DOWN
Axis -Y.
Definition: v360.h:87
prepare_equirect_out
static int prepare_equirect_out(AVFilterContext *ctx)
Prepare data for processing equirectangular output format.
Definition: vf_v360.c:1765
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:162
xyz_to_stereographic
static int xyz_to_stereographic(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in stereographic format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:1906
AV_PIX_FMT_YUVA422P9
#define AV_PIX_FMT_YUVA422P9
Definition: pixfmt.h:538
prepare_orthographic_out
static int prepare_orthographic_out(AVFilterContext *ctx)
Prepare data for processing orthographic output format.
Definition: vf_v360.c:2048
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: filters.h:262
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:389
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
pixdesc.h
AV_PIX_FMT_YUVA420P16
#define AV_PIX_FMT_YUVA420P16
Definition: pixfmt.h:545
w
uint8_t w
Definition: llviddspenc.c:38
prepare_cube_out
static int prepare_cube_out(AVFilterContext *ctx)
Prepare data for processing cubemap output format.
Definition: vf_v360.c:939
xyz_to_cylindrical
static int xyz_to_cylindrical(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in cylindrical format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:3125
barrelsplit_to_xyz
static int barrelsplit_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in barrel split facebook's format...
Definition: vf_v360.c:3746
M_PI_2
#define M_PI_2
Definition: mathematics.h:73
stereographic_to_xyz
static int stereographic_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in stereographic format.
Definition: vf_v360.c:1860
AV_PIX_FMT_YUVA420P10
#define AV_PIX_FMT_YUVA420P10
Definition: pixfmt.h:540
ROLL
@ ROLL
Definition: v360.h:104
AVOption
AVOption.
Definition: opt.h:429
b
#define b
Definition: input.c:41
prepare_cube_in
static int prepare_cube_in(AVFilterContext *ctx)
Prepare data for processing cubemap input format.
Definition: vf_v360.c:885
NEAREST
#define NEAREST(type, name)
Definition: vf_lenscorrection.c:75
expf
#define expf(x)
Definition: libm.h:283
get_rotation
static int get_rotation(char c)
Convert char to corresponding rotation angle.
Definition: vf_v360.c:842
FRONT
@ FRONT
Axis -Z.
Definition: v360.h:88
AV_PIX_FMT_YUV420P10
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:502
xyz_to_barrel
static int xyz_to_barrel(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in barrel facebook's format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:3578
perspective_to_xyz
static int perspective_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in perspective format.
Definition: vf_v360.c:3273
xyz_to_cube3x2
static int xyz_to_cube3x2(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in cubemap3x2 format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:1453
CUBEMAP_3_2
@ CUBEMAP_3_2
Definition: v360.h:34
v360_options
static const AVOption v360_options[]
Definition: vf_v360.c:57
NB_PROJECTIONS
@ NB_PROJECTIONS
Definition: v360.h:58
AV_PIX_FMT_YUV440P
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:106
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_v360.c:4903
xyz_to_tspyramid
static int xyz_to_tspyramid(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in tspyramid format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:3879
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:205
ThreadData::out
AVFrame * out
Definition: af_adeclick.c:526
rotate_cube_face_inverse
static void rotate_cube_face_inverse(float *uf, float *vf, int rotation)
Definition: vf_v360.c:1012
video.h
ThreadData::in
AVFrame * in
Definition: af_adecorrelate.c:155
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(v360)
AV_PIX_FMT_YUVA422P10
#define AV_PIX_FMT_YUVA422P10
Definition: pixfmt.h:541
BARREL
@ BARREL
Definition: v360.h:39
ceilf
static __device__ float ceilf(float a)
Definition: cuda_runtime.h:175
v360_slice
static int v360_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_v360.c:4237
AV_PIX_FMT_GRAY9
#define AV_PIX_FMT_GRAY9
Definition: pixfmt.h:482
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_v360.c:4954
formats.h
S
#define S(s, c, i)
Definition: flacdsp_template.c:46
xyz_to_sinusoidal
static int xyz_to_sinusoidal(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in sinusoidal format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2574
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3210
AV_PIX_FMT_YUVA420P9
#define AV_PIX_FMT_YUVA420P9
Definition: pixfmt.h:537
prepare_eac_out
static int prepare_eac_out(AVFilterContext *ctx)
Prepare data for processing equi-angular cubemap output format.
Definition: vf_v360.c:2635
HAMMER
@ HAMMER
Definition: v360.h:44
AV_PIX_FMT_GBRP14
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:520
FISHEYE
@ FISHEYE
Definition: v360.h:46
slice_end
static int slice_end(AVCodecContext *avctx, AVFrame *pict, int *got_output)
Handle slice ends.
Definition: mpeg12dec.c:1719
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:212
cosf
#define cosf(x)
Definition: libm.h:78
interp
interp
Definition: vf_curves.c:62
AV_PIX_FMT_GBRP10
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:518
calculate_lanczos_coeffs
static void calculate_lanczos_coeffs(float t, float *coeffs)
Calculate 1-dimensional lanczos coefficients.
Definition: vf_v360.c:540
AV_PIX_FMT_YUVA444P16
#define AV_PIX_FMT_YUVA444P16
Definition: pixfmt.h:547
FFSIGN
#define FFSIGN(a)
Definition: common.h:75
conjugate_quaternion
static void conjugate_quaternion(float d[4], const float q[4])
Definition: vf_v360.c:4025
AV_PIX_FMT_YUV422P9
#define AV_PIX_FMT_YUV422P9
Definition: pixfmt.h:500
MERCATOR
@ MERCATOR
Definition: v360.h:42
BOTTOM_LEFT
@ BOTTOM_LEFT
Definition: v360.h:77
lanczos_kernel
static void lanczos_kernel(float du, float dv, const XYRemap *rmap, int16_t *u, int16_t *v, int16_t *ker)
Calculate kernel for lanczos interpolation.
Definition: vf_v360.c:569
PERSPECTIVE
@ PERSPECTIVE
Definition: v360.h:49
inputs
static const AVFilterPad inputs[]
Definition: vf_v360.c:4982
prepare_equisolid_in
static int prepare_equisolid_in(AVFilterContext *ctx)
Prepare data for processing equisolid input format.
Definition: vf_v360.c:1988
xyz_to_orthographic
static int xyz_to_orthographic(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in orthographic format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2121
scale
static av_always_inline float scale(float x, float s)
Definition: vf_v360.c:1394
equirect_to_xyz
static int equirect_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in equirectangular format.
Definition: vf_v360.c:1785
AV_PIX_FMT_GRAY16
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:486
us
#define us(width, name, range_min, range_max, subs,...)
Definition: cbs_h2645.c:263
xyz_to_cube6x1
static int xyz_to_cube6x1(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in cubemap6x1 format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:1690
ROT_270
@ ROT_270
Definition: v360.h:97
TSPYRAMID
@ TSPYRAMID
Definition: v360.h:52
fabsf
static __device__ float fabsf(float a)
Definition: cuda_runtime.h:181
FLAT
@ FLAT
Definition: v360.h:37
ball_to_xyz
static int ball_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in ball format.
Definition: vf_v360.c:2431
xyz_to_hammer
static int xyz_to_hammer(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in hammer format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2504
AVFilterPad
A filter pad used for either input or output.
Definition: filters.h:38
rotate
static void rotate(const float rot_quaternion[2][4], float *vec)
Rotate vector with given rotation quaternion.
Definition: vf_v360.c:4071
AV_PIX_FMT_YUV444P10
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:505
AV_PIX_FMT_YUVJ411P
@ AV_PIX_FMT_YUVJ411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor ...
Definition: pixfmt.h:283
BARREL_SPLIT
@ BARREL_SPLIT
Definition: v360.h:51
reflectx
static int reflectx(int x, int y, int w, int h)
Reflect x operation.
Definition: vf_v360.c:806
avassert.h
lagrange_kernel
static void lagrange_kernel(float du, float dv, const XYRemap *rmap, int16_t *u, int16_t *v, int16_t *ker)
Calculate kernel for lagrange interpolation.
Definition: vf_v360.c:471
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
av_cold
#define av_cold
Definition: attributes.h:90
AV_PIX_FMT_YUV422P16
#define AV_PIX_FMT_YUV422P16
Definition: pixfmt.h:514
CYLINDRICAL
@ CYLINDRICAL
Definition: v360.h:48
orthographic_to_xyz
static int orthographic_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in orthographic format.
Definition: vf_v360.c:2068
AV_PIX_FMT_YUVJ422P
@ AV_PIX_FMT_YUVJ422P
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition: pixfmt.h:86
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:522
float
float
Definition: af_crystalizer.c:122
FLAGS
#define FLAGS
Definition: vf_v360.c:54
tetrahedron_to_xyz
static int tetrahedron_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in tetrahedron format.
Definition: vf_v360.c:3319
octahedron_to_xyz
static int octahedron_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in octahedron format.
Definition: vf_v360.c:3947
calculate_spline16_coeffs
static void calculate_spline16_coeffs(float t, float *coeffs)
Calculate 1-dimensional spline16 coefficients.
Definition: vf_v360.c:593
prepare_equirect_in
static int prepare_equirect_in(AVFilterContext *ctx)
Prepare data for processing equirectangular input format.
Definition: vf_v360.c:2159
DEFINE_REMAP
#define DEFINE_REMAP(ws, bits)
Generate remapping function with a given window size and pixel depth.
Definition: vf_v360.c:283
XYRemap
Definition: v360.h:108
ROT_90
@ ROT_90
Definition: v360.h:95
s
#define s(width, name)
Definition: cbs_vp9.c:198
AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:523
AV_PIX_FMT_YUVA420P
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:108
AV_PIX_FMT_YUV444P16
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:515
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:60
TFLAGS
#define TFLAGS
Definition: vf_v360.c:55
format
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
fisheye_to_xyz
static int fisheye_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in fisheye format.
Definition: vf_v360.c:2885
UP
@ UP
Axis +Y.
Definition: v360.h:86
reflecty
static int reflecty(int y, int h)
Reflect y operation.
Definition: vf_v360.c:771
PANNINI
@ PANNINI
Definition: v360.h:47
bilinear_kernel
static void bilinear_kernel(float du, float dv, const XYRemap *rmap, int16_t *u, int16_t *v, int16_t *ker)
Calculate kernel for bilinear interpolation.
Definition: vf_v360.c:432
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
XYRemap::v
int16_t v[4][4]
Definition: v360.h:110
filters.h
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:304
query_formats
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
Definition: vf_v360.c:175
AV_PIX_FMT_YUVA444P12
#define AV_PIX_FMT_YUVA444P12
Definition: pixfmt.h:544
xyz_to_octahedron
static int xyz_to_octahedron(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in octahedron format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:3980
AV_PIX_FMT_YUV420P9
#define AV_PIX_FMT_YUV420P9
Definition: pixfmt.h:499
AV_PIX_FMT_YUV420P16
#define AV_PIX_FMT_YUV420P16
Definition: pixfmt.h:513
AV_PIX_FMT_FLAG_ALPHA
#define AV_PIX_FMT_FLAG_ALPHA
The pixel format has an alpha channel.
Definition: pixdesc.h:147
ctx
AVFormatContext * ctx
Definition: movenc.c:49
LANCZOS
@ LANCZOS
Definition: v360.h:66
AV_PIX_FMT_GRAY14
#define AV_PIX_FMT_GRAY14
Definition: pixfmt.h:485
isfinite
#define isfinite(x)
Definition: libm.h:359
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: filters.h:263
reset_rot
static void reset_rot(V360Context *s)
Definition: vf_v360.c:4927
mitchell_kernel
static void mitchell_kernel(float du, float dv, const XYRemap *rmap, int16_t *u, int16_t *v, int16_t *ker)
Calculate kernel for mitchell interpolation.
Definition: vf_v360.c:729
q0
static const uint8_t q0[256]
Definition: twofish.c:81
AV_PIX_FMT_YUVJ444P
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition: pixfmt.h:87
arg
const char * arg
Definition: jacosubdec.c:67
AV_PIX_FMT_GRAY10
#define AV_PIX_FMT_GRAY10
Definition: pixfmt.h:483
if
if(ret)
Definition: filter_design.txt:179
OCTAHEDRON
@ OCTAHEDRON
Definition: v360.h:56
offset_vector
static void offset_vector(float *vec, float h_offset, float v_offset)
Offset vector.
Definition: vf_v360.c:1043
ff_v360_init
void ff_v360_init(V360Context *s, int depth)
Definition: vf_v360.c:376
AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:521
NULL
#define NULL
Definition: coverity.c:32
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:713
xyz_to_cube1x6
static int xyz_to_cube1x6(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in cubemap1x6 format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:1610
CYLINDRICALEA
@ CYLINDRICALEA
Definition: v360.h:57
calculate_gaussian_coeffs
static void calculate_gaussian_coeffs(float t, float *coeffs)
Calculate 1-dimensional gaussian coefficients.
Definition: vf_v360.c:635
ereflectx
static int ereflectx(int x, int y, int w, int h)
Reflect x operation for equirect.
Definition: vf_v360.c:790
isnan
#define isnan(x)
Definition: libm.h:340
AV_PIX_FMT_YUVJ420P
@ AV_PIX_FMT_YUVJ420P
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition: pixfmt.h:85
mercator_to_xyz
static int mercator_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in mercator format.
Definition: vf_v360.c:2362
prepare_fisheye_out
static int prepare_fisheye_out(AVFilterContext *ctx)
Prepare data for processing fisheye output format.
Definition: vf_v360.c:2865
AV_PIX_FMT_YUV440P10
#define AV_PIX_FMT_YUV440P10
Definition: pixfmt.h:504
prepare_cylindricalea_out
static int prepare_cylindricalea_out(AVFilterContext *ctx)
Prepare data for processing cylindrical equal area output format.
Definition: vf_v360.c:3162
rotate_cube_face
static void rotate_cube_face(float *uf, float *vf, int rotation)
Definition: vf_v360.c:986
calculate_lagrange_coeffs
static void calculate_lagrange_coeffs(float t, float *coeffs)
Calculate 1-dimensional lagrange coefficients.
Definition: vf_v360.c:454
cube1x6_to_xyz
static int cube1x6_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in cubemap1x6 format.
Definition: vf_v360.c:1542
sqrtf
static __device__ float sqrtf(float a)
Definition: cuda_runtime.h:184
barrel_to_xyz
static int barrel_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in barrel facebook's format.
Definition: vf_v360.c:3506
AV_PIX_FMT_YUV422P10
#define AV_PIX_FMT_YUV422P10
Definition: pixfmt.h:503
sinf
#define sinf(x)
Definition: libm.h:419
av_clipf
av_clipf
Definition: af_crystalizer.c:122
prepare_cylindrical_out
static int prepare_cylindrical_out(AVFilterContext *ctx)
Prepare data for processing cylindrical output format.
Definition: vf_v360.c:3054
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:81
AV_PIX_FMT_GBRP9
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:517
ROT_0
@ ROT_0
Definition: v360.h:94
prepare_cylindrical_in
static int prepare_cylindrical_in(AVFilterContext *ctx)
Prepare data for processing cylindrical input format.
Definition: vf_v360.c:3103
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AVFilterFormatsConfig
Lists of formats / etc.
Definition: avfilter.h:111
pannini_to_xyz
static int pannini_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in pannini format.
Definition: vf_v360.c:2979
xyz_to_ball
static int xyz_to_ball(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in ball format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2394
NB_RORDERS
@ NB_RORDERS
Definition: v360.h:105
hammer_to_xyz
static int hammer_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in hammer format.
Definition: vf_v360.c:2465
prepare_dfisheye_in
static int prepare_dfisheye_in(AVFilterContext *ctx)
Prepare data for processing double fisheye input format.
Definition: vf_v360.c:3397
mirror
static void mirror(const float *modifier, float *vec)
Definition: vf_v360.c:4097
f
f
Definition: af_crystalizer.c:122
cylindrical_to_xyz
static int cylindrical_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in cylindrical format.
Definition: vf_v360.c:3074
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
height
#define height
Definition: dsp.h:85
nearest_kernel
static void nearest_kernel(float du, float dv, const XYRemap *rmap, int16_t *u, int16_t *v, int16_t *ker)
Save nearest pixel coordinates for remapping.
Definition: vf_v360.c:412
RIGHT
#define RIGHT
Definition: cdgraphics.c:172
AV_PIX_FMT_YUV422P12
#define AV_PIX_FMT_YUV422P12
Definition: pixfmt.h:507
BALL
@ BALL
Definition: v360.h:43
spline16_kernel
static void spline16_kernel(float du, float dv, const XYRemap *rmap, int16_t *u, int16_t *v, int16_t *ker)
Calculate kernel for spline16 interpolation.
Definition: vf_v360.c:611
CUBEMAP_6_1
@ CUBEMAP_6_1
Definition: v360.h:35
MITCHELL
@ MITCHELL
Definition: v360.h:69
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_v360.c:4963
AV_PIX_FMT_YUV444P12
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:509
LEFT
#define LEFT
Definition: cdgraphics.c:171
SliceXYRemap
Definition: v360.h:114
V360Context
Definition: v360.h:120
ff_filter_process_command
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition: avfilter.c:901
BICUBIC
@ BICUBIC
Definition: v360.h:65
eac_to_xyz
static int eac_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in equi-angular cubemap format.
Definition: vf_v360.c:2666
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
AV_PIX_FMT_YUVA444P
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:174
AV_PIX_FMT_YUVA444P10
#define AV_PIX_FMT_YUVA444P10
Definition: pixfmt.h:542
YAW
@ YAW
Definition: v360.h:102
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_v360.c:4933
HEQUIRECTANGULAR
@ HEQUIRECTANGULAR
Definition: v360.h:53
M_PI
#define M_PI
Definition: mathematics.h:67
v360.h
prepare_fisheye_in
static int prepare_fisheye_in(AVFilterContext *ctx)
Prepare data for processing fisheye input format.
Definition: vf_v360.c:2914
AV_OPT_TYPE_FLOAT
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
Definition: opt.h:271
prepare_equisolid_out
static int prepare_equisolid_out(AVFilterContext *ctx)
Prepare data for processing equisolid output format.
Definition: vf_v360.c:1944
bicubic_kernel
static void bicubic_kernel(float du, float dv, const XYRemap *rmap, int16_t *u, int16_t *v, int16_t *ker)
Calculate kernel for bicubic interpolation.
Definition: vf_v360.c:516
EQUISOLID
@ EQUISOLID
Definition: v360.h:54
NB_FACES
@ NB_FACES
Definition: v360.h:80
lrintf
#define lrintf(x)
Definition: libm_mips.h:72
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
xyz_to_equirect
static int xyz_to_equirect(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in equirectangular format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2181
BOTTOM_MIDDLE
@ BOTTOM_MIDDLE
Definition: v360.h:78
SPLINE16
@ SPLINE16
Definition: v360.h:67
cube3x2_to_xyz
static int cube3x2_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in cubemap3x2 format.
Definition: vf_v360.c:1414
rescale
static av_always_inline float rescale(int x, float s)
Definition: vf_v360.c:1399
allocate_plane
static int allocate_plane(V360Context *s, int sizeof_uv, int sizeof_ker, int sizeof_mask, int p)
Definition: vf_v360.c:4121
DEFINE_REMAP_LINE
#define DEFINE_REMAP_LINE(ws, bits, div)
Definition: vf_v360.c:341
prepare_stereographic_out
static int prepare_stereographic_out(AVFilterContext *ctx)
Prepare data for processing stereographic output format.
Definition: vf_v360.c:1840
config_output
static int config_output(AVFilterLink *outlink)
Definition: vf_v360.c:4298
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:519
cube6x1_to_xyz
static int cube6x1_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in cubemap6x1 format.
Definition: vf_v360.c:1575
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:841
xyz_to_cube
static void xyz_to_cube(const V360Context *s, const float *vec, float *uf, float *vf, int *direction)
Calculate cubemap position for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:1137
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:56
atanf
#define atanf(x)
Definition: libm.h:40
xyz_to_fisheye
static int xyz_to_fisheye(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in fisheye format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2936
M_PI_4
#define M_PI_4
Definition: mathematics.h:79
calculate_cubic_bc_coeffs
static void calculate_cubic_bc_coeffs(float t, float *coeffs, float b, float c)
Calculate 1-dimensional cubic_bc_spline coefficients.
Definition: vf_v360.c:688
ThreadData
Used for passing data between threads.
Definition: dsddec.c:71
xyz_to_flat
static int xyz_to_flat(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in flat format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2279
FILTER_QUERY_FUNC2
#define FILTER_QUERY_FUNC2(func)
Definition: filters.h:239
av_always_inline
#define av_always_inline
Definition: attributes.h:49
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
AV_PIX_FMT_YUVJ440P
@ AV_PIX_FMT_YUVJ440P
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range
Definition: pixfmt.h:107
hf
uint8_t ptrdiff_t const uint8_t ptrdiff_t int const int8_t * hf
Definition: dsp.h:249
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:44
equisolid_to_xyz
static int equisolid_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in equisolid format.
Definition: vf_v360.c:1964
OFFSET
#define OFFSET(x)
Definition: vf_v360.c:53
GAUSSIAN
@ GAUSSIAN
Definition: v360.h:68
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
AV_PIX_FMT_YUV444P9
#define AV_PIX_FMT_YUV444P9
Definition: pixfmt.h:501
mod
static int mod(int a, int b)
Modulo operation with only positive remainders.
Definition: vf_v360.c:755
TOP_RIGHT
#define TOP_RIGHT
Definition: movtextdec.c:52
DUAL_FISHEYE
@ DUAL_FISHEYE
Definition: v360.h:38
slice_start
static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, const CodedBitstreamUnit *unit, const int is_first_slice)
Definition: dec.c:738
BACK
@ BACK
Axis +Z.
Definition: v360.h:89
AVFilter
Filter definition.
Definition: avfilter.h:201
prepare_flat_out
static int prepare_flat_out(AVFilterContext *ctx)
Prepare data for processing flat output format.
Definition: vf_v360.c:2824
STEREOGRAPHIC
@ STEREOGRAPHIC
Definition: v360.h:41
hequirect_to_xyz
static int hequirect_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in half equirectangular format.
Definition: vf_v360.c:1814
ret
ret
Definition: filter_design.txt:187
CUBEMAP_1_6
@ CUBEMAP_1_6
Definition: v360.h:40
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
xyz_to_cylindricalea
static int xyz_to_cylindricalea(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in cylindrical equal area format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:3233
xyz_to_tetrahedron
static int xyz_to_tetrahedron(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in tetrahedron format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:3345
NB_INTERP_METHODS
@ NB_INTERP_METHODS
Definition: v360.h:70
PITCH
@ PITCH
Definition: v360.h:103
STEREO_2D
@ STEREO_2D
Definition: v360.h:26
AV_PIX_FMT_YUVA444P9
#define AV_PIX_FMT_YUVA444P9
Definition: pixfmt.h:539
NB_STEREO_FMTS
@ NB_STEREO_FMTS
Definition: v360.h:29
DEFINE_REMAP1_LINE
#define DEFINE_REMAP1_LINE(bits, div)
Definition: vf_v360.c:259
xyz_to_equisolid
static int xyz_to_equisolid(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in equisolid format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2010
TOP_MIDDLE
@ TOP_MIDDLE
Definition: v360.h:75
AV_PIX_FMT_YUV420P12
#define AV_PIX_FMT_YUV420P12
Definition: pixfmt.h:506
sinusoidal_to_xyz
static int sinusoidal_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in sinusoidal format.
Definition: vf_v360.c:2543
normalize_vector
static void normalize_vector(float *vec)
Normalize vector.
Definition: vf_v360.c:1054
EQUIRECTANGULAR
@ EQUIRECTANGULAR
Definition: v360.h:33
AV_PIX_FMT_YUV422P14
#define AV_PIX_FMT_YUV422P14
Definition: pixfmt.h:511
BILINEAR
@ BILINEAR
Definition: v360.h:63
get_rorder
static int get_rorder(char c)
Convert char to corresponding rotation order.
Definition: vf_v360.c:861
ff_set_common_formats_from_list2
int ff_set_common_formats_from_list2(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out, const int *fmts)
Definition: formats.c:1016
NB_DIRECTIONS
@ NB_DIRECTIONS
Definition: v360.h:90
ff_filter_execute
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: avfilter.c:1667
xyz_to_pannini
static int xyz_to_pannini(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in pannini format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:3013
STEREO_TB
@ STEREO_TB
Definition: v360.h:28
cylindricalea_to_xyz
static int cylindricalea_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in cylindrical equal area format.
Definition: vf_v360.c:3199
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
AV_PIX_FMT_YUVA422P12
#define AV_PIX_FMT_YUVA422P12
Definition: pixfmt.h:543
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
avfilter.h
calculate_bicubic_coeffs
static void calculate_bicubic_coeffs(float t, float *coeffs)
Calculate 1-dimensional cubic coefficients.
Definition: vf_v360.c:495
temp
else temp
Definition: vf_mcdeint.c:263
SINUSOIDAL
@ SINUSOIDAL
Definition: v360.h:45
LAGRANGE9
@ LAGRANGE9
Definition: v360.h:64
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:78
AVFilterContext
An instance of a filter.
Definition: avfilter.h:457
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:165
prepare_flat_in
static int prepare_flat_in(AVFilterContext *ctx)
Prepare data for processing flat input format.
Definition: vf_v360.c:2257
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:152
desc
const char * desc
Definition: libsvtav1.c:79
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AV_PIX_FMT_YUV422P
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:77
mem.h
multiply_quaternion
static void multiply_quaternion(float c[4], const float a[4], const float b[4])
Definition: vf_v360.c:4017
STEREO_SBS
@ STEREO_SBS
Definition: v360.h:27
M_SQRT2
#define M_SQRT2
Definition: mathematics.h:109
dfisheye_to_xyz
static int dfisheye_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in dual fisheye format.
Definition: vf_v360.c:3417
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
xyz_to_barrelsplit
static int xyz_to_barrelsplit(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in barrel split facebook's format for corresponding 3D coordinates on sphere...
Definition: vf_v360.c:3650
xyz_to_hequirect
static int xyz_to_hequirect(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in half equirectangular format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:2222
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
alpha
static const int16_t alpha[]
Definition: ilbcdata.h:55
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
input_flip
static void input_flip(int16_t u[4][4], int16_t v[4][4], int w, int h, int hflip, int vflip)
Definition: vf_v360.c:4104
calculate_rotation
static void calculate_rotation(float yaw, float pitch, float roll, float rot_quaternion[2][4], const int rotation_order[3])
Calculate rotation quaternion for yaw/pitch/roll angles.
Definition: vf_v360.c:4036
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
xyz_to_dfisheye
static int xyz_to_dfisheye(const V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Calculate frame position in dual fisheye format for corresponding 3D coordinates on sphere.
Definition: vf_v360.c:3456
AV_PIX_FMT_YUV411P
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:80
cube_to_xyz
static void cube_to_xyz(const V360Context *s, float uf, float vf, int face, float *vec, float scalew, float scaleh)
Calculate 3D coordinates on sphere for corresponding cubemap position.
Definition: vf_v360.c:1075
FFMAX3
#define FFMAX3(a, b, c)
Definition: macros.h:48
tspyramid_to_xyz
static int tspyramid_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in tspyramid format.
Definition: vf_v360.c:3821
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
fov_from_dfov
static void fov_from_dfov(int format, float d_fov, float w, float h, float *h_fov, float *v_fov)
Definition: vf_v360.c:4155
AV_PIX_FMT_YUV410P
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:79
set_mirror_modifier
static void set_mirror_modifier(int h_flip, int v_flip, int d_flip, float *modifier)
Definition: vf_v360.c:4089
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
TOP_LEFT
#define TOP_LEFT
Definition: movtextdec.c:50
prepare_cylindricalea_in
static int prepare_cylindricalea_in(AVFilterContext *ctx)
Prepare data for processing cylindrical equal area input format.
Definition: vf_v360.c:3179
AV_PIX_FMT_YUV440P12
#define AV_PIX_FMT_YUV440P12
Definition: pixfmt.h:508
h
h
Definition: vp9dsp_template.c:2070
AV_PIX_FMT_YUV444P14
#define AV_PIX_FMT_YUV444P14
Definition: pixfmt.h:512
AV_OPT_TYPE_STRING
@ 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...
Definition: opt.h:276
width
#define width
Definition: dsp.h:85
AV_PIX_FMT_GRAY12
#define AV_PIX_FMT_GRAY12
Definition: pixfmt.h:484
alpha_pix_fmts
static enum AVPixelFormat alpha_pix_fmts[]
Definition: vf_overlay.c:157
vf
uint8_t ptrdiff_t const uint8_t ptrdiff_t int const int8_t const int8_t * vf
Definition: dsp.h:249
TETRAHEDRON
@ TETRAHEDRON
Definition: v360.h:50
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition: opt.h:299
get_direction
static int get_direction(char c)
Convert char to corresponding direction.
Definition: vf_v360.c:818
prepare_eac_in
static int prepare_eac_in(AVFilterContext *ctx)
Prepare data for processing equi-angular cubemap input format.
Definition: vf_v360.c:2607
set_dimensions
static void set_dimensions(int *outw, int *outh, int w, int h, const AVPixFmtDescriptor *desc)
Definition: vf_v360.c:4228
AV_PIX_FMT_YUVA422P
@ AV_PIX_FMT_YUVA422P
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition: pixfmt.h:173
AV_PIX_FMT_YUV420P14
#define AV_PIX_FMT_YUV420P14
Definition: pixfmt.h:510
flat_to_xyz
static int flat_to_xyz(const V360Context *s, int i, int j, int width, int height, float *vec)
Calculate 3D coordinates on sphere for corresponding frame position in flat format.
Definition: vf_v360.c:2844
ff_vf_v360
const AVFilter ff_vf_v360
Definition: vf_v360.c:4998
BOTTOM_RIGHT
@ BOTTOM_RIGHT
Definition: v360.h:79
prepare_orthographic_in
static int prepare_orthographic_in(AVFilterContext *ctx)
Prepare data for processing orthographic input format.
Definition: vf_v360.c:2099
ui
#define ui(width, name)
Definition: cbs_mpeg2.c:113