blob: 0116c253c3a3c6dac77f7cf3d67bfd152796f97b [file] [log] [blame]
/*
* Copyright 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <iostream>
#include <string>
#include <base/at_exit.h>
#include <base/bind.h>
#include <base/logging.h>
#include <binder/IServiceManager.h>
#include <brillo/binder_watcher.h>
#include <brillo/message_loops/base_message_loop.h>
#include <brillo/syslog_logging.h>
#include <camera/CameraMetadata.h>
#include <android/hardware/ICameraService.h>
#include <camera/camera2/CaptureRequest.h>
#include <camera/camera2/SubmitInfo.h>
#include <android/hardware/camera2/BnCameraDeviceCallbacks.h>
#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
#include <android/hardware/camera2/ICameraDeviceUser.h>
#include <camera/camera2/OutputConfiguration.h>
#include <gui/BufferQueue.h>
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
#include <gui/CpuConsumer.h>
#include <gui/Surface.h>
#include <hardware/camera3.h>
#include <system/camera_metadata.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/StrongPointer.h>
using android::binder::Status;
using android::BufferQueue;
using android::CameraMetadata;
using android::CaptureResultExtras;
using android::CpuConsumer;
using android::hardware::camera2::BnCameraDeviceCallbacks;
using android::hardware::camera2::CaptureRequest;
using android::hardware::camera2::ICameraDeviceCallbacks;
using android::hardware::camera2::ICameraDeviceUser;
using android::hardware::camera2::utils::SubmitInfo;
using android::hardware::ICameraService;
using android::IGraphicBufferConsumer;
using android::IGraphicBufferProducer;
using android::OK;
using android::sp;
using android::String16;
using android::Surface;
namespace {
// TODO(wiley) This constant should probably come out that client library, but
// where is not obvious.
const char kCameraServiceName[] = "media.camera";
// TODO(wiley) This happens to be a format supported by both gralloc.default and
// the golfish camera HAL, but I have no idea how to get this into
// an actual viewable image.
const int kHalPixelFormat = HAL_PIXEL_FORMAT_RAW16;
class CameraDeviceCallbacks : public BnCameraDeviceCallbacks {
public:
explicit CameraDeviceCallbacks(brillo::MessageLoop* loop) : loop_(loop) {}
Status onDeviceError(
int error_code,
const CaptureResultExtras& /* result_extras */) override {
LOG(ERROR) << "Received camera error = " << error_code;
loop_->BreakLoop();
return Status::ok();
}
Status onDeviceIdle() override {
LOG(INFO) << "Camera device is idle";
return Status::ok();
}
Status onCaptureStarted(
const CaptureResultExtras& /* result_extras */,
int64_t /* timestamp */) override {
LOG(INFO) << "Capture started.";
return Status::ok();
}
Status onResultReceived(
const CameraMetadata& /* metadata */,
const CaptureResultExtras& /* result_extras */) override {
LOG(INFO) << "Capture result received";
result_received_ = true;
loop_->BreakLoop();
return Status::ok();
}
Status onPrepared(int stream_id) override {
LOG(INFO) << "Camera is prepared for stream " << stream_id;
return Status::ok();
}
Status onRepeatingRequestError(int64_t lastFrameNumber) {
LOG(INFO) << "Repeating request error, last frame = " << lastFrameNumber;
loop_->BreakLoop();
return Status::ok();
}
bool result_received() { return result_received_; }
private:
brillo::MessageLoop* loop_ = nullptr;
bool result_received_ = false;
};
} // namespace
int main() {
base::AtExitManager at_exit_manager;
brillo::InitLog(brillo::kLogToStderr);
// Create a message loop.
brillo::BaseMessageLoop message_loop(new base::MessageLoopForIO);
// Initialize a binder watcher.
brillo::BinderWatcher watcher(&message_loop);
watcher.Init();
LOG(INFO) << "Retrieving a binder for the camera service.";
sp<ICameraService> camera_service;
android::status_t service_status = android::getService(
String16(kCameraServiceName), &camera_service);
CHECK(service_status == OK)
<< "Failed to get ICameraService binder from service manager!";
LOG(INFO) << "Asking how many cameras we have.";
int32_t num_cameras;
Status status = camera_service->getNumberOfCameras(
ICameraService::CAMERA_TYPE_ALL, &num_cameras);
CHECK(status.isOk()) << "Failed to get number of cameras";
CHECK(num_cameras > 0)
<< "ICameraService reports no cameras available";
const int camera_id = 0;
LOG(INFO) << "Connecting to camera " << camera_id;
sp<CameraDeviceCallbacks> camera_cb =
new CameraDeviceCallbacks(&message_loop);
sp<ICameraDeviceCallbacks> camera_cb_alias = camera_cb;
const String16 client_package_name("brillo");
sp<ICameraDeviceUser> camera_device_user;
status = camera_service->connectDevice(
camera_cb_alias, camera_id, client_package_name,
ICameraService::USE_CALLING_UID,
&camera_device_user);
CHECK(status.isOk()) << "Failed to connect to camera id="
<< camera_id << " error=" << status.toString8();
LOG(INFO) << "Obtaining camera info";
CameraMetadata camera_metadata;
status = camera_device_user->getCameraInfo(&camera_metadata);
CHECK(status.isOk()) << "Failed to get camera info, error="
<< status.toString8();
LOG(INFO) << "Calculating smallest stream configuration";
camera_metadata_entry streamConfigs =
camera_metadata.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
int32_t width = std::numeric_limits<int32_t>::max();
int32_t height = 1;
for (size_t i = 0; i < streamConfigs.count; i += 4) {
LOG(INFO) << "Found " << streamConfigs.count << " stream configs.";
int32_t fmt = streamConfigs.data.i32[i];
LOG(INFO) << "Format: " << fmt;
int32_t inout = streamConfigs.data.i32[i + 3];
LOG(INFO) << "inout: " << inout;
if (fmt == ANDROID_SCALER_AVAILABLE_FORMATS_RAW16 &&
inout == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
int32_t w = streamConfigs.data.i32[i + 1];
int32_t h = streamConfigs.data.i32[i + 2];
LOG(INFO) << "w: " << w << " h: " << h;
if (width * height > w * h) {
width = w;
height = h;
}
}
}
LOG(INFO) << "width = " << width << " height = " << height;
CHECK(width != std::numeric_limits<int32_t>::max())
<< "Unable to configure stream dimensions";
LOG(INFO) << "Obtaining buffer queue";
sp<IGraphicBufferProducer> buffer_producer = nullptr;
sp<IGraphicBufferConsumer> buffer_consumer = nullptr;
BufferQueue::createBufferQueue(&buffer_producer, &buffer_consumer);
CHECK(buffer_producer.get() != nullptr && buffer_consumer.get() != nullptr);
LOG(INFO) << "Creating buffer consumer";
sp<CpuConsumer> consumer = new CpuConsumer(
buffer_consumer, 1 /* one frame only */, true /* controlled by app */);
consumer->setDefaultBufferSize(width, height);
consumer->setDefaultBufferFormat(kHalPixelFormat);
LOG(INFO) << "Configuring the camera";
status = camera_device_user->beginConfigure();
CHECK(status.isOk()) << "Failed calling ICameraDeviceUser::beginConfigure()"
<< " error = " << status.toString8();
android::OutputConfiguration output_configuration(
buffer_producer, CAMERA3_STREAM_ROTATION_0);
int32_t stream_id;
status = camera_device_user->createStream(output_configuration, &stream_id);
CHECK(status.isOk()) << "Failed calling ICameraDeviceUser::createStream()"
<< " error = " << status.toString8();
status = camera_device_user->endConfigure(false /* isConstrainedHighSpeed */);
CHECK(status.isOk()) << "Failed calling ICameraDeviceUser::endConfigure()"
<< " error = " << status.toString8();
LOG(INFO) << "Creating capture_request";
// CaptureRequest doesn't define incStrong, can't be strong pointer.
CaptureRequest* capture_request = new CaptureRequest;
status = camera_device_user->createDefaultRequest(
CAMERA3_TEMPLATE_STILL_CAPTURE, &capture_request->mMetadata);
sp<Surface> surface = new Surface(
buffer_producer, true /* controlled by app */);
capture_request->mSurfaceList.push_back(surface);
capture_request->mIsReprocess = false;
LOG(INFO) << "Submitting capture request";
SubmitInfo submit_info;
status = camera_device_user->submitRequest(
*capture_request, false, &submit_info);
CHECK(status.isOk()) << "Got error=" << status.toString8()
<< " while submitting capture request.";
LOG(INFO) << "Waiting for the camera to take a picture.";
// If we don't hear back from the camera for long enough, just time out.
message_loop.PostDelayedTask(
base::Bind(&brillo::BaseMessageLoop::BreakLoop,
base::Unretained(&message_loop)),
base::TimeDelta::FromSeconds(30));
message_loop.Run(); // We'll exit on a callback from the camera.
CHECK(camera_cb->result_received());
// TODO(wiley) render this image to a file to save somewhere.
// Cleanup.
delete capture_request;
return 0;
}