本博文是基于Android 4.4讲解

1、application 层:

当我们Android工程师想打开camera时通常直接调用Camera.java中的  Camer.open(cameraId)静态函数

camera.java 位于 frameworks/base/core/java/android/hardware目录下

//以下是部分代码

public static Camera open(int cameraId) {

return new Camera(cameraId);

}

Camera(int cameraId) {

mShutterCallback = null;

mRawImageCallback = null;

mJpegCallback = null;

mPreviewCallback = 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;

}

String packageName = ActivityThread.currentPackageName();

native_setup(new WeakReference(this), cameraId, packageName);

}

其中native_setup接口是native接口其函数声明如下

private native final void native_setup(Object camera_this, int cameraId,

String packageName);

2、jni层

在camera.java中会调用到native_setup函数,此jni接口定义在  frameworks/base/core/jni下面的android_hardware_Camera.cpp中

// connect to camera service

static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,

jobject weak_this, jint cameraId, jstring clientPackageName)

{

// Convert jstring to String16

const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);

jsize rawClientNameLen = env->GetStringLength(clientPackageName);

String16 clientName(rawClientName, rawClientNameLen);

env->ReleaseStringChars(clientPackageName, rawClientName);

sp camera = Camera::connect(cameraId, clientName,

Camera::USE_CALLING_UID);

if (camera == NULL) {

jniThrowRuntimeException(env, "Fail to connect to camera service");

return;

}

// make sure camera hardware is alive

if (camera->getStatus() != NO_ERROR) {

jniThrowRuntimeException(env, "Camera initialization failed");

return;

}

jclass clazz = env->GetObjectClass(thiz);

if (clazz == NULL) {

jniThrowRuntimeException(env, "Can't find android/hardware/Camera");

return;

}

// We use a weak reference so the Camera object can be garbage collected.

// The reference is only used as a proxy for callbacks.

sp context = new JNICameraContext(env, weak_this, clazz, camera);

context->incStrong((void*)android_hardware_Camera_native_setup);

camera->setListener(context);

// save context in opaque field

env->SetIntField(thiz, fields.context, (int)context.get());

}其中上面会调Camera::connect接口此类是frameworks/av/camera/Camera.cpp

sp Camera::connect(int cameraId, const String16& clientPackageName,

int clientUid)

{

return CameraBaseT::connect(cameraId, clientPackageName, clientUid);//调用了父类的connect接口

}frameworks/av/camera/CameraBase.cpp

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(); //得到CameraService.cpp实例

if (cs != 0) {

TCamConnectService fnConnectService = TCamTraits::fnConnectService;

status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,

/*out*/ c->mCamera); //此行最终会调用到CameraService.cpp中的connect接口

}

if (status == OK && c->mCamera != 0) {

c->mCamera->asBinder()->linkToDeath(c);

c->mStatus = NO_ERROR;

} else {

ALOGW("An error occurred while connecting to camera: %d", cameraId);

c.clear();

}

return c;

}frameworks/av/services/camera/libcameraservicw/CameraService.cpp

status_t CameraService::connect(

const sp& cameraClient,

int cameraId,

const String16& clientPackageName,

int clientUid,

/*out*/

sp& device) {

String8 clientName8(clientPackageName);

int callingPid = getCallingPid();

LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,

clientName8.string(), cameraId);

status_t status = validateConnect(cameraId, /*inout*/clientUid);

if (status != OK) {

return status;

}

sp client;

{

Mutex::Autolock lock(mServiceLock);

sp clientTmp;

if (!canConnectUnsafe(cameraId, clientPackageName,

cameraClient->asBinder(),

/*out*/clientTmp)) {

return -EBUSY;

} else if (client.get() != NULL) {

device = static_cast(clientTmp.get());

return OK;

}

int facing = -1;

int deviceVersion = getDeviceVersion(cameraId, &facing);

// If there are other non-exclusive users of the camera,

// this will tear them down before we can reuse the camera

if (isValidCameraId(cameraId)) {

// transition from PRESENT -> NOT_AVAILABLE

updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,

cameraId);

}

