filters/edit.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. | ||
| 2 | // http://avisynth.nl | ||
| 3 | |||
| 4 | // This program is free software; you can redistribute it and/or modify | ||
| 5 | // it under the terms of the GNU General Public License as published by | ||
| 6 | // the Free Software Foundation; either version 2 of the License, or | ||
| 7 | // (at your option) any later version. | ||
| 8 | // | ||
| 9 | // This program is distributed in the hope that it will be useful, | ||
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | // GNU General Public License for more details. | ||
| 13 | // | ||
| 14 | // You should have received a copy of the GNU General Public License | ||
| 15 | // along with this program; if not, write to the Free Software | ||
| 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit | ||
| 17 | // http://www.gnu.org/copyleft/gpl.html . | ||
| 18 | // | ||
| 19 | // Linking Avisynth statically or dynamically with other modules is making a | ||
| 20 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU | ||
| 21 | // General Public License cover the whole combination. | ||
| 22 | // | ||
| 23 | // As a special exception, the copyright holders of Avisynth give you | ||
| 24 | // permission to link Avisynth with independent modules that communicate with | ||
| 25 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license | ||
| 26 | // terms of these independent modules, and to copy and distribute the | ||
| 27 | // resulting combined work under terms of your choice, provided that | ||
| 28 | // every copy of the combined work is accompanied by a complete copy of | ||
| 29 | // the source code of Avisynth (the version of Avisynth used to produce the | ||
| 30 | // combined work), being distributed under the terms of the GNU General | ||
| 31 | // Public License plus this exception. An independent module is a module | ||
| 32 | // which is not derived from or based on Avisynth, such as 3rd-party filters, | ||
| 33 | // import and export plugins, or graphical user interfaces. | ||
| 34 | |||
| 35 | #include "edit.h" | ||
| 36 | #include "../convert/convert_audio.h" | ||
| 37 | #include "../core/internal.h" | ||
| 38 | #include "merge.h" | ||
| 39 | #include <climits> | ||
| 40 | #include <cmath> | ||
| 41 | |||
| 42 | #ifdef AVS_WINDOWS | ||
| 43 | #include <avs/win.h> | ||
| 44 | #else | ||
| 45 | #include <avs/posix.h> | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #include <avs/minmax.h> | ||
| 49 | #include <avs/alignment.h> | ||
| 50 | #include <stdint.h> | ||
| 51 | #include <utility> | ||
| 52 | |||
| 53 | |||
| 54 | |||
| 55 | /******************************************************************** | ||
| 56 | ***** Declare index of new filters for Avisynth's filter engine ***** | ||
| 57 | ********************************************************************/ | ||
| 58 | |||
| 59 | enum { FADE_MODE_OUT0, FADE_MODE_OUT, FADE_MODE_OUT2, FADE_MODE_IN0, FADE_MODE_IN, FADE_MODE_IN2, FADE_MODE_IO0, FADE_MODE_IO, FADE_MODE_IO2 }; | ||
| 60 | |||
| 61 | extern const AVSFunction Edit_filters[] = { | ||
| 62 | { "AudioTrim", BUILTIN_FUNC_PREFIX, "cff[cache]b", Trim::CreateA, (void*)Trim::Default}, // start time, end time | ||
| 63 | { "AudioTrim", BUILTIN_FUNC_PREFIX, "cf[cache]b", Trim::CreateA, (void*)Trim::Invalid}, // Throw Invalid argument to AudioTrim because 4 parameters expected | ||
| 64 | { "AudioTrim", BUILTIN_FUNC_PREFIX, "cf[length]f[cache]b", Trim::CreateA, (void*)Trim::Length}, // start time, duration | ||
| 65 | { "AudioTrim", BUILTIN_FUNC_PREFIX, "cf[end]f[cache]b", Trim::CreateA, (void*)Trim::End}, // start time, end time | ||
| 66 | { "Trim", BUILTIN_FUNC_PREFIX, "cii[pad]b[cache]b", Trim::Create, (void*)Trim::Default}, // first frame, last frame[, pad audio] | ||
| 67 | { "Trim", BUILTIN_FUNC_PREFIX, "ci[pad]b[cache]b", Trim::Create, (void*)Trim::Invalid}, // Throw Invalid argument to Trim because 5 parameters expected | ||
| 68 | { "Trim", BUILTIN_FUNC_PREFIX, "ci[length]i[pad]b[cache]b", Trim::Create, (void*)Trim::Length}, // first frame, frame count[, pad audio] | ||
| 69 | { "Trim", BUILTIN_FUNC_PREFIX, "ci[end]i[pad]b[cache]b", Trim::Create, (void*)Trim::End}, // first frame, last frame[, pad audio] | ||
| 70 | { "FreezeFrame", BUILTIN_FUNC_PREFIX, "ciii", FreezeFrame::Create }, // first frame, last frame, source frame | ||
| 71 | { "DeleteFrame", BUILTIN_FUNC_PREFIX, "ci+", DeleteFrame::Create }, // frame # | ||
| 72 | { "DuplicateFrame", BUILTIN_FUNC_PREFIX, "ci+", DuplicateFrame::Create }, // frame # | ||
| 73 | { "UnalignedSplice", BUILTIN_FUNC_PREFIX, "cc+", Splice::CreateUnaligned }, // clips | ||
| 74 | { "AlignedSplice", BUILTIN_FUNC_PREFIX, "cc+", Splice::CreateAligned }, // clips | ||
| 75 | { "UnalignedSplice", BUILTIN_FUNC_PREFIX, "cci", Splice::CreateUnalignedNoCache }, // clips | ||
| 76 | { "AlignedSplice", BUILTIN_FUNC_PREFIX, "cci", Splice::CreateAlignedNoCache }, // clips | ||
| 77 | { "Dissolve", BUILTIN_FUNC_PREFIX, "cc+i[fps]f", Dissolve::Create }, // clips, overlap frames[, fps] | ||
| 78 | { "AudioDub", BUILTIN_FUNC_PREFIX, "cc", AudioDub::Create, (void*)0}, // video src, audio src | ||
| 79 | { "AudioDubEx", BUILTIN_FUNC_PREFIX, "cc", AudioDub::Create, (void*)1}, // video! src, audio! src | ||
| 80 | { "Reverse", BUILTIN_FUNC_PREFIX, "c", Reverse::Create }, // plays backwards | ||
| 81 | { "FadeOut0", BUILTIN_FUNC_PREFIX, "ci[color]i[fps]f[color_yuv]i[colors]f+", Create_Fade, (void*)FADE_MODE_OUT0 }, | ||
| 82 | { "FadeOut", BUILTIN_FUNC_PREFIX, "ci[color]i[fps]f[color_yuv]i[colors]f+", Create_Fade, (void*)FADE_MODE_OUT }, | ||
| 83 | { "FadeOut2", BUILTIN_FUNC_PREFIX, "ci[color]i[fps]f[color_yuv]i[colors]f+", Create_Fade, (void*)FADE_MODE_OUT2 }, | ||
| 84 | { "FadeIn0", BUILTIN_FUNC_PREFIX, "ci[color]i[fps]f[color_yuv]i[colors]f+", Create_Fade, (void*)FADE_MODE_IN0 }, | ||
| 85 | { "FadeIn", BUILTIN_FUNC_PREFIX, "ci[color]i[fps]f[color_yuv]i[colors]f+", Create_Fade, (void*)FADE_MODE_IN }, | ||
| 86 | { "FadeIn2", BUILTIN_FUNC_PREFIX, "ci[color]i[fps]f[color_yuv]i[colors]f+", Create_Fade, (void*)FADE_MODE_IN2 }, | ||
| 87 | { "FadeIO0", BUILTIN_FUNC_PREFIX, "ci[color]i[fps]f[color_yuv]i[colors]f+", Create_Fade, (void*)FADE_MODE_IO0 }, | ||
| 88 | { "FadeIO", BUILTIN_FUNC_PREFIX, "ci[color]i[fps]f[color_yuv]i[colors]f+", Create_Fade, (void*)FADE_MODE_IO }, | ||
| 89 | { "FadeIO2", BUILTIN_FUNC_PREFIX, "ci[color]i[fps]f[color_yuv]i[colors]f+", Create_Fade, (void*)FADE_MODE_IO2 }, | ||
| 90 | { "Loop", BUILTIN_FUNC_PREFIX, "c[times]i[start]i[end]i", Loop::Create }, // number of loops, first frame, last frames | ||
| 91 | { NULL } | ||
| 92 | }; | ||
| 93 | |||
| 94 | |||
| 95 | |||
| 96 | /****************************** | ||
| 97 | ******* NonCachedGenericVideoFilter Filter ****** | ||
| 98 | ******************************/ | ||
| 99 | |||
| 100 | 38 | NonCachedGenericVideoFilter::NonCachedGenericVideoFilter(PClip _child) : | |
| 101 |
2/4✓ Branch 2 → 3 taken 38 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 38 times.
✗ Branch 3 → 6 not taken.
|
38 | GenericVideoFilter(_child) |
| 102 | { | ||
| 103 | 38 | }; | |
| 104 | |||
| 105 | |||
| 106 | 6 | int __stdcall NonCachedGenericVideoFilter::SetCacheHints(int cachehints, int frame_range) | |
| 107 | { | ||
| 108 |
1/4✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 6 times.
✗ Branch 2 → 5 not taken.
✗ Branch 2 → 13 not taken.
|
6 | switch(cachehints) |
| 109 | { | ||
| 110 | ✗ | case CACHE_DONT_CACHE_ME: | |
| 111 | ✗ | return 1; | |
| 112 | 6 | case CACHE_GET_MTMODE: | |
| 113 | 6 | return MT_NICE_FILTER; | |
| 114 | |||
| 115 | ✗ | case CACHE_GET_DEV_TYPE: | |
| 116 | ✗ | return (child->GetVersion() >= 5) ? child->SetCacheHints(CACHE_GET_DEV_TYPE, 0) : 0; | |
| 117 | |||
| 118 | ✗ | default: | |
| 119 | ✗ | return GenericVideoFilter::SetCacheHints(cachehints, frame_range); | |
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | |||
| 124 | /****************************** | ||
| 125 | ******* AudioTrim Filter ****** | ||
| 126 | ******************************/ | ||
| 127 | |||
| 128 | 1 | Trim::Trim(double starttime, double endtime, PClip _child, trim_mode_e mode, bool _cache, IScriptEnvironment* env) | |
| 129 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 39 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 37 not taken.
|
1 | : GenericVideoFilter(_child), cache(_cache) |
| 130 | { | ||
| 131 | 1 | int64_t esampleno = 0; | |
| 132 | |||
| 133 |
2/4✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 40 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 1 time.
|
1 | if (!vi.HasAudio()) |
| 134 | ✗ | env->ThrowError("AudioTrim: Cannot trim if there is no audio."); | |
| 135 | |||
| 136 | 1 | audio_offset = clamp(int64_t(starttime*vi.audio_samples_per_second + 0.5), (int64_t)0ll, vi.num_audio_samples); | |
| 137 | |||
| 138 |
1/4✗ Branch 9 → 10 not taken.
✓ Branch 9 → 16 taken 1 time.
✗ Branch 9 → 19 not taken.
✗ Branch 9 → 22 not taken.
|
1 | switch (mode) { |
| 139 | ✗ | case Default: | |
| 140 | ✗ | if (endtime == 0.0) | |
| 141 | ✗ | esampleno = vi.num_audio_samples; | |
| 142 | ✗ | else if (endtime < 0.0) | |
| 143 | ✗ | esampleno = int64_t((starttime-endtime)*vi.audio_samples_per_second + 0.5); | |
| 144 | else | ||
| 145 | ✗ | esampleno = int64_t(endtime*vi.audio_samples_per_second + 0.5); | |
| 146 | |||
| 147 | ✗ | break; | |
| 148 | 1 | case Length: | |
| 149 |
1/2✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1 time.
|
1 | if (endtime < 0.0) |
| 150 | ✗ | env->ThrowError("AudioTrim: Length must be >= 0"); | |
| 151 | |||
| 152 | 1 | esampleno = int64_t((starttime+endtime)*vi.audio_samples_per_second + 0.5); | |
| 153 | |||
| 154 | 1 | break; | |
| 155 | ✗ | case End: | |
| 156 | ✗ | if (endtime < starttime) | |
| 157 | ✗ | env->ThrowError("AudioTrim: End must be >= Start"); | |
| 158 | |||
| 159 | ✗ | esampleno = int64_t(endtime*vi.audio_samples_per_second + 0.5); | |
| 160 | |||
| 161 | ✗ | break; | |
| 162 | ✗ | default: | |
| 163 | ✗ | env->ThrowError("Script error: Invalid arguments to function \"AudioTrim\""); | |
| 164 | } | ||
| 165 | |||
| 166 |
1/2✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 1 time.
|
1 | if (esampleno > vi.num_audio_samples) |
| 167 | ✗ | esampleno = vi.num_audio_samples; | |
| 168 | |||
| 169 | 1 | vi.num_audio_samples = esampleno - audio_offset; | |
| 170 | |||
| 171 |
1/2✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 1 time.
|
1 | if (vi.num_audio_samples < 0) |
| 172 | ✗ | vi.num_audio_samples = 0; | |
| 173 | |||
| 174 |
1/2✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 40 not taken.
|
1 | firstframe= vi.FramesFromAudioSamples(audio_offset); // Floor |
| 175 | |||
| 176 |
1/4✗ Branch 28 → 29 not taken.
✓ Branch 28 → 31 taken 1 time.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
|
1 | if (endtime == 0.0 && mode == Default) |
| 177 | ✗ | vi.num_frames -= firstframe; | |
| 178 | else | ||
| 179 |
2/4✓ Branch 31 → 32 taken 1 time.
✗ Branch 31 → 40 not taken.
✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 40 not taken.
|
1 | vi.num_frames = vi.FramesFromAudioSamples(vi.num_audio_samples + vi.AudioSamplesFromFrames(1) - 1); // Ceil |
| 180 | |||
| 181 |
1/2✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 1 time.
|
1 | if (vi.num_frames < 0) |
| 182 | ✗ | vi.num_frames = 0; | |
| 183 | |||
| 184 | 1 | } | |
| 185 | |||
| 186 | |||
| 187 | ✗ | AVSValue __cdecl Trim::CreateA(AVSValue args, void* user_arg, IScriptEnvironment* env) | |
| 188 | { | ||
| 189 | ✗ | trim_mode_e mode = (trim_mode_e)size_t(user_arg); | |
| 190 | ✗ | if (mode == Trim::Invalid) | |
| 191 | ✗ | env->ThrowError("Script error: Invalid arguments to function \"AudioTrim\""); | |
| 192 | |||
| 193 | ✗ | const bool cache = args[3].AsBool(true); | |
| 194 | |||
| 195 | ✗ | return new Trim(args[1].AsFloat(), args[2].AsFloat(), args[0].AsClip(), mode, cache, env); | |
| 196 | } | ||
| 197 | |||
| 198 | |||
| 199 | /****************************** | ||
| 200 | ******* Trim Filter ****** | ||
| 201 | ******************************/ | ||
| 202 | |||
| 203 | ✗ | Trim::Trim(int _firstframe, int _lastframe, bool _padaudio, PClip _child, trim_mode_e mode, bool _cache, IScriptEnvironment* env) | |
| 204 | ✗ | : GenericVideoFilter(_child), cache(_cache) | |
| 205 | { | ||
| 206 | ✗ | int lastframe = 0; | |
| 207 | |||
| 208 | ✗ | if (!vi.HasVideo()) | |
| 209 | ✗ | env->ThrowError("Trim: Cannot trim if there is no video."); | |
| 210 | |||
| 211 | ✗ | firstframe = clamp(_firstframe, 0, vi.num_frames-1); | |
| 212 | |||
| 213 | ✗ | switch (mode) { | |
| 214 | ✗ | case Default: | |
| 215 | ✗ | if (_lastframe == 0) | |
| 216 | ✗ | lastframe = vi.num_frames-1; | |
| 217 | ✗ | else if (_lastframe < 0) | |
| 218 | ✗ | lastframe = firstframe - _lastframe - 1; | |
| 219 | else | ||
| 220 | ✗ | lastframe = _lastframe; | |
| 221 | |||
| 222 | ✗ | lastframe = clamp(lastframe, firstframe, vi.num_frames-1); | |
| 223 | |||
| 224 | ✗ | break; | |
| 225 | |||
| 226 | ✗ | case Length: | |
| 227 | ✗ | if (_lastframe < 0) | |
| 228 | ✗ | env->ThrowError("Trim: Length must be >= 0"); | |
| 229 | |||
| 230 | ✗ | lastframe = firstframe + _lastframe - 1; | |
| 231 | |||
| 232 | ✗ | if (lastframe > vi.num_frames-1) | |
| 233 | ✗ | lastframe = vi.num_frames-1; | |
| 234 | |||
| 235 | ✗ | break; | |
| 236 | |||
| 237 | ✗ | case End: | |
| 238 | ✗ | if (_lastframe < firstframe) | |
| 239 | ✗ | env->ThrowError("Trim: End must be >= Start"); | |
| 240 | |||
| 241 | ✗ | lastframe = _lastframe; | |
| 242 | |||
| 243 | ✗ | if (lastframe > vi.num_frames-1) | |
| 244 | ✗ | lastframe = vi.num_frames-1; | |
| 245 | |||
| 246 | ✗ | break; | |
| 247 | |||
| 248 | ✗ | default: | |
| 249 | ✗ | env->ThrowError("Script error: Invalid arguments to function \"Trim\""); | |
| 250 | } | ||
| 251 | |||
| 252 | ✗ | vi.num_frames = lastframe+1 - firstframe; | |
| 253 | |||
| 254 | ✗ | audio_offset = vi.AudioSamplesFromFrames(firstframe); | |
| 255 | ✗ | if (_padaudio) | |
| 256 | ✗ | vi.num_audio_samples = vi.AudioSamplesFromFrames(lastframe+1) - audio_offset; | |
| 257 | else { | ||
| 258 | int64_t samples; | ||
| 259 | |||
| 260 | ✗ | if (_lastframe == 0 && mode == Default) | |
| 261 | ✗ | samples = vi.num_audio_samples; | |
| 262 | else { | ||
| 263 | ✗ | samples = vi.AudioSamplesFromFrames(lastframe+1); | |
| 264 | ✗ | if (samples > vi.num_audio_samples) | |
| 265 | ✗ | samples = vi.num_audio_samples; | |
| 266 | } | ||
| 267 | ✗ | if (audio_offset >= samples) | |
| 268 | ✗ | vi.num_audio_samples = 0; | |
| 269 | else | ||
| 270 | ✗ | vi.num_audio_samples = samples - audio_offset; | |
| 271 | } | ||
| 272 | ✗ | } | |
| 273 | |||
| 274 | |||
| 275 | ✗ | PVideoFrame Trim::GetFrame(int n, IScriptEnvironment* env) | |
| 276 | { | ||
| 277 | ✗ | return child->GetFrame(n+firstframe, env); | |
| 278 | } | ||
| 279 | |||
| 280 | |||
| 281 | 1 | void __stdcall Trim::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) | |
| 282 | { | ||
| 283 | 1 | child->GetAudio(buf, start+audio_offset, count, env); | |
| 284 | 1 | } | |
| 285 | |||
| 286 | |||
| 287 | ✗ | bool Trim::GetParity(int n) | |
| 288 | { | ||
| 289 | ✗ | return child->GetParity(n+firstframe); | |
| 290 | } | ||
| 291 | |||
| 292 | |||
| 293 | ✗ | AVSValue __cdecl Trim::Create(AVSValue args, void* user_arg, IScriptEnvironment* env) | |
| 294 | { | ||
| 295 | ✗ | trim_mode_e mode = (trim_mode_e)size_t(user_arg); | |
| 296 | |||
| 297 | ✗ | if (mode == Trim::Invalid) | |
| 298 | ✗ | env->ThrowError("Script error: Invalid arguments to function \"Trim\""); | |
| 299 | |||
| 300 | ✗ | const bool cache = args[4].AsBool(true); | |
| 301 | |||
| 302 | ✗ | return new Trim(args[1].AsInt(), args[2].AsInt(), args[3].AsBool(true), args[0].AsClip(), mode, cache, env); | |
| 303 | } | ||
| 304 | |||
| 305 | |||
| 306 | |||
| 307 | |||
| 308 | |||
| 309 | |||
| 310 | |||
| 311 | |||
| 312 | /******************************* | ||
| 313 | ******* Freeze Frame ****** | ||
| 314 | *******************************/ | ||
| 315 | |||
| 316 | 2 | FreezeFrame::FreezeFrame(int _first, int _last, int _source, PClip _child) | |
| 317 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 6 not taken.
|
2 | : GenericVideoFilter(_child), first(_first), last(_last), source(_source) {} |
| 318 | |||
| 319 | |||
| 320 | ✗ | PVideoFrame FreezeFrame::GetFrame(int n, IScriptEnvironment* env) | |
| 321 | { | ||
| 322 | ✗ | return child->GetFrame((n >= first && n <= last) ? source : n, env); | |
| 323 | } | ||
| 324 | |||
| 325 | |||
| 326 | ✗ | bool FreezeFrame::GetParity(int n) | |
| 327 | { | ||
| 328 | ✗ | return child->GetParity((n >= first && n <= last) ? source : n); | |
| 329 | } | ||
| 330 | |||
| 331 | |||
| 332 | 2 | AVSValue __cdecl FreezeFrame::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 333 | { | ||
| 334 | AVS_UNUSED(env); | ||
| 335 |
11/24✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 21 not taken.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 21 not taken.
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 19 not taken.
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 19 not taken.
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 19 not taken.
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 19 not taken.
✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 19 not taken.
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 19 not taken.
✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 19 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 2 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
|
6 | return new FreezeFrame(args[1].AsInt(), args[2].AsInt(), args[3].AsInt(), args[0].AsClip()); |
| 336 | } | ||
| 337 | |||
| 338 | |||
| 339 | /****************************** | ||
| 340 | ******* Delete Frame ****** | ||
| 341 | ******************************/ | ||
| 342 | |||
| 343 | 3 | DeleteFrame::DeleteFrame(int _frame, PClip _child) | |
| 344 |
2/4✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 6 not taken.
|
3 | : GenericVideoFilter(_child), frame(_frame) { --vi.num_frames; } |
| 345 | |||
| 346 | |||
| 347 | ✗ | PVideoFrame DeleteFrame::GetFrame(int n, IScriptEnvironment* env) | |
| 348 | { | ||
| 349 | ✗ | return child->GetFrame(n + (n>=frame), env); | |
| 350 | } | ||
| 351 | |||
| 352 | |||
| 353 | ✗ | bool DeleteFrame::GetParity(int n) | |
| 354 | { | ||
| 355 | ✗ | return child->GetParity(n + (n>=frame)); | |
| 356 | } | ||
| 357 | |||
| 358 | |||
| 359 | 3 | AVSValue __cdecl DeleteFrame::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 360 | { | ||
| 361 | AVS_UNUSED(env); | ||
| 362 |
2/4✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 51 not taken.
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 51 not taken.
|
3 | const int n = args[1].ArraySize(); |
| 363 | 3 | int m = n-1; | |
| 364 |
2/4✓ Branch 4 → 5 taken 3 times.
✗ Branch 4 → 6 not taken.
✓ Branch 7 → 8 taken 3 times.
✗ Branch 7 → 51 not taken.
|
3 | int *frames = new int[n]; |
| 365 | |||
| 366 |
3/6✓ Branch 8 → 9 taken 3 times.
✗ Branch 8 → 51 not taken.
✓ Branch 9 → 10 taken 3 times.
✗ Branch 9 → 51 not taken.
✓ Branch 10 → 11 taken 3 times.
✗ Branch 10 → 51 not taken.
|
3 | frames[0] = args[1][0].AsInt(); |
| 367 |
1/2✗ Branch 23 → 12 not taken.
✓ Branch 23 → 24 taken 3 times.
|
3 | for (int i=1; i<n; ++i) { |
| 368 | ✗ | frames[i] = args[1][i].AsInt(); | |
| 369 | // Bubble insert | ||
| 370 | ✗ | for (int j=0; j<i; ++j) { | |
| 371 | // Remove duplicates | ||
| 372 | ✗ | if (frames[i] == frames[j]) { | |
| 373 | ✗ | m -= 1; | |
| 374 | ✗ | frames[i] = INT_MAX; | |
| 375 | ✗ | break; | |
| 376 | } | ||
| 377 | ✗ | else if (frames[i] < frames[j]) { | |
| 378 | ✗ | const int t = frames[j]; | |
| 379 | ✗ | frames[j] = frames[i]; | |
| 380 | ✗ | frames[i] = t; | |
| 381 | } | ||
| 382 | } | ||
| 383 | } | ||
| 384 |
2/4✓ Branch 24 → 25 taken 3 times.
✗ Branch 24 → 51 not taken.
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 51 not taken.
|
3 | PClip result = args[0].AsClip(); |
| 385 |
2/2✓ Branch 35 → 27 taken 3 times.
✓ Branch 35 → 36 taken 3 times.
|
6 | for (int k=m; k>=0; --k) |
| 386 |
5/12✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 49 not taken.
✓ Branch 28 → 29 taken 3 times.
✗ Branch 28 → 45 not taken.
✓ Branch 29 → 30 taken 3 times.
✗ Branch 29 → 43 not taken.
✓ Branch 30 → 31 taken 3 times.
✗ Branch 30 → 43 not taken.
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 34 taken 3 times.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
|
3 | result = new DeleteFrame(frames[k], result); |
| 387 | |||
| 388 |
1/2✓ Branch 36 → 37 taken 3 times.
✗ Branch 36 → 38 not taken.
|
3 | delete[] frames; |
| 389 |
1/2✓ Branch 38 → 39 taken 3 times.
✗ Branch 38 → 49 not taken.
|
6 | return result; |
| 390 | 3 | } | |
| 391 | |||
| 392 | |||
| 393 | |||
| 394 | /********************************* | ||
| 395 | ******* Duplicate Frame ****** | ||
| 396 | *********************************/ | ||
| 397 | |||
| 398 | 2 | DuplicateFrame::DuplicateFrame(int _frame, PClip _child) | |
| 399 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 6 not taken.
|
2 | : GenericVideoFilter(_child), frame(_frame) { ++vi.num_frames; } |
| 400 | |||
| 401 | |||
| 402 | ✗ | PVideoFrame DuplicateFrame::GetFrame(int n, IScriptEnvironment* env) | |
| 403 | { | ||
| 404 | ✗ | return child->GetFrame(n - (n>frame), env); | |
| 405 | } | ||
| 406 | |||
| 407 | |||
| 408 | ✗ | bool DuplicateFrame::GetParity(int n) | |
| 409 | { | ||
| 410 | ✗ | return child->GetParity(n - (n>frame)); | |
| 411 | } | ||
| 412 | |||
| 413 | |||
| 414 | 2 | AVSValue __cdecl DuplicateFrame::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 415 | { | ||
| 416 | AVS_UNUSED(env); | ||
| 417 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 49 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 49 not taken.
|
2 | const int n = args[1].ArraySize(); |
| 418 |
2/4✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 6 not taken.
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 49 not taken.
|
2 | int *frames = new int[n]; |
| 419 | |||
| 420 |
3/6✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 49 not taken.
✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 49 not taken.
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 49 not taken.
|
2 | frames[0] = args[1][0].AsInt(); |
| 421 |
1/2✗ Branch 21 → 12 not taken.
✓ Branch 21 → 22 taken 2 times.
|
2 | for (int i=1; i<n; ++i) { |
| 422 | ✗ | frames[i] = args[1][i].AsInt(); | |
| 423 | // Bubble insert | ||
| 424 | ✗ | for (int j=0; j<i; ++j) { | |
| 425 | ✗ | if (frames[i] < frames[j]) { | |
| 426 | ✗ | const int t = frames[j]; | |
| 427 | ✗ | frames[j] = frames[i]; | |
| 428 | ✗ | frames[i] = t; | |
| 429 | } | ||
| 430 | } | ||
| 431 | } | ||
| 432 |
2/4✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 49 not taken.
✓ Branch 23 → 24 taken 2 times.
✗ Branch 23 → 49 not taken.
|
2 | PClip result = args[0].AsClip(); |
| 433 |
2/2✓ Branch 33 → 25 taken 2 times.
✓ Branch 33 → 34 taken 2 times.
|
4 | for (int k=n-1; k>=0; --k) |
| 434 |
5/12✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 47 not taken.
✓ Branch 26 → 27 taken 2 times.
✗ Branch 26 → 43 not taken.
✓ Branch 27 → 28 taken 2 times.
✗ Branch 27 → 41 not taken.
✓ Branch 28 → 29 taken 2 times.
✗ Branch 28 → 41 not taken.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 2 times.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 46 not taken.
|
2 | result = new DuplicateFrame(frames[k], result); |
| 435 | |||
| 436 |
1/2✓ Branch 34 → 35 taken 2 times.
✗ Branch 34 → 36 not taken.
|
2 | delete[] frames; |
| 437 |
1/2✓ Branch 36 → 37 taken 2 times.
✗ Branch 36 → 47 not taken.
|
4 | return result; |
| 438 | 2 | } | |
| 439 | |||
| 440 | |||
| 441 | |||
| 442 | /******************************* | ||
| 443 | ******* Splice Filter ****** | ||
| 444 | *******************************/ | ||
| 445 | |||
| 446 | 1 | Splice::Splice(PClip _child1, PClip _child2, bool realign_sound, bool _passCache, IScriptEnvironment* env) | |
| 447 |
3/6✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 66 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 64 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 82 not taken.
|
1 | : GenericVideoFilter(_child1), child2(_child2), passCache(_passCache) |
| 448 | { | ||
| 449 |
1/2✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 79 not taken.
|
1 | VideoInfo vi2 = child2->GetVideoInfo(); |
| 450 | |||
| 451 |
3/6✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 79 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 79 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1 time.
|
1 | if (vi.HasVideo() ^ vi2.HasVideo()) |
| 452 | ✗ | env->ThrowError("Splice: one clip has video and the other doesn't (not allowed)"); | |
| 453 |
3/6✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 79 not taken.
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 79 not taken.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 1 time.
|
1 | if (vi.HasAudio() ^ vi2.HasAudio()) |
| 454 | ✗ | env->ThrowError("Splice: one clip has audio and the other doesn't (not allowed)"); | |
| 455 | |||
| 456 | |||
| 457 | // Check video | ||
| 458 |
2/4✓ Branch 16 → 17 taken 1 time.
✗ Branch 16 → 79 not taken.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 26 taken 1 time.
|
1 | if (vi.HasVideo()) { |
| 459 | ✗ | if (vi.width != vi2.width || vi.height != vi2.height) | |
| 460 | ✗ | env->ThrowError("Splice: Frame sizes don't match"); | |
| 461 | |||
| 462 | ✗ | if (!vi.IsSameColorspace(vi2)) | |
| 463 | ✗ | env->ThrowError("Splice: Video formats don't match"); | |
| 464 | |||
| 465 | ✗ | double fps_v1 = (double)vi.fps_numerator / (double)vi.fps_denominator; | |
| 466 | ✗ | double fps_v2 = (double)vi2.fps_numerator / (double)vi2.fps_denominator; | |
| 467 | ✗ | if (fabs(fps_v1-fps_v2) > 0.000001) | |
| 468 | ✗ | env->ThrowError("Splice: Video framerate doesn't match"); | |
| 469 | } | ||
| 470 | |||
| 471 | // Check Audio | ||
| 472 |
2/4✓ Branch 26 → 27 taken 1 time.
✗ Branch 26 → 79 not taken.
✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 53 not taken.
|
1 | if (vi.HasAudio()) { |
| 473 | // If sample types do not match they are both converted to float samples to avoid loss of precision. | ||
| 474 |
4/8✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 72 not taken.
✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 71 not taken.
✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 69 not taken.
✓ Branch 31 → 32 taken 1 time.
✗ Branch 31 → 67 not taken.
|
1 | child2 = ConvertAudio::Create(child2, vi.SampleType(), SAMPLE_FLOAT); // Clip 1 is check to be same type as clip 1, if not, convert to float samples. |
| 475 |
1/2✓ Branch 35 → 36 taken 1 time.
✗ Branch 35 → 79 not taken.
|
1 | vi2 = child2->GetVideoInfo(); |
| 476 | |||
| 477 |
5/10✓ Branch 36 → 37 taken 1 time.
✗ Branch 36 → 78 not taken.
✓ Branch 37 → 38 taken 1 time.
✗ Branch 37 → 78 not taken.
✓ Branch 38 → 39 taken 1 time.
✗ Branch 38 → 77 not taken.
✓ Branch 39 → 40 taken 1 time.
✗ Branch 39 → 75 not taken.
✓ Branch 40 → 41 taken 1 time.
✗ Branch 40 → 73 not taken.
|
1 | child = ConvertAudio::Create(child, vi2.SampleType(), vi2.SampleType()); // Clip 1 is now be same type as clip 2. |
| 478 |
1/2✓ Branch 44 → 45 taken 1 time.
✗ Branch 44 → 79 not taken.
|
1 | vi = child->GetVideoInfo(); |
| 479 | |||
| 480 |
3/6✓ Branch 45 → 46 taken 1 time.
✗ Branch 45 → 79 not taken.
✓ Branch 46 → 47 taken 1 time.
✗ Branch 46 → 79 not taken.
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 49 taken 1 time.
|
1 | if (vi.AudioChannels() != vi2.AudioChannels()) |
| 481 | ✗ | env->ThrowError("Splice: The number of audio channels doesn't match"); | |
| 482 | |||
| 483 |
3/6✓ Branch 49 → 50 taken 1 time.
✗ Branch 49 → 79 not taken.
✓ Branch 50 → 51 taken 1 time.
✗ Branch 50 → 79 not taken.
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 53 taken 1 time.
|
1 | if (vi.SamplesPerSecond() != vi2.SamplesPerSecond()) |
| 484 | ✗ | env->ThrowError("Splice: The audio of the two clips have different samplerates! Use SSRC()/ResampleAudio()"); | |
| 485 | } | ||
| 486 | |||
| 487 | 1 | video_switchover_point = vi.num_frames; | |
| 488 | |||
| 489 |
1/2✓ Branch 53 → 54 taken 1 time.
✗ Branch 53 → 55 not taken.
|
1 | if (!video_switchover_point) // We don't have video, so we cannot align sound to frames |
| 490 | 1 | realign_sound = false; | |
| 491 | |||
| 492 |
1/2✗ Branch 55 → 56 not taken.
✓ Branch 55 → 58 taken 1 time.
|
1 | if (realign_sound) |
| 493 | ✗ | audio_switchover_point = vi.AudioSamplesFromFrames(video_switchover_point); | |
| 494 | else | ||
| 495 | 1 | audio_switchover_point = vi.num_audio_samples; | |
| 496 | |||
| 497 | 1 | vi.num_frames += vi2.num_frames; | |
| 498 | |||
| 499 |
1/2✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 1 time.
|
1 | if (vi.num_frames < 0) |
| 500 | ✗ | env->ThrowError("Splice: Maximum number of frames exceeded."); | |
| 501 | |||
| 502 | 1 | vi.num_audio_samples = audio_switchover_point + vi2.num_audio_samples; | |
| 503 | |||
| 504 |
2/4✓ Branch 61 → 62 taken 1 time.
✗ Branch 61 → 79 not taken.
✓ Branch 62 → 63 taken 1 time.
✗ Branch 62 → 79 not taken.
|
1 | child_devs = (GetDeviceTypes(child) & GetDeviceTypes(child2)); |
| 505 | 1 | } | |
| 506 | |||
| 507 | |||
| 508 | ✗ | PVideoFrame Splice::GetFrame(int n, IScriptEnvironment* env) | |
| 509 | { | ||
| 510 | ✗ | if (n < video_switchover_point) | |
| 511 | ✗ | return child->GetFrame(n, env); | |
| 512 | else | ||
| 513 | ✗ | return child2->GetFrame(n - video_switchover_point, env); | |
| 514 | } | ||
| 515 | |||
| 516 | |||
| 517 | 1 | void Splice::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) | |
| 518 | { | ||
| 519 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 1 time.
|
1 | if (start+count <= audio_switchover_point) |
| 520 | ✗ | child->GetAudio(buf, start, count, env); | |
| 521 |
1/2✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 1 time.
|
1 | else if (start >= audio_switchover_point) |
| 522 | ✗ | child2->GetAudio(buf, start - audio_switchover_point, count, env); | |
| 523 | else { | ||
| 524 | 1 | const int64_t count1 = audio_switchover_point - start; | |
| 525 | 1 | child->GetAudio(buf, start, count1, env); | |
| 526 | 1 | child2->GetAudio((char*)buf+vi.BytesFromAudioSamples(count1), 0, count-count1, env); | |
| 527 | } | ||
| 528 | 1 | } | |
| 529 | |||
| 530 | |||
| 531 | ✗ | bool Splice::GetParity(int n) | |
| 532 | { | ||
| 533 | ✗ | if (n < video_switchover_point) | |
| 534 | ✗ | return child->GetParity(n); | |
| 535 | else | ||
| 536 | ✗ | return child2->GetParity(n - video_switchover_point); | |
| 537 | } | ||
| 538 | |||
| 539 | |||
| 540 | 1 | int Splice::SetCacheHints(int cachehints,int frame_range) | |
| 541 | { | ||
| 542 |
1/4✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
✗ Branch 2 → 5 not taken.
✗ Branch 2 → 6 not taken.
|
1 | switch(cachehints) |
| 543 | { | ||
| 544 | ✗ | case CACHE_DONT_CACHE_ME: | |
| 545 | ✗ | return 1; | |
| 546 | 1 | case CACHE_GET_MTMODE: | |
| 547 | 1 | return MT_NICE_FILTER; | |
| 548 | ✗ | case CACHE_GET_DEV_TYPE: | |
| 549 | ✗ | return child_devs; | |
| 550 | ✗ | default: | |
| 551 | ✗ | if (passCache) { | |
| 552 | ✗ | child2->SetCacheHints(cachehints, frame_range); | |
| 553 | ✗ | return child->SetCacheHints(cachehints, frame_range); | |
| 554 | } | ||
| 555 | ✗ | break; | |
| 556 | } | ||
| 557 | ✗ | return 0; // We do not pass cache requests upwards. | |
| 558 | } | ||
| 559 | |||
| 560 | |||
| 561 | ✗ | AVSValue __cdecl Splice::CreateUnaligned(AVSValue args, void*, IScriptEnvironment* env) | |
| 562 | { | ||
| 563 | ✗ | PClip result = args[0].AsClip(); | |
| 564 | ✗ | for (int i=0; i<args[1].ArraySize(); ++i) | |
| 565 | ✗ | result = new Splice(result, args[1][i].AsClip(), false, false, env); | |
| 566 | ✗ | return result; | |
| 567 | ✗ | } | |
| 568 | |||
| 569 | |||
| 570 | |||
| 571 | ✗ | AVSValue __cdecl Splice::CreateAligned(AVSValue args, void*, IScriptEnvironment* env) | |
| 572 | { | ||
| 573 | ✗ | PClip result = args[0].AsClip(); | |
| 574 | ✗ | for (int i=0; i<args[1].ArraySize(); ++i) | |
| 575 | ✗ | result = new Splice(result, args[1][i].AsClip(), true, false, env); | |
| 576 | ✗ | return result; | |
| 577 | ✗ | } | |
| 578 | |||
| 579 | |||
| 580 | |||
| 581 | ✗ | AVSValue __cdecl Splice::CreateUnalignedNoCache(AVSValue args, void*, IScriptEnvironment* env) | |
| 582 | { | ||
| 583 | ✗ | return new Splice(args[0].AsClip(), args[1].AsClip(), false, true, env); | |
| 584 | } | ||
| 585 | |||
| 586 | ✗ | AVSValue __cdecl Splice::CreateAlignedNoCache(AVSValue args, void*, IScriptEnvironment* env) | |
| 587 | { | ||
| 588 | ✗ | return new Splice(args[0].AsClip(), args[1].AsClip(), true, true, env); | |
| 589 | } | ||
| 590 | |||
| 591 | |||
| 592 | |||
| 593 | |||
| 594 | |||
| 595 | |||
| 596 | |||
| 597 | |||
| 598 | |||
| 599 | /********************************* | ||
| 600 | ******* Dissolve Filter ****** | ||
| 601 | *********************************/ | ||
| 602 | |||
| 603 | |||
| 604 | ✗ | AVSValue __cdecl Dissolve::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 605 | { | ||
| 606 | ✗ | const int overlap = args[2].AsInt(); | |
| 607 | ✗ | const double fps = args[3].AsDblDef(24.0); | |
| 608 | ✗ | PClip result = args[0].AsClip(); | |
| 609 | ✗ | for (int i=0; i < args[1].ArraySize(); ++i) | |
| 610 | ✗ | result = new Dissolve(result, args[1][i].AsClip(), overlap, fps, env); | |
| 611 | ✗ | return result; | |
| 612 | ✗ | } | |
| 613 | |||
| 614 | |||
| 615 | 1 | Dissolve::~Dissolve() | |
| 616 | { | ||
| 617 |
1/2✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
|
1 | delete[] audbuffer; |
| 618 | 1 | audbuffer = 0; | |
| 619 | 1 | audbufsize = 0; | |
| 620 | 1 | } | |
| 621 | |||
| 622 | 1 | Dissolve::Dissolve(PClip _child1, PClip _child2, int _overlap, double fps, IScriptEnvironment* env) | |
| 623 |
1/2✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 71 not taken.
|
2 | : GenericVideoFilter(ConvertAudio::Create(_child1,SAMPLE_INT16|SAMPLE_FLOAT,SAMPLE_FLOAT)), |
| 624 | 1 | child2(_child2), | |
| 625 | 1 | overlap(_overlap), | |
| 626 | 1 | audbuffer(0), | |
| 627 |
3/6✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 73 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 69 not taken.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 90 not taken.
|
3 | audbufsize(0) |
| 628 | { | ||
| 629 |
1/2✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 87 not taken.
|
1 | VideoInfo vi2 = child2->GetVideoInfo(); |
| 630 | |||
| 631 |
3/6✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 87 not taken.
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 87 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 1 time.
|
1 | if (vi.HasVideo() ^ vi2.HasVideo()) |
| 632 | ✗ | env->ThrowError("Dissolve: one clip has video and the other doesn't (not allowed)"); | |
| 633 |
3/6✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 87 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 87 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1 time.
|
1 | if (vi.HasAudio() ^ vi2.HasAudio()) |
| 634 | ✗ | env->ThrowError("Dissolve: one clip has audio and the other doesn't (not allowed)"); | |
| 635 | |||
| 636 |
1/2✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 1 time.
|
1 | if (overlap<0) |
| 637 | ✗ | env->ThrowError("Dissolve: Cannot dissolve if overlap is less than zero"); | |
| 638 | |||
| 639 |
2/4✓ Branch 20 → 21 taken 1 time.
✗ Branch 20 → 87 not taken.
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 47 not taken.
|
1 | if (vi.HasAudio()) { |
| 640 |
4/8✓ Branch 22 → 23 taken 1 time.
✗ Branch 22 → 80 not taken.
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 79 not taken.
✓ Branch 24 → 25 taken 1 time.
✗ Branch 24 → 77 not taken.
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 75 not taken.
|
1 | child2 = ConvertAudio::Create(child2, vi.SampleType(), SAMPLE_FLOAT); // Clip 1 is check to be same type as clip 1, if not, convert to float samples. |
| 641 |
1/2✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 87 not taken.
|
1 | vi2 = child2->GetVideoInfo(); |
| 642 | |||
| 643 |
5/10✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 86 not taken.
✓ Branch 31 → 32 taken 1 time.
✗ Branch 31 → 86 not taken.
✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 85 not taken.
✓ Branch 33 → 34 taken 1 time.
✗ Branch 33 → 83 not taken.
✓ Branch 34 → 35 taken 1 time.
✗ Branch 34 → 81 not taken.
|
1 | child = ConvertAudio::Create(child, vi2.SampleType(), vi2.SampleType()); // Clip 1 is now be same type as clip 2. |
| 644 |
1/2✓ Branch 38 → 39 taken 1 time.
✗ Branch 38 → 87 not taken.
|
1 | vi = child->GetVideoInfo(); |
| 645 | |||
| 646 |
3/6✓ Branch 39 → 40 taken 1 time.
✗ Branch 39 → 87 not taken.
✓ Branch 40 → 41 taken 1 time.
✗ Branch 40 → 87 not taken.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 1 time.
|
1 | if (vi.AudioChannels() != vi2.AudioChannels()) |
| 647 | ✗ | env->ThrowError("Dissolve: The number of audio channels doesn't match"); | |
| 648 | |||
| 649 |
3/6✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 87 not taken.
✓ Branch 44 → 45 taken 1 time.
✗ Branch 44 → 87 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 1 time.
|
1 | if (vi.SamplesPerSecond() != vi2.SamplesPerSecond()) |
| 650 | ✗ | env->ThrowError("Dissolve: The audio of the two clips have different samplerates! Use SSRC()/ResampleAudio()"); | |
| 651 | } | ||
| 652 | |||
| 653 |
2/4✓ Branch 47 → 48 taken 1 time.
✗ Branch 47 → 87 not taken.
✗ Branch 48 → 49 not taken.
✓ Branch 48 → 60 taken 1 time.
|
1 | if (vi.HasVideo()) { |
| 654 | ✗ | if (vi.width != vi2.width || vi.height != vi2.height) | |
| 655 | ✗ | env->ThrowError("Dissolve: frame sizes don't match"); | |
| 656 | ✗ | if (!(vi.IsSameColorspace(vi2))) | |
| 657 | ✗ | env->ThrowError("Dissolve: video formats don't match"); | |
| 658 | |||
| 659 | ✗ | pixelsize = vi.ComponentSize(); // AVS16 | |
| 660 | ✗ | bits_per_pixel = vi.BitsPerComponent(); | |
| 661 | |||
| 662 | ✗ | video_fade_start = vi.num_frames - overlap; | |
| 663 | ✗ | video_fade_end = vi.num_frames - 1; | |
| 664 | |||
| 665 | ✗ | audio_fade_start = vi.AudioSamplesFromFrames(video_fade_start); | |
| 666 | ✗ | audio_fade_end = vi.AudioSamplesFromFrames(video_fade_end+1)-1; | |
| 667 | } | ||
| 668 | else { | ||
| 669 | 1 | video_fade_start = 0; | |
| 670 | 1 | video_fade_end = 0; | |
| 671 | |||
| 672 |
1/2✓ Branch 60 → 61 taken 1 time.
✗ Branch 60 → 87 not taken.
|
1 | audio_fade_start = vi.num_audio_samples - int64_t(Int32x32To64(vi.SamplesPerSecond(), overlap)/fps+0.5); |
| 673 | 1 | audio_fade_end = vi.num_audio_samples-1; | |
| 674 | } | ||
| 675 | 1 | audio_overlap = int(audio_fade_end - audio_fade_start); | |
| 676 | |||
| 677 |
1/2✗ Branch 62 → 63 not taken.
✓ Branch 62 → 64 taken 1 time.
|
1 | if (video_fade_start < 0) video_fade_start= 0; |
| 678 |
1/2✗ Branch 64 → 65 not taken.
✓ Branch 64 → 66 taken 1 time.
|
1 | if (audio_fade_start < 0) audio_fade_start= 0; |
| 679 | |||
| 680 | 1 | vi.num_frames = video_fade_start + vi2.num_frames; | |
| 681 | |||
| 682 |
1/2✗ Branch 66 → 67 not taken.
✓ Branch 66 → 68 taken 1 time.
|
1 | if (vi.num_frames < 0) |
| 683 | ✗ | env->ThrowError("Dissolve: Maximum number of frames exceeded."); | |
| 684 | |||
| 685 | 1 | vi.num_audio_samples = audio_fade_start + vi2.num_audio_samples; | |
| 686 | 1 | } | |
| 687 | |||
| 688 | |||
| 689 | ✗ | bool Dissolve::GetParity(int n) | |
| 690 | { | ||
| 691 | ✗ | return (n < video_fade_start) ? child->GetParity(n) : child2->GetParity(n - video_fade_start); | |
| 692 | } | ||
| 693 | |||
| 694 | |||
| 695 | ✗ | PVideoFrame Dissolve::GetFrame(int n, IScriptEnvironment* env) | |
| 696 | { | ||
| 697 | ✗ | if (n < video_fade_start) | |
| 698 | ✗ | return child->GetFrame(n, env); | |
| 699 | ✗ | if (n > video_fade_end) | |
| 700 | ✗ | return child2->GetFrame(n - video_fade_start, env); | |
| 701 | |||
| 702 | ✗ | PVideoFrame a = child->GetFrame(n, env); | |
| 703 | ✗ | PVideoFrame b = child2->GetFrame(n - video_fade_start, env); | |
| 704 | |||
| 705 | ✗ | const double multiplier = n - video_fade_end + overlap; | |
| 706 | ✗ | float weight = (float)(multiplier / (overlap + 1.0)); | |
| 707 | |||
| 708 | ✗ | env->MakeWritable(&a); | |
| 709 | |||
| 710 | ✗ | const int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A }; | |
| 711 | ✗ | const int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A }; | |
| 712 | const int *planes; | ||
| 713 | |||
| 714 | int planeCount; | ||
| 715 | ✗ | planeCount = vi.IsPlanar() ? vi.NumComponents() : 1; | |
| 716 | ✗ | planes = (!vi.IsPlanar() || vi.IsYUV() || vi.IsYUVA()) ? planes_y : planes_r; | |
| 717 | |||
| 718 | ✗ | const int bits_per_pixel = vi.BitsPerComponent(); | |
| 719 | ✗ | for (int j = 0; j < planeCount; ++j) | |
| 720 | { | ||
| 721 | ✗ | const int plane = planes[j]; | |
| 722 | ✗ | const BYTE* b_data = b->GetReadPtr(plane); | |
| 723 | ✗ | int b_pitch = b->GetPitch(plane); | |
| 724 | ✗ | BYTE* a_data = a->GetWritePtr(plane); | |
| 725 | ✗ | int a_pitch = a->GetPitch(plane); | |
| 726 | ✗ | int row_size = a->GetRowSize(plane); | |
| 727 | ✗ | int height = a->GetHeight(plane); | |
| 728 | |||
| 729 | ✗ | const int pixelsize = bits_per_pixel <= 8 ? 1 : (bits_per_pixel == 32 ? 4 : 2); | |
| 730 | ✗ | const int width = row_size / pixelsize; | |
| 731 | ✗ | const int cpuFlags = env->GetCPUFlags(); | |
| 732 | ✗ | if (bits_per_pixel == 32) { | |
| 733 | ✗ | get_weighted_merge_float_fn(cpuFlags)(a_data, b_data, a_pitch, b_pitch, width, height, weight); | |
| 734 | } else { | ||
| 735 | ✗ | const int weight_i = (int)(weight * 32768.0f + 0.5f); | |
| 736 | ✗ | get_weighted_merge_fn(cpuFlags, weight_i)(a_data, b_data, a_pitch, b_pitch, width, height, weight_i, 32768 - weight_i, bits_per_pixel); | |
| 737 | } | ||
| 738 | } | ||
| 739 | ✗ | return a; | |
| 740 | ✗ | } | |
| 741 | |||
| 742 | |||
| 743 | 1 | void Dissolve::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) | |
| 744 | { | ||
| 745 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 1 time.
|
1 | if (start+count <= audio_fade_start) { |
| 746 | ✗ | child->GetAudio(buf, start, count, env); | |
| 747 | ✗ | return; | |
| 748 | } | ||
| 749 | |||
| 750 |
1/2✗ Branch 6 → 7 not taken.
✓ Branch 6 → 10 taken 1 time.
|
1 | if (start > audio_fade_end) { |
| 751 | ✗ | child2->GetAudio(buf, start - audio_fade_start, count, env); | |
| 752 | ✗ | return; | |
| 753 | } | ||
| 754 | |||
| 755 | 1 | const size_t bytes = (size_t)vi.BytesFromAudioSamples(count); | |
| 756 |
1/2✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 16 not taken.
|
1 | if (audbufsize < bytes) { |
| 757 |
1/2✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 1 time.
|
1 | delete[] audbuffer; |
| 758 | 1 | audbuffer = new BYTE[bytes]; | |
| 759 | 1 | audbufsize = bytes; | |
| 760 | } | ||
| 761 | |||
| 762 | 1 | child->GetAudio(buf, start, count, env); | |
| 763 | 1 | child2->GetAudio(audbuffer, start - audio_fade_start, count, env); | |
| 764 | |||
| 765 | 1 | const int nch = vi.AudioChannels(); | |
| 766 | 1 | const int countXnch = (int)count*nch; | |
| 767 | 1 | const int denominator = audio_overlap; | |
| 768 | 1 | int numerator = (int)(audio_fade_end - start); | |
| 769 | |||
| 770 |
1/2✗ Branch 22 → 23 not taken.
✓ Branch 22 → 33 taken 1 time.
|
1 | if (vi.IsSampleType(SAMPLE_INT16)) { |
| 771 | ✗ | short *const a = (short*)buf; | |
| 772 | ✗ | const short *const b = (short*)audbuffer; | |
| 773 | |||
| 774 | int i; | ||
| 775 | ✗ | for (i=0; i<countXnch; i+=nch) { | |
| 776 | ✗ | if (numerator <= 0) { // Past end of dissolve | |
| 777 | ✗ | break; | |
| 778 | } | ||
| 779 | ✗ | else if (numerator < denominator) { // In dissolve region | |
| 780 | ✗ | for (int p=0; p < nch; p++) | |
| 781 | ✗ | a[i+p] = short(b[i+p] + MulDiv(a[i+p]-b[i+p], numerator, denominator)); | |
| 782 | } | ||
| 783 | // else // Before begining of dissolve | ||
| 784 | ✗ | numerator--; | |
| 785 | } | ||
| 786 | ✗ | const int nchb = (countXnch - i) * sizeof(short); | |
| 787 | ✗ | memcpy(a+i, b+i, nchb); | |
| 788 | ✗ | return; | |
| 789 | } | ||
| 790 | |||
| 791 |
1/2✓ Branch 34 → 35 taken 1 time.
✗ Branch 34 → 45 not taken.
|
1 | if (vi.IsSampleType(SAMPLE_FLOAT)) { |
| 792 | 1 | const SFLOAT frdenominator = SFLOAT(1.0/denominator); | |
| 793 | 1 | SFLOAT *const a = (SFLOAT*)buf; | |
| 794 | 1 | const SFLOAT *const b = (SFLOAT*)audbuffer; | |
| 795 | |||
| 796 | int i; | ||
| 797 |
1/2✓ Branch 43 → 36 taken 4 times.
✗ Branch 43 → 44 not taken.
|
4 | for (i=0; i<countXnch; i+=nch) { |
| 798 |
2/2✓ Branch 36 → 37 taken 1 time.
✓ Branch 36 → 38 taken 3 times.
|
4 | if (numerator <= 0) { // Past end of dissolve |
| 799 | 1 | break; | |
| 800 | } | ||
| 801 |
2/2✓ Branch 38 → 39 taken 2 times.
✓ Branch 38 → 42 taken 1 time.
|
3 | else if (numerator < denominator) { // In dissolve region |
| 802 | 2 | const SFLOAT w = numerator * frdenominator; // How far into the fade are we? | |
| 803 |
2/2✓ Branch 41 → 40 taken 2 times.
✓ Branch 41 → 42 taken 2 times.
|
4 | for (int p=0; p < nch; p++) |
| 804 | 2 | a[i+p] = b[i+p] + w * (a[i+p]-b[i+p]); | |
| 805 | } | ||
| 806 | // else // Before begining of dissolve | ||
| 807 | 3 | numerator--; // When was a float only worked for N < 2^24 | |
| 808 | } | ||
| 809 | 1 | const int nchb = (countXnch - i) * sizeof(SFLOAT); | |
| 810 | 1 | memcpy(a+i, b+i, nchb); | |
| 811 | 1 | return; | |
| 812 | } | ||
| 813 | |||
| 814 | ✗ | env->ThrowError("Dissolve: Wow - this should never happend!"); | |
| 815 | |||
| 816 | } | ||
| 817 | |||
| 818 | |||
| 819 | |||
| 820 | |||
| 821 | |||
| 822 | |||
| 823 | |||
| 824 | |||
| 825 | |||
| 826 | /********************************* | ||
| 827 | ******* AudioDub Filter ****** | ||
| 828 | *********************************/ | ||
| 829 | |||
| 830 |
2/4✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 42 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 40 not taken.
|
1 | AudioDub::AudioDub(PClip child1, PClip child2, int mode, IScriptEnvironment* env) |
| 831 | { | ||
| 832 |
1/2✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 38 not taken.
|
1 | const VideoInfo& vi1 = child1->GetVideoInfo(); |
| 833 |
1/2✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 38 not taken.
|
1 | const VideoInfo& vi2 = child2->GetVideoInfo(); |
| 834 | 1 | const VideoInfo *vi_video=0, *vi_audio=0; | |
| 835 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 13 taken 1 time.
|
1 | if (mode) { // Unconditionally accept audio and video |
| 836 | ✗ | vchild = child1; achild = child2; | |
| 837 | ✗ | vi_video = &vi1; vi_audio = &vi2; | |
| 838 | } | ||
| 839 | else { | ||
| 840 |
5/10✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 38 not taken.
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 18 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 38 not taken.
✓ Branch 16 → 17 taken 1 time.
✗ Branch 16 → 18 not taken.
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 23 not taken.
|
1 | if (vi1.HasVideo() && vi2.HasAudio()) { |
| 841 |
2/4✓ Branch 20 → 21 taken 1 time.
✗ Branch 20 → 38 not taken.
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 38 not taken.
|
1 | vchild = child1; achild = child2; |
| 842 | 1 | vi_video = &vi1, vi_audio = &vi2; | |
| 843 | ✗ | } else if (vi2.HasVideo() && vi1.HasAudio()) { | |
| 844 | ✗ | vchild = child2; achild = child1; | |
| 845 | ✗ | vi_video = &vi2, vi_audio = &vi1; | |
| 846 | } else { | ||
| 847 | ✗ | env->ThrowError("AudioDub: need an audio and a video track"); | |
| 848 | } | ||
| 849 | } | ||
| 850 | |||
| 851 | 1 | vi = *vi_video; | |
| 852 | 1 | vi.audio_samples_per_second = vi_audio->audio_samples_per_second; | |
| 853 | 1 | vi.num_audio_samples = vi_audio->num_audio_samples; | |
| 854 | 1 | vi.sample_type = vi_audio->sample_type; | |
| 855 | 1 | vi.nchannels = vi_audio->nchannels; | |
| 856 |
3/6✓ Branch 34 → 35 taken 1 time.
✗ Branch 34 → 38 not taken.
✓ Branch 35 → 36 taken 1 time.
✗ Branch 35 → 38 not taken.
✓ Branch 36 → 37 taken 1 time.
✗ Branch 36 → 38 not taken.
|
1 | vi.SetChannelMask(vi_audio->IsChannelMaskKnown(), vi_audio->GetChannelMask()); |
| 857 | 1 | } | |
| 858 | |||
| 859 | |||
| 860 | 6 | const VideoInfo& AudioDub::GetVideoInfo() | |
| 861 | { | ||
| 862 | 6 | return vi; | |
| 863 | } | ||
| 864 | |||
| 865 | |||
| 866 | ✗ | PVideoFrame AudioDub::GetFrame(int n, IScriptEnvironment* env) | |
| 867 | { | ||
| 868 | ✗ | return vchild->GetFrame(n, env); | |
| 869 | } | ||
| 870 | |||
| 871 | |||
| 872 | ✗ | bool AudioDub::GetParity(int n) | |
| 873 | { | ||
| 874 | ✗ | return vchild->GetParity(n); | |
| 875 | } | ||
| 876 | |||
| 877 | |||
| 878 | 1 | void AudioDub::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) | |
| 879 | { | ||
| 880 | 1 | achild->GetAudio(buf, start, count, env); | |
| 881 | 1 | } | |
| 882 | |||
| 883 | ✗ | int __stdcall AudioDub::SetCacheHints(int cachehints,int frame_range) | |
| 884 | { | ||
| 885 | AVS_UNUSED(frame_range); | ||
| 886 | ✗ | switch(cachehints) | |
| 887 | { | ||
| 888 | ✗ | case CACHE_DONT_CACHE_ME: | |
| 889 | ✗ | return 1; | |
| 890 | ✗ | case CACHE_GET_MTMODE: | |
| 891 | ✗ | return MT_NICE_FILTER; | |
| 892 | ✗ | case CACHE_GET_DEV_TYPE: | |
| 893 | ✗ | return (vchild->GetVersion() >= 5) ? vchild->SetCacheHints(CACHE_GET_DEV_TYPE, 0) : 0; | |
| 894 | ✗ | default: | |
| 895 | ✗ | return 0; | |
| 896 | } | ||
| 897 | } | ||
| 898 | |||
| 899 | |||
| 900 | |||
| 901 | ✗ | AVSValue __cdecl AudioDub::Create(AVSValue args, void* mode, IScriptEnvironment* env) | |
| 902 | { | ||
| 903 | ✗ | return new AudioDub(args[0].AsClip(), args[1].AsClip(), (int)size_t(mode), env); | |
| 904 | } | ||
| 905 | |||
| 906 | |||
| 907 | |||
| 908 | |||
| 909 | |||
| 910 | |||
| 911 | |||
| 912 | |||
| 913 | |||
| 914 | /******************************* | ||
| 915 | ******* Reverse Filter ****** | ||
| 916 | *******************************/ | ||
| 917 | |||
| 918 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
|
1 | Reverse::Reverse(PClip _child) : GenericVideoFilter(_child) {} |
| 919 | |||
| 920 | |||
| 921 | ✗ | PVideoFrame Reverse::GetFrame(int n, IScriptEnvironment* env) | |
| 922 | { | ||
| 923 | ✗ | return child->GetFrame(vi.num_frames-n-1, env); | |
| 924 | } | ||
| 925 | |||
| 926 | |||
| 927 | ✗ | bool Reverse::GetParity(int n) | |
| 928 | { | ||
| 929 | ✗ | return child->GetParity(vi.num_frames-n-1); | |
| 930 | } | ||
| 931 | |||
| 932 | |||
| 933 | 1 | void Reverse::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) | |
| 934 | { | ||
| 935 | 1 | child->GetAudio(buf, vi.num_audio_samples - start - count, count, env); | |
| 936 | 1 | const int bytes_per_sample = vi.BytesPerAudioSample(); // includes all channels | |
| 937 | 1 | const int bytes_per_channel_sample = vi.BytesPerChannelSample(); | |
| 938 | 1 | const int nch = vi.AudioChannels(); | |
| 939 | 1 | uint8_t* buf2 = reinterpret_cast<uint8_t*>(buf); | |
| 940 | |||
| 941 |
1/5✗ Branch 7 → 8 not taken.
✓ Branch 7 → 16 taken 1 time.
✗ Branch 7 → 24 not taken.
✗ Branch 7 → 35 not taken.
✗ Branch 7 → 52 not taken.
|
1 | switch (bytes_per_channel_sample) { |
| 942 | ✗ | case 1: // 8-bit | |
| 943 | ✗ | for (int64_t i = 0; i < count / 2; ++i) { | |
| 944 | ✗ | uint8_t* a_ptr = buf2 + i * bytes_per_sample; | |
| 945 | ✗ | uint8_t* b_ptr = buf2 + (count - 1 - i) * bytes_per_sample; | |
| 946 | ✗ | for (int c = 0; c < nch; ++c) { | |
| 947 | ✗ | std::swap(a_ptr[c], b_ptr[c]); | |
| 948 | } | ||
| 949 | } | ||
| 950 | ✗ | break; | |
| 951 | 1 | case 2: // 16-bit | |
| 952 |
2/2✓ Branch 22 → 17 taken 2 times.
✓ Branch 22 → 23 taken 1 time.
|
3 | for (int64_t i = 0; i < count / 2; ++i) { |
| 953 | 2 | int16_t* a_ptr = reinterpret_cast<int16_t*>(buf2 + i * bytes_per_sample); | |
| 954 | 2 | int16_t* b_ptr = reinterpret_cast<int16_t*>(buf2 + (count - 1 - i) * bytes_per_sample); | |
| 955 |
2/2✓ Branch 20 → 18 taken 4 times.
✓ Branch 20 → 21 taken 2 times.
|
6 | for (int c = 0; c < nch; ++c) { |
| 956 | 4 | std::swap(a_ptr[c], b_ptr[c]); | |
| 957 | } | ||
| 958 | } | ||
| 959 | 1 | break; | |
| 960 | ✗ | case 3: // 24-bit, keep brute force | |
| 961 | ✗ | for (int64_t i = 0; i < count / 2; ++i) { | |
| 962 | ✗ | uint8_t* a_ptr = buf2 + i * bytes_per_sample; | |
| 963 | ✗ | uint8_t* b_ptr = buf2 + (count - 1 - i) * bytes_per_sample; | |
| 964 | ✗ | for (int c = 0; c < nch; ++c) { | |
| 965 | ✗ | uint8_t* a_chan = a_ptr + c * 3; | |
| 966 | ✗ | uint8_t* b_chan = b_ptr + c * 3; | |
| 967 | ✗ | for (int j = 0; j < 3; ++j) { | |
| 968 | ✗ | std::swap(a_chan[j], b_chan[j]); | |
| 969 | } | ||
| 970 | } | ||
| 971 | } | ||
| 972 | ✗ | break; | |
| 973 | ✗ | case 4: // 32-bit int or float, separate because of swap templates | |
| 974 | ✗ | if (vi.IsSampleType(SAMPLE_FLOAT)) { | |
| 975 | ✗ | for (int64_t i = 0; i < count / 2; ++i) { | |
| 976 | ✗ | float* a_ptr = reinterpret_cast<float*>(buf2 + i * bytes_per_sample); | |
| 977 | ✗ | float* b_ptr = reinterpret_cast<float*>(buf2 + (count - 1 - i) * bytes_per_sample); | |
| 978 | ✗ | for (int c = 0; c < nch; ++c) { | |
| 979 | ✗ | std::swap(a_ptr[c], b_ptr[c]); | |
| 980 | } | ||
| 981 | } | ||
| 982 | } | ||
| 983 | else { | ||
| 984 | ✗ | for (int64_t i = 0; i < count / 2; ++i) { | |
| 985 | ✗ | int32_t* a_ptr = reinterpret_cast<int32_t*>(buf2 + i * bytes_per_sample); | |
| 986 | ✗ | int32_t* b_ptr = reinterpret_cast<int32_t*>(buf2 + (count - 1 - i) * bytes_per_sample); | |
| 987 | ✗ | for (int c = 0; c < nch; ++c) { | |
| 988 | ✗ | std::swap(a_ptr[c], b_ptr[c]); | |
| 989 | } | ||
| 990 | } | ||
| 991 | } | ||
| 992 | ✗ | break; | |
| 993 | ✗ | default: // generic case, no such sample size though | |
| 994 | ✗ | for (int64_t i = 0; i < count / 2; ++i) { | |
| 995 | ✗ | uint8_t* a_ptr = buf2 + i * bytes_per_sample; | |
| 996 | ✗ | uint8_t* b_ptr = buf2 + (count - 1 - i) * bytes_per_sample; | |
| 997 | ✗ | for (int c = 0; c < nch; ++c) { | |
| 998 | ✗ | uint8_t* a_chan = a_ptr + c * bytes_per_channel_sample; | |
| 999 | ✗ | uint8_t* b_chan = b_ptr + c * bytes_per_channel_sample; | |
| 1000 | ✗ | for (int j = 0; j < bytes_per_channel_sample; ++j) { | |
| 1001 | ✗ | std::swap(a_chan[j], b_chan[j]); | |
| 1002 | } | ||
| 1003 | } | ||
| 1004 | } | ||
| 1005 | ✗ | break; | |
| 1006 | } | ||
| 1007 | 1 | } | |
| 1008 | |||
| 1009 | |||
| 1010 | ✗ | AVSValue __cdecl Reverse::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 1011 | { | ||
| 1012 | AVS_UNUSED(env); | ||
| 1013 | ✗ | return new Reverse(args[0].AsClip()); | |
| 1014 | } | ||
| 1015 | |||
| 1016 | |||
| 1017 | |||
| 1018 | |||
| 1019 | |||
| 1020 | |||
| 1021 | |||
| 1022 | |||
| 1023 | /***************************** | ||
| 1024 | ****** Loop Filter ******* | ||
| 1025 | *****************************/ | ||
| 1026 | |||
| 1027 | 1 | Loop::Loop(PClip _child, int times, int _start, int _end, IScriptEnvironment* env) | |
| 1028 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 33 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 31 not taken.
|
1 | : GenericVideoFilter(_child), start(_start), end(_end) |
| 1029 | { | ||
| 1030 | 1 | start = clamp(start,0,vi.num_frames-1); | |
| 1031 | 1 | end = clamp(end,start,vi.num_frames-1); | |
| 1032 | 1 | frames = end-start+1; | |
| 1033 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 18 taken 1 time.
|
1 | if (times<0) { // Loop nearly forever |
| 1034 | ✗ | vi.num_frames = 10000000; | |
| 1035 | ✗ | end = vi.num_frames; | |
| 1036 | ✗ | if (vi.HasAudio()) { | |
| 1037 | ✗ | if (vi.HasVideo()) { | |
| 1038 | ✗ | aud_start = vi.AudioSamplesFromFrames(start); | |
| 1039 | ✗ | aud_end = vi.AudioSamplesFromFrames(end+1) - 1; // This is the output end sample | |
| 1040 | ✗ | aud_count = vi.AudioSamplesFromFrames(frames); // length of each loop in samples | |
| 1041 | } else { | ||
| 1042 | // start and end frame numbers are meaningless without video | ||
| 1043 | ✗ | aud_start = 0; | |
| 1044 | ✗ | aud_count = vi.num_audio_samples; | |
| 1045 | ✗ | aud_end = Int32x32To64(400000, vi.audio_samples_per_second); | |
| 1046 | } | ||
| 1047 | ✗ | vi.num_audio_samples = aud_end+1; | |
| 1048 | } | ||
| 1049 | } | ||
| 1050 | else { | ||
| 1051 | 1 | vi.num_frames += (times-1) * frames; | |
| 1052 | |||
| 1053 |
1/2✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 1 time.
|
1 | if (vi.num_frames < 0) |
| 1054 | ✗ | env->ThrowError("Loop: Maximum number of frames exceeded."); | |
| 1055 | |||
| 1056 | 1 | end = start + times * frames - 1; | |
| 1057 |
2/4✓ Branch 20 → 21 taken 1 time.
✗ Branch 20 → 34 not taken.
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 30 not taken.
|
1 | if (vi.HasAudio()) { |
| 1058 |
2/4✓ Branch 22 → 23 taken 1 time.
✗ Branch 22 → 34 not taken.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 28 taken 1 time.
|
1 | if (vi.HasVideo()) { |
| 1059 | ✗ | aud_start = vi.AudioSamplesFromFrames(start); | |
| 1060 | ✗ | aud_end = vi.AudioSamplesFromFrames(end+1) - 1; // This is the output end sample | |
| 1061 | ✗ | aud_count = vi.AudioSamplesFromFrames(frames); // length of each loop in samples | |
| 1062 | } else { | ||
| 1063 | // start and end frame numbers are meaningless without video | ||
| 1064 | 1 | aud_start = 0; | |
| 1065 | 1 | aud_count = vi.num_audio_samples; | |
| 1066 | 1 | aud_end = vi.num_audio_samples * times; | |
| 1067 | } | ||
| 1068 | 1 | vi.num_audio_samples += (times-1) * aud_count; | |
| 1069 | } | ||
| 1070 | } | ||
| 1071 | 1 | } | |
| 1072 | |||
| 1073 | |||
| 1074 | ✗ | PVideoFrame Loop::GetFrame(int n, IScriptEnvironment* env) | |
| 1075 | { | ||
| 1076 | ✗ | return child->GetFrame(convert(n), env); | |
| 1077 | } | ||
| 1078 | |||
| 1079 | |||
| 1080 | ✗ | bool Loop::GetParity(int n) | |
| 1081 | { | ||
| 1082 | ✗ | return child->GetParity(convert(n)); | |
| 1083 | } | ||
| 1084 | |||
| 1085 | 1 | void Loop::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 1086 | int64_t get_count, get_start; | ||
| 1087 | 1 | const int bpas = vi.BytesPerAudioSample(); | |
| 1088 | 1 | char* samples = (char*)buf; | |
| 1089 | |||
| 1090 |
2/2✓ Branch 18 → 4 taken 3 times.
✓ Branch 18 → 19 taken 1 time.
|
4 | while (count > 0) { |
| 1091 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 3 times.
|
3 | if (start > aud_end) { // tail of clip |
| 1092 | ✗ | get_start = aud_start + aud_count + start - (aud_end+1); | |
| 1093 | ✗ | get_count = count; | |
| 1094 | } | ||
| 1095 | else { | ||
| 1096 |
1/2✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 8 not taken.
|
3 | if (start > aud_start) // loop part of clip |
| 1097 | 3 | get_start = (start - aud_start) % aud_count + aud_start; | |
| 1098 | else // head of clip | ||
| 1099 | ✗ | get_start = start; | |
| 1100 | |||
| 1101 | 3 | get_count = aud_count - (get_start - aud_start); // count to end of next iteration | |
| 1102 | |||
| 1103 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 3 times.
|
3 | if (get_start+get_count > aud_end+1) // loop(0) case |
| 1104 | ✗ | get_count = aud_end+1 - get_start; | |
| 1105 |
1/2✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 3 times.
|
3 | else if (start+get_count > aud_end) |
| 1106 | ✗ | get_count = count; // if is last iteration do all of remainder | |
| 1107 | |||
| 1108 |
2/2✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 15 taken 2 times.
|
3 | if (get_count > count) get_count = count; |
| 1109 | } | ||
| 1110 | |||
| 1111 | 3 | child->GetAudio(samples, get_start, get_count, env); | |
| 1112 | |||
| 1113 | 3 | samples += get_count * bpas; // update dest start pointer | |
| 1114 | 3 | start += get_count; | |
| 1115 | 3 | count -= get_count; | |
| 1116 | } | ||
| 1117 | 1 | } | |
| 1118 | |||
| 1119 | ✗ | __inline int Loop::convert(int n) | |
| 1120 | { | ||
| 1121 | ✗ | if (n>end) return n - end + start + frames - 1; | |
| 1122 | ✗ | else if (n>=start) return ((n - start) % frames) + start; | |
| 1123 | ✗ | else return n; | |
| 1124 | } | ||
| 1125 | |||
| 1126 | |||
| 1127 | ✗ | AVSValue __cdecl Loop::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 1128 | { | ||
| 1129 | ✗ | if (!args[0].AsClip()->GetVideoInfo().HasVideo() && | |
| 1130 | ✗ | (args[2].Defined() || args[3].Defined())) { | |
| 1131 | ✗ | env->ThrowError("Loop: cannot use start or end frame numbers without a video track"); | |
| 1132 | } | ||
| 1133 | ✗ | return new Loop(args[0].AsClip(), args[1].AsInt(-1), args[2].AsInt(0), args[3].AsInt(10000000),env); | |
| 1134 | } | ||
| 1135 | |||
| 1136 | |||
| 1137 | |||
| 1138 | |||
| 1139 | |||
| 1140 | |||
| 1141 | |||
| 1142 | /****************************** | ||
| 1143 | ** Assorted factory methods ** | ||
| 1144 | *****************************/ | ||
| 1145 | |||
| 1146 | |||
| 1147 | ✗ | PClip __cdecl ColorClip(PClip a, int duration, AVSValue color, AVSValue color_yuv, AVSValue colors, float fps, IScriptEnvironment* env) { | |
| 1148 | ✗ | if (a->GetVideoInfo().HasVideo()) | |
| 1149 | { | ||
| 1150 | ✗ | AVSValue blackness_args[] = { a, duration, color, color_yuv, colors }; | |
| 1151 | static const char* const arg_names[5] = { 0, 0, "color", "color_yuv", "colors" }; | ||
| 1152 | ✗ | return env->Invoke("BlankClip", AVSValue(blackness_args, 5), arg_names).AsClip(); | |
| 1153 | ✗ | } | |
| 1154 | else | ||
| 1155 | { | ||
| 1156 | ✗ | AVSValue blackness_args[] = { a, duration, color, fps, color_yuv, colors }; | |
| 1157 | static const char* const arg_names[6] = { 0, 0, "color", "fps", "color_yuv", "colors" }; | ||
| 1158 | ✗ | return env->Invoke("BlankClip", AVSValue(blackness_args, 6), arg_names).AsClip(); | |
| 1159 | ✗ | } | |
| 1160 | } | ||
| 1161 | |||
| 1162 | ✗ | AVSValue __cdecl Create_Fade(AVSValue args, void* user_data, IScriptEnvironment* env) { | |
| 1163 | ✗ | const int fade_type = (int)(intptr_t)user_data; | |
| 1164 | |||
| 1165 | ✗ | const int duration = args[1].AsInt(); | |
| 1166 | ✗ | const float fps = args[3].AsFloatf(24.0f); | |
| 1167 | |||
| 1168 | ✗ | int offset = 0; | |
| 1169 | |||
| 1170 | ✗ | PClip a = args[0].AsClip(); | |
| 1171 | |||
| 1172 | ✗ | switch (fade_type) { | |
| 1173 | ✗ | case FADE_MODE_OUT0: | |
| 1174 | case FADE_MODE_IN0: | ||
| 1175 | ✗ | case FADE_MODE_IO0: offset = 0; break; | |
| 1176 | ✗ | case FADE_MODE_OUT: | |
| 1177 | case FADE_MODE_IN: | ||
| 1178 | ✗ | case FADE_MODE_IO: offset = 1; break; | |
| 1179 | ✗ | case FADE_MODE_OUT2: | |
| 1180 | case FADE_MODE_IN2: | ||
| 1181 | ✗ | case FADE_MODE_IO2: offset = 2; break; | |
| 1182 | } | ||
| 1183 | |||
| 1184 | ✗ | PClip b = ColorClip(a, duration + offset, args[2] /* color */, args[4] /* color_yuv */, args[5] /* colors */, fps, env); | |
| 1185 | |||
| 1186 | ✗ | if(fade_type == FADE_MODE_OUT0 || fade_type == FADE_MODE_OUT || fade_type == FADE_MODE_OUT2) | |
| 1187 | ✗ | return new Dissolve(a, b, duration, fps, env); | |
| 1188 | ✗ | else if (fade_type == FADE_MODE_IN0 || fade_type == FADE_MODE_IN || fade_type == FADE_MODE_IN2) | |
| 1189 | ✗ | return new Dissolve(b, a, duration, fps, env); | |
| 1190 | else { | ||
| 1191 | /* IO In-Out */ | ||
| 1192 | ✗ | AVSValue dissolve_args[] = { b, a, b, duration, fps }; | |
| 1193 | ✗ | return env->Invoke("Dissolve", AVSValue(dissolve_args, 5)).AsClip(); | |
| 1194 | ✗ | } | |
| 1195 | ✗ | } | |
| 1196 |