Preview data ✿ Preview callback
Android Camera小系统:
嗯……直接看Camera HAL层,它实现是主要的工作, 它一般通过ioctl调用V4L2 command ①从linux kernel中的camera driver①得到preview数据. 然后交给surface(或overlay)显示或者保存为文件.在HAL层需要打开对应的设备文件,并通过ioctrl访问camera driver. Android通过这个HAL层来保证底层硬件(驱动)改变,只需修改对应的HAL层代码,FrameWork层与JAVA Ap的都不用改变.
注释:①V4L2(video 4 linux 2)
备注:①这个驱动并不是camera本身而是控制camera的主设备,这个camera控制器在linux里被抽象成为v4l2层通用,最后由(*attach)连接到具体每个不同的camera设备驱动里。camera=camera控制器+外接的camera sensor,控制器集成在cpu里,linux下的设备结点就是/dev/video0.
preview数据的显示过程:
简
单
概
括
为
|
Java app 呼叫 ② Jni ,Jni调用各种.so :
libandroid_runtime.so ---> libcamera_client.so ---> Binder IPC---> libcameraservice.so ---> libcamera.so
注释:②请原谅我用【呼叫】这个动词,实在想不出更加形象的词汇了。
|
详
细
说
明
|
1.打开linux kernel中的camera driver的设备文件,调用CameraHardwareInterface.h 中定义的openCameraHardware(),打开camera driver的设备文件(例如/dev/video0).
2.CameraHardwareInterface.h 中定义的 setParameters()函数,传参告诉camera HAL使用哪一个硬件摄像头,以及它工作的参数(size, format等等),并在HAL层分配存储preview数据的buffers(如果buffers是在linux kernel中的camera driver中分配的,并拿到这些buffers mmap后的地址指针).
3.如果不使用overlay那设置显示目标就在libcameraservice.so 中,不会进Camera HAL动态库.并将上一步拿到的preview数据buffers地址注册到surface中. 如果使用overlay那在libcameraservice.so 中会通过传进来的Isurface创建Overlay类的实例,然后调用CameraHardwareInterface.h 中定义的 setOverlay()设置到Camera HAL动态库中.
4.开始preview,调用到CameraHardwareInterface.h 中定义的 startPreview()函数.startPreviewMode会处理preview的显示介质,如果使用Overlay显示,会设置相应的Overlay,同时调用mHardware->startPreview()以启动preview;否则先调用mHardware->startPreview()启动preview,然后设置buffer:调用函数registerPreviewBuffers(),它会调用mHardware->getPreviewHeap(),从HAL层获得preview的buffer,将其设置给Surface去显示preview的结果。
|
Preview数据可以通过Overlay和Surface两种介质去显示
1、使用Overlay显示
overlay 一般用在 camera preview, 视频播放等需要高帧率的地方, 还有可能 UI 界面设计的需求,如 map 地图查看软件需两层显示信息. overlay需要硬件与驱动的支持.Overlay 没有 java 层的 code, 也就没有 JNI 调用. 一般都在 native 中使用.
如果要使用Overlay,底层硬件必须支持Overlay。在CameraService::Client的构造函数中,有相应的判断。
CameraService::Client::Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& cameraClient, pid_t clientPid){}
若mUseOverlay = mHardware->useOverlay();返回值为true,则表示硬件支持Overlay;否则只能使用Surface显示。
Android系统中提供了Overlay的接口,其具体实现需要自己做.
关于多层 overlay:例如需要同时支持 overlay1 与 overlay2.需在overlay hal 的 overlay_control_device_t 中要添加 overlay1 与 overlay2 的结构.如:
1
2
3
4
5
6
|
struct overlay_control_context_t {
struct overlay_control_device_t device;
/* our private state goes below here */
struct overlay_t* overlay_video1;//overlay1
struct overlay_t* overlay_video2;//overlay2
};
|
每个 overlay_t 代表一层 overlay, 每层 ovelay 有自己的 handle.可以使用自定义参数调用 overlay_control_device_t:: setParameter()来指明. Hal 层具体来实现,通过 Overlay object 来拿到 overlay1 与 overlay2 的 buffer 指针.
2、 使用Surface显示
如果使用Surface,会调用函数registerPreviewBuffers()向Surface注册buffers。
ISurface::BufferHeap buffers(w, h, w, h,
PIXEL_FORMAT_YCbCr_420_SP,
transform,
0,
mHardware->getPreviewHeap());
status_t ret = mSurface->registerBuffers(buffers);
其将mHardware的preview heap传递给了Surface。
关于Previewdata callback
上层Java中 调用setPreviewCallback,这个方法调用的是android_hardware_Camera_setHasPreviewCallback,最终实现落到 JNICameraContext::copyAndPost()身上。
void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType)
{
jbyteArray obj = NULL;
// allocate Java byte array and copy data
if (dataPtr != NULL) {
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size);
LOGV("postData: off=%d, size=%d", offset, size);
uint8_t *heapBase = (uint8_t*)heap->base();
if (heapBase != NULL) {
const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset);
obj = env->NewByteArray(size);
if (obj == NULL) {
LOGE("Couldn't allocate byte array for JPEG data");
env->ExceptionClear();
} else {
env->SetByteArrayRegion(obj, 0, size, data);
}
} else {
LOGE("image heap is NULL");
}
}
// post image data to Java
env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
mCameraJObjectWeak, msgType, 0, 0, obj);
if (obj) {
env->DeleteLocalRef(obj);
}
}
|
其中 obj = env->NewByteArray(size);每次都分配ByteArray .
按frame480×320 pixels计算 ,意味着230kb per call,然后花费大量的时间去释放这些资源。 为了优化preview大量数据的回调,有人提出引入:
static Mutex sPostDataLock; // A mutex that synchronizes calls to sCameraPreviewArrayGlobal
static jbyteArray sCameraPreviewArrayGlobal; // Buffer that is reused
static size_t sCameraPreviewArraySize=0; // Size of the buffer (or 0 if the buffer is not yet used)
|
为的是只申请一次空间,每帧重复使用ByteArray。
void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) {
if (dataPtr != NULL) {
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size);
LOGV("postData: off=%d, size=%d", offset, size);
uint8_t *heapBase = (uint8_t*)heap->base();
if (heapBase != NULL) {
const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset);
//HACK
if ((sCameraPreviewArraySize==0)
|| (sCameraPreviewArraySize!=size)) {
if(sCameraPreviewArraySize!=0) env->DeleteGlobalRef(sCameraPreviewArrayGlobal);
sCameraPreviewArraySize=size;
jbyteArray mCameraPreviewArray = env->NewByteArray(size);
sCameraPreviewArrayGlobal=(jbyteArray)env->NewGlobalRef(mCameraPreviewArray);
env->DeleteLocalRef(mCameraPreviewArray);
}
if (sCameraPreviewArrayGlobal == NULL) {
LOGE("Couldn't allocate byte array for JPEG data");
env->ExceptionClear();
} else {
env->SetByteArrayRegion(sCameraPreviewArrayGlobal, 0, size, data);
}
} else {
LOGE("image heap is NULL");
}
}
// post image data to Java
env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, msgType, 0, 0, sCameraPreviewArrayGlobal);
}
|
我又看了Android 2.3是 如何处理的
让我感叹,长远性的策略思考,和实践中的优化完善多么重要。如果我们平时写程序,仅仅是为了实现某某功能,解决某某BUG,那么真的实属下等了……
分享到:
相关推荐
完整的安卓摄像头获取preview视频帧APP工程代码,eclipse加载后即可运行。
use camera2 api show preview in surfaceview
Android5.0+ Camera Preview based-Gralloc with ION 自己生产的PDF文件
本篇文章主要介绍了Android camera实时预览 实时处理,面部认证示例,具有一定的参考价值,有兴趣的可以了解一下。
在具体实现代码之前,我们先来了解一下Android api对实现自定义Camera的介绍。 根据api的介绍,对于Camera应用可以简单总结以下几个步骤。 1.检查Camera是否存在,并在AndroidManifest.xml中赋予相关的权限; 2....
android camera demo; 在android 6.0,7.0上,就是有时会出现没有预览的情况。一般都是因为Camera已经打开,而View 还没有初始化完成。在楼主的Demo上,只需要把开启Camera的代码放到CameraTextureView中的...
1.打开就预览 2. button用于控制是开启preview callback并保存为jpg
Hello Camera2 is an Android Camera2 sample that plays preview. It controls camera devices by NDK camera2 APIs which becomes one of [public libraries]...
Basically this is a demo of how to hook in to the native camera preview screen and take a picture. The code doesn't do anything with the picture except display a AlertDialog. If you want, feel free to...
cameras attached to the device, display a camera preview, and take pictures. Introduction The Camera2 API provides an interface to individual camera devices connected to an Android device. It replaces...
Log.d(TAG, "Setting preview size: " + cameraResolution); parameters.setPreviewSize(cameraResolution.x, cameraResolution.y); parameters.setSceneMode(Camera.Parameters.SCENE_MODE_PORTRAIT); parameters....
android 简易camera相机,可以实现简单的拍照 & preview功能
Android Hidden Camera What is this library for? This library allows application to take the picture using the device camera without showing the preview of it. Any application can capture the image ...
基于android studio 2.2.2 gpufilter for camera preview and image edit
Android OpenGL Camera 2.0 项目使用 OpenGL ES 3.0 实现 30 种相机滤镜和特效,支持相机预览和拍照,左右滑动切换滤镜。 对 OpenGL ES 3.0 不熟悉的同学可以移步 音视频录制可以参考项目,该项目基于 FFmpeg 和 ...
android调用camera时,可以自己写一个activity,赋上相关参数,打开前camera就可以了; 需要申请的permission,在AndroidManifest.xml中添加: <uses-permission android:name="android.permission.CAMERA" /> ...
MTK8788 camera 调试手册
采用android5.0中Camera2 api+MVP模式开发的一个相机程序。 运行效果如下: 包含以下功能: 拍照 录像:单次录像,暂停与恢复录像。 模式设置:自动调焦,闪关灯,手动调焦, zoom调焦 采用的技术点: Camera2 API:...
:camera_with_flash: Android Camera2秘密拍照者(AC2SPT) 使用Android CAMERA2 API从所有可用的照相机中秘密地拍照(无需预览或启动设备的照相机应用程序)。 取代了不赞成使用的Camera类。 我如何支持这个项目?...