Bug 783551 - Get tooltool running on the b2g on OS X builds. r=respindola
[gecko.git] / dom / camera / GonkCameraHwMgr.cpp
blob58b2ad8237c9727e6e2a025ed4cad4e411295bd5
1 /*
2 * Copyright (C) 2012 Mozilla Foundation
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "base/basictypes.h"
18 #include "nsDebug.h"
19 #include "GonkCameraHwMgr.h"
20 #include "GonkNativeWindow.h"
22 #define DOM_CAMERA_LOG_LEVEL 3
23 #include "CameraCommon.h"
25 using namespace mozilla;
26 using namespace mozilla::layers;
27 using namespace android;
29 #if GIHM_TIMING_RECEIVEFRAME
30 #define INCLUDE_TIME_H 1
31 #endif
32 #if GIHM_TIMING_OVERALL
33 #define INCLUDE_TIME_H 1
34 #endif
36 #if INCLUDE_TIME_H
37 #include <time.h>
39 static __inline void timespecSubtract(struct timespec* a, struct timespec* b)
41 // a = b - a
42 if (b->tv_nsec < a->tv_nsec) {
43 b->tv_nsec += 1000000000;
44 b->tv_sec -= 1;
46 a->tv_nsec = b->tv_nsec - a->tv_nsec;
47 a->tv_sec = b->tv_sec - a->tv_sec;
49 #endif
51 GonkCameraHardware::GonkCameraHardware(GonkCamera* aTarget, PRUint32 aCamera)
52 : mCamera(aCamera)
53 , mFps(30)
54 , mPreviewFormat(PREVIEW_FORMAT_UNKNOWN)
55 , mClosing(false)
56 , mMonitor("GonkCameraHardware.Monitor")
57 , mNumFrames(0)
58 , mTarget(aTarget)
59 , mInitialized(false)
61 DOM_CAMERA_LOGI( "%s: this = %p (aTarget = %p)\n", __func__, (void* )this, (void* )aTarget );
62 init();
65 void
66 GonkCameraHardware::OnNewFrame()
68 if (mClosing) {
69 return;
71 GonkNativeWindow* window = static_cast<GonkNativeWindow*>(mWindow.get());
72 nsRefPtr<GraphicBufferLocked> buffer = window->getCurrentBuffer();
73 ReceiveFrame(mTarget, buffer);
76 // Android data callback
77 void
78 GonkCameraHardware::DataCallback(int32_t aMsgType, const sp<IMemory> &aDataPtr, camera_frame_metadata_t* aMetadata, void* aUser)
80 GonkCameraHardware* hw = GetHardware((PRUint32)aUser);
81 if (!hw) {
82 DOM_CAMERA_LOGW("%s:aUser = %d resolved to no camera hw\n", __func__, (PRUint32)aUser);
83 return;
85 if (hw->mClosing) {
86 return;
89 GonkCamera* camera = hw->mTarget;
90 if (camera) {
91 switch (aMsgType) {
92 case CAMERA_MSG_PREVIEW_FRAME:
93 // Do nothing
94 break;
96 case CAMERA_MSG_COMPRESSED_IMAGE:
97 ReceiveImage(camera, (PRUint8*)aDataPtr->pointer(), aDataPtr->size());
98 break;
100 default:
101 DOM_CAMERA_LOGE("Unhandled data callback event %d\n", aMsgType);
102 break;
104 } else {
105 DOM_CAMERA_LOGW("%s: hw = %p (camera = NULL)\n", __func__, hw);
109 // Android notify callback
110 void
111 GonkCameraHardware::NotifyCallback(int32_t aMsgType, int32_t ext1, int32_t ext2, void* aUser)
113 bool bSuccess;
114 GonkCameraHardware* hw = GetHardware((PRUint32)aUser);
115 if (!hw) {
116 DOM_CAMERA_LOGW("%s:aUser = %d resolved to no camera hw\n", __func__, (PRUint32)aUser);
117 return;
119 if (hw->mClosing) {
120 return;
123 GonkCamera* camera = hw->mTarget;
124 if (!camera) {
125 return;
128 switch (aMsgType) {
129 case CAMERA_MSG_FOCUS:
130 if (ext1) {
131 DOM_CAMERA_LOGI("Autofocus complete");
132 bSuccess = true;
133 } else {
134 DOM_CAMERA_LOGW("Autofocus failed");
135 bSuccess = false;
137 AutoFocusComplete(camera, bSuccess);
138 break;
140 case CAMERA_MSG_SHUTTER:
141 DOM_CAMERA_LOGW("Shutter event not handled yet\n");
142 break;
144 default:
145 DOM_CAMERA_LOGE("Unhandled notify callback event %d\n", aMsgType);
146 break;
150 void
151 GonkCameraHardware::init()
153 DOM_CAMERA_LOGI("%s: this = %p\n", __func__, (void* )this);
155 if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t**)&mModule) < 0) {
156 return;
158 char cameraDeviceName[4];
159 snprintf(cameraDeviceName, sizeof(cameraDeviceName), "%d", mCamera);
160 mHardware = new CameraHardwareInterface(cameraDeviceName);
161 if (mHardware->initialize(&mModule->common) != OK) {
162 mHardware.clear();
163 return;
166 mWindow = new GonkNativeWindow(this);
168 if (sHwHandle == 0) {
169 sHwHandle = 1; // don't use 0
171 mHardware->setCallbacks(GonkCameraHardware::NotifyCallback, GonkCameraHardware::DataCallback, NULL, (void*)sHwHandle);
173 // initialize the local camera parameter database
174 mParams = mHardware->getParameters();
176 mHardware->setPreviewWindow(mWindow);
178 mInitialized = true;
181 GonkCameraHardware::~GonkCameraHardware()
183 DOM_CAMERA_LOGI( "%s:%d : this = %p\n", __func__, __LINE__, (void*)this );
184 sHw = nullptr;
187 GonkCameraHardware* GonkCameraHardware::sHw = nullptr;
188 PRUint32 GonkCameraHardware::sHwHandle = 0;
190 void
191 GonkCameraHardware::ReleaseHandle(PRUint32 aHwHandle)
193 GonkCameraHardware* hw = GetHardware(aHwHandle);
194 DOM_CAMERA_LOGI("%s: aHwHandle = %d, hw = %p (sHwHandle = %d)\n", __func__, aHwHandle, (void*)hw, sHwHandle);
195 if (!hw) {
196 return;
199 DOM_CAMERA_LOGI("%s: before: sHwHandle = %d\n", __func__, sHwHandle);
200 sHwHandle += 1; // invalidate old handles before deleting
201 hw->mClosing = true;
202 hw->mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
203 hw->mHardware->stopPreview();
204 hw->mHardware->release();
205 GonkNativeWindow* window = static_cast<GonkNativeWindow*>(hw->mWindow.get());
206 window->abandon();
207 DOM_CAMERA_LOGI("%s: after: sHwHandle = %d\n", __func__, sHwHandle);
208 delete hw; // destroy the camera hardware instance
211 PRUint32
212 GonkCameraHardware::GetHandle(GonkCamera* aTarget, PRUint32 aCamera)
214 ReleaseHandle(sHwHandle);
216 sHw = new GonkCameraHardware(aTarget, aCamera);
218 if (sHw->IsInitialized()) {
219 return sHwHandle;
222 DOM_CAMERA_LOGE("failed to initialize camera hardware\n");
223 delete sHw;
224 sHw = nullptr;
225 return 0;
228 PRUint32
229 GonkCameraHardware::GetFps(PRUint32 aHwHandle)
231 GonkCameraHardware* hw = GetHardware(aHwHandle);
232 if (!hw) {
233 return 0;
236 return hw->mFps;
239 void
240 GonkCameraHardware::GetPreviewSize(PRUint32 aHwHandle, PRUint32* aWidth, PRUint32* aHeight)
242 GonkCameraHardware* hw = GetHardware(aHwHandle);
243 if (hw) {
244 *aWidth = hw->mWidth;
245 *aHeight = hw->mHeight;
246 } else {
247 *aWidth = 0;
248 *aHeight = 0;
252 void
253 GonkCameraHardware::SetPreviewSize(PRUint32 aWidth, PRUint32 aHeight)
255 Vector<Size> previewSizes;
256 PRUint32 bestWidth = aWidth;
257 PRUint32 bestHeight = aHeight;
258 PRUint32 minSizeDelta = PR_UINT32_MAX;
259 PRUint32 delta;
260 Size size;
262 mParams.getSupportedPreviewSizes(previewSizes);
264 if (!aWidth && !aHeight) {
265 // no size specified, take the first supported size
266 size = previewSizes[0];
267 bestWidth = size.width;
268 bestHeight = size.height;
269 } else if (aWidth && aHeight) {
270 // both height and width specified, find the supported size closest to requested size
271 for (PRUint32 i = 0; i < previewSizes.size(); i++) {
272 Size size = previewSizes[i];
273 PRUint32 delta = abs((long int)(size.width * size.height - aWidth * aHeight));
274 if (delta < minSizeDelta) {
275 minSizeDelta = delta;
276 bestWidth = size.width;
277 bestHeight = size.height;
280 } else if (!aWidth) {
281 // width not specified, find closest height match
282 for (PRUint32 i = 0; i < previewSizes.size(); i++) {
283 size = previewSizes[i];
284 delta = abs((long int)(size.height - aHeight));
285 if (delta < minSizeDelta) {
286 minSizeDelta = delta;
287 bestWidth = size.width;
288 bestHeight = size.height;
291 } else if (!aHeight) {
292 // height not specified, find closest width match
293 for (PRUint32 i = 0; i < previewSizes.size(); i++) {
294 size = previewSizes[i];
295 delta = abs((long int)(size.width - aWidth));
296 if (delta < minSizeDelta) {
297 minSizeDelta = delta;
298 bestWidth = size.width;
299 bestHeight = size.height;
304 mWidth = bestWidth;
305 mHeight = bestHeight;
306 mParams.setPreviewSize(mWidth, mHeight);
309 void
310 GonkCameraHardware::SetPreviewSize(PRUint32 aHwHandle, PRUint32 aWidth, PRUint32 aHeight)
312 GonkCameraHardware* hw = GetHardware(aHwHandle);
313 if (hw) {
314 hw->SetPreviewSize(aWidth, aHeight);
319 GonkCameraHardware::AutoFocus(PRUint32 aHwHandle)
321 DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
322 GonkCameraHardware* hw = GetHardware(aHwHandle);
323 if (!hw) {
324 return DEAD_OBJECT;
327 hw->mHardware->enableMsgType(CAMERA_MSG_FOCUS);
328 return hw->mHardware->autoFocus();
331 void
332 GonkCameraHardware::CancelAutoFocus(PRUint32 aHwHandle)
334 DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
335 GonkCameraHardware* hw = GetHardware(aHwHandle);
336 if (hw) {
337 hw->mHardware->cancelAutoFocus();
342 GonkCameraHardware::TakePicture(PRUint32 aHwHandle)
344 GonkCameraHardware* hw = GetHardware(aHwHandle);
345 if (!hw) {
346 return DEAD_OBJECT;
349 hw->mHardware->enableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
350 return hw->mHardware->takePicture();
353 void
354 GonkCameraHardware::CancelTakePicture(PRUint32 aHwHandle)
356 GonkCameraHardware* hw = GetHardware(aHwHandle);
357 if (hw) {
358 hw->mHardware->cancelPicture();
363 GonkCameraHardware::PushParameters(PRUint32 aHwHandle, const CameraParameters& aParams)
365 GonkCameraHardware* hw = GetHardware(aHwHandle);
366 if (!hw) {
367 return DEAD_OBJECT;
370 return hw->mHardware->setParameters(aParams);
373 void
374 GonkCameraHardware::PullParameters(PRUint32 aHwHandle, CameraParameters& aParams)
376 GonkCameraHardware* hw = GetHardware(aHwHandle);
377 if (hw) {
378 aParams = hw->mHardware->getParameters();
383 GonkCameraHardware::StartPreview()
385 const char* format;
387 DOM_CAMERA_LOGI("Preview formats: %s\n", mParams.get(mParams.KEY_SUPPORTED_PREVIEW_FORMATS));
389 // try to set preferred image format and frame rate
390 const char* const PREVIEW_FORMAT = "yuv420p";
391 const char* const BAD_PREVIEW_FORMAT = "yuv420sp";
392 mParams.setPreviewFormat(PREVIEW_FORMAT);
393 mParams.setPreviewFrameRate(mFps);
394 mHardware->setParameters(mParams);
396 // check that our settings stuck
397 mParams = mHardware->getParameters();
398 format = mParams.getPreviewFormat();
399 if (strcmp(format, PREVIEW_FORMAT) == 0) {
400 mPreviewFormat = PREVIEW_FORMAT_YUV420P; /* \o/ */
401 } else if (strcmp(format, BAD_PREVIEW_FORMAT) == 0) {
402 mPreviewFormat = PREVIEW_FORMAT_YUV420SP;
403 DOM_CAMERA_LOGA("Camera ignored our request for '%s' preview, will have to convert (from %d)\n", PREVIEW_FORMAT, mPreviewFormat);
404 } else {
405 mPreviewFormat = PREVIEW_FORMAT_UNKNOWN;
406 DOM_CAMERA_LOGE("Camera ignored our request for '%s' preview, returned UNSUPPORTED format '%s'\n", PREVIEW_FORMAT, format);
409 // Check the frame rate and log if the camera ignored our setting
410 PRUint32 fps = mParams.getPreviewFrameRate();
411 if (fps != mFps) {
412 DOM_CAMERA_LOGA("We asked for %d fps but camera returned %d fps, using it", mFps, fps);
413 mFps = fps;
416 return mHardware->startPreview();
420 GonkCameraHardware::StartPreview(PRUint32 aHwHandle)
422 GonkCameraHardware* hw = GetHardware(aHwHandle);
423 DOM_CAMERA_LOGI("%s:%d : aHwHandle = %d, hw = %p\n", __func__, __LINE__, aHwHandle, hw);
424 if (!hw) {
425 return DEAD_OBJECT;
428 return hw->StartPreview();
431 void
432 GonkCameraHardware::StopPreview(PRUint32 aHwHandle)
434 GonkCameraHardware* hw = GetHardware(aHwHandle);
435 if (hw) {
436 hw->mHardware->stopPreview();
440 PRUint32
441 GonkCameraHardware::GetPreviewFormat(PRUint32 aHwHandle)
443 GonkCameraHardware* hw = GetHardware(aHwHandle);
444 if (!hw) {
445 return PREVIEW_FORMAT_UNKNOWN;
448 return hw->mPreviewFormat;