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