#ifndef __COMPOSER_H__ #define __COMPOSER_H__ #include typedef struct Composer Composer; Composer *composer_create(int output_width, int output_height, int num_streams, int y_off); void composer_destroy(Composer *comp); /* Drop every cached RGA buffer handle (imported dmabufs). Call after * decoder teardowns if fd churn is expected; the cache also self-evicts * via LRU when full. */ void composer_invalidate_all(Composer *comp); int composer_compose(Composer *comp, int *src_fds, int *src_widths, int *src_heights, int *src_strides, int *src_vstrides, int num_src, int dst_fd, int dst_stride); /* Override tile rectangles (pixel coordinates). n must be <= the tile * capacity (MAX_TILES). Used for PLC-driven dynamic layouts. */ int composer_set_tiles(Composer *comp, const int *x, const int *y, const int *w, const int *h, int n); /* Enable/disable aspect-ratio-preserving scaling (letterbox). When enabled * each source is scaled to fit inside its tile with black bars instead of * being stretched. Default is disabled. */ void composer_set_letterbox(Composer *comp, int enable); /* Compute the standard grid tile rectangles for n tiles on an * out_w x out_h canvas (same division as composer_create). The top * y_off pixels are reserved (e.g. title bar): tiles are laid out in * the area below and the last row extends to the bottom edge. */ int composer_grid_rects(int out_w, int out_h, int n, int *xs, int *ys, int *ws, int *hs, int y_off); /* Row-aware layout: each row may hold a different number of equal-width cells. * Row height is proportional to the number of cells in that row (so a 5-cell * row is taller than a 3-cell row). Cells within a row are equal width. The * total cell count = sum(row_cols). Returns total cells or -1 on bad input. */ int composer_flow_rects(int out_w, int out_h, const int *row_cols, int nrows, int *xs, int *ys, int *ws, int *hs, int y_off); /* Region (merged-cell) layout. The grid has nrows rows, row_cols[r] cells per * row, laid out in row-major order in `cells`. Cells holding the same label * (>=0) are merged into their bounding rectangle; label -1 is an empty cell. * Row heights follow inverse-of-cell-count weighting and always fill the * canvas. Returns the number of regions, filling region_x/y/w/h and * region_sid with the region's label (which equals the camera id). */ int composer_region_rects(int out_w, int out_h, const int *row_cols, int nrows, const int *cells, int *region_x, int *region_y, int *region_w, int *region_h, int *region_sid, int y_off); /* Split layout: fixed top row + adaptive centered bottom row. * top_ids[]: camera IDs for the top row (always shown). * top_n: number of top-row cameras (e.g. 5). * top_ratio: top row height as fraction of usable area (0.0-1.0, e.g. 0.3). * bottom_ids[]: camera IDs for the bottom row (1-3 cameras, -1=empty). * bottom_n: number of valid entries in bottom_ids (max count, may include -1). * actual_bottom: how many bottom cameras to actually show (1 to bottom_n). * Writes rects into xs/ys/ws/hs/sid arrays, returns total regions. */ int composer_split_rects(int out_w, int out_h, int y_off, const int *top_ids, int top_n, double top_ratio, const int *bottom_ids, int bottom_n, int actual_bottom, int *xs, int *ys, int *ws, int *hs, int *sid); void composer_get_tile_layout(Composer *comp, int stream_idx, int *x, int *y, int *w, int *h); /* Dump per-tile compose health counters to stderr (diagnoses flicker: a tile * with import/improcess failures periodically shows a black frame). */ void composer_dump_stats(const Composer *comp); #endif