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