blob: 4f3f7276855a7903b8f79fe0dab0408cecfde757 [file] [log] [blame]
// Copyright 2019 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 "stream_constraints.h"
#include <fuchsia/camera2/cpp/fidl.h>
#include <fuchsia/camera2/hal/cpp/fidl.h>
#include <fuchsia/sysmem/c/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/affine/ratio.h>
#include <lib/image-format/image_format.h>
#include <algorithm>
#include <vector>
#include <fbl/algorithm.h>
namespace camera {
static fuchsia_sysmem_PixelFormat ConvertPixelFormatToC(fuchsia::sysmem::PixelFormat format) {
fuchsia_sysmem_PixelFormat ret;
ret.has_format_modifier = format.has_format_modifier;
// HLCPP and C enum values should always match. Spot-check a single one.
static_assert(static_cast<fuchsia_sysmem_PixelFormatType>(
fuchsia::sysmem::PixelFormatType::YUY2) == fuchsia_sysmem_PixelFormatType_YUY2,
"HLCPP and C pixel format types don't match.");
ret.type = static_cast<fuchsia_sysmem_PixelFormatType>(format.type);
return ret;
}
// Make an ImageFormat_2 struct with default values except for width, height and format.
fuchsia::sysmem::ImageFormat_2 StreamConstraints::MakeImageFormat(
uint32_t width, uint32_t height, fuchsia::sysmem::PixelFormatType format,
uint32_t original_width, uint32_t original_height) {
fuchsia::sysmem::PixelFormat pixel_format = {.type = format, .has_format_modifier = false};
fuchsia_sysmem_PixelFormat pixel_format_c = ConvertPixelFormatToC(pixel_format);
uint32_t bytes_per_row = ImageFormatStrideBytesPerWidthPixel(&pixel_format_c) * width;
// All four dimensions must be non-zero to generate a valid aspect ratio.
bool has_pixel_aspect_ratio = width && height && original_width && original_height;
uint64_t pixel_aspect_ratio_width = 1;
uint64_t pixel_aspect_ratio_height = 1;
if (width == 0 || height == 0) {
width = 1;
height = 1;
}
if (has_pixel_aspect_ratio) {
// Calculate the reduced fraction for the rational value (original_ratio / format_ratio).
// Equivalent to (original_width / original_height) / (width / height)
// = (original_width * height) / (original_height * width)
pixel_aspect_ratio_width = static_cast<uint64_t>(original_width) * height;
pixel_aspect_ratio_height = static_cast<uint64_t>(original_height) * width;
affine::Ratio::Reduce(&pixel_aspect_ratio_width, &pixel_aspect_ratio_height);
// Round and truncate values that are still too large to fit in the format struct.
while (pixel_aspect_ratio_width > std::numeric_limits<uint32_t>::max() ||
pixel_aspect_ratio_height > std::numeric_limits<uint32_t>::max()) {
pixel_aspect_ratio_width = (pixel_aspect_ratio_width + (1u << 31)) >> 1;
pixel_aspect_ratio_height = (pixel_aspect_ratio_height + (1u << 31)) >> 1;
}
}
return {
.pixel_format = {.type = format, .has_format_modifier = false},
.coded_width = width,
.coded_height = height,
.bytes_per_row = bytes_per_row,
.display_width = width,
.display_height = height,
.layers = 1,
.color_space = {.type = fuchsia::sysmem::ColorSpaceType::REC601_PAL},
.has_pixel_aspect_ratio = has_pixel_aspect_ratio,
.pixel_aspect_ratio_width = static_cast<uint32_t>(pixel_aspect_ratio_width),
.pixel_aspect_ratio_height = static_cast<uint32_t>(pixel_aspect_ratio_height),
};
}
void StreamConstraints::AddImageFormat(uint32_t width, uint32_t height,
fuchsia::sysmem::PixelFormatType format,
uint32_t original_width, uint32_t original_height) {
formats_.push_back(MakeImageFormat(width, height, format, original_width, original_height));
}
fuchsia::sysmem::BufferCollectionConstraints StreamConstraints::MakeBufferCollectionConstraints()
const {
// Don't make a stream config if AddImageFormats has not been called.
ZX_ASSERT(!formats_.empty());
fuchsia::sysmem::BufferCollectionConstraints constraints;
constraints.min_buffer_count_for_camping = buffer_count_for_camping_;
constraints.has_buffer_memory_constraints = true;
constraints.buffer_memory_constraints.ram_domain_supported = true;
if (contiguous_) {
constraints.buffer_memory_constraints.physically_contiguous_required = true;
}
if (cpu_access_) {
constraints.usage.cpu = fuchsia::sysmem::cpuUsageWrite | fuchsia::sysmem::cpuUsageRead;
} else {
constraints.usage.video = fuchsia::sysmem::videoUsageCapture;
}
// Just make one constraint that has the biggest width/height for each format type:
// TODO(fxbug.dev/41321): Map these out. Right now we just use NV12 for everything.
uint32_t max_width = 0, max_height = 0;
for (auto& format : formats_) {
max_width = std::max(max_width, format.coded_width);
max_height = std::max(max_height, format.coded_height);
}
constraints.image_format_constraints_count = 1;
constraints.image_format_constraints[0] = {
.pixel_format = {.type = fuchsia::sysmem::PixelFormatType::NV12},
.color_spaces_count = 1,
.color_space =
{
{{fuchsia::sysmem::ColorSpaceType::REC601_PAL}},
},
.bytes_per_row_divisor = bytes_per_row_divisor_,
.required_max_coded_width = max_width,
.required_max_coded_height = max_height,
};
return constraints;
}
fuchsia::camera2::hal::StreamConfig StreamConstraints::ConvertToStreamConfig() {
// Don't make a stream config if AddImageFormats has not been called.
ZX_ASSERT(!formats_.empty());
fuchsia::camera2::StreamProperties stream_properties{};
stream_properties.set_stream_type(stream_type_);
for (auto& format : formats_) {
format.bytes_per_row = fbl::round_up(format.coded_width, bytes_per_row_divisor_);
}
return {
.frame_rate = {.frames_per_sec_numerator = frames_per_second_,
.frames_per_sec_denominator = 1},
.constraints = MakeBufferCollectionConstraints(),
.properties = std::move(stream_properties),
.image_formats = fidl::Clone(formats_),
};
}
} // namespace camera