android mtk camera startpreview,android8.1 mtk camera hal各种操作流程

最近一年,一直在做android上的视频编解码和录相、以及camera hal和系统框架这一块。随着做的慢慢的深入,越发觉得mtk的camera hal这一块,有其独到之处。偏偏网上相关的资料却是极少,对新入手的人而言,很难从上到下吃透。今天闲来无事,把最近一年来,对mtk camera hal层的理解,从上到下梳理了下。现在记录下来,希望能帮到更多的有志于mtk camera hal模块的人。

强调下,这篇博客,在自己理解的基础上,也大量参照了https://blog.csdn.net/luozirong/article/details/52244031这篇文章,有兴趣的,可以去参考一下。另外说明一下,我是家里抽了半天写的这篇文章,手头没有源代码,有些函数和文件,可能描述的不太准确,但大致思路是清晰的。

对mtk camera hal的分析,我是从open、display、preview、previewcallback、recorder、takepicture以及hal层的buff流转来着手的。虽然写的很简单,只是从上到下的调用堆栈,但是大伙只要顺着这几条线看下去,mtk camera hal 的pass2以及往上的部份,就都能理得明白了。大伙可以再配合我前几篇camera的文章来看,对mtk camera hal应该就有个比较好的把握了。好了,下面开讲了。

IImgBufProviderClient是用来管理IImgBufProvider,即让CamAdapter通过ImgBufProvidersManager管理DisplayClient的IImgBufProvider

这里的IImgBufProvider是我们DiaplayClient数据队列的管理者ImgBufQueue的父类。管理着mTodoImgBufQue和mDoneImgBufQue

上面说了ImgBufQueue继承了Provider和Process,并实现了他们的函数,其中Provider是提供给外部的类提出数据包和插入数据包,而Process是用来给内部整理和读取数据包。就如我们的DisplayClient的ImgBufQueue,DisplayClient内部生成和读取Buf通过Process系列函数,而DisplayClient把Provider系列函数提供给了CamAdapter操作数据包

CamAdapter管理了ImageSensor,ISP等硬件的初始化和调度,3A,数据的分配流向和处理等,虽然CamAdapter没有去执行Preview,Capture,Record等操作,但却管理到了他们的数据的来源和数据的动向,最后Camadapter里还包含了Buf manager和整个Camera的状态。例如在CamAdapter中Preview的管理就包括了PreviewCmdQueThread和PreviewBufMgr,PreviewCmdQueThread的线程里接收到通知后,从Sensor取数据并交由ISP处理,3A等处理后把Buf交给PreviewBufMgr进行分配到相应的操作。如果PreviewBufMgr收到的Buf需要显示,则通过ImgBufProvidersManager找到DisplayClient里的ImgBufQueue,再把Buf插入到队列里,由ImgBufQueue进行通知显示

camera的打开的过程:

1.) app上通过Camera.open(0);

2.)frameworks\base\core\java\android\hardware\Camera.java里open->cameraInitNormal(cameraId)->cameraInitVersion->native_setup

3.)frameworks\base\core\jni\android_hardware_Camera.cpp里android_hardware_Camera_native_setup

4.)frameworks\av\camera\CameraBase.cpp里connect

5.)frameworks\av\services\camera\libcameraservice\CameraService.cpp里的connectHelper

6.)CameraService::makeClient

7.)newCameraClient

8.)CameraClient::initialize

9.)newCameraHardwareInterface->initialize

10.)CameraHardwareInterface::initialize

11.)CameraDevice::open

12.)CameraDevice1Base::open->CameraDeviceManagerBase->startOpenDevice在这个open函数里还调用了initHalPreviewWindow();它主要是将app上传进来的surface,传给hal层。它的定义如下

void CameraDevice1Base::initHalPreviewWindow()

{

mHalPreviewWindow.cancel_buffer = sCancelBuffer;

mHalPreviewWindow.lock_buffer = sLockBuffer;

mHalPreviewWindow.dequeue_buffer = sDequeueBuffer;

mHalPreviewWindow.enqueue_buffer = sEnqueueBuffer;

mHalPreviewWindow.set_buffer_count = sSetBufferCount;

mHalPreviewWindow.set_buffers_geometry = sSetBuffersGeometry;

mHalPreviewWindow.set_crop = sSetCrop;

mHalPreviewWindow.set_timestamp = sSetTimestamp;

mHalPreviewWindow.set_usage = sSetUsage;

mHalPreviewWindow.set_swap_interval = sSetSwapInterval;

mHalPreviewWindow.get_min_undequeued_buffer_count =

sGetMinUndequeuedBufferCount;

}

