| 355 | } |
| 356 | |
| 357 | int64_t EffectBase::MapMaskFrameNumber(int64_t frame_number) { |
| 358 | if (!mask_reader) |
| 359 | return frame_number; |
| 360 | |
| 361 | int64_t requested_index = std::max(int64_t(0), frame_number - 1); |
| 362 | if (!clip && ParentTimeline()) { |
| 363 | const double host_fps = ResolveMaskHostFps(); |
| 364 | if (host_fps > 0.0) { |
| 365 | const int64_t start_offset = static_cast<int64_t>(std::llround(std::max(0.0f, Start()) * host_fps)); |
| 366 | requested_index = std::max(int64_t(0), requested_index - start_offset); |
| 367 | } |
| 368 | } |
| 369 | int64_t mapped_index = requested_index; |
| 370 | |
| 371 | if (mask_time_mode == MASK_TIME_SOURCE_FPS && |
| 372 | mask_reader->info.fps.num > 0 && mask_reader->info.fps.den > 0) { |
| 373 | const double host_fps = ResolveMaskHostFps(); |
| 374 | const double source_fps = mask_reader->info.fps.ToDouble(); |
| 375 | if (host_fps > 0.0 && source_fps > 0.0) { |
| 376 | const double seconds = static_cast<double>(requested_index) / host_fps; |
| 377 | mapped_index = static_cast<int64_t>(std::llround(seconds * source_fps)); |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | const int64_t source_len = mask_reader->info.video_length; |
| 382 | const double source_fps = (mask_reader->info.fps.num > 0 && mask_reader->info.fps.den > 0) |
| 383 | ? mask_reader->info.fps.ToDouble() : 30.0; |
| 384 | const double source_duration = ResolveMaskSourceDuration(); |
| 385 | const double start_sec = std::min<double>(std::max(0.0f, Start()), source_duration); |
| 386 | const double end_sec = std::min<double>(std::max(0.0f, End()), source_duration); |
| 387 | |
| 388 | const int64_t range_start = std::max(int64_t(1), static_cast<int64_t>(std::llround(start_sec * source_fps)) + 1); |
| 389 | int64_t range_end = (end_sec > 0.0) |
| 390 | ? static_cast<int64_t>(std::llround(end_sec * source_fps)) + 1 |
| 391 | : source_len; |
| 392 | if (source_len > 0) |
| 393 | range_end = std::min(range_end, source_len); |
| 394 | if (range_end < range_start) |
| 395 | range_end = range_start; |
| 396 | |
| 397 | const int64_t range_len = std::max(int64_t(1), range_end - range_start + 1); |
| 398 | int64_t range_index = mapped_index; |
| 399 | |
| 400 | switch (mask_loop_mode) { |
| 401 | case MASK_LOOP_REPEAT: |
| 402 | range_index = mapped_index % range_len; |
| 403 | break; |
| 404 | case MASK_LOOP_PING_PONG: |
| 405 | if (range_len > 1) { |
| 406 | const int64_t cycle_len = (range_len * 2) - 2; |
| 407 | int64_t phase = mapped_index % cycle_len; |
| 408 | if (phase >= range_len) |
| 409 | phase = cycle_len - phase; |
| 410 | range_index = phase; |
| 411 | } else { |
| 412 | range_index = 0; |
| 413 | } |
| 414 | break; |