Skip to content

mlv_lite: reallocate buffers after a recording stops on its own - #298

Open
ServerDestroyer wants to merge 1 commit into
reticulatedpines:devfrom
ServerDestroyer:mlv-lite-rearm-after-autostop
Open

mlv_lite: reallocate buffers after a recording stops on its own#298
ServerDestroyer wants to merge 1 commit into
reticulatedpines:devfrom
ServerDestroyer:mlv-lite-rearm-after-autostop

Conversation

@ServerDestroyer

Copy link
Copy Markdown

What

One guard in raw_rec_polling_cbr(): if both memory suites are gone while
raw video is active and idle, ask for a reallocation.

Why

Recording cleanup frees both suites unconditionally. The only thing that sets
realloc in the polling CBR is a change in the state fingerprint built from
LiveView, movie mode, resolution and friends — and finishing a recording
changes none of those. Raw video is therefore left enabled with no buffers at
all.

The intended re-arm exists: the record task calls PauseLiveView /
ResumeLiveView on the way out, which writes PROP_LV_ACTION and would flip
the fingerprint. On DIGIC 6/7/8 that write is dropped when the property is
not in the port's whitelist, and prop_request_change gives no indication,
so the re-arm silently never happens.

In that state the next REC press starts a recording with zero slots and hangs
the camera. Opening and closing the ML menu is an accidental cure: losing
LiveView takes the free branch just above, and closing the menu triggers a
full realloc and re-probe.

Setting realloc directly when both suites are missing closes the gap
regardless of whether the property write landed. The guards on the
reallocation itself (RAW_IS_IDLE || RAW_IS_PREPARING, gui_state == GUISTATE_IDLE, the semaphore and UI lock) are untouched — this only schedules
work the polling CBR was already able and allowed to do.

How tested

  • Builds clean for 6D2.111 with -Werror
    (gcc-arm-embedded 15.2.1, ML_MODULES="raw_video/mlv_lite"), no new
    warnings.

  • Validated on a real 6D2 (2026-08-15), two logged sessions on the same
    build lineage, before and after.

    Before (diagnostic build without this guard): after a take auto-stopped on
    buffer exhaustion, the polling CBR logged
    No memory suites. lv=1 movie=1 gui=0 rawact=1 rec=0 suites=0/0 once a
    second for seven seconds — raw video active, both suites gone, exactly the
    dead state described above. Pressing REC then logged rec=1 suites=0/0:
    recording started with zero slots and froze the camera hard enough to
    require a battery pull. The take before it (M15-1934.MLV, 57 frames)
    finalized normally, so the failure is specific to the post-stop state.

    After (same build plus this guard): zero dead-state lines logged. The
    re-arm fired ~1 s after the take auto-stopped (t = 12.1 s), the camera
    stayed responsive, powered off cleanly at t = 17 s, and
    M15-1945.MLV (57 frames) recorded and finalized normally.

    Confirmed again on a later session with the back-to-back case the guard
    exists for: two takes five seconds apart, the second pressed immediately
    after the first stopped on its own. Both recorded 57/57 frames
    (206,857,216 B each), frame numbers 0..56 contiguous with no gaps or
    duplicates, timestamps strictly monotonic, both headers finalized. The two
    subsequent takes in the same session ran longer still (63 and 64 frames).
    Without the guard this is the sequence that required a battery pull.

Risk

  • The condition is narrow: it needs both suites NULL, raw video active, and
    the recorder idle. During recording or while any buffer is still held, it
    cannot fire.
  • Worst case if it fires spuriously is one extra reallocation pass, which is
    the same work the state-fingerprint path already performs on every menu
    close.
  • Not 6D2-specific. The free-on-stop and the fingerprint-only realloc trigger
    are body-agnostic; the dropped PROP_LV_ACTION write makes it certain on
    DIGIC 6/7/8, but any body where the re-arm write does not take effect ends
    up in the same dead state.
  • Known remaining hazard, out of scope here: pressing REC during the brief
    window while the suites are legitimately 0/0 still starts a zero-slot
    recording. A refuse-to-start guard in the record path is the defensive
    follow-up if this proves insufficient; on the validated build the re-arm
    closed the window fast enough that it was never observed.

Stopping a raw recording frees both memory suites unconditionally, but the
only thing that triggers a reallocation in the polling CBR is a change in the
state fingerprint built from LiveView, movie mode, resolution and friends.
Finishing a recording changes none of those, so raw video is left enabled
with no buffers at all. The intended re-arm is the PauseLiveView /
ResumeLiveView pair in the record task, which writes PROP_LV_ACTION; on DIGIC
6/7/8 that write is dropped when the property is not whitelisted, and the
re-arm silently never happens.

In that state the next REC press starts a recording with zero slots and
hangs the camera. Opening and closing the ML menu happens to cure it, because
losing LiveView takes the free branch above and closing the menu reallocates.

Ask for a reallocation directly when both suites are gone while raw video is
active and idle. The existing guards on the realloc below are unchanged, so
this only schedules work the polling CBR was already able to do.

Hardware validation on a 6D2 (2026-08-15): before the change, a diagnostic
build logged "suites=0/0 rawact=1" at 1 Hz for seven seconds after an
auto-stop, and pressing REC in that state froze the camera hard enough to
need a battery pull. With the change, the re-arm fires about a second after
the take auto-stops, no dead-state lines are logged at all, and the following
take records and finalizes normally.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ServerDestroyer

Copy link
Copy Markdown
Author

Cross-reference for reviewers: the dropped PROP_LV_ACTION write described under Why is the same D678 whitelist behaviour addressed in #295. The two are independent — #295 stops prop_request_change_wait() burning its full timeout on a denied write, while this one closes the resulting dead state — and this guard is deliberately written so it does not depend on #295 landing, since the re-arm is restored regardless of whether the property write ever takes effect.

Both were validated on the same 6D2 sessions; #295's effect is visible in those logs as the (!!!) denial markers completing instantly instead of stalling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant