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 set
19  * 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 <cutils/log.h>
25 #include <MetadataBufferType.h>
26 #include "EmulatedCameraDevice.h"
27 #include "CallbackNotifier.h"
28 #include "JpegCompressor.h"
29 
30 namespace android {
31 
32 /* String representation of camera messages. */
33 static const char* lCameraMessages[] =
34 {
35     "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"
46 };
47 static const int lCameraMessagesNum = sizeof(lCameraMessages) / sizeof(char*);
48 
49 /* Builds an array of strings for the given set of messages.
50  * Param:
51  *  msg - Messages to get strings for,
52  *  strings - Array where to save strings
53  *  max - Maximum number of entries in the array.
54  * Return:
55  *  Number of strings saved into the 'strings' array.
56  */
GetMessageStrings(uint32_t msg,const char ** strings,int max)57 static int GetMessageStrings(uint32_t msg, const char** strings, int max)
58 {
59     int index = 0;
60     int out = 0;
61     while (msg != 0 && out < max && index < lCameraMessagesNum) {
62         while ((msg & 0x1) == 0 && index < lCameraMessagesNum) {
63             msg >>= 1;
64             index++;
65         }
66         if ((msg & 0x1) != 0 && index < lCameraMessagesNum) {
67             strings[out] = lCameraMessages[index];
68             out++;
69             msg >>= 1;
70             index++;
71         }
72     }
73 
74     return out;
75 }
76 
77 /* Logs messages, enabled by the mask. */
PrintMessages(uint32_t msg)78 static void PrintMessages(uint32_t msg)
79 {
80     const char* strs[lCameraMessagesNum];
81     const int translated = GetMessageStrings(msg, strs, lCameraMessagesNum);
82     for (int n = 0; n < translated; n++) {
83         ALOGV("    %s", strs[n]);
84     }
85 }
86 
CallbackNotifier()87 CallbackNotifier::CallbackNotifier()
88     : mNotifyCB(NULL),
89       mDataCB(NULL),
90       mDataCBTimestamp(NULL),
91       mGetMemoryCB(NULL),
92       mCBOpaque(NULL),
93       mLastFrameTimestamp(0),
94       mFrameRefreshFreq(0),
95       mMessageEnabler(0),
96       mJpegQuality(90),
97       mVideoRecEnabled(false),
98       mTakingPicture(false)
99 {
100 }
101 
~CallbackNotifier()102 CallbackNotifier::~CallbackNotifier()
103 {
104 }
105 
106 /****************************************************************************
107  * Camera API
108  ***************************************************************************/
109 
setCallbacks(camera_notify_callback notify_cb,camera_data_callback data_cb,camera_data_timestamp_callback data_cb_timestamp,camera_request_memory get_memory,void * user)110 void CallbackNotifier::setCallbacks(camera_notify_callback notify_cb,
111                                     camera_data_callback data_cb,
112                                     camera_data_timestamp_callback data_cb_timestamp,
113                                     camera_request_memory get_memory,
114                                     void* user)
115 {
116     ALOGV("%s: %p, %p, %p, %p (%p)",
117          __FUNCTION__, notify_cb, data_cb, data_cb_timestamp, get_memory, user);
118 
119     Mutex::Autolock locker(&mObjectLock);
120     mNotifyCB = notify_cb;
121     mDataCB = data_cb;
122     mDataCBTimestamp = data_cb_timestamp;
123     mGetMemoryCB = get_memory;
124     mCBOpaque = user;
125 }
126 
enableMessage(uint msg_type)127 void CallbackNotifier::enableMessage(uint msg_type)
128 {
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 
disableMessage(uint msg_type)138 void CallbackNotifier::disableMessage(uint msg_type)
139 {
140     ALOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type);
141     PrintMessages(msg_type);
142 
143     Mutex::Autolock locker(&mObjectLock);
144     mMessageEnabler &= ~msg_type;
145     ALOGV("**** Currently enabled messages:");
146     PrintMessages(mMessageEnabler);
147 }
148 
enableVideoRecording(int fps)149 status_t CallbackNotifier::enableVideoRecording(int fps)
150 {
151     ALOGV("%s: FPS = %d", __FUNCTION__, fps);
152 
153     Mutex::Autolock locker(&mObjectLock);
154     mVideoRecEnabled = true;
155     mLastFrameTimestamp = 0;
156     mFrameRefreshFreq = 1000000000LL / fps;
157 
158     return NO_ERROR;
159 }
160 
disableVideoRecording()161 void CallbackNotifier::disableVideoRecording()
162 {
163     ALOGV("%s:", __FUNCTION__);
164 
165     Mutex::Autolock locker(&mObjectLock);
166     mVideoRecEnabled = false;
167     mLastFrameTimestamp = 0;
168     mFrameRefreshFreq = 0;
169 }
170 
releaseRecordingFrame(const void * opaque)171 void CallbackNotifier::releaseRecordingFrame(const void* opaque)
172 {
173     List<camera_memory_t*>::iterator it = mCameraMemoryTs.begin();
174     for( ; it != mCameraMemoryTs.end(); ++it ) {
175         if ( (*it)->data == opaque ) {
176             (*it)->release( *it );
177             mCameraMemoryTs.erase(it);
178             break;
179         }
180     }
181 }
182 
storeMetaDataInBuffers(bool enable)183 status_t CallbackNotifier::storeMetaDataInBuffers(bool enable)
184 {
185     /* Return INVALID_OPERATION means HAL does not support metadata. So HAL will
186      * return actual frame data with CAMERA_MSG_VIDEO_FRRAME. Return
187      * INVALID_OPERATION to mean metadata is not supported. */
188     return INVALID_OPERATION;
189 }
190 
191 /****************************************************************************
192  * Public API
193  ***************************************************************************/
194 
cleanupCBNotifier()195 void CallbackNotifier::cleanupCBNotifier()
196 {
197     Mutex::Autolock locker(&mObjectLock);
198     mMessageEnabler = 0;
199     mNotifyCB = NULL;
200     mDataCB = NULL;
201     mDataCBTimestamp = NULL;
202     mGetMemoryCB = NULL;
203     mCBOpaque = NULL;
204     mLastFrameTimestamp = 0;
205     mFrameRefreshFreq = 0;
206     mJpegQuality = 90;
207     mVideoRecEnabled = false;
208     mTakingPicture = false;
209 }
210 
onNextFrameAvailable(const void * frame,nsecs_t timestamp,EmulatedCameraDevice * camera_dev)211 void CallbackNotifier::onNextFrameAvailable(const void* frame,
212                                             nsecs_t timestamp,
213                                             EmulatedCameraDevice* camera_dev)
214 {
215     if (isMessageEnabled(CAMERA_MSG_VIDEO_FRAME) && isVideoRecordingEnabled() &&
216             isNewVideoFrameTime(timestamp)) {
217         camera_memory_t* cam_buff =
218             mGetMemoryCB(-1, camera_dev->getFrameBufferSize(), 1, NULL);
219         if (NULL != cam_buff && NULL != cam_buff->data) {
220             memcpy(cam_buff->data, frame, camera_dev->getFrameBufferSize());
221             mDataCBTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME,
222                                cam_buff, 0, mCBOpaque);
223 
224             mCameraMemoryTs.push_back( cam_buff );
225         } else {
226             ALOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
227         }
228     }
229 
230     if (isMessageEnabled(CAMERA_MSG_PREVIEW_FRAME)) {
231         camera_memory_t* cam_buff =
232             mGetMemoryCB(-1, camera_dev->getFrameBufferSize(), 1, NULL);
233         if (NULL != cam_buff && NULL != cam_buff->data) {
234             memcpy(cam_buff->data, frame, camera_dev->getFrameBufferSize());
235             mDataCB(CAMERA_MSG_PREVIEW_FRAME, cam_buff, 0, NULL, mCBOpaque);
236             cam_buff->release(cam_buff);
237         } else {
238             ALOGE("%s: Memory failure in CAMERA_MSG_PREVIEW_FRAME", __FUNCTION__);
239         }
240     }
241 
242     if (mTakingPicture) {
243         /* This happens just once. */
244         mTakingPicture = false;
245         /* The sequence of callbacks during picture taking is:
246          *  - CAMERA_MSG_SHUTTER
247          *  - CAMERA_MSG_RAW_IMAGE_NOTIFY
248          *  - CAMERA_MSG_COMPRESSED_IMAGE
249          */
250         if (isMessageEnabled(CAMERA_MSG_SHUTTER)) {
251             mNotifyCB(CAMERA_MSG_SHUTTER, 0, 0, mCBOpaque);
252         }
253         if (isMessageEnabled(CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
254             mNotifyCB(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCBOpaque);
255         }
256         if (isMessageEnabled(CAMERA_MSG_COMPRESSED_IMAGE)) {
257             /* Compress the frame to JPEG. Note that when taking pictures, we
258              * have requested camera device to provide us with NV21 frames. */
259             NV21JpegCompressor compressor;
260             status_t res =
261                 compressor.compressRawImage(frame, camera_dev->getFrameWidth(),
262                                             camera_dev->getFrameHeight(),
263                                             mJpegQuality);
264             if (res == NO_ERROR) {
265                 camera_memory_t* jpeg_buff =
266                     mGetMemoryCB(-1, compressor.getCompressedSize(), 1, NULL);
267                 if (NULL != jpeg_buff && NULL != jpeg_buff->data) {
268                     compressor.getCompressedImage(jpeg_buff->data);
269                     mDataCB(CAMERA_MSG_COMPRESSED_IMAGE, jpeg_buff, 0, NULL, mCBOpaque);
270                     jpeg_buff->release(jpeg_buff);
271                 } else {
272                     ALOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
273                 }
274             } else {
275                 ALOGE("%s: Compression failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
276             }
277         }
278     }
279 }
280 
onCameraDeviceError(int err)281 void CallbackNotifier::onCameraDeviceError(int err)
282 {
283     if (isMessageEnabled(CAMERA_MSG_ERROR) && mNotifyCB != NULL) {
284         mNotifyCB(CAMERA_MSG_ERROR, err, 0, mCBOpaque);
285     }
286 }
287 
288 /****************************************************************************
289  * Private API
290  ***************************************************************************/
291 
isNewVideoFrameTime(nsecs_t timestamp)292 bool CallbackNotifier::isNewVideoFrameTime(nsecs_t timestamp)
293 {
294     Mutex::Autolock locker(&mObjectLock);
295     if ((timestamp - mLastFrameTimestamp) >= mFrameRefreshFreq) {
296         mLastFrameTimestamp = timestamp;
297         return true;
298     }
299     return false;
300 }
301 
302 }; /* namespace android */
303