#include #include #include #include using namespace std; namespace kms { static map format_info_array = { { PixelFormat::R8, { PixelFormatInfo { "R8", "R8 ", "", PixelColorType::RGB, { 1, 1 }, { { 1, 1, 1, 1 } }, } } }, { PixelFormat::RGB332, { PixelFormatInfo { "RGB332", "RGB8", "", PixelColorType::RGB, { 1, 1 }, { { 1, 1, 1, 1 } }, } } }, { PixelFormat::RGB565, { PixelFormatInfo { "RGB565", "RG16", "RGBP", PixelColorType::RGB, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::BGR565, { PixelFormatInfo { "BGR565", "BG16", "", PixelColorType::RGB, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::XRGB1555, { PixelFormatInfo { "XRGB1555", "XR15", "", PixelColorType::RGB, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::RGBX4444, { PixelFormatInfo { "RGBX4444", "RX12", "", PixelColorType::RGB, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::XRGB4444, { PixelFormatInfo { "XRGB4444", "XR12", "", PixelColorType::RGB, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::ARGB1555, { PixelFormatInfo { "ARGB1555", "AR15", "", PixelColorType::RGB, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::RGBA4444, { PixelFormatInfo { "RGBA4444", "RA12", "", PixelColorType::RGB, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::ARGB4444, { PixelFormatInfo { "ARGB4444", "AR12", "", PixelColorType::RGB, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::RGB888, { PixelFormatInfo { "RGB888", "RG24", "BGR3", PixelColorType::RGB, { 1, 1 }, { { 3, 1, 1, 1 } }, } } }, { PixelFormat::BGR888, { PixelFormatInfo { "BGR888", "BG24", "RGB3", PixelColorType::RGB, { 1, 1 }, { { 3, 1, 1, 1 } }, } } }, { PixelFormat::XRGB8888, { PixelFormatInfo { "XRGB8888", "XR24", "XR24", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::XBGR8888, { PixelFormatInfo { "XBGR8888", "XB24", "XB24", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::RGBX8888, { PixelFormatInfo { "RGBX8888", "RX24", "RX24", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::BGRX8888, { PixelFormatInfo { "BGRX8888", "BX24", "", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::XBGR2101010, { PixelFormatInfo { "XBGR2101010", "XB30", "RX30", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::XRGB2101010, { PixelFormatInfo { "XRGB2101010", "XR30", "", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::RGBX1010102, { PixelFormatInfo { "RGBX1010102", "RX30", "", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::BGRX1010102, { PixelFormatInfo { "BGRX1010102", "BX30", "", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::ARGB8888, { PixelFormatInfo { "ARGB8888", "AR24", "AR24", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::ABGR8888, { PixelFormatInfo { "ABGR8888", "AB24", "AB24", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::RGBA8888, { PixelFormatInfo { "RGBA8888", "RA24", "RA24", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::BGRA8888, { PixelFormatInfo { "BGRA8888", "BA24", "", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::ABGR2101010, { PixelFormatInfo { "ABGR2101010", "AB30", "", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::ARGB2101010, { PixelFormatInfo { "ARGB2101010", "AR30", "", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::RGBA1010102, { PixelFormatInfo { "RGBA1010102", "RA30", "", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::BGRA1010102, { PixelFormatInfo { "BGRA1010102", "BA30", "", PixelColorType::RGB, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::YUYV, { PixelFormatInfo { "YUYV", "YUYV", "YUYV", PixelColorType::YUV, { 2, 1 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::UYVY, { PixelFormatInfo { "UYVY", "UYVY", "UYVY", PixelColorType::YUV, { 2, 1 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::YVYU, { PixelFormatInfo { "YVYU", "YVYU", "YVYU", PixelColorType::YUV, { 2, 1 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::VYUY, { PixelFormatInfo { "VYUY", "VYUY", "VYUY", PixelColorType::YUV, { 2, 1 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::VUY888, { PixelFormatInfo { "VUY888", "VU24", "YUV3", PixelColorType::YUV, { 1, 1 }, { { 3, 1, 1, 1 } }, } } }, { PixelFormat::XVUY8888, { PixelFormatInfo { "XVUY8888", "XVUY", "YUVX", PixelColorType::YUV, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::Y210, { PixelFormatInfo { "Y210", "Y210", "", PixelColorType::YUV, { 1, 1 }, { { 8, 2, 1, 1 } }, } } }, { PixelFormat::Y212, { PixelFormatInfo { "Y212", "Y212", "", PixelColorType::YUV, { 1, 1 }, { { 8, 2, 1, 1 } }, } } }, { PixelFormat::Y216, { PixelFormatInfo { "Y216", "Y216", "", PixelColorType::YUV, { 1, 1 }, { { 8, 2, 1, 1 } }, } } }, { PixelFormat::NV12, { PixelFormatInfo { "NV12", "NV12", "NM12", PixelColorType::YUV, { 2, 2 }, { { 1, 1, 1, 1 }, { 2, 1, 2, 2 } }, } } }, { PixelFormat::NV21, { PixelFormatInfo { "NV21", "NV21", "NM21", PixelColorType::YUV, { 2, 2 }, { { 1, 1, 1, 1 }, { 2, 1, 2, 2 } }, } } }, { PixelFormat::NV16, { PixelFormatInfo { "NV16", "NV16", "NM16", PixelColorType::YUV, { 2, 1 }, { { 1, 1, 1, 1 }, { 2, 1, 2, 1 } }, } } }, { PixelFormat::NV61, { PixelFormatInfo { "NV61", "NV61", "NM61", PixelColorType::YUV, { 2, 1 }, { { 1, 1, 1, 1 }, { 2, 1, 2, 1 } }, } } }, { PixelFormat::P030, { PixelFormatInfo { "P030", "P030", "", PixelColorType::YUV, { 6, 2 }, { { 4, 3, 1, 1 }, { 8, 3, 2, 2 } }, } } }, { PixelFormat::P230, { PixelFormatInfo { "P230", "P230", "", PixelColorType::YUV, { 6, 2 }, { { 4, 3, 1, 1 }, { 8, 3, 2, 1 } }, } } }, { PixelFormat::XVUY2101010, { PixelFormatInfo { "XVUY2101010", "XY30", "", PixelColorType::YUV, { 1, 1 }, { { 4, 1, 1, 1 } }, } } }, { PixelFormat::YUV420, { PixelFormatInfo { "YUV420", "YU12", "", PixelColorType::YUV, { 1, 1 }, { { 1, 1, 1, 1 }, { 1, 1, 2, 2 }, { 1, 1, 2, 2 } }, } } }, { PixelFormat::YVU420, { PixelFormatInfo { "YVU420", "YV12", "", PixelColorType::YUV, { 1, 1 }, { { 1, 1, 1, 1 }, { 1, 1, 2, 2 }, { 1, 1, 2, 2 } }, } } }, { PixelFormat::YUV422, { PixelFormatInfo { "YUV422", "YU16", "", PixelColorType::YUV, { 1, 1 }, { { 1, 1, 1, 1 }, { 1, 1, 2, 1 }, { 1, 1, 2, 1 } }, } } }, { PixelFormat::YVU422, { PixelFormatInfo { "YVU422", "YV16", "", PixelColorType::YUV, { 1, 1 }, { { 1, 1, 1, 1 }, { 1, 1, 2, 1 }, { 1, 1, 2, 1 } }, } } }, { PixelFormat::YUV444, { PixelFormatInfo { "YUV444", "YU24", "", PixelColorType::YUV, { 1, 1 }, { { 1, 1, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 1 } }, } } }, { PixelFormat::YVU444, { PixelFormatInfo { "YVU444", "YV24", "", PixelColorType::YUV, { 1, 1 }, { { 1, 1, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 1 } }, } } }, { PixelFormat::T430, { PixelFormatInfo { "T430", "T430", "", PixelColorType::YUV, { 1, 1 }, { { 4, 1, 1, 1 }, { 4, 1, 1, 1 }, { 4, 1, 1, 1 } }, } } }, { PixelFormat::Y8, { PixelFormatInfo { "Y8", "GREY", "GREY", PixelColorType::YUV, { 1, 1 }, { { 1, 1, 1, 1 } }, } } }, { PixelFormat::Y10, { PixelFormatInfo { "Y10", "", "Y10 ", PixelColorType::YUV, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::Y10P, { PixelFormatInfo { "Y10P", "", "Y10P", PixelColorType::YUV, { 4, 1 }, { { 5, 4, 1, 1 } }, } } }, { PixelFormat::Y12, { PixelFormatInfo { "Y12", "", "Y12 ", PixelColorType::YUV, { 1, 1 }, { { 2, 1, 1, 1 } }, } } }, { PixelFormat::Y12P, { PixelFormatInfo { "Y12P", "", "Y12P", PixelColorType::YUV, { 2, 1 }, { { 3, 2, 1, 1 } }, } } }, { PixelFormat::XYYY2101010, { PixelFormatInfo { "XYYY2101010", "YPA4", "", PixelColorType::YUV, { 3, 1 }, { { 4, 3, 1, 1 } }, } } }, { PixelFormat::SBGGR8, { PixelFormatInfo { "SBGGR8", "", "BA81", PixelColorType::RAW, { 2, 2 }, { { 1, 1, 1, 1 } }, } } }, { PixelFormat::SGBRG8, { PixelFormatInfo { "SGBRG8", "", "GBRG", PixelColorType::RAW, { 2, 2 }, { { 1, 1, 1, 1 } }, } } }, { PixelFormat::SGRBG8, { PixelFormatInfo { "SGRBG8", "", "GRBG", PixelColorType::RAW, { 2, 2 }, { { 1, 1, 1, 1 } }, } } }, { PixelFormat::SRGGB8, { PixelFormatInfo { "SRGGB8", "", "RGGB", PixelColorType::RAW, { 2, 2 }, { { 1, 1, 1, 1 } }, } } }, { PixelFormat::SBGGR10, { PixelFormatInfo { "SBGGR10", "", "BG10", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SGBRG10, { PixelFormatInfo { "SGBRG10", "", "GB10", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SGRBG10, { PixelFormatInfo { "SGRBG10", "", "BA10", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SRGGB10, { PixelFormatInfo { "SRGGB10", "", "RG10", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SBGGR10P, { PixelFormatInfo { "SBGGR10P", "", "pBAA", PixelColorType::RAW, { 4, 2 }, { { 5, 4, 1, 1 } }, } } }, { PixelFormat::SGBRG10P, { PixelFormatInfo { "SGBRG10P", "", "pGAA", PixelColorType::RAW, { 4, 2 }, { { 5, 4, 1, 1 } }, } } }, { PixelFormat::SGRBG10P, { PixelFormatInfo { "SGRBG10P", "", "pgAA", PixelColorType::RAW, { 4, 2 }, { { 5, 4, 1, 1 } }, } } }, { PixelFormat::SRGGB10P, { PixelFormatInfo { "SRGGB10P", "", "pRAA", PixelColorType::RAW, { 4, 2 }, { { 5, 4, 1, 1 } }, } } }, { PixelFormat::SBGGR12, { PixelFormatInfo { "SBGGR12", "", "BG12", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SGBRG12, { PixelFormatInfo { "SGBRG12", "", "GB12", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SGRBG12, { PixelFormatInfo { "SGRBG12", "", "BA12", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SRGGB12, { PixelFormatInfo { "SRGGB12", "", "RG12", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SBGGR12P, { PixelFormatInfo { "SBGGR12P", "", "pBCC", PixelColorType::RAW, { 2, 2 }, { { 3, 2, 1, 1 } }, } } }, { PixelFormat::SGBRG12P, { PixelFormatInfo { "SGBRG12P", "", "pGCC", PixelColorType::RAW, { 2, 2 }, { { 3, 2, 1, 1 } }, } } }, { PixelFormat::SGRBG12P, { PixelFormatInfo { "SGRBG12P", "", "pgCC", PixelColorType::RAW, { 2, 2 }, { { 3, 2, 1, 1 } }, } } }, { PixelFormat::SRGGB12P, { PixelFormatInfo { "SRGGB12P", "", "pRCC", PixelColorType::RAW, { 2, 2 }, { { 3, 2, 1, 1 } }, } } }, { PixelFormat::SBGGR16, { PixelFormatInfo { "SBGGR16", "", "BYR2", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SGBRG16, { PixelFormatInfo { "SGBRG16", "", "GB16", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SGRBG16, { PixelFormatInfo { "SGRBG16", "", "GR16", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::SRGGB16, { PixelFormatInfo { "SRGGB16", "", "RG16", PixelColorType::RAW, { 2, 2 }, { { 4, 2, 1, 1 } }, } } }, { PixelFormat::MJPEG, { PixelFormatInfo { "MJPEG", "MJPG", "MJPG", PixelColorType::Undefined, { 1, 1 }, { { 1, 1, 1, 1 } }, } } }, }; const struct PixelFormatInfo& get_pixel_format_info(PixelFormat format) { if (!format_info_array.count(format)) throw invalid_argument("get_pixel_format_info: Unsupported pixelformat"); return format_info_array.at(format); } PixelFormat fourcc_to_pixel_format(uint32_t fourcc) { for (const auto& [fmt, pfi] : format_info_array) { if (pfi.drm_fourcc == fourcc) return fmt; } throw invalid_argument("FourCC not supported"); } uint32_t pixel_format_to_fourcc(PixelFormat f) { return format_info_array.at(f).drm_fourcc; } PixelFormat fourcc_str_to_pixel_format(const std::string& fourcc) { return fourcc_to_pixel_format(str_to_fourcc(fourcc)); } std::string pixel_format_to_fourcc_str(PixelFormat f) { return fourcc_to_str(format_info_array.at(f).drm_fourcc); } PixelFormat find_pixel_format_by_name(const std::string& name) { for (const auto& [fmt, pfi] : format_info_array) { if (pfi.name == name) return fmt; } throw invalid_argument("Unsupported pixelformat"); } static constexpr uint32_t _div_round_up(uint32_t a, uint32_t b) { return (a + b - 1) / b; } static constexpr uint32_t _align_up(uint32_t a, uint32_t b) { return _div_round_up(a, b) * b; } std::tuple PixelFormatInfo::align_pixels(uint32_t width, uint32_t height) const { return { _align_up(width, std::get<0>(pixel_align)), _align_up(height, std::get<1>(pixel_align)) }; } uint32_t PixelFormatInfo::stride(uint32_t width, uint32_t plane, uint32_t align) const { if (plane >= num_planes) throw std::runtime_error("Invalid plane number"); assert(width % std::get<0>(pixel_align) == 0); const auto& pi = planes[plane]; assert(width % pi.pixels_per_block == 0); uint32_t stride = width / pi.pixels_per_block * pi.bytes_per_block; assert(stride % pi.hsub == 0); stride = stride / pi.hsub; stride = _align_up(stride, align); return stride; } uint32_t PixelFormatInfo::planesize(uint32_t stride, uint32_t height, uint32_t plane) const { assert(height % std::get<1>(pixel_align) == 0); const auto& pi = planes[plane]; assert(height % pi.vsub == 0); return stride * (height / pi.vsub); } uint32_t PixelFormatInfo::framesize(uint32_t width, uint32_t height, uint32_t align) const { uint32_t size = 0; for (uint32_t i = 0; i < num_planes; ++i) { uint32_t s = stride(width, i, align); size += planesize(s, height, i); } return size; } std::tuple PixelFormatInfo::dumb_size(uint32_t width, uint32_t height, uint32_t plane, uint32_t align) const { /* Helper function mainly for DRM dumb framebuffer Returns (width, height, bitspp) tuple which results in a suitable plane size. DRM_IOCTL_MODE_CREATE_DUMB takes a 'bpp' (bits-per-pixel) argument, which is then used with the width and height to allocate the buffer. This doesn't work for pixel formats where the average bits-per-pixel is not an integer (e.g. P030) So, we instead use the bytes_per_block (in bits) as the 'bpp' argument, and adjust the width accordingly. */ assert(height % std::get<1>(pixel_align) == 0); const auto& pi = planes[plane]; assert(height % pi.vsub == 0); uint32_t stride = PixelFormatInfo::stride(width, plane, align); assert(stride % pi.bytes_per_block == 0); width = stride / pi.bytes_per_block; height = height / pi.vsub; uint32_t bitspp = pi.bytes_per_block * 8; return { width, height, bitspp }; } } // namespace kms