| /* |
| * 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 android::BnCameraDeviceCallbacks; |
| using android::BufferQueue; |
| using android::CameraMetadata; |
| using android::CaptureRequest; |
| using android::CaptureResultExtras; |
| using android::CpuConsumer; |
| using android::ICameraDeviceCallbacks; |
| using android::ICameraDeviceUser; |
| using android::ICameraService; |
| using android::IGraphicBufferConsumer; |
| using android::IGraphicBufferProducer; |
| using android::OK; |
| using android::String16; |
| using android::Surface; |
| using android::sp; |
| |
| 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; |
| } |