Android Camera Subsystem 架构(Binder机制)及显示分析(3) .
来源:互联网 发布:163邮箱端口设置 编辑:程序博客网 时间:2024/05/15 19:06
Camera Display
对于AP层用户,通过Camera界面, 以最直观的方式能够从Camera显示窗口中看到的Camera Display主要包括三部分。各部分的具体细节如下所示。
(1)Camera Preview Display
对于Camera Preview Display, 从Camera应用程序的角度来看,AP层需要实现Android.hardware.Camera(Framework层)类提供给上层应用的preview相关接口,完成相应的逻辑处理。但Preview作为大数据量交换的处理过程,系统不可能通过回调方式,最终将底层Camera硬件设备采集的数据交给AP层来处理。所以,上层应用只需要做一些简单的状态和UI显示处理,AP不需要接收处理真正的Preview数据,而是将数据接收和处理的过程交由ISurface接口来完成,确切的说是由ISurface的实现类SurfaceFlinger来完成。
AP层通过调用Android.hardware.Camera类提供的startPreview函数,最终通过libcamera_client.so的Camera类,利用Binder IPC,通知CameraService, CameraService通过调用其内部类Clien,内部类再通过调用HAL层提供的Camera功能完成相应的操作。
CameraService层针对Camera Client端得请求,都将交与其内部类Client来完成。CameraService层的startPreview的具体实现由CameraService::Client类的startPreviewMode函数完成相应的操作。
status_t CameraService::Client::startPreviewMode() {
// if preview has been enabled, nothing needs to be done
if (mHardware->previewEnabled()) {
return NO_ERROR;
}
// start preview mode
status_t ret = NO_ERROR;
if (mUseOverlay) {
….
} else {
mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
ret = mHardware->startPreview();
if (ret != NO_ERROR) return ret;
// If preview display has been set, register preview buffers now.
if (mSurface != 0) {
// Unregister here because the surface registered with raw heap.
mSurface->unregisterBuffers();
ret = registerPreviewBuffers();
}
}
return ret;
}
status_t CameraService::Client::registerPreviewBuffers()
{
int width, height;
CameraParameters params(mHardware->getParameters());
params.getPreviewSize(&width, &height);
// don't use a hardcoded format here
ISurface::BufferHeap buffers(width, height, width, height,
PIXEL_FORMAT_RGB_565,
mOrientation, 0,
mHardware->getPreviewHeap());
status_t ret = mSurface->registerBuffers(buffers);
if (ret != NO_ERROR) {
LOGE("registerBuffers failed with status %d", ret);
}
return ret;
}
从上面的代码我们可以看到,ISurface为Camera Preview Display专门注册了显示缓冲区,该缓冲区映射到mHardware->getPreviewHeap()指向的内存空间,缓冲区接收的数据格式为PIXEL_FORMAT_RGB_565。
CameraService已经为Camera Preview Display准备好了显示缓冲区,哪谁为注册的这块Buffer填充Preview数据呢?为了完成Camera Preview,Camera HAL层的CameraHardware类提供了previewThread线程,来完成底层数据到ISurface缓冲区的投递。通过线程Loop最终将Camera硬件设备采集的数据不断送到显示缓冲区,最后显示到AP界面上。
int CameraHardware::previewThread()
{
int width, height;
mParameters.getPreviewSize(&width, &height);
if (!previewStopped && mPreviewBuffer != 0 && mRawBuffer !=0 && mDataFn) {
int delay = (int)(1000000.0f / float(previewFrameRate));
①mCamera.GrabRawFrame(mHeap->getBase());
if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME){
②mCamera.GrabPreviewFrame((mHeap->getBase(),
mPreviewHeap->getBase());
③mDataFn(CAMERA_MSG_PREVIEW_FRAME,
mPreviewBuffer, mUser);
delay-=100;
}
………
}
return NO_ERROR;
}
从代码中我们可以看到,previewThread线程针对Preview Display,主要完成三个步骤的操作,
首先调用V4L2Camera的GrabRawFrame函数,通过V4L2驱动取得Camera采集的一帧数据,将该帧数据放到指定缓冲区中;
其次将取得的原始数据通过数据格式转化函数convert,将采集到得原始数据转化成与Preview Buffer注册类型相一致的数据类型,也就是RGB565。在我们的系统中,Camera hardware采集的原始数据时YUYV(YUV4:2:2)格式的。所以我们必须将YUYV格式的原始数据转化为RGB565格式的数据,然后放到PreviewBuffer中。
最后,通过回调函数,向CameraService发送Preview消息CAMERA_MSG_PREVIEW_FRAME,CameraService收到该消息之后调用Preview处理函数handlePreviewData,通过调用postBuffer函数,最终由SurfaceFlinger完成对PreviewBuffer的Draw工作。
void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {
ssize_t offset,size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
if (!mUseOverlay)
{
Mutex::Autolock surfaceLock(mSurfaceLock);
if (mSurface != NULL) {
mSurface->postBuffer(offset);
}
}
int flags = mPreviewCallbackFlag;
if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
LOGV("frame callback is diabled");
return;
}
……..
}
如上所示,HAL层将数据投递到framebuffer中,然后通知CameraService调用postBuffer对数据进行显示。Preview模式下,底层并不需要向上层AP通知自己的状态,所以postBuffer之后直接返回不再向上通知CAMERA_MSG_PREVIEW_FRAME消息。
在Preview模式下,通过ClickShutterButton,Camera由Previw模式进入TakePicture模式。在进入TakePicture模式之前,需要关闭Camera的预览功能,即停止Camera Preview Display。在TakePicture模式下,AP层首先会发送一个Focus请求,Focus请求会直接到达CameraHardware层,CameraHardware调用底层硬件提供的接口完成Focus功能。并通过回调函数notify,发送CAMERA_MSG_FOCUS消息,完成Focus,在完成Focus之前,系统并不会停止Preview Display,只有上层接到底层返回的FOCUS成功消息之后,才真正的进入TakePicture模式。在进入TakePicture之后,Camera主要完成三个功能。
int CameraHardware::pictureThread() {
int width, height;
if (mMsgEnabled & CAMERA_MSG_SHUTTER) {
①mNotifyFn(CAMERA_MSG_SHUTTER, 0, 0, mUser);
}
mParameters.getPictureSize(&width, &height);
②mCamera.GrabRawFrame(mHeap->getBase());
if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
②mCamera.convert((unsigned char *)mHeap->getBase(),
(uint8_t *)mRawHeap->getBase(), width, height);
②mDataFn(CAMERA_MSG_RAW_IMAGE, mRawBuffer,mUser);
}
if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
③mDataFn(CAMERA_MSG_COMPRESSED_IMAGE,
camera.GrabJpegFrame(mHeap->getBase()),mUser);
}
return NO_ERROR;
}
Step1:上层通过调用takepicture函数,最终通过Camera HAL层的CameraHardware启动captureThread线程,启动Capture线程之后,CameraHardware在第一时间会通过回调函数notify,向上发送CAMERA_MSG_SHUTTER消息给CameraService,同时CameraService将该消息返回给上层AP。
void CameraService::Client::handleShutter(image_rect_type *size) {
// Play shutter sound.
……
// Screen goes black after the buffer is unregistered.
if (mSurface != 0 && !mUseOverlay) {
mSurface->unregisterBuffers();
}
sp<ICameraClient> c = mCameraClient;
if (c != NULL) {
c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
}
mHardware->disableMsgType(CAMERA_MSG_SHUTTER);
if (mSurface != 0 && !mUseOverlay) {
int width, height;
CameraParameters params(mHardware->getParameters());
width = size->width;
height = size->height;
ISurface::BufferHeap buffers(width, height, width, height,
PIXEL_FORMAT_RGB_565,
mOrientation, 0, mHardware->getRawHeap());
mSurface->registerBuffers(buffers);
IPCThreadState::self()->flushCommands();
}
}
如上图所示,CameraService收到CAMERA_MSG_SHUTTER消息之后,首先通过回调函数,将该消息再转发给上层AP,然后根据Picture大小调用ISurface注册用于Capture Image Display的Capture Image Display Buffer。
Step2:CameraHardware开始真正的Capture Frame,首先调用底层GrabRawFrame函数获取Capture Image Frame,接下来要完成两件事:
一是将获取的原始Capture Frame数据转化为与显示缓冲区一直的数据格式,然后将转化后的数据投递到之前注册的Capture Image Display缓冲区中。
二是通过回调函数,向CameraService发送Capture Image Display消息CAMERA_MSG_RAW_IMAGE,CameraService收到该消息之后调用RawPicture处理函数handleRawPicture,通过调用postBuffer函数,最终由SurfaceFlinger完成对RawBuffer的Draw工作。
void CameraService::Client::handleRawPicture(const sp<IMemory>& mem)
{
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
// Put the YUV version of the snapshot in the preview display.
if (mSurface != 0 && !mUseOverlay) {
mSurface->postBuffer(offset);
}
sp<ICameraClient> c = mCameraClient;
if (c != NULL) {
c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
}
mHardware->disableMsgType(CAMERA_MSG_RAW_IMAGE);
}
private final class RawPictureCallback implements PictureCallback {
public void onPictureTaken(
byte [] rawData, Android.hardware.Camera camera) {
mRawPictureCallbackTime = System.currentTimeMillis();
}
}
与Preview消息不同的是,CameraService会将该消息继续发给上层AP,上层针对该消息会做一些简单的处理,主要是记录消息到达的系统时间。
Step3:获取JPEG Image,并存储JPEG Image,生成JPEG Image的缩略图显示在Camera窗口的右上角。在GrabRawFrame函数的基础上,我们需要将获取的原始数据转化成JPEG格式的数据,所以我们将之前GrabRawFrame获得的原始数据传给GrabJpegFrame(void * buffer)函数,返回满足要求的JPEG格式的数据。随后通过回调函数,向CameraService发送CAMERA_MSG_COMPRESSED_IMAGE消息,CameraService收到该消息之后调用JPEG Image处理函数handleCompressedPicture。
void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem)
{
sp<ICameraClient> c = mCameraClient;
if (c != NULL) {
c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
}
mHardware->disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
}
handleCompressedPicture和之前的处理函数不同,而是将消息和数据直接(其实是间接,还要通过Camera Client端,Camera JNI, Android.hardware.Camera)交给上层AP来处理。包括JPEG Image Storage和 Create Image Thumbnail。
在定义的延迟时间内,在Preview Layout中显示Capture image,之后通过调用restartPreview,恢复到Preview Mode状态下。
(3)VideoCamera Preview Display
当由Capture Preview状态切换到VideoPreview状态进入VideoCamera模式时,首先VideoCamera模式提供给用户的是Preview Display,这部分同Camera Preview Display。
int CameraHardware::previewThread()
{
mLock.lock();
int previewFrameRate = mParameters.getPreviewFrameRate();
mLock.unlock();
Mutex::Autolock lock(mPreviewLock);
if (!previewStopped && mPreviewBuffer != 0
&& mRawBuffer !=0 && mDataFn) {
int delay = (int)(1000000.0f / float(previewFrameRate));
①mCamera.GrabRawFrame(mHeap->getBase());
if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME){
②mCamera.GrabPreviewFrame(mHeap->getBase(),
mPreviewHeap->getBase());
③mDataFn(CAMERA_MSG_PREVIEW_FRAME,
mPreviewBuffer, mUser);
delay-=100;
}
①mRecordingLock.lock();
if ((mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)
&& mRecordBuffer != 0 && mTimestampFn) {
②mCamera.GrabRecordFrame(mHeap->getBase(),
mRecordHeap->getBase());
③nsecs_t timeStamp = systemTime(SYSTEM_TIME_MONOTONIC);
④mTimestampFn(timeStamp,
CAMERA_MSG_VIDEO_FRAME, mRecordBuffer, mUser);
delay-=100;
}
mRecordingLock.unlock();
usleep(delay);
}
return NO_ERROR;
}
在VideoCamera模式下,当用户通过ClickShutterButton进入Camera Recording状态时,用户看到的是Camera Recording Preview Display,从数据的显示过程同Camera Preview Display,但在此状态下,需要考虑到向Opencore框架,也就是CameraInput模块投递由Camera硬件采集的Record数据。CameraHardware不仅需要向Preview缓冲区投递数据,同时还要向CameraInput传送数据。如上图所示。
在Camera Recording状态下,libcamera_client.so端的回调函数(也就是CameraListener类定义的回调函数)不再由JNICameraContext类来实现,而是由AndroidCameraInputListener实现,换句话说,在CameraInput中的mListener成员变量是由AndroidCameraInputListener来初始化的。
Location:frameworks/base/include/camera/Camera.h
class CameraListener: virtual public RefBase
{
public:
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType,
const sp<IMemory>& dataPtr) = 0;
};
在整个Androi系统中,总共有三个类来分别实现这个抽象类,他们分别是JNICameraContext、AndroidCameraInputListener、CameraSourceListener类。
①Location:frameworks/base/core/jni/Android_hardware_Camera.cpp
class JNICameraContext: public CameraListener
②Location:external/opencore/Android/author/Android_camera_input.h
class AndroidCameraInputListener: public CameraListener
③Location:frameworks/base/core/jni/Android_hardware_Camera.cpp
class CameraSourceListener: public CameraListener
而具体实现上,由于CameraInput只需要带时间戳的数据,所以AndroidCameraInputListener只实现了postDataTimestamp回调函数。
void AndroidCameraInputListener::postDataTimestamp(nsecs_t timestamp,
int32_t msgType, const sp<IMemory>& dataPtr)
{
if ((mCameraInput != NULL)
&& (msgType == CAMERA_MSG_VIDEO_FRAME)) {
mCameraInput->postWriteAsync(timestamp, dataPtr);
}
}
根据Opencore框架中CameraInput中的实现,CameraInput可以作为CameraClient端得一个实例,通过Camera和CameraService架构实现包括预览,录像在内的所有功能。
但在目前的Camera子系统中,Camera Recording模式与Camera Capture模式共享同一个CameraDevice实例,Camera Recording的预览是通过使用Camera Capture模式下的Surface实现的,即Camera Recording通过调用Camera Capture中的setPreviewDisplay和底层CameraHardware层的previewThread线程实现Camera Recording预览。
- Android Camera Subsystem 架构(Binder机制)及显示分析
- Android Camera Subsystem 架构(Binder机制)及显示分析
- Android Camera Subsystem 架构(Binder机制)及显示分析
- Android Camera Subsystem 架构(Binder机制)及显示分析
- Android Camera Subsystem 架构(Binder机制)及显示分析(3)
- Android Camera Subsystem 架构(Binder机制)及显示分析(3) .
- Android Camera Subsystem 架构(Binder机制)及显示分析(1)
- Android Camera Subsystem 架构(Binder机制)及显示分析(2)
- Android Binder机制(1):Binder架构分析
- Android Binder 机制(3)
- 实例分析android中的Binder通信机制(3)
- Android Camera 系统架构源码分析(3)---->Camera的显示流程
- Android Camera 系统架构源码分析(3)---->Camera的显示流程
- Android Camera Subsystem - startPreview
- Android Binder机制分析
- Android Binder机制分析
- android binder机制之--(我是binder)
- android binder机制之--(我是binder)
- How to Determine if Two Words Are Anagrams of Each Other in C# (转)
- SQL语句求日期
- platform驱动之probe函数
- springmvc的url传参及后台接受参数
- !!!
- Android Camera Subsystem 架构(Binder机制)及显示分析(3) .
- linux学习(七) jar命令详解
- div中背景色的设置
- Android中第二次启动程序时,去除引导页
- SpringMVC中出现" 400 Bad Request "错误(用@ResponseBody处理ajax传过来的json数据转成bean)的解决方法
- ice版本resize 错误调试(Host key verification failed)
- SQL查询表中重复记录
- ANDROID 解析json数据
- ios 中生成随机数