blob: c815db4540445c93cc465c26fa083c42f4df56a9 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "lib/image-format/image_format.h"
#include <zircon/assert.h>
#include <map>
#include <set>
namespace {
// There are two aspects of the ColorSpace and PixelFormat that we care about:
// * bits-per-sample - bits per primary sample (R, G, B, or Y)
// * RGB vs. YUV - whether the system supports the ColorSpace or PixelFormat
// representing RGB data or YUV data. Any given ColorSpace only supports
// one or the other. Currently any given PixelFormat only supports one or
// the other and this isn't likely to change.
// While we could just list all the ColorSpace(s) that each PixelFormat could
// plausibly support, expressing in terms of bits-per-sample and RGB vs. YUV is
// perhaps easier to grok.
enum ColorType {
kColorType_NONE,
kColorType_RGB,
kColorType_YUV
};
struct SamplingInfo {
std::set<uint32_t> possible_bits_per_sample;
ColorType color_type;
};
const std::map<fuchsia_sysmem_ColorSpaceType, SamplingInfo> kColorSpaceSamplingInfo = {
{fuchsia_sysmem_ColorSpaceType_SRGB, {{8, 10, 12, 16}, kColorType_RGB}},
{fuchsia_sysmem_ColorSpaceType_REC601_NTSC, {{8, 10}, kColorType_YUV}},
{fuchsia_sysmem_ColorSpaceType_REC601_NTSC_FULL_RANGE, {{8, 10}, kColorType_YUV}},
{fuchsia_sysmem_ColorSpaceType_REC601_PAL, {{8, 10}, kColorType_YUV}},
{fuchsia_sysmem_ColorSpaceType_REC601_PAL_FULL_RANGE, {{8, 10}, kColorType_YUV}},
{fuchsia_sysmem_ColorSpaceType_REC709, {{8, 10}, kColorType_YUV}},
{fuchsia_sysmem_ColorSpaceType_REC2020, {{10, 12}, kColorType_YUV}},
{fuchsia_sysmem_ColorSpaceType_REC2100, {{10, 12}, kColorType_YUV}},
};
const std::map<fuchsia_sysmem_PixelFormatType, SamplingInfo> kPixelFormatSamplingInfo = {
{fuchsia_sysmem_PixelFormatType_R8G8B8A8, {{8}, kColorType_RGB}},
{fuchsia_sysmem_PixelFormatType_BGRA32, {{8}, kColorType_RGB}},
{fuchsia_sysmem_PixelFormatType_I420, {{8}, kColorType_YUV}},
{fuchsia_sysmem_PixelFormatType_M420, {{8}, kColorType_YUV}},
{fuchsia_sysmem_PixelFormatType_NV12, {{8}, kColorType_YUV}},
{fuchsia_sysmem_PixelFormatType_YUY2, {{8}, kColorType_YUV}},
// 8 bits RGB when uncompressed - in this context, MJPEG is essentially
// pretending to be uncompressed.
{fuchsia_sysmem_PixelFormatType_MJPEG, {{8}, kColorType_RGB}},
};
} // namespace
bool ImageFormatIsPixelFormatEqual(const fuchsia_sysmem_PixelFormat& a, const fuchsia_sysmem_PixelFormat& b) {
return
a.type == b.type &&
// !has_format_modifier is for consistency with making format_modifier
// optional in future.
a.has_format_modifier == b.has_format_modifier &&
// Must be 0 if !has_format_modifier.
a.format_modifier.value == b.format_modifier.value;
}
bool ImageFormatIsSupportedColorSpaceForPixelFormat(const fuchsia_sysmem_ColorSpace& color_space, const fuchsia_sysmem_PixelFormat& pixel_format) {
// Not yet supported.
ZX_DEBUG_ASSERT(!pixel_format.has_format_modifier);
auto color_space_sampling_info_iter = kColorSpaceSamplingInfo.find(color_space.type);
if (color_space_sampling_info_iter == kColorSpaceSamplingInfo.end()) {
return false;
}
auto pixel_format_sampling_info_iter = kPixelFormatSamplingInfo.find(pixel_format.type);
if (pixel_format_sampling_info_iter == kPixelFormatSamplingInfo.end()) {
return false;
}
const SamplingInfo& color_space_sampling_info = color_space_sampling_info_iter->second;
const SamplingInfo& pixel_format_sampling_info = pixel_format_sampling_info_iter->second;
if (color_space_sampling_info.color_type != pixel_format_sampling_info.color_type) {
return false;
}
bool is_bits_per_sample_match_found = false;
for (uint32_t bits_per_sample : color_space_sampling_info.possible_bits_per_sample) {
auto pixel_format_bits_per_sample_iter = pixel_format_sampling_info.possible_bits_per_sample.find(bits_per_sample);
if (pixel_format_bits_per_sample_iter != pixel_format_sampling_info.possible_bits_per_sample.end()) {
is_bits_per_sample_match_found = true;
break;
}
}
if (!is_bits_per_sample_match_found) {
return false;
}
return true;
}
bool ImageFormatIsSupported(const fuchsia_sysmem_PixelFormat* pixel_format) {
if (pixel_format->has_format_modifier) {
return false;
}
switch (pixel_format->type) {
case fuchsia_sysmem_PixelFormatType_INVALID:
case fuchsia_sysmem_PixelFormatType_MJPEG:
return false;
case fuchsia_sysmem_PixelFormatType_R8G8B8A8:
case fuchsia_sysmem_PixelFormatType_BGRA32:
case fuchsia_sysmem_PixelFormatType_I420:
case fuchsia_sysmem_PixelFormatType_M420:
case fuchsia_sysmem_PixelFormatType_NV12:
case fuchsia_sysmem_PixelFormatType_YUY2:
return true;
}
return false;
}
// Overall bits per pixel, across all pixel data in the whole image.
uint32_t ImageFormatBitsPerPixel(const fuchsia_sysmem_PixelFormat* pixel_format) {
ZX_DEBUG_ASSERT(ImageFormatIsSupported(pixel_format));
switch (pixel_format->type) {
case fuchsia_sysmem_PixelFormatType_INVALID:
case fuchsia_sysmem_PixelFormatType_MJPEG:
// impossible; checked previously.
ZX_DEBUG_ASSERT(false);
return 0u;
case fuchsia_sysmem_PixelFormatType_R8G8B8A8:
return 4u * 8u;
case fuchsia_sysmem_PixelFormatType_BGRA32:
return 4u * 8u;
case fuchsia_sysmem_PixelFormatType_I420:
return 12u;
case fuchsia_sysmem_PixelFormatType_M420:
return 12u;
case fuchsia_sysmem_PixelFormatType_NV12:
return 12u;
case fuchsia_sysmem_PixelFormatType_YUY2:
return 2u * 8u;
}
ZX_PANIC("Unknown Pixel Format: %d", static_cast<int>(pixel_format->type));
return 0u;
}
uint32_t ImageFormatStrideBytesPerWidthPixel(
const fuchsia_sysmem_PixelFormat* pixel_format) {
ZX_DEBUG_ASSERT(ImageFormatIsSupported(pixel_format));
switch (pixel_format->type) {
case fuchsia_sysmem_PixelFormatType_INVALID:
case fuchsia_sysmem_PixelFormatType_MJPEG:
// impossible; checked previously.
ZX_DEBUG_ASSERT(false);
return 0u;
case fuchsia_sysmem_PixelFormatType_R8G8B8A8:
return 4u;
case fuchsia_sysmem_PixelFormatType_BGRA32:
return 4u;
case fuchsia_sysmem_PixelFormatType_I420:
return 1u;
case fuchsia_sysmem_PixelFormatType_M420:
return 1u;
case fuchsia_sysmem_PixelFormatType_NV12:
return 1u;
case fuchsia_sysmem_PixelFormatType_YUY2:
return 2u;
}
ZX_PANIC("Unknown Pixel Format: %d", static_cast<int>(pixel_format->type));
return 0u;
}
uint64_t ImageFormatImageSize(const fuchsia_sysmem_ImageFormat_2* image_format) {
ZX_DEBUG_ASSERT(ImageFormatIsSupported(&image_format->pixel_format));
uint64_t coded_height = image_format->coded_height;
uint64_t bytes_per_row = image_format->bytes_per_row;
switch (image_format->pixel_format.type) {
case fuchsia_sysmem_PixelFormatType_INVALID:
case fuchsia_sysmem_PixelFormatType_MJPEG:
// impossible; checked previously.
ZX_DEBUG_ASSERT(false);
return 0u;
case fuchsia_sysmem_PixelFormatType_R8G8B8A8:
case fuchsia_sysmem_PixelFormatType_BGRA32:
return coded_height * bytes_per_row;
case fuchsia_sysmem_PixelFormatType_I420:
return coded_height * bytes_per_row * 3 / 2;
case fuchsia_sysmem_PixelFormatType_M420:
return coded_height * bytes_per_row * 3 / 2;
case fuchsia_sysmem_PixelFormatType_NV12:
return coded_height * bytes_per_row * 3 / 2;
case fuchsia_sysmem_PixelFormatType_YUY2:
return coded_height * bytes_per_row;
}
ZX_PANIC("Unknown Pixel Format: %d", static_cast<int>(image_format->pixel_format.type));
return 0u;
}
uint32_t ImageFormatCodedWidthMinDivisor(
const fuchsia_sysmem_PixelFormat* pixel_format) {
ZX_DEBUG_ASSERT(ImageFormatIsSupported(pixel_format));
switch (pixel_format->type) {
case fuchsia_sysmem_PixelFormatType_INVALID:
case fuchsia_sysmem_PixelFormatType_MJPEG:
// impossible; checked previously.
ZX_DEBUG_ASSERT(false);
return 0u;
case fuchsia_sysmem_PixelFormatType_R8G8B8A8:
return 1u;
case fuchsia_sysmem_PixelFormatType_BGRA32:
return 1u;
case fuchsia_sysmem_PixelFormatType_I420:
return 2u;
case fuchsia_sysmem_PixelFormatType_M420:
return 2u;
case fuchsia_sysmem_PixelFormatType_NV12:
return 2u;
case fuchsia_sysmem_PixelFormatType_YUY2:
return 2u;
}
ZX_PANIC("Unknown Pixel Format: %d", static_cast<int>(pixel_format->type));
return 0u;
}
uint32_t ImageFormatCodedHeightMinDivisor(
const fuchsia_sysmem_PixelFormat* pixel_format) {
ZX_DEBUG_ASSERT(ImageFormatIsSupported(pixel_format));
switch (pixel_format->type) {
case fuchsia_sysmem_PixelFormatType_INVALID:
case fuchsia_sysmem_PixelFormatType_MJPEG:
// impossible; checked previously.
ZX_DEBUG_ASSERT(false);
return 0u;
case fuchsia_sysmem_PixelFormatType_R8G8B8A8:
return 1u;
case fuchsia_sysmem_PixelFormatType_BGRA32:
return 1u;
case fuchsia_sysmem_PixelFormatType_I420:
return 2u;
case fuchsia_sysmem_PixelFormatType_M420:
return 2u;
case fuchsia_sysmem_PixelFormatType_NV12:
return 2u;
case fuchsia_sysmem_PixelFormatType_YUY2:
return 2u;
}
ZX_PANIC("Unknown Pixel Format: %d", static_cast<int>(pixel_format->type));
return 0u;
}
uint32_t ImageFormatSampleAlignment(
const fuchsia_sysmem_PixelFormat* pixel_format) {
ZX_DEBUG_ASSERT(ImageFormatIsSupported(pixel_format));
switch (pixel_format->type) {
case fuchsia_sysmem_PixelFormatType_INVALID:
case fuchsia_sysmem_PixelFormatType_MJPEG:
// impossible; checked previously.
ZX_DEBUG_ASSERT(false);
return 0u;
case fuchsia_sysmem_PixelFormatType_R8G8B8A8:
return 4u;
case fuchsia_sysmem_PixelFormatType_BGRA32:
return 4u;
case fuchsia_sysmem_PixelFormatType_I420:
return 2u;
case fuchsia_sysmem_PixelFormatType_M420:
return 2u;
case fuchsia_sysmem_PixelFormatType_NV12:
return 2u;
case fuchsia_sysmem_PixelFormatType_YUY2:
return 2u;
}
ZX_PANIC("Unknown Pixel Format: %d", static_cast<int>(pixel_format->type));
return 0u;
}