switch(deviceVersion) {

case CAMERA_DEVICE_API_VERSION_1_0:

client = new CameraClient(this, cameraClient,

clientPackageName, cameraId,

facing, callingPid, clientUid, getpid()); //我用的是camer1

break;

case CAMERA_DEVICE_API_VERSION_2_0:

case CAMERA_DEVICE_API_VERSION_2_1:

case CAMERA_DEVICE_API_VERSION_3_0:

client = new Camera2Client(this, cameraClient,

clientPackageName, cameraId,

facing, callingPid, clientUid, getpid(),

deviceVersion);

break;

case -1:

ALOGE("Invalid camera id %d", cameraId);

return BAD_VALUE;

default:

ALOGE("Unknown camera device HAL version: %d", deviceVersion);

return INVALID_OPERATION;

}

status_t status = connectFinishUnsafe(client, client->getRemote()); //见下面定义

if (status != OK) {

// this is probably not recoverable.. maybe the client can try again

// OK: we can only get here if we were originally in PRESENT state

updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);

return status;

}

mClient[cameraId] = client;

LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,

getpid());

}

// 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;

return OK;

}

status_t CameraService::connectFinishUnsafe(const sp& client,

const sp& remoteCallback) {

status_t status = client->initialize(mModule); //其中 camera_module_t *mModule为一个结构体指针,此指针会在onFirstRef()接口中初始化见下面代码

if (status != OK) {

return status;

}

remoteCallback->linkToDeath(this);

return OK;

}

//此接口会在CameraService实例化后调用,其中用到了sp机制,目前尚未研究通。

void CameraService::onFirstRef()

{

LOG1("CameraService::onFirstRef");

BnCameraService::onFirstRef();

if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,//此句代码是关键之处

(const hw_module_t **)&mModule) < 0) {

ALOGE("Could not load camera HAL module");

mNumberOfCameras = 0;

}

else {

ALOGI("Loaded \"%s\" camera module", mModule->common.name);

mNumberOfCameras = mModule->get_number_of_cameras();

if (mNumberOfCameras > MAX_CAMERAS) {

ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",

mNumberOfCameras, MAX_CAMERAS);

mNumberOfCameras = MAX_CAMERAS;

}

for (int i = 0; i < mNumberOfCameras; i++) {

setCameraFree(i);

}

if (mModule->common.module_api_version >=

CAMERA_MODULE_API_VERSION_2_1) {

mModule->set_callbacks(this);

}

CameraDeviceFactory::registerService(this);

}

}

hw_get_module位于Android源码目录下  hardware/libhardware/Hardware.cint hw_get_module(const char *id, const struct hw_module_t **module)

{

return hw_get_module_by_class(id, NULL, module);

}//此函数会加载动态库"/system/lib/hw"下面有名字为class_id的动态库int hw_get_module_by_class(const char *class_id, const char *inst,

const struct hw_module_t **module)

{

int status;

int i;

const struct hw_module_t *hmi = NULL;

char prop[PATH_MAX];

char path[PATH_MAX];

char name[PATH_MAX];

if (inst)

snprintf(name, PATH_MAX, "%s.%s", class_id, inst);

else

strlcpy(name, class_id, PATH_MAX);

/*

* Here we rely on the fact that calling dlopen multiple times on

* the same .so will simply increment a refcount (and not load

* a new copy of the library).

* We also assume that dlopen() is thread-safe.

*/

/* Loop through the configuration variants looking for a module */

for (i=0 ; i

if (i < HAL_VARIANT_KEYS_COUNT) {

if (property_get(variant_keys[i], prop, NULL) == 0) {

continue;

}

snprintf(path, sizeof(path), "%s/%s.%s.so",

HAL_LIBRARY_PATH2, name, prop); // PATH2: "/vendor/lib/hw"

if (access(path, R_OK) == 0) break;

snprintf(path, sizeof(path), "%s/%s.%s.so",

HAL_LIBRARY_PATH1, name, prop); //PATH1: "/system/lib/hw"

if (access(path, R_OK) == 0) break;

} else {

snprintf(path, sizeof(path), "%s/%s.default.so",

HAL_LIBRARY_PATH2, name);

if (access(path, R_OK) == 0) break;

snprintf(path, sizeof(path), "%s/%s.default.so",

HAL_LIBRARY_PATH1, name);

if (access(path, R_OK) == 0) break;

}

}

status = -ENOENT;

if (i < HAL_VARIANT_KEYS_COUNT+1) {

/* load the module, if this fails, we're doomed, and we should not try

* to load a different variant. */

status = load(class_id, path, module);

}

return status;

}

