| 512 | } |
| 513 | |
| 514 | std::shared_ptr<openshot::Frame> EffectBase::ProcessFrame(std::shared_ptr<openshot::Frame> frame, int64_t frame_number) { |
| 515 | // Audio-only effects skip common mask handling. |
| 516 | if (!info.has_video || !mask_reader) |
| 517 | return GetFrame(frame, frame_number); |
| 518 | |
| 519 | // Effects that already apply masks inside GetFrame() should bypass common blend handling. |
| 520 | if (HandlesMaskInternally()) |
| 521 | return GetFrame(frame, frame_number); |
| 522 | |
| 523 | auto pre_image = frame->GetImage(); |
| 524 | if (!pre_image || pre_image->isNull()) |
| 525 | return GetFrame(frame, frame_number); |
| 526 | |
| 527 | const auto original_image = std::make_shared<QImage>(pre_image->copy()); |
| 528 | auto output_frame = GetFrame(frame, frame_number); |
| 529 | if (!output_frame) |
| 530 | return output_frame; |
| 531 | auto effected_image = output_frame->GetImage(); |
| 532 | if (!effected_image || effected_image->isNull() || |
| 533 | effected_image->size() != original_image->size()) |
| 534 | return output_frame; |
| 535 | |
| 536 | auto mask_image = GetMaskImage(effected_image, frame_number); |
| 537 | if (!mask_image || mask_image->isNull()) |
| 538 | return output_frame; |
| 539 | |
| 540 | if (UseCustomMaskBlend(frame_number)) |
| 541 | ApplyCustomMaskBlend(original_image, effected_image, mask_image, frame_number); |
| 542 | else |
| 543 | BlendWithMask(original_image, effected_image, mask_image); |
| 544 | |
| 545 | return output_frame; |
| 546 | } |
| 547 | |
| 548 | /// Parent clip object of this reader (which can be unparented and NULL) |
| 549 | openshot::ClipBase* EffectBase::ParentClip() { |
no test coverage detected