blob: 35f4846f9b72a7f2df68c2c3b644ae13706f0d9a [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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),
Benny Wongda83f462009-08-12 12:01:27 -050036 mNotifyCb(0),
37 mDataCb(0),
38 mDataCbTimestamp(0),
39 mCallbackCookie(0),
40 mMsgEnabled(0),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041 mCurrentPreviewFrame(0)
42{
43 initDefaultParameters();
44}
45
46void CameraHardwareStub::initDefaultParameters()
47{
48 CameraParameters p;
49
50 p.setPreviewSize(176, 144);
51 p.setPreviewFrameRate(15);
52 p.setPreviewFormat("yuv422sp");
53
54 p.setPictureSize(kCannedJpegWidth, kCannedJpegHeight);
55 p.setPictureFormat("jpeg");
56
57 if (setParameters(p) != NO_ERROR) {
58 LOGE("Failed to set default parameters?!");
59 }
60}
61
62void CameraHardwareStub::initHeapLocked()
63{
64 // Create raw heap.
65 int picture_width, picture_height;
66 mParameters.getPictureSize(&picture_width, &picture_height);
67 mRawHeap = new MemoryHeapBase(picture_width * 2 * picture_height);
68
69 int preview_width, preview_height;
70 mParameters.getPreviewSize(&preview_width, &preview_height);
71 LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
72
73 // Note that we enforce yuv422 in setParameters().
74 int how_big = preview_width * preview_height * 2;
75
76 // If we are being reinitialized to the same size as before, no
77 // work needs to be done.
78 if (how_big == mPreviewFrameSize)
79 return;
80
81 mPreviewFrameSize = how_big;
82
83 // Make a new mmap'ed heap that can be shared across processes.
84 // use code below to test with pmem
85 mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
86 // Make an IMemory for each frame so that we can reuse them in callbacks.
87 for (int i = 0; i < kBufferCount; i++) {
88 mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
89 }
90
91 // Recreate the fake camera to reflect the current size.
92 delete mFakeCamera;
93 mFakeCamera = new FakeCamera(preview_width, preview_height);
94}
95
96CameraHardwareStub::~CameraHardwareStub()
97{
98 delete mFakeCamera;
99 mFakeCamera = 0; // paranoia
100 singleton.clear();
101}
102
103sp<IMemoryHeap> CameraHardwareStub::getPreviewHeap() const
104{
105 return mPreviewHeap;
106}
107
108sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
109{
110 return mRawHeap;
111}
112
Benny Wongda83f462009-08-12 12:01:27 -0500113void CameraHardwareStub::setCallbacks(notify_callback notify_cb,
114 data_callback data_cb,
115 data_callback_timestamp data_cb_timestamp,
116 void* user)
117{
118 Mutex::Autolock lock(mLock);
119 mNotifyCb = notify_cb;
120 mDataCb = data_cb;
121 mDataCbTimestamp = data_cb_timestamp;
122 mCallbackCookie = user;
123}
124
125void CameraHardwareStub::enableMsgType(int32_t msgType)
126{
127 Mutex::Autolock lock(mLock);
128 mMsgEnabled |= msgType;
129}
130
131void CameraHardwareStub::disableMsgType(int32_t msgType)
132{
133 Mutex::Autolock lock(mLock);
134 mMsgEnabled &= ~msgType;
135}
136
137bool CameraHardwareStub::msgTypeEnabled(int32_t msgType)
138{
139 Mutex::Autolock lock(mLock);
140 return (mMsgEnabled & msgType);
141}
142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143// ---------------------------------------------------------------------------
144
145int CameraHardwareStub::previewThread()
146{
147 mLock.lock();
148 // the attributes below can change under our feet...
149
150 int previewFrameRate = mParameters.getPreviewFrameRate();
151
152 // Find the offset within the heap of the current buffer.
153 ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
154
155 sp<MemoryHeapBase> heap = mPreviewHeap;
156
157 // this assumes the internal state of fake camera doesn't change
158 // (or is thread safe)
159 FakeCamera* fakeCamera = mFakeCamera;
160
161 sp<MemoryBase> buffer = mBuffers[mCurrentPreviewFrame];
162
163 mLock.unlock();
164
165 // TODO: here check all the conditions that could go wrong
166 if (buffer != 0) {
167 // Calculate how long to wait between frames.
168 int delay = (int)(1000000.0f / float(previewFrameRate));
169
170 // This is always valid, even if the client died -- the memory
171 // is still mapped in our process.
172 void *base = heap->base();
173
174 // Fill the current frame with the fake camera.
175 uint8_t *frame = ((uint8_t *)base) + offset;
176 fakeCamera->getNextFrameAsYuv422(frame);
177
178 //LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
179
180 // Notify the client of a new frame.
Benny Wongda83f462009-08-12 12:01:27 -0500181 if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
182 mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
184 // Advance the buffer pointer.
185 mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
186
187 // Wait for it...
188 usleep(delay);
189 }
190
191 return NO_ERROR;
192}
193
Benny Wongda83f462009-08-12 12:01:27 -0500194status_t CameraHardwareStub::startPreview()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195{
196 Mutex::Autolock lock(mLock);
197 if (mPreviewThread != 0) {
198 // already running
199 return INVALID_OPERATION;
200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 mPreviewThread = new PreviewThread(this);
202 return NO_ERROR;
203}
204
205void CameraHardwareStub::stopPreview()
206{
207 sp<PreviewThread> previewThread;
208
209 { // scope for the lock
210 Mutex::Autolock lock(mLock);
211 previewThread = mPreviewThread;
212 }
213
214 // don't hold the lock while waiting for the thread to quit
215 if (previewThread != 0) {
216 previewThread->requestExitAndWait();
217 }
218
219 Mutex::Autolock lock(mLock);
220 mPreviewThread.clear();
221}
222
223bool CameraHardwareStub::previewEnabled() {
224 return mPreviewThread != 0;
225}
226
Benny Wongda83f462009-08-12 12:01:27 -0500227status_t CameraHardwareStub::startRecording()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228{
229 return UNKNOWN_ERROR;
230}
231
232void CameraHardwareStub::stopRecording()
233{
234}
235
236bool CameraHardwareStub::recordingEnabled()
237{
238 return false;
239}
240
241void CameraHardwareStub::releaseRecordingFrame(const sp<IMemory>& mem)
242{
243}
244
245// ---------------------------------------------------------------------------
246
247int CameraHardwareStub::beginAutoFocusThread(void *cookie)
248{
249 CameraHardwareStub *c = (CameraHardwareStub *)cookie;
250 return c->autoFocusThread();
251}
252
253int CameraHardwareStub::autoFocusThread()
254{
Benny Wongda83f462009-08-12 12:01:27 -0500255 if (mMsgEnabled & CAMERA_MSG_FOCUS)
256 mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie);
257 return NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258}
259
Benny Wongda83f462009-08-12 12:01:27 -0500260status_t CameraHardwareStub::autoFocus()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261{
262 Mutex::Autolock lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 if (createThread(beginAutoFocusThread, this) == false)
264 return UNKNOWN_ERROR;
265 return NO_ERROR;
266}
267
Chih-Chung Chang244f8c22009-09-15 14:51:56 +0800268status_t CameraHardwareStub::cancelAutoFocus()
269{
270 return NO_ERROR;
271}
272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273/*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
274{
275 CameraHardwareStub *c = (CameraHardwareStub *)cookie;
276 return c->pictureThread();
277}
278
279int CameraHardwareStub::pictureThread()
280{
Benny Wongda83f462009-08-12 12:01:27 -0500281 if (mMsgEnabled & CAMERA_MSG_SHUTTER)
282 mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283
Benny Wongda83f462009-08-12 12:01:27 -0500284 if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 //FIXME: use a canned YUV image!
286 // In the meantime just make another fake camera picture.
287 int w, h;
288 mParameters.getPictureSize(&w, &h);
289 sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
290 FakeCamera cam(w, h);
291 cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());
Benny Wongda83f462009-08-12 12:01:27 -0500292 mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 }
294
Benny Wongda83f462009-08-12 12:01:27 -0500295 if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
297 sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
298 memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
Benny Wongda83f462009-08-12 12:01:27 -0500299 mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, mCallbackCookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 }
301 return NO_ERROR;
302}
303
Benny Wongda83f462009-08-12 12:01:27 -0500304status_t CameraHardwareStub::takePicture()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305{
306 stopPreview();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 if (createThread(beginPictureThread, this) == false)
308 return -1;
309 return NO_ERROR;
310}
311
Benny Wongda83f462009-08-12 12:01:27 -0500312status_t CameraHardwareStub::cancelPicture()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 return NO_ERROR;
315}
316
317status_t CameraHardwareStub::dump(int fd, const Vector<String16>& args) const
318{
319 const size_t SIZE = 256;
320 char buffer[SIZE];
321 String8 result;
322 AutoMutex lock(&mLock);
323 if (mFakeCamera != 0) {
Niko Catania28275602009-03-24 20:55:36 -0700324 mFakeCamera->dump(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 mParameters.dump(fd, args);
326 snprintf(buffer, 255, " preview frame(%d), size (%d), running(%s)\n", mCurrentPreviewFrame, mPreviewFrameSize, mPreviewRunning?"true": "false");
327 result.append(buffer);
328 } else {
329 result.append("No camera client yet.\n");
330 }
331 write(fd, result.string(), result.size());
332 return NO_ERROR;
333}
334
335status_t CameraHardwareStub::setParameters(const CameraParameters& params)
336{
337 Mutex::Autolock lock(mLock);
338 // XXX verify params
339
340 if (strcmp(params.getPreviewFormat(), "yuv422sp") != 0) {
341 LOGE("Only yuv422sp preview is supported");
342 return -1;
343 }
344
345 if (strcmp(params.getPictureFormat(), "jpeg") != 0) {
346 LOGE("Only jpeg still pictures are supported");
347 return -1;
348 }
349
350 int w, h;
351 params.getPictureSize(&w, &h);
352 if (w != kCannedJpegWidth && h != kCannedJpegHeight) {
353 LOGE("Still picture size must be size of canned JPEG (%dx%d)",
354 kCannedJpegWidth, kCannedJpegHeight);
355 return -1;
356 }
357
358 mParameters = params;
359
360 initHeapLocked();
361
362 return NO_ERROR;
363}
364
365CameraParameters CameraHardwareStub::getParameters() const
366{
367 Mutex::Autolock lock(mLock);
368 return mParameters;
369}
370
371void CameraHardwareStub::release()
372{
373}
374
375wp<CameraHardwareInterface> CameraHardwareStub::singleton;
376
377sp<CameraHardwareInterface> CameraHardwareStub::createInstance()
378{
379 if (singleton != 0) {
380 sp<CameraHardwareInterface> hardware = singleton.promote();
381 if (hardware != 0) {
382 return hardware;
383 }
384 }
385 sp<CameraHardwareInterface> hardware(new CameraHardwareStub());
386 singleton = hardware;
387 return hardware;
388}
389
390extern "C" sp<CameraHardwareInterface> openCameraHardware()
391{
392 return CameraHardwareStub::createInstance();
393}
394
395}; // namespace android