camera设置preview窗口的过程

)app上调用camera.setPreviewDisplay(SurfaceHolder);

)frameworks/base/core/java/android/hardware/Camera.java里setPreviewDisplay

3.) Camera.java里setPreviewSurface(holder.getSurface());

4.)frameworks\base\core\jni\android_hardware_Camera.cpp里android_hardware_Camera_setPreviewSurface

5.) frameworks/av/camera/Camera.cpp里Camera::setPreviewTarget(constsp& bufferProducer)

6.)CameraClient::setPreviewTarget(constsp& bufferProducer)

7.)CameraClient::setPreviewWindow(constsp& binder,constsp& window)

8.)CameraHardwareInterface::setPreviewWindow(constsp& buf)

9.)CameraDevice.cpp::setPreviewWindow

10.)CameraDevice1Base.cpp::setPreviewWindow

11.)CameraDevice1Base.cpp::initDisplayClient

12.)DisplayClient::setWindow()

13.)DisplayClient:: set_preview_stream_ops() ----> mpStreamOps = window

预览的过程

)紧跟着上面一部份,在)CameraDevice1Base.cpp::initDisplayClient

)IDisplayClient::createInstance()

)DisplayClient::init()

)createDisplayThread()&& createImgBufQueue()

)cameraDevice1Base::enableDisplayClient()

)DisplayClient::enableDisplay()

)DisplayClient::enableDisplay()-

) mpDisplayThread-> postCommand(Command(Command::eID_WAKEUP))

)DisplayThread::threadLoop()

)DisplayClient::onThreadLoop()

)DisplayClient::waitAndHandleReturnBuffers

)rpBufQueue->dequeProcessor(vQueNode)

)DisplayClient::handleReturnBuffers()

)enquePrvOps()

)mpStreamOps->enqueue_buffer(mpStreamOps,rpImgBuf->getBufHndlPtr())(mpStreamOps这个就是app上传下来的surface)

如果把上面enqueue_buffer这一部份给删除,则预览界面无显示.所以总体来说是在DisplayClient的init的时候创建了一个线程:

mpDisplayThread =IDisplayThread::createInstance(this)

一个队列:

mpImgBufQueue = newImgBufQueue(IImgBufProvider::eID_DISPLAY, "CameraDisplay@ImgBufQue");

然后mpDisplayThread等待ImgBufQueue有数据的时候通过dequeProcessor取到要渲染的数据,交给mpStreamOps也就是preview_stream_ops对象,其实preview_stream_ops只是对ANativeWindow的简单封装,最后调用的其实是ANativeWindow的queueBuffer函数

录相的过程

)CameraClient::startRecordingMode

)CameraHardwareInterface::startRecording()

3.)vendor\mediatek\proprietary\hardware\mtkcam\main\hal\device\1.x\device\CameraDevice.cpp里

mpDevice->startRecording();

4.)CameraDevice1Base::startRecording()->mpCamClient->startRecording

5.)vendor\mediatek\proprietary\hardware\mtkcam\middleware\v1\client\CamClient\CamClient::startRecording()->mpRecordClient->startRecording()

6.)vendor\mediatek\proprietary\hardware\mtkcam\middleware\v1\client\CamClient\Record\RecordClient.cpp

RecordClient::startRecording()

7.)RecordClient::

onStateChanged()->postCommand(Command(Command::eID_WAKEUP));

8.)RecordClient.Thread.cpp里的

threadLoop()

9.)RecordClient.Thread.cpp里的onClientThreadLoop,prepareAllTodoBuffers->pBufQueue->startProcessor()->waitAndHandleReturnBuffers(pBufQueue, blocking)

在onClientThreadLoop函数里,通过prepareAllTodoBuffers去准备好接收收据的buff,prepareAllTodoBuffers的第一个参数就是在init里初始化的mpImgBufQueue, 在这里赋值给了pBufQueue,在prepareAllTodoBuffers里, 通过enqueProcessor将当前的帧放到了mpImgBufQueue 里。

再在onClientThreadLoop里, 调用pBufQueue->startProcessor() 去通知处理。      然后再通过waitAndHandleReturnBuffers去处理这些buff.这个函数里,通过rpBufQueue->dequeProcessor(vQueNode);来取刚刚得到的帧buff,最后丢给handleReturnBuffers处理理。     waitAndHandleReturnBuffers定义在vendor\mediatek\proprietary\hardware\mtkcam\middleware\v1\client\CamClient\Record\RecordClient.BufOps.cpp里.在waitAndHandleReturnBuffers中,通过rpBufQueue->dequeProcessor(vQueNode);,去获取当前帧,然后通过handleReturnBuffers去处理, 最后取到帧后,会丢给performRecordCallback去回调给app