//static int load(const char *id,

const char *path,

const struct hw_module_t **pHmi)

{

int status;

void *handle;

struct hw_module_t *hmi;

/*

* load the symbols resolving undefined symbols before

* dlopen returns. Since RTLD_GLOBAL is not or'd in with

* RTLD_NOW the external symbols will not be global

*/

handle = dlopen(path, RTLD_NOW);

if (handle == NULL) {

char const *err_str = dlerror();

ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");

status = -EINVAL;

goto done;

}

/* Get the address of the struct hal_module_info. */

const char *sym = HAL_MODULE_INFO_SYM_AS_STR; //HAL_MODULE_INFO_SYM_AS_STR 为 "HMI"//dlsym根据sym去实例化hmi,其中Camera_Moduel.cpp下有"HMI"名字的camera_module_t变量,见下面代码

hmi = (struct hw_module_t *)dlsym(handle, sym);

if (hmi == NULL) {

ALOGE("load: couldn't find symbol %s", sym);

status = -EINVAL;

goto done;

}

/* Check that the id matches */

if (strcmp(id, hmi->id) != 0) {

ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);

status = -EINVAL;

goto done;

}

hmi->dso = handle;

/* success */

status = 0;

done:

if (status != 0) {

hmi = NULL;

if (handle != NULL) {

dlclose(handle);

handle = NULL;

}

} else {

ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",

id, path, *pHmi, handle);

}

*pHmi = hmi;

return status;

}

CameraHal_Module.cpp   //此类位于hardware/rk29/camera/camerahal目录下,这是我的源代码camera模块

camera_module_t HAL_MODULE_INFO_SYM = {

common: {

tag: HARDWARE_MODULE_TAG,

version_major: ((CONFIG_CAMERAHAL_VERSION&0xff00)>>8),

version_minor: CONFIG_CAMERAHAL_VERSION&0xff,

id: CAMERA_HARDWARE_MODULE_ID,

name: CAMERA_MODULE_NAME,

author: "RockChip",

methods: &camera_module_methods,

dso: NULL, /* remove compilation warnings */

reserved: {0}, /* remove compilation warnings */

},

get_number_of_cameras: camera_get_number_of_cameras,

get_camera_info: camera_get_camera_info,

set_callbacks:NULL,

get_vendor_tag_ops:NULL,

reserved: {0}

};

到此frameworks/av/services/camera/libcameraservicw/CameraService.cpp下的mModule实例化完成

我们在进入到CameraClient.cpp(frameworks/av/services/camera/libcameraservice/api1)中(上面的CameraService.cpp实例化了CameraClient并且调用了它内部的initialize(camera_module_t *module)接口)

status_t CameraClient::initialize(camera_module_t *module) {

int callingPid = getCallingPid();

status_t res;

LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);

// Verify ops permissions

res = startCameraOps();

if (res != OK) {

return res;

}

char camera_device_name[10];

snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);

mHardware = new CameraHardwareInterface(camera_device_name);

res = mHardware->initialize(&module->common);

if (res != OK) {

ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",

__FUNCTION__, mCameraId, strerror(-res), res);

mHardware.clear();

return NO_INIT;

}

mHardware->setCallbacks(notifyCallback,

dataCallback,

dataCallbackTimestamp,

(void *)mCameraId);

