filters/field.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 | |||
| 36 | #include "field.h" | ||
| 37 | #ifdef INTEL_INTRINSICS | ||
| 38 | #include "intel/resample_sse.h" | ||
| 39 | #else | ||
| 40 | #include "resample.h" | ||
| 41 | #endif | ||
| 42 | #include <avs/minmax.h> | ||
| 43 | #include "../core/internal.h" | ||
| 44 | #include "../convert/convert_helper.h" | ||
| 45 | #include <vector> | ||
| 46 | |||
| 47 | |||
| 48 | /**** Factory methods ****/ | ||
| 49 | |||
| 50 | static AVSValue __cdecl Create_DoubleWeave(AVSValue args, void*, IScriptEnvironment* env); | ||
| 51 | static AVSValue __cdecl Create_Weave(AVSValue args, void*, IScriptEnvironment* env); | ||
| 52 | static AVSValue __cdecl Create_Pulldown(AVSValue args, void*, IScriptEnvironment* env); | ||
| 53 | static AVSValue __cdecl Create_SwapFields(AVSValue args, void*, IScriptEnvironment* env); | ||
| 54 | static AVSValue __cdecl Create_Bob(AVSValue args, void*, IScriptEnvironment* env); | ||
| 55 | |||
| 56 | |||
| 57 | /******************************************************************** | ||
| 58 | ***** Declare index of new filters for Avisynth's filter engine ***** | ||
| 59 | ********************************************************************/ | ||
| 60 | |||
| 61 | extern const AVSFunction Field_filters[] = { | ||
| 62 | { "ComplementParity", BUILTIN_FUNC_PREFIX, "c", ComplementParity::Create }, | ||
| 63 | { "AssumeTFF", BUILTIN_FUNC_PREFIX, "c", AssumeParity::Create, (void*)true }, | ||
| 64 | { "AssumeBFF", BUILTIN_FUNC_PREFIX, "c", AssumeParity::Create, (void*)false }, | ||
| 65 | { "AssumeFieldBased", BUILTIN_FUNC_PREFIX, "c", AssumeFieldBased::Create }, | ||
| 66 | { "AssumeFrameBased", BUILTIN_FUNC_PREFIX, "c", AssumeFrameBased::Create }, | ||
| 67 | { "SeparateColumns", BUILTIN_FUNC_PREFIX, "ci", SeparateColumns::Create }, | ||
| 68 | { "WeaveColumns", BUILTIN_FUNC_PREFIX, "ci", WeaveColumns::Create }, | ||
| 69 | { "SeparateRows", BUILTIN_FUNC_PREFIX, "ci", SeparateRows::Create }, | ||
| 70 | { "WeaveRows", BUILTIN_FUNC_PREFIX, "ci", WeaveRows::Create }, | ||
| 71 | { "SeparateFields", BUILTIN_FUNC_PREFIX, "c", SeparateFields::Create }, | ||
| 72 | { "Weave", BUILTIN_FUNC_PREFIX, "c", Create_Weave }, | ||
| 73 | { "DoubleWeave", BUILTIN_FUNC_PREFIX, "c", Create_DoubleWeave }, | ||
| 74 | { "Pulldown", BUILTIN_FUNC_PREFIX, "cii", Create_Pulldown }, | ||
| 75 | { "SelectEvery", BUILTIN_FUNC_PREFIX, "cii*", SelectEvery::Create }, | ||
| 76 | { "SelectEven", BUILTIN_FUNC_PREFIX, "c", SelectEvery::Create_SelectEven }, | ||
| 77 | { "SelectOdd", BUILTIN_FUNC_PREFIX, "c", SelectEvery::Create_SelectOdd }, | ||
| 78 | { "Interleave", BUILTIN_FUNC_PREFIX, "c+", Interleave::Create }, | ||
| 79 | { "SwapFields", BUILTIN_FUNC_PREFIX, "c", Create_SwapFields }, | ||
| 80 | { "Bob", BUILTIN_FUNC_PREFIX, "c[b]f[c]f[height]i", Create_Bob }, | ||
| 81 | { "SelectRangeEvery", BUILTIN_FUNC_PREFIX, "c[every]i[length]i[offset]i[audio]b", SelectRangeEvery::Create}, | ||
| 82 | { NULL } | ||
| 83 | }; | ||
| 84 | |||
| 85 | |||
| 86 | |||
| 87 | |||
| 88 | |||
| 89 | /********************************* | ||
| 90 | ******* SeparateColumns ****** | ||
| 91 | *********************************/ | ||
| 92 | |||
| 93 | ✗ | SeparateColumns::SeparateColumns(PClip _child, int _interval, IScriptEnvironment* env) | |
| 94 | ✗ | : GenericVideoFilter(_child), interval(_interval) | |
| 95 | { | ||
| 96 | ✗ | if (_interval <= 0) | |
| 97 | ✗ | env->ThrowError("SeparateColumns: interval must be greater than zero."); | |
| 98 | |||
| 99 | ✗ | if (_interval > vi.width) | |
| 100 | ✗ | env->ThrowError("SeparateColumns: interval must be less than or equal width."); | |
| 101 | |||
| 102 | ✗ | if (vi.width % _interval) | |
| 103 | ✗ | env->ThrowError("SeparateColumns: width must be mod %d.", _interval); | |
| 104 | |||
| 105 | ✗ | vi.width /= _interval; | |
| 106 | ✗ | vi.MulDivFPS(_interval, 1); | |
| 107 | ✗ | vi.num_frames *= _interval; | |
| 108 | |||
| 109 | ✗ | if (vi.num_frames < 0) | |
| 110 | ✗ | env->ThrowError("SeparateColumns: Maximum number of frames exceeded."); | |
| 111 | |||
| 112 | |||
| 113 | ✗ | if (vi.IsYUY2() && vi.width & 1) | |
| 114 | ✗ | env->ThrowError("SeparateColumns: YUY2 output width must be even."); | |
| 115 | ✗ | if (vi.Is420() && vi.width & 1) | |
| 116 | ✗ | env->ThrowError("SeparateColumns: YUV420 output width must be even."); | |
| 117 | ✗ | if (vi.Is422() && vi.width & 1) | |
| 118 | ✗ | env->ThrowError("SeparateColumns: YUV422 output width must be even."); | |
| 119 | ✗ | if (vi.IsYV411() && vi.width & 3) | |
| 120 | ✗ | env->ThrowError("SeparateColumns: YV411 output width must be mod 4."); | |
| 121 | ✗ | } | |
| 122 | |||
| 123 | |||
| 124 | ✗ | PVideoFrame SeparateColumns::GetFrame(int n, IScriptEnvironment* env) | |
| 125 | { | ||
| 126 | ✗ | const int m = n%interval; | |
| 127 | ✗ | const int f = n/interval; | |
| 128 | |||
| 129 | ✗ | PVideoFrame src = child->GetFrame(f, env); | |
| 130 | ✗ | PVideoFrame dst = env->NewVideoFrameP(vi, &src); | |
| 131 | |||
| 132 | ✗ | if (vi.IsPlanar()) { | |
| 133 | ✗ | int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A }; | |
| 134 | ✗ | int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A }; | |
| 135 | ✗ | int *planes = (vi.IsYUV() || vi.IsYUVA()) ? planes_y : planes_r; | |
| 136 | ✗ | for (int p = 0; p < vi.NumComponents(); ++p) { | |
| 137 | ✗ | int plane = planes[p]; | |
| 138 | ✗ | const int srcpitch = src->GetPitch(plane); | |
| 139 | ✗ | const int dstpitch = dst->GetPitch(plane); | |
| 140 | ✗ | const int height = dst->GetHeight(plane); | |
| 141 | ✗ | const int rowsize_pixels = dst->GetRowSize(plane) / vi.ComponentSize(); | |
| 142 | |||
| 143 | ✗ | const BYTE* srcp = src->GetReadPtr(plane); | |
| 144 | ✗ | BYTE* dstp = dst->GetWritePtr(plane); | |
| 145 | |||
| 146 | ✗ | switch (vi.ComponentSize()) { | |
| 147 | ✗ | case 1: | |
| 148 | ✗ | for (int y = 0; y < height; y++) { | |
| 149 | ✗ | for (int i = m, j = 0; j < rowsize_pixels; i += interval, j += 1) { | |
| 150 | ✗ | dstp[j] = srcp[i]; | |
| 151 | } | ||
| 152 | ✗ | srcp += srcpitch; | |
| 153 | ✗ | dstp += dstpitch; | |
| 154 | } | ||
| 155 | ✗ | break; | |
| 156 | ✗ | case 2: | |
| 157 | ✗ | for (int y = 0; y < height; y++) { | |
| 158 | ✗ | for (int i = m, j = 0; j < rowsize_pixels; i += interval, j += 1) { | |
| 159 | ✗ | reinterpret_cast<uint16_t *>(dstp)[j] = reinterpret_cast<const uint16_t *>(srcp)[i]; | |
| 160 | } | ||
| 161 | ✗ | srcp += srcpitch; | |
| 162 | ✗ | dstp += dstpitch; | |
| 163 | } | ||
| 164 | ✗ | break; | |
| 165 | ✗ | case 4: | |
| 166 | ✗ | for (int y = 0; y < height; y++) { | |
| 167 | ✗ | for (int i = m, j = 0; j < rowsize_pixels; i += interval, j += 1) { | |
| 168 | ✗ | reinterpret_cast<float *>(dstp)[j] = reinterpret_cast<const float *>(srcp)[i]; | |
| 169 | } | ||
| 170 | ✗ | srcp += srcpitch; | |
| 171 | ✗ | dstp += dstpitch; | |
| 172 | } | ||
| 173 | ✗ | break; | |
| 174 | } | ||
| 175 | } | ||
| 176 | } | ||
| 177 | ✗ | else if (vi.IsYUY2()) { | |
| 178 | ✗ | const int srcpitch = src->GetPitch(); | |
| 179 | ✗ | const int dstpitch = dst->GetPitch(); | |
| 180 | ✗ | const int height = dst->GetHeight(); | |
| 181 | ✗ | const int rowsize = dst->GetRowSize(); | |
| 182 | |||
| 183 | ✗ | const BYTE* srcp = src->GetReadPtr(); | |
| 184 | ✗ | BYTE* dstp = dst->GetWritePtr(); | |
| 185 | |||
| 186 | ✗ | const int m2 = m*2; | |
| 187 | ✗ | const int interval2 = interval*2; | |
| 188 | ✗ | const int interval4 = interval*4; | |
| 189 | |||
| 190 | ✗ | for (int y=0; y<height; y+=1) { | |
| 191 | ✗ | for (int i=m2, j=0; j<rowsize; i+=interval4, j+=4) { | |
| 192 | // Luma | ||
| 193 | ✗ | dstp[j+0] = srcp[i+0]; | |
| 194 | ✗ | dstp[j+2] = srcp[i+interval2]; | |
| 195 | // Chroma | ||
| 196 | ✗ | dstp[j+1] = srcp[i+m2+1]; | |
| 197 | ✗ | dstp[j+3] = srcp[i+m2+3]; | |
| 198 | } | ||
| 199 | ✗ | srcp += srcpitch; | |
| 200 | ✗ | dstp += dstpitch; | |
| 201 | } | ||
| 202 | } | ||
| 203 | ✗ | else if (vi.IsRGB24() || vi.IsRGB48()) { | |
| 204 | ✗ | const int srcpitch = src->GetPitch(); | |
| 205 | ✗ | const int dstpitch = dst->GetPitch(); | |
| 206 | ✗ | const int height = dst->GetHeight(); | |
| 207 | ✗ | const int rowsize_pixels = dst->GetRowSize() / vi.ComponentSize(); | |
| 208 | |||
| 209 | ✗ | const BYTE* srcp = src->GetReadPtr(); | |
| 210 | ✗ | BYTE* dstp = dst->GetWritePtr(); | |
| 211 | |||
| 212 | ✗ | const int m3 = m * 3; | |
| 213 | ✗ | const int interval3 = interval * 3; | |
| 214 | |||
| 215 | ✗ | if (vi.IsRGB24()) | |
| 216 | { | ||
| 217 | ✗ | for (int y = 0; y < height; y += 1) { | |
| 218 | ✗ | for (int i = m3, j = 0; j < rowsize_pixels; i += interval3, j += 3) { | |
| 219 | ✗ | dstp[j + 0] = srcp[i + 0]; | |
| 220 | ✗ | dstp[j + 1] = srcp[i + 1]; | |
| 221 | ✗ | dstp[j + 2] = srcp[i + 2]; | |
| 222 | } | ||
| 223 | ✗ | srcp += srcpitch; | |
| 224 | ✗ | dstp += dstpitch; | |
| 225 | } | ||
| 226 | } | ||
| 227 | else { | ||
| 228 | // RGB48 | ||
| 229 | ✗ | for (int y = 0; y < height; y += 1) { | |
| 230 | ✗ | for (int i = m3, j = 0; j < rowsize_pixels; i += interval3, j += 3) { | |
| 231 | ✗ | reinterpret_cast<uint16_t *>(dstp)[j + 0] = reinterpret_cast<const uint16_t *>(srcp)[i + 0]; | |
| 232 | ✗ | reinterpret_cast<uint16_t *>(dstp)[j + 1] = reinterpret_cast<const uint16_t *>(srcp)[i + 1]; | |
| 233 | ✗ | reinterpret_cast<uint16_t *>(dstp)[j + 2] = reinterpret_cast<const uint16_t *>(srcp)[i + 2]; | |
| 234 | } | ||
| 235 | ✗ | srcp += srcpitch; | |
| 236 | ✗ | dstp += dstpitch; | |
| 237 | } | ||
| 238 | } | ||
| 239 | } | ||
| 240 | ✗ | else if (vi.IsRGB32()) { | |
| 241 | ✗ | const int srcpitch4 = src->GetPitch()>>2; | |
| 242 | ✗ | const int dstpitch4 = dst->GetPitch()>>2; | |
| 243 | ✗ | const int height = dst->GetHeight(); | |
| 244 | ✗ | const int rowsize4 = dst->GetRowSize()>>2; | |
| 245 | |||
| 246 | ✗ | const int* srcp4 = (const int*)src->GetReadPtr(); | |
| 247 | ✗ | int* dstp4 = (int*)dst->GetWritePtr(); | |
| 248 | |||
| 249 | ✗ | for (int y=0; y<height; y+=1) { | |
| 250 | ✗ | for (int i=m, j=0; j<rowsize4; i+=interval, j+=1) { | |
| 251 | ✗ | dstp4[j] = srcp4[i]; | |
| 252 | } | ||
| 253 | ✗ | srcp4 += srcpitch4; | |
| 254 | ✗ | dstp4 += dstpitch4; | |
| 255 | } | ||
| 256 | } | ||
| 257 | ✗ | else if (vi.IsRGB64()) { | |
| 258 | ✗ | const int srcpitch8 = src->GetPitch()>>3; | |
| 259 | ✗ | const int dstpitch8 = dst->GetPitch()>>3; | |
| 260 | ✗ | const int height = dst->GetHeight(); | |
| 261 | ✗ | const int rowsize8 = dst->GetRowSize()>>3; | |
| 262 | |||
| 263 | ✗ | const uint64_t* srcp8 = (const uint64_t*)src->GetReadPtr(); | |
| 264 | ✗ | uint64_t* dstp8 = (uint64_t*)dst->GetWritePtr(); | |
| 265 | |||
| 266 | ✗ | for (int y=0; y<height; y+=1) { | |
| 267 | ✗ | for (int i=m, j=0; j<rowsize8; i+=interval, j+=1) { | |
| 268 | ✗ | dstp8[j] = srcp8[i]; | |
| 269 | } | ||
| 270 | ✗ | srcp8 += srcpitch8; | |
| 271 | ✗ | dstp8 += dstpitch8; | |
| 272 | } | ||
| 273 | } | ||
| 274 | ✗ | return dst; | |
| 275 | ✗ | } | |
| 276 | |||
| 277 | |||
| 278 | ✗ | AVSValue __cdecl SeparateColumns::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 279 | { | ||
| 280 | ✗ | if (args[1].AsInt() == 1) | |
| 281 | ✗ | return args[0]; | |
| 282 | |||
| 283 | ✗ | return new SeparateColumns(args[0].AsClip(), args[1].AsInt(), env); | |
| 284 | } | ||
| 285 | |||
| 286 | |||
| 287 | |||
| 288 | |||
| 289 | |||
| 290 | |||
| 291 | |||
| 292 | /******************************* | ||
| 293 | ******* WeaveColumns ****** | ||
| 294 | *******************************/ | ||
| 295 | |||
| 296 | ✗ | WeaveColumns::WeaveColumns(PClip _child, int _period, IScriptEnvironment* env) | |
| 297 | ✗ | : GenericVideoFilter(_child), period(_period), inframes(vi.num_frames) | |
| 298 | { | ||
| 299 | ✗ | if (_period <= 0) | |
| 300 | ✗ | env->ThrowError("WeaveColumns: period must be greater than zero."); | |
| 301 | |||
| 302 | ✗ | vi.width *= _period; | |
| 303 | ✗ | vi.MulDivFPS(1, _period); | |
| 304 | ✗ | vi.num_frames += _period-1; // Ceil! | |
| 305 | ✗ | vi.num_frames /= _period; | |
| 306 | ✗ | } | |
| 307 | |||
| 308 | |||
| 309 | ✗ | PVideoFrame WeaveColumns::GetFrame(int n, IScriptEnvironment* env) | |
| 310 | { | ||
| 311 | ✗ | const int b = n * period; | |
| 312 | |||
| 313 | ✗ | PVideoFrame dst = env->NewVideoFrame(vi); | |
| 314 | |||
| 315 | ✗ | for (int m=0; m<period; m++) { | |
| 316 | ✗ | const int f = b+m < inframes ? b+m : inframes-1; | |
| 317 | ✗ | PVideoFrame src = child->GetFrame(f, env); | |
| 318 | ✗ | if(0 == m) | |
| 319 | ✗ | env->copyFrameProps(src, dst); | |
| 320 | |||
| 321 | ✗ | if (vi.IsPlanar()) { | |
| 322 | ✗ | int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A }; | |
| 323 | ✗ | int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A }; | |
| 324 | ✗ | int *planes = (vi.IsYUV() || vi.IsYUVA()) ? planes_y : planes_r; | |
| 325 | ✗ | for (int p = 0; p < vi.NumComponents(); ++p) { | |
| 326 | ✗ | int plane = planes[p]; | |
| 327 | ✗ | BYTE *_dstp = dst->GetWritePtr(plane); | |
| 328 | ✗ | const int srcpitch = src->GetPitch(plane); | |
| 329 | ✗ | const int dstpitch = dst->GetPitch(plane); | |
| 330 | ✗ | const int height = src->GetHeight(plane); | |
| 331 | ✗ | const int rowsize_pixels = src->GetRowSize(plane) / vi.ComponentSize(); | |
| 332 | |||
| 333 | ✗ | const BYTE* srcp = src->GetReadPtr(plane); | |
| 334 | ✗ | BYTE* dstp = _dstp; | |
| 335 | ✗ | switch (vi.ComponentSize()) { | |
| 336 | ✗ | case 1: | |
| 337 | ✗ | for (int y = 0; y < height; y++) { | |
| 338 | ✗ | for (int i = m, j = 0; j < rowsize_pixels; i += period, j += 1) { | |
| 339 | ✗ | dstp[i] = srcp[j]; | |
| 340 | } | ||
| 341 | ✗ | srcp += srcpitch; | |
| 342 | ✗ | dstp += dstpitch; | |
| 343 | } | ||
| 344 | ✗ | break; | |
| 345 | ✗ | case 2: | |
| 346 | ✗ | for (int y = 0; y < height; y++) { | |
| 347 | ✗ | for (int i = m, j = 0; j < rowsize_pixels; i += period, j += 1) { | |
| 348 | ✗ | reinterpret_cast<uint16_t *>(dstp)[i] = reinterpret_cast<const uint16_t *>(srcp)[j]; | |
| 349 | } | ||
| 350 | ✗ | srcp += srcpitch; | |
| 351 | ✗ | dstp += dstpitch; | |
| 352 | } | ||
| 353 | ✗ | break; | |
| 354 | ✗ | case 4: | |
| 355 | ✗ | for (int y = 0; y < height; y++) { | |
| 356 | ✗ | for (int i = m, j = 0; j < rowsize_pixels; i += period, j += 1) { | |
| 357 | ✗ | reinterpret_cast<float *>(dstp)[i] = reinterpret_cast<const float *>(srcp)[j]; | |
| 358 | } | ||
| 359 | ✗ | srcp += srcpitch; | |
| 360 | ✗ | dstp += dstpitch; | |
| 361 | } | ||
| 362 | ✗ | break; | |
| 363 | } | ||
| 364 | } | ||
| 365 | } | ||
| 366 | ✗ | else if (vi.IsYUY2()) { | |
| 367 | ✗ | BYTE *_dstp = dst->GetWritePtr(); | |
| 368 | ✗ | const int dstpitch = dst->GetPitch(); | |
| 369 | |||
| 370 | ✗ | const int srcpitch = src->GetPitch(); | |
| 371 | ✗ | const int height = src->GetHeight(); | |
| 372 | ✗ | const int rowsize = src->GetRowSize(); | |
| 373 | ✗ | const BYTE* srcp = src->GetReadPtr(); | |
| 374 | ✗ | BYTE* dstp = _dstp; | |
| 375 | ✗ | const int m2 = m*2; | |
| 376 | ✗ | const int period2 = period*2; | |
| 377 | ✗ | const int period4 = period*4; | |
| 378 | |||
| 379 | ✗ | for (int y=0; y<height; y+=1) { | |
| 380 | ✗ | for (int i=m2, j=0; j<rowsize; i+=period4, j+=4) { | |
| 381 | // Luma | ||
| 382 | ✗ | dstp[i+0] = srcp[j+0]; | |
| 383 | ✗ | dstp[i+period2] = srcp[j+2]; | |
| 384 | // Chroma | ||
| 385 | ✗ | dstp[i+m2+1] = srcp[j+1]; | |
| 386 | ✗ | dstp[i+m2+3] = srcp[j+3]; | |
| 387 | } | ||
| 388 | ✗ | srcp += srcpitch; | |
| 389 | ✗ | dstp += dstpitch; | |
| 390 | } | ||
| 391 | } | ||
| 392 | ✗ | else if (vi.IsRGB24() || vi.IsRGB48()) { | |
| 393 | ✗ | BYTE *_dstp = dst->GetWritePtr(); | |
| 394 | ✗ | const int dstpitch = dst->GetPitch(); | |
| 395 | |||
| 396 | ✗ | const int srcpitch = src->GetPitch(); | |
| 397 | ✗ | const int height = src->GetHeight(); | |
| 398 | ✗ | const int rowsize_pixels = src->GetRowSize() / vi.ComponentSize(); | |
| 399 | ✗ | const BYTE* srcp = src->GetReadPtr(); | |
| 400 | ✗ | BYTE* dstp = _dstp; | |
| 401 | ✗ | const int m3 = m*3; | |
| 402 | ✗ | const int period3 = period*3; | |
| 403 | ✗ | if (vi.IsRGB24()) { | |
| 404 | ✗ | for (int y = 0; y < height; y += 1) { | |
| 405 | ✗ | for (int i = m3, j = 0; j < rowsize_pixels; i += period3, j += 3) { | |
| 406 | ✗ | dstp[i + 0] = srcp[j + 0]; | |
| 407 | ✗ | dstp[i + 1] = srcp[j + 1]; | |
| 408 | ✗ | dstp[i + 2] = srcp[j + 2]; | |
| 409 | } | ||
| 410 | ✗ | srcp += srcpitch; | |
| 411 | ✗ | dstp += dstpitch; | |
| 412 | } | ||
| 413 | } | ||
| 414 | else { | ||
| 415 | // RGB48 | ||
| 416 | ✗ | for (int y = 0; y < height; y += 1) { | |
| 417 | ✗ | for (int i = m3, j = 0; j < rowsize_pixels; i += period3, j += 3) { | |
| 418 | ✗ | reinterpret_cast<uint16_t *>(dstp)[i + 0] = reinterpret_cast<const uint16_t *>(srcp)[j + 0]; | |
| 419 | ✗ | reinterpret_cast<uint16_t *>(dstp)[i + 1] = reinterpret_cast<const uint16_t *>(srcp)[j + 1]; | |
| 420 | ✗ | reinterpret_cast<uint16_t *>(dstp)[i + 2] = reinterpret_cast<const uint16_t *>(srcp)[j + 2]; | |
| 421 | } | ||
| 422 | ✗ | srcp += srcpitch; | |
| 423 | ✗ | dstp += dstpitch; | |
| 424 | } | ||
| 425 | } | ||
| 426 | } | ||
| 427 | ✗ | else if (vi.IsRGB32()) { | |
| 428 | ✗ | BYTE *_dstp = dst->GetWritePtr(); | |
| 429 | ✗ | const int dstpitch = dst->GetPitch(); | |
| 430 | |||
| 431 | ✗ | const int srcpitch4 = src->GetPitch()>>2; | |
| 432 | ✗ | const int dstpitch4 = dstpitch>>2; | |
| 433 | ✗ | const int height = src->GetHeight(); | |
| 434 | ✗ | const int rowsize4 = src->GetRowSize()>>2; | |
| 435 | ✗ | const int* srcp4 = (const int*)src->GetReadPtr(); | |
| 436 | ✗ | int* dstp4 = (int*)_dstp; | |
| 437 | |||
| 438 | ✗ | for (int y=0; y<height; y+=1) { | |
| 439 | ✗ | for (int i=m, j=0; j<rowsize4; i+=period, j+=1) { | |
| 440 | ✗ | dstp4[i] = srcp4[j]; | |
| 441 | } | ||
| 442 | ✗ | srcp4 += srcpitch4; | |
| 443 | ✗ | dstp4 += dstpitch4; | |
| 444 | } | ||
| 445 | } | ||
| 446 | ✗ | else if (vi.IsRGB64()) { | |
| 447 | ✗ | BYTE *_dstp = dst->GetWritePtr(); | |
| 448 | ✗ | const int dstpitch = dst->GetPitch(); | |
| 449 | |||
| 450 | ✗ | const int srcpitch8 = src->GetPitch()>>3; | |
| 451 | ✗ | const int dstpitch8 = dstpitch>>3; | |
| 452 | ✗ | const int height = src->GetHeight(); | |
| 453 | ✗ | const int rowsize8 = src->GetRowSize()>>3; | |
| 454 | ✗ | const uint64_t* srcp8 = (const uint64_t*)src->GetReadPtr(); | |
| 455 | ✗ | uint64_t* dstp8 = (uint64_t*)_dstp; | |
| 456 | |||
| 457 | ✗ | for (int y=0; y<height; y+=1) { | |
| 458 | ✗ | for (int i=m, j=0; j<rowsize8; i+=period, j+=1) { | |
| 459 | ✗ | dstp8[i] = srcp8[j]; | |
| 460 | } | ||
| 461 | ✗ | srcp8 += srcpitch8; | |
| 462 | ✗ | dstp8 += dstpitch8; | |
| 463 | } | ||
| 464 | } | ||
| 465 | ✗ | } | |
| 466 | ✗ | return dst; | |
| 467 | ✗ | } | |
| 468 | |||
| 469 | |||
| 470 | ✗ | AVSValue __cdecl WeaveColumns::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 471 | { | ||
| 472 | ✗ | if (args[1].AsInt() == 1) | |
| 473 | ✗ | return args[0]; | |
| 474 | |||
| 475 | ✗ | return new WeaveColumns(args[0].AsClip(), args[1].AsInt(), env); | |
| 476 | } | ||
| 477 | |||
| 478 | |||
| 479 | |||
| 480 | |||
| 481 | |||
| 482 | |||
| 483 | |||
| 484 | /********************************* | ||
| 485 | ******* SeparateRows ****** | ||
| 486 | *********************************/ | ||
| 487 | |||
| 488 | ✗ | SeparateRows::SeparateRows(PClip _child, int _interval, IScriptEnvironment* env) | |
| 489 | ✗ | : NonCachedGenericVideoFilter(_child), interval(_interval) | |
| 490 | { | ||
| 491 | ✗ | if (_interval <= 0) | |
| 492 | ✗ | env->ThrowError("SeparateRows: interval must be greater than zero."); | |
| 493 | |||
| 494 | ✗ | if (_interval > vi.height) | |
| 495 | ✗ | env->ThrowError("SeparateRows: interval must be less than or equal height."); | |
| 496 | |||
| 497 | ✗ | if (vi.height % _interval) | |
| 498 | ✗ | env->ThrowError("SeparateRows: height must be mod %d.", _interval); | |
| 499 | |||
| 500 | ✗ | vi.height /= _interval; | |
| 501 | ✗ | vi.MulDivFPS(_interval, 1); | |
| 502 | ✗ | vi.num_frames *= _interval; | |
| 503 | |||
| 504 | ✗ | if (vi.num_frames < 0) | |
| 505 | ✗ | env->ThrowError("SeparateRows: Maximum number of frames exceeded."); | |
| 506 | |||
| 507 | ✗ | if (vi.Is420() && vi.height & 1) | |
| 508 | ✗ | env->ThrowError("SeparateRows: YUV420 output height must be even."); | |
| 509 | ✗ | } | |
| 510 | |||
| 511 | |||
| 512 | ✗ | PVideoFrame SeparateRows::GetFrame(int n, IScriptEnvironment* env) | |
| 513 | { | ||
| 514 | ✗ | const int m = (vi.IsRGB() && !vi.IsPlanar())? interval-1 - n%interval : n%interval; // RGB upside-down | |
| 515 | ✗ | const int f = n/interval; | |
| 516 | |||
| 517 | ✗ | PVideoFrame frame = child->GetFrame(f, env); | |
| 518 | |||
| 519 | ✗ | if (vi.IsPlanar() && !vi.IsY()) { | |
| 520 | ✗ | int plane0 = vi.IsRGB() ? PLANAR_G : PLANAR_Y; | |
| 521 | ✗ | int plane1 = vi.IsRGB() ? PLANAR_B : PLANAR_U; | |
| 522 | ✗ | const int Ypitch = frame->GetPitch(plane0); | |
| 523 | ✗ | const int UVpitch = frame->GetPitch(plane1); | |
| 524 | ✗ | const int Yoffset = Ypitch * m; | |
| 525 | ✗ | const int UVoffset = UVpitch * m; | |
| 526 | |||
| 527 | ✗ | if (vi.NumComponents() == 4) { | |
| 528 | ✗ | int Aoffset = frame->GetPitch(PLANAR_A) * m; | |
| 529 | |||
| 530 | ✗ | return env->SubframePlanarA(frame, Yoffset, Ypitch * interval, | |
| 531 | frame->GetRowSize(plane0), vi.height, | ||
| 532 | ✗ | UVoffset, UVoffset, UVpitch * interval, Aoffset); | |
| 533 | } | ||
| 534 | else { | ||
| 535 | ✗ | return env->SubframePlanar(frame, Yoffset, Ypitch * interval, | |
| 536 | frame->GetRowSize(plane0), vi.height, | ||
| 537 | ✗ | UVoffset, UVoffset, UVpitch * interval); | |
| 538 | } | ||
| 539 | } | ||
| 540 | ✗ | const int pitch = frame->GetPitch(); | |
| 541 | ✗ | return env->Subframe(frame, pitch * m, pitch * interval, frame->GetRowSize(), vi.height); | |
| 542 | ✗ | } | |
| 543 | |||
| 544 | |||
| 545 | ✗ | AVSValue __cdecl SeparateRows::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 546 | { | ||
| 547 | ✗ | if (args[1].AsInt() == 1) | |
| 548 | ✗ | return args[0]; | |
| 549 | |||
| 550 | ✗ | return new SeparateRows(args[0].AsClip(), args[1].AsInt(), env); | |
| 551 | } | ||
| 552 | |||
| 553 | |||
| 554 | |||
| 555 | |||
| 556 | |||
| 557 | |||
| 558 | |||
| 559 | /**************************** | ||
| 560 | ******* WeaveRows ****** | ||
| 561 | ****************************/ | ||
| 562 | |||
| 563 | ✗ | WeaveRows::WeaveRows(PClip _child, int _period, IScriptEnvironment* env) | |
| 564 | ✗ | : GenericVideoFilter(_child), period(_period), inframes(vi.num_frames) | |
| 565 | { | ||
| 566 | ✗ | if (_period <= 0) | |
| 567 | ✗ | env->ThrowError("WeaveRows: period must be greater than zero."); | |
| 568 | |||
| 569 | ✗ | vi.height *= _period; | |
| 570 | ✗ | vi.MulDivFPS(1, _period); | |
| 571 | ✗ | vi.num_frames += _period-1; // Ceil! | |
| 572 | ✗ | vi.num_frames /= _period; | |
| 573 | ✗ | } | |
| 574 | |||
| 575 | |||
| 576 | ✗ | PVideoFrame WeaveRows::GetFrame(int n, IScriptEnvironment* env) | |
| 577 | { | ||
| 578 | ✗ | const int b = n * period; | |
| 579 | ✗ | const int e = b + period; | |
| 580 | |||
| 581 | ✗ | PVideoFrame dst = env->NewVideoFrame(vi); | |
| 582 | ✗ | BYTE *dstp = dst->GetWritePtr(); | |
| 583 | ✗ | const int dstpitch = dst->GetPitch(); | |
| 584 | |||
| 585 | ✗ | if (vi.IsRGB() && !vi.IsPlanar()) { // RGB upsidedown | |
| 586 | ✗ | dstp += dstpitch * period; | |
| 587 | ✗ | for (int i=b; i<e; i++) { | |
| 588 | ✗ | dstp -= dstpitch; | |
| 589 | ✗ | const int j = i < inframes ? i : inframes-1; | |
| 590 | ✗ | PVideoFrame src = child->GetFrame(j, env); | |
| 591 | ✗ | if(i==b) // very first | |
| 592 | ✗ | env->copyFrameProps(src, dst); | |
| 593 | |||
| 594 | ✗ | env->BitBlt( dstp, dstpitch * period, | |
| 595 | src->GetReadPtr(), src->GetPitch(), | ||
| 596 | src->GetRowSize(), src->GetHeight() ); | ||
| 597 | ✗ | } | |
| 598 | } | ||
| 599 | else { | ||
| 600 | ✗ | int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A }; | |
| 601 | ✗ | int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A }; | |
| 602 | ✗ | int *planes = (vi.IsYUV() || vi.IsYUVA()) ? planes_y : planes_r; | |
| 603 | ✗ | bool isYUY2 = vi.IsYUY2(); | |
| 604 | int dstpitch[4]; | ||
| 605 | BYTE *dstp[4]; | ||
| 606 | ✗ | for (int p = 0; p < (isYUY2 ? 1 : vi.NumComponents()); ++p) { | |
| 607 | ✗ | int plane = planes[p]; | |
| 608 | ✗ | dstpitch[p] = dst->GetPitch(plane); | |
| 609 | ✗ | dstp[p] = dst->GetWritePtr(plane); | |
| 610 | } | ||
| 611 | |||
| 612 | ✗ | for (int i=b; i<e; i++) { | |
| 613 | ✗ | const int j = i < inframes ? i : inframes-1; | |
| 614 | ✗ | PVideoFrame src = child->GetFrame(j, env); | |
| 615 | ✗ | if (i == b) // very first | |
| 616 | ✗ | env->copyFrameProps(src, dst); | |
| 617 | ✗ | for (int p = 0; p < (isYUY2 ? 1 : vi.NumComponents()); ++p) { | |
| 618 | ✗ | int plane = planes[p]; | |
| 619 | ✗ | env->BitBlt(dstp[p], dstpitch[p] * period, | |
| 620 | src->GetReadPtr(plane), src->GetPitch(plane), | ||
| 621 | src->GetRowSize(plane), src->GetHeight(plane) ); | ||
| 622 | ✗ | dstp[p] += dstpitch[p]; | |
| 623 | } | ||
| 624 | ✗ | } | |
| 625 | } | ||
| 626 | ✗ | return dst; | |
| 627 | ✗ | } | |
| 628 | |||
| 629 | |||
| 630 | ✗ | AVSValue __cdecl WeaveRows::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 631 | { | ||
| 632 | ✗ | if (args[1].AsInt() == 1) | |
| 633 | ✗ | return args[0]; | |
| 634 | |||
| 635 | ✗ | return new WeaveRows(args[0].AsClip(), args[1].AsInt(), env); | |
| 636 | } | ||
| 637 | |||
| 638 | |||
| 639 | |||
| 640 | |||
| 641 | |||
| 642 | |||
| 643 | |||
| 644 | /********************************* | ||
| 645 | ******* SeparateFields ****** | ||
| 646 | *********************************/ | ||
| 647 | |||
| 648 | 9 | SeparateFields::SeparateFields(PClip _child, IScriptEnvironment* env) | |
| 649 |
2/4✓ Branch 2 → 3 taken 9 times.
✗ Branch 2 → 21 not taken.
✓ Branch 3 → 4 taken 9 times.
✗ Branch 3 → 19 not taken.
|
9 | : NonCachedGenericVideoFilter(_child) |
| 650 | { | ||
| 651 |
1/2✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 9 times.
|
9 | if (vi.height & 1) |
| 652 | ✗ | env->ThrowError("SeparateFields: height must be even"); | |
| 653 |
5/8✓ Branch 7 → 8 taken 9 times.
✗ Branch 7 → 22 not taken.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 11 taken 7 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 2 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 9 times.
|
9 | if (vi.Is420() && vi.height & 3) |
| 654 | ✗ | env->ThrowError("SeparateFields: YUV420 height must be multiple of 4"); | |
| 655 | 9 | vi.height >>= 1; | |
| 656 |
1/2✓ Branch 14 → 15 taken 9 times.
✗ Branch 14 → 22 not taken.
|
9 | vi.MulDivFPS(2, 1); |
| 657 | 9 | vi.num_frames *= 2; | |
| 658 | |||
| 659 |
1/2✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 9 times.
|
9 | if (vi.num_frames < 0) |
| 660 | ✗ | env->ThrowError("SeparateFields: Maximum number of frames exceeded."); | |
| 661 | |||
| 662 |
1/2✓ Branch 17 → 18 taken 9 times.
✗ Branch 17 → 22 not taken.
|
9 | vi.SetFieldBased(true); |
| 663 | 9 | } | |
| 664 | |||
| 665 | |||
| 666 | 28 | PVideoFrame SeparateFields::GetFrame(int n, IScriptEnvironment* env) | |
| 667 | { | ||
| 668 | #ifdef CACHE_GROWTH_INFINITELY_TEST | ||
| 669 | // FIXME: debug for Issue #270 | ||
| 670 | // See other occurencies of this define | ||
| 671 | // When filter is combined with non-SeparateFielded frames | ||
| 672 | // the cache can grow infinitely, behaves like a memory leak. | ||
| 673 | // Tried putting n or (n-1) or (n*2) instead of n >> 1 then the problem does not occur. | ||
| 674 | _RPT2(0, "SeparateFields::GetFrame before %d, >>1: %d\n", n, n >> 1); | ||
| 675 | #endif | ||
| 676 |
2/2✓ Branch 3 → 4 taken 27 times.
✓ Branch 3 → 90 taken 1 time.
|
28 | PVideoFrame frame = child->GetFrame(n>>1, env); |
| 677 | #ifdef CACHE_GROWTH_INFINITELY_TEST | ||
| 678 | _RPT2(0, "SeparateFields::GetFrame after %d, >>1: %d\n", n, n >> 1); | ||
| 679 | #endif | ||
| 680 |
2/4✓ Branch 4 → 5 taken 27 times.
✗ Branch 4 → 88 not taken.
✓ Branch 5 → 6 taken 27 times.
✗ Branch 5 → 58 not taken.
|
27 | if (vi.IsPlanar()) { |
| 681 |
1/2✓ Branch 6 → 7 taken 27 times.
✗ Branch 6 → 88 not taken.
|
27 | const bool topfield = GetParity(n); |
| 682 | |||
| 683 |
2/4✓ Branch 7 → 8 taken 27 times.
✗ Branch 7 → 88 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 27 times.
|
27 | int plane0 = vi.IsRGB() ? PLANAR_G : PLANAR_Y; |
| 684 |
2/4✓ Branch 11 → 12 taken 27 times.
✗ Branch 11 → 88 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 27 times.
|
27 | int plane1 = vi.IsRGB() ? PLANAR_B : PLANAR_U; |
| 685 |
1/2✓ Branch 16 → 17 taken 27 times.
✗ Branch 16 → 88 not taken.
|
27 | const int Ypitch = frame->GetPitch(plane0); |
| 686 |
1/2✓ Branch 18 → 19 taken 27 times.
✗ Branch 18 → 88 not taken.
|
27 | const int UVpitch = frame->GetPitch(plane1); |
| 687 |
2/2✓ Branch 19 → 20 taken 13 times.
✓ Branch 19 → 21 taken 14 times.
|
27 | const int UVoffset = !topfield ? UVpitch : 0; |
| 688 |
2/2✓ Branch 22 → 23 taken 13 times.
✓ Branch 22 → 24 taken 14 times.
|
27 | const int Yoffset = !topfield ? Ypitch : 0; |
| 689 | |||
| 690 |
2/4✓ Branch 25 → 26 taken 27 times.
✗ Branch 25 → 88 not taken.
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 45 taken 27 times.
|
27 | if (vi.NumComponents() == 4) { |
| 691 | ✗ | int Aoffset = !topfield ? frame->GetPitch(PLANAR_A) : 0; | |
| 692 | |||
| 693 | ✗ | return env->SubframePlanarA(frame, Yoffset, frame->GetPitch() * 2, frame->GetRowSize(), frame->GetHeight() >> 1, | |
| 694 | ✗ | UVoffset, UVoffset, frame->GetPitch(PLANAR_U) * 2, Aoffset); | |
| 695 | } | ||
| 696 | else { | ||
| 697 |
2/4✓ Branch 48 → 49 taken 27 times.
✗ Branch 48 → 88 not taken.
✓ Branch 52 → 53 taken 27 times.
✗ Branch 52 → 88 not taken.
|
81 | return env->SubframePlanar(frame, Yoffset, frame->GetPitch() * 2, frame->GetRowSize(), frame->GetHeight() >> 1, |
| 698 |
4/8✓ Branch 46 → 47 taken 27 times.
✗ Branch 46 → 88 not taken.
✓ Branch 50 → 51 taken 27 times.
✗ Branch 50 → 88 not taken.
✓ Branch 53 → 54 taken 27 times.
✗ Branch 53 → 84 not taken.
✓ Branch 54 → 55 taken 27 times.
✗ Branch 54 → 82 not taken.
|
81 | UVoffset, UVoffset, frame->GetPitch(PLANAR_U) * 2); |
| 699 | } | ||
| 700 | } | ||
| 701 | ✗ | return env->Subframe(frame,(GetParity(n) ^ vi.IsYUY2()) ? frame->GetPitch() : 0, | |
| 702 | ✗ | frame->GetPitch()*2, frame->GetRowSize(), frame->GetHeight()>>1); | |
| 703 | 27 | } | |
| 704 | |||
| 705 | |||
| 706 | ✗ | AVSValue __cdecl SeparateFields::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 707 | { | ||
| 708 | ✗ | PClip clip = args[0].AsClip(); | |
| 709 | ✗ | if (clip->GetVideoInfo().IsFieldBased()) | |
| 710 | ✗ | env->ThrowError("SeparateFields: SeparateFields should be applied on frame-based material: use AssumeFrameBased() beforehand"); | |
| 711 | |||
| 712 | ✗ | return new SeparateFields(clip, env); | |
| 713 | ✗ | } | |
| 714 | |||
| 715 | |||
| 716 | |||
| 717 | |||
| 718 | |||
| 719 | |||
| 720 | |||
| 721 | /****************************** | ||
| 722 | ******* Interleave ******* | ||
| 723 | ******************************/ | ||
| 724 | |||
| 725 | 2 | Interleave::Interleave(const std::vector<PClip>&& _child_array, IScriptEnvironment* env) | |
| 726 |
1/2✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 35 not taken.
|
4 | : num_children((int)_child_array.size()), child_array(std::move(_child_array)) |
| 727 | { | ||
| 728 |
1/2✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 33 not taken.
|
2 | vi = child_array[0]->GetVideoInfo(); |
| 729 |
1/2✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 33 not taken.
|
2 | vi.MulDivFPS(num_children, 1); |
| 730 | 2 | vi.num_frames = (vi.num_frames - 1) * num_children + 1; | |
| 731 |
1/2✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 33 not taken.
|
2 | child_devs = GetDeviceTypes(child_array[0]); |
| 732 |
2/2✓ Branch 29 → 14 taken 2 times.
✓ Branch 29 → 30 taken 2 times.
|
4 | for (int i=1; i<num_children; ++i) |
| 733 | { | ||
| 734 |
1/2✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 33 not taken.
|
2 | const VideoInfo& vi2 = child_array[i]->GetVideoInfo(); |
| 735 |
2/4✓ Branch 17 → 18 taken 2 times.
✗ Branch 17 → 19 not taken.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 2 times.
|
2 | if (vi.width != vi2.width || vi.height != vi2.height) |
| 736 | ✗ | env->ThrowError("Interleave: videos must be of the same size."); | |
| 737 |
2/4✓ Branch 20 → 21 taken 2 times.
✗ Branch 20 → 33 not taken.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 2 times.
|
2 | if (!vi.IsSameColorspace(vi2)) |
| 738 | ✗ | env->ThrowError("Interleave: video formats don't match"); | |
| 739 | |||
| 740 | 2 | vi.num_frames = max(vi.num_frames, (vi2.num_frames - 1) * num_children + i + 1); | |
| 741 | |||
| 742 |
1/2✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 33 not taken.
|
2 | child_devs &= GetDeviceTypes(child_array[i]); |
| 743 |
1/2✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 2 times.
|
2 | if (child_devs == 0) |
| 744 | ✗ | env->ThrowError("Interleave: device types don't match"); | |
| 745 | } | ||
| 746 |
1/2✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 2 times.
|
2 | if (vi.num_frames < 0) |
| 747 | ✗ | env->ThrowError("Interleave: Maximum number of frames exceeded."); | |
| 748 | |||
| 749 | 2 | } | |
| 750 | |||
| 751 | ✗ | int __stdcall Interleave::SetCacheHints(int cachehints,int frame_range) | |
| 752 | { | ||
| 753 | AVS_UNUSED(frame_range); | ||
| 754 | ✗ | switch (cachehints) | |
| 755 | { | ||
| 756 | ✗ | case CACHE_DONT_CACHE_ME: | |
| 757 | ✗ | return 1; | |
| 758 | ✗ | case CACHE_GET_MTMODE: | |
| 759 | ✗ | return MT_NICE_FILTER; | |
| 760 | ✗ | case CACHE_GET_DEV_TYPE: | |
| 761 | ✗ | return child_devs; | |
| 762 | ✗ | default: | |
| 763 | ✗ | return 0; | |
| 764 | } | ||
| 765 | } | ||
| 766 | |||
| 767 | ✗ | AVSValue __cdecl Interleave::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 768 | { | ||
| 769 | ✗ | args = args[0]; | |
| 770 | ✗ | const int num_args = args.ArraySize(); | |
| 771 | ✗ | if (num_args == 1) | |
| 772 | ✗ | return args[0]; | |
| 773 | |||
| 774 | ✗ | std::vector<PClip> children(num_args); | |
| 775 | |||
| 776 | ✗ | for (int i = 0; i < (int)children.size(); ++i) | |
| 777 | ✗ | children[i] = args[i].AsClip(); | |
| 778 | |||
| 779 | ✗ | return new Interleave(std::move(children), env); | |
| 780 | ✗ | } | |
| 781 | |||
| 782 | |||
| 783 | |||
| 784 | |||
| 785 | |||
| 786 | |||
| 787 | /********************************* | ||
| 788 | ******** SelectEvery ******* | ||
| 789 | *********************************/ | ||
| 790 | |||
| 791 | |||
| 792 | 12 | SelectEvery::SelectEvery(PClip _child, int _every, int _from, IScriptEnvironment* env) | |
| 793 |
2/4✓ Branch 2 → 3 taken 12 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 12 times.
✗ Branch 3 → 9 not taken.
|
12 | : NonCachedGenericVideoFilter(_child), every(_every), from(_from) |
| 794 | { | ||
| 795 |
1/2✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 12 times.
|
12 | if (_every == 0) |
| 796 | ✗ | env->ThrowError("Parameter 'every' of SelectEvery cannot be zero."); | |
| 797 | |||
| 798 |
1/2✓ Branch 7 → 8 taken 12 times.
✗ Branch 7 → 12 not taken.
|
12 | vi.MulDivFPS(1, every); |
| 799 | 12 | vi.num_frames = (vi.num_frames-1-from) / every + 1; | |
| 800 | 12 | } | |
| 801 | |||
| 802 | |||
| 803 | ✗ | AVSValue __cdecl SelectEvery::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 804 | { | ||
| 805 | ✗ | const int num_vals = args[2].ArraySize(); | |
| 806 | ✗ | if (num_vals <= 1) | |
| 807 | ✗ | return new SelectEvery(args[0].AsClip(), args[1].AsInt(), num_vals>0 ? args[2][0].AsInt() : 0, env); | |
| 808 | else { | ||
| 809 | ✗ | std::vector<PClip> children(num_vals); | |
| 810 | |||
| 811 | ✗ | for (int i = 0; i < (int)children.size(); ++i) | |
| 812 | ✗ | children[i] = new SelectEvery(args[0].AsClip(), args[1].AsInt(), args[2][i].AsInt(), env); | |
| 813 | |||
| 814 | ✗ | return new Interleave(std::move(children), env); | |
| 815 | ✗ | } | |
| 816 | } | ||
| 817 | |||
| 818 | |||
| 819 | |||
| 820 | |||
| 821 | |||
| 822 | |||
| 823 | |||
| 824 | |||
| 825 | /************************************** | ||
| 826 | ******** DoubleWeaveFields ******* | ||
| 827 | *************************************/ | ||
| 828 | |||
| 829 | 5 | DoubleWeaveFields::DoubleWeaveFields(PClip _child) | |
| 830 |
2/4✓ Branch 2 → 3 taken 5 times.
✗ Branch 2 → 9 not taken.
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 7 not taken.
|
5 | : GenericVideoFilter(_child) |
| 831 | { | ||
| 832 | 5 | vi.height *= 2; | |
| 833 |
1/2✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 10 not taken.
|
5 | vi.SetFieldBased(false); |
| 834 | 5 | } | |
| 835 | |||
| 836 | |||
| 837 | 10 | void copy_field(const PVideoFrame& dst, const PVideoFrame& src, bool yuv, bool planarRGB, bool parity, IScriptEnvironment* env) | |
| 838 | { | ||
| 839 |
1/4✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 10 times.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
|
10 | bool noTopBottom = yuv || planarRGB; |
| 840 | |||
| 841 |
1/2✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 10 times.
|
10 | int plane1 = planarRGB ? PLANAR_B : PLANAR_U; |
| 842 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 10 times.
|
10 | int plane2 = planarRGB ? PLANAR_R : PLANAR_V; |
| 843 | |||
| 844 | 10 | const int add_pitch = dst->GetPitch() * (parity ^ noTopBottom); | |
| 845 | 10 | const int add_pitchUV = dst->GetPitch(plane1) * (parity ^ noTopBottom); | |
| 846 | 10 | const int add_pitchA = dst->GetPitch(PLANAR_A) * (parity ^ noTopBottom); | |
| 847 | |||
| 848 | 10 | env->BitBlt(dst->GetWritePtr() + add_pitch, dst->GetPitch()*2, | |
| 849 | src->GetReadPtr(), src->GetPitch(), | ||
| 850 | src->GetRowSize(), src->GetHeight()); | ||
| 851 | |||
| 852 | 10 | env->BitBlt(dst->GetWritePtr(plane1) + add_pitchUV, dst->GetPitch(plane1)*2, | |
| 853 | src->GetReadPtr(plane1), src->GetPitch(plane1), | ||
| 854 | src->GetRowSize(plane1), src->GetHeight(plane1)); | ||
| 855 | |||
| 856 | 10 | env->BitBlt(dst->GetWritePtr(plane2) + add_pitchUV, dst->GetPitch(plane2)*2, | |
| 857 | src->GetReadPtr(plane2), src->GetPitch(plane2), | ||
| 858 | src->GetRowSize(plane2), src->GetHeight(plane2)); | ||
| 859 | |||
| 860 | 10 | env->BitBlt(dst->GetWritePtr(PLANAR_A) + add_pitchA, dst->GetPitch(PLANAR_A)*2, | |
| 861 | src->GetReadPtr(PLANAR_A), src->GetPitch(PLANAR_A), | ||
| 862 | src->GetRowSize(PLANAR_A), src->GetHeight(PLANAR_A)); | ||
| 863 | 10 | } | |
| 864 | |||
| 865 | |||
| 866 | 6 | PVideoFrame DoubleWeaveFields::GetFrame(int n, IScriptEnvironment* env) | |
| 867 | { | ||
| 868 |
1/2✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 45 not taken.
|
6 | PVideoFrame a = child->GetFrame(n, env); |
| 869 |
2/2✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 43 taken 1 time.
|
6 | PVideoFrame b = child->GetFrame(n+1, env); |
| 870 | |||
| 871 |
1/2✓ Branch 6 → 7 taken 5 times.
✗ Branch 6 → 41 not taken.
|
5 | PVideoFrame result = env->NewVideoFrameP(vi, &a); |
| 872 | |||
| 873 |
1/2✓ Branch 8 → 9 taken 5 times.
✗ Branch 8 → 39 not taken.
|
5 | const bool parity = child->GetParity(n); |
| 874 | |||
| 875 |
7/18✓ Branch 9 → 10 taken 5 times.
✗ Branch 9 → 39 not taken.
✓ Branch 10 → 11 taken 5 times.
✗ Branch 10 → 13 not taken.
✓ Branch 11 → 12 taken 5 times.
✗ Branch 11 → 39 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 5 times.
✓ Branch 15 → 16 taken 5 times.
✗ Branch 15 → 39 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 5 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 39 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 20 not taken.
✓ Branch 21 → 22 taken 5 times.
✗ Branch 21 → 39 not taken.
|
5 | copy_field(result, a, vi.IsYUV() || vi.IsYUVA(), vi.IsPlanarRGB() || vi.IsPlanarRGBA(), parity, env); |
| 876 |
7/18✓ Branch 22 → 23 taken 5 times.
✗ Branch 22 → 39 not taken.
✓ Branch 23 → 24 taken 5 times.
✗ Branch 23 → 26 not taken.
✓ Branch 24 → 25 taken 5 times.
✗ Branch 24 → 39 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 5 times.
✓ Branch 28 → 29 taken 5 times.
✗ Branch 28 → 39 not taken.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 32 taken 5 times.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 39 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
✓ Branch 34 → 35 taken 5 times.
✗ Branch 34 → 39 not taken.
|
5 | copy_field(result, b, vi.IsYUV() || vi.IsYUVA(), vi.IsPlanarRGB() || vi.IsPlanarRGBA(), !parity, env); |
| 877 | |||
| 878 | 5 | return result; | |
| 879 | 6 | } | |
| 880 | |||
| 881 | |||
| 882 | |||
| 883 | /************************************** | ||
| 884 | ******** DoubleWeaveFrames ******* | ||
| 885 | *************************************/ | ||
| 886 | |||
| 887 | 2 | DoubleWeaveFrames::DoubleWeaveFrames(PClip _child) | |
| 888 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 9 not taken.
|
2 | : GenericVideoFilter(_child) |
| 889 | { | ||
| 890 | 2 | vi.num_frames *= 2; | |
| 891 |
1/2✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2 times.
|
2 | if (vi.num_frames < 0) |
| 892 | ✗ | vi.num_frames = 0x7FFFFFFF; // MAXINT | |
| 893 | |||
| 894 |
1/2✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 12 not taken.
|
2 | vi.MulDivFPS(2, 1); |
| 895 | 2 | } | |
| 896 | |||
| 897 | 2 | void copy_alternate_lines(const PVideoFrame& dst, const PVideoFrame& src, bool yuv, bool planarRGB, bool parity, IScriptEnvironment* env) | |
| 898 | { | ||
| 899 |
1/4✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
|
2 | bool noTopBottom = yuv || planarRGB; |
| 900 | |||
| 901 |
1/2✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2 times.
|
2 | int plane1 = planarRGB ? PLANAR_B : PLANAR_U; |
| 902 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 2 times.
|
2 | int plane2 = planarRGB ? PLANAR_R : PLANAR_V; |
| 903 | |||
| 904 | 2 | const int src_add_pitch = src->GetPitch() * (parity ^ noTopBottom); | |
| 905 | 2 | const int src_add_pitchUV = src->GetPitch(plane1) * (parity ^ noTopBottom); | |
| 906 | 2 | const int src_add_pitchA = src->GetPitch(PLANAR_A) * (parity ^ noTopBottom); | |
| 907 | |||
| 908 | 2 | const int dst_add_pitch = dst->GetPitch() * (parity ^ noTopBottom); | |
| 909 | 2 | const int dst_add_pitchUV = dst->GetPitch(plane1) * (parity ^ noTopBottom); | |
| 910 | 2 | const int dst_add_pitchA = dst->GetPitch(PLANAR_A) * (parity ^ noTopBottom); | |
| 911 | |||
| 912 | 4 | env->BitBlt(dst->GetWritePtr() + dst_add_pitch, dst->GetPitch()*2, | |
| 913 | 2 | src->GetReadPtr() + src_add_pitch, src->GetPitch()*2, | |
| 914 | 2 | src->GetRowSize(), src->GetHeight()>>1); | |
| 915 | |||
| 916 | 4 | env->BitBlt(dst->GetWritePtr(plane1) + dst_add_pitchUV, dst->GetPitch(plane1)*2, | |
| 917 | 2 | src->GetReadPtr(plane1) + src_add_pitchUV, src->GetPitch(plane1)*2, | |
| 918 | 2 | src->GetRowSize(plane1), src->GetHeight(plane1)>>1); | |
| 919 | |||
| 920 | 4 | env->BitBlt(dst->GetWritePtr(plane2) + dst_add_pitchUV, dst->GetPitch(plane2)*2, | |
| 921 | 2 | src->GetReadPtr(plane2) + src_add_pitchUV, src->GetPitch(plane2)*2, | |
| 922 | 2 | src->GetRowSize(plane2), src->GetHeight(plane2)>>1); | |
| 923 | |||
| 924 | 4 | env->BitBlt(dst->GetWritePtr(PLANAR_A) + dst_add_pitchA, dst->GetPitch(PLANAR_A)*2, | |
| 925 | 2 | src->GetReadPtr(PLANAR_A) + src_add_pitchA, src->GetPitch(PLANAR_A)*2, | |
| 926 | 2 | src->GetRowSize(PLANAR_A), src->GetHeight(PLANAR_A)>>1); | |
| 927 | 2 | } | |
| 928 | |||
| 929 | |||
| 930 | 4 | PVideoFrame DoubleWeaveFrames::GetFrame(int n, IScriptEnvironment* env) | |
| 931 | { | ||
| 932 |
2/2✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 5 taken 2 times.
|
4 | if (!(n&1)) |
| 933 | { | ||
| 934 | 2 | return child->GetFrame(n>>1, env); | |
| 935 | } | ||
| 936 | else { | ||
| 937 |
1/2✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 88 not taken.
|
2 | PVideoFrame a = child->GetFrame(n>>1, env); |
| 938 |
2/2✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 86 taken 1 time.
|
2 | PVideoFrame b = child->GetFrame((n+1)>>1, env); |
| 939 |
1/2✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 84 not taken.
|
1 | bool parity = this->GetParity(n); |
| 940 | |||
| 941 |
2/4✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 84 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 28 taken 1 time.
|
1 | if (a->IsWritable()) { |
| 942 | ✗ | copy_alternate_lines(a, b, vi.IsYUV() || vi.IsYUVA(), vi.IsPlanarRGB() || vi.IsPlanarRGBA(), !parity, env); | |
| 943 | ✗ | return a; | |
| 944 | } | ||
| 945 |
2/4✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 84 not taken.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 46 taken 1 time.
|
1 | else if (b->IsWritable()) { |
| 946 | ✗ | copy_alternate_lines(b, a, vi.IsYUV() || vi.IsYUVA(), vi.IsPlanarRGB() || vi.IsPlanarRGBA(), parity, env); | |
| 947 | ✗ | return b; | |
| 948 | } | ||
| 949 | else { | ||
| 950 |
1/2✓ Branch 46 → 47 taken 1 time.
✗ Branch 46 → 83 not taken.
|
1 | PVideoFrame result = env->NewVideoFrameP(vi, &a); |
| 951 |
7/18✓ Branch 47 → 48 taken 1 time.
✗ Branch 47 → 81 not taken.
✓ Branch 48 → 49 taken 1 time.
✗ Branch 48 → 51 not taken.
✓ Branch 49 → 50 taken 1 time.
✗ Branch 49 → 81 not taken.
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 52 taken 1 time.
✓ Branch 53 → 54 taken 1 time.
✗ Branch 53 → 81 not taken.
✗ Branch 54 → 55 not taken.
✓ Branch 54 → 57 taken 1 time.
✗ Branch 55 → 56 not taken.
✗ Branch 55 → 81 not taken.
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 58 not taken.
✓ Branch 59 → 60 taken 1 time.
✗ Branch 59 → 81 not taken.
|
1 | copy_alternate_lines(result, a, vi.IsYUV() || vi.IsYUVA(), vi.IsPlanarRGB() || vi.IsPlanarRGBA(), parity, env); |
| 952 |
7/18✓ Branch 60 → 61 taken 1 time.
✗ Branch 60 → 81 not taken.
✓ Branch 61 → 62 taken 1 time.
✗ Branch 61 → 64 not taken.
✓ Branch 62 → 63 taken 1 time.
✗ Branch 62 → 81 not taken.
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 65 taken 1 time.
✓ Branch 66 → 67 taken 1 time.
✗ Branch 66 → 81 not taken.
✗ Branch 67 → 68 not taken.
✓ Branch 67 → 70 taken 1 time.
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 81 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
✓ Branch 72 → 73 taken 1 time.
✗ Branch 72 → 81 not taken.
|
1 | copy_alternate_lines(result, b, vi.IsYUV() || vi.IsYUVA(), vi.IsPlanarRGB() || vi.IsPlanarRGBA(), !parity, env); |
| 953 |
1/2✓ Branch 73 → 74 taken 1 time.
✗ Branch 73 → 81 not taken.
|
1 | return result; |
| 954 | 1 | } | |
| 955 | 2 | } | |
| 956 | } | ||
| 957 | |||
| 958 | |||
| 959 | |||
| 960 | |||
| 961 | |||
| 962 | /******************************* | ||
| 963 | ******** Bob Filter ******* | ||
| 964 | *******************************/ | ||
| 965 | |||
| 966 | ✗ | Fieldwise::Fieldwise(PClip _child1, PClip _child2) | |
| 967 | ✗ | : NonCachedGenericVideoFilter(_child1), child2(_child2) | |
| 968 | ✗ | { vi.SetFieldBased(false); } // Make FrameBased, leave IT_BFF and IT_TFF alone | |
| 969 | |||
| 970 | |||
| 971 | ✗ | PVideoFrame __stdcall Fieldwise::GetFrame(int n, IScriptEnvironment* env) | |
| 972 | { | ||
| 973 | ✗ | return (child->GetParity(n) ? child2 : child)->GetFrame(n, env); | |
| 974 | } | ||
| 975 | |||
| 976 | |||
| 977 | ✗ | bool __stdcall Fieldwise::GetParity(int n) | |
| 978 | { | ||
| 979 | ✗ | return child->GetParity(n) ^ (n&1); // ^ = XOR | |
| 980 | } | ||
| 981 | |||
| 982 | |||
| 983 | |||
| 984 | |||
| 985 | |||
| 986 | |||
| 987 | |||
| 988 | /************************************ | ||
| 989 | ******** Factory Methods ******* | ||
| 990 | ***********************************/ | ||
| 991 | |||
| 992 | ✗ | static AVSValue __cdecl Create_DoubleWeave(AVSValue args, void*, IScriptEnvironment* env) | |
| 993 | { | ||
| 994 | AVS_UNUSED(env); | ||
| 995 | ✗ | PClip clip = args[0].AsClip(); | |
| 996 | ✗ | if (clip->GetVideoInfo().IsFieldBased()) | |
| 997 | ✗ | return new DoubleWeaveFields(clip); | |
| 998 | else | ||
| 999 | ✗ | return new DoubleWeaveFrames(clip); | |
| 1000 | ✗ | } | |
| 1001 | |||
| 1002 | |||
| 1003 | ✗ | static AVSValue __cdecl Create_Weave(AVSValue args, void*, IScriptEnvironment* env) | |
| 1004 | { | ||
| 1005 | ✗ | PClip clip = args[0].AsClip(); | |
| 1006 | ✗ | if (!clip->GetVideoInfo().IsFieldBased()) | |
| 1007 | ✗ | env->ThrowError("Weave: Weave should be applied on field-based material: use AssumeFieldBased() beforehand"); | |
| 1008 | ✗ | return new SelectEvery(Create_DoubleWeave(args, 0, env).AsClip(), 2, 0, env); | |
| 1009 | ✗ | } | |
| 1010 | |||
| 1011 | |||
| 1012 | ✗ | static AVSValue __cdecl Create_Pulldown(AVSValue args, void*, IScriptEnvironment* env) | |
| 1013 | { | ||
| 1014 | ✗ | PClip clip = args[0].AsClip(); | |
| 1015 | ✗ | std::vector<PClip> children(2); | |
| 1016 | ✗ | children[0] = new SelectEvery(clip, 5, args[1].AsInt() % 5, env); | |
| 1017 | ✗ | children[1] = new SelectEvery(clip, 5, args[2].AsInt() % 5, env); | |
| 1018 | ✗ | return new AssumeFrameBased(new Interleave(std::move(children), env)); | |
| 1019 | ✗ | } | |
| 1020 | |||
| 1021 | |||
| 1022 | ✗ | static AVSValue __cdecl Create_SwapFields(AVSValue args, void*, IScriptEnvironment* env) | |
| 1023 | { | ||
| 1024 | ✗ | return new SelectEvery(new DoubleWeaveFields(new ComplementParity( | |
| 1025 | ✗ | new SeparateFields(args[0].AsClip(), env))), 2, 0, env); | |
| 1026 | } | ||
| 1027 | |||
| 1028 | |||
| 1029 | ✗ | static AVSValue __cdecl Create_Bob(AVSValue args, void*, IScriptEnvironment* env) | |
| 1030 | { | ||
| 1031 | ✗ | PClip clip = args[0].AsClip(); | |
| 1032 | ✗ | if (!clip->GetVideoInfo().IsFieldBased()) | |
| 1033 | ✗ | clip = new SeparateFields(clip, env); | |
| 1034 | |||
| 1035 | ✗ | const VideoInfo& vi = clip->GetVideoInfo(); | |
| 1036 | |||
| 1037 | ✗ | bool preserve_center = true; // default Avisynth | |
| 1038 | ✗ | int chroma_placement = ChromaLocation_e::AVS_CHROMA_UNUSED; // default | |
| 1039 | |||
| 1040 | ✗ | const double b = args[1].AsDblDef(1./3.); | |
| 1041 | ✗ | const double c = args[2].AsDblDef(1./3.); | |
| 1042 | ✗ | const int new_height = args[3].AsInt(vi.height*2); | |
| 1043 | ✗ | MitchellNetravaliFilter filter(b, c); | |
| 1044 | ✗ | return new Fieldwise(new FilteredResizeV(clip, -0.25, vi.height, | |
| 1045 | ✗ | new_height, &filter, preserve_center, chroma_placement, env), | |
| 1046 | ✗ | new FilteredResizeV(clip, +0.25, vi.height, | |
| 1047 | ✗ | new_height, &filter, preserve_center, chroma_placement, env)); | |
| 1048 | ✗ | } | |
| 1049 | |||
| 1050 | |||
| 1051 | ✗ | SelectRangeEvery::SelectRangeEvery(PClip _child, int _every, int _length, int _offset, bool _audio, IScriptEnvironment* env) | |
| 1052 | ✗ | : NonCachedGenericVideoFilter(_child), audio(_audio), achild(_child) | |
| 1053 | { | ||
| 1054 | ✗ | const int64_t num_audio_samples = vi.num_audio_samples; | |
| 1055 | |||
| 1056 | ✗ | AVSValue trimargs[3] = { _child, _offset, 0}; | |
| 1057 | ✗ | PClip c = env->Invoke("Trim",AVSValue(trimargs,3)).AsClip(); | |
| 1058 | ✗ | child = c; | |
| 1059 | ✗ | vi = c->GetVideoInfo(); | |
| 1060 | |||
| 1061 | ✗ | every = clamp(_every,1,vi.num_frames); | |
| 1062 | ✗ | length = clamp(_length,1,every); | |
| 1063 | |||
| 1064 | ✗ | const int n = vi.num_frames; | |
| 1065 | ✗ | vi.num_frames = (n/every)*length+(n%every<length?n%every:length); | |
| 1066 | |||
| 1067 | ✗ | if (audio && vi.HasAudio()) { | |
| 1068 | ✗ | vi.num_audio_samples = vi.AudioSamplesFromFrames(vi.num_frames); | |
| 1069 | } else { | ||
| 1070 | ✗ | vi.num_audio_samples = num_audio_samples; // Undo Trim's work! | |
| 1071 | } | ||
| 1072 | ✗ | } | |
| 1073 | |||
| 1074 | |||
| 1075 | ✗ | PVideoFrame __stdcall SelectRangeEvery::GetFrame(int n, IScriptEnvironment* env) | |
| 1076 | { | ||
| 1077 | ✗ | return child->GetFrame((n/length)*every+(n%length), env); | |
| 1078 | } | ||
| 1079 | |||
| 1080 | |||
| 1081 | ✗ | bool __stdcall SelectRangeEvery::GetParity(int n) | |
| 1082 | { | ||
| 1083 | ✗ | return child->GetParity((n/length)*every+(n%length)); | |
| 1084 | } | ||
| 1085 | |||
| 1086 | |||
| 1087 | ✗ | void __stdcall SelectRangeEvery::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) | |
| 1088 | { | ||
| 1089 | ✗ | if (!audio) { | |
| 1090 | // Use original unTrim'd child | ||
| 1091 | ✗ | achild->GetAudio(buf, start, count, env); | |
| 1092 | ✗ | return; | |
| 1093 | } | ||
| 1094 | |||
| 1095 | ✗ | int64_t samples_filled = 0; | |
| 1096 | ✗ | BYTE* samples = (BYTE*)buf; | |
| 1097 | ✗ | const int bps = vi.BytesPerAudioSample(); | |
| 1098 | ✗ | int startframe = vi.FramesFromAudioSamples(start); | |
| 1099 | ✗ | int64_t general_offset = start - vi.AudioSamplesFromFrames(startframe); // General compensation for startframe rounding. | |
| 1100 | |||
| 1101 | ✗ | while (samples_filled < count) { | |
| 1102 | ✗ | const int iteration = startframe / length; // Which iteration is this. | |
| 1103 | ✗ | const int iteration_into = startframe % length; // How far, in frames are we into this iteration. | |
| 1104 | ✗ | const int iteration_left = length - iteration_into; // How many frames is left of this iteration. | |
| 1105 | |||
| 1106 | ✗ | const int64_t iteration_left_samples = vi.AudioSamplesFromFrames(iteration_left); | |
| 1107 | // This is the number of samples we can get without either having to skip, or being finished. | ||
| 1108 | ✗ | const int64_t getsamples = min(iteration_left_samples, count-samples_filled); | |
| 1109 | ✗ | const int64_t start_offset = vi.AudioSamplesFromFrames(iteration * every + iteration_into) + general_offset; | |
| 1110 | |||
| 1111 | ✗ | child->GetAudio(&samples[samples_filled*bps], start_offset, getsamples, env); | |
| 1112 | ✗ | samples_filled += getsamples; | |
| 1113 | ✗ | startframe = (iteration+1) * length; | |
| 1114 | ✗ | general_offset = 0; // On the following loops, general offset should be 0, as we are either skipping. | |
| 1115 | } | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | ✗ | AVSValue __cdecl SelectRangeEvery::Create(AVSValue args, void* user_data, IScriptEnvironment* env) { | |
| 1119 | AVS_UNUSED(user_data); | ||
| 1120 | ✗ | return new SelectRangeEvery(args[0].AsClip(), args[1].AsInt(1500), args[2].AsInt(50), args[3].AsInt(0), args[4].AsBool(true), env); | |
| 1121 | } | ||
| 1122 |