OpenShot Library | libopenshot  0.7.0
AnalogTape.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 "AnalogTape.h"
14 #include "Clip.h"
15 #include "Exceptions.h"
16 #include "ReaderBase.h"
17 #include "Timeline.h"
18 
19 #include <algorithm>
20 #include <cmath>
21 
22 using namespace openshot;
23 
25  : tracking(0.55), bleed(0.65), softness(0.40), noise(0.50), stripe(0.25f),
26  staticBands(0.20f), seed_offset(0) {
27  init_effect_details();
28 }
29 
31  Keyframe st, Keyframe sb, int seed)
32  : tracking(t), bleed(b), softness(s), noise(n), stripe(st),
33  staticBands(sb), seed_offset(seed) {
34  init_effect_details();
35 }
36 
37 void AnalogTape::init_effect_details() {
39  info.class_name = "AnalogTape";
40  info.name = "Analog Tape";
41  info.description = "Vintage home video wobble, bleed, and grain.";
42  info.has_video = true;
43  info.has_audio = false;
44 }
45 
46 static inline float lerp(float a, float b, float t) { return a + (b - a) * t; }
47 
48 std::shared_ptr<Frame> AnalogTape::GetFrame(std::shared_ptr<Frame> frame,
49  int64_t frame_number) {
50  std::shared_ptr<QImage> img = frame->GetImage();
51  int w = img->width();
52  int h = img->height();
53  int Uw = (w + 1) / 2;
54  int stride = img->bytesPerLine() / 4;
55  uint32_t *base = reinterpret_cast<uint32_t *>(img->bits());
56 
57  if (w != last_w || h != last_h) {
58  last_w = w;
59  last_h = h;
60  Y.resize(w * h);
61  U.resize(Uw * h);
62  V.resize(Uw * h);
63  tmpY.resize(w * h);
64  tmpU.resize(Uw * h);
65  tmpV.resize(Uw * h);
66  dx.resize(h);
67  }
68 
69 
70 #ifdef _OPENMP
71 #pragma omp parallel for
72 #endif
73  for (int y = 0; y < h; ++y) {
74  uint32_t *row = base + y * stride;
75  float *yrow = &Y[y * w];
76  float *urow = &U[y * Uw];
77  float *vrow = &V[y * Uw];
78  for (int x2 = 0; x2 < Uw; ++x2) {
79  int x0 = x2 * 2;
80  uint32_t p0 = row[x0];
81  float r0 = ((p0 >> 16) & 0xFF) / 255.0f;
82  float g0 = ((p0 >> 8) & 0xFF) / 255.0f;
83  float b0 = (p0 & 0xFF) / 255.0f;
84  float y0 = 0.299f * r0 + 0.587f * g0 + 0.114f * b0;
85  float u0 = -0.14713f * r0 - 0.28886f * g0 + 0.436f * b0;
86  float v0 = 0.615f * r0 - 0.51499f * g0 - 0.10001f * b0;
87  yrow[x0] = y0;
88 
89  float u, v;
90  if (x0 + 1 < w) {
91  uint32_t p1 = row[x0 + 1];
92  float r1 = ((p1 >> 16) & 0xFF) / 255.0f;
93  float g1 = ((p1 >> 8) & 0xFF) / 255.0f;
94  float b1 = (p1 & 0xFF) / 255.0f;
95  float y1 = 0.299f * r1 + 0.587f * g1 + 0.114f * b1;
96  float u1 = -0.14713f * r1 - 0.28886f * g1 + 0.436f * b1;
97  float v1 = 0.615f * r1 - 0.51499f * g1 - 0.10001f * b1;
98  yrow[x0 + 1] = y1;
99  u = (u0 + u1) * 0.5f;
100  v = (v0 + v1) * 0.5f;
101  } else {
102  u = u0;
103  v = v0;
104  }
105  urow[x2] = u;
106  vrow[x2] = v;
107  }
108  }
109 
110  Fraction fps(1, 1);
111  Clip *clip = (Clip *)ParentClip();
112  Timeline *timeline = nullptr;
113  if (clip && clip->ParentTimeline())
114  timeline = (Timeline *)clip->ParentTimeline();
115  else if (ParentTimeline())
116  timeline = (Timeline *)ParentTimeline();
117  if (timeline)
118  fps = timeline->info.fps;
119  else if (clip && clip->Reader())
120  fps = clip->Reader()->info.fps;
121  int reference_w = w;
122  int reference_h = h;
123  if (timeline && timeline->info.width > 0 && timeline->info.height > 0) {
124  reference_w = timeline->info.width;
125  reference_h = timeline->info.height;
126  }
127  const float reference_scale_x = w > 0 ? static_cast<float>(reference_w) / static_cast<float>(w) : 1.0f;
128  const float reference_scale_y = h > 0 ? static_cast<float>(reference_h) / static_cast<float>(h) : 1.0f;
129  const float inverse_scale_x = reference_scale_x > 0.0f ? 1.0f / reference_scale_x : 1.0f;
130  double fps_d = fps.ToDouble();
131  double t = fps_d > 0 ? frame_number / fps_d : frame_number;
132 
133  const float k_track = tracking.GetValue(frame_number);
134  const float k_bleed = bleed.GetValue(frame_number);
135  const float k_soft = softness.GetValue(frame_number);
136  const float k_noise = noise.GetValue(frame_number);
137  const float k_stripe = stripe.GetValue(frame_number);
138  const float k_bands = staticBands.GetValue(frame_number);
139 
140  int r_y = std::round(lerp(0.0f, 2.0f, k_soft) * inverse_scale_x);
141  if (k_noise > 0.6f)
142  r_y = std::min(r_y, 1);
143  if (r_y > 0) {
144 #ifdef _OPENMP
145 #pragma omp parallel for
146 #endif
147  for (int y = 0; y < h; ++y)
148  box_blur_row(&Y[y * w], &tmpY[y * w], w, r_y);
149  Y.swap(tmpY);
150  }
151 
152  float shift = lerp(0.0f, 2.5f, k_bleed) * inverse_scale_x;
153  int r_c = std::round(lerp(0.0f, 3.0f, k_bleed) * inverse_scale_x);
154  float sat = 1.0f - 0.30f * k_bleed;
155  float shift_h = shift * 0.5f;
156 #ifdef _OPENMP
157 #pragma omp parallel for
158 #endif
159  for (int y = 0; y < h; ++y) {
160  const float *srcU = &U[y * Uw];
161  const float *srcV = &V[y * Uw];
162  float *dstU = &tmpU[y * Uw];
163  float *dstV = &tmpV[y * Uw];
164  for (int x = 0; x < Uw; ++x) {
165  float xs = std::clamp(x - shift_h, 0.0f, float(Uw - 1));
166  int x0 = int(xs);
167  int x1 = std::min(x0 + 1, Uw - 1);
168  float t = xs - x0;
169  dstU[x] = srcU[x0] * (1 - t) + srcU[x1] * t;
170  dstV[x] = srcV[x0] * (1 - t) + srcV[x1] * t;
171  }
172  }
173  U.swap(tmpU);
174  V.swap(tmpV);
175 
176  if (r_c > 0) {
177 #ifdef _OPENMP
178 #pragma omp parallel for
179 #endif
180  for (int y = 0; y < h; ++y)
181  box_blur_row(&U[y * Uw], &tmpU[y * Uw], Uw, r_c);
182  U.swap(tmpU);
183 #ifdef _OPENMP
184 #pragma omp parallel for
185 #endif
186  for (int y = 0; y < h; ++y)
187  box_blur_row(&V[y * Uw], &tmpV[y * Uw], Uw, r_c);
188  V.swap(tmpV);
189  }
190 
191  uint32_t SEED = fnv1a_32(Id()) ^ (uint32_t)seed_offset;
192  uint32_t schedSalt = (uint32_t)(k_bands * 64.0f) ^
193  ((uint32_t)(k_stripe * 64.0f) << 8) ^
194  ((uint32_t)(k_noise * 64.0f) << 16);
195  uint32_t SCHED_SEED = SEED ^ fnv1a_32(schedSalt, 0x9e3779b9u);
196  const float PI = 3.14159265358979323846f;
197 
198  float sigmaY = lerp(0.0f, 0.08f, k_noise);
199  const float decay = 0.88f + 0.08f * k_noise;
200  const float amp = 0.18f * k_noise;
201  const float baseP = 0.0025f + 0.02f * k_noise;
202 
203  float Hfixed = lerp(0.0f, 0.12f * h, k_stripe);
204  float Gfixed = 0.10f * k_stripe;
205  float Nfixed = 1.0f + 1.5f * k_stripe;
206 
207  float rate = 0.4f * k_bands;
208  int dur_frames = std::round(lerp(1.0f, 6.0f, k_bands));
209  float Hburst = lerp(0.06f * h, 0.25f * h, k_bands);
210  float Gburst = lerp(0.10f, 0.25f, k_bands);
211  float sat_band = lerp(0.8f, 0.5f, k_bands);
212  float Nburst = 1.0f + 2.0f * k_bands;
213 
214  struct Band { float center; double t0; };
215  std::vector<Band> bands;
216  if (k_bands > 0.0f && rate > 0.0f) {
217  const double win_len = 0.25;
218  int win_idx = int(t / win_len);
219  double lambda = rate * win_len *
220  (0.25 + 1.5f * row_density(SCHED_SEED, frame_number, 0));
221  double prob_ge1 = 1.0 - std::exp(-lambda);
222  double prob_ge2 = 1.0 - std::exp(-lambda) - lambda * std::exp(-lambda);
223 
224  auto spawn_band = [&](int kseed) {
225  float r1 = hash01(SCHED_SEED, uint32_t(win_idx), 11 + kseed, 0);
226  float start = r1 * win_len;
227  float center =
228  hash01(SCHED_SEED, uint32_t(win_idx), 12 + kseed, 0) * (h - Hburst) +
229  0.5f * Hburst;
230  double t0 = win_idx * win_len + start;
231  double t1 = t0 + dur_frames / (fps_d > 0 ? fps_d : 1.0);
232  if (t >= t0 && t < t1)
233  bands.push_back({center, t0});
234  };
235 
236  float r = hash01(SCHED_SEED, uint32_t(win_idx), 9, 0);
237  if (r < prob_ge1)
238  spawn_band(0);
239  if (r < prob_ge2)
240  spawn_band(1);
241  }
242 
243  float ft = 2.0f;
244  int kf = int(std::floor(t * ft));
245  float a = float(t * ft - kf);
246 
247 #ifdef _OPENMP
248 #pragma omp parallel for
249 #endif
250  for (int y = 0; y < h; ++y) {
251  const int y_ref = static_cast<int>(std::round(static_cast<float>(y) * reference_scale_y));
252  float bandF = 0.0f;
253  if (Hfixed > 0.0f && y >= h - Hfixed)
254  bandF = (y - (h - Hfixed)) / std::max(1.0f, Hfixed);
255  float burstF = 0.0f;
256  for (const auto &b : bands) {
257  float halfH = Hburst * 0.5f;
258  float dist = std::abs(y - b.center);
259  float profile = std::max(0.0f, 1.0f - dist / halfH);
260  float life = float((t - b.t0) * fps_d);
261  float env = (life < 1.0f)
262  ? life
263  : (life < dur_frames - 1 ? 1.0f
264  : std::max(0.0f, dur_frames - life));
265  burstF = std::max(burstF, profile * env);
266  }
267 
268  float sat_row = 1.0f - (1.0f - sat_band) * burstF;
269  if (burstF > 0.0f && sat_row != 1.0f) {
270  float *urow = &U[y * Uw];
271  float *vrow = &V[y * Uw];
272  for (int xh = 0; xh < Uw; ++xh) {
273  urow[xh] *= sat_row;
274  vrow[xh] *= sat_row;
275  }
276  }
277 
278  float rowBias = row_density(SEED, frame_number, y_ref);
279  float p = baseP * (0.25f + 1.5f * rowBias);
280  p *= (1.0f + 1.5f * bandF + 2.0f * burstF);
281 
282  float hum = 0.008f * k_noise *
283  std::sin(2 * PI * (y_ref * (6.0f / reference_h) + 0.08f * t));
284  uint32_t s0 = SEED ^ 0x9e37u * kf ^ 0x85ebu * y_ref;
285  uint32_t s1 = SEED ^ 0x9e37u * (kf + 1) ^ 0x85ebu * y_ref ^ 0x1234567u;
286  auto step = [](uint32_t &s) {
287  s ^= s << 13;
288  s ^= s >> 17;
289  s ^= s << 5;
290  return s;
291  };
292  float lift = Gfixed * bandF + Gburst * burstF;
293  float rowSigma = sigmaY * (1 + (Nfixed - 1) * bandF +
294  (Nburst - 1) * burstF);
295  float k = 0.15f + 0.35f * hash01(SEED, uint32_t(frame_number), y_ref, 777);
296  float sL = 0.0f, sR = 0.0f;
297  for (int x = 0; x < w; ++x) {
298  const int x_ref = static_cast<int>(std::round(static_cast<float>(x) * reference_scale_x));
299  if (hash01(SEED, uint32_t(frame_number), y_ref, x_ref) < p)
300  sL = 1.0f;
301  if (hash01(SEED, uint32_t(frame_number), y_ref, reference_w - 1 - x_ref) < p * 0.7f)
302  sR = 1.0f;
303  float n = ((step(s0) & 0xFFFFFF) / 16777215.0f) * (1 - a) +
304  ((step(s1) & 0xFFFFFF) / 16777215.0f) * a;
305  int idx = y * w + x;
306  float mt = std::clamp((Y[idx] - 0.2f) / (0.8f - 0.2f), 0.0f, 1.0f);
307  float val = Y[idx] + lift + rowSigma * (2 * n - 1) *
308  (0.6f + 0.4f * mt) + hum;
309  float streak = amp * (sL + sR);
310  float newY = val + streak * (k + (1.0f - val));
311  Y[idx] = std::clamp(newY, 0.0f, 1.0f);
312  sL *= decay;
313  sR *= decay;
314  }
315  }
316 
317  float A = lerp(0.0f, 3.0f, k_track) * inverse_scale_x; // pixels
318  float f = lerp(0.25f, 1.2f, k_track); // Hz
319  float Hsk = lerp(0.0f, 0.10f * h, k_track); // pixels
320  float S = lerp(0.0f, 5.0f, k_track) * inverse_scale_x; // pixels
321  float phase = 2 * PI * (f * t) + 0.7f * (SEED * 0.001f);
322  for (int y = 0; y < h; ++y) {
323  const float y_ref = static_cast<float>(y) * reference_scale_y;
324  float base = A * std::sin(2 * PI * 0.0035f * y_ref + phase);
325  float skew = (y >= h - Hsk)
326  ? S * ((y - (h - Hsk)) / std::max(1.0f, Hsk))
327  : 0.0f;
328  dx[y] = base + skew;
329  }
330 
331  auto remap_line = [&](const float *src, float *dst, int width, float scale) {
332 #ifdef _OPENMP
333 #pragma omp parallel for
334 #endif
335  for (int y = 0; y < h; ++y) {
336  float off = dx[y] * scale;
337  const float *s = src + y * width;
338  float *d = dst + y * width;
339  int start = std::max(0, int(std::ceil(-off)));
340  int end = std::min(width, int(std::floor(width - off)));
341  float xs = start + off;
342  int x0 = int(xs);
343  float t = xs - x0;
344  for (int x = start; x < end; ++x) {
345  int x1 = x0 + 1;
346  d[x] = s[x0] * (1 - t) + s[x1] * t;
347  xs += 1.0f;
348  x0 = int(xs);
349  t = xs - x0;
350  }
351  for (int x = 0; x < start; ++x)
352  d[x] = s[0];
353  for (int x = end; x < width; ++x)
354  d[x] = s[width - 1];
355  }
356  };
357 
358  remap_line(Y.data(), tmpY.data(), w, 1.0f);
359  Y.swap(tmpY);
360  remap_line(U.data(), tmpU.data(), Uw, 0.5f);
361  U.swap(tmpU);
362  remap_line(V.data(), tmpV.data(), Uw, 0.5f);
363  V.swap(tmpV);
364 
365 #ifdef _OPENMP
366 #pragma omp parallel for
367 #endif
368  for (int y = 0; y < h; ++y) {
369  float *yrow = &Y[y * w];
370  float *urow = &U[y * Uw];
371  float *vrow = &V[y * Uw];
372  uint32_t *row = base + y * stride;
373  for (int x = 0; x < w; ++x) {
374  float xs = x * 0.5f;
375  int x0 = int(xs);
376  int x1 = std::min(x0 + 1, Uw - 1);
377  float t = xs - x0;
378  float u = (urow[x0] * (1 - t) + urow[x1] * t) * sat;
379  float v = (vrow[x0] * (1 - t) + vrow[x1] * t) * sat;
380  float yv = yrow[x];
381  float r = yv + 1.13983f * v;
382  float g = yv - 0.39465f * u - 0.58060f * v;
383  float b = yv + 2.03211f * u;
384  int R = int(std::clamp(r, 0.0f, 1.0f) * 255.0f);
385  int G = int(std::clamp(g, 0.0f, 1.0f) * 255.0f);
386  int B = int(std::clamp(b, 0.0f, 1.0f) * 255.0f);
387  uint32_t A = row[x] & 0xFF000000u;
388  row[x] = A | (R << 16) | (G << 8) | B;
389  }
390  }
391 
392  return frame;
393 }
394 
395 // JSON
396 std::string AnalogTape::Json() const { return JsonValue().toStyledString(); }
397 
398 Json::Value AnalogTape::JsonValue() const {
399  Json::Value root = EffectBase::JsonValue();
400  root["type"] = info.class_name;
401  root["tracking"] = tracking.JsonValue();
402  root["bleed"] = bleed.JsonValue();
403  root["softness"] = softness.JsonValue();
404  root["noise"] = noise.JsonValue();
405  root["stripe"] = stripe.JsonValue();
406  root["static_bands"] = staticBands.JsonValue();
407  root["seed_offset"] = seed_offset;
408  return root;
409 }
410 
411 void AnalogTape::SetJson(const std::string value) {
412  try {
413  Json::Value root = openshot::stringToJson(value);
414  SetJsonValue(root);
415  } catch (const std::exception &) {
416  throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
417  }
418 }
419 
420 void AnalogTape::SetJsonValue(const Json::Value root) {
422  if (!root["tracking"].isNull())
423  tracking.SetJsonValue(root["tracking"]);
424  if (!root["bleed"].isNull())
425  bleed.SetJsonValue(root["bleed"]);
426  if (!root["softness"].isNull())
427  softness.SetJsonValue(root["softness"]);
428  if (!root["noise"].isNull())
429  noise.SetJsonValue(root["noise"]);
430  if (!root["stripe"].isNull())
431  stripe.SetJsonValue(root["stripe"]);
432  if (!root["static_bands"].isNull())
433  staticBands.SetJsonValue(root["static_bands"]);
434  if (!root["seed_offset"].isNull())
435  seed_offset = root["seed_offset"].asInt();
436 }
437 
438 std::string AnalogTape::PropertiesJSON(int64_t requested_frame) const {
439  Json::Value root = BasePropertiesJSON(requested_frame);
440  root["tracking"] =
441  add_property_json("Tracking", tracking.GetValue(requested_frame), "float",
442  "", &tracking, 0, 1, false, requested_frame);
443  root["bleed"] =
444  add_property_json("Bleed", bleed.GetValue(requested_frame), "float", "",
445  &bleed, 0, 1, false, requested_frame);
446  root["softness"] =
447  add_property_json("Softness", softness.GetValue(requested_frame), "float",
448  "", &softness, 0, 1, false, requested_frame);
449  root["noise"] =
450  add_property_json("Noise", noise.GetValue(requested_frame), "float", "",
451  &noise, 0, 1, false, requested_frame);
452  root["stripe"] =
453  add_property_json("Stripe", stripe.GetValue(requested_frame), "float",
454  "Bottom tracking stripe brightness and noise.",
455  &stripe, 0, 1, false, requested_frame);
456  root["static_bands"] =
457  add_property_json("Static Bands", staticBands.GetValue(requested_frame),
458  "float",
459  "Short bright static bands and extra dropouts.",
460  &staticBands, 0, 1, false, requested_frame);
461  root["seed_offset"] =
462  add_property_json("Seed Offset", seed_offset, "int", "", NULL, 0, 1000,
463  false, requested_frame);
464  return root.toStyledString();
465 }
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::ClipBase::timeline
openshot::TimelineBase * timeline
Pointer to the parent timeline instance (if any)
Definition: ClipBase.h:40
openshot::EffectBase::info
EffectInfoStruct info
Information about the current effect.
Definition: EffectBase.h:110
openshot::AnalogTape::PropertiesJSON
std::string PropertiesJSON(int64_t requested_frame) const override
Definition: AnalogTape.cpp:438
openshot::AnalogTape::AnalogTape
AnalogTape()
Definition: AnalogTape.cpp:24
Clip.h
Header file for Clip class.
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: AnimatedCurve.h:24
openshot::EffectBase::ParentClip
openshot::ClipBase * ParentClip()
Parent clip object of this effect (which can be unparented and NULL)
Definition: EffectBase.cpp:549
openshot::AnalogTape::seed_offset
int seed_offset
seed offset for deterministic randomness
Definition: AnalogTape.h:108
openshot::Clip
This class represents a clip (used to arrange readers on the timeline)
Definition: Clip.h:89
openshot::EffectBase::JsonValue
virtual Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: EffectBase.cpp:96
openshot::Fraction
This class represents a fraction.
Definition: Fraction.h:30
openshot::AnalogTape::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(std::shared_ptr< openshot::Frame > frame, int64_t frame_number) override
This method is required for all derived classes of ClipBase, and returns a modified openshot::Frame o...
Timeline.h
Header file for Timeline class.
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::AnalogTape::noise
Keyframe noise
grain/dropouts amount
Definition: AnalogTape.h:105
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:236
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::AnalogTape::JsonValue
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition: AnalogTape.cpp:398
openshot::AnalogTape::bleed
Keyframe bleed
color bleed amount
Definition: AnalogTape.h:103
openshot::InvalidJSON
Exception for invalid JSON.
Definition: Exceptions.h:223
openshot::Timeline
This class represents a timeline.
Definition: Timeline.h:153
openshot::EffectBase::InitEffectInfo
void InitEffectInfo()
Definition: EffectBase.cpp:37
openshot::EffectInfoStruct::has_audio
bool has_audio
Determines if this effect manipulates the audio of a frame.
Definition: EffectBase.h:44
openshot::ClipBase::end
float end
The position in seconds to end playing (used to trim the ending of a clip)
Definition: ClipBase.h:38
openshot::ClipBase::start
float start
The position in seconds to start playing (used to trim the beginning of a clip)
Definition: ClipBase.h:37
openshot::AnalogTape::SetJsonValue
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
Definition: AnalogTape.cpp:420
openshot::EffectInfoStruct::class_name
std::string class_name
The class name of the effect.
Definition: EffectBase.h:39
ReaderBase.h
Header file for ReaderBase class.
openshot::AnalogTape::tracking
Keyframe tracking
tracking wobble amount
Definition: AnalogTape.h:102
openshot::EffectInfoStruct::description
std::string description
The description of this effect and what it does.
Definition: EffectBase.h:41
openshot::EffectInfoStruct::has_video
bool has_video
Determines if this effect manipulates the image of a frame.
Definition: EffectBase.h:43
openshot::ClipBase::Id
void Id(std::string value)
Definition: ClipBase.h:94
AnalogTape.h
Header file for AnalogTape effect class.
openshot::AnalogTape::stripe
Keyframe stripe
bottom tracking stripe strength
Definition: AnalogTape.h:106
openshot::AnalogTape::SetJson
void SetJson(const std::string value) override
Load JSON string into this object.
Definition: AnalogTape.cpp:411
openshot::EffectInfoStruct::name
std::string name
The name of the effect.
Definition: EffectBase.h:40
openshot::AnalogTape::staticBands
Keyframe staticBands
burst static band strength
Definition: AnalogTape.h:107
openshot::AnalogTape::Json
std::string Json() const override
Generate JSON string of this object.
Definition: AnalogTape.cpp:396
openshot::AnalogTape::softness
Keyframe softness
luma blur radius
Definition: AnalogTape.h:104
Exceptions.h
Header file for all Exception classes.
openshot::EffectBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: EffectBase.cpp:139
openshot::Keyframe::GetValue
double GetValue(int64_t index) const
Get the value at a specific index.
Definition: KeyFrame.cpp:258
openshot::EffectBase::clip
openshot::ClipBase * clip
Pointer to the parent clip instance (if any)
Definition: EffectBase.h:73