|
1 /* |
|
2 * Copyright (C) 2012-2014 Mozilla Foundation |
|
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 #include "GonkCameraHwMgr.h" |
|
18 #include "TestGonkCameraHardware.h" |
|
19 |
|
20 #include <binder/IPCThreadState.h> |
|
21 #include <sys/system_properties.h> |
|
22 |
|
23 #include "base/basictypes.h" |
|
24 #include "nsDebug.h" |
|
25 #include "mozilla/layers/TextureClient.h" |
|
26 #include "mozilla/Preferences.h" |
|
27 #include "mozilla/RefPtr.h" |
|
28 #include "GonkCameraControl.h" |
|
29 #include "GonkNativeWindow.h" |
|
30 #include "CameraCommon.h" |
|
31 |
|
32 using namespace mozilla; |
|
33 using namespace mozilla::layers; |
|
34 using namespace android; |
|
35 |
|
36 GonkCameraHardware::GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId, const sp<Camera>& aCamera) |
|
37 : mCameraId(aCameraId) |
|
38 , mClosing(false) |
|
39 , mNumFrames(0) |
|
40 , mCamera(aCamera) |
|
41 , mTarget(aTarget) |
|
42 , mSensorOrientation(0) |
|
43 { |
|
44 DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n", __func__, __LINE__, (void*)this, (void*)aTarget); |
|
45 } |
|
46 |
|
47 void |
|
48 GonkCameraHardware::OnNewFrame() |
|
49 { |
|
50 if (mClosing) { |
|
51 return; |
|
52 } |
|
53 RefPtr<TextureClient> buffer = mNativeWindow->getCurrentBuffer(); |
|
54 if (!buffer) { |
|
55 DOM_CAMERA_LOGW("received null frame"); |
|
56 return; |
|
57 } |
|
58 OnNewPreviewFrame(mTarget, buffer); |
|
59 } |
|
60 |
|
61 // Android data callback |
|
62 void |
|
63 GonkCameraHardware::postData(int32_t aMsgType, const sp<IMemory>& aDataPtr, camera_frame_metadata_t* metadata) |
|
64 { |
|
65 if (mClosing) { |
|
66 return; |
|
67 } |
|
68 |
|
69 switch (aMsgType) { |
|
70 case CAMERA_MSG_PREVIEW_FRAME: |
|
71 // Do nothing |
|
72 break; |
|
73 |
|
74 case CAMERA_MSG_COMPRESSED_IMAGE: |
|
75 if (aDataPtr != nullptr) { |
|
76 OnTakePictureComplete(mTarget, static_cast<uint8_t*>(aDataPtr->pointer()), aDataPtr->size()); |
|
77 } else { |
|
78 OnTakePictureError(mTarget); |
|
79 } |
|
80 break; |
|
81 |
|
82 case CAMERA_MSG_PREVIEW_METADATA: |
|
83 OnFacesDetected(mTarget, metadata); |
|
84 break; |
|
85 |
|
86 default: |
|
87 DOM_CAMERA_LOGE("Unhandled data callback event %d\n", aMsgType); |
|
88 break; |
|
89 } |
|
90 } |
|
91 |
|
92 // Android notify callback |
|
93 void |
|
94 GonkCameraHardware::notify(int32_t aMsgType, int32_t ext1, int32_t ext2) |
|
95 { |
|
96 if (mClosing) { |
|
97 return; |
|
98 } |
|
99 |
|
100 switch (aMsgType) { |
|
101 case CAMERA_MSG_FOCUS: |
|
102 OnAutoFocusComplete(mTarget, !!ext1); |
|
103 break; |
|
104 |
|
105 #if ANDROID_VERSION >= 16 |
|
106 case CAMERA_MSG_FOCUS_MOVE: |
|
107 OnAutoFocusMoving(mTarget, !!ext1); |
|
108 break; |
|
109 #endif |
|
110 |
|
111 case CAMERA_MSG_SHUTTER: |
|
112 OnShutter(mTarget); |
|
113 break; |
|
114 |
|
115 case CAMERA_MSG_ERROR: |
|
116 OnError(mTarget, CameraControlListener::kErrorServiceFailed, ext1, ext2); |
|
117 break; |
|
118 |
|
119 default: |
|
120 DOM_CAMERA_LOGE("Unhandled notify callback event %d\n", aMsgType); |
|
121 break; |
|
122 } |
|
123 } |
|
124 |
|
125 void |
|
126 GonkCameraHardware::postDataTimestamp(nsecs_t aTimestamp, int32_t aMsgType, const sp<IMemory>& aDataPtr) |
|
127 { |
|
128 DOM_CAMERA_LOGI("%s",__func__); |
|
129 if (mClosing) { |
|
130 return; |
|
131 } |
|
132 |
|
133 if (mListener.get()) { |
|
134 DOM_CAMERA_LOGI("Listener registered, posting recording frame!"); |
|
135 mListener->postDataTimestamp(aTimestamp, aMsgType, aDataPtr); |
|
136 } else { |
|
137 DOM_CAMERA_LOGW("No listener was set. Drop a recording frame."); |
|
138 mCamera->releaseRecordingFrame(aDataPtr); |
|
139 } |
|
140 } |
|
141 |
|
142 nsresult |
|
143 GonkCameraHardware::Init() |
|
144 { |
|
145 DOM_CAMERA_LOGT("%s: this=%p\n", __func__, (void* )this); |
|
146 |
|
147 CameraInfo info; |
|
148 int rv = Camera::getCameraInfo(mCameraId, &info); |
|
149 if (rv != 0) { |
|
150 DOM_CAMERA_LOGE("%s: failed to get CameraInfo mCameraId %d\n", __func__, mCameraId); |
|
151 return NS_ERROR_FAILURE; |
|
152 } |
|
153 |
|
154 mRawSensorOrientation = info.orientation; |
|
155 mSensorOrientation = mRawSensorOrientation; |
|
156 |
|
157 /** |
|
158 * Non-V4L2-based camera driver adds extra offset onto picture orientation |
|
159 * set by gecko, so we have to adjust it back. |
|
160 */ |
|
161 char propname[PROP_NAME_MAX]; |
|
162 char prop[PROP_VALUE_MAX]; |
|
163 int offset = 0; |
|
164 snprintf(propname, sizeof(propname), "ro.moz.cam.%d.sensor_offset", mCameraId); |
|
165 if (__system_property_get(propname, prop) > 0) { |
|
166 offset = clamped(atoi(prop), 0, 270); |
|
167 mSensorOrientation += offset; |
|
168 mSensorOrientation %= 360; |
|
169 } |
|
170 DOM_CAMERA_LOGI("Sensor orientation: base=%d, offset=%d, final=%d\n", info.orientation, offset, mSensorOrientation); |
|
171 |
|
172 // Disable shutter sound in android CameraService because gaia camera app will play it |
|
173 mCamera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0); |
|
174 |
|
175 mNativeWindow = new GonkNativeWindow(); |
|
176 mNativeWindow->setNewFrameCallback(this); |
|
177 mCamera->setListener(this); |
|
178 |
|
179 #if defined(MOZ_WIDGET_GONK) |
|
180 |
|
181 #if ANDROID_VERSION >= 19 |
|
182 mCamera->setPreviewTarget(mNativeWindow->getBufferQueue()); |
|
183 #elif (ANDROID_VERSION == 17) || (ANDROID_VERSION == 18) |
|
184 mCamera->setPreviewTexture(mNativeWindow->getBufferQueue()); |
|
185 #else |
|
186 mCamera->setPreviewTexture(mNativeWindow); |
|
187 #endif |
|
188 |
|
189 #if ANDROID_VERSION >= 16 |
|
190 rv = mCamera->sendCommand(CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG, 1, 0); |
|
191 if (rv != OK) { |
|
192 NS_WARNING("Failed to send command CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG"); |
|
193 } |
|
194 #endif |
|
195 |
|
196 #endif |
|
197 |
|
198 return NS_OK; |
|
199 } |
|
200 |
|
201 sp<GonkCameraHardware> |
|
202 GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId) |
|
203 { |
|
204 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 |
|
205 sp<Camera> camera = Camera::connect(aCameraId, /* clientPackageName */String16("gonk.camera"), Camera::USE_CALLING_UID); |
|
206 #else |
|
207 sp<Camera> camera = Camera::connect(aCameraId); |
|
208 #endif |
|
209 |
|
210 if (camera.get() == nullptr) { |
|
211 return nullptr; |
|
212 } |
|
213 |
|
214 const nsAdoptingCString& test = |
|
215 mozilla::Preferences::GetCString("camera.control.test.enabled"); |
|
216 sp<GonkCameraHardware> cameraHardware; |
|
217 if (test.EqualsASCII("hardware")) { |
|
218 NS_WARNING("Using test Gonk hardware layer"); |
|
219 cameraHardware = new TestGonkCameraHardware(aTarget, aCameraId, camera); |
|
220 } else { |
|
221 cameraHardware = new GonkCameraHardware(aTarget, aCameraId, camera); |
|
222 } |
|
223 |
|
224 nsresult rv = cameraHardware->Init(); |
|
225 if (NS_FAILED(rv)) { |
|
226 DOM_CAMERA_LOGE("Failed to initialize camera hardware (0x%X)\n", rv); |
|
227 return nullptr; |
|
228 } |
|
229 |
|
230 return cameraHardware; |
|
231 } |
|
232 |
|
233 void |
|
234 GonkCameraHardware::Close() |
|
235 { |
|
236 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, (void*)this); |
|
237 |
|
238 mClosing = true; |
|
239 mCamera->stopPreview(); |
|
240 mCamera->disconnect(); |
|
241 if (mNativeWindow.get()) { |
|
242 mNativeWindow->abandon(); |
|
243 } |
|
244 mCamera.clear(); |
|
245 mNativeWindow.clear(); |
|
246 |
|
247 // Ensure that ICamera's destructor is actually executed |
|
248 IPCThreadState::self()->flushCommands(); |
|
249 } |
|
250 |
|
251 GonkCameraHardware::~GonkCameraHardware() |
|
252 { |
|
253 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, (void*)this); |
|
254 mCamera.clear(); |
|
255 mNativeWindow.clear(); |
|
256 |
|
257 if (mClosing) { |
|
258 return; |
|
259 } |
|
260 |
|
261 /** |
|
262 * Trigger the OnClosed event; the upper layers can't do anything |
|
263 * with the hardware layer once they receive this event. |
|
264 */ |
|
265 if (mTarget) { |
|
266 OnClosed(mTarget); |
|
267 } |
|
268 } |
|
269 |
|
270 int |
|
271 GonkCameraHardware::GetSensorOrientation(uint32_t aType) |
|
272 { |
|
273 DOM_CAMERA_LOGI("%s\n", __func__); |
|
274 |
|
275 switch (aType) { |
|
276 case OFFSET_SENSOR_ORIENTATION: |
|
277 return mSensorOrientation; |
|
278 |
|
279 case RAW_SENSOR_ORIENTATION: |
|
280 return mRawSensorOrientation; |
|
281 |
|
282 default: |
|
283 DOM_CAMERA_LOGE("%s:%d : unknown aType=%d\n", __func__, __LINE__, aType); |
|
284 return 0; |
|
285 } |
|
286 } |
|
287 |
|
288 int |
|
289 GonkCameraHardware::AutoFocus() |
|
290 { |
|
291 DOM_CAMERA_LOGI("%s\n", __func__); |
|
292 return mCamera->autoFocus(); |
|
293 } |
|
294 |
|
295 int |
|
296 GonkCameraHardware::CancelAutoFocus() |
|
297 { |
|
298 DOM_CAMERA_LOGI("%s\n", __func__); |
|
299 return mCamera->cancelAutoFocus(); |
|
300 } |
|
301 |
|
302 int |
|
303 GonkCameraHardware::StartFaceDetection() |
|
304 { |
|
305 DOM_CAMERA_LOGI("%s\n", __func__); |
|
306 int rv = INVALID_OPERATION; |
|
307 |
|
308 #if ANDROID_VERSION >= 15 |
|
309 rv = mCamera->sendCommand(CAMERA_CMD_START_FACE_DETECTION, CAMERA_FACE_DETECTION_HW, 0); |
|
310 #endif |
|
311 if (rv != OK) { |
|
312 DOM_CAMERA_LOGE("Start face detection failed with status %d", rv); |
|
313 } |
|
314 |
|
315 return rv; |
|
316 } |
|
317 |
|
318 int |
|
319 GonkCameraHardware::StopFaceDetection() |
|
320 { |
|
321 DOM_CAMERA_LOGI("%s\n", __func__); |
|
322 int rv = INVALID_OPERATION; |
|
323 |
|
324 #if ANDROID_VERSION >= 15 |
|
325 rv = mCamera->sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, 0, 0); |
|
326 #endif |
|
327 if (rv != OK) { |
|
328 DOM_CAMERA_LOGE("Stop face detection failed with status %d", rv); |
|
329 } |
|
330 |
|
331 return rv; |
|
332 } |
|
333 |
|
334 int |
|
335 GonkCameraHardware::TakePicture() |
|
336 { |
|
337 return mCamera->takePicture(CAMERA_MSG_SHUTTER | CAMERA_MSG_COMPRESSED_IMAGE); |
|
338 } |
|
339 |
|
340 void |
|
341 GonkCameraHardware::CancelTakePicture() |
|
342 { |
|
343 DOM_CAMERA_LOGW("%s: android::Camera do not provide this capability\n", __func__); |
|
344 } |
|
345 |
|
346 int |
|
347 GonkCameraHardware::PushParameters(const GonkCameraParameters& aParams) |
|
348 { |
|
349 const String8 s = aParams.Flatten(); |
|
350 return mCamera->setParameters(s); |
|
351 } |
|
352 |
|
353 int |
|
354 GonkCameraHardware::PushParameters(const CameraParameters& aParams) |
|
355 { |
|
356 String8 s = aParams.flatten(); |
|
357 return mCamera->setParameters(s); |
|
358 } |
|
359 |
|
360 nsresult |
|
361 GonkCameraHardware::PullParameters(GonkCameraParameters& aParams) |
|
362 { |
|
363 const String8 s = mCamera->getParameters(); |
|
364 return aParams.Unflatten(s); |
|
365 } |
|
366 |
|
367 void |
|
368 GonkCameraHardware::PullParameters(CameraParameters& aParams) |
|
369 { |
|
370 const String8 s = mCamera->getParameters(); |
|
371 aParams.unflatten(s); |
|
372 } |
|
373 |
|
374 int |
|
375 GonkCameraHardware::StartPreview() |
|
376 { |
|
377 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); |
|
378 return mCamera->startPreview(); |
|
379 } |
|
380 |
|
381 void |
|
382 GonkCameraHardware::StopPreview() |
|
383 { |
|
384 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); |
|
385 mCamera->stopPreview(); |
|
386 } |
|
387 |
|
388 int |
|
389 GonkCameraHardware::StartRecording() |
|
390 { |
|
391 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); |
|
392 int rv = OK; |
|
393 |
|
394 rv = mCamera->startRecording(); |
|
395 if (rv != OK) { |
|
396 DOM_CAMERA_LOGE("mHardware->startRecording() failed with status %d", rv); |
|
397 } |
|
398 return rv; |
|
399 } |
|
400 |
|
401 int |
|
402 GonkCameraHardware::StopRecording() |
|
403 { |
|
404 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); |
|
405 mCamera->stopRecording(); |
|
406 return OK; |
|
407 } |
|
408 |
|
409 int |
|
410 GonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener) |
|
411 { |
|
412 mListener = aListener; |
|
413 return OK; |
|
414 } |
|
415 |
|
416 void |
|
417 GonkCameraHardware::ReleaseRecordingFrame(const sp<IMemory>& aFrame) |
|
418 { |
|
419 mCamera->releaseRecordingFrame(aFrame); |
|
420 } |
|
421 |
|
422 int |
|
423 GonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled) |
|
424 { |
|
425 return mCamera->storeMetaDataInBuffers(aEnabled); |
|
426 } |