diff options
author | Christopher Wiley <wiley@google.com> | 2016-02-17 12:30:30 -0800 |
---|---|---|
committer | Christopher Wiley <wiley@google.com> | 2016-02-25 12:10:05 -0800 |
commit | 4d0acca2374437bab19e6640ff7141fbc557723d (patch) | |
tree | b17fd6102c43a4085e12038e7a9ea234cdbcd9c2 | |
parent | 0e344a92a6536fe72af1b98bbf07f715b33dbfd2 (diff) | |
download | common-4d0acca2374437bab19e6640ff7141fbc557723d.tar.gz |
Add example of taking a picture with the camera stack
Bug: 23631807
Test: Running this code on a brilloemulator claims to have taken a
picture
Change-Id: I8d43fe7ed7b72f6293c57c08addef5fc1354f01f
-rw-r--r-- | brillo_camera/Android.mk | 36 | ||||
-rw-r--r-- | brillo_camera/main.cpp | 219 |
2 files changed, 255 insertions, 0 deletions
diff --git a/brillo_camera/Android.mk b/brillo_camera/Android.mk new file mode 100644 index 0000000..ab5de75 --- /dev/null +++ b/brillo_camera/Android.mk @@ -0,0 +1,36 @@ +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := brillo_camera_client +ifdef BRILLO +LOCAL_MODULE_TAGS := eng +endif # defined(BRILLO) +LOCAL_CFLAGS := -Wall -Werror +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libbrillo \ + libbrillo-binder \ + libcamera_client \ + libcamera_metadata \ + libchrome \ + libcutils \ + libgui \ + libutils +LOCAL_SRC_FILES := \ + main.cpp +include $(BUILD_EXECUTABLE) diff --git a/brillo_camera/main.cpp b/brillo_camera/main.cpp new file mode 100644 index 0000000..244c7e9 --- /dev/null +++ b/brillo_camera/main.cpp @@ -0,0 +1,219 @@ +/* + * 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 <camera/ICameraService.h> +#include <camera/camera2/CaptureRequest.h> +#include <camera/camera2/ICameraDeviceCallbacks.h> +#include <camera/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 namespace android; + +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) {} + + void onDeviceError(ICameraDeviceCallbacks::CameraErrorCode error_code, + const CaptureResultExtras& /* result_extras */) override { + LOG(ERROR) << "Received camera error = " << error_code; + loop_->BreakLoop(); + } + + void onDeviceIdle() override { + LOG(INFO) << "Camera device is idle"; + } + + void onCaptureStarted( + const CaptureResultExtras& /* result_extras */, + int64_t /* timestamp */) override { + LOG(INFO) << "Capture started."; + } + + void onResultReceived( + const CameraMetadata& /* metadata */, + const CaptureResultExtras& /* result_extras */) override { + LOG(INFO) << "Capture result received"; + result_received_ = true; + loop_->BreakLoop(); + } + + void onPrepared(int stream_id) override { + LOG(INFO) << "Camera is prepared for stream " << stream_id; + } + + 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; + + // 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 status = android::getService( + String16(kCameraServiceName), &camera_service); + CHECK(status == OK) + << "Failed to get ICameraService binder from service manager!"; + + LOG(INFO) << "Asking how many cameras we have."; + const int32_t num_cameras = camera_service->getNumberOfCameras( + ICameraService::CAMERA_TYPE_ALL); + 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 == OK) << "Failed to connect to camera id=" << camera_id + << " error=" << status; + + LOG(INFO) << "Obtaining camera info"; + CameraMetadata camera_metadata; + status = camera_device_user->getCameraInfo(&camera_metadata); + CHECK(status == OK) << "Failed to get camera info, error=" << status; + + 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) { + int32_t fmt = streamConfigs.data.i32[i]; + int32_t inout = streamConfigs.data.i32[i + 3]; + 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]; + + 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 == OK) << "Failed calling ICameraDeviceUser::beginConfigure()" + << " error = " << status; + android::OutputConfiguration output_configuration( + buffer_producer, CAMERA3_STREAM_ROTATION_0); + status = camera_device_user->createStream(output_configuration); + CHECK(status == OK) << "Failed calling ICameraDeviceUser::createStream()" + << " error = " << status; + status = camera_device_user->endConfigure(false /* isConstrainedHighSpeed */); + CHECK(status == OK) << "Failed calling ICameraDeviceUser::endConfigure()" + << " error = " << status; + + LOG(INFO) << "Creating capture_request"; + sp<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"; + int64_t last_frame_number = 0; + status = camera_device_user->submitRequest( + capture_request, false, &last_frame_number); + CHECK(status == OK) << "Got error=" << status + << " 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. + + return 0; +} |