| // 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 |