blob: 4baa1f49d56dbce4386223a9cb8b7bff041653e0 [file] [log] [blame] [edit]
/* 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 "hal/fake/fake_stream.h"
#include <utility>
#include <vector>
#include <base/files/file_util.h>
#include <base/memory/ptr_util.h>
#include <base/notreached.h>
#include <base/numerics/clamped_math.h>
#include <base/timer/elapsed_timer.h>
#include <libyuv.h>
#include <linux/videodev2.h>
#include "hal/fake/camera_hal.h"
#include "hal/fake/frame_buffer/gralloc_frame_buffer.h"
#include "hal/fake/test_pattern.h"
#include "hal/fake/y4m_fake_stream.h"
namespace cros {
namespace {
std::unique_ptr<GrallocFrameBuffer> ReadAndScaleMJPGFromFile(
const base::FilePath& path, Size size, ScaleMode scale_mode) {
auto bytes = base::ReadFileToBytes(path);
if (!bytes.has_value()) {
LOGF(WARNING) << "Failed to read file: " << path;
return nullptr;
}
int width, height;
if (libyuv::MJPGSize(bytes->data(), bytes->size(), &width, &height) != 0) {
LOGF(WARNING) << "Failed to get MJPG size: " << path;
return nullptr;
}
CHECK(width > 0 && height > 0);
if (width > kFrameMaxDimension || height > kFrameMaxDimension) {
LOGF(WARNING) << "Image size too large: " << path;
return nullptr;
}
auto temp_buffer = FrameBuffer::Create<GrallocFrameBuffer>(
Size(width, height), V4L2_PIX_FMT_NV12);
if (temp_buffer == nullptr) {
LOGF(WARNING) << "Failed to create temporary buffer";
return nullptr;
}
auto mapped_temp_buffer = temp_buffer->Map();
if (mapped_temp_buffer == nullptr) {
LOGF(WARNING) << "Failed to map temporary buffer";
return nullptr;
}
auto temp_y_plane = mapped_temp_buffer->plane(0);
auto temp_uv_plane = mapped_temp_buffer->plane(1);
int ret = libyuv::MJPGToNV12(
bytes->data(), bytes->size(), temp_y_plane.addr, temp_y_plane.stride,
temp_uv_plane.addr, temp_uv_plane.stride, width, height, width, height);
if (ret != 0) {
LOGF(WARNING) << "MJPGToNV12() failed with " << ret;
return nullptr;
}
return FrameBuffer::Scale<GrallocFrameBuffer>(*temp_buffer, size, scale_mode);
}
} // namespace
FakeStream::FakeStream()
: buffer_manager_(CameraBufferManager::GetInstance()) {}
FakeStream::~FakeStream() = default;
template <class... Ts>
struct Overloaded : Ts... {
using Ts::operator()...;
};
template <class... Ts>
Overloaded(Ts...) -> Overloaded<Ts...>;
// static
std::unique_ptr<FakeStream> FakeStream::Create(Size size,
const FramesSpec& spec) {
std::unique_ptr<FakeStream> fake_stream = std::visit(
Overloaded{
[&size](const FramesTestPatternSpec& spec)
-> std::unique_ptr<FakeStream> {
auto input_buffer = GenerateTestPattern(
size,
spec.use_solid_color_bar
? ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR
: ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);
return base::WrapUnique(
new StaticFakeStream(std::move(input_buffer)));
},
[&size](const FramesFileSpec& spec) -> std::unique_ptr<FakeStream> {
auto extension = spec.path.Extension();
if (extension == ".jpg" || extension == ".jpeg" ||
extension == ".mjpg" || extension == ".mjpeg") {
// TODO(pihsun): This only reads a single frame now, read and
// convert the whole stream on fly.
auto input_buffer =
ReadAndScaleMJPGFromFile(spec.path, size, spec.scale_mode);
return base::WrapUnique(
new StaticFakeStream(std::move(input_buffer)));
} else if (extension == ".y4m") {
return base::WrapUnique(new Y4mFakeStream(
spec.path, spec.scale_mode, spec.loop_mode));
} else {
LOGF(WARNING) << "Unknown file extension: " << extension;
return nullptr;
}
},
},
spec);
if (fake_stream == nullptr || !fake_stream->Initialize(size, spec)) {
return nullptr;
}
return fake_stream;
}
bool FakeStream::Initialize(Size size, const FramesSpec& spec) {
size_ = size;
return true;
}
StaticFakeStream::StaticFakeStream(std::unique_ptr<GrallocFrameBuffer> buffer)
: buffer_(std::move(buffer)) {}
bool StaticFakeStream::FillBuffer(buffer_handle_t output_buffer_handle) {
auto output_buffer = GrallocFrameBuffer::Wrap(output_buffer_handle);
if (output_buffer == nullptr) {
LOGF(WARNING) << "Failed to wrap output buffer";
return false;
}
return FrameBuffer::ConvertFromNv12(*buffer_, *output_buffer);
}
} // namespace cros