// Enable zoom, error, focus, and metadata messages by default

enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |

CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);

LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);

return OK;

}

CameraHardwareInterface.h位于 frameworks/av/services/camera/libcameraservice/device1

status_t initialize(hw_module_t *module)

{

ALOGI("Opening camera %s", mName.string());

int rc = module->methods->open(module, mName.string(),

(hw_device_t **)&mDevice); //调用了上面CameraHal_Module.cpp下的camera_module_t HAL_MODULE_INFO_SYM的open函数,此函数定义见下面代码

if (rc != OK) {

ALOGE("Could not open camera %s: %d", mName.string(), rc);

return rc;

}

initHalPreviewWindow();

return rc;

}

static struct hw_module_methods_t camera_module_methods = {

open: camera_device_open

};int camera_device_open(const hw_module_t* module, const char* name,

hw_device_t** device)

{

int rv = 0;

int cameraid;

rk_camera_device_t* camera_device = NULL;

camera_device_ops_t* camera_ops = NULL;

android::CameraHal* camera = NULL;

android::Mutex::Autolock lock(gCameraHalDeviceLock);

LOGI("camera_device open");

if (name != NULL) {

cameraid = atoi(name);

if(cameraid > gCamerasNumber) {

LOGE("camera service provided cameraid out of bounds, "

"cameraid = %d, num supported = %d",

cameraid, gCamerasNumber);

rv = -EINVAL;

goto fail;

}

if(gCamerasOpen >= CAMERAS_SUPPORTED_SIMUL_MAX) {

LOGE("maximum number(%d) of cameras already open",gCamerasOpen);

rv = -ENOMEM;

goto fail;

}

camera_device = (rk_camera_device_t*)malloc(sizeof(*camera_device));

if(!camera_device) {

LOGE("camera_device allocation fail");

rv = -ENOMEM;

goto fail;

}

camera_ops = (camera_device_ops_t*)malloc(sizeof(*camera_ops));

if(!camera_ops) {

LOGE("camera_ops allocation fail");

rv = -ENOMEM;

goto fail;

}

memset(camera_device, 0, sizeof(*camera_device));

memset(camera_ops, 0, sizeof(*camera_ops));

camera_device->base.common.tag = HARDWARE_DEVICE_TAG;

camera_device->base.common.version = 0;

camera_device->base.common.module = (hw_module_t *)(module);

camera_device->base.common.close = camera_device_close;

camera_device->base.ops = camera_ops;

camera_ops->set_preview_window = camera_set_preview_window;

camera_ops->set_callbacks = camera_set_callbacks;

camera_ops->enable_msg_type = camera_enable_msg_type;

camera_ops->disable_msg_type = camera_disable_msg_type;

camera_ops->msg_type_enabled = camera_msg_type_enabled;

camera_ops->start_preview = camera_start_preview;

camera_ops->stop_preview = camera_stop_preview;

camera_ops->preview_enabled = camera_preview_enabled;

camera_ops->store_meta_data_in_buffers = camera_store_meta_data_in_buffers;

camera_ops->start_recording = camera_start_recording;

camera_ops->stop_recording = camera_stop_recording;

camera_ops->recording_enabled = camera_recording_enabled;

camera_ops->release_recording_frame = camera_release_recording_frame;

camera_ops->auto_focus = camera_auto_focus;

camera_ops->cancel_auto_focus = camera_cancel_auto_focus;

camera_ops->take_picture = camera_take_picture;

camera_ops->cancel_picture = camera_cancel_picture;

camera_ops->set_parameters = camera_set_parameters;

camera_ops->get_parameters = camera_get_parameters;

camera_ops->put_parameters = camera_put_parameters;

camera_ops->send_command = camera_send_command;

camera_ops->release = camera_release;

camera_ops->dump = camera_dump;

*device = &camera_device->base.common;

// -------- RockChip specific stuff --------

camera_device->cameraid = cameraid;

camera = new android::CameraHal(cameraid); //进入hal层

if(!camera) {

LOGE("Couldn't create instance of CameraHal class");

rv = -ENOMEM;

goto fail;

}

gCameraHals[cameraid] = camera;

gCamerasOpen++;

}

return rv;

fail:

if(camera_device) {

free(camera_device);

camera_device = NULL;

}

if(camera_ops) {

free(camera_ops);

camera_ops = NULL;

}

if(camera) {

delete camera;

camera = NULL;

}

*device = NULL;

return rv;

}