IImgBufProvider的设置过程:

DisplayClient::enableDisplay ()---->DisplayClient::setImgBufProviderClient (mpCamAdapter)----> IImgBufProviderClient::onImgBufProviderCreated(mpImgBufQueue) ---->BaseCamAdapter::

onImgBufProviderCreated(spconst&rpProvider) ----> ImgBufProvidersManager::setProvider()

Camera的数据来源

DefaultCam1Device::onStartPreview()----> Cam1DeviceBase::initCameraAdapter() ----> CamAdapter::init() ---->IPreviewCmdQueThread::createInstance() ----> CamAdapter::startPreview() ---->StateIdle::onStartPreview() ----> CamAdapter::onHandleStartPreview() ---->mpPreviewCmdQueThread->postCommand(PrvCmdCookie::eUpdate, PrvCmdCookie::eSemBefore)----> PreviewCmdQueThread::threadLoop()----> PreviewCmdQueThread::update()----> PreviewCmdQueThread::updateOne() ----> PreviewBufMgr::enqueBuffer()----> IImgBufProvider:: enqueProvider()

5.Camera预览数据回调流程

用api1去预览,并且在app上通过setPreviewCallBack设置预览回调,想获取预览数据的流程如下:

)app调用Camera.java的startPreview, setPreviewCallback

)android_hardware_Camera.cpp里的android_hardware_Camera_startPreview

)Camera.cpp Camera::startPreview()

)CameraClient::startPreview()

)CameraClient::startCameraMode

)CameraClient::startPreviewMode()

)CameraHardwareInterface::startPreview

)CameraDevice::startPreview

{

//(1) 此函数在其子类DefaultCam1Device中实现

//仅是初始化了CameraAdapter

onStartPreview();

//(2) 初始化DisplayClient,重要,稍后研究

enableDisplayClient();

//(3)

mpCamClient->startPreview();

//(4) 我们通过(3)和(4)开始研究,再返回去看(1)(2)

mpCamAdapter->startPreview();

enableMsgType(CAMERA_MSG_PREVIEW_METADATA);

//

mIsPreviewEnabled= true;

}

)CamClient::startPreview()里的mpCamclient->startPreview()

)PreviewClient::startPreview(),这个里面会去调用initBuffers();

PreviewClient::startPreview()

{

//获得预览参数,这里参数为800*480,yuv420sp

ms8PrvTgtFmt=mpParamsMgr->getPreviewFormat();

mpParamsMgr->getPreviewSize(&mi4PrvWidth, &mi4PrvHeight);

//初始化预览Buf

initBuffers();

//

returnonStateChanged();

}

PreviewClient::initBuffers()

{

//预览数据的Buf

mpImgBufMgr= ImgBufManager::alloc(ms8PrvTgtFmt,mi4PrvWidth,

mi4PrvHeight,eMAX_PREVIEW_BUFFER_NUM,

"PreviewClientCb",mpCamMsgCbInfo->mRequestMemory,

0, 0);

//预览数据的处理类,这里只是保留了一个处理接口

//里面并没有什么东西,可自行填充

mpExtImgProc= ExtImgProc::createInstance();

mpExtImgProc->init();

}

PreviewClient::onStateChanged()

{ //发送了一个eID_WAKEUP的消息

postCommand(Command(Command::eID_WAKEUP));

}

//接收eID_WAKEUP消息

PreviewClient::threadLoop()

{

Commandcmd;

if (getCommand(cmd) )

{

switch (cmd.eId)

{

case Command::eID_WAKEUP:

case Command::eID_PREVIEW_FRAME:

case Command::eID_POSTVIEW_FRAME:

onClientThreadLoop(cmd);

break;

//

case Command::eID_EXIT:

//...

}

}

)PreviewClient::onClientThreadLoop开始处理数据Buf

)PreviewClient::waitAndHandleReturnBuffers(spconst&rpBufQueue)

)PreviewClient::handleReturnBuffers(Vectorconst& rvQueNode). 这个函数会调用到performPreviewCallback

)PreviewClient::performPreviewCallback(spconst& pCameraImgBuf, int32_t const msgType)。这个函数里,会调用到pCamMsgCbInfo->mDataCb函数。这个函数,就是在在CameraClient.cpp的initialize()函数里,通过mHardware->setCallbacks(notifyCallback, dataCallback, dataCallbackTimestamp, (void *)mCameraId);这句话其中的dataCallback,设置的mDataCb函数。也就是app上调用这句话其中的dataCallback,设置了mDataCb函数传下来的回调函数。这里会将数据传到app层上去。

