|
| 1 | +# Asynchronous remote stills |
| 2 | + |
| 3 | +Version 0.93 adds Bun `RemoteFrame.encodeImageAsync`, `saveAsync` and |
| 4 | +`saveDngAsync`, plus C/Zig native image encoding jobs. They cover main/lores |
| 5 | +JPEG, PNG, TIFF, BMP, PPM and GIF and calibrated raw DNG through Home codecs. |
| 6 | + |
| 7 | +```ts |
| 8 | +const job = remote.saveAsync('trail.jpeg', { |
| 9 | + quality: 98, |
| 10 | + maxInputBytes: 64 * 1024 * 1024, |
| 11 | + maxOutputBytes: 64 * 1024 * 1024, |
| 12 | + maxWorkingBytes: 128 * 1024 * 1024, |
| 13 | +}) |
| 14 | +remote.close() // Admission already owns pixels and needed metadata. |
| 15 | +// Low-level callers still acknowledge/retire their source export separately. |
| 16 | +await job |
| 17 | +``` |
| 18 | + |
| 19 | +Admission synchronously copies selected physical used bytes (including used row |
| 20 | +padding), requested ICC/Exif and any metadata needed for request-derived Exif. |
| 21 | +The worker owns no camera, lease, remote map, fd or caller metadata pointer. |
| 22 | +Conversion, metadata generation, compression and file staging run on the native |
| 23 | +worker. Owned encoded bytes and completed files outlive source closure. Bun owns |
| 24 | +option snapshots before admission and rechecks private read permission after all |
| 25 | +application accessors. Writable remote scopes reject admission. |
| 26 | + |
| 27 | +`encodeImageAsync` accepts the synchronous image options, byte limits and ordinary |
| 28 | +Bun job options. `saveAsync(path, options, stream)` preserves the existing main/ |
| 29 | +lores save signature and extension inference. `saveDngAsync(path, jobOptions)` |
| 30 | +selects raw. JPEG still defaults to source-request Exif; PNG/TIFF opt in with |
| 31 | +`exif: true`, and explicit fields override defaults. ICC interpretation checks |
| 32 | +and RGB16 precision follow the synchronous encoders. These methods do not infer |
| 33 | +values from the process pool's initialization camera. |
| 34 | + |
| 35 | +## Bounds and ownership |
| 36 | + |
| 37 | +Input/output defaults are 64 MiB, working memory 128 MiB. Each limit accepts |
| 38 | +1 byte through 256 MiB. Input counts copied physical pixels, ICC, raw Exif and needed full |
| 39 | +metadata. Working memory counts live allocator requests, including conversion, |
| 40 | +metadata, encoded bytes and native zlib workspace. Native zlib uses the caller's |
| 41 | +allocator with checked aligned allocation hooks and failure-safe partial cleanup. |
| 42 | +An output ceiling can reject after compression; the working budget also applies |
| 43 | +while the output is being built. Allocator denial reports NOMEM; input/output |
| 44 | +limit violations report INVALID. |
| 45 | + |
| 46 | +Four live jobs share a 512 MiB input-plus-working reservation (including owners); |
| 47 | +byte limits can admit fewer than four. Completed handles stay charged until |
| 48 | +close. Bounds cover owned payload and allocator requests, not thread stacks, |
| 49 | +allocator bookkeeping, source storage or application-retained returned results. |
| 50 | +C state reports input bytes, encoded output size, working peak and budget denials; |
| 51 | +working/output telemetry is published only after the worker finishes. |
| 52 | + |
| 53 | +C `zc_remote_frame_encode_async` accepts optional limits and an optional existing |
| 54 | +staged-file owner. Poll state, optionally cancel, then take a byte result once or |
| 55 | +finish the staged file. Keep that file alive until image-job close. Close returns |
| 56 | +BUSY until the worker finishes, consumes only on success and joins before freeing |
| 57 | +input/workspace. Zig `ImageEncodeJob` preserves that retryable ownership. Native |
| 58 | +callers serialize API entries against close. |
| 59 | + |
| 60 | +Cancellation is cooperative between codec stages; an active codec call completes |
| 61 | +before cleanup joins. Bun remains responsive during native encoding. An accepted |
| 62 | +cancellation/deadline suppresses file publication and joins job/file disposal |
| 63 | +before terminal completion and callbacks. Native staged files retain inode checks |
| 64 | +against substitution. Publication claims the irreversible decision before rename; |
| 65 | +late cancellation can be refused. Existing destinations survive admission, |
| 66 | +encoding, budget, cancellation and staging failures. |
| 67 | + |
| 68 | +A process handler must await its image jobs before returning. Process termination |
| 69 | +is an external boundary: files already published cannot be rolled back, and a |
| 70 | +process killed while owning a named temporary may leave that temporary behind. |
| 71 | +Parent-controlled cross-process publication/cleanup and file-like destinations |
| 72 | +remain open. These cooperative job guarantees do not claim rollback after SIGKILL. |
| 73 | + |
| 74 | +Software coverage includes all 14 processed layouts and 46 raw layouts, exact |
| 75 | +synchronous/async bytes, independent DNG/Exif/ICC readback, early source retirement, |
| 76 | +actual child processes, input/output/workspace denial, completion-held admission, |
| 77 | +native result transfer, event-loop responsiveness, deadline/cancellation cleanup, |
| 78 | +callbacks and accessor reentry. Full parity and physical Pi acceptance remain open. |
| 79 | + |
| 80 | +Local validation passes 445 native ReleaseSafe tests with an explicit macOS 15 |
| 81 | +target and all 1,418 Bun tests with Home codecs/AAC, independent media readers and |
| 82 | +SDL dummy. Independent C ABI/export/channel/process exec checks, TypeScript, |
| 83 | +pinned formatting and workflow YAML validation pass. The normal local build |
| 84 | +runner still fails macOS SDK/libSystem linkage before project compilation; its |
| 85 | +failure is retained separately. Hosted platform, real-backend and Home/APNG |
| 86 | +consumer checks remain independent publication gates. |
0 commit comments