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
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;
+}