FFmpeg  4.3
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[] = {
238  AV_PIX_FMT_NONE
239  };
240 
241  AVFilterFormats *fmts_list = ff_make_format_list(s->alpha ? alpha_pix_fmts : pix_fmts);
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') {
810  av_log(ctx, AV_LOG_ERROR,
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) {
817  av_log(ctx, AV_LOG_ERROR,
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') {
830  av_log(ctx, AV_LOG_ERROR,
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) {
837  av_log(ctx, AV_LOG_ERROR,
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') {
864  av_log(ctx, AV_LOG_ERROR,
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) {
871  av_log(ctx, AV_LOG_ERROR,
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') {
884  av_log(ctx, AV_LOG_ERROR,
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) {
891  av_log(ctx, AV_LOG_ERROR,
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 
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];
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) {
2271  } else if (s->ih_flip) {
2278  } else if (s->iv_flip) {
2285  } else {
2292  }
2293 
2294  if (s->iv_flip) {
2301  } else {
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 
2330 
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:
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:
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:
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:
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:
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:
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:
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') {
3838  av_log(ctx, AV_LOG_WARNING,
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) {
3848  av_log(ctx, AV_LOG_WARNING,
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:
3896  err = 0;
3897  wf = w;
3898  hf = h;
3899  break;
3900  case CUBEMAP_3_2:
3902  err = prepare_cube_in(ctx);
3903  wf = w / 3.f * 4.f;
3904  hf = h;
3905  break;
3906  case CUBEMAP_1_6:
3908  err = prepare_cube_in(ctx);
3909  wf = w * 4.f;
3910  hf = h / 3.f;
3911  break;
3912  case CUBEMAP_6_1:
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:
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:
3935  err = prepare_fisheye_in(ctx);
3936  wf = w;
3937  hf = h;
3938  break;
3939  case BARREL:
3941  err = 0;
3942  wf = w / 5.f * 4.f;
3943  hf = h;
3944  break;
3945  case STEREOGRAPHIC:
3947  err = prepare_stereographic_in(ctx);
3948  wf = w;
3949  hf = h / 2.f;
3950  break;
3951  case MERCATOR:
3953  err = 0;
3954  wf = w;
3955  hf = h / 2.f;
3956  break;
3957  case BALL:
3959  err = 0;
3960  wf = w;
3961  hf = h / 2.f;
3962  break;
3963  case HAMMER:
3965  err = 0;
3966  wf = w;
3967  hf = h;
3968  break;
3969  case SINUSOIDAL:
3971  err = 0;
3972  wf = w;
3973  hf = h;
3974  break;
3975  case FISHEYE:
3977  err = prepare_fisheye_in(ctx);
3978  wf = w * 2;
3979  hf = h;
3980  break;
3981  case PANNINI:
3983  err = 0;
3984  wf = w;
3985  hf = h;
3986  break;
3987  case CYLINDRICAL:
3989  err = prepare_cylindrical_in(ctx);
3990  wf = w;
3991  hf = h * 2.f;
3992  break;
3993  case TETRAHEDRON:
3995  err = 0;
3996  wf = w;
3997  hf = h;
3998  break;
3999  case BARREL_SPLIT:
4001  err = 0;
4002  wf = w * 4.f / 3.f;
4003  hf = h;
4004  break;
4005  case TSPYRAMID:
4007  err = 0;
4008  wf = w;
4009  hf = h;
4010  break;
4011  case HEQUIRECTANGULAR:
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:
4029  prepare_out = NULL;
4030  w = lrintf(wf);
4031  h = lrintf(hf);
4032  break;
4033  case CUBEMAP_3_2:
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:
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:
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:
4053  prepare_out = prepare_eac_out;
4054  w = lrintf(wf);
4055  h = lrintf(hf / 8.f * 9.f);
4056  break;
4057  case FLAT:
4059  prepare_out = prepare_flat_out;
4060  w = lrintf(wf);
4061  h = lrintf(hf);
4062  break;
4063  case DUAL_FISHEYE:
4065  prepare_out = prepare_fisheye_out;
4066  w = lrintf(wf);
4067  h = lrintf(hf);
4068  break;
4069  case BARREL:
4071  prepare_out = NULL;
4072  w = lrintf(wf / 4.f * 5.f);
4073  h = lrintf(hf);
4074  break;
4075  case STEREOGRAPHIC:
4077  prepare_out = prepare_stereographic_out;
4078  w = lrintf(wf);
4079  h = lrintf(hf * 2.f);
4080  break;
4081  case MERCATOR:
4083  prepare_out = NULL;
4084  w = lrintf(wf);
4085  h = lrintf(hf * 2.f);
4086  break;
4087  case BALL:
4089  prepare_out = NULL;
4090  w = lrintf(wf);
4091  h = lrintf(hf * 2.f);
4092  break;
4093  case HAMMER:
4095  prepare_out = NULL;
4096  w = lrintf(wf);
4097  h = lrintf(hf);
4098  break;
4099  case SINUSOIDAL:
4101  prepare_out = NULL;
4102  w = lrintf(wf);
4103  h = lrintf(hf);
4104  break;
4105  case FISHEYE:
4107  prepare_out = prepare_fisheye_out;
4108  w = lrintf(wf * 0.5f);
4109  h = lrintf(hf);
4110  break;
4111  case PANNINI:
4113  prepare_out = NULL;
4114  w = lrintf(wf);
4115  h = lrintf(hf);
4116  break;
4117  case CYLINDRICAL:
4119  prepare_out = prepare_cylindrical_out;
4120  w = lrintf(wf);
4121  h = lrintf(hf * 0.5f);
4122  break;
4123  case PERSPECTIVE:
4125  prepare_out = NULL;
4126  w = lrintf(wf / 2.f);
4127  h = lrintf(hf);
4128  break;
4129  case TETRAHEDRON:
4131  prepare_out = NULL;
4132  w = lrintf(wf);
4133  h = lrintf(hf);
4134  break;
4135  case BARREL_SPLIT:
4137  prepare_out = NULL;
4138  w = lrintf(wf / 4.f * 3.f);
4139  h = lrintf(hf);
4140  break;
4141  case TSPYRAMID:
4143  prepare_out = NULL;
4144  w = lrintf(wf);
4145  h = lrintf(hf);
4146  break;
4147  case HEQUIRECTANGULAR:
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 
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 
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  }
4258  av_frame_copy_props(out, in);
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 };
Definition: v360.h:60
Definition: v360.h:42
Axis +Z.
Definition: v360.h:84
int(* in_transform)(const struct V360Context *s, const float *vec, int width, int height, int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
Definition: v360.h:170
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
#define NULL
Definition: coverity.c:32
static void multiply_matrix(float c[3][3], const float a[3][3], const float b[3][3])
Definition: vf_v360.c:3535
static const AVOption v360_options[]
Definition: vf_v360.c:57
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
#define AV_PIX_FMT_YUVA422P16
Definition: pixfmt.h:440
float iflat_range[2]
Definition: v360.h:141
AVFrame * out
Definition: af_adeclick.c:494
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
#define AV_PIX_FMT_YUV440P10
Definition: pixfmt.h:399
static const char * format[]
Definition: af_aiir.c:339
#define AV_PIX_FMT_YUVA422P9
Definition: pixfmt.h:432
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2549
int nb_planes
Definition: v360.h:159
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
This structure describes decoded (raw) audio or video data.
Definition: frame.h:300
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
#define TOP_LEFT
Definition: movtextdec.c:48
int in_transpose
Definition: v360.h:136
AVOption.
Definition: opt.h:246
float input_mirror_modifier[2]
Definition: v360.h:145
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&#39;s format for corresponding 3D coordinates on sphere...
Definition: vf_v360.c:3230
#define AV_PIX_FMT_YUVA420P10
Definition: pixfmt.h:434
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
int h_flip
Definition: v360.h:135
#define AV_PIX_FMT_YUV444P14
Definition: pixfmt.h:407
static void calculate_lanczos_coeffs(float t, float *coeffs)
Calculate 1-dimensional lanczos coefficients.
Definition: vf_v360.c:521
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:417
static int prepare_stereographic_out(AVFilterContext *ctx)
Prepare data for processing stereographic output format.
Definition: vf_v360.c:1723
#define AV_PIX_FMT_YUVA422P10
Definition: pixfmt.h:435
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
Definition: v360.h:28
misc image utilities
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
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
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2589
Main libavfilter public API header.
else temp
Definition: vf_mcdeint.c:256
int elements
Definition: v360.h:161
static int prepare_eac_out(AVFilterContext *ctx)
Prepare data for processing equi-angular cubemap output format.
Definition: vf_v360.c:2320
int alpha
Definition: v360.h:113
static void rotate_cube_face_inverse(float *uf, float *vf, int rotation)
Definition: vf_v360.c:928
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
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
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:168
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
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
static void rotate_cube_face(float *uf, float *vf, int rotation)
Definition: vf_v360.c:902
int in
Definition: v360.h:111
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:413
static int get_rorder(char c)
Convert char to corresponding rotation order.
Definition: vf_v360.c:777
#define us(width, name, range_min, range_max, subs,...)
Definition: cbs_h2645.c:276
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
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
Definition: v360.h:52
Definition: v360.h:37
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
#define AV_PIX_FMT_GRAY9
Definition: pixfmt.h:377
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
#define AV_PIX_FMT_YUV420P12
Definition: pixfmt.h:401
int inplanewidth[4]
Definition: v360.h:157
int out_offset_w[4]
Definition: v360.h:154
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
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
static void set_mirror_modifier(int h_flip, int v_flip, int d_flip, float *modifier)
Definition: vf_v360.c:3604
char * in_frot
Definition: v360.h:117
int pr_height[4]
Definition: v360.h:151
static int config_output(AVFilterLink *outlink)
Definition: vf_v360.c:3755
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:92
static int reflectx(int x, int y, int w, int h)
Reflect x operation.
Definition: vf_v360.c:722
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:247
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
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
#define AV_PIX_FMT_GRAY10
Definition: pixfmt.h:378
Axis +Y.
Definition: v360.h:81
Definition: v360.h:47
int16_t u[4][4]
Definition: v360.h:104
const char * name
Pad name.
Definition: internal.h:60
static int allocate_plane(V360Context *s, int sizeof_uv, int sizeof_ker, int sizeof_mask, int p)
Definition: vf_v360.c:3619
#define AV_PIX_FMT_GRAY12
Definition: pixfmt.h:379
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
float pitch
Definition: v360.h:132
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1075
float roll
Definition: v360.h:132
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:101
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:117
static void calculate_gaussian_coeffs(float t, float *coeffs)
Calculate 1-dimensional gaussian coefficients.
Definition: vf_v360.c:616
uint8_t
float yaw
Definition: v360.h:132
#define av_cold
Definition: attributes.h:88
#define AV_PIX_FMT_FLAG_ALPHA
The pixel format has an alpha channel.
Definition: pixdesc.h:177
AVOptions.
int out_transpose
Definition: v360.h:136
int planeheight[4]
Definition: v360.h:156
#define f(width, name)
Definition: cbs_vp9.c:255
Axis -Y.
Definition: v360.h:82
char * out_frot
Definition: v360.h:118
void(* calculate_kernel)(float du, float dv, const XYRemap *rmap, int16_t *u, int16_t *v, int16_t *ker)
Definition: v360.h:178
#define u(width, name, range_min, range_max)
Definition: cbs_h2645.c:262
#define AV_PIX_FMT_YUVA420P9
Definition: pixfmt.h:431
float iv_fov
Definition: v360.h:139
Definition: v360.h:99
#define cosf(x)
Definition: libm.h:78
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:412
int height
Definition: vf_avgblur.c:61
static int prepare_cylindrical_out(AVFilterContext *ctx)
Prepare data for processing cylindrical output format.
Definition: vf_v360.c:2747
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
#define atanf(x)
Definition: libm.h:40
AVFilter ff_vf_v360
Definition: vf_v360.c:4311
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range...
Definition: pixfmt.h:100
int height
Definition: v360.h:114
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
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition: pixfmt.h:79
#define atan2f(y, x)
Definition: libm.h:45
float ih_fov
Definition: v360.h:139
#define lrintf(x)
Definition: libm_mips.h:70
int width
Definition: v360.h:114
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:410
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
#define AV_PIX_FMT_YUV422P12
Definition: pixfmt.h:402
#define AV_PIX_FMT_YUVA420P16
Definition: pixfmt.h:439
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
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
#define FFALIGN(x, a)
Definition: macros.h:48
int rotation_order[3]
Definition: v360.h:125
#define av_log(a,...)
A filter pad used for either input or output.
Definition: internal.h:54
#define expf(x)
Definition: libm.h:283
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
int fin_pad
Definition: v360.h:130
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
int in_stereo
Definition: v360.h:127
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&#39;s format...
Definition: vf_v360.c:3327
void ff_v360_init(V360Context *s, int depth)
Definition: vf_v360.c:359
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition: pixfmt.h:176
int max_value
Definition: v360.h:163
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
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:600
#define td
Definition: regdef.h:70
Definition: v360.h:97
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&#39;s format...
Definition: vf_v360.c:3081
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:101
Definition: v360.h:44
Definition: v360.h:46
static void mirror(const float *modifier, float *vec)
Definition: vf_v360.c:3612
#define S(s, c, i)
#define ARCH_X86
Definition: config.h:38
#define isfinite(x)
Definition: libm.h:359
static int prepare_fisheye_out(AVFilterContext *ctx)
Prepare data for processing fisheye output format.
Definition: vf_v360.c:2554
#define AVERROR(e)
Definition: error.h:43
int out_offset_h[4]
Definition: v360.h:154
#define DEFINE_REMAP1_LINE(bits, div)
Definition: vf_v360.c:247
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
#define FF_CEIL_RSHIFT
Definition: common.h:61
static void calculate_bicubic_coeffs(float t, float *coeffs)
Calculate 1-dimensional cubic coefficients.
Definition: vf_v360.c:476
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
#define FLAGS
Definition: vf_v360.c:54
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
const char * r
Definition: vf_curves.c:114
void * priv
private data for use by the filter
Definition: avfilter.h:353
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:116
#define AV_PIX_FMT_YUVA444P16
Definition: pixfmt.h:441
const char * arg
Definition: jacosubdec.c:66
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:418
simple assert() macros that are a bit more flexible than ISO C assert().
static int prepare_eac_in(AVFilterContext *ctx)
Prepare data for processing equi-angular cubemap input format.
Definition: vf_v360.c:2260
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
Definition: v360.h:63
Definition: v360.h:92
static void set_dimensions(int *outw, int *outh, int w, int h, const AVPixFmtDescriptor *desc)
Definition: vf_v360.c:3690
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
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:400
Definition: v360.h:58
int in_offset_w[4]
Definition: v360.h:153
#define FFMAX(a, b)
Definition: common.h:94
int16_t * v[2]
Definition: v360.h:165
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
int out
Definition: v360.h:111
int out_stereo
Definition: v360.h:127
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:419
uint8_t * mask
Definition: v360.h:167
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
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
Definition: v360.h:61
int out_cubemap_face_rotation[6]
Definition: v360.h:124
int16_t * ker[2]
Definition: v360.h:166
int in_offset_h[4]
Definition: v360.h:153
static void calculate_spline16_coeffs(float t, float *coeffs)
Calculate 1-dimensional spline16 coefficients.
Definition: vf_v360.c:574
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
#define AV_PIX_FMT_YUV422P9
Definition: pixfmt.h:395
unsigned map[4]
Definition: v360.h:168
int ih_flip
Definition: v360.h:134
int interp
Definition: v360.h:112
int in_height
Definition: v360.h:148
#define OFFSET(x)
Definition: vf_v360.c:53
Definition: v360.h:90
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:416
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:784
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:381
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:53
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
float in_pad
Definition: v360.h:129
#define FFMIN(a, b)
Definition: common.h:96
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
float out_pad
Definition: v360.h:129
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition: pixfmt.h:78
static av_always_inline int v360_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_v360.c:3699
#define AV_PIX_FMT_YUVA444P12
Definition: pixfmt.h:438
static int prepare_stereographic_in(AVFilterContext *ctx)
Prepare data for processing stereographic input format.
Definition: vf_v360.c:1769
int(* out_transform)(const struct V360Context *s, int i, int j, int width, int height, float *vec)
Definition: v360.h:174
Definition: v360.h:26
static int query_formats(AVFilterContext *ctx)
Definition: vf_v360.c:163
#define M_PI_2
Definition: mathematics.h:55
int inplaneheight[4]
Definition: v360.h:157
AVFrame * m
int mask_size
Definition: v360.h:162
Definition: v360.h:59
AVFormatContext * ctx
Definition: movenc.c:48
Definition: v360.h:62
static int ereflectx(int x, int y, int w, int h)
Reflect x operation for equirect.
Definition: vf_v360.c:706
AVFILTER_DEFINE_CLASS(v360)
int in_cubemap_face_order[6]
Definition: v360.h:121
static void calculate_lagrange_coeffs(float t, float *coeffs)
Calculate 1-dimensional lagrange coefficients.
Definition: vf_v360.c:435
#define AV_PIX_FMT_YUVA444P10
Definition: pixfmt.h:436
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
static const AVFilterPad outputs[]
Definition: vf_v360.c:4302
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_v360.c:4269
int(* remap_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: v360.h:181
#define AV_PIX_FMT_YUV444P9
Definition: pixfmt.h:396
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:415
#define AV_PIX_FMT_YUV420P16
Definition: pixfmt.h:408
float v_fov
Definition: v360.h:138
float output_mirror_modifier[3]
Definition: v360.h:146
Definition: v360.h:98
#define sinf(x)
Definition: libm.h:419
#define DEFINE_REMAP_LINE(ws, bits, div)
Definition: vf_v360.c:325
#define TOP_RIGHT
Definition: movtextdec.c:50
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_v360.c:4281
#define AV_PIX_FMT_YUV420P14
Definition: pixfmt.h:405
static int prepare_flat_out(AVFilterContext *ctx)
Prepare data for processing flat output format.
Definition: vf_v360.c:2511
int16_t v[4][4]
Definition: v360.h:105
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
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
int planewidth[4]
Definition: v360.h:156
Used for passing data between threads.
Definition: dsddec.c:67
int in_cubemap_face_rotation[6]
Definition: v360.h:123
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:177
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
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
static int mod(int a, int b)
Modulo operation with only positive remainders.
Definition: vf_v360.c:671
int nb_allocated
Definition: v360.h:160
float id_fov
Definition: v360.h:139
#define AV_PIX_FMT_GRAY14
Definition: pixfmt.h:380
static const int16_t alpha[]
Definition: ilbcdata.h:55
Definition: v360.h:89
static int prepare_cube_in(AVFilterContext *ctx)
Prepare data for processing cubemap input format.
Definition: vf_v360.c:801
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
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
int d_flip
Definition: v360.h:135
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_v360.c:4245
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
int out_cubemap_direction_order[6]
Definition: v360.h:122
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:397
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:72
static const AVFilterPad inputs[]
Definition: vf_v360.c:4293
Definition: v360.h:103
Filter definition.
Definition: avfilter.h:144
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
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
#define isnan(x)
Definition: libm.h:340
AVFrame * b
int v_flip
Definition: v360.h:135
#define DEFINE_REMAP(ws, bits)
Generate remapping function with a given window size and pixel depth.
Definition: vf_v360.c:271
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
const char * name
Filter name.
Definition: avfilter.h:148
#define AV_PIX_FMT_YUV440P12
Definition: pixfmt.h:403
#define AV_PIX_FMT_YUV420P9
Definition: pixfmt.h:394
char * in_forder
Definition: v360.h:115
static int reflecty(int y, int h)
Reflect y operation.
Definition: vf_v360.c:687
static int prepare_cube_out(AVFilterContext *ctx)
Prepare data for processing cubemap output format.
Definition: vf_v360.c:855
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
int outw
Definition: vf_rotate.c:88
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
float flat_range[2]
Definition: v360.h:140
#define AV_PIX_FMT_YUV422P14
Definition: pixfmt.h:406
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
int pr_width[4]
Definition: v360.h:151
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:414
#define flags(name, subs,...)
Definition: cbs_av1.c:564
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:378
#define AV_PIX_FMT_YUV422P10
Definition: pixfmt.h:398
float rot_mat[3][3]
Definition: v360.h:143
int uv_linesize[4]
Definition: v360.h:158
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:404
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
#define M_SQRT2
Definition: mathematics.h:61
static int prepare_flat_in(AVFilterContext *ctx)
Prepare data for processing flat input format.
Definition: vf_v360.c:1907
float h_fov
Definition: v360.h:138
void ff_v360_init_x86(V360Context *s, int depth)
Definition: vf_v360_init.c:44
int
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
static void normalize_vector(float *vec)
Normalize vector.
Definition: vf_v360.c:959
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
Y , 8bpp.
Definition: pixfmt.h:74
static void rotate(const float rot_mat[3][3], float *vec)
Rotate vector with given rotation matrix.
Definition: vf_v360.c:3592
Definition: v360.h:91
int iv_flip
Definition: v360.h:134
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
int fout_pad
Definition: v360.h:130
static int get_rotation(char c)
Convert char to corresponding rotation angle.
Definition: vf_v360.c:758
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:215
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&#39;s format for corresponding 3D coordinates on sphere...
Definition: vf_v360.c:3155
#define AV_PIX_FMT_YUVA444P9
Definition: pixfmt.h:433
#define ui(width, name)
Definition: cbs_mpeg2.c:43
Definition: v360.h:75
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition: pixfmt.h:80
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:73
Definition: v360.h:43
char * out_forder
Definition: v360.h:116
avfilter_execute_func * execute
Definition: internal.h:144
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
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2040
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
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
Axis -Z.
Definition: v360.h:83
static int get_direction(char c)
Convert char to corresponding direction.
Definition: vf_v360.c:734
const AVPixFmtDescriptor * desc
Definition: vf_tonemap.c:196
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
A list of supported formats for one end of a filter link.
Definition: formats.h:64
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor ...
Definition: pixfmt.h:258
An instance of a filter.
Definition: avfilter.h:338
#define RIGHT
Definition: cdgraphics.c:167
#define av_freep(p)
const void ** s
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
#define av_always_inline
Definition: attributes.h:45
#define M_PI
Definition: mathematics.h:52
Definition: v360.h:39
AVFrame * in
Definition: af_afftdn.c:1083
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
#define FFSWAP(type, a, b)
Definition: common.h:99
#define TFLAGS
Definition: vf_v360.c:55
int outh
Definition: vf_rotate.c:88
#define LEFT
Definition: cdgraphics.c:166
AVFilterLink * inlink
Definition: vf_blend.c:57
static int prepare_fisheye_in(AVFilterContext *ctx)
Prepare data for processing fisheye input format.
Definition: vf_v360.c:2605
internal API functions
char * rorder
Definition: v360.h:119
int depth
Number of bits in the component.
Definition: pixdesc.h:58
AVFrame * a
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
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
float d_fov
Definition: v360.h:138
int in_width
Definition: v360.h:148
#define AV_PIX_FMT_YUV422P16
Definition: pixfmt.h:409
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:659
#define FFMAX3(a, b, c)
Definition: common.h:95
static enum AVPixelFormat alpha_pix_fmts[]
Definition: vf_overlay.c:155
static int prepare_cylindrical_in(AVFilterContext *ctx)
Prepare data for processing cylindrical input format.
Definition: vf_v360.c:2798
#define AV_PIX_FMT_YUVA422P12
Definition: pixfmt.h:437
int16_t * u[2]
Definition: v360.h:165
Definition: v360.h:64
static uint8_t tmp[11]
Definition: aes_ctr.c:26