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