blob: 8ae95540c04df642840468225e2b55290e9e70fb [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 "src/camera/drivers/controller/stream_protocol.h"
#include <lib/fit/defer.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace/event.h>
#include <zircon/errors.h>
#include <utility>
#include "src/camera/drivers/controller/graph_utils.h"
#include "src/camera/drivers/controller/processing_node.h"
namespace camera {
constexpr auto kTag = "camera_controller";
StreamImpl::StreamImpl(ProcessNode* output_node) : binding_(this), output_node_(*output_node) {}
zx_status_t StreamImpl::Attach(zx::channel channel, fit::function<void(void)> disconnect_handler) {
FX_DCHECK(!binding_.is_bound());
disconnect_handler_ = std::move(disconnect_handler);
binding_.set_error_handler([this](zx_status_t status) {
Shutdown(status);
disconnect_handler_();
});
zx_status_t status = binding_.Bind(std::move(channel));
if (status != ZX_OK) {
FX_PLOGST(ERROR, kTag, status);
return status;
}
return ZX_OK;
}
void StreamImpl::FrameReady(const frame_available_info_t* info) {
TRACE_DURATION("camera", "StreamImpl::FrameReady");
TRACE_FLOW_BEGIN("camera", "camera_stream_on_frame_available", info->metadata.timestamp);
ZX_ASSERT(thread_checker_.is_thread_valid());
fuchsia::camera2::FrameAvailableInfo frame_info;
frame_info.frame_status = static_cast<fuchsia::camera2::FrameStatus>(info->frame_status);
frame_info.buffer_id = info->buffer_id;
frame_info.metadata.set_image_format_index(info->metadata.image_format_index);
frame_info.metadata.set_timestamp(info->metadata.timestamp);
frame_info.metadata.set_capture_timestamp(info->metadata.capture_timestamp);
ZX_ASSERT(binding_.is_bound());
binding_.events().OnFrameAvailable(std::move(frame_info));
}
void StreamImpl::Shutdown(zx_status_t status) {
// Close the connection if it's open.
if (binding_.is_bound()) {
binding_.Close(status);
}
// Stop streaming if its started
if (started_) {
Stop();
}
}
void StreamImpl::Stop() {
output_node_.OnStopStreaming();
started_ = false;
}
void StreamImpl::Start() {
output_node_.OnStartStreaming();
started_ = true;
}
void StreamImpl::ReleaseFrame(uint32_t buffer_id) { output_node_.OnReleaseFrame(buffer_id); }
void StreamImpl::AcknowledgeFrameError() {
FX_LOGST(ERROR, kTag) << __PRETTY_FUNCTION__ << " not implemented";
Shutdown(ZX_ERR_UNAVAILABLE);
}
void StreamImpl::SetRegionOfInterest(float x_min, float y_min, float x_max, float y_max,
SetRegionOfInterestCallback callback) {
zx_status_t status = ZX_OK;
auto cleanup = fit::defer([&]() { callback(status); });
auto stream_type = output_node_.configured_streams().at(0);
auto* parent_node = output_node_.parent_node();
while (parent_node) {
if (parent_node->is_crop_region_supported(stream_type)) {
status = parent_node->OnSetCropRect(x_min, y_min, x_max, y_max);
break;
}
parent_node = parent_node->parent_node();
}
if (parent_node == nullptr) {
status = ZX_ERR_NOT_SUPPORTED;
}
}
void StreamImpl::SetImageFormat(uint32_t image_format_index, SetImageFormatCallback callback) {
zx_status_t status = ZX_OK;
auto cleanup = fit::defer([&]() {
if (status == ZX_OK) {
output_node_.set_current_image_format_index(image_format_index);
}
callback(status);
});
auto& available_image_formats = output_node_.output_image_formats();
if (image_format_index >= available_image_formats.size()) {
status = ZX_ERR_INVALID_ARGS;
return;
}
auto stream_type = output_node_.configured_streams().at(0);
auto* parent_node = output_node_.parent_node();
if (output_node_.current_image_format_index() != image_format_index) {
while (parent_node) {
if (parent_node->is_dynamic_resolution_supported(stream_type)) {
parent_node->OnResolutionChangeRequest(image_format_index);
break;
}
parent_node = parent_node->parent_node();
}
if (parent_node == nullptr) {
status = ZX_ERR_INVALID_ARGS;
}
}
}
void StreamImpl::GetImageFormats(GetImageFormatsCallback callback) {
auto& available_image_formats = output_node_.output_image_formats();
callback({available_image_formats.begin(), available_image_formats.end()});
}
void StreamImpl::GetBuffers(GetBuffersCallback callback) {
auto parent_node = output_node_.parent_node();
// in_place nodes may not have bound buffer collection ptr, walk up to find the real collection.
while (parent_node && !parent_node->output_buffer_collection()) {
parent_node = parent_node->parent_node();
}
auto& input_buffer_collection = parent_node->output_buffer_collection();
ZX_ASSERT(input_buffer_collection);
fuchsia::sysmem::BufferCollectionTokenHandle token;
input_buffer_collection->AttachToken(ZX_RIGHT_SAME_RIGHTS, token.NewRequest());
input_buffer_collection->Sync(
[token = std::move(token), callback = std::move(callback)]() mutable {
callback(std::move(token));
});
}
} // namespace camera