1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* 18 * Contains implementation of a class CallbackNotifier that manages callbacks 19 * set via set_callbacks, enable_msg_type, and disable_msg_type camera HAL API. 20 */ 21 22#define LOG_NDEBUG 0 23#define LOG_TAG "EmulatedCamera_CallbackNotifier" 24#include "CallbackNotifier.h" 25#include <MetadataBufferType.h> 26#include <cutils/log.h> 27#include "EmulatedCameraDevice.h" 28#include "JpegCompressor.h" 29#include "Exif.h" 30#include "Thumbnail.h" 31 32namespace android { 33 34/* String representation of camera messages. */ 35static const char* lCameraMessages[] = {"CAMERA_MSG_ERROR", 36 "CAMERA_MSG_SHUTTER", 37 "CAMERA_MSG_FOCUS", 38 "CAMERA_MSG_ZOOM", 39 "CAMERA_MSG_PREVIEW_FRAME", 40 "CAMERA_MSG_VIDEO_FRAME", 41 "CAMERA_MSG_POSTVIEW_FRAME", 42 "CAMERA_MSG_RAW_IMAGE", 43 "CAMERA_MSG_COMPRESSED_IMAGE", 44 "CAMERA_MSG_RAW_IMAGE_NOTIFY", 45 "CAMERA_MSG_PREVIEW_METADATA"}; 46static const int lCameraMessagesNum = sizeof(lCameraMessages) / sizeof(char*); 47 48/* Builds an array of strings for the given set of messages. 49 * Param: 50 * msg - Messages to get strings for, 51 * strings - Array where to save strings 52 * max - Maximum number of entries in the array. 53 * Return: 54 * Number of strings saved into the 'strings' array. 55 */ 56static int GetMessageStrings(uint32_t msg, const char** strings, int max) { 57 int index = 0; 58 int out = 0; 59 while (msg != 0 && out < max && index < lCameraMessagesNum) { 60 while ((msg & 0x1) == 0 && index < lCameraMessagesNum) { 61 msg >>= 1; 62 index++; 63 } 64 if ((msg & 0x1) != 0 && index < lCameraMessagesNum) { 65 strings[out] = lCameraMessages[index]; 66 out++; 67 msg >>= 1; 68 index++; 69 } 70 } 71 72 return out; 73} 74 75/* Logs messages, enabled by the mask. */ 76static void PrintMessages(uint32_t msg) { 77 const char* strs[lCameraMessagesNum]; 78 const int translated = GetMessageStrings(msg, strs, lCameraMessagesNum); 79 for (int n = 0; n < translated; n++) { 80 ALOGV(" %s", strs[n]); 81 } 82} 83 84CallbackNotifier::CallbackNotifier() 85 : mNotifyCB(NULL), 86 mDataCB(NULL), 87 mDataCBTimestamp(NULL), 88 mGetMemoryCB(NULL), 89 mCBOpaque(NULL), 90 mLastFrameTimestamp(0), 91 mFrameRefreshFreq(0), 92 mMessageEnabler(0), 93 mJpegQuality(90), 94 mVideoRecEnabled(false), 95 mTakingPicture(false) {} 96 97CallbackNotifier::~CallbackNotifier() {} 98 99/**************************************************************************** 100 * Camera API 101 ***************************************************************************/ 102 103void CallbackNotifier::setCallbacks( 104 camera_notify_callback notify_cb, camera_data_callback data_cb, 105 camera_data_timestamp_callback data_cb_timestamp, 106 camera_request_memory get_memory, void* user) { 107 ALOGV("%s: %p, %p, %p, %p (%p)", __FUNCTION__, notify_cb, data_cb, 108 data_cb_timestamp, get_memory, user); 109 110 Mutex::Autolock locker(&mObjectLock); 111 mNotifyCB = notify_cb; 112 mDataCB = data_cb; 113 mDataCBTimestamp = data_cb_timestamp; 114 mGetMemoryCB = get_memory; 115 mCBOpaque = user; 116} 117 118void CallbackNotifier::enableMessage(uint msg_type) { 119 ALOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type); 120 PrintMessages(msg_type); 121 122 Mutex::Autolock locker(&mObjectLock); 123 mMessageEnabler |= msg_type; 124 ALOGV("**** Currently enabled messages:"); 125 PrintMessages(mMessageEnabler); 126} 127 128void CallbackNotifier::disableMessage(uint msg_type) { 129 ALOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type); 130 PrintMessages(msg_type); 131 132 Mutex::Autolock locker(&mObjectLock); 133 mMessageEnabler &= ~msg_type; 134 ALOGV("**** Currently enabled messages:"); 135 PrintMessages(mMessageEnabler); 136} 137 138status_t CallbackNotifier::enableVideoRecording(int fps) { 139 ALOGV("%s: FPS = %d", __FUNCTION__, fps); 140 141 Mutex::Autolock locker(&mObjectLock); 142 mVideoRecEnabled = true; 143 mLastFrameTimestamp = 0; 144 mFrameRefreshFreq = 1000000000LL / fps; 145 146 return NO_ERROR; 147} 148 149void CallbackNotifier::disableVideoRecording() { 150 ALOGV("%s:", __FUNCTION__); 151 152 Mutex::Autolock locker(&mObjectLock); 153 mVideoRecEnabled = false; 154 mLastFrameTimestamp = 0; 155 mFrameRefreshFreq = 0; 156} 157 158void CallbackNotifier::releaseRecordingFrame(const void* opaque) { 159 List<camera_memory_t*>::iterator it = mCameraMemoryTs.begin(); 160 for (; it != mCameraMemoryTs.end(); ++it) { 161 if ((*it)->data == opaque) { 162 (*it)->release(*it); 163 mCameraMemoryTs.erase(it); 164 break; 165 } 166 } 167} 168 169status_t CallbackNotifier::storeMetaDataInBuffers(bool enable) { 170 // Return error if metadata is request, otherwise silently agree. 171 return enable ? INVALID_OPERATION : NO_ERROR; 172} 173 174/**************************************************************************** 175 * Public API 176 ***************************************************************************/ 177 178void CallbackNotifier::cleanupCBNotifier() { 179 Mutex::Autolock locker(&mObjectLock); 180 mMessageEnabler = 0; 181 mNotifyCB = NULL; 182 mDataCB = NULL; 183 mDataCBTimestamp = NULL; 184 mGetMemoryCB = NULL; 185 mCBOpaque = NULL; 186 mLastFrameTimestamp = 0; 187 mFrameRefreshFreq = 0; 188 mJpegQuality = 90; 189 mVideoRecEnabled = false; 190 mTakingPicture = false; 191} 192 193void CallbackNotifier::onNextFrameAvailable(const void* frame, 194 nsecs_t timestamp, 195 EmulatedCameraDevice* camera_dev) { 196 if (isMessageEnabled(CAMERA_MSG_VIDEO_FRAME) && isVideoRecordingEnabled() && 197 isNewVideoFrameTime(timestamp)) { 198 camera_memory_t* cam_buff = 199 mGetMemoryCB(-1, camera_dev->getFrameBufferSize(), 1, mCBOpaque); 200 if (NULL != cam_buff && NULL != cam_buff->data) { 201 memcpy(cam_buff->data, frame, camera_dev->getFrameBufferSize()); 202 mDataCBTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, cam_buff, 0, 203 mCBOpaque); 204 205 mCameraMemoryTs.push_back(cam_buff); 206 } else { 207 ALOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__); 208 } 209 } 210 211 if (isMessageEnabled(CAMERA_MSG_PREVIEW_FRAME)) { 212 camera_memory_t* cam_buff = 213 mGetMemoryCB(-1, camera_dev->getFrameBufferSize(), 1, mCBOpaque); 214 if (NULL != cam_buff && NULL != cam_buff->data) { 215 memcpy(cam_buff->data, frame, camera_dev->getFrameBufferSize()); 216 mDataCB(CAMERA_MSG_PREVIEW_FRAME, cam_buff, 0, NULL, mCBOpaque); 217 cam_buff->release(cam_buff); 218 } else { 219 ALOGE("%s: Memory failure in CAMERA_MSG_PREVIEW_FRAME", __FUNCTION__); 220 } 221 } 222 223 if (mTakingPicture) { 224 /* This happens just once. */ 225 mTakingPicture = false; 226 /* The sequence of callbacks during picture taking is: 227 * - CAMERA_MSG_SHUTTER 228 * - CAMERA_MSG_RAW_IMAGE_NOTIFY 229 * - CAMERA_MSG_COMPRESSED_IMAGE 230 */ 231 if (isMessageEnabled(CAMERA_MSG_SHUTTER)) { 232 mNotifyCB(CAMERA_MSG_SHUTTER, 0, 0, mCBOpaque); 233 } 234 if (isMessageEnabled(CAMERA_MSG_RAW_IMAGE_NOTIFY)) { 235 mNotifyCB(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCBOpaque); 236 } 237 if (isMessageEnabled(CAMERA_MSG_COMPRESSED_IMAGE)) { 238 /* Compress the frame to JPEG. Note that when taking pictures, we 239 * have requested camera device to provide us with NV21 frames. */ 240 NV21JpegCompressor compressor; 241 const CameraParameters* cameraParameters = camera_dev->getCameraParameters(); 242 if (cameraParameters == nullptr) { 243 ALOGE("%s: Could not get camera parameters to take picture.", __FUNCTION__); 244 return; 245 } 246 247 ExifData* exifData = createExifData(*cameraParameters); 248 249 // Create a thumbnail and place the pointer and size in the EXIF 250 // data structure. This transfers ownership to the EXIF data and 251 // the memory will be deallocated in the freeExifData call below. 252 int width = camera_dev->getFrameWidth(); 253 int height = camera_dev->getFrameHeight(); 254 int thumbWidth = cameraParameters->getInt( 255 CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); 256 int thumbHeight = cameraParameters->getInt( 257 CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); 258 if (thumbWidth > 0 && thumbHeight > 0) { 259 if (!createThumbnail(static_cast<const unsigned char*>(frame), 260 width, height, thumbWidth, thumbHeight, 261 mJpegQuality, exifData)) { 262 // Not really a fatal error, we'll just keep going 263 ALOGE("%s: Failed to create thumbnail for image", 264 __FUNCTION__); 265 } 266 } 267 268 status_t res = compressor.compressRawImage(frame, exifData, mJpegQuality, width, height); 269 if (res == NO_ERROR) { 270 camera_memory_t* jpeg_buff = 271 mGetMemoryCB(-1, compressor.getCompressedSize(), 1, mCBOpaque); 272 if (NULL != jpeg_buff && NULL != jpeg_buff->data) { 273 compressor.getCompressedImage(jpeg_buff->data); 274 mDataCB(CAMERA_MSG_COMPRESSED_IMAGE, jpeg_buff, 0, NULL, mCBOpaque); 275 jpeg_buff->release(jpeg_buff); 276 } else { 277 ALOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__); 278 } 279 } else { 280 ALOGE("%s: Compression failure in CAMERA_MSG_VIDEO_FRAME", 281 __FUNCTION__); 282 } 283 freeExifData(exifData); 284 } 285 } 286} 287 288void CallbackNotifier::onCameraDeviceError(int err) { 289 if (isMessageEnabled(CAMERA_MSG_ERROR) && mNotifyCB != NULL) { 290 mNotifyCB(CAMERA_MSG_ERROR, err, 0, mCBOpaque); 291 } 292} 293 294void CallbackNotifier::onCameraFocusAcquired() { 295 if (isMessageEnabled(CAMERA_MSG_FOCUS) && mNotifyCB != NULL) { 296 mNotifyCB(CAMERA_MSG_FOCUS, 1, 0, mCBOpaque); 297 } 298} 299 300/**************************************************************************** 301 * Private API 302 ***************************************************************************/ 303 304bool CallbackNotifier::isNewVideoFrameTime(nsecs_t timestamp) { 305 Mutex::Autolock locker(&mObjectLock); 306 if ((timestamp - mLastFrameTimestamp) >= mFrameRefreshFreq) { 307 mLastFrameTimestamp = timestamp; 308 return true; 309 } 310 return false; 311} 312 313}; /* namespace android */ 314