1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/camera/GonkCameraHwMgr.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,426 @@ 1.4 +/* 1.5 + * Copyright (C) 2012-2014 Mozilla Foundation 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#include "GonkCameraHwMgr.h" 1.21 +#include "TestGonkCameraHardware.h" 1.22 + 1.23 +#include <binder/IPCThreadState.h> 1.24 +#include <sys/system_properties.h> 1.25 + 1.26 +#include "base/basictypes.h" 1.27 +#include "nsDebug.h" 1.28 +#include "mozilla/layers/TextureClient.h" 1.29 +#include "mozilla/Preferences.h" 1.30 +#include "mozilla/RefPtr.h" 1.31 +#include "GonkCameraControl.h" 1.32 +#include "GonkNativeWindow.h" 1.33 +#include "CameraCommon.h" 1.34 + 1.35 +using namespace mozilla; 1.36 +using namespace mozilla::layers; 1.37 +using namespace android; 1.38 + 1.39 +GonkCameraHardware::GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId, const sp<Camera>& aCamera) 1.40 + : mCameraId(aCameraId) 1.41 + , mClosing(false) 1.42 + , mNumFrames(0) 1.43 + , mCamera(aCamera) 1.44 + , mTarget(aTarget) 1.45 + , mSensorOrientation(0) 1.46 +{ 1.47 + DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n", __func__, __LINE__, (void*)this, (void*)aTarget); 1.48 +} 1.49 + 1.50 +void 1.51 +GonkCameraHardware::OnNewFrame() 1.52 +{ 1.53 + if (mClosing) { 1.54 + return; 1.55 + } 1.56 + RefPtr<TextureClient> buffer = mNativeWindow->getCurrentBuffer(); 1.57 + if (!buffer) { 1.58 + DOM_CAMERA_LOGW("received null frame"); 1.59 + return; 1.60 + } 1.61 + OnNewPreviewFrame(mTarget, buffer); 1.62 +} 1.63 + 1.64 +// Android data callback 1.65 +void 1.66 +GonkCameraHardware::postData(int32_t aMsgType, const sp<IMemory>& aDataPtr, camera_frame_metadata_t* metadata) 1.67 +{ 1.68 + if (mClosing) { 1.69 + return; 1.70 + } 1.71 + 1.72 + switch (aMsgType) { 1.73 + case CAMERA_MSG_PREVIEW_FRAME: 1.74 + // Do nothing 1.75 + break; 1.76 + 1.77 + case CAMERA_MSG_COMPRESSED_IMAGE: 1.78 + if (aDataPtr != nullptr) { 1.79 + OnTakePictureComplete(mTarget, static_cast<uint8_t*>(aDataPtr->pointer()), aDataPtr->size()); 1.80 + } else { 1.81 + OnTakePictureError(mTarget); 1.82 + } 1.83 + break; 1.84 + 1.85 + case CAMERA_MSG_PREVIEW_METADATA: 1.86 + OnFacesDetected(mTarget, metadata); 1.87 + break; 1.88 + 1.89 + default: 1.90 + DOM_CAMERA_LOGE("Unhandled data callback event %d\n", aMsgType); 1.91 + break; 1.92 + } 1.93 +} 1.94 + 1.95 +// Android notify callback 1.96 +void 1.97 +GonkCameraHardware::notify(int32_t aMsgType, int32_t ext1, int32_t ext2) 1.98 +{ 1.99 + if (mClosing) { 1.100 + return; 1.101 + } 1.102 + 1.103 + switch (aMsgType) { 1.104 + case CAMERA_MSG_FOCUS: 1.105 + OnAutoFocusComplete(mTarget, !!ext1); 1.106 + break; 1.107 + 1.108 +#if ANDROID_VERSION >= 16 1.109 + case CAMERA_MSG_FOCUS_MOVE: 1.110 + OnAutoFocusMoving(mTarget, !!ext1); 1.111 + break; 1.112 +#endif 1.113 + 1.114 + case CAMERA_MSG_SHUTTER: 1.115 + OnShutter(mTarget); 1.116 + break; 1.117 + 1.118 + case CAMERA_MSG_ERROR: 1.119 + OnError(mTarget, CameraControlListener::kErrorServiceFailed, ext1, ext2); 1.120 + break; 1.121 + 1.122 + default: 1.123 + DOM_CAMERA_LOGE("Unhandled notify callback event %d\n", aMsgType); 1.124 + break; 1.125 + } 1.126 +} 1.127 + 1.128 +void 1.129 +GonkCameraHardware::postDataTimestamp(nsecs_t aTimestamp, int32_t aMsgType, const sp<IMemory>& aDataPtr) 1.130 +{ 1.131 + DOM_CAMERA_LOGI("%s",__func__); 1.132 + if (mClosing) { 1.133 + return; 1.134 + } 1.135 + 1.136 + if (mListener.get()) { 1.137 + DOM_CAMERA_LOGI("Listener registered, posting recording frame!"); 1.138 + mListener->postDataTimestamp(aTimestamp, aMsgType, aDataPtr); 1.139 + } else { 1.140 + DOM_CAMERA_LOGW("No listener was set. Drop a recording frame."); 1.141 + mCamera->releaseRecordingFrame(aDataPtr); 1.142 + } 1.143 +} 1.144 + 1.145 +nsresult 1.146 +GonkCameraHardware::Init() 1.147 +{ 1.148 + DOM_CAMERA_LOGT("%s: this=%p\n", __func__, (void* )this); 1.149 + 1.150 + CameraInfo info; 1.151 + int rv = Camera::getCameraInfo(mCameraId, &info); 1.152 + if (rv != 0) { 1.153 + DOM_CAMERA_LOGE("%s: failed to get CameraInfo mCameraId %d\n", __func__, mCameraId); 1.154 + return NS_ERROR_FAILURE; 1.155 + } 1.156 + 1.157 + mRawSensorOrientation = info.orientation; 1.158 + mSensorOrientation = mRawSensorOrientation; 1.159 + 1.160 + /** 1.161 + * Non-V4L2-based camera driver adds extra offset onto picture orientation 1.162 + * set by gecko, so we have to adjust it back. 1.163 + */ 1.164 + char propname[PROP_NAME_MAX]; 1.165 + char prop[PROP_VALUE_MAX]; 1.166 + int offset = 0; 1.167 + snprintf(propname, sizeof(propname), "ro.moz.cam.%d.sensor_offset", mCameraId); 1.168 + if (__system_property_get(propname, prop) > 0) { 1.169 + offset = clamped(atoi(prop), 0, 270); 1.170 + mSensorOrientation += offset; 1.171 + mSensorOrientation %= 360; 1.172 + } 1.173 + DOM_CAMERA_LOGI("Sensor orientation: base=%d, offset=%d, final=%d\n", info.orientation, offset, mSensorOrientation); 1.174 + 1.175 + // Disable shutter sound in android CameraService because gaia camera app will play it 1.176 + mCamera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0); 1.177 + 1.178 + mNativeWindow = new GonkNativeWindow(); 1.179 + mNativeWindow->setNewFrameCallback(this); 1.180 + mCamera->setListener(this); 1.181 + 1.182 +#if defined(MOZ_WIDGET_GONK) 1.183 + 1.184 +#if ANDROID_VERSION >= 19 1.185 + mCamera->setPreviewTarget(mNativeWindow->getBufferQueue()); 1.186 +#elif (ANDROID_VERSION == 17) || (ANDROID_VERSION == 18) 1.187 + mCamera->setPreviewTexture(mNativeWindow->getBufferQueue()); 1.188 +#else 1.189 + mCamera->setPreviewTexture(mNativeWindow); 1.190 +#endif 1.191 + 1.192 +#if ANDROID_VERSION >= 16 1.193 + rv = mCamera->sendCommand(CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG, 1, 0); 1.194 + if (rv != OK) { 1.195 + NS_WARNING("Failed to send command CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG"); 1.196 + } 1.197 +#endif 1.198 + 1.199 +#endif 1.200 + 1.201 + return NS_OK; 1.202 +} 1.203 + 1.204 +sp<GonkCameraHardware> 1.205 +GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId) 1.206 +{ 1.207 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18 1.208 + sp<Camera> camera = Camera::connect(aCameraId, /* clientPackageName */String16("gonk.camera"), Camera::USE_CALLING_UID); 1.209 +#else 1.210 + sp<Camera> camera = Camera::connect(aCameraId); 1.211 +#endif 1.212 + 1.213 + if (camera.get() == nullptr) { 1.214 + return nullptr; 1.215 + } 1.216 + 1.217 + const nsAdoptingCString& test = 1.218 + mozilla::Preferences::GetCString("camera.control.test.enabled"); 1.219 + sp<GonkCameraHardware> cameraHardware; 1.220 + if (test.EqualsASCII("hardware")) { 1.221 + NS_WARNING("Using test Gonk hardware layer"); 1.222 + cameraHardware = new TestGonkCameraHardware(aTarget, aCameraId, camera); 1.223 + } else { 1.224 + cameraHardware = new GonkCameraHardware(aTarget, aCameraId, camera); 1.225 + } 1.226 + 1.227 + nsresult rv = cameraHardware->Init(); 1.228 + if (NS_FAILED(rv)) { 1.229 + DOM_CAMERA_LOGE("Failed to initialize camera hardware (0x%X)\n", rv); 1.230 + return nullptr; 1.231 + } 1.232 + 1.233 + return cameraHardware; 1.234 +} 1.235 + 1.236 +void 1.237 +GonkCameraHardware::Close() 1.238 +{ 1.239 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, (void*)this); 1.240 + 1.241 + mClosing = true; 1.242 + mCamera->stopPreview(); 1.243 + mCamera->disconnect(); 1.244 + if (mNativeWindow.get()) { 1.245 + mNativeWindow->abandon(); 1.246 + } 1.247 + mCamera.clear(); 1.248 + mNativeWindow.clear(); 1.249 + 1.250 + // Ensure that ICamera's destructor is actually executed 1.251 + IPCThreadState::self()->flushCommands(); 1.252 +} 1.253 + 1.254 +GonkCameraHardware::~GonkCameraHardware() 1.255 +{ 1.256 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, (void*)this); 1.257 + mCamera.clear(); 1.258 + mNativeWindow.clear(); 1.259 + 1.260 + if (mClosing) { 1.261 + return; 1.262 + } 1.263 + 1.264 + /** 1.265 + * Trigger the OnClosed event; the upper layers can't do anything 1.266 + * with the hardware layer once they receive this event. 1.267 + */ 1.268 + if (mTarget) { 1.269 + OnClosed(mTarget); 1.270 + } 1.271 +} 1.272 + 1.273 +int 1.274 +GonkCameraHardware::GetSensorOrientation(uint32_t aType) 1.275 +{ 1.276 + DOM_CAMERA_LOGI("%s\n", __func__); 1.277 + 1.278 + switch (aType) { 1.279 + case OFFSET_SENSOR_ORIENTATION: 1.280 + return mSensorOrientation; 1.281 + 1.282 + case RAW_SENSOR_ORIENTATION: 1.283 + return mRawSensorOrientation; 1.284 + 1.285 + default: 1.286 + DOM_CAMERA_LOGE("%s:%d : unknown aType=%d\n", __func__, __LINE__, aType); 1.287 + return 0; 1.288 + } 1.289 +} 1.290 + 1.291 +int 1.292 +GonkCameraHardware::AutoFocus() 1.293 +{ 1.294 + DOM_CAMERA_LOGI("%s\n", __func__); 1.295 + return mCamera->autoFocus(); 1.296 +} 1.297 + 1.298 +int 1.299 +GonkCameraHardware::CancelAutoFocus() 1.300 +{ 1.301 + DOM_CAMERA_LOGI("%s\n", __func__); 1.302 + return mCamera->cancelAutoFocus(); 1.303 +} 1.304 + 1.305 +int 1.306 +GonkCameraHardware::StartFaceDetection() 1.307 +{ 1.308 + DOM_CAMERA_LOGI("%s\n", __func__); 1.309 + int rv = INVALID_OPERATION; 1.310 + 1.311 +#if ANDROID_VERSION >= 15 1.312 + rv = mCamera->sendCommand(CAMERA_CMD_START_FACE_DETECTION, CAMERA_FACE_DETECTION_HW, 0); 1.313 +#endif 1.314 + if (rv != OK) { 1.315 + DOM_CAMERA_LOGE("Start face detection failed with status %d", rv); 1.316 + } 1.317 + 1.318 + return rv; 1.319 +} 1.320 + 1.321 +int 1.322 +GonkCameraHardware::StopFaceDetection() 1.323 +{ 1.324 + DOM_CAMERA_LOGI("%s\n", __func__); 1.325 + int rv = INVALID_OPERATION; 1.326 + 1.327 +#if ANDROID_VERSION >= 15 1.328 + rv = mCamera->sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, 0, 0); 1.329 +#endif 1.330 + if (rv != OK) { 1.331 + DOM_CAMERA_LOGE("Stop face detection failed with status %d", rv); 1.332 + } 1.333 + 1.334 + return rv; 1.335 +} 1.336 + 1.337 +int 1.338 +GonkCameraHardware::TakePicture() 1.339 +{ 1.340 + return mCamera->takePicture(CAMERA_MSG_SHUTTER | CAMERA_MSG_COMPRESSED_IMAGE); 1.341 +} 1.342 + 1.343 +void 1.344 +GonkCameraHardware::CancelTakePicture() 1.345 +{ 1.346 + DOM_CAMERA_LOGW("%s: android::Camera do not provide this capability\n", __func__); 1.347 +} 1.348 + 1.349 +int 1.350 +GonkCameraHardware::PushParameters(const GonkCameraParameters& aParams) 1.351 +{ 1.352 + const String8 s = aParams.Flatten(); 1.353 + return mCamera->setParameters(s); 1.354 +} 1.355 + 1.356 +int 1.357 +GonkCameraHardware::PushParameters(const CameraParameters& aParams) 1.358 +{ 1.359 + String8 s = aParams.flatten(); 1.360 + return mCamera->setParameters(s); 1.361 +} 1.362 + 1.363 +nsresult 1.364 +GonkCameraHardware::PullParameters(GonkCameraParameters& aParams) 1.365 +{ 1.366 + const String8 s = mCamera->getParameters(); 1.367 + return aParams.Unflatten(s); 1.368 +} 1.369 + 1.370 +void 1.371 +GonkCameraHardware::PullParameters(CameraParameters& aParams) 1.372 +{ 1.373 + const String8 s = mCamera->getParameters(); 1.374 + aParams.unflatten(s); 1.375 +} 1.376 + 1.377 +int 1.378 +GonkCameraHardware::StartPreview() 1.379 +{ 1.380 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); 1.381 + return mCamera->startPreview(); 1.382 +} 1.383 + 1.384 +void 1.385 +GonkCameraHardware::StopPreview() 1.386 +{ 1.387 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); 1.388 + mCamera->stopPreview(); 1.389 +} 1.390 + 1.391 +int 1.392 +GonkCameraHardware::StartRecording() 1.393 +{ 1.394 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); 1.395 + int rv = OK; 1.396 + 1.397 + rv = mCamera->startRecording(); 1.398 + if (rv != OK) { 1.399 + DOM_CAMERA_LOGE("mHardware->startRecording() failed with status %d", rv); 1.400 + } 1.401 + return rv; 1.402 +} 1.403 + 1.404 +int 1.405 +GonkCameraHardware::StopRecording() 1.406 +{ 1.407 + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); 1.408 + mCamera->stopRecording(); 1.409 + return OK; 1.410 +} 1.411 + 1.412 +int 1.413 +GonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener) 1.414 +{ 1.415 + mListener = aListener; 1.416 + return OK; 1.417 +} 1.418 + 1.419 +void 1.420 +GonkCameraHardware::ReleaseRecordingFrame(const sp<IMemory>& aFrame) 1.421 +{ 1.422 + mCamera->releaseRecordingFrame(aFrame); 1.423 +} 1.424 + 1.425 +int 1.426 +GonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled) 1.427 +{ 1.428 + return mCamera->storeMetaDataInBuffers(aEnabled); 1.429 +}