| /* Copyright 2022 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include <base/bits.h> |
| #include <base/logging.h> |
| #include <libyuv.h> |
| #include <linux/videodev2.h> |
| #include <iterator> |
| |
| #include "hal/fake/fake_stream.h" |
| #include "hal/fake/frame_buffer/gralloc_frame_buffer.h" |
| #include "hal/fake/test_pattern.h" |
| |
| #include "cros-camera/common.h" |
| |
| namespace cros { |
| |
| namespace { |
| |
| constexpr uint8_t kMultiColorBar[8][3] = { |
| // R, G, B |
| {0xFF, 0xFF, 0xFF}, // White |
| {0xFF, 0xFF, 0x00}, // Yellow |
| {0x00, 0xFF, 0xFF}, // Cyan |
| {0x00, 0xFF, 0x00}, // Green |
| {0xFF, 0x00, 0xFF}, // Magenta |
| {0xFF, 0x00, 0x00}, // Red |
| {0x00, 0x00, 0xFF}, // Blue |
| {0x00, 0x00, 0x00}, // Black |
| }; |
| |
| constexpr uint8_t kSolidColorBar[1][3] = { |
| // R, G, B |
| {0x00, 0x00, 0x00}, // Black |
| }; |
| |
| std::unique_ptr<GrallocFrameBuffer> GenerateTestPatternColorBarsFadeToGray( |
| Size size, const uint8_t color_bar[][3], const int bars) { |
| // TODO(pihsun): Should this limits be enforced on reading config? |
| if (size.width > kFrameMaxDimension || size.height > kFrameMaxDimension) { |
| LOGF(WARNING) << "Image size too large for test pattern"; |
| return nullptr; |
| } |
| if (size.width < bars) { |
| LOGF(WARNING) << "Image width too small for test pattern"; |
| return nullptr; |
| } |
| if (size.width % 2 != 0 || size.height % 2 != 0) { |
| LOGF(WARNING) << "Image width and height should be even"; |
| return nullptr; |
| } |
| |
| // TODO(pihsun): Use sensor size and scale. |
| size_t argb_size = size.width * size.height * 4; |
| std::unique_ptr<uint8_t[]> raw_buffer(new uint8_t[argb_size]); |
| if (raw_buffer == nullptr) { |
| LOGF(WARNING) << "Failed to create temporary buffer for test pattern"; |
| return nullptr; |
| } |
| |
| uint8_t* data = raw_buffer.get(); |
| int color_bar_width = size.width / bars; |
| int color_bar_height = size.height < 128 |
| ? size.height |
| : base::bits::AlignDown(size.height, 128u); |
| for (size_t h = 0; h < size.height; h++) { |
| float gray_factor = |
| static_cast<float>(color_bar_height - (h % color_bar_height)) / |
| static_cast<float>(color_bar_height); |
| for (size_t w = 0; w < size.width; w++) { |
| int index = (w / color_bar_width) % bars; |
| auto get_fade_color = [&](uint8_t base_color) { |
| uint8_t color = base_color * gray_factor; |
| if ((w / (color_bar_width / 2)) == 1) { |
| color = (color & 0xF0) | (color >> 4); |
| } |
| return color; |
| }; |
| *data++ = get_fade_color(color_bar[index][2]); // B |
| *data++ = get_fade_color(color_bar[index][1]); // G |
| *data++ = get_fade_color(color_bar[index][0]); // R |
| *data++ = 0x00; // A |
| } |
| } |
| |
| auto buffer = |
| FrameBuffer::Create<GrallocFrameBuffer>(size, V4L2_PIX_FMT_NV12); |
| if (buffer == nullptr) { |
| LOGF(WARNING) << "Failed to create buffer for test pattern"; |
| return nullptr; |
| } |
| |
| auto mapped_buffer = buffer->Map(); |
| if (mapped_buffer == nullptr) { |
| LOGF(WARNING) << "Failed to map buffer for test pattern"; |
| return nullptr; |
| } |
| |
| auto y_plane = mapped_buffer->plane(0); |
| auto uv_plane = mapped_buffer->plane(1); |
| |
| int ret = libyuv::ARGBToNV12( |
| raw_buffer.get(), /*src_stride_argb=*/size.width * 4, y_plane.addr, |
| y_plane.stride, uv_plane.addr, uv_plane.stride, size.width, size.height); |
| if (ret != 0) { |
| LOGF(WARNING) << "ARGBToNV12() failed with " << ret; |
| return nullptr; |
| } |
| |
| return buffer; |
| } |
| |
| } // namespace |
| |
| std::unique_ptr<GrallocFrameBuffer> GenerateTestPattern( |
| Size size, camera_metadata_enum_android_sensor_test_pattern_mode mode) { |
| switch (mode) { |
| case ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY: |
| return GenerateTestPatternColorBarsFadeToGray(size, kMultiColorBar, |
| std::size(kMultiColorBar)); |
| case ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR: |
| return GenerateTestPatternColorBarsFadeToGray(size, kSolidColorBar, |
| std::size(kSolidColorBar)); |
| default: |
| LOGF(WARNING) << "test pattern mode not implemented: " << mode; |
| return nullptr; |
| } |
| } |
| |
| } // namespace cros |