3、hal层

hardware/rk29/camera/camerahal/CameraHal.cpp

//以下会根据camera硬件分类uvc soc isp等,实例化成对应的adapter.cpp(数据适配器,此类会调用iotrl系统接口和驱动层进行通信)CameraHal::CameraHal(int cameraId)

:commandThreadCommandQ("commandCmdQ")

{

LOG_FUNCTION_NAME

{

char trace_level[PROPERTY_VALUE_MAX];

int level;

property_get(CAMERAHAL_TRACE_LEVEL_PROPERTY_KEY, trace_level, "0");

sscanf(trace_level,"%d",&level);

setTracerLevel(level);

}

mCamId = cameraId;

mCamFd = -1;

mCommandRunning = -1;

mCameraStatus = 0;

#if (CONFIG_CAMERA_MEM == CAMERA_MEM_ION)

mCamMemManager = new IonMemManager();

LOG1("%s(%d): Camera Hal memory is alloced from ION device",__FUNCTION__,__LINE__);

#elif(CONFIG_CAMERA_MEM == CAMERA_MEM_IONDMA)

if((strcmp(gCamInfos[cameraId].driver,"uvcvideo") == 0) //uvc camera

|| (gCamInfos[cameraId].pcam_total_info->mHardInfo.mSensorInfo.mPhy.type == CamSys_Phy_end)// soc cif

) {

gCamInfos[cameraId].pcam_total_info->mIsIommuEnabled = (IOMMU_ENABLED == 1)? true:false;

}

mCamMemManager = new IonDmaMemManager(gCamInfos[cameraId].pcam_total_info->mIsIommuEnabled);

LOG1("%s(%d): Camera Hal memory is alloced from ION device",__FUNCTION__,__LINE__);

#elif(CONFIG_CAMERA_MEM == CAMERA_MEM_PMEM)

if(access(CAMERA_PMEM_NAME, O_RDWR) < 0) {

LOGE("%s(%d): %s isn't registered, CameraHal_Mem current configuration isn't support ION memory!!!",

__FUNCTION__,__LINE__,CAMERA_PMEM_NAME);

} else {

mCamMemManager = new PmemManager((char*)CAMERA_PMEM_NAME);

LOG1("%s(%d): Camera Hal memory is alloced from %s device",__FUNCTION__,__LINE__,CAMERA_PMEM_NAME);

}

#endif

mPreviewBuf = new PreviewBufferProvider(mCamMemManager);

mVideoBuf = new BufferProvider(mCamMemManager);

mRawBuf = new BufferProvider(mCamMemManager);

mJpegBuf = new BufferProvider(mCamMemManager);

char value[PROPERTY_VALUE_MAX];

property_get(/*CAMERAHAL_TYPE_PROPERTY_KEY*/"sys.cam_hal.type", value, "none");

if (!strcmp(value, "fakecamera")) {

LOGD("it is a fake camera!");

mCameraAdapter = new CameraFakeAdapter(cameraId);

} else {

if((strcmp(gCamInfos[cameraId].driver,"uvcvideo") == 0)) {

LOGD("it is a uvc camera!");

mCameraAdapter = new CameraUSBAdapter(cameraId);

}

else if(gCamInfos[cameraId].pcam_total_info->mHardInfo.mSensorInfo.mPhy.type == CamSys_Phy_Cif){

LOGD("it is a isp soc camera");

if(gCamInfos[cameraId].pcam_total_info->mHardInfo.mSensorInfo.mPhy.info.cif.fmt == CamSys_Fmt_Raw_10b)

mCameraAdapter = new CameraIspSOCAdapter(cameraId);

else

mCameraAdapter = new CameraIspAdapter(cameraId);

}

else if(gCamInfos[cameraId].pcam_total_info->mHardInfo.mSensorInfo.mPhy.type == CamSys_Phy_Mipi){

LOGD("it is a isp camera");

mCameraAdapter = new CameraIspAdapter(cameraId);

}

else{

LOGD("it is a soc camera!");

mCameraAdapter = new CameraSOCAdapter(cameraId);

}

}

//initialize

{

char *call_process = getCallingProcess();

if(strstr(call_process,"com.android.cts.verifier")) {

mCameraAdapter->setImageAllFov(true);

} else {

mCameraAdapter->setImageAllFov(false);

}

}

mDisplayAdapter = new DisplayAdapter();

mEventNotifier = new AppMsgNotifier(mCameraAdapter);

mCameraAdapter->setEventNotifierRef(*mEventNotifier);

mCameraAdapter->initialize();

updateParameters(mParameters);

mCameraAdapter->setPreviewBufProvider(mPreviewBuf);

mCameraAdapter->setDisplayAdapterRef(*mDisplayAdapter);

mDisplayAdapter->setFrameProvider(mCameraAdapter);

mEventNotifier->setPictureRawBufProvider(mRawBuf);

mEventNotifier->setPictureJpegBufProvider(mJpegBuf);

mEventNotifier->setVideoBufProvider(mVideoBuf);

mEventNotifier->setFrameProvider(mCameraAdapter);

//command thread

mCommandThread = new CommandThread(this);

mCommandThread->run("CameraCmdThread", ANDROID_PRIORITY_URGENT_DISPLAY);

bool dataCbFrontMirror;

bool dataCbFrontFlip;

#if CONFIG_CAMERA_FRONT_MIRROR_MDATACB

if (gCamInfos[cameraId].facing_info.facing == CAMERA_FACING_FRONT) {

#if CONFIG_CAMERA_FRONT_MIRROR_MDATACB_ALL

dataCbFrontMirror = true;

#else

const char* cameraCallProcess = getCallingProcess();

if (strstr(CONFIG_CAMERA_FRONT_MIRROR_MDATACB_APK,cameraCallProcess)) {

dataCbFrontMirror = true;

} else {

dataCbFrontMirror = false;

}

if (strstr(CONFIG_CAMERA_FRONT_FLIP_MDATACB_APK,cameraCallProcess)) {

dataCbFrontFlip = true;

} else {

dataCbFrontFlip = false;

}

#endif

} else {

dataCbFrontMirror = false;

dataCbFrontFlip = false;

}

#else

dataCbFrontMirror = false;

#endif

mEventNotifier->setDatacbFrontMirrorFlipState(dataCbFrontMirror,dataCbFrontFlip);

// register for sensor events

mSensorListener = new SensorListener();

if (mSensorListener.get()) {

if (mSensorListener->initialize() == NO_ERROR) {

mSensorListener->setCallbacks(gsensor_orientation_cb, this);

mSensorListener->enableSensor(SensorListener::SENSOR_ORIENTATION);

} else {

LOGE("Error initializing SensorListener. not fatal, continuing");

mSensorListener.clear();

mSensorListener = NULL;

}

}

LOG_FUNCTION_NAME_EXIT

}

