| // Copyright 2018 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 <lib/async-loop/cpp/loop.h> |
| #include <lib/async/default.h> |
| #include <lib/zx/eventpair.h> |
| #include <src/lib/fxl/logging.h> |
| |
| #include <iostream> |
| |
| #include "src/camera/test/camera_client_test/camera_client_test.h" |
| |
| #define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) |
| |
| // This is a stand-in for some actual gralloc type service which would allocate |
| // the right type of memory for the application and return it as a vmo. |
| zx_status_t Gralloc(fuchsia::camera::VideoFormat format, uint32_t num_buffers, |
| fuchsia::sysmem::BufferCollectionInfo* buffer_collection) { |
| // In the future, some special alignment might happen here, or special |
| // memory allocated... |
| // Simple GetBufferSize. Only valid for simple formats: |
| size_t buffer_size = ROUNDUP( |
| format.format.height * format.format.planes[0].bytes_per_row, PAGE_SIZE); |
| buffer_collection->buffer_count = num_buffers; |
| buffer_collection->vmo_size = buffer_size; |
| buffer_collection->format.set_image(format.format); |
| zx_status_t status; |
| for (uint32_t i = 0; i < num_buffers; ++i) { |
| status = zx::vmo::create(buffer_size, 0, &buffer_collection->vmos[i]); |
| if (status != ZX_OK) { |
| FXL_LOG(ERROR) << "Failed to allocate Buffer Collection"; |
| return status; |
| } |
| } |
| return ZX_OK; |
| } |
| |
| /* |
| Note: source can either be the device index if use_camera_manager, |
| or the full path to the camera driver if use_camera_manager |
| is false |
| */ |
| zx_status_t run_camera(bool use_camera_manager, const char* source) { |
| printf("Connecting to camera using %s\n", |
| use_camera_manager ? "camera manager" : "camera driver"); |
| |
| async::Loop loop(&kAsyncLoopConfigAttachToThread); |
| |
| camera::Client client; |
| |
| if (use_camera_manager) { |
| client.StartManager(atoi(source)); |
| } else { |
| client.StartDriver(source); |
| } |
| |
| int frame_counter = 0; |
| fuchsia::camera::StreamPtr stream; |
| |
| static constexpr uint16_t kNumberOfBuffers = 8; |
| fuchsia::sysmem::BufferCollectionInfo buffer_collection; |
| zx_status_t status = |
| Gralloc(client.formats()[0], kNumberOfBuffers, &buffer_collection); |
| if (status != ZX_OK) { |
| FXL_LOG(ERROR) << "Couldn't allocate buffers (status " << status; |
| return status; |
| } |
| |
| // Create stream token. The stream token is not very meaningful when |
| // you have a direct connection to the driver, but this use case should |
| // be disappearing soon anyway. For now, we just hold on to the token. |
| zx::eventpair driver_token; |
| zx::eventpair stream_token; |
| status = zx::eventpair::create(0, &stream_token, &driver_token); |
| if (status != ZX_OK) { |
| FXL_LOG(ERROR) << "Couldn't create driver token. status: " << status; |
| return status; |
| } |
| |
| if (use_camera_manager) { |
| fuchsia::camera::VideoStream request = {.camera_id = 0, |
| .format = client.formats()[0]}; |
| |
| status = client.manager()->CreateStream( |
| request, std::move(buffer_collection), stream.NewRequest(), |
| std::move(driver_token)); |
| } else { |
| status = client.camera()->CreateStream( |
| std::move(buffer_collection), client.formats()[0].rate, |
| stream.NewRequest(), std::move(driver_token)); |
| } |
| |
| if (status != ZX_OK) { |
| FXL_LOG(ERROR) << "Couldn't set camera format. status: " << status; |
| return status; |
| } |
| |
| stream.events() |
| .OnFrameAvailable = [&stream, &loop, &frame_counter]( |
| fuchsia::camera::FrameAvailableEvent frame) { |
| printf("Received FrameNotify Event %d at index: %u\n", frame_counter, |
| frame.buffer_id); |
| |
| if (frame.frame_status == fuchsia::camera::FrameStatus::OK) { |
| stream->ReleaseFrame(frame.buffer_id); |
| if (frame_counter++ > 10) { |
| FXL_LOG(INFO) << "Counted 10 frames, stopping stream and quitting loop"; |
| stream->Stop(); |
| loop.Quit(); |
| } |
| } else { |
| FXL_LOG(ERROR) << "Error set on incoming frame. Error: " |
| << static_cast<int>(frame.frame_status); |
| } |
| }; |
| |
| stream->Start(); |
| |
| printf("all done, waiting for frames...\n"); |
| |
| loop.Run(); |
| |
| FXL_LOG(INFO) << "Camera Test A-OK!"; |
| return ZX_OK; |
| } |
| |
| int main(int argc, const char** argv) { |
| printf("hello camera client\n"); |
| |
| bool use_camera_manager = true; |
| const char* source = "0"; |
| for (int i = 1; i < argc; ++i) { |
| if (!strcmp("--driver", argv[i])) { |
| use_camera_manager = false; |
| source = "/dev/class/camera/000"; |
| } else if (!strcmp("--manager", argv[i])) { |
| use_camera_manager = true; |
| source = "0"; |
| } else { |
| source = argv[i]; |
| break; |
| } |
| } |
| printf("using source %s\n", source); |
| |
| zx_status_t result = run_camera(use_camera_manager, source); |
| |
| return result == ZX_OK ? 0 : -1; |
| } |