6.拍照的流程:

CamAdapter::takePicture()-> IState::onCapture() ->IStateHandler::onHandleCapture() ->CamAdapter::onHandleCapture()CamAdapter::onHandleCapture() ->CaptureCmdQueThread::onCapture() -> CaptureCmdQueThread::threadLoop() ->CamAdapter::onCaptureThreadLoop()->CapBufShot::sendCommand()->CapBufShot::onCmd_capture()-> SingleShot::startOne()在这里组装IImgBuffer

7.拍照回调的流程:

SingleShot::startOne() --> CamShotImp::handleDataCallback() --> CamShotImp::onDataCallback--> CapBufShot::fgCamShotDataCb --> CapBufShot::handleJpegData  -->CamAdapter::onCB_RawImage -->mpCamMsgCbInfo->mDataCb

##注意两个两个标红的和标蓝的,他们这样就头尾对起来了。

1.所谓的Camera主要就是从摄像头取一点数据放到LCD上显示,所以打蛇打七寸,我们首先介绍HAL层的Window对象是mpStrwamOps。而这个对象被设置的流程是:

Cam1DeviceBase::setPreviewWindow()  --->  initDisplayClient()  ---> DisplayClient::setWindow()  ---> set_preview_stream_ops()  ---> mpStreamOps = window

2.另一个面我们看下数据的获取流程,Camera HAL层数据主要通过ImgBufQueue对象传递,而这个对象最开始的赋值过程如下:

CamAdapter::takePicture() -> IState::onCapture() ->IStateHandler::onHandleCapture() -> CamAdapter::onHandleCapture()CamAdapter::onHandleCapture() -> CaptureCmdQueThread::onCapture() -> CaptureCmdQueThread::threadLoop() -> CamAdapter::onCaptureThreadLoop()->CapBufShot::sendCommand()->CapBufShot::onCmd_capture() -> SingleShot::startOne()在这里组装IImgBuffer

8.)CamAdapter, pass1分发到pass2的过程

1.)我们从DefaultCam1Device.cpp开始看起,DefaultCam1Device::onStartPreview()

2.)Cam1DeviceBase::initCameraAdapter()

{

....

mpCamAdapter = ICamAdapter::createInstance(mDevName, mi4OpenId, mpParamsMgr);

....

// (.4) [DisplayClient] set Image Buffer Provider Client if needed.

mpDisplayClient->setImgBufProviderClient(mpCamAdapter);

// (.5) [CamClient] set Image Buffer Provider Client if needed.

mpCamClient->setImgBufProviderClient(mpCamAdapter);

}

3.)ICamAdapter::createInstance会调到MtkDefaultCamAdapter.cpp里的

CamAdapter::init()

{

//PreviewBufMgr

mpPreviewBufMgr = IPreviewBufMgr::createInstance(mpImgBufProvidersMgr);

//PreviewCmdQueThread,注意第一个参数为PreviewBufMgr

mpPreviewCmdQueThread = IPreviewCmdQueThread::createInstance(mpPreviewBufMgr, getOpenId(), mpParamsMgr);

mpPreviewCmdQueThread->run();

//CaptureCmdQueThread

mpCaptureCmdQueThread = ICaptureCmdQueThread::createInstance(this);

mpCaptureCmdQueThread->run();

//就是相机的3个Auto,自动曝光,自动对焦,自动白平衡

init3A();

}

4.)CamAdapter::startPreview()

5.)state.cpp里的StateIdle::onStartPreview(IStateHandler* pHandler)

6.)CamAdapter::onHandleStartPreview()里会调用”mpPreviewCmdQueThread->postCommand(PrvCmdCookie::eStart, PrvCmdCookie::eSemAfter); ”

7.)PreviewCmdQueThread.cpp PreviewCmdQueThread::threadLoop()

{

....

case PrvCmdCookie::eStart:

isvalid = start();

break;

....

}

8.)PreviewCmdQueThread::start()

