blob: b288f523b73dac69f4770c8f25895cdab54f68c9
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 | */ |
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. */ |
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 | |
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 | |
102 | CallbackNotifier::~CallbackNotifier() |
103 | { |
104 | } |
105 | |
106 | /**************************************************************************** |
107 | * Camera API |
108 | ***************************************************************************/ |
109 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 |