blob: 9155f6732c66329b723b34c518dcbd62fd6ef32d [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/bin/factory/factory_server.h"
#include <lib/async/cpp/task.h>
#include <lib/syslog/cpp/macros.h>
#include <iostream>
#include "src/lib/files/directory.h"
#include "src/lib/files/file.h"
#include "src/lib/files/path.h"
namespace camera {
FactoryServer::FactoryServer()
: loop_(&kAsyncLoopConfigNoAttachToCurrentThread), controller_binding_(this) {}
FactoryServer::~FactoryServer() {
loop_.RunUntilIdle();
controller_binding_.Unbind();
streamer_ = nullptr;
loop_.Quit();
loop_.JoinThreads();
}
fit::result<std::unique_ptr<FactoryServer>, zx_status_t> FactoryServer::Create(
fuchsia::sysmem::AllocatorHandle allocator, fuchsia::camera3::DeviceWatcherHandle watcher,
fit::closure stop_callback) {
auto server = std::make_unique<FactoryServer>();
server->stop_callback_ = std::move(stop_callback);
// Start a thread and begin processing messages.
zx_status_t status = server->loop_.StartThread("camera-factory Loop");
if (status != ZX_OK) {
FX_PLOGS(ERROR, status);
return fit::error(status);
}
auto streamer_result =
Streamer::Create(std::move(allocator), std::move(watcher), std::move(stop_callback));
if (streamer_result.is_error()) {
FX_PLOGS(ERROR, streamer_result.error()) << "Failed to create Streamer.";
return streamer_result.take_error_result();
}
server->streamer_ = streamer_result.take_value();
// Create the WebUI
auto webui_result = WebUI::Create(server.get());
if (webui_result.is_error()) {
FX_PLOGS(ERROR, webui_result.error()) << "Failed to create WebUI.";
return webui_result.take_error_result();
}
server->webui_ = webui_result.take_value();
constexpr uint32_t kPortNumber = 52224;
server->webui_->PostListen(kPortNumber);
return fit::ok(std::move(server));
}
fidl::InterfaceRequestHandler<fuchsia::factory::camera::Controller> FactoryServer::GetHandler() {
return fit::bind_member(this, &FactoryServer::OnNewRequest);
}
void FactoryServer::OnNewRequest(
fidl::InterfaceRequest<fuchsia::factory::camera::Controller> request) {
if (controller_binding_.is_bound()) {
request.Close(ZX_ERR_ALREADY_BOUND);
return;
}
controller_binding_.Bind(std::move(request), loop_.dispatcher());
}
void FactoryServer::Capture() {
streamer_->RequestCapture(
0, "", true, [&](zx_status_t status, std::unique_ptr<camera::Capture> frame) {
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "capture failed";
return;
}
char file[] = "/data/capture.png";
FILE* filefp = fopen(file, "w");
if (filefp == NULL) {
FX_LOGS(ERROR) << "failed to open " << file << ": " << strerror(errno);
return;
}
frame->WritePNGAsNV12(filefp);
fclose(filefp);
});
}
void FactoryServer::RequestCaptureData(uint32_t stream, CaptureResponse callback) {
streamer_->RequestCapture(
stream, "", true,
[callback = callback.share()](zx_status_t status, std::unique_ptr<camera::Capture> frame) {
callback(status, std::move(frame));
});
}
void FactoryServer::IsIspBypassModeEnabled(bool enabled) {}
void FactoryServer::CaptureFrames(std::string dir_path, CaptureFramesCallback callback) {
streamer_->RequestCapture(
0, "", true,
[this, dir_path = std::move(dir_path), cb = std::move(callback)](
zx_status_t status, std::unique_ptr<camera::Capture> frame) mutable {
async::PostTask(loop_.dispatcher(),
[this, dir_path = std::move(dir_path), cb = std::move(cb), status,
frame = std::move(frame)]() {
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "capture failed";
cb(ZX_OK, fuchsia::images::ImageInfo{});
return;
}
if (dir_path != "") {
if (!files::CreateDirectory("/data/" + dir_path)) {
FX_LOGS(ERROR) << "Failed to create on-disk directory to write to.";
return;
}
}
auto file = "/data/" + dir_path + "/capture.png";
FILE* filefp = fopen(file.data(), "w");
if (filefp == NULL) {
FX_LOGS(ERROR) << "failed to open " << file << ": " << strerror(errno);
return;
}
// TODO(fxbug.dev/58498): Check if frame->properties_.image_format ==
// fuchsia::sysmem::PixelFormatType::NV12
if (bypass_) {
frame->WritePNGUnprocessed(filefp, true);
} else {
frame->WritePNGAsNV12(filefp);
}
fclose(filefp);
cb(ZX_OK, fuchsia::images::ImageInfo{});
});
});
}
} // namespace camera