Leave SIGPIPE disposition unchanged so Python can handle a disconnected output pipe as EPIPE instead of terminating the editor. Add a native regression test that verifies the ignored disposition and a write to a closed pipe.
Validation: 50 CrashHandler, Logger, and Timeline tests passed. A Python subprocess exits with signal 13 using the installed library and survives the same closed-pipe write using the rebuilt library.
Persist canvas or geometry location units per clip so legacy animation is evaluated without rewriting keyframes. Keep auto behavior for new clips and add historical render and JSON regression coverage.
Align reduced preview dimensions after aspect fitting while preserving native output sizes. Pad export scaler rows and copy planes by stride, including compatibility handling for legacy GIF palettes.
Preserve delayed audio encoder timestamps, skip unavailable packets, and use actual resampler output counts. Share JPEG-range normalization with live capture and add sizing, export, audio, GIF, and color regression tests.
Preserve clip order for equal layer and position values, and route video and audio transitions according to compositing order. Cover fade directions, rounded start frames, audio gains, and JSON order preservation.
Interactive transform edits repeatedly replace growing X/Y keyframe curves.
Applying each update copied the same JSON data through several layers and
rebuilt keyframe storage from scratch, making edits increasingly expensive
as an animation accumulated points.
Move JSON values that are already owned by the loader through the existing
by-value interfaces instead of copying them again. Clip and effect loading
now share a base-field helper that reads common fields without copying all
of the derived animation data. Parsed SetJson input and nested color/point
values use the same ownership approach.
Keep allocated keyframe capacity across replacements and append sorted
points directly. Unordered input and duplicate frames still use AddPoint,
preserving ordering and replacement behavior. Existing public signatures,
virtual method layout, JSON format, and timeline locking remain unchanged.
Add two optional benchmark cases for a 720p/24fps image clip with 0 or 1,000
existing keyframes per axis. Each performs 100 successive X/Y transform
updates through Timeline::ApplyJsonDiff and reports the median of three
trials. Input preparation stays outside the measurement, and final point
counts and values are checked so a skipped update cannot look faster.
These cases belong to the separate benchmark executable, not normal CTest
runs. Report Ops/s because an operation can now be a JSON edit or a frame.
Document the reproduction commands and local before/after measurements.
The measured cost per update fell from 0.82 to 0.33 ms for the initially
empty curves and from 17.99 to 6.73 ms for curves starting at 1,000 points.
These isolate native JSON application; they do not measure GUI rendering
or guarantee the same performance on other machines.
Add regression coverage for caller-owned JSON, sorted and unordered input,
duplicate and fractional frames, interpolation handles, large curve
replacement, multiple actions in one diff, unchanged properties, and cache
invalidation.
Validation: rebuilt the library, benchmark, and affected test executables;
all 197 KeyFrame, Timeline, Clip, Point, Color, ColorGrade, Mask, and
EffectMask tests passed in 6.2 seconds. Both remaining transform benchmark
cases also completed successfully. The slower 5,000-point benchmark case
is intentionally omitted.
Add severity levels and environment configuration, preserve source aliases and raw crash-log output, and remove ZeroMQ build dependencies. Document the API and cover filtering, environment precedence, concurrent writes, and Python bindings.
Position PulseAudio and WASAPI loopback samples relative to recording start, dropping stale audio and preserving gaps without delaying subsequent sound. Request smaller PulseAudio fragments and tolerate bounded timestamp jitter to avoid crackling at packet boundaries.
Add regression coverage for both capture clocks, pre-recording buffers, late packets, gaps, queue overflow, reset, and sample continuity.
Serialize the FFmpeg capture Open path with GetFrame and Close using the
existing recursive mutex. Close still signals cancellation before waiting,
but cannot free a context while avformat_open_input or decoder setup uses it.
Clean up partially initialized resources on failure or cancellation.
Add a hardware-independent regression test that pauses a V4L2 open inside
FFmpeg and requests Close from another thread. It reproduces SIGSEGV with
the original implementation and passes with the fix, including 20 repeated
runs. All 15 camera/screen capture test cases pass (78 assertions).
Real-device AppImage validation remains necessary after rebuilding.
Sentry-related fix:
- OPENSHOT-BV93 (confirmed deletion path): Read a clip's position and duration
before removing it, since removal can immediately free the timeline-owned clip.
Additional coverage:
- Verify that deletion invalidates the former clip range without clearing
unrelated cached frames.
- Verify that repeating an already-completed deletion is harmless.
Validation: 518 native tests pass, with two unavailable VAAPI hardware tests
explicitly skipped. The deletion regression covers seven assertions. Valgrind
reported four invalid reads before the fix and zero errors after it.
The paired openshot-qt branch passes 598 Python tests, and Jonathan's manual
editing tests were reported stable.
This summary records the fix in the preceding commit. BV93 also contains other
crash stacks, so this does not claim the entire Sentry issue group is resolved.