blob: 90bb4051dec83e6636d3c2d08758d751f9365b2a [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 "fake_legacy_stream.h"
#include <fuchsia/camera2/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/async/default.h>
#include <lib/async/dispatcher.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fit/result.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <array>
#include <memory>
#include <sstream>
#include <unordered_set>
namespace camera {
// NOTE: these must be a superset of the formats defined in
// //src/camera/bin/device/test/take_controller.cc
// TODO(fxbug.dev/49137): improve legacy test fakes
static constexpr std::array<fuchsia::sysmem::ImageFormat_2, 3> kFakeImageFormats{{
{
.pixel_format =
{
.type = fuchsia::sysmem::PixelFormatType::NV12,
},
.coded_width = 1920,
.coded_height = 1080,
.bytes_per_row = 1920,
.color_space =
{
.type = fuchsia::sysmem::ColorSpaceType::REC601_NTSC,
},
},
{
.pixel_format =
{
.type = fuchsia::sysmem::PixelFormatType::NV12,
},
.coded_width = 1280,
.coded_height = 720,
.bytes_per_row = 1920,
.color_space =
{
.type = fuchsia::sysmem::ColorSpaceType::REC601_NTSC,
},
},
{
.pixel_format =
{
.type = fuchsia::sysmem::PixelFormatType::NV12,
},
.coded_width = 1024,
.coded_height = 576,
.bytes_per_row = 1920,
.color_space =
{
.type = fuchsia::sysmem::ColorSpaceType::REC601_NTSC,
},
},
}};
class FakeLegacyStreamImpl : public FakeLegacyStream, public fuchsia::camera2::Stream {
public:
FakeLegacyStreamImpl() : binding_(this) {}
void CheckSameThread() {
auto dispatcher = async_get_default_dispatcher();
if (dispatcher) {
ZX_ASSERT_MSG(dispatcher == binding_.dispatcher(), "FakeLegacyStream is not thread-safe!");
}
}
// |camera::FakeLegacyStream|
fit::result<void, std::string> StreamClientStatus() override {
if (client_error_count_ == 0) {
return fit::ok();
}
auto error_string = client_error_explanation_.str();
return fit::error(std::move(error_string));
}
zx_status_t SendFrameAvailable(fuchsia::camera2::FrameAvailableInfo info) override {
CheckSameThread();
if (stopped_) {
FX_LOGS(INFO) << "Client has not started the stream";
return ZX_ERR_BAD_STATE;
}
if (outstanding_error_frame_) {
FX_LOGS(INFO) << "Client has not yet acknowledged a previous error frame";
return ZX_ERR_BAD_STATE;
}
if (info.frame_status == fuchsia::camera2::FrameStatus::OK) {
auto it = outstanding_buffer_ids_.find(info.buffer_id);
if (it != outstanding_buffer_ids_.end()) {
FX_LOGS(INFO) << "Client has not yet returned buffer_id " << info.buffer_id;
return ZX_ERR_BAD_STATE;
}
outstanding_buffer_ids_.insert(info.buffer_id);
} else {
outstanding_error_frame_ = true;
}
binding_.events().OnFrameAvailable(std::move(info));
return ZX_OK;
}
bool IsStreaming() override {
CheckSameThread();
return !stopped_;
}
bool IsOutstanding(uint32_t buffer_id) override {
CheckSameThread();
return outstanding_buffer_ids_.find(buffer_id) != outstanding_buffer_ids_.end();
};
std::tuple<float, float, float, float> GetRegionOfInterest() override {
return region_of_interest_;
}
uint32_t GetImageFormat() override { return image_format_; }
private:
std::stringstream& ClientErrors() {
if (client_error_count_ > 0) {
client_error_explanation_ << std::endl;
}
client_error_explanation_ << client_error_count_++ << ": ";
return client_error_explanation_;
}
// |fuchsia::camera2::Stream|
void Start() override {
if (!stopped_) {
ClientErrors() << "Client called Start while stream is already started";
}
stopped_ = false;
}
void Stop() override {
if (stopped_) {
ClientErrors() << "Client called Stop while stream is already stopped";
}
stopped_ = true;
}
void ReleaseFrame(uint32_t buffer_id) override {
auto it = outstanding_buffer_ids_.find(buffer_id);
if (it == outstanding_buffer_ids_.end()) {
ClientErrors() << "Client called Release with unowned buffer_id " << buffer_id;
} else {
outstanding_buffer_ids_.erase(it);
}
}
void AcknowledgeFrameError() override {
if (!outstanding_error_frame_) {
ClientErrors()
<< "Client called AcknowledgeFrameError without having received any new error frames";
}
outstanding_error_frame_ = false;
}
void SetRegionOfInterest(float x_min, float y_min, float x_max, float y_max,
SetRegionOfInterestCallback callback) override {
if (x_min < 0 || y_min < 0 || x_min >= x_max || y_min >= y_max) {
ClientErrors() << "Client called SetRegionOfInterest with invalid args: " << x_min << ", "
<< y_min << ", " << x_max << ", " << y_max;
callback(ZX_ERR_INVALID_ARGS);
} else {
region_of_interest_ = {x_min, y_min, x_max, y_max};
callback(ZX_OK);
}
}
void SetImageFormat(uint32_t image_format_index, SetImageFormatCallback callback) override {
if (image_format_index >= kFakeImageFormats.size()) {
ClientErrors() << "Client called SetImageFormat with invalid index: " << image_format_index;
callback(ZX_ERR_INVALID_ARGS);
} else {
image_format_ = image_format_index;
callback(ZX_OK);
}
}
void GetImageFormats(GetImageFormatsCallback callback) override {
callback({kFakeImageFormats.begin(), kFakeImageFormats.end()});
}
fidl::Binding<fuchsia::camera2::Stream> binding_;
bool stopped_ = true;
std::unordered_set<uint32_t> outstanding_buffer_ids_;
bool outstanding_error_frame_ = false;
uint32_t client_error_count_ = 0;
std::stringstream client_error_explanation_;
std::tuple<float, float, float, float> region_of_interest_{0.0f, 0.0f, 1.0f, 1.0f};
uint32_t image_format_ = 0;
friend class FakeLegacyStream;
};
fit::result<std::unique_ptr<FakeLegacyStream>, zx_status_t> FakeLegacyStream::Create(
fidl::InterfaceRequest<fuchsia::camera2::Stream> request, uint32_t format_index,
async_dispatcher_t* dispatcher) {
auto impl = std::make_unique<FakeLegacyStreamImpl>();
zx_status_t status = impl->binding_.Bind(std::move(request), dispatcher);
impl->image_format_ = format_index;
if (status) {
return fit::error(status);
}
impl->binding_.set_error_handler(
[impl = impl.get()](zx_status_t status) { impl->ClientErrors() << "Client disconnected"; });
return fit::ok(std::move(impl));
}
} // namespace camera