FFmpeg
vf_v360.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Eugene Lyapustin
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * 360 video conversion filter.
24  * Principle of operation:
25  *
26  * (for each pixel in output frame)
27  * 1) Calculate OpenGL-like coordinates (x, y, z) for pixel position (i, j)
28  * 2) Apply 360 operations (rotation, mirror) to (x, y, z)
29  * 3) Calculate pixel position (u, v) in input frame
30  * 4) Calculate interpolation window and weight for each pixel
31  *
32  * (for each frame)
33  * 5) Remap input frame to output frame using precalculated data
34  */
35 
36 #include <math.h>
37 
38 #include "libavutil/avassert.h"
39 #include "libavutil/imgutils.h"
40 #include "libavutil/pixdesc.h"
41 #include "libavutil/opt.h"
42 #include "avfilter.h"
43 #include "formats.h"
44 #include "internal.h"
45 #include "video.h"
46 #include "v360.h"
47 
48 typedef struct ThreadData {
49  AVFrame *in;
50  AVFrame *out;
51 } ThreadData;
52 
53 #define OFFSET(x) offsetof(V360Context, x)
54 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
55 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
56 
57 static const AVOption v360_options[] = {
58  { "input", "set input projection", OFFSET(in), AV_OPT_TYPE_INT, {.i64=EQUIRECTANGULAR}, 0, NB_PROJECTIONS-1, FLAGS, "in" },
59  { "e", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "in" },
60  { "equirect", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "in" },
61  { "c3x2", "cubemap 3x2", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_3_2}, 0, 0, FLAGS, "in" },
62  { "c6x1", "cubemap 6x1", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_6_1}, 0, 0, FLAGS, "in" },
63  { "eac", "equi-angular cubemap", 0, AV_OPT_TYPE_CONST, {.i64=EQUIANGULAR}, 0, 0, FLAGS, "in" },
64  { "dfisheye", "dual fisheye", 0, AV_OPT_TYPE_CONST, {.i64=DUAL_FISHEYE}, 0, 0, FLAGS, "in" },
65  { "flat", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "in" },
66  {"rectilinear", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "in" },
67  { "gnomonic", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "in" },
68  { "barrel", "barrel facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL}, 0, 0, FLAGS, "in" },
69  { "fb", "barrel facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL}, 0, 0, FLAGS, "in" },
70  { "c1x6", "cubemap 1x6", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_1_6}, 0, 0, FLAGS, "in" },
71  { "sg", "stereographic", 0, AV_OPT_TYPE_CONST, {.i64=STEREOGRAPHIC}, 0, 0, FLAGS, "in" },
72  { "mercator", "mercator", 0, AV_OPT_TYPE_CONST, {.i64=MERCATOR}, 0, 0, FLAGS, "in" },
73  { "ball", "ball", 0, AV_OPT_TYPE_CONST, {.i64=BALL}, 0, 0, FLAGS, "in" },
74  { "hammer", "hammer", 0, AV_OPT_TYPE_CONST, {.i64=HAMMER}, 0, 0, FLAGS, "in" },
75  {"sinusoidal", "sinusoidal", 0, AV_OPT_TYPE_CONST, {.i64=SINUSOIDAL}, 0, 0, FLAGS, "in" },
76  { "fisheye", "fisheye", 0, AV_OPT_TYPE_CONST, {.i64=FISHEYE}, 0, 0, FLAGS, "in" },
77  { "pannini", "pannini", 0, AV_OPT_TYPE_CONST, {.i64=PANNINI}, 0, 0, FLAGS, "in" },
78  {"cylindrical", "cylindrical", 0, AV_OPT_TYPE_CONST, {.i64=CYLINDRICAL}, 0, 0, FLAGS, "in" },
79  {"tetrahedron", "tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=TETRAHEDRON}, 0, 0, FLAGS, "in" },
80  {"barrelsplit", "barrel split facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL_SPLIT}, 0, 0, FLAGS, "in" },
81  { "tsp", "truncated square pyramid", 0, AV_OPT_TYPE_CONST, {.i64=TSPYRAMID}, 0, 0, FLAGS, "in" },
82  { "hequirect", "half equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=HEQUIRECTANGULAR},0, 0, FLAGS, "in" },
83  { "he", "half equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=HEQUIRECTANGULAR},0, 0, FLAGS, "in" },
84  { "output", "set output projection", OFFSET(out), AV_OPT_TYPE_INT, {.i64=CUBEMAP_3_2}, 0, NB_PROJECTIONS-1, FLAGS, "out" },
85  { "e", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "out" },
86  { "equirect", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=EQUIRECTANGULAR}, 0, 0, FLAGS, "out" },
87  { "c3x2", "cubemap 3x2", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_3_2}, 0, 0, FLAGS, "out" },
88  { "c6x1", "cubemap 6x1", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_6_1}, 0, 0, FLAGS, "out" },
89  { "eac", "equi-angular cubemap", 0, AV_OPT_TYPE_CONST, {.i64=EQUIANGULAR}, 0, 0, FLAGS, "out" },
90  { "dfisheye", "dual fisheye", 0, AV_OPT_TYPE_CONST, {.i64=DUAL_FISHEYE}, 0, 0, FLAGS, "out" },
91  { "flat", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "out" },
92  {"rectilinear", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "out" },
93  { "gnomonic", "regular video", 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "out" },
94  { "barrel", "barrel facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL}, 0, 0, FLAGS, "out" },
95  { "fb", "barrel facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL}, 0, 0, FLAGS, "out" },
96  { "c1x6", "cubemap 1x6", 0, AV_OPT_TYPE_CONST, {.i64=CUBEMAP_1_6}, 0, 0, FLAGS, "out" },
97  { "sg", "stereographic", 0, AV_OPT_TYPE_CONST, {.i64=STEREOGRAPHIC}, 0, 0, FLAGS, "out" },
98  { "mercator", "mercator", 0, AV_OPT_TYPE_CONST, {.i64=MERCATOR}, 0, 0, FLAGS, "out" },
99  { "ball", "ball", 0, AV_OPT_TYPE_CONST, {.i64=BALL}, 0, 0, FLAGS, "out" },
100  { "hammer", "hammer", 0, AV_OPT_TYPE_CONST, {.i64=HAMMER}, 0, 0, FLAGS, "out" },
101  {"sinusoidal", "sinusoidal", 0, AV_OPT_TYPE_CONST, {.i64=SINUSOIDAL}, 0, 0, FLAGS, "out" },
102  { "fisheye", "fisheye", 0, AV_OPT_TYPE_CONST, {.i64=FISHEYE}, 0, 0, FLAGS, "out" },
103  { "pannini", "pannini", 0, AV_OPT_TYPE_CONST, {.i64=PANNINI}, 0, 0, FLAGS, "out" },
104  {"cylindrical", "cylindrical", 0, AV_OPT_TYPE_CONST, {.i64=CYLINDRICAL}, 0, 0, FLAGS, "out" },
105  {"perspective", "perspective", 0, AV_OPT_TYPE_CONST, {.i64=PERSPECTIVE}, 0, 0, FLAGS, "out" },
106  {"tetrahedron", "tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=TETRAHEDRON}, 0, 0, FLAGS, "out" },
107  {"barrelsplit", "barrel split facebook's 360 format", 0, AV_OPT_TYPE_CONST, {.i64=BARREL_SPLIT}, 0, 0, FLAGS, "out" },
108  { "tsp", "truncated square pyramid", 0, AV_OPT_TYPE_CONST, {.i64=TSPYRAMID}, 0, 0, FLAGS, "out" },
109  { "hequirect", "half equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=HEQUIRECTANGULAR},0, 0, FLAGS, "out" },
110  { "he", "half equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=HEQUIRECTANGULAR},0, 0, FLAGS, "out" },
111  { "interp", "set interpolation method", OFFSET(interp), AV_OPT_TYPE_INT, {.i64=BILINEAR}, 0, NB_INTERP_METHODS-1, FLAGS, "interp" },
112  { "near", "nearest neighbour", 0, AV_OPT_TYPE_CONST, {.i64=NEAREST}, 0, 0, FLAGS, "interp" },
113  { "nearest", "nearest neighbour", 0, AV_OPT_TYPE_CONST, {.i64=NEAREST}, 0, 0, FLAGS, "interp" },
114  { "line", "bilinear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=BILINEAR}, 0, 0, FLAGS, "interp" },
115  { "linear", "bilinear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=BILINEAR}, 0, 0, FLAGS, "interp" },
116  { "lagrange9", "lagrange9 interpolation", 0, AV_OPT_TYPE_CONST, {.i64=LAGRANGE9}, 0, 0, FLAGS, "interp" },
117  { "cube", "bicubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=BICUBIC}, 0, 0, FLAGS, "interp" },
118  { "cubic", "bicubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=BICUBIC}, 0, 0, FLAGS, "interp" },
119  { "lanc", "lanczos interpolation", 0, AV_OPT_TYPE_CONST, {.i64=LANCZOS}, 0, 0, FLAGS, "interp" },
120  { "lanczos", "lanczos interpolation", 0, AV_OPT_TYPE_CONST, {.i64=LANCZOS}, 0, 0, FLAGS, "interp" },
121  { "sp16", "spline16 interpolation", 0, AV_OPT_TYPE_CONST, {.i64=SPLINE16}, 0, 0, FLAGS, "interp" },
122  { "spline16", "spline16 interpolation", 0, AV_OPT_TYPE_CONST, {.i64=SPLINE16}, 0, 0, FLAGS, "interp" },
123  { "gauss", "gaussian interpolation", 0, AV_OPT_TYPE_CONST, {.i64=GAUSSIAN}, 0, 0, FLAGS, "interp" },
124  { "gaussian", "gaussian interpolation", 0, AV_OPT_TYPE_CONST, {.i64=GAUSSIAN}, 0, 0, FLAGS, "interp" },
125  { "w", "output width", OFFSET(width), AV_OPT_TYPE_INT, {.i64=0}, 0, INT16_MAX, FLAGS, "w"},
126  { "h", "output height", OFFSET(height), AV_OPT_TYPE_INT, {.i64=0}, 0, INT16_MAX, FLAGS, "h"},
127  { "in_stereo", "input stereo format", OFFSET(in_stereo), AV_OPT_TYPE_INT, {.i64=STEREO_2D}, 0, NB_STEREO_FMTS-1, FLAGS, "stereo" },
128  {"out_stereo", "output stereo format", OFFSET(out_stereo), AV_OPT_TYPE_INT, {.i64=STEREO_2D}, 0, NB_STEREO_FMTS-1, FLAGS, "stereo" },
129  { "2d", "2d mono", 0, AV_OPT_TYPE_CONST, {.i64=STEREO_2D}, 0, 0, FLAGS, "stereo" },
130  { "sbs", "side by side", 0, AV_OPT_TYPE_CONST, {.i64=STEREO_SBS}, 0, 0, FLAGS, "stereo" },
131  { "tb", "top bottom", 0, AV_OPT_TYPE_CONST, {.i64=STEREO_TB}, 0, 0, FLAGS, "stereo" },
132  { "in_forder", "input cubemap face order", OFFSET(in_forder), AV_OPT_TYPE_STRING, {.str="rludfb"}, 0, NB_DIRECTIONS-1, FLAGS, "in_forder"},
133  {"out_forder", "output cubemap face order", OFFSET(out_forder), AV_OPT_TYPE_STRING, {.str="rludfb"}, 0, NB_DIRECTIONS-1, FLAGS, "out_forder"},
134  { "in_frot", "input cubemap face rotation", OFFSET(in_frot), AV_OPT_TYPE_STRING, {.str="000000"}, 0, NB_DIRECTIONS-1, FLAGS, "in_frot"},
135  { "out_frot", "output cubemap face rotation",OFFSET(out_frot), AV_OPT_TYPE_STRING, {.str="000000"}, 0, NB_DIRECTIONS-1, FLAGS, "out_frot"},
136  { "in_pad", "percent input cubemap pads", OFFSET(in_pad), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 1.f,TFLAGS, "in_pad"},
137  { "out_pad", "percent output cubemap pads", OFFSET(out_pad), AV_OPT_TYPE_FLOAT, {.dbl=0.f}, 0.f, 1.f,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 scale = 1.f + s->out_pad;
2995 
2996  const float ew = width / 2.f;
2997  const float eh = height;
2998 
2999  const int ei = i >= ew ? i - ew : i;
3000  const float m = i >= ew ? 1.f : -1.f;
3001 
3002  const float uf = ((2.f * ei) / ew - 1.f) * scale;
3003  const float vf = ((2.f * j + 1.f) / eh - 1.f) * scale;
3004 
3005  const float h = hypotf(uf, vf);
3006  const float lh = h > 0.f ? h : 1.f;
3007  const float theta = m * M_PI_2 * (1.f - h);
3008 
3009  const float sin_theta = sinf(theta);
3010  const float cos_theta = cosf(theta);
3011 
3012  vec[0] = cos_theta * m * uf / lh;
3013  vec[1] = cos_theta * vf / lh;
3014  vec[2] = sin_theta;
3015 
3016  normalize_vector(vec);
3017 
3018  return 1;
3019 }
3020 
3021 /**
3022  * Calculate frame position in dual fisheye format for corresponding 3D coordinates on sphere.
3023  *
3024  * @param s filter private context
3025  * @param vec coordinates on sphere
3026  * @param width frame width
3027  * @param height frame height
3028  * @param us horizontal coordinates for interpolation window
3029  * @param vs vertical coordinates for interpolation window
3030  * @param du horizontal relative coordinate
3031  * @param dv vertical relative coordinate
3032  */
3033 static int xyz_to_dfisheye(const V360Context *s,
3034  const float *vec, int width, int height,
3035  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3036 {
3037  const float scale = 1.f - s->in_pad;
3038 
3039  const float ew = width / 2.f;
3040  const float eh = height;
3041 
3042  const float h = hypotf(vec[0], vec[1]);
3043  const float lh = h > 0.f ? h : 1.f;
3044  const float theta = acosf(fabsf(vec[2])) / M_PI;
3045 
3046  float uf = (theta * (vec[0] / lh) * s->input_mirror_modifier[0] * scale + 0.5f) * ew;
3047  float vf = (theta * (vec[1] / lh) * s->input_mirror_modifier[1] * scale + 0.5f) * eh;
3048 
3049  int ui, vi;
3050  int u_shift;
3051 
3052  if (vec[2] >= 0.f) {
3053  u_shift = ceilf(ew);
3054  } else {
3055  u_shift = 0;
3056  uf = ew - uf;
3057  }
3058 
3059  ui = floorf(uf);
3060  vi = floorf(vf);
3061 
3062  *du = uf - ui;
3063  *dv = vf - vi;
3064 
3065  for (int i = 0; i < 4; i++) {
3066  for (int j = 0; j < 4; j++) {
3067  us[i][j] = av_clip(u_shift + ui + j - 1, 0, width - 1);
3068  vs[i][j] = av_clip( vi + i - 1, 0, height - 1);
3069  }
3070  }
3071 
3072  return 1;
3073 }
3074 
3075 /**
3076  * Calculate 3D coordinates on sphere for corresponding frame position in barrel facebook's format.
3077  *
3078  * @param s filter private context
3079  * @param i horizontal position on frame [0, width)
3080  * @param j vertical position on frame [0, height)
3081  * @param width frame width
3082  * @param height frame height
3083  * @param vec coordinates on sphere
3084  */
3085 static int barrel_to_xyz(const V360Context *s,
3086  int i, int j, int width, int height,
3087  float *vec)
3088 {
3089  const float scale = 0.99f;
3090  float l_x, l_y, l_z;
3091 
3092  if (i < 4 * width / 5) {
3093  const float theta_range = M_PI_4;
3094 
3095  const int ew = 4 * width / 5;
3096  const int eh = height;
3097 
3098  const float phi = ((2.f * i) / ew - 1.f) * M_PI / scale;
3099  const float theta = ((2.f * j) / eh - 1.f) * theta_range / scale;
3100 
3101  const float sin_phi = sinf(phi);
3102  const float cos_phi = cosf(phi);
3103  const float sin_theta = sinf(theta);
3104  const float cos_theta = cosf(theta);
3105 
3106  l_x = cos_theta * sin_phi;
3107  l_y = sin_theta;
3108  l_z = cos_theta * cos_phi;
3109  } else {
3110  const int ew = width / 5;
3111  const int eh = height / 2;
3112 
3113  float uf, vf;
3114 
3115  if (j < eh) { // UP
3116  uf = 2.f * (i - 4 * ew) / ew - 1.f;
3117  vf = 2.f * (j ) / eh - 1.f;
3118 
3119  uf /= scale;
3120  vf /= scale;
3121 
3122  l_x = uf;
3123  l_y = -1.f;
3124  l_z = vf;
3125  } else { // DOWN
3126  uf = 2.f * (i - 4 * ew) / ew - 1.f;
3127  vf = 2.f * (j - eh) / eh - 1.f;
3128 
3129  uf /= scale;
3130  vf /= scale;
3131 
3132  l_x = uf;
3133  l_y = 1.f;
3134  l_z = -vf;
3135  }
3136  }
3137 
3138  vec[0] = l_x;
3139  vec[1] = l_y;
3140  vec[2] = l_z;
3141 
3142  normalize_vector(vec);
3143 
3144  return 1;
3145 }
3146 
3147 /**
3148  * Calculate frame position in barrel facebook's format for corresponding 3D coordinates on sphere.
3149  *
3150  * @param s filter private context
3151  * @param vec coordinates on sphere
3152  * @param width frame width
3153  * @param height frame height
3154  * @param us horizontal coordinates for interpolation window
3155  * @param vs vertical coordinates for interpolation window
3156  * @param du horizontal relative coordinate
3157  * @param dv vertical relative coordinate
3158  */
3159 static int xyz_to_barrel(const V360Context *s,
3160  const float *vec, int width, int height,
3161  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3162 {
3163  const float scale = 0.99f;
3164 
3165  const float phi = atan2f(vec[0], vec[2]) * s->input_mirror_modifier[0];
3166  const float theta = asinf(vec[1]) * s->input_mirror_modifier[1];
3167  const float theta_range = M_PI_4;
3168 
3169  int ew, eh;
3170  int u_shift, v_shift;
3171  float uf, vf;
3172  int ui, vi;
3173 
3174  if (theta > -theta_range && theta < theta_range) {
3175  ew = 4 * width / 5;
3176  eh = height;
3177 
3178  u_shift = s->ih_flip ? width / 5 : 0;
3179  v_shift = 0;
3180 
3181  uf = (phi / M_PI * scale + 1.f) * ew / 2.f;
3182  vf = (theta / theta_range * scale + 1.f) * eh / 2.f;
3183  } else {
3184  ew = width / 5;
3185  eh = height / 2;
3186 
3187  u_shift = s->ih_flip ? 0 : 4 * ew;
3188 
3189  if (theta < 0.f) { // UP
3190  uf = -vec[0] / vec[1];
3191  vf = -vec[2] / vec[1];
3192  v_shift = 0;
3193  } else { // DOWN
3194  uf = vec[0] / vec[1];
3195  vf = -vec[2] / vec[1];
3196  v_shift = eh;
3197  }
3198 
3199  uf *= s->input_mirror_modifier[0] * s->input_mirror_modifier[1];
3200  vf *= s->input_mirror_modifier[1];
3201 
3202  uf = 0.5f * ew * (uf * scale + 1.f);
3203  vf = 0.5f * eh * (vf * scale + 1.f);
3204  }
3205 
3206  ui = floorf(uf);
3207  vi = floorf(vf);
3208 
3209  *du = uf - ui;
3210  *dv = vf - vi;
3211 
3212  for (int i = 0; i < 4; i++) {
3213  for (int j = 0; j < 4; j++) {
3214  us[i][j] = u_shift + av_clip(ui + j - 1, 0, ew - 1);
3215  vs[i][j] = v_shift + av_clip(vi + i - 1, 0, eh - 1);
3216  }
3217  }
3218 
3219  return 1;
3220 }
3221 
3222 /**
3223  * Calculate frame position in barrel split facebook's format for corresponding 3D coordinates on sphere.
3224  *
3225  * @param s filter private context
3226  * @param vec coordinates on sphere
3227  * @param width frame width
3228  * @param height frame height
3229  * @param us horizontal coordinates for interpolation window
3230  * @param vs vertical coordinates for interpolation window
3231  * @param du horizontal relative coordinate
3232  * @param dv vertical relative coordinate
3233  */
3235  const float *vec, int width, int height,
3236  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3237 {
3238  const float phi = atan2f(vec[0], vec[2]) * s->input_mirror_modifier[0];
3239  const float theta = asinf(vec[1]) * s->input_mirror_modifier[1];
3240 
3241  const float theta_range = M_PI_4;
3242 
3243  int ew, eh;
3244  int u_shift, v_shift;
3245  float uf, vf;
3246  int ui, vi;
3247 
3248  if (theta >= -theta_range && theta <= theta_range) {
3249  const float scalew = s->fin_pad > 0 ? 1.f - s->fin_pad / (width * 2.f / 3.f) : 1.f - s->in_pad;
3250  const float scaleh = s->fin_pad > 0 ? 1.f - s->fin_pad / (height / 2.f) : 1.f - s->in_pad;
3251 
3252  ew = width / 3 * 2;
3253  eh = height / 2;
3254 
3255  u_shift = s->ih_flip ? width / 3 : 0;
3256  v_shift = phi >= M_PI_2 || phi < -M_PI_2 ? eh : 0;
3257 
3258  uf = fmodf(phi, M_PI_2) / M_PI_2;
3259  vf = theta / M_PI_4;
3260 
3261  if (v_shift)
3262  uf = uf >= 0.f ? fmodf(uf - 1.f, 1.f) : fmodf(uf + 1.f, 1.f);
3263 
3264  uf = (uf * scalew + 1.f) * width / 3.f;
3265  vf = (vf * scaleh + 1.f) * height / 4.f;
3266  } else {
3267  const float scalew = s->fin_pad > 0 ? 1.f - s->fin_pad / (width / 3.f) : 1.f - s->in_pad;
3268  const float scaleh = s->fin_pad > 0 ? 1.f - s->fin_pad / (height / 4.f) : 1.f - s->in_pad;
3269  int v_offset = 0;
3270 
3271  ew = width / 3;
3272  eh = height / 4;
3273 
3274  u_shift = s->ih_flip ? 0 : 2 * ew;
3275 
3276  if (theta <= 0.f && theta >= -M_PI_2 &&
3277  phi <= M_PI_2 && phi >= -M_PI_2) {
3278  uf = -vec[0] / vec[1];
3279  vf = -vec[2] / vec[1];
3280  v_shift = 0;
3281  v_offset = -eh;
3282  } else if (theta >= 0.f && theta <= M_PI_2 &&
3283  phi <= M_PI_2 && phi >= -M_PI_2) {
3284  uf = vec[0] / vec[1];
3285  vf = -vec[2] / vec[1];
3286  v_shift = height * 0.25f;
3287  } else if (theta <= 0.f && theta >= -M_PI_2) {
3288  uf = vec[0] / vec[1];
3289  vf = vec[2] / vec[1];
3290  v_shift = height * 0.5f;
3291  v_offset = -eh;
3292  } else {
3293  uf = -vec[0] / vec[1];
3294  vf = vec[2] / vec[1];
3295  v_shift = height * 0.75f;
3296  }
3297 
3298  uf *= s->input_mirror_modifier[0] * s->input_mirror_modifier[1];
3299  vf *= s->input_mirror_modifier[1];
3300 
3301  uf = 0.5f * width / 3.f * (uf * scalew + 1.f);
3302  vf = height * 0.25f * (vf * scaleh + 1.f) + v_offset;
3303  }
3304 
3305  ui = floorf(uf);
3306  vi = floorf(vf);
3307 
3308  *du = uf - ui;
3309  *dv = vf - vi;
3310 
3311  for (int i = 0; i < 4; i++) {
3312  for (int j = 0; j < 4; j++) {
3313  us[i][j] = u_shift + av_clip(ui + j - 1, 0, ew - 1);
3314  vs[i][j] = v_shift + av_clip(vi + i - 1, 0, eh - 1);
3315  }
3316  }
3317 
3318  return 1;
3319 }
3320 
3321 /**
3322  * Calculate 3D coordinates on sphere for corresponding frame position in barrel split facebook's format.
3323  *
3324  * @param s filter private context
3325  * @param i horizontal position on frame [0, width)
3326  * @param j vertical position on frame [0, height)
3327  * @param width frame width
3328  * @param height frame height
3329  * @param vec coordinates on sphere
3330  */
3332  int i, int j, int width, int height,
3333  float *vec)
3334 {
3335  const float x = (i + 0.5f) / width;
3336  const float y = (j + 0.5f) / height;
3337  float l_x, l_y, l_z;
3338 
3339  if (x < 2.f / 3.f) {
3340  const float scalew = s->fout_pad > 0 ? 1.f - s->fout_pad / (width * 2.f / 3.f) : 1.f - s->out_pad;
3341  const float scaleh = s->fout_pad > 0 ? 1.f - s->fout_pad / (height / 2.f) : 1.f - s->out_pad;
3342 
3343  const float back = floorf(y * 2.f);
3344 
3345  const float phi = ((3.f / 2.f * x - 0.5f) / scalew - back) * M_PI;
3346  const float theta = (y - 0.25f - 0.5f * back) / scaleh * M_PI;
3347 
3348  const float sin_phi = sinf(phi);
3349  const float cos_phi = cosf(phi);
3350  const float sin_theta = sinf(theta);
3351  const float cos_theta = cosf(theta);
3352 
3353  l_x = cos_theta * sin_phi;
3354  l_y = sin_theta;
3355  l_z = cos_theta * cos_phi;
3356  } else {
3357  const float scalew = s->fout_pad > 0 ? 1.f - s->fout_pad / (width / 3.f) : 1.f - s->out_pad;
3358  const float scaleh = s->fout_pad > 0 ? 1.f - s->fout_pad / (height / 4.f) : 1.f - s->out_pad;
3359 
3360  const int face = floorf(y * 4.f);
3361  float uf, vf;
3362 
3363  uf = x * 3.f - 2.f;
3364 
3365  switch (face) {
3366  case 0:
3367  vf = y * 2.f;
3368  uf = 1.f - uf;
3369  vf = 0.5f - vf;
3370 
3371  l_x = (0.5f - uf) / scalew;
3372  l_y = -0.5f;
3373  l_z = (0.5f - vf) / scaleh;
3374  break;
3375  case 1:
3376  vf = y * 2.f;
3377  uf = 1.f - uf;
3378  vf = 1.f - (vf - 0.5f);
3379 
3380  l_x = (0.5f - uf) / scalew;
3381  l_y = 0.5f;
3382  l_z = (-0.5f + vf) / scaleh;
3383  break;
3384  case 2:
3385  vf = y * 2.f - 0.5f;
3386  vf = 1.f - (1.f - vf);
3387 
3388  l_x = (0.5f - uf) / scalew;
3389  l_y = -0.5f;
3390  l_z = (0.5f - vf) / scaleh;
3391  break;
3392  case 3:
3393  vf = y * 2.f - 1.5f;
3394 
3395  l_x = (0.5f - uf) / scalew;
3396  l_y = 0.5f;
3397  l_z = (-0.5f + vf) / scaleh;
3398  break;
3399  }
3400  }
3401 
3402  vec[0] = l_x;
3403  vec[1] = l_y;
3404  vec[2] = l_z;
3405 
3406  normalize_vector(vec);
3407 
3408  return 1;
3409 }
3410 
3411 /**
3412  * Calculate 3D coordinates on sphere for corresponding frame position in tspyramid format.
3413  *
3414  * @param s filter private context
3415  * @param i horizontal position on frame [0, width)
3416  * @param j vertical position on frame [0, height)
3417  * @param width frame width
3418  * @param height frame height
3419  * @param vec coordinates on sphere
3420  */
3421 static int tspyramid_to_xyz(const V360Context *s,
3422  int i, int j, int width, int height,
3423  float *vec)
3424 {
3425  const float x = (i + 0.5f) / width;
3426  const float y = (j + 0.5f) / height;
3427 
3428  if (x < 0.5f) {
3429  vec[0] = x * 4.f - 1.f;
3430  vec[1] = (y * 2.f - 1.f);
3431  vec[2] = 1.f;
3432  } else if (x >= 0.6875f && x < 0.8125f &&
3433  y >= 0.375f && y < 0.625f) {
3434  vec[0] = -(x - 0.6875f) * 16.f + 1.f;
3435  vec[1] = (y - 0.375f) * 8.f - 1.f;
3436  vec[2] = -1.f;
3437  } else if (0.5f <= x && x < 0.6875f &&
3438  ((0.f <= y && y < 0.375f && y >= 2.f * (x - 0.5f)) ||
3439  (0.375f <= y && y < 0.625f) ||
3440  (0.625f <= y && y < 1.f && y <= 2.f * (1.f - x)))) {
3441  vec[0] = 1.f;
3442  vec[1] = 2.f * (y - 2.f * x + 1.f) / (3.f - 4.f * x) - 1.f;
3443  vec[2] = -2.f * (x - 0.5f) / 0.1875f + 1.f;
3444  } else if (0.8125f <= x && x < 1.f &&
3445  ((0.f <= y && y < 0.375f && x >= (1.f - y / 2.f)) ||
3446  (0.375f <= y && y < 0.625f) ||
3447  (0.625f <= y && y < 1.f && y <= (2.f * x - 1.f)))) {
3448  vec[0] = -1.f;
3449  vec[1] = 2.f * (y + 2.f * x - 2.f) / (4.f * x - 3.f) - 1.f;
3450  vec[2] = 2.f * (x - 0.8125f) / 0.1875f - 1.f;
3451  } else if (0.f <= y && y < 0.375f &&
3452  ((0.5f <= x && x < 0.8125f && y < 2.f * (x - 0.5f)) ||
3453  (0.6875f <= x && x < 0.8125f) ||
3454  (0.8125f <= x && x < 1.f && x < (1.f - y / 2.f)))) {
3455  vec[0] = 2.f * (1.f - x - 0.5f * y) / (0.5f - y) - 1.f;
3456  vec[1] = -1.f;
3457  vec[2] = 2.f * (0.375f - y) / 0.375f - 1.f;
3458  } else {
3459  vec[0] = 2.f * (0.5f - x + 0.5f * y) / (y - 0.5f) - 1.f;
3460  vec[1] = 1.f;
3461  vec[2] = -2.f * (1.f - y) / 0.375f + 1.f;
3462  }
3463 
3464  normalize_vector(vec);
3465 
3466  return 1;
3467 }
3468 
3469 /**
3470  * Calculate frame position in tspyramid format for corresponding 3D coordinates on sphere.
3471  *
3472  * @param s filter private context
3473  * @param vec coordinates on sphere
3474  * @param width frame width
3475  * @param height frame height
3476  * @param us horizontal coordinates for interpolation window
3477  * @param vs vertical coordinates for interpolation window
3478  * @param du horizontal relative coordinate
3479  * @param dv vertical relative coordinate
3480  */
3481 static int xyz_to_tspyramid(const V360Context *s,
3482  const float *vec, int width, int height,
3483  int16_t us[4][4], int16_t vs[4][4], float *du, float *dv)
3484 {
3485  float uf, vf;
3486  int ui, vi;
3487  int face;
3488 
3489  xyz_to_cube(s, vec, &uf, &vf, &face);
3490 
3491  uf = (uf + 1.f) * 0.5f;
3492  vf = (vf + 1.f) * 0.5f;
3493 
3494  switch (face) {
3495  case UP:
3496  uf = 0.1875f * vf - 0.375f * uf * vf - 0.125f * uf + 0.8125f;
3497  vf = 0.375f - 0.375f * vf;
3498  break;
3499  case FRONT:
3500  uf = 0.5f * uf;
3501  break;
3502  case DOWN:
3503  uf = 1.f - 0.1875f * vf - 0.5f * uf + 0.375f * uf * vf;
3504  vf = 1.f - 0.375f * vf;
3505  break;
3506  case LEFT:
3507  vf = 0.25f * vf + 0.75f * uf * vf - 0.375f * uf + 0.375f;
3508  uf = 0.1875f * uf + 0.8125f;
3509  break;
3510  case RIGHT:
3511  vf = 0.375f * uf - 0.75f * uf * vf + vf;
3512  uf = 0.1875f * uf + 0.5f;
3513  break;
3514  case BACK:
3515  uf = 0.125f * uf + 0.6875f;
3516  vf = 0.25f * vf + 0.375f;
3517  break;
3518  }
3519 
3520  uf *= width;
3521  vf *= height;
3522 
3523  ui = floorf(uf);
3524  vi = floorf(vf);
3525 
3526  *du = uf - ui;
3527  *dv = vf - vi;
3528 
3529  for (int i = 0; i < 4; i++) {
3530  for (int j = 0; j < 4; j++) {
3531  us[i][j] = reflectx(ui + j - 1, vi + i - 1, width, height);
3532  vs[i][j] = reflecty(vi + i - 1, height);
3533  }
3534  }
3535 
3536  return 1;
3537 }
3538 
3539 static void multiply_matrix(float c[3][3], const float a[3][3], const float b[3][3])
3540 {
3541  for (int i = 0; i < 3; i++) {
3542  for (int j = 0; j < 3; j++) {
3543  float sum = 0.f;
3544 
3545  for (int k = 0; k < 3; k++)
3546  sum += a[i][k] * b[k][j];
3547 
3548  c[i][j] = sum;
3549  }
3550  }
3551 }
3552 
3553 /**
3554  * Calculate rotation matrix for yaw/pitch/roll angles.
3555  */
3556 static inline void calculate_rotation_matrix(float yaw, float pitch, float roll,
3557  float rot_mat[3][3],
3558  const int rotation_order[3])
3559 {
3560  const float yaw_rad = yaw * M_PI / 180.f;
3561  const float pitch_rad = pitch * M_PI / 180.f;
3562  const float roll_rad = roll * M_PI / 180.f;
3563 
3564  const float sin_yaw = sinf(yaw_rad);
3565  const float cos_yaw = cosf(yaw_rad);
3566  const float sin_pitch = sinf(pitch_rad);
3567  const float cos_pitch = cosf(pitch_rad);
3568  const float sin_roll = sinf(roll_rad);
3569  const float cos_roll = cosf(roll_rad);
3570 
3571  float m[3][3][3];
3572  float temp[3][3];
3573 
3574  m[0][0][0] = cos_yaw; m[0][0][1] = 0; m[0][0][2] = sin_yaw;
3575  m[0][1][0] = 0; m[0][1][1] = 1; m[0][1][2] = 0;
3576  m[0][2][0] = -sin_yaw; m[0][2][1] = 0; m[0][2][2] = cos_yaw;
3577 
3578  m[1][0][0] = 1; m[1][0][1] = 0; m[1][0][2] = 0;
3579  m[1][1][0] = 0; m[1][1][1] = cos_pitch; m[1][1][2] = -sin_pitch;
3580  m[1][2][0] = 0; m[1][2][1] = sin_pitch; m[1][2][2] = cos_pitch;
3581 
3582  m[2][0][0] = cos_roll; m[2][0][1] = -sin_roll; m[2][0][2] = 0;
3583  m[2][1][0] = sin_roll; m[2][1][1] = cos_roll; m[2][1][2] = 0;
3584  m[2][2][0] = 0; m[2][2][1] = 0; m[2][2][2] = 1;
3585 
3586  multiply_matrix(temp, m[rotation_order[0]], m[rotation_order[1]]);
3587  multiply_matrix(rot_mat, temp, m[rotation_order[2]]);
3588 }
3589 
3590 /**
3591  * Rotate vector with given rotation matrix.
3592  *
3593  * @param rot_mat rotation matrix
3594  * @param vec vector
3595  */
3596 static inline void rotate(const float rot_mat[3][3],
3597  float *vec)
3598 {
3599  const float x_tmp = vec[0] * rot_mat[0][0] + vec[1] * rot_mat[0][1] + vec[2] * rot_mat[0][2];
3600  const float y_tmp = vec[0] * rot_mat[1][0] + vec[1] * rot_mat[1][1] + vec[2] * rot_mat[1][2];
3601  const float z_tmp = vec[0] * rot_mat[2][0] + vec[1] * rot_mat[2][1] + vec[2] * rot_mat[2][2];
3602 
3603  vec[0] = x_tmp;
3604  vec[1] = y_tmp;
3605  vec[2] = z_tmp;
3606 }
3607 
3608 static inline void set_mirror_modifier(int h_flip, int v_flip, int d_flip,
3609  float *modifier)
3610 {
3611  modifier[0] = h_flip ? -1.f : 1.f;
3612  modifier[1] = v_flip ? -1.f : 1.f;
3613  modifier[2] = d_flip ? -1.f : 1.f;
3614 }
3615 
3616 static inline void mirror(const float *modifier, float *vec)
3617 {
3618  vec[0] *= modifier[0];
3619  vec[1] *= modifier[1];
3620  vec[2] *= modifier[2];
3621 }
3622 
3623 static int allocate_plane(V360Context *s, int sizeof_uv, int sizeof_ker, int sizeof_mask, int p)
3624 {
3625  if (!s->u[p])
3626  s->u[p] = av_calloc(s->uv_linesize[p] * s->pr_height[p], sizeof_uv);
3627  if (!s->v[p])
3628  s->v[p] = av_calloc(s->uv_linesize[p] * s->pr_height[p], sizeof_uv);
3629  if (!s->u[p] || !s->v[p])
3630  return AVERROR(ENOMEM);
3631  if (sizeof_ker) {
3632  if (!s->ker[p])
3633  s->ker[p] = av_calloc(s->uv_linesize[p] * s->pr_height[p], sizeof_ker);
3634  if (!s->ker[p])
3635  return AVERROR(ENOMEM);
3636  }
3637 
3638  if (sizeof_mask && !p) {
3639  if (!s->mask)
3640  s->mask = av_calloc(s->pr_width[p] * s->pr_height[p], sizeof_mask);
3641  if (!s->mask)
3642  return AVERROR(ENOMEM);
3643  }
3644 
3645  return 0;
3646 }
3647 
3648 static void fov_from_dfov(int format, float d_fov, float w, float h, float *h_fov, float *v_fov)
3649 {
3650  switch (format) {
3651  case STEREOGRAPHIC:
3652  {
3653  const float d = 0.5f * hypotf(w, h);
3654  const float l = d / (tanf(d_fov * M_PI / 720.f));
3655 
3656  *h_fov = 2.f * atan2f(w * 0.5f, l) * 360.f / M_PI;
3657  *v_fov = 2.f * atan2f(h * 0.5f, l) * 360.f / M_PI;
3658  }
3659  break;
3660  case FISHEYE:
3661  {
3662  const float d = 0.5f * hypotf(w, h);
3663 
3664  *h_fov = d / w * d_fov;
3665  *v_fov = d / h * d_fov;
3666  }
3667  break;
3668  case FLAT:
3669  default:
3670  {
3671  const float da = tanf(0.5f * FFMIN(d_fov, 359.f) * M_PI / 180.f);
3672  const float d = hypotf(w, h);
3673 
3674  *h_fov = atan2f(da * w, d) * 360.f / M_PI;
3675  *v_fov = atan2f(da * h, d) * 360.f / M_PI;
3676 
3677  if (*h_fov < 0.f)
3678  *h_fov += 360.f;
3679  if (*v_fov < 0.f)
3680  *v_fov += 360.f;
3681  }
3682  break;
3683  }
3684 }
3685 
3686 static void set_dimensions(int *outw, int *outh, int w, int h, const AVPixFmtDescriptor *desc)
3687 {
3688  outw[1] = outw[2] = FF_CEIL_RSHIFT(w, desc->log2_chroma_w);
3689  outw[0] = outw[3] = w;
3690  outh[1] = outh[2] = FF_CEIL_RSHIFT(h, desc->log2_chroma_h);
3691  outh[0] = outh[3] = h;
3692 }
3693 
3694 // Calculate remap data
3695 static av_always_inline int v360_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
3696 {
3697  V360Context *s = ctx->priv;
3698 
3699  for (int p = 0; p < s->nb_allocated; p++) {
3700  const int max_value = s->max_value;
3701  const int width = s->pr_width[p];
3702  const int uv_linesize = s->uv_linesize[p];
3703  const int height = s->pr_height[p];
3704  const int in_width = s->inplanewidth[p];
3705  const int in_height = s->inplaneheight[p];
3706  const int slice_start = (height * jobnr ) / nb_jobs;
3707  const int slice_end = (height * (jobnr + 1)) / nb_jobs;
3708  float du, dv;
3709  float vec[3];
3710  XYRemap rmap;
3711 
3712  for (int j = slice_start; j < slice_end; j++) {
3713  for (int i = 0; i < width; i++) {
3714  int16_t *u = s->u[p] + (j * uv_linesize + i) * s->elements;
3715  int16_t *v = s->v[p] + (j * uv_linesize + i) * s->elements;
3716  int16_t *ker = s->ker[p] + (j * uv_linesize + i) * s->elements;
3717  uint8_t *mask8 = p ? NULL : s->mask + (j * s->pr_width[0] + i);
3718  uint16_t *mask16 = p ? NULL : (uint16_t *)s->mask + (j * s->pr_width[0] + i);
3719  int in_mask, out_mask;
3720 
3721  if (s->out_transpose)
3722  out_mask = s->out_transform(s, j, i, height, width, vec);
3723  else
3724  out_mask = s->out_transform(s, i, j, width, height, vec);
3725  av_assert1(!isnan(vec[0]) && !isnan(vec[1]) && !isnan(vec[2]));
3726  rotate(s->rot_mat, vec);
3727  av_assert1(!isnan(vec[0]) && !isnan(vec[1]) && !isnan(vec[2]));
3728  normalize_vector(vec);
3729  mirror(s->output_mirror_modifier, vec);
3730  if (s->in_transpose)
3731  in_mask = s->in_transform(s, vec, in_height, in_width, rmap.v, rmap.u, &du, &dv);
3732  else
3733  in_mask = s->in_transform(s, vec, in_width, in_height, rmap.u, rmap.v, &du, &dv);
3734  av_assert1(!isnan(du) && !isnan(dv));
3735  s->calculate_kernel(du, dv, &rmap, u, v, ker);
3736 
3737  if (!p && s->mask) {
3738  if (s->mask_size == 1) {
3739  mask8[0] = 255 * (out_mask & in_mask);
3740  } else {
3741  mask16[0] = max_value * (out_mask & in_mask);
3742  }
3743  }
3744  }
3745  }
3746  }
3747 
3748  return 0;
3749 }
3750 
3751 static int config_output(AVFilterLink *outlink)
3752 {
3753  AVFilterContext *ctx = outlink->src;
3754  AVFilterLink *inlink = ctx->inputs[0];
3755  V360Context *s = ctx->priv;
3757  const int depth = desc->comp[0].depth;
3758  const int sizeof_mask = s->mask_size = (depth + 7) >> 3;
3759  int sizeof_uv;
3760  int sizeof_ker;
3761  int err;
3762  int h, w;
3763  int in_offset_h, in_offset_w;
3764  int out_offset_h, out_offset_w;
3765  float hf, wf;
3766  int (*prepare_out)(AVFilterContext *ctx);
3767  int have_alpha;
3768 
3769  s->max_value = (1 << depth) - 1;
3770  s->input_mirror_modifier[0] = s->ih_flip ? -1.f : 1.f;
3771  s->input_mirror_modifier[1] = s->iv_flip ? -1.f : 1.f;
3772 
3773  switch (s->interp) {
3774  case NEAREST:
3776  s->remap_slice = depth <= 8 ? remap1_8bit_slice : remap1_16bit_slice;
3777  s->elements = 1;
3778  sizeof_uv = sizeof(int16_t) * s->elements;
3779  sizeof_ker = 0;
3780  break;
3781  case BILINEAR:
3783  s->remap_slice = depth <= 8 ? remap2_8bit_slice : remap2_16bit_slice;
3784  s->elements = 2 * 2;
3785  sizeof_uv = sizeof(int16_t) * s->elements;
3786  sizeof_ker = sizeof(int16_t) * s->elements;
3787  break;
3788  case LAGRANGE9:
3790  s->remap_slice = depth <= 8 ? remap3_8bit_slice : remap3_16bit_slice;
3791  s->elements = 3 * 3;
3792  sizeof_uv = sizeof(int16_t) * s->elements;
3793  sizeof_ker = sizeof(int16_t) * s->elements;
3794  break;
3795  case BICUBIC:
3797  s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice;
3798  s->elements = 4 * 4;
3799  sizeof_uv = sizeof(int16_t) * s->elements;
3800  sizeof_ker = sizeof(int16_t) * s->elements;
3801  break;
3802  case LANCZOS:
3804  s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice;
3805  s->elements = 4 * 4;
3806  sizeof_uv = sizeof(int16_t) * s->elements;
3807  sizeof_ker = sizeof(int16_t) * s->elements;
3808  break;
3809  case SPLINE16:
3811  s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice;
3812  s->elements = 4 * 4;
3813  sizeof_uv = sizeof(int16_t) * s->elements;
3814  sizeof_ker = sizeof(int16_t) * s->elements;
3815  break;
3816  case GAUSSIAN:
3818  s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice;
3819  s->elements = 4 * 4;
3820  sizeof_uv = sizeof(int16_t) * s->elements;
3821  sizeof_ker = sizeof(int16_t) * s->elements;
3822  break;
3823  default:
3824  av_assert0(0);
3825  }
3826 
3827  ff_v360_init(s, depth);
3828 
3829  for (int order = 0; order < NB_RORDERS; order++) {
3830  const char c = s->rorder[order];
3831  int rorder;
3832 
3833  if (c == '\0') {
3834  av_log(ctx, AV_LOG_WARNING,
3835  "Incomplete rorder option. Direction for all 3 rotation orders should be specified. Switching to default rorder.\n");
3836  s->rotation_order[0] = YAW;
3837  s->rotation_order[1] = PITCH;
3838  s->rotation_order[2] = ROLL;
3839  break;
3840  }
3841 
3842  rorder = get_rorder(c);
3843  if (rorder == -1) {
3844  av_log(ctx, AV_LOG_WARNING,
3845  "Incorrect rotation order symbol '%c' in rorder option. Switching to default rorder.\n", c);
3846  s->rotation_order[0] = YAW;
3847  s->rotation_order[1] = PITCH;
3848  s->rotation_order[2] = ROLL;
3849  break;
3850  }
3851 
3852  s->rotation_order[order] = rorder;
3853  }
3854 
3855  switch (s->in_stereo) {
3856  case STEREO_2D:
3857  w = inlink->w;
3858  h = inlink->h;
3859  in_offset_w = in_offset_h = 0;
3860  break;
3861  case STEREO_SBS:
3862  w = inlink->w / 2;
3863  h = inlink->h;
3864  in_offset_w = w;
3865  in_offset_h = 0;
3866  break;
3867  case STEREO_TB:
3868  w = inlink->w;
3869  h = inlink->h / 2;
3870  in_offset_w = 0;
3871  in_offset_h = h;
3872  break;
3873  default:
3874  av_assert0(0);
3875  }
3876 
3877  set_dimensions(s->inplanewidth, s->inplaneheight, w, h, desc);
3878  set_dimensions(s->in_offset_w, s->in_offset_h, in_offset_w, in_offset_h, desc);
3879 
3880  s->in_width = s->inplanewidth[0];
3881  s->in_height = s->inplaneheight[0];
3882 
3883  if (s->id_fov > 0.f)
3884  fov_from_dfov(s->in, s->id_fov, w, h, &s->ih_fov, &s->iv_fov);
3885 
3886  if (s->in_transpose)
3887  FFSWAP(int, s->in_width, s->in_height);
3888 
3889  switch (s->in) {
3890  case EQUIRECTANGULAR:
3892  err = 0;
3893  wf = w;
3894  hf = h;
3895  break;
3896  case CUBEMAP_3_2:
3898  err = prepare_cube_in(ctx);
3899  wf = w / 3.f * 4.f;
3900  hf = h;
3901  break;
3902  case CUBEMAP_1_6:
3904  err = prepare_cube_in(ctx);
3905  wf = w * 4.f;
3906  hf = h / 3.f;
3907  break;
3908  case CUBEMAP_6_1:
3910  err = prepare_cube_in(ctx);
3911  wf = w / 3.f * 2.f;
3912  hf = h * 2.f;
3913  break;
3914  case EQUIANGULAR:
3915  s->in_transform = xyz_to_eac;
3916  err = prepare_eac_in(ctx);
3917  wf = w;
3918  hf = h / 9.f * 8.f;
3919  break;
3920  case FLAT:
3922  err = prepare_flat_in(ctx);
3923  wf = w;
3924  hf = h;
3925  break;
3926  case PERSPECTIVE:
3927  av_log(ctx, AV_LOG_ERROR, "Supplied format is not accepted as input.\n");
3928  return AVERROR(EINVAL);
3929  case DUAL_FISHEYE:
3931  err = 0;
3932  wf = w;
3933  hf = h;
3934  break;
3935  case BARREL:
3937  err = 0;
3938  wf = w / 5.f * 4.f;
3939  hf = h;
3940  break;
3941  case STEREOGRAPHIC:
3943  err = prepare_stereographic_in(ctx);
3944  wf = w;
3945  hf = h / 2.f;
3946  break;
3947  case MERCATOR:
3949  err = 0;
3950  wf = w;
3951  hf = h / 2.f;
3952  break;
3953  case BALL:
3955  err = 0;
3956  wf = w;
3957  hf = h / 2.f;
3958  break;
3959  case HAMMER:
3961  err = 0;
3962  wf = w;
3963  hf = h;
3964  break;
3965  case SINUSOIDAL:
3967  err = 0;
3968  wf = w;
3969  hf = h;
3970  break;
3971  case FISHEYE:
3973  err = prepare_fisheye_in(ctx);
3974  wf = w * 2;
3975  hf = h;
3976  break;
3977  case PANNINI:
3979  err = 0;
3980  wf = w;
3981  hf = h;
3982  break;
3983  case CYLINDRICAL:
3985  err = prepare_cylindrical_in(ctx);
3986  wf = w;
3987  hf = h * 2.f;
3988  break;
3989  case TETRAHEDRON:
3991  err = 0;
3992  wf = w;
3993  hf = h;
3994  break;
3995  case BARREL_SPLIT:
3997  err = 0;
3998  wf = w * 4.f / 3.f;
3999  hf = h;
4000  break;
4001  case TSPYRAMID:
4003  err = 0;
4004  wf = w;
4005  hf = h;
4006  break;
4007  case HEQUIRECTANGULAR:
4009  err = 0;
4010  wf = w * 2.f;
4011  hf = h;
4012  break;
4013  default:
4014  av_log(ctx, AV_LOG_ERROR, "Specified input format is not handled.\n");
4015  return AVERROR_BUG;
4016  }
4017 
4018  if (err != 0) {
4019  return err;
4020  }
4021 
4022  switch (s->out) {
4023  case EQUIRECTANGULAR:
4025  prepare_out = NULL;
4026  w = lrintf(wf);
4027  h = lrintf(hf);
4028  break;
4029  case CUBEMAP_3_2:
4031  prepare_out = prepare_cube_out;
4032  w = lrintf(wf / 4.f * 3.f);
4033  h = lrintf(hf);
4034  break;
4035  case CUBEMAP_1_6:
4037  prepare_out = prepare_cube_out;
4038  w = lrintf(wf / 4.f);
4039  h = lrintf(hf * 3.f);
4040  break;
4041  case CUBEMAP_6_1:
4043  prepare_out = prepare_cube_out;
4044  w = lrintf(wf / 2.f * 3.f);
4045  h = lrintf(hf / 2.f);
4046  break;
4047  case EQUIANGULAR:
4049  prepare_out = prepare_eac_out;
4050  w = lrintf(wf);
4051  h = lrintf(hf / 8.f * 9.f);
4052  break;
4053  case FLAT:
4055  prepare_out = prepare_flat_out;
4056  w = lrintf(wf);
4057  h = lrintf(hf);
4058  break;
4059  case DUAL_FISHEYE:
4061  prepare_out = NULL;
4062  w = lrintf(wf);
4063  h = lrintf(hf);
4064  break;
4065  case BARREL:
4067  prepare_out = NULL;
4068  w = lrintf(wf / 4.f * 5.f);
4069  h = lrintf(hf);
4070  break;
4071  case STEREOGRAPHIC:
4073  prepare_out = prepare_stereographic_out;
4074  w = lrintf(wf);
4075  h = lrintf(hf * 2.f);
4076  break;
4077  case MERCATOR:
4079  prepare_out = NULL;
4080  w = lrintf(wf);
4081  h = lrintf(hf * 2.f);
4082  break;
4083  case BALL:
4085  prepare_out = NULL;
4086  w = lrintf(wf);
4087  h = lrintf(hf * 2.f);
4088  break;
4089  case HAMMER:
4091  prepare_out = NULL;
4092  w = lrintf(wf);
4093  h = lrintf(hf);
4094  break;
4095  case SINUSOIDAL:
4097  prepare_out = NULL;
4098  w = lrintf(wf);
4099  h = lrintf(hf);
4100  break;
4101  case FISHEYE:
4103  prepare_out = prepare_fisheye_out;
4104  w = lrintf(wf * 0.5f);
4105  h = lrintf(hf);
4106  break;
4107  case PANNINI:
4109  prepare_out = NULL;
4110  w = lrintf(wf);
4111  h = lrintf(hf);
4112  break;
4113  case CYLINDRICAL:
4115  prepare_out = prepare_cylindrical_out;
4116  w = lrintf(wf);
4117  h = lrintf(hf * 0.5f);
4118  break;
4119  case PERSPECTIVE:
4121  prepare_out = NULL;
4122  w = lrintf(wf / 2.f);
4123  h = lrintf(hf);
4124  break;
4125  case TETRAHEDRON:
4127  prepare_out = NULL;
4128  w = lrintf(wf);
4129  h = lrintf(hf);
4130  break;
4131  case BARREL_SPLIT:
4133  prepare_out = NULL;
4134  w = lrintf(wf / 4.f * 3.f);
4135  h = lrintf(hf);
4136  break;
4137  case TSPYRAMID:
4139  prepare_out = NULL;
4140  w = lrintf(wf);
4141  h = lrintf(hf);
4142  break;
4143  case HEQUIRECTANGULAR:
4145  prepare_out = NULL;
4146  w = lrintf(wf / 2.f);
4147  h = lrintf(hf);
4148  break;
4149  default:
4150  av_log(ctx, AV_LOG_ERROR, "Specified output format is not handled.\n");
4151  return AVERROR_BUG;
4152  }
4153 
4154  // Override resolution with user values if specified
4155  if (s->width > 0 && s->height <= 0 && s->h_fov > 0.f && s->v_fov > 0.f &&
4156  s->out == FLAT && s->d_fov == 0.f) {
4157  w = s->width;
4158  h = w / tanf(s->h_fov * M_PI / 360.f) * tanf(s->v_fov * M_PI / 360.f);
4159  } else 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  h = s->height;
4162  w = h / tanf(s->v_fov * M_PI / 360.f) * tanf(s->h_fov * M_PI / 360.f);
4163  } else if (s->width > 0 && s->height > 0) {
4164  w = s->width;
4165  h = s->height;
4166  } else if (s->width > 0 || s->height > 0) {
4167  av_log(ctx, AV_LOG_ERROR, "Both width and height values should be specified.\n");
4168  return AVERROR(EINVAL);
4169  } else {
4170  if (s->out_transpose)
4171  FFSWAP(int, w, h);
4172 
4173  if (s->in_transpose)
4174  FFSWAP(int, w, h);
4175  }
4176 
4177  s->width = w;
4178  s->height = h;
4179 
4180  if (s->d_fov > 0.f)
4181  fov_from_dfov(s->out, s->d_fov, w, h, &s->h_fov, &s->v_fov);
4182 
4183  if (prepare_out) {
4184  err = prepare_out(ctx);
4185  if (err != 0)
4186  return err;
4187  }
4188 
4189  set_dimensions(s->pr_width, s->pr_height, w, h, desc);
4190 
4191  switch (s->out_stereo) {
4192  case STEREO_2D:
4193  out_offset_w = out_offset_h = 0;
4194  break;
4195  case STEREO_SBS:
4196  out_offset_w = w;
4197  out_offset_h = 0;
4198  w *= 2;
4199  break;
4200  case STEREO_TB:
4201  out_offset_w = 0;
4202  out_offset_h = h;
4203  h *= 2;
4204  break;
4205  default:
4206  av_assert0(0);
4207  }
4208 
4209  set_dimensions(s->out_offset_w, s->out_offset_h, out_offset_w, out_offset_h, desc);
4210  set_dimensions(s->planewidth, s->planeheight, w, h, desc);
4211 
4212  for (int i = 0; i < 4; i++)
4213  s->uv_linesize[i] = FFALIGN(s->pr_width[i], 8);
4214 
4215  outlink->h = h;
4216  outlink->w = w;
4217 
4219  have_alpha = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA);
4220 
4221  if (desc->log2_chroma_h == desc->log2_chroma_w && desc->log2_chroma_h == 0) {
4222  s->nb_allocated = 1;
4223  s->map[0] = s->map[1] = s->map[2] = s->map[3] = 0;
4224  } else {
4225  s->nb_allocated = 2;
4226  s->map[0] = s->map[3] = 0;
4227  s->map[1] = s->map[2] = 1;
4228  }
4229 
4230  for (int i = 0; i < s->nb_allocated; i++)
4231  allocate_plane(s, sizeof_uv, sizeof_ker, sizeof_mask * have_alpha * s->alpha, i);
4232 
4235 
4236  ctx->internal->execute(ctx, v360_slice, NULL, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
4237 
4238  return 0;
4239 }
4240 
4242 {
4243  AVFilterContext *ctx = inlink->dst;
4244  AVFilterLink *outlink = ctx->outputs[0];
4245  V360Context *s = ctx->priv;
4246  AVFrame *out;
4247  ThreadData td;
4248 
4249  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
4250  if (!out) {
4251  av_frame_free(&in);
4252  return AVERROR(ENOMEM);
4253  }
4254  av_frame_copy_props(out, in);
4255 
4256  td.in = in;
4257  td.out = out;
4258 
4259  ctx->internal->execute(ctx, s->remap_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
4260 
4261  av_frame_free(&in);
4262  return ff_filter_frame(outlink, out);
4263 }
4264 
4265 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
4266  char *res, int res_len, int flags)
4267 {
4268  int ret;
4269 
4270  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
4271  if (ret < 0)
4272  return ret;
4273 
4274  return config_output(ctx->outputs[0]);
4275 }
4276 
4278 {
4279  V360Context *s = ctx->priv;
4280 
4281  for (int p = 0; p < s->nb_allocated; p++) {
4282  av_freep(&s->u[p]);
4283  av_freep(&s->v[p]);
4284  av_freep(&s->ker[p]);
4285  }
4286  av_freep(&s->mask);
4287 }
4288 
4289 static const AVFilterPad inputs[] = {
4290  {
4291  .name = "default",
4292  .type = AVMEDIA_TYPE_VIDEO,
4293  .filter_frame = filter_frame,
4294  },
4295  { NULL }
4296 };
4297 
4298 static const AVFilterPad outputs[] = {
4299  {
4300  .name = "default",
4301  .type = AVMEDIA_TYPE_VIDEO,
4302  .config_props = config_output,
4303  },
4304  { NULL }
4305 };
4306 
4308  .name = "v360",
4309  .description = NULL_IF_CONFIG_SMALL("Convert 360 projection of video."),
4310  .priv_size = sizeof(V360Context),
4311  .uninit = uninit,
4313  .inputs = inputs,
4314  .outputs = outputs,
4315  .priv_class = &v360_class,
4318 };
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:3539
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
#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:295
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:47
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:3234
#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:266
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:3608
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate.The lists are not just lists
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:3751
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:244
static void fov_from_dfov(int format, float d_fov, float w, float h, float *h_fov, float *v_fov)
Definition: vf_v360.c:3648
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:3623
#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:82
#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:252
#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:4307
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:3033
#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:3331
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:259
#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:569
#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:3085
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:3616
#define S(s, c, i)
#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
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:3686
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:3695
#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:4298
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_v360.c:4265
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:49
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_v360.c:4277
#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:3421
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:64
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:4241
#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:4289
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:3556
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:3481
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:3596
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:3159
#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:2043
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:39
#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:56
static int prepare_fisheye_in(AVFilterContext *ctx)
Prepare data for processing fisheye input format.
Definition: vf_v360.c:2605
internal API functions
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
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