src/zm_pixformat.h
Rama master · réplica de lectura del repositorio original.
//
// ZoneMinder Pixel Format Helpers
// Copyright (C) 2026 ZoneMinder
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
#ifndef ZM_PIXFORMAT_H
#define ZM_PIXFORMAT_H
#include "zm_ffmpeg.h"
#include "zm_rgb.h"
#include <libavutil/pixdesc.h>
//
// Central pixel format conversion helpers.
//
// These replace the legacy ZM_COLOUR_* / ZM_SUBPIX_ORDER_* integer pair with
// AVPixelFormat as the single source of truth. The ZM_COLOUR_* constants
// (1=GRAY8, 3=RGB24, 4=RGB32) are retained only as bytes-per-pixel values for
// backwards compatibility with pixel-stride arithmetic.
//
// Forward mapping: (ZM colours, ZM subpixelorder) -> AVPixelFormat
inline AVPixelFormat zm_pixformat_from_colours(unsigned int colours, unsigned int subpixelorder) {
if (colours == ZM_COLOUR_GRAY8) {
if (subpixelorder == ZM_SUBPIX_ORDER_YUV420P) return AV_PIX_FMT_YUV420P;
if (subpixelorder == ZM_SUBPIX_ORDER_YUVJ420P) return AV_PIX_FMT_YUVJ420P;
if (subpixelorder == ZM_SUBPIX_ORDER_YUV422P) return AV_PIX_FMT_YUV422P;
if (subpixelorder == ZM_SUBPIX_ORDER_YUVJ422P) return AV_PIX_FMT_YUVJ422P;
return AV_PIX_FMT_GRAY8;
}
if (colours == ZM_COLOUR_RGB24) {
if (subpixelorder == ZM_SUBPIX_ORDER_BGR) return AV_PIX_FMT_BGR24;
return AV_PIX_FMT_RGB24;
}
if (colours == ZM_COLOUR_RGB32) {
if (subpixelorder == ZM_SUBPIX_ORDER_ARGB) return AV_PIX_FMT_ARGB;
if (subpixelorder == ZM_SUBPIX_ORDER_ABGR) return AV_PIX_FMT_ABGR;
if (subpixelorder == ZM_SUBPIX_ORDER_BGRA) return AV_PIX_FMT_BGRA;
return AV_PIX_FMT_RGBA;
}
return AV_PIX_FMT_NONE;
}
// Inverse mapping: AVPixelFormat -> (ZM colours, ZM subpixelorder)
// Returns true if the format is recognised, false otherwise (out params untouched).
inline bool zm_colours_from_pixformat(AVPixelFormat fmt,
unsigned int &colours,
unsigned int &subpixelorder) {
switch (fmt) {
case AV_PIX_FMT_GRAY8:
colours = ZM_COLOUR_GRAY8;
subpixelorder = ZM_SUBPIX_ORDER_NONE;
return true;
case AV_PIX_FMT_YUV420P:
colours = ZM_COLOUR_GRAY8;
subpixelorder = ZM_SUBPIX_ORDER_YUV420P;
return true;
case AV_PIX_FMT_YUVJ420P:
colours = ZM_COLOUR_GRAY8;
subpixelorder = ZM_SUBPIX_ORDER_YUVJ420P;
return true;
case AV_PIX_FMT_YUV422P:
colours = ZM_COLOUR_GRAY8; // Y-plane is 1 byte/pixel
subpixelorder = ZM_SUBPIX_ORDER_YUV422P;
return true;
case AV_PIX_FMT_YUVJ422P:
colours = ZM_COLOUR_GRAY8; // Y-plane is 1 byte/pixel
subpixelorder = ZM_SUBPIX_ORDER_YUVJ422P;
return true;
case AV_PIX_FMT_RGB24:
colours = ZM_COLOUR_RGB24;
subpixelorder = ZM_SUBPIX_ORDER_RGB;
return true;
case AV_PIX_FMT_BGR24:
colours = ZM_COLOUR_RGB24;
subpixelorder = ZM_SUBPIX_ORDER_BGR;
return true;
case AV_PIX_FMT_RGBA:
colours = ZM_COLOUR_RGB32;
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
return true;
case AV_PIX_FMT_BGRA:
colours = ZM_COLOUR_RGB32;
subpixelorder = ZM_SUBPIX_ORDER_BGRA;
return true;
case AV_PIX_FMT_ARGB:
colours = ZM_COLOUR_RGB32;
subpixelorder = ZM_SUBPIX_ORDER_ARGB;
return true;
case AV_PIX_FMT_ABGR:
colours = ZM_COLOUR_RGB32;
subpixelorder = ZM_SUBPIX_ORDER_ABGR;
return true;
default:
return false;
}
}
// Bytes-per-pixel in the primary buffer. For planar YUV formats this is the
// Y-plane stride (1), not the overall average.
inline unsigned int zm_bytes_per_pixel(AVPixelFormat fmt) {
switch (fmt) {
case AV_PIX_FMT_GRAY8:
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUVJ420P:
case AV_PIX_FMT_YUV422P:
case AV_PIX_FMT_YUVJ422P:
return 1;
case AV_PIX_FMT_RGB24:
case AV_PIX_FMT_BGR24:
return 3;
case AV_PIX_FMT_RGBA:
case AV_PIX_FMT_BGRA:
case AV_PIX_FMT_ARGB:
case AV_PIX_FMT_ABGR:
return 4;
default:
return 0;
}
}
// Map the persisted DB Monitors.Colours value to an AVPixelFormat.
// Valid DB values are {1, 3, 4}.
inline AVPixelFormat zm_db_colours_to_pixformat(int db_colours) {
switch (db_colours) {
case ZM_COLOUR_GRAY8: return AV_PIX_FMT_GRAY8;
case ZM_COLOUR_RGB24: return AV_PIX_FMT_RGB24;
case ZM_COLOUR_RGB32: return AV_PIX_FMT_RGBA;
default: return AV_PIX_FMT_NONE;
}
}
// Format-family predicates. Prefer these over ZM_COLOUR_* comparisons when
// dispatching on pixel format.
inline bool zm_is_rgb32(AVPixelFormat fmt) {
return fmt == AV_PIX_FMT_RGBA
|| fmt == AV_PIX_FMT_BGRA
|| fmt == AV_PIX_FMT_ARGB
|| fmt == AV_PIX_FMT_ABGR;
}
inline bool zm_is_rgb24(AVPixelFormat fmt) {
return fmt == AV_PIX_FMT_RGB24 || fmt == AV_PIX_FMT_BGR24;
}
inline bool zm_is_yuv420(AVPixelFormat fmt) {
return fmt == AV_PIX_FMT_YUV420P || fmt == AV_PIX_FMT_YUVJ420P;
}
// av_get_pix_fmt_name returns nullptr for unknown formats (including
// AV_PIX_FMT_NONE). Passing nullptr to a %s format specifier is undefined,
// so always go through this wrapper when logging.
inline const char *zm_get_pix_fmt_name(AVPixelFormat fmt) {
const char *name = av_get_pix_fmt_name(fmt);
return name ? name : "unknown";
}
#endif // ZM_PIXFORMAT_H