OpenShot Library | libopenshot  0.5.0
SphericalProjection.cpp
Go to the documentation of this file.
1 
9 // Copyright (c) 2008-2025 OpenShot Studios, LLC
10 //
11 // SPDX-License-Identifier: LGPL-3.0-or-later
12 
13 #include "SphericalProjection.h"
14 #include "Exceptions.h"
15 
16 #include <algorithm>
17 #include <cmath>
18 #include <omp.h>
19 #include <vector>
20 
21 using namespace openshot;
22 
24  : yaw(0.0), pitch(0.0), roll(0.0), fov(90.0), in_fov(180.0),
25  projection_mode(0), invert(0), input_model(INPUT_EQUIRECT), interpolation(3)
26 {
27  init_effect_details();
28 }
29 
31  Keyframe new_roll, Keyframe new_fov)
32  : yaw(new_yaw), pitch(new_pitch), roll(new_roll), fov(new_fov),
33  in_fov(180.0), projection_mode(0), invert(0),
34  input_model(INPUT_EQUIRECT), interpolation(3)
35 {
36  init_effect_details();
37 }
38 
39 void SphericalProjection::init_effect_details()
40 {
42  info.class_name = "SphericalProjection";
43  info.name = "Spherical Projection";
45  "Flatten and reproject 360° or fisheye inputs into a rectilinear view with yaw, pitch, roll, and FOV. Supports Equirect and multiple fisheye lens models.";
46  info.has_audio = false;
47  info.has_video = true;
48 }
49 
50 namespace {
51  inline double cubic_interp(double p0, double p1, double p2, double p3,
52  double t)
53  {
54  double a0 = -0.5 * p0 + 1.5 * p1 - 1.5 * p2 + 0.5 * p3;
55  double a1 = p0 - 2.5 * p1 + 2.0 * p2 - 0.5 * p3;
56  double a2 = -0.5 * p0 + 0.5 * p2;
57  double a3 = p1;
58  return ((a0 * t + a1) * t + a2) * t + a3;
59  }
60 } // namespace
61 
62 std::shared_ptr<openshot::Frame>
63 SphericalProjection::GetFrame(std::shared_ptr<openshot::Frame> frame,
64  int64_t frame_number) {
65  auto img = frame->GetImage();
66  if (img->format() != QImage::Format_ARGB32)
67  *img = img->convertToFormat(QImage::Format_ARGB32);
68 
69  int W = img->width(), H = img->height();
70  int bpl = img->bytesPerLine();
71  uchar *src = img->bits();
72 
73  QImage output(W, H, QImage::Format_ARGB32);
74  output.fill(Qt::black);
75  uchar *dst = output.bits();
76  int dst_bpl = output.bytesPerLine();
77 
78  // Keyframes / angles
79  const double DEG = M_PI / 180.0;
80  double yaw_r = -yaw.GetValue(frame_number) * DEG; // drag right -> look right
81  double pitch_r = pitch.GetValue(frame_number) * DEG; // drag up -> look up
82  double roll_r = -roll.GetValue(frame_number) * DEG; // positive slider -> clockwise on screen
83  double in_fov_r = in_fov.GetValue(frame_number) * DEG;
84  double out_fov_r= fov.GetValue(frame_number) * DEG;
85 
86  // Apply invert as a 180° yaw for equirect inputs (camera-centric; no mirroring)
88  yaw_r += M_PI;
89  }
90 
91  // Rotation R = Ry(yaw) * Rx(pitch). (Roll applied in screen space.)
92  double sy = sin(yaw_r), cy = cos(yaw_r);
93  double sp = sin(pitch_r),cp = cos(pitch_r);
94 
95  double r00 = cy;
96  double r01 = sy * sp;
97  double r02 = sy * cp;
98 
99  double r10 = 0.0;
100  double r11 = cp;
101  double r12 = -sp;
102 
103  double r20 = -sy;
104  double r21 = cy * sp;
105  double r22 = cy * cp;
106 
107  // Keep roll clockwise on screen regardless of facing direction
108  double roll_sign = (r22 >= 0.0) ? 1.0 : -1.0;
109 
110  // Perspective scalars (rectilinear)
111  double hx = tan(out_fov_r * 0.5);
112  double vy = hx * double(H) / W;
113 
114  auto q = [](double a) { return std::llround(a * 1e6); };
115  bool recompute = uv_map.empty() || W != cached_width || H != cached_height ||
116  q(yaw_r) != q(cached_yaw) ||
117  q(pitch_r) != q(cached_pitch) ||
118  q(roll_r) != q(cached_roll) ||
119  q(in_fov_r) != q(cached_in_fov) ||
120  q(out_fov_r) != q(cached_out_fov) ||
121  input_model != cached_input_model ||
122  projection_mode != cached_projection_mode ||
123  invert != cached_invert;
124 
125  if (recompute) {
126  uv_map.resize(W * H * 2);
127 
128 #pragma omp parallel for schedule(static)
129  for (int yy = 0; yy < H; yy++) {
130  double ndc_y = (2.0 * (yy + 0.5) / H - 1.0) * vy;
131 
132  for (int xx = 0; xx < W; xx++) {
133  double uf = -1.0, vf = -1.0;
134 
135  const bool out_is_rect =
137 
138  if (!out_is_rect) {
139  // ---------------- FISHEYE OUTPUT ----------------
140  double cx = (xx + 0.5) - W * 0.5;
141  double cy_dn = (yy + 0.5) - H * 0.5;
142  double R = 0.5 * std::min(W, H);
143 
144  // screen plane, Y-up; apply roll by -roll (clockwise), adjusted by roll_sign
145  double rx = cx / R;
146  double ry_up = -cy_dn / R;
147  double cR = cos(roll_r), sR = sin(roll_r) * roll_sign;
148  double rxr = cR * rx + sR * ry_up;
149  double ryr = -sR * rx + cR * ry_up;
150 
151  double r_norm = std::sqrt(rxr * rxr + ryr * ryr);
152  if (r_norm <= 1.0) {
153  double theta_max = out_fov_r * 0.5;
154  double theta = 0.0;
155  switch (projection_mode) {
157  // r ∝ θ
158  theta = r_norm * theta_max;
159  break;
161  // r ∝ 2 sin(θ/2)
162  theta = 2.0 * std::asin(std::clamp(r_norm * std::sin(theta_max * 0.5), -1.0, 1.0));
163  break;
165  // r ∝ 2 tan(θ/2)
166  theta = 2.0 * std::atan(r_norm * std::tan(theta_max * 0.5));
167  break;
169  // r ∝ sin(θ)
170  theta = std::asin(std::clamp(r_norm * std::sin(theta_max), -1.0, 1.0));
171  break;
172  default:
173  theta = r_norm * theta_max;
174  break;
175  }
176 
177  // NOTE: Y was upside-down; fix by using +ryr (not -ryr)
178  double phi = std::atan2(ryr, rxr);
179 
180  // Camera ray from fisheye output
181  double vx = std::sin(theta) * std::cos(phi);
182  double vy2= std::sin(theta) * std::sin(phi);
183  double vz = -std::cos(theta);
184 
185  // Rotate into world
186  double dx = r00 * vx + r01 * vy2 + r02 * vz;
187  double dy = r10 * vx + r11 * vy2 + r12 * vz;
188  double dz = r20 * vx + r21 * vy2 + r22 * vz;
189 
190  project_input(dx, dy, dz, in_fov_r, W, H, uf, vf);
191  } else {
192  uf = vf = -1.0; // outside disk
193  }
194 
195  } else {
196  // ---------------- RECTILINEAR OUTPUT ----------------
197  double ndc_x = (2.0 * (xx + 0.5) / W - 1.0) * hx;
198 
199  // screen plane Y-up; roll by -roll (clockwise), adjusted by roll_sign
200  double sx = ndc_x;
201  double sy_up = -ndc_y;
202  double cR = cos(roll_r), sR = sin(roll_r) * roll_sign;
203  double rx = cR * sx + sR * sy_up;
204  double ry = -sR * sx + cR * sy_up;
205 
206  // Camera ray (camera looks down -Z)
207  double vx = rx, vy2 = ry, vz = -1.0;
208  double inv_len = 1.0 / std::sqrt(vx*vx + vy2*vy2 + vz*vz);
209  vx *= inv_len; vy2 *= inv_len; vz *= inv_len;
210 
211  // Rotate into world
212  double dx = r00 * vx + r01 * vy2 + r02 * vz;
213  double dy = r10 * vx + r11 * vy2 + r12 * vz;
214  double dz = r20 * vx + r21 * vy2 + r22 * vz;
215 
216  project_input(dx, dy, dz, in_fov_r, W, H, uf, vf);
217  }
218 
219  int idx = 2 * (yy * W + xx);
220  uv_map[idx] = (float)uf;
221  uv_map[idx + 1] = (float)vf;
222  }
223  }
224 
225  cached_width = W;
226  cached_height = H;
227  cached_yaw = yaw_r;
228  cached_pitch = pitch_r;
229  cached_roll = roll_r;
230  cached_in_fov = in_fov_r;
231  cached_out_fov= out_fov_r;
232  cached_input_model = input_model;
233  cached_projection_mode = projection_mode;
234  cached_invert = invert;
235  }
236 
237  // Auto sampler selection (uses enums)
238  int sampler = interpolation;
239  if (interpolation == INTERP_AUTO) {
240  double coverage_r =
241  (projection_mode == MODE_RECT_SPHERE) ? 2.0 * M_PI :
243  in_fov_r; // rough heuristic otherwise
244  double ppd_src = W / coverage_r;
245  double ppd_out = W / out_fov_r;
246  double ratio = ppd_out / ppd_src;
247  if (ratio < 0.8) sampler = INTERP_AUTO; // mipmaps path below
248  else if (ratio <= 1.2) sampler = INTERP_BILINEAR;
249  else sampler = INTERP_BICUBIC;
250  }
251 
252  // Build mipmaps only if needed (box)
253  std::vector<QImage> mipmaps;
254  if (sampler == INTERP_AUTO) {
255  mipmaps.push_back(*img);
256  for (int level = 1; level < 4; ++level) {
257  const QImage &prev = mipmaps[level - 1];
258  if (prev.width() <= 1 || prev.height() <= 1) break;
259  int w = prev.width() / 2, h = prev.height() / 2;
260  QImage next(w, h, QImage::Format_ARGB32);
261  uchar *nb = next.bits(); int nbpl = next.bytesPerLine();
262  const uchar *pb = prev.bits(); int pbpl = prev.bytesPerLine();
263  for (int y = 0; y < h; y++) {
264  for (int x = 0; x < w; x++) {
265  for (int c = 0; c < 4; c++) {
266  int p00 = pb[(2*y) * pbpl + (2*x) * 4 + c];
267  int p10 = pb[(2*y) * pbpl + (2*x+1) * 4 + c];
268  int p01 = pb[(2*y+1) * pbpl + (2*x) * 4 + c];
269  int p11 = pb[(2*y+1) * pbpl + (2*x+1) * 4 + c];
270  nb[y * nbpl + x * 4 + c] = (p00 + p10 + p01 + p11) / 4;
271  }
272  }
273  }
274  mipmaps.push_back(next);
275  }
276  }
277 
278 #pragma omp parallel for schedule(static)
279  for (int yy = 0; yy < H; yy++) {
280  uchar *dst_row = dst + yy * dst_bpl;
281  for (int xx = 0; xx < W; xx++) {
282  int idx = 2 * (yy * W + xx);
283  double uf = uv_map[idx];
284  double vf = uv_map[idx + 1];
285  uchar *d = dst_row + xx * 4;
286 
288  uf = std::fmod(std::fmod(uf, W) + W, W);
289  vf = std::clamp(vf, 0.0, (double)H - 1);
291  uf = std::clamp(uf, 0.0, (double)W - 1);
292  vf = std::clamp(vf, 0.0, (double)H - 1);
293  } else if (uf < 0 || uf >= W || vf < 0 || vf >= H) {
294  d[0] = d[1] = d[2] = 0; d[3] = 0;
295  continue;
296  }
297 
298  if (sampler == INTERP_NEAREST) {
299  int x0 = std::clamp(int(std::floor(uf)), 0, W - 1);
300  int y0 = std::clamp(int(std::floor(vf)), 0, H - 1);
301  uchar *s = src + y0 * bpl + x0 * 4;
302  d[0]=s[0]; d[1]=s[1]; d[2]=s[2]; d[3]=s[3];
303  } else if (sampler == INTERP_BILINEAR) {
304  int x0 = std::clamp(int(std::floor(uf)), 0, W - 1);
305  int y0 = std::clamp(int(std::floor(vf)), 0, H - 1);
306  int x1 = std::clamp(x0 + 1, 0, W - 1);
307  int y1 = std::clamp(y0 + 1, 0, H - 1);
308  double dxr = uf - x0, dyr = vf - y0;
309  uchar *p00 = src + y0 * bpl + x0 * 4;
310  uchar *p10 = src + y0 * bpl + x1 * 4;
311  uchar *p01 = src + y1 * bpl + x0 * 4;
312  uchar *p11 = src + y1 * bpl + x1 * 4;
313  for (int c = 0; c < 4; c++) {
314  double v0 = p00[c] * (1 - dxr) + p10[c] * dxr;
315  double v1 = p01[c] * (1 - dxr) + p11[c] * dxr;
316  d[c] = uchar(v0 * (1 - dyr) + v1 * dyr + 0.5);
317  }
318  } else if (sampler == INTERP_BICUBIC) {
319  int x1 = std::clamp(int(std::floor(uf)), 0, W - 1);
320  int y1 = std::clamp(int(std::floor(vf)), 0, H - 1);
321  double tx = uf - x1, ty = vf - y1;
322  for (int c = 0; c < 4; c++) {
323  double col[4];
324  for (int j = -1; j <= 2; j++) {
325  int y = std::clamp(y1 + j, 0, H - 1);
326  double row[4];
327  for (int i = -1; i <= 2; i++) {
328  int x = std::clamp(x1 + i, 0, W - 1);
329  row[i + 1] = src[y * bpl + x * 4 + c];
330  }
331  col[j + 1] = cubic_interp(row[0], row[1], row[2], row[3], tx);
332  }
333  double val = cubic_interp(col[0], col[1], col[2], col[3], ty);
334  d[c] = uchar(std::clamp(val, 0.0, 255.0) + 0.5);
335  }
336  } else { // INTERP_AUTO -> mipmaps + bilinear
337  double uf_dx = 0.0, vf_dx = 0.0, uf_dy = 0.0, vf_dy = 0.0;
338  if (xx + 1 < W) { uf_dx = uv_map[idx + 2] - uf; vf_dx = uv_map[idx + 3] - vf; }
339  if (yy + 1 < H) { uf_dy = uv_map[idx + 2 * W] - uf; vf_dy = uv_map[idx + 2 * W + 1] - vf; }
340  double scale_x = std::sqrt(uf_dx*uf_dx + vf_dx*vf_dx);
341  double scale_y = std::sqrt(uf_dy*uf_dy + vf_dy*vf_dy);
342  double scale = std::max(scale_x, scale_y);
343  int level = 0;
344  if (scale > 1.0)
345  level = std::min<int>(std::floor(std::log2(scale)), (int)mipmaps.size() - 1);
346  const QImage &lvl = mipmaps[level];
347  int Wl = lvl.width(), Hl = lvl.height();
348  int bpl_l = lvl.bytesPerLine();
349  const uchar *srcl = lvl.bits();
350  double uf_l = uf / (1 << level);
351  double vf_l = vf / (1 << level);
352  int x0 = std::clamp(int(std::floor(uf_l)), 0, Wl - 1);
353  int y0 = std::clamp(int(std::floor(vf_l)), 0, Hl - 1);
354  int x1 = std::clamp(x0 + 1, 0, Wl - 1);
355  int y1 = std::clamp(y0 + 1, 0, Hl - 1);
356  double dxr = uf_l - x0, dyr = vf_l - y0;
357  const uchar *p00 = srcl + y0 * bpl_l + x0 * 4;
358  const uchar *p10 = srcl + y0 * bpl_l + x1 * 4;
359  const uchar *p01 = srcl + y1 * bpl_l + x0 * 4;
360  const uchar *p11 = srcl + y1 * bpl_l + x1 * 4;
361  for (int c = 0; c < 4; c++) {
362  double v0 = p00[c] * (1 - dxr) + p10[c] * dxr;
363  double v1 = p01[c] * (1 - dxr) + p11[c] * dxr;
364  d[c] = uchar(v0 * (1 - dyr) + v1 * dyr + 0.5);
365  }
366  }
367  }
368  }
369 
370  *img = output;
371  return frame;
372 }
373 
374 void SphericalProjection::project_input(double dx, double dy, double dz,
375  double in_fov_r, int W, int H,
376  double &uf, double &vf) const {
377  if (input_model == INPUT_EQUIRECT) {
378  // Center (-Z) -> lon=0; +X (screen right) -> +lon
379  double lon = std::atan2(dx, -dz);
380  double lat = std::asin(std::clamp(dy, -1.0, 1.0));
381 
383  lon = std::clamp(lon, -M_PI / 2.0, M_PI / 2.0);
384 
385  double horiz_span = (projection_mode == MODE_RECT_HEMISPHERE) ? M_PI : 2.0 * M_PI;
386  double lon_offset = (projection_mode == MODE_RECT_HEMISPHERE) ? M_PI / 2.0 : M_PI;
387  uf = ((lon + lon_offset) / horiz_span) * W;
388 
389  // Image Y grows downward: north (lat = +π/2) at top
390  vf = (M_PI / 2.0 - lat) / M_PI * H;
391  return;
392  }
393 
394  // -------- Fisheye inputs --------
395  // Optical axis default is -Z; "Invert" flips hemisphere.
396  const double ax = 0.0, ay = 0.0;
397  double az = -1.0;
398  if (invert == INVERT_BACK) az = 1.0;
399 
400  double cos_t = std::clamp(dx * ax + dy * ay + dz * az, -1.0, 1.0);
401  double theta = std::acos(cos_t);
402  double tmax = std::max(1e-6, in_fov_r * 0.5);
403 
404  double r_norm = 0.0;
405  switch (input_model) {
406  case INPUT_FEQ_EQUIDISTANT: r_norm = theta / tmax; break;
407  case INPUT_FEQ_EQUISOLID: r_norm = std::sin(theta*0.5) / std::max(1e-12, std::sin(tmax*0.5)); break;
408  case INPUT_FEQ_STEREOGRAPHIC: r_norm = std::tan(theta*0.5) / std::max(1e-12, std::tan(tmax*0.5)); break;
409  case INPUT_FEQ_ORTHOGRAPHIC: r_norm = std::sin(theta) / std::max(1e-12, std::sin(tmax)); break;
410  default: r_norm = theta / tmax; break;
411  }
412 
413  // Azimuth in camera XY; final Y is downward -> subtract sine in vf
414  double phi = std::atan2(dy, dx);
415 
416  double R = 0.5 * std::min(W, H);
417  double rpx = r_norm * R;
418  uf = W * 0.5 + rpx * std::cos(phi);
419  vf = H * 0.5 - rpx * std::sin(phi);
420 }
421 
422 std::string SphericalProjection::Json() const
423 {
424  return JsonValue().toStyledString();
425 }
426 
428 {
429  Json::Value root = EffectBase::JsonValue();
430  root["type"] = info.class_name;
431  root["yaw"] = yaw.JsonValue();
432  root["pitch"] = pitch.JsonValue();
433  root["roll"] = roll.JsonValue();
434  root["fov"] = fov.JsonValue();
435  root["in_fov"] = in_fov.JsonValue();
436  root["projection_mode"] = projection_mode;
437  root["invert"] = invert;
438  root["input_model"] = input_model;
439  root["interpolation"] = interpolation;
440  return root;
441 }
442 
443 void SphericalProjection::SetJson(const std::string value)
444 {
445  try
446  {
447  Json::Value root = openshot::stringToJson(value);
448  SetJsonValue(root);
449  }
450  catch (...)
451  {
452  throw InvalidJSON("Invalid JSON for SphericalProjection");
453  }
454 }
455 
456 void SphericalProjection::SetJsonValue(const Json::Value root)
457 {
459 
460  if (!root["yaw"].isNull()) yaw.SetJsonValue(root["yaw"]);
461  if (!root["pitch"].isNull()) pitch.SetJsonValue(root["pitch"]);
462  if (!root["roll"].isNull()) roll.SetJsonValue(root["roll"]);
463  if (!root["fov"].isNull()) fov.SetJsonValue(root["fov"]);
464  if (!root["in_fov"].isNull()) in_fov.SetJsonValue(root["in_fov"]);
465 
466  if (!root["projection_mode"].isNull())
467  projection_mode = root["projection_mode"].asInt();
468 
469  if (!root["invert"].isNull())
470  invert = root["invert"].asInt();
471 
472  if (!root["input_model"].isNull())
473  input_model = root["input_model"].asInt();
474 
475  if (!root["interpolation"].isNull())
476  interpolation = root["interpolation"].asInt();
477 
478  // Clamp to enum options
479  projection_mode = std::clamp(projection_mode,
480  (int)MODE_RECT_SPHERE,
482  invert = std::clamp(invert, (int)INVERT_NORMAL, (int)INVERT_BACK);
484  interpolation = std::clamp(interpolation, (int)INTERP_NEAREST, (int)INTERP_AUTO);
485 
486  // any property change should invalidate cached UV map
487  uv_map.clear();
488 
489 
490  // any property change should invalidate cached UV map
491  uv_map.clear();
492 }
493 std::string SphericalProjection::PropertiesJSON(int64_t requested_frame) const
494 {
495  Json::Value root = BasePropertiesJSON(requested_frame);
496 
497  root["yaw"] = add_property_json("Yaw", yaw.GetValue(requested_frame), "float", "degrees", &yaw, -180, 180, false, requested_frame);
498  root["pitch"] = add_property_json("Pitch", pitch.GetValue(requested_frame), "float", "degrees", &pitch,-180, 180, false, requested_frame);
499  root["roll"] = add_property_json("Roll", roll.GetValue(requested_frame), "float", "degrees", &roll, -180, 180, false, requested_frame);
500 
501  root["fov"] = add_property_json("Out FOV", fov.GetValue(requested_frame), "float", "degrees", &fov, 0, 179, false, requested_frame);
502  root["in_fov"] = add_property_json("In FOV", in_fov.GetValue(requested_frame), "float", "degrees", &in_fov, 1, 360, false, requested_frame);
503 
504  root["projection_mode"] = add_property_json("Projection Mode", projection_mode, "int", "", nullptr,
505  (int)MODE_RECT_SPHERE, (int)MODE_FISHEYE_ORTHOGRAPHIC, false, requested_frame);
506  root["projection_mode"]["choices"].append(add_property_choice_json("Sphere", (int)MODE_RECT_SPHERE, projection_mode));
507  root["projection_mode"]["choices"].append(add_property_choice_json("Hemisphere", (int)MODE_RECT_HEMISPHERE, projection_mode));
508  root["projection_mode"]["choices"].append(add_property_choice_json("Fisheye: Equidistant", (int)MODE_FISHEYE_EQUIDISTANT, projection_mode));
509  root["projection_mode"]["choices"].append(add_property_choice_json("Fisheye: Equisolid", (int)MODE_FISHEYE_EQUISOLID, projection_mode));
510  root["projection_mode"]["choices"].append(add_property_choice_json("Fisheye: Stereographic", (int)MODE_FISHEYE_STEREOGRAPHIC,projection_mode));
511  root["projection_mode"]["choices"].append(add_property_choice_json("Fisheye: Orthographic", (int)MODE_FISHEYE_ORTHOGRAPHIC, projection_mode));
512 
513  root["invert"] = add_property_json("Invert View", invert, "int", "", nullptr, 0, 1, false, requested_frame);
514  root["invert"]["choices"].append(add_property_choice_json("Normal", 0, invert));
515  root["invert"]["choices"].append(add_property_choice_json("Invert", 1, invert));
516 
517  root["input_model"] = add_property_json("Input Model", input_model, "int", "", nullptr, INPUT_EQUIRECT, INPUT_FEQ_ORTHOGRAPHIC, false, requested_frame);
518  root["input_model"]["choices"].append(add_property_choice_json("Equirectangular (Panorama)", INPUT_EQUIRECT, input_model));
519  root["input_model"]["choices"].append(add_property_choice_json("Fisheye: Equidistant", INPUT_FEQ_EQUIDISTANT, input_model));
520  root["input_model"]["choices"].append(add_property_choice_json("Fisheye: Equisolid", INPUT_FEQ_EQUISOLID, input_model));
521  root["input_model"]["choices"].append(add_property_choice_json("Fisheye: Stereographic", INPUT_FEQ_STEREOGRAPHIC, input_model));
522  root["input_model"]["choices"].append(add_property_choice_json("Fisheye: Orthographic", INPUT_FEQ_ORTHOGRAPHIC, input_model));
523 
524  root["interpolation"] = add_property_json("Interpolation", interpolation, "int", "", nullptr, 0, 3, false, requested_frame);
525  root["interpolation"]["choices"].append(add_property_choice_json("Nearest", 0, interpolation));
526  root["interpolation"]["choices"].append(add_property_choice_json("Bilinear", 1, interpolation));
527  root["interpolation"]["choices"].append(add_property_choice_json("Bicubic", 2, interpolation));
528  root["interpolation"]["choices"].append(add_property_choice_json("Auto", 3, interpolation));
529 
530  return root.toStyledString();
531 }
openshot::SphericalProjection::invert
int invert
0=Normal, 1=Invert (back lens / +180°)
Definition: SphericalProjection.h:74
openshot::ClipBase::add_property_json
Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, const Keyframe *keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) const
Generate JSON for a property.
Definition: ClipBase.cpp:96
openshot::stringToJson
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:16
openshot::EffectBase::info
EffectInfoStruct info
Information about the current effect.
Definition: EffectBase.h:69
openshot::SphericalProjection::interpolation
int interpolation
0=Nearest, 1=Bilinear, 2=Bicubic, 3=Auto
Definition: SphericalProjection.h:76
openshot::SphericalProjection::pitch
Keyframe pitch
Pitch around right-axis (degrees)
Definition: SphericalProjection.h:68
openshot::SphericalProjection::MODE_FISHEYE_EQUIDISTANT
@ MODE_FISHEYE_EQUIDISTANT
Definition: SphericalProjection.h:49
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:28
openshot::SphericalProjection::INTERP_BILINEAR
@ INTERP_BILINEAR
Definition: SphericalProjection.h:57
openshot::SphericalProjection::INPUT_FEQ_STEREOGRAPHIC
@ INPUT_FEQ_STEREOGRAPHIC
Definition: SphericalProjection.h:42
openshot::SphericalProjection::SetJsonValue
void SetJsonValue(Json::Value root) override
Load Json::Value into this object.
Definition: SphericalProjection.cpp:456
openshot::SphericalProjection::INTERP_BICUBIC
@ INTERP_BICUBIC
Definition: SphericalProjection.h:58
openshot::ClipBase::add_property_choice_json
Json::Value add_property_choice_json(std::string name, int value, int selected_value) const
Generate JSON choice for a property (dropdown properties)
Definition: ClipBase.cpp:132
openshot::SphericalProjection::INPUT_FEQ_ORTHOGRAPHIC
@ INPUT_FEQ_ORTHOGRAPHIC
Definition: SphericalProjection.h:43
openshot::EffectBase::JsonValue
virtual Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: EffectBase.cpp:79
openshot::SphericalProjection::MODE_FISHEYE_STEREOGRAPHIC
@ MODE_FISHEYE_STEREOGRAPHIC
Definition: SphericalProjection.h:51
openshot::SphericalProjection::MODE_FISHEYE_EQUISOLID
@ MODE_FISHEYE_EQUISOLID
Definition: SphericalProjection.h:50
openshot::SphericalProjection::INVERT_NORMAL
@ INVERT_NORMAL
Definition: SphericalProjection.h:63
openshot::SphericalProjection::yaw
Keyframe yaw
Yaw around up-axis (degrees)
Definition: SphericalProjection.h:67
openshot::Keyframe::SetJsonValue
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: KeyFrame.cpp:372
openshot::Keyframe::JsonValue
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: KeyFrame.cpp:339
openshot::SphericalProjection::INPUT_FEQ_EQUIDISTANT
@ INPUT_FEQ_EQUIDISTANT
Definition: SphericalProjection.h:40
openshot::EffectBase::BasePropertiesJSON
Json::Value BasePropertiesJSON(int64_t requested_frame) const
Generate JSON object of base properties (recommended to be used by all effects)
Definition: EffectBase.cpp:179
openshot::SphericalProjection::INPUT_FEQ_EQUISOLID
@ INPUT_FEQ_EQUISOLID
Definition: SphericalProjection.h:41
openshot::SphericalProjection::PropertiesJSON
std::string PropertiesJSON(int64_t requested_frame) const override
Definition: SphericalProjection.cpp:493
openshot::Keyframe
A Keyframe is a collection of Point instances, which is used to vary a number or property over time.
Definition: KeyFrame.h:53
openshot::SphericalProjection::INPUT_EQUIRECT
@ INPUT_EQUIRECT
Definition: SphericalProjection.h:39
openshot::SphericalProjection::MODE_RECT_HEMISPHERE
@ MODE_RECT_HEMISPHERE
Definition: SphericalProjection.h:48
openshot::SphericalProjection::MODE_RECT_SPHERE
@ MODE_RECT_SPHERE
Definition: SphericalProjection.h:47
openshot::InvalidJSON
Exception for invalid JSON.
Definition: Exceptions.h:217
openshot::SphericalProjection::GetFrame
std::shared_ptr< Frame > GetFrame(int64_t frame_number) override
ClipBase override: create a fresh Frame then call the main GetFrame.
Definition: SphericalProjection.h:86
openshot::EffectBase::InitEffectInfo
void InitEffectInfo()
Definition: EffectBase.cpp:24
openshot::SphericalProjection::INTERP_NEAREST
@ INTERP_NEAREST
Definition: SphericalProjection.h:56
openshot::EffectInfoStruct::has_audio
bool has_audio
Determines if this effect manipulates the audio of a frame.
Definition: EffectBase.h:41
openshot::SphericalProjection::projection_mode
int projection_mode
0=Sphere, 1=Hemisphere, 2=Fisheye
Definition: SphericalProjection.h:73
SphericalProjection.h
Header file for SphericalProjection effect class.
openshot::SphericalProjection::SphericalProjection
SphericalProjection()
Blank ctor (for JSON deserialization)
Definition: SphericalProjection.cpp:23
openshot::SphericalProjection::Json
std::string Json() const override
Generate JSON string of this object.
Definition: SphericalProjection.cpp:422
openshot::EffectInfoStruct::class_name
std::string class_name
The class name of the effect.
Definition: EffectBase.h:36
openshot::EffectInfoStruct::description
std::string description
The description of this effect and what it does.
Definition: EffectBase.h:38
openshot::EffectInfoStruct::has_video
bool has_video
Determines if this effect manipulates the image of a frame.
Definition: EffectBase.h:40
openshot::SphericalProjection::in_fov
Keyframe in_fov
Source lens coverage / FOV (degrees)
Definition: SphericalProjection.h:71
openshot::SphericalProjection::INTERP_AUTO
@ INTERP_AUTO
Definition: SphericalProjection.h:59
openshot::EffectInfoStruct::name
std::string name
The name of the effect.
Definition: EffectBase.h:37
openshot::SphericalProjection::SetJson
void SetJson(std::string value) override
Load JSON string into this object.
Definition: SphericalProjection.cpp:443
openshot::SphericalProjection::JsonValue
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition: SphericalProjection.cpp:427
openshot::SphericalProjection::input_model
int input_model
0=Equirect, 1=Fisheye-Equidistant
Definition: SphericalProjection.h:75
openshot::SphericalProjection::fov
Keyframe fov
Output field-of-view (degrees)
Definition: SphericalProjection.h:70
Exceptions.h
Header file for all Exception classes.
openshot::SphericalProjection::roll
Keyframe roll
Roll around forward-axis (degrees)
Definition: SphericalProjection.h:69
openshot::SphericalProjection::MODE_FISHEYE_ORTHOGRAPHIC
@ MODE_FISHEYE_ORTHOGRAPHIC
Definition: SphericalProjection.h:52
openshot::EffectBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: EffectBase.cpp:115
openshot::SphericalProjection::INVERT_BACK
@ INVERT_BACK
Definition: SphericalProjection.h:64
openshot::Keyframe::GetValue
double GetValue(int64_t index) const
Get the value at a specific index.
Definition: KeyFrame.cpp:258