android camera工程师,浅析Android Camera架构相关推荐

  1. android 动画 alpha,浅析Android 动画之AlphaAnimation应用操作

    作为程序员不管是为了什么,或多或少都会模仿其他人的一些手法来达到效果,程序员都必须要做出各种绚丽的动画画面来吸引大家,下面是爱站技术频道小编浅析 动画之AlphaAnimation应用操作,一起来了解 ...

  2. Android笔记:浅析Android电视APP开发

    TV应用程序使用相同的结构与手机和平板电脑.这种相似性意味着你也可以修改现有的应用程序运行在TV设备或创建新的应用程序基于你现在已经掌握的Android技术开发应用. 1.创建Android TV工程 ...

  3. 2012年全国最新Android开发工程师薪资水平调查分析

    为什么80%的码农都做不了架构师?>>>    2012年全国最新Android开发工程师薪资水平调查分析 最近几年,随着Android的飞速发展,伴随着巨大的产业需求,国内Andr ...

  4. android要学什么,android入门要学什么 应该做哪些学习准备

    当今现实生活中,随着移动互联网飞速发展,还真是没有一门专业的技术无法生存,比如说互联网IT行业中的android大家应该都不陌生吧,市场上的android开发人才是相当匮乏的,那么作为准android ...

  5. 【Android】Camera 使用浅析

    Camera的简单使用浅析 由于最近工作上用到android.hardware.Camera这个类,于是简单的学习了一些基本用法.  首先注意:Camera这个类在API21以后就不推荐使用了,官方提 ...

  6. Android Camera简单整理(一)-Camera Android架构(基于Q)

    Camera整体架构简单整理 一.Android Camera整体架构简述 1.1 Android Camera 基本分层 1.2 Android Camera工作大体流程 二. Camera App ...

  7. Android 10 Camera学习笔记:Camera Framework架构

    CameraFramework架构 又是很久没有写了,这几天一直在看camera framework相关源码,于是乎整理出了这个架构图.Camera API2比较好整理,反而是Camera API1花 ...

  8. 【高通SDM660平台 Android 10.0】(14) --- Camera ISP

    [高通SDM660平台 Android 10.0]--- Camera ISP 一.Camera ISP 与 DSP 区别 1.1 名词解释 1.2 功能解释 1.3 手机摄像头ISP是独立好还是内置 ...

  9. android camera 工作原理,Android Camera原理之openCamera模块(一)

    我们平时开发,知道怎么调度api,怎么调起camera,怎么调用camera的实例来操作camera就可以了,但是这些调度的背后都做了什么事情,我们可能不太清楚,本文打算从openCamera这个调用 ...

