Repository navigation
Expand file tree
/
Copy pathzig_camera.h
More file actions
1762 lines (1741 loc) · 129 KB
/
Copy pathzig_camera.h
File metadata and controls
1762 lines (1741 loc) · 129 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef ZIG_CAMERA_H
#define ZIG_CAMERA_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ZC_ABI_VERSION 1
#define ZC_MAX_BUFFERS 32
#define ZC_MAX_PLANES 4
#define ZC_MAX_FRAME_REFERENCES 256
/* Negative results, stable across platforms. */
enum { ZC_OK=0, ZC_INVALID=-1, ZC_STATE=-2, ZC_TIMEOUT=-3, ZC_BUSY=-4,
ZC_STALE=-5, ZC_IO=-6, ZC_NOMEM=-7, ZC_UNSUPPORTED=-8, ZC_DEVICE=-9, ZC_CANCELLED=-10, ZC_DISCONNECTED=-11 };
enum { ZC_FIFO=0, ZC_LATEST=1 };
enum { ZC_SYNTHETIC=0, ZC_LIBCAMERA=1 };
/* Zero dimensions select libcamera's default still size. Set both or neither.
* All other fields must be initialized with zc_default_config(). */
typedef struct {
uint32_t width, height, buffer_count, camera_index, policy;
uint32_t exposure_us, frame_duration_us;
float analogue_gain, lens_position; /* exposure and gain: both zero or both positive; lens: -1 auto */
uint32_t raw; /* optional paired raw stream */
char raw_format[32]; /* empty = libcamera default; e.g. SRGGB12 */
} zc_config;
typedef struct {
const uint8_t *data;
uint64_t length, bytes_used, offset;
int32_t fd; /* borrowed DMA-BUF; -1 for synthetic. Never close this fd. */
uint32_t reserved;
} zc_plane;
typedef struct {
uint32_t width, height, stride, plane_count;
char format[32]; /* processed: BGR888/RGB888/XBGR8888/XRGB8888/YUV420/YVU420/NV12/NV21/YUYV/YVYU/UYVY/VYUY/BGR161616/RGB161616; raw: negotiated name */
zc_plane planes[ZC_MAX_PLANES];
} zc_stream;
typedef struct {
uint64_t token, sequence, timestamp_ns;
uint32_t exposure_us;
float analogue_gain, red_gain, blue_gain;
zc_stream main, raw;
} zc_frame;
typedef struct {
uint32_t backend, buffer_count;
zc_stream main, raw; /* plane pointers/fds are empty; geometry describes negotiated config */
char camera_id[256];
} zc_info;
typedef struct {
uint64_t completed, delivered, dropped, errors;
uint32_t ready, leased;
} zc_stats;
enum { ZC_STILL=0, ZC_PREVIEW=1, ZC_VIDEO=2 };
/* Additive API: all original ABI v1 layouts and functions remain unchanged. */
typedef struct {
uint32_t struct_size, role, unpacked_raw, noise_reduction; /* NR: 0..4, UINT32_MAX = role default */
} zc_capture_options;
typedef struct zc_camera zc_camera;
typedef struct zc_capture_allocator zc_capture_allocator;
/* Persistent capture backing. backend must match this library. Synthetic uses
* ordinary owned RAM; libcamera uses Linux DMA heaps with no RAM fallback.
* max_entries: 1..16; max_bytes: 1..8 GiB (default 512 MiB). */
typedef struct {
uint32_t struct_size,backend,max_entries,reserved;
uint64_t max_bytes;
} zc_capture_allocator_config;
typedef struct {
uint32_t struct_size,backend,max_entries,entries;
uint32_t borrowed,pins,retiring,reserved;
uint64_t max_bytes,used_bytes,high_bytes,preparations,reuses,retired;
uint64_t allocations,writable_maps,cleanup_errors;
int32_t last_errno;
uint32_t closing;
} zc_capture_allocator_state;
void zc_default_capture_allocator_config(zc_capture_allocator_config *);
int zc_capture_allocator_open(const zc_capture_allocator_config *,const uint8_t *heap_path,uint32_t path_length,zc_capture_allocator **out);
/* Explicitly provisioned Linux FD imports. No fallback allocation/eviction.
* Inputs remain caller-owned; keep them stable/inactive through import. Success
* owns CLOEXEC duplicates; callers may close their descriptors afterwards.
* Relinquish outside CPU/device access until these imported resources retire;
* do not concurrently use them through another owner or allocator.
* Each frame needs a distinct underlying object (aliases are rejected even for
* disjoint ranges). Whole object sizes count against max_bytes. Offsets/frame
* ends fit uint32 SDK ranges. Synthetic inputs must be sealed against grow and
* shrink; real inputs must support DMA_BUF_IOCTL_SYNC. Import cleanup failures
* retain an entry/budget for trim/close retry. Never discard the allocator owner
* after a failed import. Exact negotiated configuration/stream order is the key.
* Provision another independent set for overlapping same-layout reconnects. */
typedef struct {
uint32_t width,height,stride,buffer_count;
uint64_t frame_bytes,modifier;
char format[32];
} zc_capture_import_stream;
typedef struct { int32_t fd; uint32_t reserved; uint64_t offset; } zc_capture_import_buffer;
/* One frame may use disjoint planes of a shared object, independent objects,
* or a mixture. Each physical object is charged/duplicated/mapped once; objects
* may not alias across frames/entries. Plane ends must fit SDK uint32 ranges.
* Use count 1 for any existing contiguous format, 2 for linear NV12/NV21 or
* 3 for linear YUV420/YVU420. Extra declared capacity is allowed, overlapping
* ranges are not. Objects remain application-owned until import returns. */
typedef struct { int32_t fd; uint32_t reserved; uint64_t offset,length; } zc_capture_import_plane;
typedef struct { uint32_t struct_size,plane_count; zc_capture_import_plane planes[4]; } zc_capture_import_frame;
typedef struct {
uint32_t struct_size,backend,stream_count,id_length;
uint8_t camera_id[4096];
zc_capture_import_stream streams[3]; /* main, optional lores, optional raw */
} zc_capture_import_layout;
/* Owned scalar snapshot of the actual SDK frameSize/stride/count/modifier and
* full ID. Query a configured camera; no capture/start is required. */
int zc_camera_capture_layout_get(zc_camera *,zc_capture_import_layout *out);
int zc_capture_allocator_open_imported(const zc_capture_allocator_config *,zc_capture_allocator **out);
/* Buffers are stream-major, exactly sum(stream.buffer_count), max 3*64. */
int zc_capture_allocator_import(zc_capture_allocator *,const uint8_t *camera_id,uint32_t id_length,
const zc_capture_import_stream *,uint32_t stream_count,const zc_capture_import_buffer *,uint32_t buffer_count);
int zc_capture_allocator_import_frames(zc_capture_allocator *,const uint8_t *camera_id,uint32_t id_length,
const zc_capture_import_stream *,uint32_t stream_count,const zc_capture_import_frame *,uint32_t frame_count);
int zc_capture_allocator_state_get(zc_capture_allocator *,zc_capture_allocator_state *out);
/* Pins keep the allocator alive across camera gaps and mode/open workers.
* Each successful pin must be unpinned exactly once, after the worker joins. */
int zc_capture_allocator_pin(zc_capture_allocator *,uint64_t *out_pin);
int zc_capture_allocator_unpin(zc_capture_allocator *,uint64_t pin);
/* Trim only idle/pending-cleanup storage. Close is BUSY with loans or pins;
* IO failure retains the owner for retry. Serialize final close with new calls. */
int zc_capture_allocator_trim(zc_capture_allocator *);
int zc_capture_allocator_close(zc_capture_allocator *);
/* Native ownership for an allocation-capable worker. Success transfers initial
* camera ownership into this scope until take; null is an initial open. A scope
* is bound to one allocator and one attached native thread. IDs are generation
* checked, so late calls fail STALE rather than dereferencing freed wrappers.
* Detach runs after the worker body; an actual pthread exit also retires its
* attachment. Close returns BUSY with native calls/threads/factories in flight.
* Close requests fatal cancellation, retains ownership on errors, and otherwise
* closes any camera not taken. Serialize final disposal with new calls. */
typedef uint64_t zc_capture_open_scope;
typedef struct {
uint32_t struct_size,stage,started,threads;
uint32_t active,pending_factories,cancelled,aborted;
zc_camera *camera;
} zc_capture_open_scope_state;
int zc_capture_open_scope_open(zc_capture_allocator *,zc_camera *initial,uint32_t started,uint32_t timeout_ms,zc_capture_open_scope *out);
int zc_capture_open_scope_attach(zc_capture_open_scope);
int zc_capture_open_scope_detach(zc_capture_open_scope);
int zc_capture_open_scope_state_get(zc_capture_open_scope,zc_capture_open_scope_state *out);
int zc_capture_open_scope_cancel(zc_capture_open_scope,uint32_t fatal);
int zc_capture_open_scope_take(zc_capture_open_scope,zc_camera **out,uint32_t *started);
int zc_capture_open_scope_close(zc_capture_open_scope);
/* Imported-pool allocation notification. Register before cameras/scopes/pins
* start. The notification returns void; it never returns buffers synchronously.
* Only a scoped native opening waits for its factory. begin claims one ticket,
* supply duplicates inputs and reserves that exact loan, finish follows joined
* producer/input cleanup. Always finish a successful begin, including cancelled
* notifications; tickets retain allocator/scope ownership until both actors
* retire. Nonzero finish codes report failure; do not reuse finished tickets. */
typedef void (*zc_capture_allocator_factory_notify)(void *context,uint64_t ticket);
typedef struct {
uint32_t struct_size,accepting,restoring,cancelled;
zc_capture_open_scope scope;
} zc_capture_factory_request_state;
int zc_capture_allocator_factory_set(zc_capture_allocator *,zc_capture_allocator_factory_notify,void *context);
int zc_capture_allocator_factory_begin(zc_capture_allocator *,uint64_t ticket,zc_capture_import_layout *out,zc_capture_factory_request_state *state);
int zc_capture_allocator_factory_supply(zc_capture_allocator *,uint64_t ticket,const zc_capture_import_buffer *,uint32_t count);
int zc_capture_allocator_factory_supply_frames(zc_capture_allocator *,uint64_t ticket,const zc_capture_import_frame *,uint32_t count);
int zc_capture_allocator_factory_finish(zc_capture_allocator *,uint64_t ticket,int32_t result);
/* Pipeline extensions preserve zc_config/zc_frame/zc_info ABI v1 layouts.
* Explicit sensor selection requires both size and bit depth. Zero = automatic.
* Lores: both dimensions zero disable; YUV420 requires even dimensions.
* Its negotiated size must not exceed main. All three streams share one lease. */
enum { ZC_MAIN=0, ZC_RAW=1, ZC_LORES=2 };
/* Processed format names use libcamera FourCC; constants describe memory bytes.
* RGB48/BGR48 contain three little-endian u16 words (BGR161616/RGB161616). */
enum { ZC_YUV420=0, ZC_RGB24=1, ZC_BGR24=2, ZC_RGBX32=3, ZC_BGRX32=4, ZC_YVU420=5, ZC_NV12=6, ZC_NV21=7, ZC_YUYV=8, ZC_YVYU=9, ZC_UYVY=10, ZC_VYUY=11, ZC_RGB48=12, ZC_BGR48=13 };
/* Negotiated color values, not configuration defaults. Zero means unknown.
* Decoding YCbCr converts encoded R'G'B' values; it does not transform primaries
* or transfer functions. present=0 means the pipeline supplied no color space. */
enum { ZC_PRIMARIES_RAW=1,ZC_PRIMARIES_SMPTE170M=2,ZC_PRIMARIES_REC709=3,ZC_PRIMARIES_REC2020=4 };
enum { ZC_TRANSFER_LINEAR=1,ZC_TRANSFER_SRGB=2,ZC_TRANSFER_REC709=3 };
enum { ZC_YCBCR_NONE=1,ZC_YCBCR_REC601=2,ZC_YCBCR_REC709=3,ZC_YCBCR_REC2020=4 };
enum { ZC_RANGE_FULL=1,ZC_RANGE_LIMITED=2 };
typedef struct { uint32_t struct_size,present,primaries,transfer,ycbcr_encoding,range; } zc_color_space;
int zc_get_stream_color_space(zc_camera *,uint32_t stream,zc_color_space *out);
typedef struct {
uint32_t struct_size;
zc_capture_options capture;
uint32_t sensor_width, sensor_height, sensor_bit_depth;
uint32_t lores_width, lores_height, lores_format;
} zc_pipeline_options;
typedef struct { uint32_t width,height,bit_depth; char format[32]; } zc_sensor_mode;
typedef struct {
uint32_t struct_size,sensor_width,sensor_height,sensor_bit_depth;
zc_stream lores;
} zc_pipeline_info;
void zc_default_pipeline_options(zc_pipeline_options *);
/* Shared processed-stream color request. present=0 selects the legacy default recipe and
* requires zero color components and strict_color=0. RGB normalizes the requested
* matrix/range to none/full while preserving primaries/transfer. YUV requires a
* matrix. Raw primaries cannot describe processed streams. */
typedef struct { uint32_t struct_size,main_format,strict_color; zc_color_space color_space; } zc_processed_options;
enum { ZC_COLOR_SRGB=1,ZC_COLOR_SYCC=2,ZC_COLOR_SMPTE170M=3,ZC_COLOR_REC709=4,ZC_COLOR_REC2020=5,ZC_COLOR_RAW=6 };
void zc_default_processed_options(zc_processed_options *);
int zc_color_space_preset(uint32_t preset,zc_color_space *out);
int zc_check_processed_options(const zc_processed_options *,const zc_pipeline_options *);
/* Allocation-free structural preflight shared by open. Does not negotiate with
* hardware or validate a camera identity/sensor's available modes. */
int zc_check_camera_configuration(const zc_config *,const zc_pipeline_options *,const zc_processed_options *,uint32_t orientation,uint32_t strict_orientation);
/* Explicit geometry planning, without opening/negotiating a device or changing
* pixels/strides. Profiles use Picamera2's VC4/PiSP recipes. optimal=0 uses 2x2.
* Positive extents which round to zero reject. Failure preserves every output. */
enum { ZC_ALIGN_VC4=0, ZC_ALIGN_PISP=1 };
enum { ZC_ALIGN_PACKED=0, ZC_ALIGN_PLANAR420=1, ZC_ALIGN_WIDE=2 };
typedef struct { uint32_t struct_size,width,height,width_alignment,height_alignment; } zc_stream_alignment;
int zc_align_stream_geometry(uint32_t width,uint32_t height,uint32_t layout,uint32_t profile,uint32_t optimal,zc_stream_alignment *out);
/* Align explicit main/lores geometry, preserve auto 0/0 and raw/sensor settings,
* then run structural preflight. Outputs must be disjoint from each other; they
* may replace their respective input objects in place. No hardware acceptance. */
int zc_align_camera_configuration(const zc_config *,const zc_pipeline_options *,const zc_processed_options *,uint32_t profile,uint32_t optimal,zc_config *out_config,zc_pipeline_options *out_pipeline);
/* Existing config/stream/frame layouts remain ABI v1. Strict color rejects
* backend adjustments against the format-normalized effective request. */
int zc_open_processed_pipeline(const zc_config *,const zc_pipeline_options *,const zc_processed_options *,uint32_t orientation,uint32_t strict_orientation,zc_camera **out);
int zc_open_id_processed_pipeline(const zc_config *,const zc_pipeline_options *,const zc_processed_options *,uint32_t orientation,uint32_t strict_orientation,const uint8_t *id,uint32_t length,zc_camera **out);
/* Null ID + zero length selects camera_index. Allocator backing is retained
* through every request/map/export lease and reused only after camera close. */
int zc_open_allocated_pipeline(const zc_config *,const zc_pipeline_options *,const zc_processed_options *,uint32_t orientation,uint32_t strict_orientation,const uint8_t *id,uint32_t length,zc_capture_allocator *,zc_camera **out);
/* Attached-thread operations. The scope owns every opened camera until take;
* restoring suppresses ordinary cancellation/deadline during source recovery. */
int zc_open_allocated_scoped_pipeline(zc_capture_open_scope,const zc_config *,const zc_pipeline_options *,const zc_processed_options *,uint32_t orientation,uint32_t strict_orientation,const uint8_t *id,uint32_t length,uint32_t restoring,zc_camera **out);
int zc_capture_open_scope_stop_camera(zc_capture_open_scope scope);
int zc_capture_open_scope_start_camera(zc_capture_open_scope);
int zc_camera_capture_allocator_get(zc_camera *,zc_capture_allocator **out_borrowed);
/* flags: configured=1, strict=2, RGB-normalized=4, backend-adjusted=8.
* Absent/unknown actual metadata counts as adjusted for configured requests.
* main/lores only; requested/effective are absent for backend-default requests. */
typedef struct { uint32_t struct_size,flags,format,reserved; zc_color_space requested,effective,actual; } zc_color_negotiation;
int zc_get_color_negotiation(zc_camera *,uint32_t stream,zc_color_negotiation *out);
/* Exact UTF-8 backend ID selection. ID bytes are nonempty, at most 4096 bytes,
* with no NUL or terminator. cfg.camera_index must be zero; never falls back.
* Old config/ABI layouts remain unchanged. Copy returns the full selected ID;
* null/zero queries length, short buffers reject without writing a prefix. */
#define ZC_MAX_CAMERA_ID 4096
/* A watch pins the backend manager without acquiring a camera. Open before
* discovery; subsequent events invalidate discovery snapshots. No initial added
* events or atomic snapshot/event boundary is promised. Each event is consumed
* once. missed is a cumulative eviction/invalid-ID count; rescan on any change.
* RESCAN carries no ID. Other IDs are exact length-delimited UTF-8, never cut.
* Capacity is 1..64; at most 32 live watches per backend. Callbacks only copy to
* preallocated storage. stop retires callbacks/releases the manager and wakes
* waiters; queued events remain readable, then wait returns CANCELLED. close
* stops first and returns BUSY while waits remain; retry after joining them.
* Synchronize all other entries with close. Failed wait leaves out untouched.
* Choose custom tuning BEFORE opening a watch, using a tuning session. */
enum { ZC_CAMERA_ADDED=1, ZC_CAMERA_REMOVED=2, ZC_CAMERA_RESCAN=3 };
typedef struct zc_camera_watch zc_camera_watch;
typedef struct {
uint32_t struct_size,backend,kind,id_length;
uint64_t sequence,missed;
uint8_t id[ZC_MAX_CAMERA_ID];
} zc_camera_event;
typedef struct {
uint32_t struct_size,backend,capacity,queued;
uint64_t sequence,missed;
uint32_t stopped,waiters;
} zc_camera_watch_state;
int zc_camera_watch_open(uint32_t backend,uint32_t capacity,zc_camera_watch **out);
int zc_camera_watch_wait(zc_camera_watch *,uint32_t timeout_ms,zc_camera_event *out);
int zc_camera_watch_get_state(zc_camera_watch *,zc_camera_watch_state *out);
int zc_camera_watch_stop(zc_camera_watch *);
int zc_camera_watch_close(zc_camera_watch *);
/* Scoped synthetic event injection; does not change discovery/capture topology.
* Real watches reject UNSUPPORTED. Invalid input does not mutate the queue. */
int zc_camera_watch_simulate_event(zc_camera_watch *,uint32_t kind,const uint8_t *id,uint32_t length);
/* Caller-owned, serialized Home retry policy on a supplied monotonic ns clock.
* 1..1024 attempts; no allocation/timers/I/O. Poll returns 1 for a claim, 0 when
* not due/exhausted, negative on invalid state without mutation.
* First claim waits initial_ns, later failures use capped exponential backoff.
* Observe failure at completion to arm without shifting the next deadline;
* success clears the deadline, never the lifetime attempt budget. */
typedef struct {
uint32_t struct_size,max_attempts,attempts,armed;
uint64_t initial_ns,maximum_ns,deadline_ns;
} zc_recovery_retry;
int zc_recovery_retry_init(uint32_t max_attempts,uint64_t initial_ns,uint64_t maximum_ns,zc_recovery_retry *out);
int zc_recovery_retry_poll(zc_recovery_retry *,uint64_t now_ns,uint32_t failed);
int zc_recovery_retry_observe(zc_recovery_retry *,uint64_t now_ns,uint32_t failed);
/* Owned JSON tuning data; does not apply an ISP policy. Native limits are
* 16 MiB, 262144 scanner tokens and 64 container levels. Number text is exact.
* Copy/find NULL+0 queries required length; short outputs remain untouched.
* Mutations are serialized and transactional. Close requires caller lifetime
* coordination. Missing algorithms return UNSUPPORTED; ambiguous/invalid data
* returns INVALID. Old ABI layouts are unchanged. */
typedef struct zc_tuning_document zc_tuning_document;
int zc_tuning_document_open(const uint8_t *,uint64_t length,zc_tuning_document **out);
int zc_tuning_document_version(zc_tuning_document *,uint32_t *out);
int zc_tuning_document_copy(zc_tuning_document *,uint8_t *data,uint64_t capacity,uint64_t *length);
int zc_tuning_document_find(zc_tuning_document *,const uint8_t *name,uint32_t name_length,uint8_t *data,uint64_t capacity,uint64_t *length);
int zc_tuning_document_replace(zc_tuning_document *,const uint8_t *name,uint32_t name_length,const uint8_t *json,uint64_t length);
void zc_tuning_document_close(zc_tuning_document *);
/* A process/backend-wide immutable tuning reservation, acquired BEFORE camera
* discovery/open. Equal byte snapshots share; conflicting/default live managers
* reject BUSY. Retain across worker reopens. Untuned opens inherit the manager's
* policy. Only the Raspberry Pi IPA consumes this file; synthetic tests lifecycle.
* Close may fail on cleanup and then retains the handle for retry. */
typedef struct zc_tuning_session zc_tuning_session;
typedef struct {
uint32_t struct_size,backend,custom,manager_users,session_users,environment_active,cleanup_pending,external_change;
int32_t last_error;
uint32_t reserved;
uint64_t generation,bytes;
} zc_tuning_state;
int zc_tuning_session_open(const uint8_t *json,uint64_t length,uint32_t backend,zc_tuning_session **out);
int zc_tuning_session_close(zc_tuning_session *);
int zc_get_tuning_state(uint32_t backend,zc_tuning_state *out);
int zc_tuning_cleanup(uint32_t backend);
int zc_open_id_pipeline(const zc_config *, const zc_pipeline_options *, const uint8_t *id, uint32_t length, zc_camera **out);
int zc_get_camera_id(zc_camera *, uint8_t *data, uint32_t capacity, uint32_t *length);
int zc_open_pipeline(const zc_config *,const zc_pipeline_options *,zc_camera **);
/* libcamera orientation values. Rotations are clockwise. Request rotation first,
* then flips along output axes and optional final diagonal transposition with
* zc_orientation_from_transform. Already
* transformed pixels must not receive the orientation again as an EXIF tag. */
enum { ZC_ROTATE0=1,ZC_ROTATE0_MIRROR=2,ZC_ROTATE180=3,ZC_ROTATE180_MIRROR=4,
ZC_ROTATE90_MIRROR=5,ZC_ROTATE270=6,ZC_ROTATE270_MIRROR=7,ZC_ROTATE90=8 };
typedef struct { uint32_t struct_size,requested,actual,adjusted; } zc_orientation_info;
int zc_orientation_from_transform(uint32_t rotation,uint32_t hflip,uint32_t vflip,uint32_t transpose,uint32_t *out);
/* strict is 0 (accept/report pipeline adjustments) or 1 (require exact orientation).
* Existing config/stream layouts remain unchanged; width/height are requested
* output dimensions. Sensor dimensions remain physical. Raw CFA order and raw
* geometry are negotiated and reported by get_info, never assumed from input. */
int zc_open_oriented_pipeline(const zc_config *,const zc_pipeline_options *,uint32_t orientation,uint32_t strict,zc_camera **out);
int zc_open_id_oriented_pipeline(const zc_config *,const zc_pipeline_options *,uint32_t orientation,uint32_t strict,const uint8_t *id,uint32_t length,zc_camera **out);
/* Main format is one of the ZC_YUV420..ZC_VYUY processed formats. RGB24 is
* the legacy default. 4:2:0 requires even dimensions; packed 4:2:2 requires
* even width, with odd height permitted; negotiated format/stride must remain supported.
* RGB and 4:2:0 plane descriptors share the existing ABI v1 layouts. Color space
* is negotiated and queried with zc_get_stream_color_space, never guessed. */
int zc_open_formatted_pipeline(const zc_config *,const zc_pipeline_options *,uint32_t main_format,uint32_t orientation,uint32_t strict,zc_camera **out);
int zc_open_id_formatted_pipeline(const zc_config *,const zc_pipeline_options *,uint32_t main_format,uint32_t orientation,uint32_t strict,const uint8_t *id,uint32_t length,zc_camera **out);
int zc_get_orientation(zc_camera *,zc_orientation_info *out);
int zc_get_pipeline_info(zc_camera *,zc_pipeline_info *);
/* Cached discovery: no reconfiguration or capture interruption. Query with
* NULL/0 first. count is total; insufficient capacity returns INVALID. Formats
* advertise raw outputs, not measured FPS, exposure or optical guarantees. */
int zc_get_sensor_modes(zc_camera *,zc_sensor_mode *,uint32_t capacity,uint32_t *count);
/* Borrowed descriptor valid only for this lease. Disabled stream: UNSUPPORTED. */
int zc_get_stream(zc_camera *,uint64_t token,uint32_t stream,zc_stream *);
/* Opt in before the first start. DMA CPU access uses READ|WRITE for this whole
* handle and every mapping must permit writes. Default handles remain READ-only.
* Failure preserves read capture; never silently substitutes read-only access. */
int zc_enable_writable(zc_camera *);
int zc_frame_readable(zc_camera *,uint64_t token);
int zc_copy_frame_rgb(zc_camera *,uint64_t token,uint8_t *out,uint64_t length);
/* Packed RGB/BGR/RGBX/BGRX main/lores or planar/semi-planar 4:2:0 or packed 4:2:2 converted into tight RGB24.
* All planes and destination are validated before writing; raw is unsupported. */
int zc_copy_stream_rgb(zc_camera *,uint64_t token,uint32_t stream,uint8_t *out,uint64_t length);
/* Scoped maps retain their own generation-checked frame reference. Read maps
* share; write maps require writable mode and exactly one external owner. A
* writer excludes stream reads and retention until close. Metadata remains usable.
* Map count shares the existing bounded reference pool/producer reservation.
* Returned stream pointers are borrowed until map close, which consumes even on
* DMA/requeue failure. Never access escaped views after close or race CPU access. */
typedef struct zc_frame_map zc_frame_map;
int zc_frame_map_open(zc_camera *,uint64_t token,uint32_t stream,uint32_t write,zc_frame_map **out);
int zc_frame_map_stream(const zc_frame_map *,zc_stream *out);
/* Other streams under the same scoped access gate. No additional lease/writer. */
int zc_frame_map_get_stream(const zc_frame_map *,uint32_t stream,zc_stream *out);
int zc_frame_map_close(zc_frame_map *);
/* Tight owned copies preserve byte layout (RGB/BGR/RGBX/BGRX); YUV420/YVU420/NV12/NV21 preserve plane order; Bayer => unchanged
* unpacked samples, CSI-2 packed rows or PiSP COMP1 blocks, with row padding removed.
* Raw packing and monochrome/Bayer order remain unchanged. The size query never dereferences plane pointers. */
int zc_stream_copy_size(const zc_stream *,uint64_t *bytes);
int zc_copy_stream(const zc_stream *,uint8_t *out,uint64_t length);
typedef struct {
uint32_t valid; /* bit 0 black levels, bit 1 CCM, bit 2 white balance */
float black_levels[4]; /* R, Gr, Gb, B; normalized to a 16-bit range */
float camera_to_srgb[9]; /* libcamera ColourCorrectionMatrix; WB is separate */
char model[128];
} zc_raw_metadata;
/* IMX708 sensor HDR is a pre-open layout control, distinct from runtime HdrMode.
* Exact ID and index selection are mutually exclusive; UINT32_MAX means automatic
* first matching IMX708. Explicit synthetic backend models ownership only.
* At most 16 helpers may own descriptors. Mutations require every camera,
* discovery scope and manager watch in this process to have closed; BUSY never
* resets an active manager. Later camera opens obtain a fresh mode catalog.
* Flags preserve observations even on failed/partially applied writes. Unknown
* current/previous values remain absent. Close does not reset the sensor mode.
* Per-helper operations require caller serialization; close returns BUSY while
* an operation is entered. No HDR quality or hardware acceptance is implied. */
/* Logical-client scopes protect sensor layouts across native close/reopen jobs.
* Native sessions and Bun Camera owners retain these automatically. Up to 64
* additional explicit scopes may be retained; close each exactly once. */
typedef struct zc_sensor_layout_scope zc_sensor_layout_scope;
int zc_sensor_layout_scope_open(uint32_t backend,zc_sensor_layout_scope **out);
int zc_sensor_layout_scope_close(zc_sensor_layout_scope *);
int zc_sensor_layout_users_get(uint32_t backend,uint32_t *count);
typedef struct zc_imx708 zc_imx708;
enum { ZC_SENSOR_HDR_CURRENT=1,ZC_SENSOR_HDR_PREVIOUS=2,ZC_SENSOR_HDR_CHANGED=4,ZC_SENSOR_HDR_WRITE_ATTEMPTED=8,ZC_SENSOR_HDR_WRITE_SUCCEEDED=16,ZC_SENSOR_HDR_CATALOG_INVALIDATED=32,ZC_SENSOR_HDR_SYNTHETIC=64 };
typedef struct {uint32_t struct_size,backend,flags;int32_t system_errno;uint64_t manager_generation;uint32_t enabled,previous_enabled;} zc_sensor_hdr_state;
int zc_imx708_open(uint32_t backend,uint32_t index,const uint8_t *id,uint32_t id_length,zc_imx708 **out);
int zc_imx708_camera_id(zc_imx708 *,uint8_t *,uint64_t capacity,uint64_t *length);
int zc_imx708_get_hdr_mode(zc_imx708 *,zc_sensor_hdr_state *);
int zc_imx708_set_hdr_mode(zc_imx708 *,uint32_t enabled,zc_sensor_hdr_state *);
int zc_imx708_close(zc_imx708 *);
/* Independent pinned IMX500 control descriptor. Cached ROI is not proof of
* per-frame hardware application. Close preserves the kernel's cached state. */
typedef struct zc_imx500 zc_imx500;
typedef struct {uint32_t struct_size,flags;int64_t minimum,maximum;uint64_t step;int64_t default_value;} zc_imx500_control_info;
enum {ZC_IMX500_PREVIOUS=1,ZC_IMX500_CURRENT=2,ZC_IMX500_SAVED=4,ZC_IMX500_WRITE_ATTEMPTED=8,ZC_IMX500_WRITE_SUCCEEDED=16,ZC_IMX500_CHANGED=32,ZC_IMX500_SYNTHETIC=64,ZC_IMX500_CAPABILITIES=128,ZC_IMX500_PREVIOUS_ROI=256,ZC_IMX500_CURRENT_ROI=512,ZC_IMX500_SAVED_ROI=1024,ZC_IMX500_STATE=2048};
typedef struct {
uint32_t struct_size,backend,flags;int32_t system_errno;
uint64_t revision;
zc_imx500_control_info control;
uint32_t previous[4],current[4],saved[4];
int32_t previous_roi[4],current_roi[4],saved_roi[4];
} zc_imx500_state;
int zc_imx500_open(uint32_t backend,uint32_t index,const uint8_t *id,uint32_t length,zc_imx500 **out);
int zc_imx500_camera_id(zc_imx500 *,uint8_t *,uint64_t capacity,uint64_t *length);
int zc_imx500_get_roi(zc_imx500 *,zc_imx500_state *);
int zc_imx500_set_roi(zc_imx500 *,int32_t x,int32_t y,uint32_t width,uint32_t height,zc_imx500_state *);
int zc_imx500_set_aspect(zc_imx500 *,uint32_t width,uint32_t height,zc_imx500_state *);
int zc_imx500_restore_roi(zc_imx500 *,zc_imx500_state *);
int zc_imx500_device_id(zc_imx500 *,uint32_t output[4]);
int zc_imx500_close(zc_imx500 *);
/* Typed bounded runtime controls. IDs map to libcamera names in docs/controls.md.
* Query support/ranges; a batch is validated atomically and staged for the next
* recycled request. Already queued frames and sensor pipeline latency remain.
* ControlRevision denotes request submission, not proof of physical application. */
enum { ZC_BOOL=1,ZC_INT=2,ZC_FLOAT=3,ZC_RECT=4,ZC_MAX_CONTROLS=32 };
enum { ZC_AE_ENABLE=1,ZC_EXPOSURE_TIME,ZC_ANALOGUE_GAIN,ZC_EXPOSURE_VALUE,
ZC_AWB_ENABLE,ZC_COLOUR_GAINS,ZC_BRIGHTNESS,ZC_CONTRAST,ZC_SATURATION,
ZC_SHARPNESS,ZC_FRAME_DURATION_LIMITS,ZC_LENS_POSITION,ZC_AF_MODE,ZC_AF_TRIGGER,
ZC_AF_RANGE,ZC_AF_SPEED,ZC_AF_METERING,ZC_AF_WINDOWS,ZC_SCALER_CROP,
ZC_NOISE_REDUCTION,ZC_AE_METERING,ZC_AE_EXPOSURE,ZC_AWB_MODE,
ZC_EXPOSURE_TIME_MODE,ZC_ANALOGUE_GAIN_MODE,ZC_AF_PAUSE,ZC_AE_CONSTRAINT,
ZC_COLOUR_TEMPERATURE,ZC_AE_FLICKER_MODE,ZC_AE_FLICKER_PERIOD,ZC_HDR_MODE,ZC_CONTROL_COUNT };
enum { ZC_HDR_OFF=0,ZC_HDR_SINGLE_EXPOSURE=1,ZC_HDR_MULTI_EXPOSURE=2,ZC_HDR_NIGHT=3,ZC_HDR_MULTI_EXPOSURE_UNMERGED=4 };
typedef struct {uint32_t id,type,count,reserved;double values[16];} zc_control;
typedef struct {
uint32_t id,type,min_count,max_count;
double min[4],max[4],def[4]; uint64_t enum_mask;
} zc_control_info;
typedef struct {
uint32_t struct_size,valid; /* AF=1, lens=2, duration=4, crop=8, capture-clock timestamp=16, AF pause=32, exposure=64 */
uint64_t event_id,sequence,timestamp_ns,control_revision;
uint32_t exposure_us; int32_t af_state,af_pause_state; uint32_t reserved;
float analogue_gain,lens_position,red_gain,blue_gain;
uint64_t frame_duration_us; int32_t crop[4];
} zc_metadata;
/* Tight multi-stream request snapshot. Layouts are in caller-selected order;
* offsets/lengths index one caller-owned byte buffer. No camera pointers escape.
* 1..3 distinct enabled main/raw/lores IDs are required. All sources and output
* capacity are validated under the request lock before any pixel is copied.
* data=NULL/capacity=0 queries size and layouts; other insufficient capacity
* returns INVALID. On failure only *size becomes zero; other outputs stay intact.
* The caller owns the lease across query/copy and provides disjoint output
* buffers which do not alias source pixels, IDs or each other. */
typedef struct {
uint32_t stream,width,height,row_bytes; char format[32];
uint64_t offset,length;
} zc_packed_stream;
int zc_copy_frame_streams(zc_camera *,uint64_t token,const uint32_t *streams,uint32_t count,
zc_packed_stream *layouts,uint32_t layout_capacity,uint8_t *data,uint64_t capacity,
uint64_t *size,zc_metadata *metadata);
/* Consumer-owned bounded selection state; initialize once, serialize access and
* use within one camera completion timeline. Never edits/recycles a request.
* Timestamp is inclusive; EXPOSURE_GUARD subtracts exposure_us*1000, saturating
* at zero. Required timing must be explicitly valid, otherwise UNSUPPORTED.
* Repeated/out-of-order completion events do not consume more drops.
* SYNC_READY also requires explicitly true per-request SyncReady; false/absent
* waits. Backend/query errors preserve filter state. Acceptance is terminal. */
enum { ZC_CAPTURE_TIMESTAMP=1, ZC_CAPTURE_EXPOSURE_GUARD=2, ZC_CAPTURE_SYNC_READY=4 };
/* Exact request-local software-sync metadata. valid: ready=1, timer=2.
* Missing values stay absent; timer is signed microseconds to the ready time.
* Failure clears out. This reads the backend algorithm's status; it does not
* synchronize cameras or infer readiness from host timestamps. */
typedef struct { uint32_t struct_size,valid,ready,reserved; int64_t timer_us; } zc_frame_sync_state;
int zc_get_frame_sync_state(zc_camera *,uint64_t token,zc_frame_sync_state *out);
typedef struct {
uint32_t struct_size,remaining,flags,observed;
uint64_t after_ns,last_event;
} zc_capture_filter;
int zc_capture_filter_init(zc_capture_filter *,uint32_t drop_frames,uint32_t flags,uint64_t after_ns);
/* Same-clock first-pixel timestamps, 2..8 streams. Masked candidates must be
* released/replaced by the caller; no sensor or clock synchronization is done.
* Invalid arguments preserve output. Equality at tolerance qualifies. */
typedef struct {
uint32_t struct_size,replace_mask;
uint64_t earliest_ns,latest_ns,skew_ns;
} zc_frame_match;
int zc_match_frame_timestamps(const uint64_t *,uint32_t count,uint64_t tolerance_ns,zc_frame_match *);
/* Linux BOOTTIME, Darwin virtual-camera MONOTONIC; never wall-clock time. */
int zc_capture_clock_ns(uint64_t *out);
/* Relative idle delay in one caller-supplied monotonic ns domain. Queries update
* the last observation; regression/overflow preserve state. Caller serializes.
* Initialize before use. Remaining is zeroed on failure; reserved must be zero. */
typedef struct { uint64_t started_ns,last_ns,deadline_ns; uint32_t armed,reserved; } zc_capture_delay;
void zc_default_capture_delay(zc_capture_delay *);
int zc_capture_delay_arm(zc_capture_delay *,uint64_t now_ns,uint64_t duration_ns);
int zc_capture_delay_remaining(zc_capture_delay *,uint64_t now_ns,uint64_t *remaining_ns);
int zc_capture_filter_accept(zc_camera *,uint64_t token,zc_capture_filter *);
/* Releases every rejected frame; success transfers one owner. timeout=0 tries
* one frame. Filter progress is retained on TIMEOUT; out stays untouched. */
int zc_acquire_filtered(zc_camera *,zc_capture_filter *,uint32_t timeout_ms,zc_frame *out);
int zc_get_control_info(zc_camera *,uint32_t id,zc_control_info *);
/* Copied, sorted persistent requests (AF trigger/pause excluded). Null/zero queries
* count/revision. Small buffers reject without copying. Revisions are logical
* request submissions, not physical application acknowledgements. */
int zc_get_controls(zc_camera *,zc_control *,uint32_t capacity,uint32_t *count,uint64_t *revision);
/* Replay atomically before the FIRST start on a fresh handle, once only. Rejects
* one-shot controls. The base carries revision continuity across reopened modes.
* Invalid/unsupported replay leaves the fresh handle retryable. Empty replay
* seeds the base without issuing controls. Never mutates an already-used handle. */
int zc_restore_controls(zc_camera *,const zc_control *,uint32_t count,uint64_t base_revision,uint64_t *revision);
int zc_set_controls(zc_camera *,const zc_control *,uint32_t count,uint64_t *revision);
int zc_get_frame_metadata(zc_camera *,uint64_t token,zc_metadata *);
/* Observer only: consumes no frame. event_id is monotonic across restart.
* Wait/AF wait must have returned before close; stop wakes all observers. */
int zc_wait_metadata(zc_camera *,uint64_t after_event,uint32_t timeout_ms,zc_metadata *);
enum { ZC_AF_PENDING=1,ZC_AF_SCANNING=2,ZC_AF_SUCCEEDED=3,ZC_AF_FAILED=4,
ZC_AF_CANCELLED=5,ZC_AF_STOPPED=6 };
/* Continuous AF requires an explicit accepted AfMode=2 setting. Pause commands:
* immediate=0, deferred=1, resume=2. Wait/cancel use the same AF ID namespace.
* Pause success acknowledges Paused, resume success acknowledges Running, at or
* after the submitted revision. Cancellation restores the prior accepted intent.
* Restore supersedes this owned pause with a fresh job for its previous intent.
* One-shot pause intent is not included in persistent mode replay. */
enum { ZC_AF_PAUSE_IMMEDIATE=0,ZC_AF_PAUSE_DEFERRED=1,ZC_AF_PAUSE_RESUME=2 };
int zc_autofocus_pause_start(zc_camera *,uint32_t command,uint64_t *job_id);
int zc_autofocus_pause_restore(zc_camera *,uint64_t job_id,uint64_t *restore_job_id);
/* Requires a successful pause job. Filters stale/unpaused frames and releases
* every rejection. require_focused=1 also requires AF metadata reporting Focused;
* paused scanning/failed => STATE, absent AF metadata => UNSUPPORTED.
* Later focus controls/resume invalidate the token.
* Validate an existing lease with the same predicate; TIMEOUT means this frame
* is older/unpaused. Does not acquire, release or mutate the frame. */
int zc_focus_locked_validate(zc_camera *,uint64_t job_id,uint64_t token,uint32_t require_focused);
/* Acquire variant releases all rejected frames. timeout=0 tries one frame. */
int zc_acquire_focus_locked(zc_camera *,uint64_t job_id,uint32_t require_focused,uint32_t timeout_ms,zc_frame *);
int zc_autofocus_start(zc_camera *,uint64_t *job_id);
int zc_autofocus_cancel(zc_camera *,uint64_t job_id);
int zc_autofocus_wait(zc_camera *,uint64_t job_id,uint32_t timeout_ms,uint32_t *state);
/* Owned immutable HCAT v1 snapshots, bounded to 4 MiB. Query/copy is atomic:
* null/zero obtains size; too-small destinations remain untouched. Close after
* use; snapshots outlive camera/frame close. Unknown backend types retain bytes.
* backend: ZC_LIBCAMERA=1 or ZC_SYNTHETIC=0, never implicit fallback. */
enum { ZC_CATALOG_DISCOVERY=1, ZC_CATALOG_PROPERTIES=2, ZC_CATALOG_CONTROLS=3, ZC_CATALOG_METADATA=4, ZC_CATALOG_CONTROL_STATE=5, ZC_CATALOG_CONTROL_UPDATE=6, ZC_CATALOG_CONFIGURATION=7 };
enum { ZC_CATALOG_INPUT=1, ZC_CATALOG_OUTPUT=2, ZC_CATALOG_ARRAY=4,
ZC_CATALOG_DIRECTION_KNOWN=8, ZC_CATALOG_EXTENT_KNOWN=16,
ZC_CATALOG_VENDOR_KNOWN=32, ZC_CATALOG_ENUMERATORS_KNOWN=64 };
enum { ZC_CONTROL_NO_REPLAY=128, ZC_MAX_NATIVE_CONTROLS=256 };
enum { ZC_CATALOG_CURRENT=0, ZC_CATALOG_MINIMUM=1, ZC_CATALOG_MAXIMUM=2,
ZC_CATALOG_DEFAULT=3, ZC_CATALOG_CHOICE=4, ZC_CATALOG_ENUMERATOR=5 };
typedef struct zc_catalog zc_catalog;
int zc_discover(uint32_t backend, zc_catalog **out);
/* HCAT control-update (6) inputs, control-state (5) snapshots. One current value
* per record, native IDs, <=256 records / 4 MiB. Flag 128 excludes replay. Native
* and convenience controls share revisions; typed state is owned by Zig. Restore
* is pre-start only; optional convenience restore must precede typed restore. */
int zc_set_native_controls(zc_camera *,const uint8_t *,uint64_t,uint64_t *revision);
int zc_get_native_controls(zc_camera *,zc_catalog **out,uint64_t *revision);
int zc_restore_native_controls(zc_camera *,const uint8_t *,uint64_t,uint64_t base,uint64_t *revision);
int zc_camera_properties(zc_camera *, zc_catalog **out);
int zc_camera_controls(zc_camera *, zc_catalog **out);
int zc_frame_metadata_catalog(zc_camera *, uint64_t token, zc_catalog **out);
/* CNN-only owned metadata snapshot; 4..64 MiB float-payload ceiling, multiple
* of four. Skips unrelated values and remains valid after source retirement. */
int zc_frame_cnn_catalog(zc_camera *,uint64_t token,uint64_t max_output_bytes,zc_catalog **out);
/* CNN values are contiguous float32. Tensor geometry counts elements; offset
* is relative to the complete output. Default column order matches the RPi
* exported metadata; explicit row order reorders values and strides together. */
enum { ZC_CNN_COLUMN_MAJOR=0,ZC_CNN_ROW_MAJOR=1 };
typedef struct { uint32_t count,rank;uint64_t offset;uint32_t shape[16];uint64_t strides[16]; } zc_cnn_tensor;
typedef struct {
uint32_t struct_size,present,tensor_count,frame_count;
uint32_t network_name_length,order;
uint64_t value_count;
uint8_t network_name[64];
zc_cnn_tensor tensors[16];
} zc_cnn_outputs_info;
/* NULL/0 output queries the descriptor. Errors preserve descriptor and output
* values. Output may not alias source bytes or the output descriptor. */
int zc_decode_cnn_outputs(const uint8_t *info,uint64_t info_length,const uint8_t *values,uint64_t values_length,uint32_t big_endian,uint32_t order,uint64_t max_output_bytes,zc_cnn_outputs_info *,float *output,uint64_t capacity);
int zc_cnn_catalog_outputs(const zc_catalog *,uint32_t order,uint64_t max_output_bytes,zc_cnn_outputs_info *,float *output,uint64_t capacity);
int zc_cnn_tensor_row_major(const zc_cnn_tensor *,uint32_t source_order,const float *source,uint64_t count,float *output,uint64_t capacity);
/* Stateless staged sensor/raw/scaler/ISP projection. Flags: ROI=1. Geometry
* and results are values; no camera/model owner is retained. Errors preserve
* caller outputs. Normalized coordinates are four doubles in y0,x0,y1,x1 order.
* Empty rectangles may retain anchors outside the canvas, as in libcamera. */
typedef struct { uint32_t width,height; } zc_inference_size;
typedef struct { int32_t x,y;uint32_t width,height; } zc_inference_rect;
typedef struct {
uint32_t struct_size,flags;
zc_inference_size full_sensor,sensor_output,isp_output;
zc_inference_rect scaler_crop,roi;
} zc_inference_geometry;
int zc_inference_project(const zc_inference_geometry *,const zc_inference_rect *,zc_inference_rect *);
int zc_inference_convert(const zc_inference_geometry *,const double *yxyx,zc_inference_rect *);
int zc_inference_roi(const zc_inference_geometry *,zc_inference_rect *);
int zc_inference_aspect(const zc_inference_size *,const zc_inference_size *,zc_inference_rect *);
/* Signed counters exactly as the libcamera int32[2] control. The double view
* follows Picamera2's /1000 conversion; it is not independently calibrated time. */
typedef struct {uint32_t struct_size,present;int32_t dnn_raw,dsp_raw;double picamera_dnn_ms,picamera_dsp_ms;} zc_cnn_kpi_info;
int zc_decode_cnn_kpi(const uint8_t *,uint64_t length,uint32_t big_endian,zc_cnn_kpi_info *);
int zc_cnn_kpi_catalog(const zc_catalog *,zc_cnn_kpi_info *);
int zc_frame_cnn_kpi(zc_camera *,uint64_t token,zc_cnn_kpi_info *);
/* Owned request-time recipe/negotiated configuration, <=64 KiB, HCAT kind 7.
* Full metadata additionally carries these reserved groups, vendor zig-camera.
* Startup hints are distinct from per-frame applied controls/metadata. */
#define ZC_CONFIGURATION_GROUP_BASE 0x5a430000u
int zc_frame_configuration_catalog(zc_camera *,uint64_t token,zc_catalog **out);
/* Session properties are snapshotted lazily once per camera owner, independent
* of runtime controls. Returned catalogs own exact backend bytes after close. */
int zc_frame_properties_catalog(zc_camera *,uint64_t token,zc_catalog **out);
int zc_catalog_copy(const zc_catalog *, uint8_t *data, uint64_t capacity, uint64_t *length);
void zc_catalog_close(zc_catalog *);
/* Low-level process handoff owner. Hold until every consumer has unmapped and
* acknowledged completion or its process has verifiably exited. Duplication of
* an fd does not extend the camera lease. This API does not supervise children.
* Caller serializes get/copy/close; close consumes even on DMA/requeue errors.
* Real DMA descriptors are duplicated (no pixel copy). fd-less sources stage
* bytes_used into zero-initialized anonymous shared memory; writable staging
* copies used bytes back before retiring the exclusive native map.
* Export info contains no pointers. fd fields are borrowed from this owner:
* never close them or access buffers after export close. CLOEXEC on every fd.
* At most 32 exports and 512 MiB declared plane bytes+catalog are admitted. */
#define ZC_MAX_EXPORT_PLANES 12
enum { ZC_EXPORT_WRITABLE=1, ZC_EXPORT_STAGED=2 };
typedef struct zc_frame_export zc_frame_export;
typedef struct { uint32_t stream,width,height,stride,plane_count,first_plane; char format[32]; } zc_export_stream;
typedef struct { int32_t fd; uint32_t flags; uint64_t offset,length,bytes_used; } zc_export_plane;
typedef struct {
uint32_t struct_size,stream_count,plane_count,flags;
zc_metadata metadata;
zc_color_space colors[3];
zc_export_stream streams[3];
zc_export_plane planes[ZC_MAX_EXPORT_PLANES];
} zc_export_info;
/* streams is a nonempty mask of (1u<<ZC_MAIN/RAW/LORES); flags only WRITABLE.
* Each export's declared planes are capped at 256 MiB, metadata at 4 MiB. */
int zc_frame_export_open(zc_camera *,uint64_t token,uint32_t streams,uint32_t flags,zc_frame_export **out);
int zc_frame_export_info(const zc_frame_export *,zc_export_info *out);
int zc_frame_export_catalog_copy(const zc_frame_export *,uint8_t *,uint64_t capacity,uint64_t *length);
/* Immutable request-time configuration projected from the retained full catalog. */
int zc_frame_export_configuration_copy(const zc_frame_export *,uint8_t *,uint64_t capacity,uint64_t *length);
/* Properties embedded in this export's existing full metadata. Legacy absence
* => UNSUPPORTED/length=0. Copies reject malformed, short or overlapping output. */
int zc_frame_export_properties_copy(const zc_frame_export *,uint8_t *,uint64_t capacity,uint64_t *length);
/* Immutable request-time calibration; validity bits preserve unavailable fields. */
int zc_frame_export_raw_metadata(const zc_frame_export *,zc_raw_metadata *out);
int zc_frame_export_close(zc_frame_export *);
/* Local Linux/Darwin 64-bit little-endian descriptor channel, no process
* supervision. Pair/duplicate return owned CLOEXEC descriptors; close once.
* All I/O is nonblocking: TIMEOUT means empty/full queue, no partial send.
* Hold the sending export until remote maps are closed and ACK or peer exit
* verified. ACK cookies must be unique among live sends. Sending does not
* transfer/retire the export owner. Calls on each owner must be serialized. */
typedef struct zc_remote_frame zc_remote_frame;
typedef struct zc_image_blob zc_image_blob;
int zc_frame_channel_pair(int32_t out[2]);
int zc_frame_channel_duplicate(int32_t borrowed,int32_t *out);
int zc_frame_channel_close(int32_t owned);
int zc_frame_channel_send(int32_t channel,const zc_frame_export *,uint64_t cookie);
int zc_frame_channel_receive(int32_t channel,zc_remote_frame **out,uint64_t *cookie);
/* Send ACK only AFTER closing the remote frame and its borrowed views.
* These primitives do not associate acknowledgements with sender owners. */
int zc_frame_channel_ack(int32_t channel,uint64_t cookie);
int zc_frame_channel_receive_ack(int32_t channel,uint64_t *cookie);
int zc_remote_frame_info(const zc_remote_frame *,zc_export_info *out);
int zc_remote_frame_catalog_copy(const zc_remote_frame *,uint8_t *,uint64_t capacity,uint64_t *length);
/* Borrowed mapped planes; const/read-only unless export is WRITABLE. Mapping
* does not extend sender camera ownership. Close views before remote close. */
int zc_remote_frame_stream(const zc_remote_frame *,uint32_t stream,zc_stream *out);
/* Independent tight RGB8/RGB16 copies through Home conversions. Query with
* data=NULL,capacity=0; raw is unsupported. No borrowed pixels escape. */
int zc_remote_frame_copy_rgb(const zc_remote_frame *,uint32_t stream,uint32_t bits,uint8_t *data,uint64_t capacity,uint64_t *length);
/* Missing configuration namespace => UNSUPPORTED, zero length; pixels remain usable. */
int zc_remote_frame_configuration_copy(const zc_remote_frame *,uint8_t *,uint64_t capacity,uint64_t *length);
int zc_remote_frame_properties_copy(const zc_remote_frame *,uint8_t *,uint64_t capacity,uint64_t *length);
/* Exact calibration from the sender. Legacy v1 records return zero validity. */
int zc_remote_frame_raw_metadata(const zc_remote_frame *,zc_raw_metadata *out);
/* Tight owned bundle in caller order, removing padding but preserving format/
* plane order/packing. Query data=NULL,capacity=0. No output prefix on failure. */
int zc_remote_frame_copy_streams(const zc_remote_frame *,const uint32_t *ids,uint32_t count,zc_packed_stream *layouts,uint32_t layout_capacity,uint8_t *data,uint64_t capacity,uint64_t *size);
/* Concatenate physical bytes_used in plane order, preserving used padding. */
int zc_remote_frame_copy_buffer(const zc_remote_frame *,uint32_t stream,uint8_t *data,uint64_t capacity,uint64_t *length);
/* Home raw decoder, tight LE u16 without scaling or demosaicing; <=256 MiB. */
int zc_remote_frame_copy_raw16(const zc_remote_frame *,uint8_t *data,uint64_t capacity,uint64_t *length);
/* Existing calibrated DNG writer; no inferred calibration. Owned encoded blob
* <=256 MiB, or streaming atomic file (including used rows, no full pixel copy).
* Calls are synchronous; process cancellation does not roll back a saved file. */
int zc_remote_frame_encode_dng(const zc_remote_frame *,zc_image_blob **out);
int zc_remote_frame_save_dng(const zc_remote_frame *,const char *path);
int zc_remote_frame_close(zc_remote_frame *);
/* Failed shared-memory unmaps retain their original bounded admission and
* physical mapping after the public export/remote handle is consumed. Do not
* retry close or access those handles. This process-wide cleanup API reports
* deferred owners only; live handles are excluded. Each drain attempts at most
* 32 export and 32 remote owners once, without writeback or camera lease work.
* Concurrent drains claim distinct owners. IO reports an attempted failure;
* BUSY means owners remain (including another drain), otherwise OK. A later
* close can add work after this call; this is not a camera/session fence. */
typedef struct {
uint32_t struct_size,exports,remote_frames,busy;
uint64_t retained_bytes;
} zc_shared_cleanup_state;
int zc_shared_cleanup_state_get(zc_shared_cleanup_state *out);
int zc_shared_cleanup_drain(void);
/* Supervised processing ownership. Up to 8 sessions, 8 workers/session and 32
* tasks/session; args <=16 MiB, reserved results <=256 MiB and aggregate <=512 MiB. Native owns
* exports and argument bytes after successful submit; failure consumes neither.
* Workers have monotonic generations. ACK is read from the selected channel.
* stop_worker quarantines only; it never permits retiring sent tasks. The host
* MUST await verified child exit before worker_joined. No OS process is spawned
* or joined by these C primitives. Each session's calls must be serialized. */
typedef struct zc_process_session zc_process_session;
typedef struct {uint32_t struct_size,workers,pending,queued,active,retired,live_workers,reserved;uint64_t bytes,issued,released;} zc_process_state;
typedef struct {uint32_t pending,accepting,joined,reserved;uint64_t generation,active;} zc_process_worker_state;
int zc_process_open(uint32_t workers,uint32_t items,uint64_t bytes,zc_process_session **out);
/* BUSY retains session until all tasks released and all peers verified joined. */
int zc_process_close(zc_process_session *);
/* Non-reserving preflight; submit revalidates atomically after source export. */
int zc_process_can_submit(zc_process_session *,uint64_t args_bytes,uint64_t reserved_result_bytes);
int zc_process_submit(zc_process_session *,zc_frame_export *owned,const uint8_t *args,uint64_t length,uint64_t reserved_result_bytes,uint64_t *cookie,uint32_t *worker,uint64_t *generation);
int zc_process_next(zc_process_session *,uint32_t worker,uint64_t generation,uint64_t *cookie);
int zc_process_send(zc_process_session *,uint64_t cookie,int32_t channel);
int zc_process_payload_copy(zc_process_session *,uint64_t cookie,uint8_t *,uint64_t capacity,uint64_t *length);
int zc_process_receive_ack(zc_process_session *,uint32_t worker,uint64_t generation,int32_t channel,uint64_t *cookie);
int zc_process_stop_worker(zc_process_session *,uint32_t worker,uint64_t generation);
int zc_process_worker_joined(zc_process_session *,uint32_t worker,uint64_t generation);
int zc_process_restart_worker(zc_process_session *,uint32_t worker,uint64_t generation,uint64_t *next_generation);
/* Retire closes the export/args but retains admission for completion callbacks.
* Sent tasks return BUSY until ACK or verified join. A permitted retire consumes
* resources even on I/O error. Release requires retired; frees the task slot. */
int zc_process_retire(zc_process_session *,uint64_t cookie);
int zc_process_release(zc_process_session *,uint64_t cookie);
int zc_process_get_state(zc_process_session *,zc_process_state *out);
int zc_process_get_worker_state(zc_process_session *,uint32_t worker,zc_process_worker_state *out);
int zc_process_pending_through(zc_process_session *,uint64_t target,uint32_t *pending);
uint32_t zc_abi_version(void);
void zc_default_config(zc_config *config);
/* Camera lifecycle calls must be serialized by the caller. acquire/release/stats
* may run on different threads; stop wakes waiters. close requires all leases released.
* A stopped camera keeps leased mappings valid until release; restart rejects leases. */
int zc_open(const zc_config *config, zc_camera **out);
void zc_default_capture_options(zc_capture_options *);
int zc_open_ex(const zc_config *, const zc_capture_options *, zc_camera **out);
int zc_get_raw_metadata(zc_camera *, uint64_t token, zc_raw_metadata *out);
int zc_save_dng(zc_camera *, uint64_t token, const char *path);
int zc_get_info(zc_camera *, zc_info *out);
int zc_start(zc_camera *);
int zc_acquire(zc_camera *, uint32_t timeout_ms, zc_frame *out);
/* Acquire one owned request and stop the camera without copying pixels.
* Success leaves a readable lease; release it before restart/close/reconfigure.
* Failure clears out and releases a private acquired candidate before returning;
* a cleanup error takes precedence over the stop error. Lifecycle is serialized
* by the caller as for acquire/stop. No request callbacks run in this C helper. */
int zc_acquire_and_stop(zc_camera *,uint32_t timeout_ms,zc_frame *out);
/* Distinct token for the same completed request, without copying pixels.
* Release each token once. Final release ends DMA access and recycles.
* Stats.leased counts pinned buffers, not references. Capacity is reserved for
* primary references of unleased buffers. Retains survive stop; close/restart
* reject any outstanding reference. Tokens are scoped to the issuing camera. */
int zc_retain(zc_camera *,uint64_t token,zc_frame *out);
int zc_frame_references(zc_camera *,uint64_t token,uint32_t *out);
int zc_release(zc_camera *, uint64_t token);
int zc_stop(zc_camera *);
int zc_close(zc_camera *);
/* Terminal device loss is separate from stop and generic errors. Existing
* completed leases/maps retain ownership and may still be read/released. No
* restart/requeue is allowed on a lost handle. Fence errors remain observable.
* Waiters require caller coordination with close. Synthetic injection is never
* available on a real-backend build. This does not reconnect/replace a camera. */
typedef struct {
uint32_t struct_size,connected,running,leased;
int32_t status;
uint32_t ready;
uint64_t disconnect_event;
} zc_device_state;
int zc_get_device_state(zc_camera *,zc_device_state *out);
int zc_wait_disconnected(zc_camera *,uint32_t timeout_ms,zc_device_state *out);
int zc_simulate_disconnect(zc_camera *);
/* Same close ownership contract; successful close copies final state AFTER
* callback retirement and before freeing the handle. Failure leaves out intact. */
int zc_close_with_device_state(zc_camera *,zc_device_state *out);
int zc_capture_open_scope_close_camera(zc_capture_open_scope,zc_device_state *out);
int zc_get_stats(zc_camera *, zc_stats *out);
/* quality 1..100, 4:4:4 sampling; operates on an outstanding lease, no RGB copy. */
int zc_save_jpeg(zc_camera *, uint64_t token, const char *path, uint32_t quality);
/* GIF uses an adaptive <=256-color palette. RGB16 reduces to high bytes. */
enum { ZC_IMAGE_JPEG=1,ZC_IMAGE_PNG=2,ZC_IMAGE_BMP=3,ZC_IMAGE_TIFF=4,ZC_IMAGE_PPM=5,ZC_IMAGE_DNG=6,ZC_IMAGE_GIF=7 };
enum { ZC_PNG_ADAPTIVE=0,ZC_PNG_NONE=1,ZC_PNG_SUB=2,ZC_PNG_UP=3,ZC_PNG_AVERAGE=4,ZC_PNG_PAETH=5 };
typedef struct { uint32_t struct_size,format,quality,png_compression,png_filter; } zc_image_options;
enum { ZC_IMAGE_PROFILE_SRGB=1 };
/* Bytes remain immutable/live for each synchronous call. flags=0 supplies RGB ICC bytes (<=16MiB);
* SRGB requires null data/zero length and an actual Rec709/sRGB source.
* Embedding describes samples; it never transforms their gamut or transfer. */
typedef struct { uint32_t struct_size,flags; const uint8_t *data; uint64_t length; } zc_image_profile;
int zc_check_image_profile(const zc_image_options *,const zc_image_profile *);
/* Exif payload is borrowed, immutable classic TIFF (optional Exif prefix).
* CAPTURE fills missing fields from this request; raw caller fields win.
* Null/empty flags=0 disables Exif. JPEG defaults can be requested independently
* of custom bytes. Old image/profile APIs keep their existing behavior. */
enum { ZC_IMAGE_EXIF_CAPTURE=1 };
typedef struct { uint32_t struct_size,flags; const uint8_t *data; uint64_t length; } zc_image_exif;
enum { ZC_EXIF_IMAGE=0,ZC_EXIF_PHOTO=1,ZC_EXIF_GPS=2,ZC_EXIF_INTEROP=3,ZC_EXIF_THUMBNAIL=4 };
/* TIFF types 1..12 accept little-endian field bytes. Application value types
* GPS_DECIMAL (f64; GPS tags 2,4,6) and ISO (u32; photo tag 0x8833) expand
* through Home's shared typed builders. Reserved fields must be zero. */
enum { ZC_EXIF_GPS_DECIMAL=256,ZC_EXIF_ISO=257 };
typedef struct {
uint16_t group,tag,field_type,reserved_a; uint32_t count,reserved_b;
const uint8_t *data; uint64_t length;
} zc_exif_field;
void zc_default_image_exif(zc_image_exif *);
int zc_check_image_metadata(const zc_image_options *,const zc_image_profile *,const zc_image_exif *);
void zc_default_image_options(zc_image_options *);
/* Owned bare TIFF blob from typed fields. Does not read a camera, retain input
* pointers or add capture defaults. Thumbnail bytes, if present, are copied. */
int zc_exif_build(const zc_exif_field *,uint32_t count,const uint8_t *thumbnail,uint64_t thumbnail_length,zc_image_blob **out);
/* Synchronous encode of an owned readable lease. Blob owns its encoded bytes,
* survives frame/camera release and keeps no native buffer. Caller serializes
* blob operations and closes exactly once. Output is null on encode failure. */
int zc_encode_image(zc_camera *,uint64_t token,const zc_image_options *,zc_image_blob **out);
/* Explicit source. Processed formats accept main/lores, DNG accepts raw only.
* Disabled streams reject. Existing image option layouts remain unchanged. */
int zc_encode_stream_image(zc_camera *,uint64_t token,uint32_t stream,const zc_image_options *,zc_image_blob **out);
int zc_encode_stream_image_profile(zc_camera *,uint64_t token,uint32_t stream,const zc_image_options *,const zc_image_profile *,zc_image_blob **out);
int zc_encode_stream_image_metadata(zc_camera *,uint64_t token,uint32_t stream,const zc_image_options *,const zc_image_profile *,const zc_image_exif *,zc_image_blob **out);
/* Remote request encoding: same Home options/profile/Exif policy, using owned
* request metadata. JPEG capture defaults require an enabled capture descriptor.
* Pixel conversion and encoded blobs are each <=256 MiB. Calls are serialized
* with remote close/write access. Saves atomically replace a path; child job
* cancellation does not undo publication or clean crash-orphan temporaries. */
int zc_remote_frame_encode_image_metadata(const zc_remote_frame *,uint32_t stream,const zc_image_options *,const zc_image_profile *,const zc_image_exif *,zc_image_blob **out);
int zc_remote_frame_save_image_metadata(const zc_remote_frame *,uint32_t stream,const char *path,const zc_image_options *,const zc_image_profile *,const zc_image_exif *);
int zc_image_blob_copy(const zc_image_blob *,uint8_t *data,uint64_t capacity,uint64_t *length);
void zc_image_blob_close(zc_image_blob *);
/* Atomic file replacement; explicit format does not depend on path extension.
* JPEG quality 1..100; PNG zlib level 0..9 and one of the filter policies above.
* DNG requires a supported raw stream and complete calibration. */
int zc_save_image(zc_camera *,uint64_t token,const char *path,const zc_image_options *);
int zc_save_stream_image(zc_camera *,uint64_t token,uint32_t stream,const char *path,const zc_image_options *);
int zc_save_stream_image_profile(zc_camera *,uint64_t token,uint32_t stream,const char *path,const zc_image_options *,const zc_image_profile *);
int zc_save_stream_image_metadata(zc_camera *,uint64_t token,uint32_t stream,const char *path,const zc_image_options *,const zc_image_profile *,const zc_image_exif *);
/* Staged atomic still-file output. Create copies the path and reserves an I/O
* thread without file I/O. Every created object needs finish (even if unused).
* Prepare runs synchronously on the capture owner and retains no frame. Retire
* that owner before finish/close. cancel/state may run concurrently with prepare.
* finish(1) irrevocably claims publication; finish(0) discards. Both start native
* I/O jobs. Poll finished before close, which joins and releases exactly once.
* Error/cleanup codes remain observable even if publication was already claimed.
* No durability/fsync guarantee. Crash cleanup of orphan temporaries is external. */
typedef struct zc_image_file zc_image_file;
typedef struct { uint32_t struct_size,phase,preparing,released,finished,committed; int32_t result,cleanup_code; } zc_image_file_state;
/* Bounded owned still encoding. Copies selected physical pixels, ICC/Exif and
* needed metadata at admission; no remote owner/lease/fd survives that call.
* Codec conversion/encoding and optional file staging run on a joined worker.
* Limits are per-job: input includes copied metadata, working includes ALL
* allocator-routed codec allocations and the encoded result, output caps bytes.
* Four live jobs share a 512 MiB input+working reservation, held until close.
* Cancel is cooperative at codec boundaries; close BUSY means join by polling.
* File publication remains explicit through image_file_finish AFTER completion;
* retain that file owner until the job closes. Null limits uses defaults. */
typedef struct zc_image_job zc_image_job;
typedef struct {uint32_t struct_size,reserved;uint64_t max_input_bytes,max_output_bytes,max_working_bytes;} zc_image_job_limits;
typedef struct {uint32_t struct_size,phase,finished;int32_t result;uint64_t input_bytes,output_bytes,working_peak,budget_denials;} zc_image_job_state;
void zc_default_image_job_limits(zc_image_job_limits *);
int zc_remote_frame_encode_async(const zc_remote_frame *,uint32_t stream,const zc_image_options *,const zc_image_profile *,const zc_image_exif *,const zc_image_job_limits *,zc_image_file *,zc_image_job **out);
/* Copies the selected request under its read gate, including local Exif
* provenance. The request/camera may be released immediately on success. */
int zc_encode_stream_image_async(zc_camera *,uint64_t token,uint32_t stream,const zc_image_options *,const zc_image_profile *,const zc_image_exif *,const zc_image_job_limits *,zc_image_file *,zc_image_job **out);
int zc_image_job_state_get(zc_image_job *,zc_image_job_state *);
int zc_image_job_cancel(zc_image_job *);
int zc_image_job_take_blob(zc_image_job *,zc_image_blob **out);
int zc_image_job_close(zc_image_job *);
/* Factory admission is globally bounded to 32 retained handles, including ready
* and finished handles. BUSY preserves a null output; close releases the slot
* after joining. This also bounds threads for rejected async file submissions. */
int zc_image_file_create(const char *,zc_image_file **);
int zc_image_file_prepare(zc_image_file *,zc_camera *,uint64_t token,uint32_t stream,const zc_image_options *,const zc_image_profile *);
int zc_image_file_prepare_metadata(zc_image_file *,zc_camera *,uint64_t token,uint32_t stream,const zc_image_options *,const zc_image_profile *,const zc_image_exif *);
int zc_image_file_cancel(zc_image_file *); /* 1 accepted, 0 too late/already cancelled */
/* Copy 1..256 MiB of encoded bytes, stage on the reserved I/O worker, then
* query preparation_result before finish. No source pointer survives admission.
* Shared 512 MiB reservation stays charged until close, even after completion.
* preparation_result returns TIMEOUT while pending, STATE after release; otherwise
* writes the staging result code. Failed preparation still needs discard/close. */
int zc_image_file_prepare_bytes(zc_image_file *,const uint8_t *,uint64_t length);
int zc_image_file_preparation_result(zc_image_file *,int32_t *out);
int zc_image_file_finish(zc_image_file *,uint32_t publish);
int zc_image_file_state_get(zc_image_file *,zc_image_file_state *);
int zc_image_file_close(zc_image_file *); /* BUSY until owner/job retired */
/* Borrowed input descriptors. data must be readable for the submit call only;
* submission copies active rows, never retains a camera/lease or row padding. */
enum { ZC_APNG_GRAY=0, ZC_APNG_RGB=1, ZC_APNG_RGBA=2 };
enum { ZC_APNG_DISPOSE_NONE=0, ZC_APNG_DISPOSE_BACKGROUND=1, ZC_APNG_DISPOSE_PREVIOUS=2 };
enum { ZC_APNG_BLEND_SOURCE=0, ZC_APNG_BLEND_OVER=1 };
typedef struct {
uint32_t struct_size,width,height,format,bits,big_endian;
uint64_t stride,length;
const uint8_t *data;
} zc_apng_raster;
/* General borrowed gray/RGB/RGBA8/16 raster. All calls below consume pointers
* synchronously and retain none. Active pixels/output are limited to 256 MiB.
* Conversion/crop query with data=NULL,capacity=0; failures never copy prefixes.
* Source/target overlap rejects, except identical no-op copies. Native endian
* is explicit; 8->16 replicates bytes and 16->8 selects high bytes. */
typedef zc_apng_raster zc_raster;
/* Strict 8-bit Huffman JPEG loading through Home. Sequential/progressive,
* component sampling, restarts and owned source ICC/Exif; no implicit ICC/Exif
* orientation conversion. Result pixels are gray8 or RGB8 (CMYK converted).
* Upsampling: 0 centered bilinear, 1 nearest. Unsupported coding returns UNSUPPORTED.
* Jobs copy input before return; cancellation joins checkpoints and native close.
* Result and job share the existing image admission; take transfers once. */
typedef struct zc_jpeg_image zc_jpeg_image;
typedef struct zc_jpeg_job zc_jpeg_job;
typedef struct {uint32_t struct_size,max_scans,max_markers,upsampling;uint64_t max_input_bytes,max_output_bytes,max_working_bytes,max_metadata_bytes,max_work_units;} zc_jpeg_limits;
typedef struct {uint32_t struct_size,width,height,components,progressive,scans,color_model,upsampling,sampling[4],metadata_flags,adobe_transform,reserved[2];uint64_t stride,length,working_peak,work_units;} zc_jpeg_info;
void zc_default_jpeg_limits(zc_jpeg_limits *);
int zc_jpeg_decode(const uint8_t *,uint64_t,const zc_jpeg_limits *,zc_jpeg_image **out);
int zc_jpeg_decode_async(const uint8_t *,uint64_t,const zc_jpeg_limits *,zc_jpeg_job **out);
int zc_jpeg_info_get(zc_jpeg_image *,zc_jpeg_info *);
int zc_jpeg_pixels_copy(zc_jpeg_image *,uint8_t *,uint64_t,uint64_t *);
/* metadata kind: 1 source ICC profile, 2 source Exif TIFF bytes. */
int zc_jpeg_metadata_copy(zc_jpeg_image *,uint32_t,uint8_t *,uint64_t,uint64_t *);
void zc_jpeg_close(zc_jpeg_image *);
int zc_jpeg_job_state_get(zc_jpeg_job *,zc_image_job_state *);
int zc_jpeg_job_cancel(zc_jpeg_job *);
int zc_jpeg_job_take_image(zc_jpeg_job *,zc_jpeg_image **out);
int zc_jpeg_job_close(zc_jpeg_job *);
/* Strict PNG/APNG loading. All pixel words are little endian and straight alpha.
* Default image slot is 0; animation rectangles are slots 1..frame_count.
* Scalar metadata flags: ICC=1, Exif=2, sRGB=4, gamma=8, cHRM=16, cICP=32.
* No gamma conversion, animation compositing or Exif orientation is applied.
* Owners/jobs share the image encoder's four-owner, 512 MiB admission ceiling.
* An async result retains its reservation after take and job close until its
* own close. Cancellation never publishes a partial result; join before close.
* Owner operations require caller serialization. Metadata copies: ICC=1,
* Exif=2, RGBA palette=3. A null destination queries required bytes. */
typedef struct zc_png_image zc_png_image;
typedef struct zc_png_job zc_png_job;
typedef struct {uint32_t struct_size,max_frames,max_chunks,reserved;uint64_t max_input_bytes,max_output_bytes,max_working_bytes,max_metadata_bytes;} zc_png_limits;
typedef struct {uint32_t struct_size,frame_count,default_is_frame,plays,source_depth,source_color,interlaced,palette_count;uint32_t metadata_flags,srgb,gamma,chromaticities[8],cicp[4],reserved;} zc_png_info;
typedef struct {uint32_t struct_size,width,height,format,bits,x,y,delay_num,delay_den,dispose,blend,reserved;uint64_t stride,length;} zc_png_frame_info;
void zc_default_png_limits(zc_png_limits *);
int zc_png_decode(const uint8_t *,uint64_t,const zc_png_limits *,zc_png_image **out);
int zc_png_decode_async(const uint8_t *,uint64_t,const zc_png_limits *,zc_png_job **out);
int zc_png_info_get(zc_png_image *,zc_png_info *);
int zc_png_frame_get(zc_png_image *,uint32_t slot,zc_png_frame_info *);
int zc_png_frame_copy(zc_png_image *,uint32_t slot,uint8_t *,uint64_t capacity,uint64_t *length);
int zc_png_metadata_copy(zc_png_image *,uint32_t kind,uint8_t *,uint64_t capacity,uint64_t *length);
void zc_png_close(zc_png_image *);
int zc_png_job_state_get(zc_png_job *,zc_image_job_state *);
int zc_png_job_cancel(zc_png_job *);
int zc_png_job_take_image(zc_png_job *,zc_png_image **out);
int zc_png_job_close(zc_png_job *);
/* APNG display canvas: exact RGBA8/16, little endian, straight alpha. External
* serialization required. push borrows a checked raster of matching bit depth
* for this call only. The canvas starts/reset to transparent black; disposal
* applies before the next valid push. Invalid pushes leave all state unchanged.
* Working limit (1..256 MiB) covers two full RGBA canvases. Global image admission
* is shared with PNG/image jobs. No transfers, gamma conversion or timer implied.
* copy queries with NULL,0; insufficient capacity writes nothing. close(NULL) OK. */
typedef struct zc_apng_compositor zc_apng_compositor;
int zc_apng_compositor_open(uint32_t width,uint32_t height,uint32_t bits,uint64_t max_working_bytes,zc_apng_compositor **out);
int zc_apng_compositor_push(zc_apng_compositor *,const zc_raster *,uint32_t x,uint32_t y,uint32_t dispose,uint32_t blend);
int zc_apng_compositor_copy(zc_apng_compositor *,uint8_t *,uint64_t capacity,uint64_t *length);
void zc_apng_compositor_reset(zc_apng_compositor *);
void zc_apng_compositor_close(zc_apng_compositor *);
/* Straight-alpha encoded-sample composition. Signed offsets clip the overlay to
* the base canvas. Tight RGBA output; bits=0 selects greater input precision,
* otherwise 8/16; big_endian=0/1. Opacity is 0..65535. No color conversion.
* Borrowed sync sources; query with NULL/0. Invalid options/spans/aliasing write
* no output. Async copies both tight source rasters before returning, shares
* image-job input/output/workspace quotas and returns raw RGBA in its blob. */
enum { ZC_COMPOSITE_OVER=0, ZC_COMPOSITE_SOURCE=1 };
typedef struct {
uint32_t struct_size,blend;
int32_t x,y;
uint32_t bits,big_endian,opacity,reserved;
} zc_raster_composite_options;
void zc_default_raster_composite_options(zc_raster_composite_options *);
int zc_raster_composite(const zc_raster *base,const zc_raster *overlay,const zc_raster_composite_options *,uint8_t *data,uint64_t capacity,uint64_t *length);
int zc_raster_composite_async(const zc_raster *base,const zc_raster *overlay,const zc_raster_composite_options *,const zc_image_job_limits *,zc_image_job **out);
int zc_raster_convert(const zc_raster *,uint32_t format,uint32_t bits,uint32_t big_endian,uint8_t *data,uint64_t capacity,uint64_t *length);
int zc_raster_crop(const zc_raster *,uint32_t x,uint32_t y,uint32_t width,uint32_t height,uint8_t *data,uint64_t capacity,uint64_t *length);
int zc_raster_pixel16(const zc_raster *,uint32_t x,uint32_t y,uint16_t rgba[4]);
enum { ZC_RESAMPLE_NEAREST=0, ZC_RESAMPLE_BILINEAR=1, ZC_RESAMPLE_BICUBIC=2, ZC_RESAMPLE_LANCZOS2=3, ZC_RESAMPLE_LANCZOS3=4 };
/* Compact same-format/depth/endian resize; NULL/0 queries size and heap limits.
* Pixel-center sampling, normalized widened reduction kernels, premultiplied
* filtering of straight RGBA. BICUBIC uses Home Mitchell-Netravali B=C=1/3.
* Working heap is capped at 64 MiB in addition to the 256 MiB output bound.