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