最新文章

  1. Git 删除已经提交的文件(Delete commits from a branch in Git)
  2. Indy接收邮件可能会出现的一个Bug
  3. 【转载】一行代码加载网络图片到ImageView——Android Picasso
  4. Ethernet/IP 学习笔记四
  5. java之七 高级类设计
  6. decimal转换为int_“System.InvalidCastException 指定的转换无效”问题的反思和总结
  7. ERP和SAP是什么意思
  8. git tracked branch
  9. 你无法访问计算机,计算机无法访问,您可能没有权限使用网络资源.请与这台服务器的管理员联系的解决办法...
  10. 汉字机内码简介及转换工具
  11. springboot之微信支付与退款
  12. 音频文件(.wav)解析读取
  13. 小程序开发之瀑布流布局
  14. 7-14 电话聊天狂人 (25分) 【map】
  15. 使用fairseq从头开始训练一个中英神经机器翻译模型
  16. 不同VLAN下实现网络互相通信(配置port trunk pvid vlan进行数据转发)
  17. PHP cURL学习-域名备案查询
  18. zxing白边java_ZXing生成无白边条形码
  19. 34年为爱奔赴,这位退休老师荣获“新时代的贵州省人”称号
  20. 什么在阻挡互联网应用“称王”

热门文章

  1. python计算机视觉常见报错及解决方案(不断更新中)
  2. 单文件浏览器_图文并茂深度解析浏览器渲染原理,包看懂超值得收藏
  3. PRT(Precomputed Radiance Transfer)球谐光照(Spherical Harmonic Lighting)
  4. C4D和Redshift:2D矢量到三维渲染 Cinema 4D and Redshift: 2D vector to 3D render
  5. 3D游戏设计和创作工具学习教程 3D Game Design Creation Tools
  6. Oracle数据库基本操作(二) —— 视图、序列、索引、同义词
  7. 性能测试之二——常用的性能测试策略
  8. Splunk学习与实践
  9. 源码-0205-02--聊天布局
  10. 批量修改图片以及加水印