1/*
2**
3** Copyright 2008, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "CameraHardwareStub"
19#include <utils/Log.h>
20
21#include "CameraHardwareStub.h"
22#include <utils/threads.h>
23#include <fcntl.h>
24#include <sys/mman.h>
25
26#include "CannedJpeg.h"
27
28namespace android {
29
30CameraHardwareStub::CameraHardwareStub()
31                  : mParameters(),
32                    mPreviewHeap(0),
33                    mRawHeap(0),
34                    mFakeCamera(0),
35                    mPreviewFrameSize(0),
36                    mNotifyCb(0),
37                    mDataCb(0),
38                    mDataCbTimestamp(0),
39                    mCallbackCookie(0),
40                    mMsgEnabled(0),
41                    mCurrentPreviewFrame(0)
42{
43    initDefaultParameters();
44}
45
46void CameraHardwareStub::initDefaultParameters()
47{
48    CameraParameters p;
49
50    p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "320x240");
51    p.setPreviewSize(320, 240);
52    p.setPreviewFrameRate(15);
53    p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
54
55    p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "320x240");
56    p.setPictureSize(320, 240);
57    p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
58
59    if (setParameters(p) != NO_ERROR) {
60        ALOGE("Failed to set default parameters?!");
61    }
62}
63
64void CameraHardwareStub::initHeapLocked()
65{
66    // Create raw heap.
67    int picture_width, picture_height;
68    mParameters.getPictureSize(&picture_width, &picture_height);
69    mRawHeap = new MemoryHeapBase(picture_width * picture_height * 3 / 2);
70
71    int preview_width, preview_height;
72    mParameters.getPreviewSize(&preview_width, &preview_height);
73    ALOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
74
75    // Note that we enforce yuv420sp in setParameters().
76    int how_big = preview_width * preview_height * 3 / 2;
77
78    // If we are being reinitialized to the same size as before, no
79    // work needs to be done.
80    if (how_big == mPreviewFrameSize)
81        return;
82
83    mPreviewFrameSize = how_big;
84
85    // Make a new mmap'ed heap that can be shared across processes.
86    // use code below to test with pmem
87    mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
88    // Make an IMemory for each frame so that we can reuse them in callbacks.
89    for (int i = 0; i < kBufferCount; i++) {
90        mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
91    }
92
93    // Recreate the fake camera to reflect the current size.
94    delete mFakeCamera;
95    mFakeCamera = new FakeCamera(preview_width, preview_height);
96}
97
98CameraHardwareStub::~CameraHardwareStub()
99{
100    delete mFakeCamera;
101    mFakeCamera = 0; // paranoia
102}
103
104status_t CameraHardwareStub::setPreviewWindow(const sp<ANativeWindow>& buf)
105{
106    return NO_ERROR;
107}
108
109sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
110{
111    return mRawHeap;
112}
113
114void CameraHardwareStub::setCallbacks(notify_callback notify_cb,
115                                      data_callback data_cb,
116                                      data_callback_timestamp data_cb_timestamp,
117                                      void* user)
118{
119    Mutex::Autolock lock(mLock);
120    mNotifyCb = notify_cb;
121    mDataCb = data_cb;
122    mDataCbTimestamp = data_cb_timestamp;
123    mCallbackCookie = user;
124}
125
126void CameraHardwareStub::enableMsgType(int32_t msgType)
127{
128    Mutex::Autolock lock(mLock);
129    mMsgEnabled |= msgType;
130}
131
132void CameraHardwareStub::disableMsgType(int32_t msgType)
133{
134    Mutex::Autolock lock(mLock);
135    mMsgEnabled &= ~msgType;
136}
137
138bool CameraHardwareStub::msgTypeEnabled(int32_t msgType)
139{
140    Mutex::Autolock lock(mLock);
141    return (mMsgEnabled & msgType);
142}
143
144// ---------------------------------------------------------------------------
145
146int CameraHardwareStub::previewThread()
147{
148    mLock.lock();
149        // the attributes below can change under our feet...
150
151        int previewFrameRate = mParameters.getPreviewFrameRate();
152
153        // Find the offset within the heap of the current buffer.
154        ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
155
156        sp<MemoryHeapBase> heap = mPreviewHeap;
157
158        // this assumes the internal state of fake camera doesn't change
159        // (or is thread safe)
160        FakeCamera* fakeCamera = mFakeCamera;
161
162        sp<MemoryBase> buffer = mBuffers[mCurrentPreviewFrame];
163
164    mLock.unlock();
165
166    // TODO: here check all the conditions that could go wrong
167    if (buffer != 0) {
168        // Calculate how long to wait between frames.
169        int delay = (int)(1000000.0f / float(previewFrameRate));
170
171        // This is always valid, even if the client died -- the memory
172        // is still mapped in our process.
173        void *base = heap->base();
174
175        // Fill the current frame with the fake camera.
176        uint8_t *frame = ((uint8_t *)base) + offset;
177        fakeCamera->getNextFrameAsYuv420(frame);
178
179        //ALOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
180
181        // Notify the client of a new frame.
182        if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
183            mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, NULL, mCallbackCookie);
184
185        // Advance the buffer pointer.
186        mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
187
188        // Wait for it...
189        usleep(delay);
190    }
191
192    return NO_ERROR;
193}
194
195status_t CameraHardwareStub::startPreview()
196{
197    Mutex::Autolock lock(mLock);
198    if (mPreviewThread != 0) {
199        // already running
200        return INVALID_OPERATION;
201    }
202    mPreviewThread = new PreviewThread(this);
203    return NO_ERROR;
204}
205
206void CameraHardwareStub::stopPreview()
207{
208    sp<PreviewThread> previewThread;
209
210    { // scope for the lock
211        Mutex::Autolock lock(mLock);
212        previewThread = mPreviewThread;
213    }
214
215    // don't hold the lock while waiting for the thread to quit
216    if (previewThread != 0) {
217        previewThread->requestExitAndWait();
218    }
219
220    Mutex::Autolock lock(mLock);
221    mPreviewThread.clear();
222}
223
224bool CameraHardwareStub::previewEnabled() {
225    return mPreviewThread != 0;
226}
227
228status_t CameraHardwareStub::startRecording()
229{
230    return UNKNOWN_ERROR;
231}
232
233void CameraHardwareStub::stopRecording()
234{
235}
236
237bool CameraHardwareStub::recordingEnabled()
238{
239    return false;
240}
241
242void CameraHardwareStub::releaseRecordingFrame(const sp<IMemory>& mem)
243{
244}
245
246// ---------------------------------------------------------------------------
247
248int CameraHardwareStub::beginAutoFocusThread(void *cookie)
249{
250    CameraHardwareStub *c = (CameraHardwareStub *)cookie;
251    return c->autoFocusThread();
252}
253
254int CameraHardwareStub::autoFocusThread()
255{
256    if (mMsgEnabled & CAMERA_MSG_FOCUS)
257        mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie);
258    return NO_ERROR;
259}
260
261status_t CameraHardwareStub::autoFocus()
262{
263    Mutex::Autolock lock(mLock);
264    if (createThread(beginAutoFocusThread, this) == false)
265        return UNKNOWN_ERROR;
266    return NO_ERROR;
267}
268
269status_t CameraHardwareStub::cancelAutoFocus()
270{
271    return NO_ERROR;
272}
273
274/*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
275{
276    CameraHardwareStub *c = (CameraHardwareStub *)cookie;
277    return c->pictureThread();
278}
279
280int CameraHardwareStub::pictureThread()
281{
282    if (mMsgEnabled & CAMERA_MSG_SHUTTER)
283        mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);
284
285    if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
286        //FIXME: use a canned YUV image!
287        // In the meantime just make another fake camera picture.
288        int w, h;
289        mParameters.getPictureSize(&w, &h);
290        sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * h * 3 / 2);
291        FakeCamera cam(w, h);
292        cam.getNextFrameAsYuv420((uint8_t *)mRawHeap->base());
293        mDataCb(CAMERA_MSG_RAW_IMAGE, mem, NULL, mCallbackCookie);
294    }
295
296    if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
297        sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
298        sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
299        memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
300        mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL, mCallbackCookie);
301    }
302    return NO_ERROR;
303}
304
305status_t CameraHardwareStub::takePicture()
306{
307    stopPreview();
308    if (createThread(beginPictureThread, this) == false)
309        return UNKNOWN_ERROR;
310    return NO_ERROR;
311}
312
313status_t CameraHardwareStub::cancelPicture()
314{
315    return NO_ERROR;
316}
317
318status_t CameraHardwareStub::dump(int fd, const Vector<String16>& args) const
319{
320    const size_t SIZE = 256;
321    char buffer[SIZE];
322    String8 result;
323    AutoMutex lock(&mLock);
324    if (mFakeCamera != 0) {
325        mFakeCamera->dump(fd);
326        mParameters.dump(fd, args);
327        snprintf(buffer, 255, " preview frame(%d), size (%d), running(%s)\n", mCurrentPreviewFrame, mPreviewFrameSize, mPreviewRunning?"true": "false");
328        result.append(buffer);
329    } else {
330        result.append("No camera client yet.\n");
331    }
332    write(fd, result.string(), result.size());
333    return NO_ERROR;
334}
335
336status_t CameraHardwareStub::setParameters(const CameraParameters& params)
337{
338    Mutex::Autolock lock(mLock);
339    // XXX verify params
340
341    if (strcmp(params.getPreviewFormat(),
342        CameraParameters::PIXEL_FORMAT_YUV420SP) != 0) {
343        ALOGE("Only yuv420sp preview is supported");
344        return -1;
345    }
346
347    if (strcmp(params.getPictureFormat(),
348        CameraParameters::PIXEL_FORMAT_JPEG) != 0) {
349        ALOGE("Only jpeg still pictures are supported");
350        return -1;
351    }
352
353    int w, h;
354    params.getPictureSize(&w, &h);
355    if (w != kCannedJpegWidth && h != kCannedJpegHeight) {
356        ALOGE("Still picture size must be size of canned JPEG (%dx%d)",
357             kCannedJpegWidth, kCannedJpegHeight);
358        return -1;
359    }
360
361    mParameters = params;
362    initHeapLocked();
363
364    return NO_ERROR;
365}
366
367CameraParameters CameraHardwareStub::getParameters() const
368{
369    Mutex::Autolock lock(mLock);
370    return mParameters;
371}
372
373status_t CameraHardwareStub::sendCommand(int32_t command, int32_t arg1,
374                                         int32_t arg2)
375{
376    return BAD_VALUE;
377}
378
379void CameraHardwareStub::release()
380{
381}
382
383sp<CameraHardwareInterface> CameraHardwareStub::createInstance()
384{
385    return new CameraHardwareStub();
386}
387
388static CameraInfo sCameraInfo[] = {
389    {
390        CAMERA_FACING_BACK,
391        90,  /* orientation */
392    }
393};
394
395extern "C" int HAL_getNumberOfCameras()
396{
397    return sizeof(sCameraInfo) / sizeof(sCameraInfo[0]);
398}
399
400extern "C" void HAL_getCameraInfo(int cameraId, struct CameraInfo* cameraInfo)
401{
402    memcpy(cameraInfo, &sCameraInfo[cameraId], sizeof(CameraInfo));
403}
404
405extern "C" sp<CameraHardwareInterface> HAL_openCameraHardware(int cameraId)
406{
407    return CameraHardwareStub::createInstance();
408}
409
410}; // namespace android
411