/* * Copyright (C) 2017 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. */ /* * Contains implementation of a class EmulatedQemuCamera3 that encapsulates * functionality of an advanced fake camera. */ // Uncomment LOG_NDEBUG to enable verbose logging, and uncomment both LOG_NDEBUG // *and* LOG_NNDEBUG to enable very verbose logging. //#define LOG_NDEBUG 0 //#define LOG_NNDEBUG 0 #define LOG_TAG "EmulatedCamera_QemuCamera3" #if defined(LOG_NNDEBUG) && LOG_NNDEBUG == 0 #define ALOGVV ALOGV #else #define ALOGVV(...) ((void)0) #endif #include "EmulatedCameraFactory.h" #include "GrallocModule.h" #include "EmulatedQemuCamera3.h" #include <cmath> #include <cutils/properties.h> #include <inttypes.h> #include <sstream> #include <ui/Fence.h> #include <utils/Log.h> #include <vector> namespace android { /* * Constants for Camera Capabilities */ const int64_t USEC = 1000LL; const int64_t MSEC = USEC * 1000LL; const int64_t SEC = MSEC * 1000LL; const int32_t EmulatedQemuCamera3::kAvailableFormats[] = { HAL_PIXEL_FORMAT_BLOB, HAL_PIXEL_FORMAT_RGBA_8888, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, // These are handled by YCbCr_420_888 // HAL_PIXEL_FORMAT_YV12, // HAL_PIXEL_FORMAT_YCrCb_420_SP, HAL_PIXEL_FORMAT_YCbCr_420_888 }; /** * 3A constants */ // Default exposure and gain targets for different scenarios const nsecs_t EmulatedQemuCamera3::kNormalExposureTime = 10 * MSEC; const nsecs_t EmulatedQemuCamera3::kFacePriorityExposureTime = 30 * MSEC; const int EmulatedQemuCamera3::kNormalSensitivity = 100; const int EmulatedQemuCamera3::kFacePrioritySensitivity = 400; //CTS requires 8 frames timeout in waitForAeStable const float EmulatedQemuCamera3::kExposureTrackRate = 0.2; const int EmulatedQemuCamera3::kPrecaptureMinFrames = 10; const int EmulatedQemuCamera3::kStableAeMaxFrames = 100; const float EmulatedQemuCamera3::kExposureWanderMin = -2; const float EmulatedQemuCamera3::kExposureWanderMax = 1; /***************************************************************************** * Constructor/Destructor ****************************************************************************/ EmulatedQemuCamera3::EmulatedQemuCamera3(int cameraId, struct hw_module_t* module) : EmulatedCamera3(cameraId, module) { ALOGI("Constructing emulated qemu camera 3: ID %d", mCameraID); for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; ++i) { mDefaultTemplates[i] = nullptr; } } EmulatedQemuCamera3::~EmulatedQemuCamera3() { for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; ++i) { if (mDefaultTemplates[i] != nullptr) { free_camera_metadata(mDefaultTemplates[i]); } } delete[] mDeviceName; } /***************************************************************************** * Public Methods ****************************************************************************/ /* * Camera Device Lifecycle Methods */ void EmulatedQemuCamera3::parseResolutions(const char *frameDims) { const size_t kMaxFrameDimsLength = 512; size_t frameDimsLength = strnlen(frameDims, kMaxFrameDimsLength); if (frameDimsLength == kMaxFrameDimsLength) { ALOGE("%s: Frame dimensions string was too long (>= %d)", __FUNCTION__, frameDimsLength); return; } else if (frameDimsLength == 0) { ALOGE("%s: Frame dimensions string was NULL or zero-length", __FUNCTION__); return; } std::stringstream ss(frameDims); std::string input; while (std::getline(ss, input, ',')) { int width = 0; int height = 0; char none = 0; /* * Expect only two results because that means there was nothing after * the height, we don't want any trailing characters. Otherwise, we just * ignore this entry. */ if (sscanf(input.c_str(), "%dx%d%c", &width, &height, &none) == 2) { mResolutions.push_back(std::pair<int32_t,int32_t>(width, height)); ALOGE("%s: %dx%d", __FUNCTION__, width, height); } } /* * We assume the sensor size of the webcam is the resolution with the * largest area. Any resolution with a dimension that exceeds the sensor * size will be rejected, so Camera API calls will start failing. To work * around this, we remove any resolutions with at least one dimension * exceeding that of the max area resolution. */ // Find the resolution with the maximum area and use that as the sensor // size. int maxArea = 0; for (const auto &res : mResolutions) { int area = res.first * res.second; if (area > maxArea) { maxArea = area; mSensorWidth = res.first; mSensorHeight = res.second; } } // Remove any resolution with a dimension exceeding the sensor size. for (auto res = mResolutions.begin(); res != mResolutions.end(); ) { if (res->first > mSensorWidth || res->second > mSensorHeight) { // Width and/or height larger than sensor. Remove it. res = mResolutions.erase(res); } else { ++res; } } if (mResolutions.empty()) { ALOGE("%s: Qemu camera has no valid resolutions", __FUNCTION__); } } status_t EmulatedQemuCamera3::Initialize(const char *deviceName, const char *frameDims, const char *facingDir) { if (mStatus != STATUS_ERROR) { ALOGE("%s: Already initialized!", __FUNCTION__); return INVALID_OPERATION; } /* * Save parameters for later. */ mDeviceName = deviceName; parseResolutions(frameDims); if (strcmp("back", facingDir) == 0) { mFacingBack = true; } else { mFacingBack = false; } // We no longer need these two strings. delete[] frameDims; delete[] facingDir; status_t res = getCameraCapabilities(); if (res != OK) { ALOGE("%s: Unable to get camera capabilities: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } res = constructStaticInfo(); if (res != OK) { ALOGE("%s: Unable to allocate static info: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } return EmulatedCamera3::Initialize(); } status_t EmulatedQemuCamera3::connectCamera(hw_device_t** device) { Mutex::Autolock l(mLock); status_t res; if (mStatus != STATUS_CLOSED) { ALOGE("%s: Can't connect in state %d", __FUNCTION__, mStatus); return INVALID_OPERATION; } /* * Initialize sensor. */ mSensor = new QemuSensor(mDeviceName, mSensorWidth, mSensorHeight); mSensor->setQemuSensorListener(this); res = mSensor->startUp(); if (res != NO_ERROR) { return res; } mReadoutThread = new ReadoutThread(this); mJpegCompressor = new JpegCompressor(); res = mReadoutThread->run("EmuCam3::readoutThread"); if (res != NO_ERROR) return res; return EmulatedCamera3::connectCamera(device); } status_t EmulatedQemuCamera3::closeCamera() { status_t res; { Mutex::Autolock l(mLock); if (mStatus == STATUS_CLOSED) return OK; res = mSensor->shutDown(); if (res != NO_ERROR) { ALOGE("%s: Unable to shut down sensor: %d", __FUNCTION__, res); return res; } mSensor.clear(); mReadoutThread->requestExit(); } mReadoutThread->join(); { Mutex::Autolock l(mLock); // Clear out private stream information. for (StreamIterator s = mStreams.begin(); s != mStreams.end(); s++) { PrivateStreamInfo *privStream = static_cast<PrivateStreamInfo*>((*s)->priv); delete privStream; (*s)->priv = nullptr; } mStreams.clear(); mReadoutThread.clear(); } return EmulatedCamera3::closeCamera(); } status_t EmulatedQemuCamera3::getCameraInfo(struct camera_info *info) { info->facing = mFacingBack ? CAMERA_FACING_BACK : CAMERA_FACING_FRONT; info->orientation = gEmulatedCameraFactory.getFakeCameraOrientation(); return EmulatedCamera3::getCameraInfo(info); } /* * Camera3 Interface Methods */ status_t EmulatedQemuCamera3::configureStreams( camera3_stream_configuration *streamList) { Mutex::Autolock l(mLock); ALOGV("%s: %d streams", __FUNCTION__, streamList->num_streams); if (mStatus != STATUS_OPEN && mStatus != STATUS_READY) { ALOGE("%s: Cannot configure streams in state %d", __FUNCTION__, mStatus); return NO_INIT; } /* * Sanity-check input list. */ if (streamList == nullptr) { ALOGE("%s: NULL stream configuration", __FUNCTION__); return BAD_VALUE; } if (streamList->streams == nullptr) { ALOGE("%s: NULL stream list", __FUNCTION__); return BAD_VALUE; } if (streamList->num_streams < 1) { ALOGE("%s: Bad number of streams requested: %d", __FUNCTION__, streamList->num_streams); return BAD_VALUE; } camera3_stream_t *inputStream = nullptr; for (size_t i = 0; i < streamList->num_streams; ++i) { camera3_stream_t *newStream = streamList->streams[i]; if (newStream == nullptr) { ALOGE("%s: Stream index %zu was NULL", __FUNCTION__, i); return BAD_VALUE; } ALOGV("%s: Stream %p (id %zu), type %d, usage 0x%x, format 0x%x", __FUNCTION__, newStream, i, newStream->stream_type, newStream->usage, newStream->format); if (newStream->stream_type == CAMERA3_STREAM_INPUT || newStream->stream_type == CAMERA3_STREAM_BIDIRECTIONAL) { if (inputStream != nullptr) { ALOGE("%s: Multiple input streams requested!", __FUNCTION__); return BAD_VALUE; } inputStream = newStream; } bool validFormat = false; size_t numFormats = sizeof(kAvailableFormats) / sizeof(kAvailableFormats[0]); for (size_t f = 0; f < numFormats; ++f) { if (newStream->format == kAvailableFormats[f]) { validFormat = true; break; } } if (!validFormat) { ALOGE("%s: Unsupported stream format 0x%x requested", __FUNCTION__, newStream->format); return BAD_VALUE; } } mInputStream = inputStream; /* * Initially mark all existing streams as not alive. */ for (StreamIterator s = mStreams.begin(); s != mStreams.end(); ++s) { PrivateStreamInfo *privStream = static_cast<PrivateStreamInfo*>((*s)->priv); privStream->alive = false; } /* * Find new streams and mark still-alive ones. */ for (size_t i = 0; i < streamList->num_streams; ++i) { camera3_stream_t *newStream = streamList->streams[i]; if (newStream->priv == nullptr) { // New stream. Construct info. PrivateStreamInfo *privStream = new PrivateStreamInfo(); privStream->alive = true; newStream->max_buffers = kMaxBufferCount; newStream->priv = privStream; mStreams.push_back(newStream); } else { // Existing stream, mark as still alive. PrivateStreamInfo *privStream = static_cast<PrivateStreamInfo*>(newStream->priv); privStream->alive = true; } // Always update usage and max buffers. newStream->max_buffers = kMaxBufferCount; switch (newStream->stream_type) { case CAMERA3_STREAM_OUTPUT: newStream->usage |= GRALLOC_USAGE_HW_CAMERA_WRITE; break; case CAMERA3_STREAM_INPUT: newStream->usage |= GRALLOC_USAGE_HW_CAMERA_READ; break; case CAMERA3_STREAM_BIDIRECTIONAL: newStream->usage |= GRALLOC_USAGE_HW_CAMERA_READ | GRALLOC_USAGE_HW_CAMERA_WRITE; break; } // Set the buffer format, inline with gralloc implementation if (newStream->format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { if (newStream->usage & GRALLOC_USAGE_HW_CAMERA_WRITE) { if (newStream->usage & GRALLOC_USAGE_HW_TEXTURE) { newStream->format = HAL_PIXEL_FORMAT_RGBA_8888; } else if (newStream->usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) { newStream->format = HAL_PIXEL_FORMAT_YCbCr_420_888; } else { newStream->format = HAL_PIXEL_FORMAT_RGB_888; } } } } /* * Reap the dead streams. */ for (StreamIterator s = mStreams.begin(); s != mStreams.end();) { PrivateStreamInfo *privStream = static_cast<PrivateStreamInfo*>((*s)->priv); if (!privStream->alive) { (*s)->priv = nullptr; delete privStream; s = mStreams.erase(s); } else { ++s; } } /* * Can't reuse settings across configure call. */ mPrevSettings.clear(); return OK; } status_t EmulatedQemuCamera3::registerStreamBuffers( const camera3_stream_buffer_set *bufferSet) { Mutex::Autolock l(mLock); ALOGE("%s: Should not be invoked on HAL versions >= 3.2!", __FUNCTION__); return NO_INIT; } const camera_metadata_t* EmulatedQemuCamera3::constructDefaultRequestSettings( int type) { Mutex::Autolock l(mLock); if (type < 0 || type >= CAMERA3_TEMPLATE_COUNT) { ALOGE("%s: Unknown request settings template: %d", __FUNCTION__, type); return nullptr; } if (!hasCapability(BACKWARD_COMPATIBLE) && type != CAMERA3_TEMPLATE_PREVIEW) { ALOGE("%s: Template %d not supported w/o BACKWARD_COMPATIBLE capability", __FUNCTION__, type); return nullptr; } /* * Cache is not just an optimization - pointer returned has to live at least * as long as the camera device instance does. */ if (mDefaultTemplates[type] != nullptr) { return mDefaultTemplates[type]; } CameraMetadata settings; /* android.request */ static const uint8_t metadataMode = ANDROID_REQUEST_METADATA_MODE_FULL; settings.update(ANDROID_REQUEST_METADATA_MODE, &metadataMode, 1); static const int32_t id = 0; settings.update(ANDROID_REQUEST_ID, &id, 1); static const int32_t frameCount = 0; settings.update(ANDROID_REQUEST_FRAME_COUNT, &frameCount, 1); /* android.lens */ static const float focalLength = 5.0f; settings.update(ANDROID_LENS_FOCAL_LENGTH, &focalLength, 1); if (hasCapability(BACKWARD_COMPATIBLE)) { static const float focusDistance = 0; settings.update(ANDROID_LENS_FOCUS_DISTANCE, &focusDistance, 1); static const float aperture = 2.8f; settings.update(ANDROID_LENS_APERTURE, &aperture, 1); static const float filterDensity = 0; settings.update(ANDROID_LENS_FILTER_DENSITY, &filterDensity, 1); static const uint8_t opticalStabilizationMode = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF; settings.update(ANDROID_LENS_OPTICAL_STABILIZATION_MODE, &opticalStabilizationMode, 1); // FOCUS_RANGE set only in frame } /* android.flash */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t flashMode = ANDROID_FLASH_MODE_OFF; settings.update(ANDROID_FLASH_MODE, &flashMode, 1); static const uint8_t flashPower = 10; settings.update(ANDROID_FLASH_FIRING_POWER, &flashPower, 1); static const int64_t firingTime = 0; settings.update(ANDROID_FLASH_FIRING_TIME, &firingTime, 1); } /* android.scaler */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const int32_t cropRegion[4] = { 0, 0, mSensorWidth, mSensorHeight }; settings.update(ANDROID_SCALER_CROP_REGION, cropRegion, 4); } /* android.jpeg */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t jpegQuality = 80; settings.update(ANDROID_JPEG_QUALITY, &jpegQuality, 1); static const int32_t thumbnailSize[2] = { 320, 240 }; settings.update(ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2); static const uint8_t thumbnailQuality = 80; settings.update(ANDROID_JPEG_THUMBNAIL_QUALITY, &thumbnailQuality, 1); static const double gpsCoordinates[3] = { 0, 0, 0 }; settings.update(ANDROID_JPEG_GPS_COORDINATES, gpsCoordinates, 3); static const uint8_t gpsProcessingMethod[32] = "None"; settings.update(ANDROID_JPEG_GPS_PROCESSING_METHOD, gpsProcessingMethod, 32); static const int64_t gpsTimestamp = 0; settings.update(ANDROID_JPEG_GPS_TIMESTAMP, &gpsTimestamp, 1); static const int32_t jpegOrientation = 0; settings.update(ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1); } /* android.stats */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF; settings.update(ANDROID_STATISTICS_FACE_DETECT_MODE, &faceDetectMode, 1); static const uint8_t hotPixelMapMode = ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF; settings.update(ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE, &hotPixelMapMode, 1); } /* android.control */ uint8_t controlIntent = 0; switch (type) { case CAMERA3_TEMPLATE_PREVIEW: controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW; break; case CAMERA3_TEMPLATE_STILL_CAPTURE: controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE; break; case CAMERA3_TEMPLATE_VIDEO_RECORD: controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD; break; case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT: controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT; break; case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG: controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG; break; case CAMERA3_TEMPLATE_MANUAL: controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL; break; default: controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM; break; } settings.update(ANDROID_CONTROL_CAPTURE_INTENT, &controlIntent, 1); const uint8_t controlMode = (type == CAMERA3_TEMPLATE_MANUAL) ? ANDROID_CONTROL_MODE_OFF : ANDROID_CONTROL_MODE_AUTO; settings.update(ANDROID_CONTROL_MODE, &controlMode, 1); int32_t aeTargetFpsRange[2] = { 5, 30 }; if (type == CAMERA3_TEMPLATE_VIDEO_RECORD || type == CAMERA3_TEMPLATE_VIDEO_SNAPSHOT) { aeTargetFpsRange[0] = 30; } settings.update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, aeTargetFpsRange, 2); if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t effectMode = ANDROID_CONTROL_EFFECT_MODE_OFF; settings.update(ANDROID_CONTROL_EFFECT_MODE, &effectMode, 1); static const uint8_t sceneMode = ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY; settings.update(ANDROID_CONTROL_SCENE_MODE, &sceneMode, 1); const uint8_t aeMode = (type == CAMERA3_TEMPLATE_MANUAL) ? ANDROID_CONTROL_AE_MODE_OFF : ANDROID_CONTROL_AE_MODE_ON; settings.update(ANDROID_CONTROL_AE_MODE, &aeMode, 1); static const uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF; settings.update(ANDROID_CONTROL_AE_LOCK, &aeLock, 1); static const int32_t controlRegions[5] = { 0, 0, 0, 0, 0 }; settings.update(ANDROID_CONTROL_AE_REGIONS, controlRegions, 5); static const int32_t aeExpCompensation = 0; settings.update(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, &aeExpCompensation, 1); static const uint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO; settings.update(ANDROID_CONTROL_AE_ANTIBANDING_MODE, &aeAntibandingMode, 1); static const uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE; settings.update(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &aePrecaptureTrigger, 1); const uint8_t awbMode = (type == CAMERA3_TEMPLATE_MANUAL) ? ANDROID_CONTROL_AWB_MODE_OFF : ANDROID_CONTROL_AWB_MODE_AUTO; settings.update(ANDROID_CONTROL_AWB_MODE, &awbMode, 1); static const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF; settings.update(ANDROID_CONTROL_AWB_LOCK, &awbLock, 1); uint8_t afMode = 0; if (mFacingBack) { switch (type) { case CAMERA3_TEMPLATE_PREVIEW: afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE; break; case CAMERA3_TEMPLATE_STILL_CAPTURE: afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE; break; case CAMERA3_TEMPLATE_VIDEO_RECORD: afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO; break; case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT: afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO; break; case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG: afMode = ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE; break; case CAMERA3_TEMPLATE_MANUAL: afMode = ANDROID_CONTROL_AF_MODE_OFF; break; default: afMode = ANDROID_CONTROL_AF_MODE_AUTO; break; } } else { afMode = ANDROID_CONTROL_AF_MODE_OFF; } settings.update(ANDROID_CONTROL_AF_MODE, &afMode, 1); settings.update(ANDROID_CONTROL_AF_REGIONS, controlRegions, 5); static const uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE; settings.update(ANDROID_CONTROL_AF_TRIGGER, &afTrigger, 1); static const uint8_t vstabMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF; settings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &vstabMode, 1); static const uint8_t blackLevelLock = ANDROID_BLACK_LEVEL_LOCK_OFF; settings.update(ANDROID_BLACK_LEVEL_LOCK, &blackLevelLock, 1); static const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF; settings.update(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1); static const uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST; settings.update(ANDROID_COLOR_CORRECTION_ABERRATION_MODE, &aberrationMode, 1); static const int32_t testPatternMode = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF; settings.update(ANDROID_SENSOR_TEST_PATTERN_MODE, &testPatternMode, 1); } mDefaultTemplates[type] = settings.release(); return mDefaultTemplates[type]; } status_t EmulatedQemuCamera3::processCaptureRequest( camera3_capture_request *request) { Mutex::Autolock l(mLock); status_t res; /* Validation */ if (mStatus < STATUS_READY) { ALOGE("%s: Can't submit capture requests in state %d", __FUNCTION__, mStatus); return INVALID_OPERATION; } if (request == nullptr) { ALOGE("%s: NULL request!", __FUNCTION__); return BAD_VALUE; } uint32_t frameNumber = request->frame_number; if (request->settings == nullptr && mPrevSettings.isEmpty()) { ALOGE("%s: Request %d: NULL settings for first request after" "configureStreams()", __FUNCTION__, frameNumber); return BAD_VALUE; } if (request->input_buffer != nullptr && request->input_buffer->stream != mInputStream) { ALOGE("%s: Request %d: Input buffer not from input stream!", __FUNCTION__, frameNumber); ALOGV("%s: Bad stream %p, expected: %p", __FUNCTION__, request->input_buffer->stream, mInputStream); ALOGV("%s: Bad stream type %d, expected stream type %d", __FUNCTION__, request->input_buffer->stream->stream_type, mInputStream ? mInputStream->stream_type : -1); return BAD_VALUE; } if (request->num_output_buffers < 1 || request->output_buffers == nullptr) { ALOGE("%s: Request %d: No output buffers provided!", __FUNCTION__, frameNumber); return BAD_VALUE; } /* * Validate all buffers, starting with input buffer if it's given. */ ssize_t idx; const camera3_stream_buffer_t *b; if (request->input_buffer != nullptr) { idx = -1; b = request->input_buffer; } else { idx = 0; b = request->output_buffers; } do { PrivateStreamInfo *priv = static_cast<PrivateStreamInfo*>(b->stream->priv); if (priv == nullptr) { ALOGE("%s: Request %d: Buffer %zu: Unconfigured stream!", __FUNCTION__, frameNumber, idx); return BAD_VALUE; } if (!priv->alive) { ALOGE("%s: Request %d: Buffer %zu: Dead stream!", __FUNCTION__, frameNumber, idx); return BAD_VALUE; } if (b->status != CAMERA3_BUFFER_STATUS_OK) { ALOGE("%s: Request %d: Buffer %zu: Status not OK!", __FUNCTION__, frameNumber, idx); return BAD_VALUE; } if (b->release_fence != -1) { ALOGE("%s: Request %d: Buffer %zu: Has a release fence!", __FUNCTION__, frameNumber, idx); return BAD_VALUE; } if (b->buffer == nullptr) { ALOGE("%s: Request %d: Buffer %zu: NULL buffer handle!", __FUNCTION__, frameNumber, idx); return BAD_VALUE; } idx++; b = &(request->output_buffers[idx]); } while (idx < (ssize_t)request->num_output_buffers); // TODO: Validate settings parameters. /* * Start processing this request. */ mStatus = STATUS_ACTIVE; CameraMetadata settings; if (request->settings == nullptr) { settings.acquire(mPrevSettings); } else { settings = request->settings; } res = process3A(settings); if (res != OK) { return res; } /* * Get ready for sensor config. */ // TODO: We shouldn't need exposureTime or frameDuration for webcams. nsecs_t exposureTime; nsecs_t frameDuration; bool needJpeg = false; camera_metadata_entry_t entry; entry = settings.find(ANDROID_SENSOR_EXPOSURE_TIME); exposureTime = (entry.count > 0) ? entry.data.i64[0] : QemuSensor::kExposureTimeRange[0]; // Note: Camera consumers may rely on there being an exposure // time set in the camera metadata. settings.update(ANDROID_SENSOR_EXPOSURE_TIME, &exposureTime, 1); entry = settings.find(ANDROID_SENSOR_FRAME_DURATION); frameDuration = (entry.count > 0) ? entry.data.i64[0] : QemuSensor::kFrameDurationRange[0]; if (exposureTime > frameDuration) { frameDuration = exposureTime + QemuSensor::kMinVerticalBlank; settings.update(ANDROID_SENSOR_FRAME_DURATION, &frameDuration, 1); } static const int32_t sensitivity = QemuSensor::kSensitivityRange[0]; settings.update(ANDROID_SENSOR_SENSITIVITY, &sensitivity, 1); static const uint8_t colorMode = ANDROID_COLOR_CORRECTION_MODE_FAST; settings.update(ANDROID_COLOR_CORRECTION_MODE, &colorMode, 1); static const float colorGains[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; settings.update(ANDROID_COLOR_CORRECTION_GAINS, colorGains, 4); static const camera_metadata_rational colorTransform[9] = { {1,1}, {0,1}, {0,1}, {0,1}, {1,1}, {0,1}, {0,1}, {0,1}, {1,1} }; settings.update(ANDROID_COLOR_CORRECTION_TRANSFORM, colorTransform, 9); static const camera_metadata_rational neutralColorPoint[3] = { {1,1}, {1,1}, {1,1}, }; settings.update(ANDROID_SENSOR_NEUTRAL_COLOR_POINT, neutralColorPoint, 3); Buffers *sensorBuffers = new Buffers(); HalBufferVector *buffers = new HalBufferVector(); sensorBuffers->setCapacity(request->num_output_buffers); buffers->setCapacity(request->num_output_buffers); /* * Process all the buffers we got for output, constructing internal buffer * structures for them, and lock them for writing. */ for (size_t i = 0; i < request->num_output_buffers; ++i) { const camera3_stream_buffer &srcBuf = request->output_buffers[i]; StreamBuffer destBuf; destBuf.streamId = kGenericStreamId; destBuf.width = srcBuf.stream->width; destBuf.height = srcBuf.stream->height; // inline with goldfish gralloc if (srcBuf.stream->format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { if (srcBuf.stream->usage & GRALLOC_USAGE_HW_CAMERA_WRITE) { if (srcBuf.stream->usage & GRALLOC_USAGE_HW_TEXTURE) { destBuf.format = HAL_PIXEL_FORMAT_RGBA_8888; } else if (srcBuf.stream->usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) { destBuf.format = HAL_PIXEL_FORMAT_YCbCr_420_888; } else if ((srcBuf.stream->usage & GRALLOC_USAGE_HW_CAMERA_MASK) == GRALLOC_USAGE_HW_CAMERA_ZSL) { destBuf.format = HAL_PIXEL_FORMAT_RGB_888; } } } else { destBuf.format = srcBuf.stream->format; } destBuf.stride = srcBuf.stream->width; destBuf.dataSpace = srcBuf.stream->data_space; destBuf.buffer = srcBuf.buffer; if (destBuf.format == HAL_PIXEL_FORMAT_BLOB) { needJpeg = true; } // Wait on fence. sp<Fence> bufferAcquireFence = new Fence(srcBuf.acquire_fence); res = bufferAcquireFence->wait(kFenceTimeoutMs); if (res == TIMED_OUT) { ALOGE("%s: Request %d: Buffer %zu: Fence timed out after %d ms", __FUNCTION__, frameNumber, i, kFenceTimeoutMs); } if (res == OK) { // Lock buffer for writing. if (srcBuf.stream->format == HAL_PIXEL_FORMAT_YCbCr_420_888) { if (destBuf.format == HAL_PIXEL_FORMAT_YCbCr_420_888) { android_ycbcr ycbcr = android_ycbcr(); res = GrallocModule::getInstance().lock_ycbcr( *(destBuf.buffer), GRALLOC_USAGE_HW_CAMERA_WRITE, 0, 0, destBuf.width, destBuf.height, &ycbcr); /* * This is only valid because we know that emulator's * YCbCr_420_888 is really contiguous NV21 under the hood. */ destBuf.img = static_cast<uint8_t*>(ycbcr.y); } else { ALOGE("Unexpected private format for flexible YUV: 0x%x", destBuf.format); res = INVALID_OPERATION; } } else { res = GrallocModule::getInstance().lock( *(destBuf.buffer), GRALLOC_USAGE_HW_CAMERA_WRITE, 0, 0, destBuf.width, destBuf.height, (void**)&(destBuf.img)); } if (res != OK) { ALOGE("%s: Request %d: Buffer %zu: Unable to lock buffer", __FUNCTION__, frameNumber, i); } } if (res != OK) { /* * Either waiting or locking failed. Unlock locked buffers and bail * out. */ for (size_t j = 0; j < i; j++) { GrallocModule::getInstance().unlock( *(request->output_buffers[i].buffer)); } delete sensorBuffers; delete buffers; return NO_INIT; } sensorBuffers->push_back(destBuf); buffers->push_back(srcBuf); } /* * Wait for JPEG compressor to not be busy, if needed. */ if (needJpeg) { bool ready = mJpegCompressor->waitForDone(kJpegTimeoutNs); if (!ready) { ALOGE("%s: Timeout waiting for JPEG compression to complete!", __FUNCTION__); return NO_INIT; } res = mJpegCompressor->reserve(); if (res != OK) { ALOGE("%s: Error managing JPEG compressor resources, can't " "reserve it!", __FUNCTION__); return NO_INIT; } } /* * TODO: We shouldn't need to wait for sensor readout with a webcam, because * we might be wasting time. */ /* * Wait until the in-flight queue has room. */ res = mReadoutThread->waitForReadout(); if (res != OK) { ALOGE("%s: Timeout waiting for previous requests to complete!", __FUNCTION__); return NO_INIT; } /* * Wait until sensor's ready. This waits for lengthy amounts of time with * mLock held, but the interface spec is that no other calls may by done to * the HAL by the framework while process_capture_request is happening. */ int syncTimeoutCount = 0; while(!mSensor->waitForVSync(kSyncWaitTimeout)) { if (mStatus == STATUS_ERROR) { return NO_INIT; } if (syncTimeoutCount == kMaxSyncTimeoutCount) { ALOGE("%s: Request %d: Sensor sync timed out after %" PRId64 " ms", __FUNCTION__, frameNumber, kSyncWaitTimeout * kMaxSyncTimeoutCount / 1000000); return NO_INIT; } syncTimeoutCount++; } /* * Configure sensor and queue up the request to the readout thread. */ mSensor->setFrameDuration(frameDuration); mSensor->setDestinationBuffers(sensorBuffers); mSensor->setFrameNumber(request->frame_number); ReadoutThread::Request r; r.frameNumber = request->frame_number; r.settings = settings; r.sensorBuffers = sensorBuffers; r.buffers = buffers; mReadoutThread->queueCaptureRequest(r); ALOGVV("%s: Queued frame %d", __FUNCTION__, request->frame_number); // Cache the settings for next time. mPrevSettings.acquire(settings); return OK; } status_t EmulatedQemuCamera3::flush() { ALOGW("%s: Not implemented; ignored", __FUNCTION__); return OK; } /***************************************************************************** * Private Methods ****************************************************************************/ status_t EmulatedQemuCamera3::getCameraCapabilities() { const char *key = mFacingBack ? "qemu.sf.back_camera_caps" : "qemu.sf.front_camera_caps"; /* * Defined by 'qemu.sf.*_camera_caps' boot property: if the property doesn't * exist, it is assumed to list FULL. */ char prop[PROPERTY_VALUE_MAX]; if (property_get(key, prop, nullptr) > 0) { char *saveptr = nullptr; char *cap = strtok_r(prop, " ,", &saveptr); while (cap != nullptr) { for (int i = 0; i < NUM_CAPABILITIES; ++i) { if (!strcasecmp(cap, sAvailableCapabilitiesStrings[i])) { mCapabilities.add(static_cast<AvailableCapabilities>(i)); break; } } cap = strtok_r(nullptr, " ,", &saveptr); } if (mCapabilities.size() == 0) { ALOGE("qemu.sf.back_camera_caps had no valid capabilities: %s", prop); } } mCapabilities.add(BACKWARD_COMPATIBLE); ALOGI("Camera %d capabilities:", mCameraID); for (size_t i = 0; i < mCapabilities.size(); ++i) { ALOGI(" %s", sAvailableCapabilitiesStrings[mCapabilities[i]]); } return OK; } bool EmulatedQemuCamera3::hasCapability(AvailableCapabilities cap) { ssize_t idx = mCapabilities.indexOf(cap); return idx >= 0; } status_t EmulatedQemuCamera3::constructStaticInfo() { CameraMetadata info; Vector<int32_t> availableCharacteristicsKeys; status_t res; #define ADD_STATIC_ENTRY(name, varptr, count) \ availableCharacteristicsKeys.add(name); \ res = info.update(name, varptr, count); \ if (res != OK) return res static const float sensorPhysicalSize[2] = {3.20f, 2.40f}; // mm ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, sensorPhysicalSize, 2); const int32_t pixelArray[] = {mSensorWidth, mSensorHeight}; ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, pixelArray, 2); const int32_t activeArray[] = {0, 0, mSensorWidth, mSensorHeight}; ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArray, 4); static const int32_t orientation = 90; // Aligned with 'long edge'. ADD_STATIC_ENTRY(ANDROID_SENSOR_ORIENTATION, &orientation, 1); static const uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN; ADD_STATIC_ENTRY(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, ×tampSource, 1); if (hasCapability(BACKWARD_COMPATIBLE)) { static const int32_t availableTestPatternModes[] = { ANDROID_SENSOR_TEST_PATTERN_MODE_OFF }; ADD_STATIC_ENTRY(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, availableTestPatternModes, sizeof(availableTestPatternModes) / sizeof(int32_t)); } /* android.lens */ static const float focalLength = 3.30f; // mm ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, &focalLength, 1); if (hasCapability(BACKWARD_COMPATIBLE)) { // infinity (fixed focus) const float minFocusDistance = 0.0; ADD_STATIC_ENTRY(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, &minFocusDistance, 1); // (fixed focus) const float hyperFocalDistance = 0.0; ADD_STATIC_ENTRY(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE, &minFocusDistance, 1); static const float aperture = 2.8f; ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_APERTURES, &aperture, 1); static const float filterDensity = 0; ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES, &filterDensity, 1); static const uint8_t availableOpticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF; ADD_STATIC_ENTRY(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION, &availableOpticalStabilization, 1); static const int32_t lensShadingMapSize[] = {1, 1}; ADD_STATIC_ENTRY(ANDROID_LENS_INFO_SHADING_MAP_SIZE, lensShadingMapSize, sizeof(lensShadingMapSize) / sizeof(int32_t)); static const uint8_t lensFocusCalibration = ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE; ADD_STATIC_ENTRY(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, &lensFocusCalibration, 1); } static const uint8_t lensFacing = mFacingBack ? ANDROID_LENS_FACING_BACK : ANDROID_LENS_FACING_FRONT; ADD_STATIC_ENTRY(ANDROID_LENS_FACING, &lensFacing, 1); /* android.flash */ static const uint8_t flashAvailable = 0; ADD_STATIC_ENTRY(ANDROID_FLASH_INFO_AVAILABLE, &flashAvailable, 1); /* android.scaler */ std::vector<int32_t> availableStreamConfigurations; std::vector<int64_t> availableMinFrameDurations; std::vector<int64_t> availableStallDurations; /* * Build stream configurations, min frame durations, and stall durations for * all resolutions reported by camera device. */ for (const auto &res : mResolutions) { int32_t width = res.first, height = res.second; std::vector<int32_t> currentResStreamConfigurations = { HAL_PIXEL_FORMAT_BLOB, width, height, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, width, height, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, HAL_PIXEL_FORMAT_YCbCr_420_888, width, height, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, HAL_PIXEL_FORMAT_RGBA_8888, width, height, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT }; std::vector<int32_t> currentResMinFrameDurations = { HAL_PIXEL_FORMAT_BLOB, width, height, QemuSensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, width, height, QemuSensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_YCbCr_420_888, width, height, QemuSensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_RGBA_8888, width, height, QemuSensor::kFrameDurationRange[0] }; std::vector<int32_t> currentResStallDurations = { // We should only introduce stall times with JPEG-compressed frames. HAL_PIXEL_FORMAT_BLOB, width, height, QemuSensor::kFrameDurationRange[0], HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, width, height, 0, HAL_PIXEL_FORMAT_YCbCr_420_888, width, height, 0, HAL_PIXEL_FORMAT_RGBA_8888, width, height, 0 }; availableStreamConfigurations.insert( availableStreamConfigurations.end(), currentResStreamConfigurations.begin(), currentResStreamConfigurations.end()); availableMinFrameDurations.insert( availableMinFrameDurations.end(), currentResMinFrameDurations.begin(), currentResMinFrameDurations.end()); availableStallDurations.insert( availableStallDurations.end(), currentResStallDurations.begin(), currentResStallDurations.end()); } /* * Now, if nonempty, add them to the camera's available characteristics. */ if (availableStreamConfigurations.size() > 0) { ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, availableStreamConfigurations.data(), availableStreamConfigurations.size()); } if (availableMinFrameDurations.size() > 0) { ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, &availableMinFrameDurations[0], availableMinFrameDurations.size()); } if (availableStallDurations.size() > 0) { ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, &availableStallDurations[0], availableStallDurations.size()); } if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_FREEFORM; ADD_STATIC_ENTRY(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1); static const float maxZoom = 10; ADD_STATIC_ENTRY(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &maxZoom, 1); } /* android.jpeg */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const int32_t jpegThumbnailSizes[] = { 0, 0, 160, 120, 320, 240 }; ADD_STATIC_ENTRY(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegThumbnailSizes, sizeof(jpegThumbnailSizes) / sizeof(int32_t)); static const int32_t jpegMaxSize = JpegCompressor::kMaxJpegSize; ADD_STATIC_ENTRY(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1); } /* android.stats */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t availableFaceDetectModes[] = { ANDROID_STATISTICS_FACE_DETECT_MODE_OFF }; ADD_STATIC_ENTRY(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, availableFaceDetectModes, sizeof(availableFaceDetectModes)); static const int32_t maxFaceCount = 0; ADD_STATIC_ENTRY(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, &maxFaceCount, 1); static const uint8_t availableShadingMapModes[] = { ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF }; ADD_STATIC_ENTRY( ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, availableShadingMapModes, sizeof(availableShadingMapModes)); } /* android.sync */ static const int32_t maxLatency = hasCapability(FULL_LEVEL) ? ANDROID_SYNC_MAX_LATENCY_PER_FRAME_CONTROL : 3; ADD_STATIC_ENTRY(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1); /* android.control */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t availableControlModes[] = { ANDROID_CONTROL_MODE_OFF, ANDROID_CONTROL_MODE_AUTO, ANDROID_CONTROL_MODE_USE_SCENE_MODE }; ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_MODES, availableControlModes, sizeof(availableControlModes)); } else { static const uint8_t availableControlModes[] = { ANDROID_CONTROL_MODE_AUTO }; ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_MODES, availableControlModes, sizeof(availableControlModes)); } static const uint8_t availableSceneModes[] = { hasCapability(BACKWARD_COMPATIBLE) ? ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY : ANDROID_CONTROL_SCENE_MODE_DISABLED }; ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, availableSceneModes, sizeof(availableSceneModes)); if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t availableEffects[] = { ANDROID_CONTROL_EFFECT_MODE_OFF }; ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_EFFECTS, availableEffects, sizeof(availableEffects)); } if (hasCapability(BACKWARD_COMPATIBLE)) { static const int32_t max3aRegions[] = { /* AE */ 1, /* AWB */ 0, /* AF */ 1 }; ADD_STATIC_ENTRY(ANDROID_CONTROL_MAX_REGIONS, max3aRegions, sizeof(max3aRegions) / sizeof(max3aRegions[0])); static const uint8_t availableAeModes[] = { ANDROID_CONTROL_AE_MODE_OFF, ANDROID_CONTROL_AE_MODE_ON }; ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_AVAILABLE_MODES, availableAeModes, sizeof(availableAeModes)); static const camera_metadata_rational exposureCompensationStep = {1, 3}; ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_COMPENSATION_STEP, &exposureCompensationStep, 1); int32_t exposureCompensationRange[] = {-9, 9}; ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_COMPENSATION_RANGE, exposureCompensationRange, sizeof(exposureCompensationRange) / sizeof(int32_t)); } static const int32_t availableTargetFpsRanges[] = { 5, 30, 15, 30, 15, 15, 30, 30 }; ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, availableTargetFpsRanges, sizeof(availableTargetFpsRanges) / sizeof(int32_t)); if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t availableAntibandingModes[] = { ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF, ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO }; ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, availableAntibandingModes, sizeof(availableAntibandingModes)); } static const uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE; ADD_STATIC_ENTRY(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailable, 1); if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t availableAwbModes[] = { ANDROID_CONTROL_AWB_MODE_OFF, ANDROID_CONTROL_AWB_MODE_AUTO, ANDROID_CONTROL_AWB_MODE_INCANDESCENT, ANDROID_CONTROL_AWB_MODE_FLUORESCENT, ANDROID_CONTROL_AWB_MODE_DAYLIGHT, ANDROID_CONTROL_AWB_MODE_SHADE, }; ADD_STATIC_ENTRY(ANDROID_CONTROL_AWB_AVAILABLE_MODES, availableAwbModes, sizeof(availableAwbModes)); } static const uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE; ADD_STATIC_ENTRY(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &awbLockAvailable, 1); static const uint8_t availableAfModesBack[] = { ANDROID_CONTROL_AF_MODE_OFF }; static const uint8_t availableAfModesFront[] = { ANDROID_CONTROL_AF_MODE_OFF }; if (mFacingBack && hasCapability(BACKWARD_COMPATIBLE)) { ADD_STATIC_ENTRY(ANDROID_CONTROL_AF_AVAILABLE_MODES, availableAfModesBack, sizeof(availableAfModesBack)); } else { ADD_STATIC_ENTRY(ANDROID_CONTROL_AF_AVAILABLE_MODES, availableAfModesFront, sizeof(availableAfModesFront)); } static const uint8_t availableVstabModes[] = { ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF, }; ADD_STATIC_ENTRY(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, availableVstabModes, sizeof(availableVstabModes)); /* android.colorCorrection */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t availableAberrationModes[] = { ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF, ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST, ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY }; ADD_STATIC_ENTRY(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, availableAberrationModes, sizeof(availableAberrationModes)); } else { static const uint8_t availableAberrationModes[] = { ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF, }; ADD_STATIC_ENTRY(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, availableAberrationModes, sizeof(availableAberrationModes)); } /* android.edge */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t availableEdgeModes[] = { ANDROID_EDGE_MODE_OFF, ANDROID_EDGE_MODE_FAST, ANDROID_EDGE_MODE_HIGH_QUALITY, }; ADD_STATIC_ENTRY(ANDROID_EDGE_AVAILABLE_EDGE_MODES, availableEdgeModes, sizeof(availableEdgeModes)); } else { static const uint8_t availableEdgeModes[] = { ANDROID_EDGE_MODE_OFF }; ADD_STATIC_ENTRY(ANDROID_EDGE_AVAILABLE_EDGE_MODES, availableEdgeModes, sizeof(availableEdgeModes)); } /* android.info */ static const uint8_t supportedHardwareLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; ADD_STATIC_ENTRY(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &supportedHardwareLevel, /* count */ 1); /* android.noiseReduction */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t availableNoiseReductionModes[] = { ANDROID_NOISE_REDUCTION_MODE_OFF, ANDROID_NOISE_REDUCTION_MODE_FAST, ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY }; ADD_STATIC_ENTRY(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, availableNoiseReductionModes, sizeof(availableNoiseReductionModes)); } else { static const uint8_t availableNoiseReductionModes[] = { ANDROID_NOISE_REDUCTION_MODE_OFF }; ADD_STATIC_ENTRY(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, availableNoiseReductionModes, sizeof(availableNoiseReductionModes)); } /* android.shading */ if (hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t availableShadingModes[] = { ANDROID_SHADING_MODE_OFF, ANDROID_SHADING_MODE_FAST, ANDROID_SHADING_MODE_HIGH_QUALITY }; ADD_STATIC_ENTRY(ANDROID_SHADING_AVAILABLE_MODES, availableShadingModes, sizeof(availableShadingModes)); } else { static const uint8_t availableShadingModes[] = { ANDROID_SHADING_MODE_OFF }; ADD_STATIC_ENTRY(ANDROID_SHADING_AVAILABLE_MODES, availableShadingModes, sizeof(availableShadingModes)); } /* android.request */ static const int32_t maxNumOutputStreams[] = { kMaxRawStreamCount, kMaxProcessedStreamCount, kMaxJpegStreamCount }; ADD_STATIC_ENTRY(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, maxNumOutputStreams, 3); static const uint8_t maxPipelineDepth = kMaxBufferCount; ADD_STATIC_ENTRY(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &maxPipelineDepth, 1); static const int32_t partialResultCount = 1; ADD_STATIC_ENTRY(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &partialResultCount, /* count */ 1); SortedVector<uint8_t> caps; for (size_t i = 0; i < mCapabilities.size(); ++i) { switch (mCapabilities[i]) { case BACKWARD_COMPATIBLE: caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); break; case PRIVATE_REPROCESSING: caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); break; case READ_SENSOR_SETTINGS: caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS); break; case BURST_CAPTURE: caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE); break; case YUV_REPROCESSING: caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); break; case CONSTRAINED_HIGH_SPEED_VIDEO: caps.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO); break; default: // Ignore LEVELs. break; } } ADD_STATIC_ENTRY(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, caps.array(), caps.size()); // Scan a default request template for included request keys. Vector<int32_t> availableRequestKeys; const camera_metadata_t *previewRequest = constructDefaultRequestSettings(CAMERA3_TEMPLATE_PREVIEW); for (size_t i = 0; i < get_camera_metadata_entry_count(previewRequest); ++i) { camera_metadata_ro_entry_t entry; get_camera_metadata_ro_entry(previewRequest, i, &entry); availableRequestKeys.add(entry.tag); } ADD_STATIC_ENTRY(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, availableRequestKeys.array(), availableRequestKeys.size()); /* * Add a few more result keys. Must be kept up to date with the various * places that add these. */ Vector<int32_t> availableResultKeys(availableRequestKeys); if (hasCapability(BACKWARD_COMPATIBLE)) { availableResultKeys.add(ANDROID_CONTROL_AE_STATE); availableResultKeys.add(ANDROID_CONTROL_AF_STATE); availableResultKeys.add(ANDROID_CONTROL_AWB_STATE); availableResultKeys.add(ANDROID_FLASH_STATE); availableResultKeys.add(ANDROID_LENS_STATE); availableResultKeys.add(ANDROID_LENS_FOCUS_RANGE); availableResultKeys.add(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW); availableResultKeys.add(ANDROID_STATISTICS_SCENE_FLICKER); } availableResultKeys.add(ANDROID_REQUEST_PIPELINE_DEPTH); availableResultKeys.add(ANDROID_SENSOR_TIMESTAMP); ADD_STATIC_ENTRY(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, availableResultKeys.array(), availableResultKeys.size()); // Needs to be last, to collect all the keys set. availableCharacteristicsKeys.add(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS); info.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, availableCharacteristicsKeys); mCameraInfo = info.release(); #undef ADD_STATIC_ENTRY return OK; } status_t EmulatedQemuCamera3::process3A(CameraMetadata &settings) { /** * Extract top-level 3A controls */ status_t res; bool facePriority = false; camera_metadata_entry e; e = settings.find(ANDROID_CONTROL_MODE); if (e.count == 0) { ALOGE("%s: No control mode entry!", __FUNCTION__); return BAD_VALUE; } uint8_t controlMode = e.data.u8[0]; if (controlMode == ANDROID_CONTROL_MODE_OFF) { mAeMode = ANDROID_CONTROL_AE_MODE_OFF; mAfMode = ANDROID_CONTROL_AF_MODE_OFF; mAwbMode = ANDROID_CONTROL_AWB_MODE_OFF; mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE; mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE; mAwbState = ANDROID_CONTROL_AWB_STATE_INACTIVE; update3A(settings); return OK; } else if (controlMode == ANDROID_CONTROL_MODE_USE_SCENE_MODE) { if (!hasCapability(BACKWARD_COMPATIBLE)) { ALOGE("%s: Can't use scene mode when BACKWARD_COMPATIBLE not supported!", __FUNCTION__); return BAD_VALUE; } e = settings.find(ANDROID_CONTROL_SCENE_MODE); if (e.count == 0) { ALOGE("%s: No scene mode entry!", __FUNCTION__); return BAD_VALUE; } uint8_t sceneMode = e.data.u8[0]; switch(sceneMode) { case ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY: mFacePriority = true; break; default: ALOGE("%s: Emulator doesn't support scene mode %d", __FUNCTION__, sceneMode); return BAD_VALUE; } } else { mFacePriority = false; } // controlMode == AUTO or sceneMode = FACE_PRIORITY // Process individual 3A controls res = doFakeAE(settings); if (res != OK) return res; res = doFakeAF(settings); if (res != OK) return res; res = doFakeAWB(settings); if (res != OK) return res; update3A(settings); return OK; } status_t EmulatedQemuCamera3::doFakeAE(CameraMetadata &settings) { camera_metadata_entry e; e = settings.find(ANDROID_CONTROL_AE_MODE); if (e.count == 0 && hasCapability(BACKWARD_COMPATIBLE)) { ALOGE("%s: No AE mode entry!", __FUNCTION__); return BAD_VALUE; } uint8_t aeMode = (e.count > 0) ? e.data.u8[0] : (uint8_t)ANDROID_CONTROL_AE_MODE_ON; mAeMode = aeMode; switch (aeMode) { case ANDROID_CONTROL_AE_MODE_OFF: // AE is OFF mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE; return OK; case ANDROID_CONTROL_AE_MODE_ON: // OK for AUTO modes break; default: // Mostly silently ignore unsupported modes ALOGV("%s: Emulator doesn't support AE mode %d, assuming ON", __FUNCTION__, aeMode); break; } e = settings.find(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER); bool precaptureTrigger = false; if (e.count != 0) { precaptureTrigger = (e.data.u8[0] == ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START); } if (precaptureTrigger) { ALOGV("%s: Pre capture trigger = %d", __FUNCTION__, precaptureTrigger); } else if (e.count > 0) { ALOGV("%s: Pre capture trigger was present? %zu", __FUNCTION__, e.count); } if (precaptureTrigger || mAeState == ANDROID_CONTROL_AE_STATE_PRECAPTURE) { // Run precapture sequence if (mAeState != ANDROID_CONTROL_AE_STATE_PRECAPTURE) { mAeCounter = 0; } if (mFacePriority) { mAeTargetExposureTime = kFacePriorityExposureTime; } else { mAeTargetExposureTime = kNormalExposureTime; } if (mAeCounter > kPrecaptureMinFrames && (mAeTargetExposureTime - mAeCurrentExposureTime) < mAeTargetExposureTime / 10) { // Done with precapture mAeCounter = 0; mAeState = ANDROID_CONTROL_AE_STATE_CONVERGED; } else { // Converge some more mAeCurrentExposureTime += (mAeTargetExposureTime - mAeCurrentExposureTime) * kExposureTrackRate; mAeCounter++; mAeState = ANDROID_CONTROL_AE_STATE_PRECAPTURE; } } else { mAeState = ANDROID_CONTROL_AE_STATE_CONVERGED; } return OK; } status_t EmulatedQemuCamera3::doFakeAF(CameraMetadata &settings) { camera_metadata_entry e; e = settings.find(ANDROID_CONTROL_AF_MODE); if (e.count == 0 && hasCapability(BACKWARD_COMPATIBLE)) { ALOGE("%s: No AF mode entry!", __FUNCTION__); return BAD_VALUE; } uint8_t afMode = (e.count > 0) ? e.data.u8[0] : (uint8_t)ANDROID_CONTROL_AF_MODE_OFF; switch (afMode) { case ANDROID_CONTROL_AF_MODE_OFF: case ANDROID_CONTROL_AF_MODE_AUTO: case ANDROID_CONTROL_AF_MODE_MACRO: case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO: case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE: // Always report INACTIVE for Qemu Camera mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE; break; default: ALOGE("%s: Emulator doesn't support AF mode %d", __FUNCTION__, afMode); return BAD_VALUE; } return OK; } status_t EmulatedQemuCamera3::doFakeAWB(CameraMetadata &settings) { camera_metadata_entry e; e = settings.find(ANDROID_CONTROL_AWB_MODE); if (e.count == 0 && hasCapability(BACKWARD_COMPATIBLE)) { ALOGE("%s: No AWB mode entry!", __FUNCTION__); return BAD_VALUE; } uint8_t awbMode = (e.count > 0) ? e.data.u8[0] : (uint8_t)ANDROID_CONTROL_AWB_MODE_AUTO; // TODO: Add white balance simulation switch (awbMode) { case ANDROID_CONTROL_AWB_MODE_OFF: case ANDROID_CONTROL_AWB_MODE_AUTO: case ANDROID_CONTROL_AWB_MODE_INCANDESCENT: case ANDROID_CONTROL_AWB_MODE_FLUORESCENT: case ANDROID_CONTROL_AWB_MODE_DAYLIGHT: case ANDROID_CONTROL_AWB_MODE_SHADE: // Always magically right for Qemu Camera mAwbState = ANDROID_CONTROL_AWB_STATE_CONVERGED; break; default: ALOGE("%s: Emulator doesn't support AWB mode %d", __FUNCTION__, awbMode); return BAD_VALUE; } return OK; } void EmulatedQemuCamera3::update3A(CameraMetadata &settings) { if (mAeMode != ANDROID_CONTROL_AE_MODE_OFF) { settings.update(ANDROID_SENSOR_EXPOSURE_TIME, &mAeCurrentExposureTime, 1); settings.update(ANDROID_SENSOR_SENSITIVITY, &mAeCurrentSensitivity, 1); } settings.update(ANDROID_CONTROL_AE_STATE, &mAeState, 1); settings.update(ANDROID_CONTROL_AF_STATE, &mAfState, 1); settings.update(ANDROID_CONTROL_AWB_STATE, &mAwbState, 1); uint8_t lensState; switch (mAfState) { case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN: case ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN: lensState = ANDROID_LENS_STATE_MOVING; break; case ANDROID_CONTROL_AF_STATE_INACTIVE: case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED: case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED: case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: case ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED: default: lensState = ANDROID_LENS_STATE_STATIONARY; break; } settings.update(ANDROID_LENS_STATE, &lensState, 1); } void EmulatedQemuCamera3::signalReadoutIdle() { Mutex::Autolock l(mLock); /* * Need to check isIdle again because waiting on mLock may have allowed * something to be placed in the in-flight queue. */ if (mStatus == STATUS_ACTIVE && mReadoutThread->isIdle()) { ALOGV("Now idle"); mStatus = STATUS_READY; } } void EmulatedQemuCamera3::onQemuSensorEvent(uint32_t frameNumber, Event e, nsecs_t timestamp) { switch (e) { case QemuSensor::QemuSensorListener::EXPOSURE_START: ALOGVV("%s: Frame %d: Sensor started exposure at %lld", __FUNCTION__, frameNumber, timestamp); // Trigger shutter notify to framework. camera3_notify_msg_t msg; msg.type = CAMERA3_MSG_SHUTTER; msg.message.shutter.frame_number = frameNumber; msg.message.shutter.timestamp = timestamp; sendNotify(&msg); break; default: ALOGW("%s: Unexpected sensor event %d at %" PRId64, __FUNCTION__, e, timestamp); break; } } EmulatedQemuCamera3::ReadoutThread::ReadoutThread(EmulatedQemuCamera3 *parent) : mParent(parent), mJpegWaiting(false) { ALOGV("%s: Creating readout thread", __FUNCTION__); } EmulatedQemuCamera3::ReadoutThread::~ReadoutThread() { for (List<Request>::iterator i = mInFlightQueue.begin(); i != mInFlightQueue.end(); ++i) { delete i->buffers; delete i->sensorBuffers; } } void EmulatedQemuCamera3::ReadoutThread::queueCaptureRequest(const Request &r) { Mutex::Autolock l(mLock); mInFlightQueue.push_back(r); mInFlightSignal.signal(); } bool EmulatedQemuCamera3::ReadoutThread::isIdle() { Mutex::Autolock l(mLock); return mInFlightQueue.empty() && !mThreadActive; } status_t EmulatedQemuCamera3::ReadoutThread::waitForReadout() { status_t res; Mutex::Autolock l(mLock); int loopCount = 0; while (mInFlightQueue.size() >= kMaxQueueSize) { res = mInFlightSignal.waitRelative(mLock, kWaitPerLoop); if (res != OK && res != TIMED_OUT) { ALOGE("%s: Error waiting for in-flight queue to shrink", __FUNCTION__); return INVALID_OPERATION; } if (loopCount == kMaxWaitLoops) { ALOGE("%s: Timed out waiting for in-flight queue to shrink", __FUNCTION__); return TIMED_OUT; } loopCount++; } return OK; } bool EmulatedQemuCamera3::ReadoutThread::threadLoop() { status_t res; ALOGVV("%s: ReadoutThread waiting for request", __FUNCTION__); // First wait for a request from the in-flight queue. if (mCurrentRequest.settings.isEmpty()) { Mutex::Autolock l(mLock); if (mInFlightQueue.empty()) { res = mInFlightSignal.waitRelative(mLock, kWaitPerLoop); if (res == TIMED_OUT) { ALOGVV("%s: ReadoutThread: Timed out waiting for request", __FUNCTION__); return true; } else if (res != NO_ERROR) { ALOGE("%s: Error waiting for capture requests: %d", __FUNCTION__, res); return false; } } mCurrentRequest.frameNumber = mInFlightQueue.begin()->frameNumber; mCurrentRequest.settings.acquire(mInFlightQueue.begin()->settings); mCurrentRequest.buffers = mInFlightQueue.begin()->buffers; mCurrentRequest.sensorBuffers = mInFlightQueue.begin()->sensorBuffers; mInFlightQueue.erase(mInFlightQueue.begin()); mInFlightSignal.signal(); mThreadActive = true; ALOGVV("%s: Beginning readout of frame %d", __FUNCTION__, mCurrentRequest.frameNumber); } // Then wait for it to be delivered from the sensor. ALOGVV("%s: ReadoutThread: Wait for frame to be delivered from sensor", __FUNCTION__); nsecs_t captureTime; bool gotFrame = mParent->mSensor->waitForNewFrame(kWaitPerLoop, &captureTime); if (!gotFrame) { ALOGVV("%s: ReadoutThread: Timed out waiting for sensor frame", __FUNCTION__); return true; } ALOGVV("Sensor done with readout for frame %d, captured at %lld ", mCurrentRequest.frameNumber, captureTime); /* * Check if we need to JPEG encode a buffer, and send it for async * compression if so. Otherwise prepare the buffer for return. */ bool needJpeg = false; HalBufferVector::iterator buf = mCurrentRequest.buffers->begin(); while (buf != mCurrentRequest.buffers->end()) { bool goodBuffer = true; if (buf->stream->format == HAL_PIXEL_FORMAT_BLOB && buf->stream->data_space != HAL_DATASPACE_DEPTH) { Mutex::Autolock jl(mJpegLock); if (mJpegWaiting) { /* * This shouldn't happen, because processCaptureRequest should * be stalling until JPEG compressor is free. */ ALOGE("%s: Already processing a JPEG!", __FUNCTION__); goodBuffer = false; } if (goodBuffer) { // Compressor takes ownership of sensorBuffers here. res = mParent->mJpegCompressor->start(mCurrentRequest.sensorBuffers, this, &(mCurrentRequest.settings)); goodBuffer = (res == OK); } if (goodBuffer) { needJpeg = true; mJpegHalBuffer = *buf; mJpegFrameNumber = mCurrentRequest.frameNumber; mJpegWaiting = true; mCurrentRequest.sensorBuffers = nullptr; buf = mCurrentRequest.buffers->erase(buf); continue; } ALOGE("%s: Error compressing output buffer: %s (%d)", __FUNCTION__, strerror(-res), res); // Fallthrough for cleanup. } GrallocModule::getInstance().unlock(*(buf->buffer)); buf->status = goodBuffer ? CAMERA3_BUFFER_STATUS_OK : CAMERA3_BUFFER_STATUS_ERROR; buf->acquire_fence = -1; buf->release_fence = -1; ++buf; } // Construct result for all completed buffers and results. camera3_capture_result result; if (mParent->hasCapability(BACKWARD_COMPATIBLE)) { static const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE; mCurrentRequest.settings.update(ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1); static const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE; mCurrentRequest.settings.update(ANDROID_FLASH_STATE, &flashState, 1); nsecs_t rollingShutterSkew = 0; mCurrentRequest.settings.update(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW, &rollingShutterSkew, 1); float focusRange[] = { 1.0f / 5.0f, 0 }; // 5 m to infinity in focus mCurrentRequest.settings.update(ANDROID_LENS_FOCUS_RANGE, focusRange, sizeof(focusRange) / sizeof(float)); } mCurrentRequest.settings.update(ANDROID_SENSOR_TIMESTAMP, &captureTime, 1); // JPEGs take a stage longer. const uint8_t pipelineDepth = needJpeg ? kMaxBufferCount : kMaxBufferCount - 1; mCurrentRequest.settings.update(ANDROID_REQUEST_PIPELINE_DEPTH, &pipelineDepth, 1); result.frame_number = mCurrentRequest.frameNumber; result.result = mCurrentRequest.settings.getAndLock(); result.num_output_buffers = mCurrentRequest.buffers->size(); result.output_buffers = mCurrentRequest.buffers->array(); result.input_buffer = nullptr; result.partial_result = 1; // Go idle if queue is empty, before sending result. bool signalIdle = false; { Mutex::Autolock l(mLock); if (mInFlightQueue.empty()) { mThreadActive = false; signalIdle = true; } } if (signalIdle) mParent->signalReadoutIdle(); // Send it off to the framework. ALOGVV("%s: ReadoutThread: Send result to framework", __FUNCTION__); mParent->sendCaptureResult(&result); // Clean up. mCurrentRequest.settings.unlock(result.result); delete mCurrentRequest.buffers; mCurrentRequest.buffers = nullptr; if (!needJpeg) { delete mCurrentRequest.sensorBuffers; mCurrentRequest.sensorBuffers = nullptr; } mCurrentRequest.settings.clear(); return true; } void EmulatedQemuCamera3::ReadoutThread::onJpegDone( const StreamBuffer &jpegBuffer, bool success) { Mutex::Autolock jl(mJpegLock); GrallocModule::getInstance().unlock(*(jpegBuffer.buffer)); mJpegHalBuffer.status = success ? CAMERA3_BUFFER_STATUS_OK : CAMERA3_BUFFER_STATUS_ERROR; mJpegHalBuffer.acquire_fence = -1; mJpegHalBuffer.release_fence = -1; mJpegWaiting = false; camera3_capture_result result; result.frame_number = mJpegFrameNumber; result.result = nullptr; result.num_output_buffers = 1; result.output_buffers = &mJpegHalBuffer; result.input_buffer = nullptr; result.partial_result = 0; if (!success) { ALOGE("%s: Compression failure, returning error state buffer to" " framework", __FUNCTION__); } else { ALOGV("%s: Compression complete, returning buffer to framework", __FUNCTION__); } mParent->sendCaptureResult(&result); } void EmulatedQemuCamera3::ReadoutThread::onJpegInputDone( const StreamBuffer &inputBuffer) { /* * Should never get here, since the input buffer has to be returned by end * of processCaptureRequest. */ ALOGE("%s: Unexpected input buffer from JPEG compressor!", __FUNCTION__); } }; // end of namespace android