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
30namespace android {
31
32/* String representation of camera messages. */
33static 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};
47static 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 */
57static 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. */
78static 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
87CallbackNotifier::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
102CallbackNotifier::~CallbackNotifier()
103{
104}
105
106/****************************************************************************
107 * Camera API
108 ***************************************************************************/
109
110void 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
127void 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
138void 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
149status_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
161void CallbackNotifier::disableVideoRecording()
162{
163    ALOGV("%s:", __FUNCTION__);
164
165    Mutex::Autolock locker(&mObjectLock);
166    mVideoRecEnabled = false;
167    mLastFrameTimestamp = 0;
168    mFrameRefreshFreq = 0;
169}
170
171void CallbackNotifier::releaseRecordingFrame(const void* opaque)
172{
173    /* We don't really have anything to release here, since we report video
174     * frames by copying them directly to the camera memory. */
175}
176
177status_t CallbackNotifier::storeMetaDataInBuffers(bool enable)
178{
179    /* Return INVALID_OPERATION means HAL does not support metadata. So HAL will
180     * return actual frame data with CAMERA_MSG_VIDEO_FRRAME. Return
181     * INVALID_OPERATION to mean metadata is not supported. */
182    return INVALID_OPERATION;
183}
184
185/****************************************************************************
186 * Public API
187 ***************************************************************************/
188
189void CallbackNotifier::cleanupCBNotifier()
190{
191    Mutex::Autolock locker(&mObjectLock);
192    mMessageEnabler = 0;
193    mNotifyCB = NULL;
194    mDataCB = NULL;
195    mDataCBTimestamp = NULL;
196    mGetMemoryCB = NULL;
197    mCBOpaque = NULL;
198    mLastFrameTimestamp = 0;
199    mFrameRefreshFreq = 0;
200    mJpegQuality = 90;
201    mVideoRecEnabled = false;
202    mTakingPicture = false;
203}
204
205void CallbackNotifier::onNextFrameAvailable(const void* frame,
206                                            nsecs_t timestamp,
207                                            EmulatedCameraDevice* camera_dev)
208{
209    if (isMessageEnabled(CAMERA_MSG_VIDEO_FRAME) && isVideoRecordingEnabled() &&
210            isNewVideoFrameTime(timestamp)) {
211        camera_memory_t* cam_buff =
212            mGetMemoryCB(-1, camera_dev->getFrameBufferSize(), 1, NULL);
213        if (NULL != cam_buff && NULL != cam_buff->data) {
214            memcpy(cam_buff->data, frame, camera_dev->getFrameBufferSize());
215            mDataCBTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME,
216                               cam_buff, 0, mCBOpaque);
217        } else {
218            ALOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
219        }
220    }
221
222    if (isMessageEnabled(CAMERA_MSG_PREVIEW_FRAME)) {
223        camera_memory_t* cam_buff =
224            mGetMemoryCB(-1, camera_dev->getFrameBufferSize(), 1, NULL);
225        if (NULL != cam_buff && NULL != cam_buff->data) {
226            memcpy(cam_buff->data, frame, camera_dev->getFrameBufferSize());
227            mDataCB(CAMERA_MSG_PREVIEW_FRAME, cam_buff, 0, NULL, mCBOpaque);
228            cam_buff->release(cam_buff);
229        } else {
230            ALOGE("%s: Memory failure in CAMERA_MSG_PREVIEW_FRAME", __FUNCTION__);
231        }
232    }
233
234    if (mTakingPicture) {
235        /* This happens just once. */
236        mTakingPicture = false;
237        /* The sequence of callbacks during picture taking is:
238         *  - CAMERA_MSG_SHUTTER
239         *  - CAMERA_MSG_RAW_IMAGE_NOTIFY
240         *  - CAMERA_MSG_COMPRESSED_IMAGE
241         */
242        if (isMessageEnabled(CAMERA_MSG_SHUTTER)) {
243            mNotifyCB(CAMERA_MSG_SHUTTER, 0, 0, mCBOpaque);
244        }
245        if (isMessageEnabled(CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
246            mNotifyCB(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCBOpaque);
247        }
248        if (isMessageEnabled(CAMERA_MSG_COMPRESSED_IMAGE)) {
249            /* Compress the frame to JPEG. Note that when taking pictures, we
250             * have requested camera device to provide us with NV21 frames. */
251            NV21JpegCompressor compressor;
252            status_t res =
253                compressor.compressRawImage(frame, camera_dev->getFrameWidth(),
254                                            camera_dev->getFrameHeight(),
255                                            mJpegQuality);
256            if (res == NO_ERROR) {
257                camera_memory_t* jpeg_buff =
258                    mGetMemoryCB(-1, compressor.getCompressedSize(), 1, NULL);
259                if (NULL != jpeg_buff && NULL != jpeg_buff->data) {
260                    compressor.getCompressedImage(jpeg_buff->data);
261                    mDataCB(CAMERA_MSG_COMPRESSED_IMAGE, jpeg_buff, 0, NULL, mCBOpaque);
262                    jpeg_buff->release(jpeg_buff);
263                } else {
264                    ALOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
265                }
266            } else {
267                ALOGE("%s: Compression failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
268            }
269        }
270    }
271}
272
273void CallbackNotifier::onCameraDeviceError(int err)
274{
275    if (isMessageEnabled(CAMERA_MSG_ERROR) && mNotifyCB != NULL) {
276        mNotifyCB(CAMERA_MSG_ERROR, err, 0, mCBOpaque);
277    }
278}
279
280/****************************************************************************
281 * Private API
282 ***************************************************************************/
283
284bool CallbackNotifier::isNewVideoFrameTime(nsecs_t timestamp)
285{
286    Mutex::Autolock locker(&mObjectLock);
287    if ((timestamp - mLastFrameTimestamp) >= mFrameRefreshFreq) {
288        mLastFrameTimestamp = timestamp;
289        return true;
290    }
291    return false;
292}
293
294}; /* namespace android */
295