Android(安卓)Camera子系统代码流程1
16lz
2021-12-04
Z:\workspace\MT3561\frameworks\base\core\java\android\hardware\Camera.java
/** * Creates a new Camera object to access the first back-facing camera on the * device. If the device does not have a back-facing camera, this returns * null. * @see #open(int) */ public static Camera open() { if (!isPermissionGranted()) { return null; }/// Modified By: jason./// commit: Interface usage restrictions. @{int pid = android.os.Process.myPid();String enable = SystemProperties.get(ISystemPropert.ENABLE_3RD_PARTY_CAMERA, "0");boolean allow_3rdparty = enable.equals("1");if (mAVInputProcessID == pid || allow_3rdparty) {int numberOfCameras = getNumberOfCameras();CameraInfo cameraInfo = new CameraInfo();for (int i = 0; i < numberOfCameras; i++) {getCameraInfo(i, cameraInfo);if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {return new Camera(i);}}}/// }@ return null; }
/** used by Camera#open, Camera#open(int) */ Camera(int cameraId) { int err = cameraInitNormal(cameraId); if (checkInitErrors(err)) { switch(err) { case EACCESS: throw new RuntimeException("Fail to connect to camera service"); case ENODEV: throw new RuntimeException("Camera initialization failed"); default: // Should never hit this. throw new RuntimeException("Unknown camera error"); } } }
private int cameraInitNormal(int cameraId) { return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT); }
private int cameraInitVersion(int cameraId, int halVersion) { mShutterCallback = null; mRawImageCallback = null; mJpegCallback = null; mPreviewCallback = null; mPreviewRawDumpCallback = null; mPostviewCallback = null; mUsingPreviewAllocation = false; mZoomListener = null; Looper looper; if ((looper = Looper.myLooper()) != null) { mEventHandler = new EventHandler(this, looper); } else if ((looper = Looper.getMainLooper()) != null) { mEventHandler = new EventHandler(this, looper); } else { mEventHandler = null; } return native_setup(new WeakReference(this), cameraId, halVersion, ActivityThread.currentOpPackageName()); }
private native final int native_setup(Object camera_this, int cameraId, int halVersion, String packageName);
Z:\workspace\MT3561\frameworks\base\core\jni\android_hardware_Camera.cpp
static JNINativeMethod camMethods[] = { { "getNumberOfCameras", "()I", (void *)android_hardware_Camera_getNumberOfCameras }, { "_getCameraInfo", "(ILandroid/hardware/Camera$CameraInfo;)V", (void*)android_hardware_Camera_getCameraInfo }, { "native_setup", "(Ljava/lang/Object;IILjava/lang/String;)I", (void*)android_hardware_Camera_native_setup }, { "native_release", "()V", (void*)android_hardware_Camera_release }, { "setPreviewSurface", "(Landroid/view/Surface;)V", (void *)android_hardware_Camera_setPreviewSurface }, { "setPreviewTexture", "(Landroid/graphics/SurfaceTexture;)V", (void *)android_hardware_Camera_setPreviewTexture }, { "setPreviewCallbackSurface", "(Landroid/view/Surface;)V", (void *)android_hardware_Camera_setPreviewCallbackSurface }, { "startPreview", "()V", (void *)android_hardware_Camera_startPreview }, { "_stopPreview", "()V", (void *)android_hardware_Camera_stopPreview },
// Get all the required offsets in java class and register native functionsint register_android_hardware_Camera(JNIEnv *env){ field fields_to_find[] = { { "android/hardware/Camera", "mNativeContext", "J", &fields.context }, { "android/hardware/Camera$CameraInfo", "facing", "I", &fields.facing }, { "android/hardware/Camera$CameraInfo", "orientation", "I", &fields.orientation }, { "android/hardware/Camera$CameraInfo", "canDisableShutterSound", "Z", &fields.canDisableShutterSound }, { "android/hardware/Camera$Face", "rect", "Landroid/graphics/Rect;", &fields.face_rect }, { "android/hardware/Camera$Face", "leftEye", "Landroid/graphics/Point;", &fields.face_left_eye}, { "android/hardware/Camera$Face", "rightEye", "Landroid/graphics/Point;", &fields.face_right_eye}, { "android/hardware/Camera$Face", "mouth", "Landroid/graphics/Point;", &fields.face_mouth}, { "android/hardware/Camera$Face", "score", "I", &fields.face_score }, { "android/hardware/Camera$Face", "id", "I", &fields.face_id}, { "android/graphics/Rect", "left", "I", &fields.rect_left }, { "android/graphics/Rect", "top", "I", &fields.rect_top }, { "android/graphics/Rect", "right", "I", &fields.rect_right }, { "android/graphics/Rect", "bottom", "I", &fields.rect_bottom }, { "android/graphics/Point", "x", "I", &fields.point_x}, { "android/graphics/Point", "y", "I", &fields.point_y}, }; find_fields(env, fields_to_find, NELEM(fields_to_find)); jclass clazz = FindClassOrDie(env, "android/hardware/Camera"); fields.post_event = GetStaticMethodIDOrDie(env, clazz, "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V"); clazz = FindClassOrDie(env, "android/graphics/Rect"); fields.rect_constructor = GetMethodIDOrDie(env, clazz, "", "()V"); clazz = FindClassOrDie(env, "android/hardware/Camera$Face"); fields.face_constructor = GetMethodIDOrDie(env, clazz, "", "()V"); clazz = env->FindClass("android/graphics/Point"); fields.point_constructor = env->GetMethodID(clazz, "", "()V"); if (fields.point_constructor == NULL) { ALOGE("Can't find android/graphics/Point()"); return -1; }// Added by: jason.env->GetJavaVM(&javaVM); // Register native functions return RegisterMethodsOrDie(env, "android/hardware/Camera", camMethods, NELEM(camMethods));}
// connect to camera servicestatic jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName){ // Convert jstring to String16 const char16_t *rawClientName = reinterpret_cast( env->GetStringChars(clientPackageName, NULL)); jsize rawClientNameLen = env->GetStringLength(clientPackageName); String16 clientName(rawClientName, rawClientNameLen); env->ReleaseStringChars(clientPackageName, reinterpret_cast(rawClientName)); sp camera; if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) { // Default path: hal version is don't care, do normal camera connect. camera = Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID); } else { jint status = Camera::connectLegacy(cameraId, halVersion, clientName, Camera::USE_CALLING_UID, camera); if (status != NO_ERROR) { return status; } } if (camera == NULL) { return -EACCES; } // make sure camera hardware is alive if (camera->getStatus() != NO_ERROR) { return NO_INIT; } jclass clazz = env->GetObjectClass(thiz); if (clazz == NULL) { // This should never happen jniThrowRuntimeException(env, "Can't find android/hardware/Camera"); return INVALID_OPERATION; } // We use a weak reference so the Camera object can be garbage collected. // The reference is only used as a proxy for callbacks. //!++ #if 0 // Use MTK JNI for MTK camera feature. sp context = new JNICameraContext(env, weak_this, clazz, camera); #else sp context = new MtkJNICameraContext(env, weak_this, clazz, camera); #endif //!-- context->incStrong((void*)android_hardware_Camera_native_setup); camera->setListener(context); // save context in opaque field env->SetLongField(thiz, fields.context, (jlong)context.get()); return NO_ERROR;}
Z:\workspace\MT3561\frameworks\av\include\camera\CameraBase.h
typedef CameraBase CameraBaseT; typedef typename TCamTraits::TCamListener TCamListener; typedef typename TCamTraits::TCamUser TCamUser; typedef typename TCamTraits::TCamCallbacks TCamCallbacks; typedef typename TCamTraits::TCamConnectService TCamConnectService;
Z:\workspace\MT3561\frameworks\av\include\camera\Camera.h
class Camera;template <>struct CameraTraits{ typedef CameraListener TCamListener; typedef ICamera TCamUser; typedef ICameraClient TCamCallbacks; typedef status_t (ICameraService::*TCamConnectService)(const sp&, int, const String16&, int, /*out*/ sp&); static TCamConnectService fnConnectService;};
class Camera : public CameraBase, public BnCameraClient{public: enum { USE_CALLING_UID = ICameraService::USE_CALLING_UID }; // construct a camera client from an existing remote static sp create(const sp& camera); static sp connect(int cameraId, const String16& clientPackageName, int clientUid); static status_t connectLegacy(int cameraId, int halVersion, const String16& clientPackageName, int clientUid, sp& camera); virtual ~Camera();
Z:\workspace\MT3561\frameworks\av\camera\Camera.cpp
sp Camera::connect(int cameraId, const String16& clientPackageName, int clientUid){ return CameraBaseT::connect(cameraId, clientPackageName, clientUid);}
template sp CameraBase::connect(int cameraId, const String16& clientPackageName, int clientUid){ ALOGV("%s: connect", __FUNCTION__); sp c = new TCam(cameraId); sp cl = c; status_t status = NO_ERROR; const sp& cs = getCameraService(); if (cs != 0) { TCamConnectService fnConnectService = TCamTraits::fnConnectService; status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, /*out*/ c->mCamera); } if (status == OK && c->mCamera != 0) { IInterface::asBinder(c->mCamera)->linkToDeath(c); c->mStatus = NO_ERROR; } else { ALOGW("An error occurred while connecting to camera: %d", cameraId); c.clear(); } return c;}
创建Camera的过程
Camera::Camera(int cameraId) : CameraBase(cameraId){}
template CameraBase::CameraBase(int cameraId) : mStatus(UNKNOWN_ERROR), mCameraId(cameraId){}
const char* kCameraServiceName = "media.camera";
// establish binder interface to camera servicetemplate const sp& CameraBase::getCameraService(){ Mutex::Autolock _l(gLock); if (gCameraService.get() == 0) { sp sm = defaultServiceManager(); sp binder; do { binder = sm->getService(String16(kCameraServiceName)); if (binder != 0) { break; } ALOGW("CameraService not published, waiting..."); usleep(kCameraServicePollDelay); } while(true); if (gDeathNotifier == NULL) { gDeathNotifier = new DeathNotifier(); } binder->linkToDeath(gDeathNotifier); gCameraService = interface_cast(binder); } ALOGE_IF(gCameraService == 0, "no CameraService!?"); return gCameraService;}
fnConnectService通过参数和返回类型为BpCameraService.connect函数
Z:\workspace\MT3561\frameworks\av\camera\ICameraService.cpp
class BpCameraService: public BpInterface{public: BpCameraService(const sp& impl) : BpInterface(impl) { }
// connect to camera service (android.hardware.Camera) virtual status_t connect(const sp& cameraClient, int cameraId, const String16 &clientPackageName, int clientUid, /*out*/ sp& device) { Parcel data, reply; data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(cameraClient)); data.writeInt32(cameraId); data.writeString16(clientPackageName); data.writeInt32(clientUid); status_t status; status = remote()->transact(BnCameraService::CONNECT, data, &reply); if (status != OK) return status; if (readExceptionCode(reply)) return -EPROTO; status = reply.readInt32(); if (reply.readInt32() != 0) { device = interface_cast(reply.readStrongBinder()); } return status; }
再通过binder进程间通信跳转到BnCameraService类中
class BnCameraService: public BnInterface{public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);};
status_t BnCameraService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ switch(code) { case GET_NUMBER_OF_CAMERAS: { CHECK_INTERFACE(ICameraService, data, reply); reply->writeNoException(); reply->writeInt32(getNumberOfCameras(data.readInt32())); return NO_ERROR; } break; case CONNECT: { CHECK_INTERFACE(ICameraService, data, reply); sp cameraClient = interface_cast(data.readStrongBinder()); int32_t cameraId = data.readInt32(); const String16 clientName = data.readString16(); int32_t clientUid = data.readInt32(); sp camera; status_t status = connect(cameraClient, cameraId, clientName, clientUid, /*out*/camera); reply->writeNoException(); reply->writeInt32(status); if (camera != NULL) { reply->writeInt32(1); reply->writeStrongBinder(IInterface::asBinder(camera)); } else { reply->writeInt32(0); } return NO_ERROR; } break; ......}
Z:\workspace\MT3561\frameworks\av\services\camera\libcameraservice\CameraService.h
class MemoryHeapBase;class MediaPlayer;class CameraService : public BinderService, public BnCameraService, public IBinder::DeathRecipient, public camera_module_callbacks_t{ friend class BinderService;public: class Client; class BasicClient; ...... / // CameraClient functionality class BasicClient : public virtual RefBase { public: virtual status_t initialize(CameraModule *module) = 0; virtual void disconnect(); // because we can't virtually inherit IInterface, which breaks // virtual inheritance virtual sp asBinderWrapper() = 0; // Return the remote callback binder object (e.g. ICameraDeviceCallbacks) sp getRemote() { return mRemoteBinder; } ....... } class Client : public BnCamera, public BasicClient { public: typedef ICameraClient TCamCallbacks; // ICamera interface (see ICamera for details) virtual void disconnect(); virtual status_t connect(const sp& client) = 0; virtual status_t lock() = 0; virtual status_t unlock() = 0; virtual status_t setPreviewTarget(const sp& bufferProducer)=0; virtual void setPreviewCallbackFlag(int flag) = 0; virtual status_t setPreviewCallbackTarget( const sp& callbackProducer) = 0; ...... } /** * A listener class that implements the LISTENER interface for use with a ClientManager, and * implements the following methods: * void onClientRemoved(const ClientDescriptor& descriptor); * void onClientAdded(const ClientDescriptor& descriptor); */ class ClientEventListener { public: void onClientAdded(const resource_policy::ClientDescriptor>& descriptor); void onClientRemoved(const resource_policy::ClientDescriptor>& descriptor); }; // class ClientEventListener typedef std::shared_ptr>> DescriptorPtr; /** * A container class for managing active camera clients that are using HAL devices. Active * clients are represented by ClientDescriptor objects that contain strong pointers to the * actual BasicClient subclass binder interface implementation. * * This class manages the eviction behavior for the camera clients. See the parent class * implementation in utils/ClientManager for the specifics of this behavior. */ class CameraClientManager : public resource_policy::ClientManager, ClientEventListener> { public: CameraClientManager(); virtual ~CameraClientManager(); /** * Return a strong pointer to the active BasicClient for this camera ID, or an empty * if none exists. */ sp getCameraClient(const String8& id) const; /** * Return a string describing the current state. */ String8 toString() const; /** * Make a ClientDescriptor object wrapping the given BasicClient strong pointer. */ static DescriptorPtr makeClientDescriptor(const String8& key, const sp& value, int32_t cost, const std::set& conflictingKeys, int32_t priority, int32_t ownerId); /** * Make a ClientDescriptor object wrapping the given BasicClient strong pointer with * values intialized from a prior ClientDescriptor. */ static DescriptorPtr makeClientDescriptor(const sp& value, const CameraService::DescriptorPtr& partial); }; // class CameraClientManager .......}
Z:\workspace\MT3561\frameworks\av\services\camera\libcameraservice\CameraService.cpp
status_t CameraService::connect( const sp& cameraClient, int cameraId, const String16& clientPackageName, int clientUid, /*out*/ sp& device) { status_t ret = NO_ERROR; String8 id = String8::format("%d", cameraId); sp client = nullptr; ret = connectHelper(cameraClient, id, CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, API_1, false, false, /*out*/client); if(ret != NO_ERROR) { logRejected(id, getCallingPid(), String8(clientPackageName), String8::format("%s (%d)", strerror(-ret), ret)); return ret; } device = client; return NO_ERROR;}
templatestatus_t CameraService::connectHelper(const sp& cameraCb, const String8& cameraId, int halVersion, const String16& clientPackageName, int clientUid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly, /*out*/sp& device) { status_t ret = NO_ERROR; String8 clientName8(clientPackageName); int clientPid = getCallingPid(); ALOGI("CameraService::connectHelper call (PID %d \"%s\", camera ID %s) for HAL version %s and " "Camera API version %d", clientPid, clientName8.string(), cameraId.string(), (halVersion == -1) ? "default" : std::to_string(halVersion).c_str(), static_cast(effectiveApiLevel)); sp client = nullptr; { // Acquire mServiceLock and prevent other clients from connecting std::unique_ptr lock = AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS); if (lock == nullptr) { ALOGE("CameraService::connect X (PID %d) rejected (too many other clients connecting)." , clientPid); return -EBUSY; } // Enforce client permissions and do basic sanity checks if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) { return ret; } // Check the shim parameters after acquiring lock, if they have already been updated and // we were doing a shim update, return immediately if (shimUpdateOnly) { auto cameraState = getCameraState(cameraId); if (cameraState != nullptr) { if (!cameraState->getShimParams().isEmpty()) return NO_ERROR; } } sp clientTmp = nullptr; std::shared_ptr>> partial; if ((ret = handleEvictionsLocked(cameraId, clientPid, effectiveApiLevel, IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp, /*out*/&partial)) != NO_ERROR) { return ret; } if (clientTmp.get() != nullptr) { // Handle special case for API1 MediaRecorder where the existing client is returned device = static_cast(clientTmp.get()); return NO_ERROR; } // give flashlight a chance to close devices if necessary. mFlashlight->prepareDeviceOpen(cameraId); // TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDs int id = cameraIdToInt(cameraId); if (id == -1) { ALOGE("%s: Invalid camera ID %s, cannot get device version from HAL.", __FUNCTION__, cameraId.string()); return BAD_VALUE; } int facing = -1; int deviceVersion = getDeviceVersion(id, /*out*/&facing); sp tmp = nullptr; if((ret = makeClient(this, cameraCb, clientPackageName, cameraId, facing, clientPid, clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel, /*out*/&tmp)) != NO_ERROR) { return ret; } client = static_cast(tmp.get()); LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state", __FUNCTION__); #ifdef ATC_SUPPORT_CVBS_FORMAT_CHANGE int i4_cameraID = cameraIdToInt(cameraId);ALOGI("CameraService::connectHelper i4_cameraID=%d, getNumberOfCameras()=%d, mNeedUpdateCameraStaticInfo=%d", i4_cameraID, getNumberOfCameras(), mNeedUpdateCameraStaticInfo); //if( (getNumberOfCameras() == i4_cameraID)){ //lmk mark if(1){ // only do this for calling from apps which use cvbs-camera. // two apps which both use cvbs-camera should not work concurrently. /*do not use performance optimazation. setInitMode() is used for other purpose.*/ // // now we have sub-sensor (GM7150) and main sensor(imx135) on board. // according to onFirstRef() in this file // when only have GM7150 on board. mNumberOfNormalCameras = 0, camera id for GM7150 is 0; // when GM7150 and imx135 both on board, mNumberOfNormalCameras = 1, camera id for GM7150 is 1;mNeedUpdateCameraStaticInfo = 1; if(1 == mNeedUpdateCameraStaticInfo){ ALOGD("cvbs_switch:for cvbs camera (%d), trigger camera HAL staticInfo update",i4_cameraID); mModule->setInitMode(CAMERA_CMD_UPDATE_STATICINFO); mNeedUpdateCameraStaticInfo = 0; }else{ mModule->setInitMode(0); } } #else /**************************************************** if "media" open camera,means only for get parameter, we can cut some flow.for performance optimize >atc0113 *****************************************************/ String16 CallerName("media"); if(CallerName ==clientPackageName ) mModule->setInitMode(1); else mModule->setInitMode(0); #endif if ((ret = client->initialize(mModule)) != OK) { ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__); return ret; } //!++ The part is merged by MTK, google will merge in MR1 /* sp remoteCallback = client->getRemote(); if (remoteCallback != nullptr) { remoteCallback->linkToDeath(this); } */ //!-- // Update shim paremeters for legacy clients if (effectiveApiLevel == API_1) { // Assume we have always received a Client subclass for API1 // update CameraParameters here for legacy camera interface. sp shimClient = reinterpret_cast(client.get()); String8 rawParams = shimClient->getParameters(); CameraParameters params(rawParams); auto cameraState = getCameraState(cameraId); if (cameraState != nullptr) { cameraState->setShimParams(params); } else { ALOGE("%s: Cannot update shim parameters for camera %s, no such device exists.", __FUNCTION__, cameraId.string()); } } if (shimUpdateOnly) { // If only updating legacy shim parameters, immediately disconnect client ALOGD("shimUpdateOnly in"); mServiceLock.unlock(); client->disconnect(); mServiceLock.lock(); } else { // Otherwise, add client to active clients list finishConnectLocked(client, partial); } } // lock is destroyed, allow further connect calls // Important: release the mutex here so the client can call back into the service from its // destructor (can be at the end of the call) device = client; ALOGD("CameraService::connectHelper -"); return NO_ERROR;}
status_t CameraService::makeClient(const sp& cameraService, const sp& cameraCb, const String16& packageName, const String8& cameraId, int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel, /*out*/sp* client) { // TODO: Update CameraClients + HAL interface to use strings for Camera IDs int id = cameraIdToInt(cameraId); if (id == -1) { ALOGE("%s: Invalid camera ID %s, cannot convert to integer.", __FUNCTION__, cameraId.string()); return BAD_VALUE; } ALOGE("%s: Version -- %d, %d, %d.", __FUNCTION__, halVersion, deviceVersion, effectiveApiLevel); if (halVersion < 0 || halVersion == deviceVersion) { // Default path: HAL version is unspecified by caller, create CameraClient // based on device version reported by the HAL. switch(deviceVersion) { case CAMERA_DEVICE_API_VERSION_1_0: if (effectiveApiLevel == API_1) { // Camera1 API route sp tmp = static_cast(cameraCb.get()); *client = new CameraClient(cameraService, tmp, packageName, id, facing, clientPid, clientUid, getpid(), legacyMode); } else { // Camera2 API route ALOGW("Camera using old HAL version: %d", deviceVersion); return -EOPNOTSUPP; } break; case CAMERA_DEVICE_API_VERSION_2_0: case CAMERA_DEVICE_API_VERSION_2_1: case CAMERA_DEVICE_API_VERSION_3_0: case CAMERA_DEVICE_API_VERSION_3_1: case CAMERA_DEVICE_API_VERSION_3_2: case CAMERA_DEVICE_API_VERSION_3_3: if (effectiveApiLevel == API_1) { // Camera1 API route sp tmp = static_cast(cameraCb.get()); *client = new Camera2Client(cameraService, tmp, packageName, id, facing, clientPid, clientUid, servicePid, legacyMode); } else { // Camera2 API route sp tmp = static_cast(cameraCb.get()); *client = new CameraDeviceClient(cameraService, tmp, packageName, id, facing, clientPid, clientUid, servicePid); } break; default: // Should not be reachable ALOGE("Unknown camera device HAL version: %d", deviceVersion); return INVALID_OPERATION; } } else { // A particular HAL version is requested by caller. Create CameraClient // based on the requested HAL version. if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 && halVersion == CAMERA_DEVICE_API_VERSION_1_0) { // Only support higher HAL version device opened as HAL1.0 device. sp tmp = static_cast(cameraCb.get()); *client = new CameraClient(cameraService, tmp, packageName, id, facing, clientPid, clientUid, servicePid, legacyMode); } else { // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet. ALOGE("Invalid camera HAL version %x: HAL %x device can only be" " opened as HAL %x device", halVersion, deviceVersion, CAMERA_DEVICE_API_VERSION_1_0); return INVALID_OPERATION; } } return NO_ERROR;}
更多相关文章
- android文件缓存,并SD卡创建目录未能解决和bitmap内存溢出解决
- S5PV210 ANDROID 为摄像头增加闪光灯
- Android(安卓)使用RenderScript
- [转]Android进程管理
- 关于声明文件中android:process属性说明
- Android环境搭建
- 2、创建android应用程序
- 创建android文件系统(Root file system)
- android 7.0 系统关闭彩信过CTA测试的方法