{

....

for (int32_t i = 0; i < PASS1BUFCNT; i++)

{

//取出刚才创建的Buf

mspPreviewBufHandler->dequeBuffer(eID_Pass1Out, Pass1Node);

//获取bufinfo

mapNode2BufInfo(eID_Pass1Out, Pass1Node, BufInfo);

//收集bufinfo

vBufPass1Out.push_back(BufInfo);

}

......

预览

if (flag & eID_Pass2DISPO)

{

dispNode.getImgBuf()->setTimestamp(pass1LatestTimeStamp);

//通知Client的接收队列,进行接收处理

mspPreviewBufHandler->enqueBuffer(dispNode);

}

//录相

if (flag & eID_Pass2VIDO)

{

vidoNode.getImgBuf()->setTimestamp(pass1LatestTimeStamp);

mspPreviewBufHandler->enqueBuffer(vidoNode);

}

}

9.)PreviewBufMgr::enqueBuffer(ImgBufQueNode const& node)

{

....

//这里将从pass1取出来的数据分发给pass2

case eBuf_Disp:

{

//从Provider的队列中找到Id为eID_DISPLAY的Provider,

spbufProvider = mspImgBufProvidersMgr->getDisplayPvdr();

/**

在DisplayClient::waitAndHandleReturnBuffers()中,调用了ImgBufQueue.cpp dequeProcessor()

dequeProcessor()里mDoneImgBufQueCond.wait()会一直在等待。直到下面的函数被调用了

就会把buf传进去,并 mDoneImgBufQueCond.broadcast();通知接收buf

**/

bufProvider->enqueProvider(node);

}

break;

//...

case eBuf_Rec:

....

}

看到这里验证了我们之前的猜想,CamAdapter管理了ImageSensor,ISP等硬件的初始化和调度,3A,数据的分配流向和处理等,虽然CamAdapter没有去执行Preview,Capture,Record等操作,但却管理到了他们的数据的来源和数据的动向,最后Camdapter里还包含了Buf manager和整个Camera的状态。例如在CamAdapter中Preview的管理就包括了PreviewCmdQueThread和PreviewBufMgr,PreviewCmdQueThread的线程里接收到通知后,从Sensor取数据并交由ISP处理,3A等处理后把Buf交给PreviewBufMgr进行分配到相应的操作。如果PreviewBufMgr收到的Buf需要显示,则通过ImgBufProvidersManager找到DisplayClient里的ImgBufQueue,再把Buf插入到队列里,由ImgBufQueue进行通知显示

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 10 中,使用标准 Camera API 打开相机的流程与之前的版本略有不同。下面是在 Android 10 中使用标准 Camera API 打开相机的基本流程: 1. 添加权限 在 AndroidManifest.xml 文件中添加相机权限: ```xml <uses-permission android:name="android.permission.CAMERA" /> ``` 2. 创建预览布局 在您的 Activity 中添加一个 SurfaceView 作为相机预览的布局容器,例如: ```xml <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 请求权限 在 Android 10 中,您需要动态请求相机权限。首先,在您的 Activity 中检查相机权限是否已经被授予: ```java private static final int REQUEST_CAMERA_PERMISSION = 1; private boolean hasCameraPermission() { return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; } ``` 如果相机权限已经被授予,那么继续执行下面的步骤。否则,请求相机权限: ```java private void requestCameraPermission() { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } ``` 在 onRequestPermissionsResult() 回调方法中处理权限请求的结果: ```java @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CAMERA_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 相机权限已经被授予 openCamera(); } else { // 用户拒绝了相机权限请求 Toast.makeText(this, "Camera permission is required", Toast.LENGTH_SHORT).show(); finish(); } } } ``` 4. 创建相机实例 在您的 Activity 中创建相机实例并设置预览展示的 SurfaceView: ```java private Camera camera; private SurfaceView surfaceView; private void openCamera() { surfaceView = findViewById(R.id.surfaceView); // 打开相机 camera = Camera.open(); // 绑定预览视图 try { camera.setPreviewDisplay(surfaceView.getHolder()); } catch (IOException e) { e.printStackTrace(); } } ``` 5. 启动预览 调用 Camera.startPreview() 方法启动相机预览: ```java @Override protected void onResume() { super.onResume(); if (hasCameraPermission()) { // 启动预览 camera.startPreview(); } else { requestCameraPermission(); } } ``` 6. 释放相机资源 在 Activity 销毁时释放相机资源: ```java @Override protected void onDestroy() { super.onDestroy(); // 释放相机资源 camera.stopPreview(); camera.release(); camera = null; } ``` 以上就是在 Android 10 中使用标准 Camera API 打开相机的基本流程。需要注意的是,在 Android 10 中,您还需要在 AndroidManifest.xml 文件中添加以下属性: ```xml <uses-feature android:name="android.hardware.camera.any" android:required="true" /> ``` 这个属性表示您的应用程序需要至少一个相机,如果设备没有相机,您的应用程序将无法安装。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值