Preview的显示流程
这次我们要从最开始startPreview的时候开始,在starPreview之间就setPreviewWindow()。
//CameraClient.cpp
status_t CameraClient::startPreviewMode() {
mHardware->previewEnabled();
mHardware->setPreviewWindow(mPreviewWindow);
result = mHardware->startPreview();
}
最后会调用到Cam1DeviceBase的setPreviewWindow(),其中的调用过程和startPreview()的一样,不再赘述
Cam1DeviceBase::setPreviewWindow(preview_stream_ops* window)
{
//(1) 初始化显示
status_t status = initDisplayClient(window);
//(2) 开始显示
status = enableDisplayClient();
}
initDisplayClient(); 在之前说的Cam1DeviceBase::startPreview()的(2)也调用 了
initDisplayClient();
Cam1DeviceBase::initDisplayClient(preview_stream_ops* window)
{
Size previewSize;
// [1] Check to see whether the passed window is NULL or not.
//...
// [2] Get preview size. 获得预览参数
queryPreviewSize(previewSize.width, previewSize.height);
// [3] Initialize Display Client.
// [3.1] create a Display Client. 仅是初始化变量
mpDisplayClient = IDisplayClient::createInstance();
// [3.2] initialize the newly-created Display Client.
mpDisplayClient->init();
// [3.3] set preview_stream_ops & related window info.
mpDisplayClient->setWindow(window, previewSize.width, previewSize.height, queryDisplayBufCount());
// [3.4] set Image Buffer Provider Client if it exist.
mpCamAdapter != 0 && ! mpDisplayClient->setImgBufProviderClient(mpCamAdapter);
}
下面是
initDisplayClient();的细节分析
DisplayClient::init()
{
/**
构造DisplayThread并让它run起来,注意构造时传入的handle参数为dispalyClient
构造ImgBufQueue,它的id为eID_DISPLAY
在previewClient init()时,也创建了一个ImgBufQueue,而ID是eID_PRV_CB
**/
ret = createDisplayThread() && createImgBufQueue();
}
DisplayClient::setWindow(preview_stream_ops*const window, int32_t const wndWidth,
int32_t const wndHeight, int32_t const i4MaxImgBufCount)
{ return set_preview_stream_ops(window, wndWidth, wndHeight, i4MaxImgBufCount);
}
DisplayClient::set_preview_stream_ops(preview_stream_ops*const window, int32_t const wndWidth,
int32_t const wndHeight, int32_t const i4MaxImgBufCount)
{
int32_t min_undequeued_buf_count = 0;
//
// (2) Check
//....
// (3) Sava info.
mpStreamImgInfo.clear();
mpStreamImgInfo = new ImgInfo(wndWidth, wndHeight, CAMERA_DISPLAY_FORMAT, CAMERA_DISPLAY_FORMAT_HAL, "Camera@Display");
mpStreamOps = window;
mi4MaxImgBufCount = i4MaxImgBufCount;
// (4.1) Set gralloc usage bits for window.
err = mpStreamOps->set_usage(mpStreamOps, CAMERA_GRALLOC_USAGE);
// (4.2) Get minimum undequeue buffer count
err = mpStreamOps->get_min_undequeued_buffer_count(mpStreamOps, &min_undequeued_buf_count);
// (4.3) Set the number of buffers needed for display.
err = mpStreamOps->set_buffer_count(mpStreamOps, mi4MaxImgBufCount+min_undequeued_buf_count);
// (4.4) Set window geometry
err = mpStreamOps->set_buffers_geometry(mpStreamOps, mpStreamImgInfo->mu4ImgWidth,
mpStreamImgInfo->mu4ImgHeight, mpStreamImgInfo->mi4ImgFormat);
}
DisplayClient::setImgBufProviderClient(sp<IImgBufProviderClient>const& rpClient)
{
rpClient->onImgBufProviderCreated(mpImgBufQueue);
mpImgBufPvdrClient = rpClient;
}
//BaseCamAdapter.cpp
BaseCamAdapter::onImgBufProviderCreated(sp<IImgBufProvider>const& rpProvider)
{
int32_t const i4ProviderId = rpProvider->getProviderId();
mpImgBufProvidersMgr->setProvider(i4ProviderId, rpProvider);
}
DispalyClient的初始化就这么完成了,从但是我们并不知道上面已经初始化的参数有什么作用,又是如何开始刷显示的呢?我们返回到enableDisplayClient()继续跟踪
Cam1DeviceBase::enableDisplayClient()
{
Size previewSize;
// [1] Get preview size. 获取预览参数
queryPreviewSize(previewSize.width, previewSize.height);
// [2] Enable
mpDisplayClient->enableDisplay(previewSize.width, previewSize.height, queryDisplayBufCount(), mpCamAdapter);
}
Cam1DeviceBase::enableDisplayClient()
{
Size previewSize;
// [1] Get preview size. 获取预览参数
queryPreviewSize(previewSize.width, previewSize.height);
// [2] Enable
mpDisplayClient->enableDisplay(previewSize.width, previewSize.height, queryDisplayBufCount(), mpCamAdapter);
}
DisplayClient::enableDisplay(int32_t const i4Width, int32_t const i4Height,
int32_t const i4BufCount, sp<IImgBufProviderClient>const& rpClient)
{
// Enable.
enableDisplay();
}
DisplayClient::enableDisplay()
{
//Post a command to wake up the thread. 向DisplayThread发送消息
mpDisplayThread->postCommand(Command(Command::eID_WAKEUP));
}
DisplayThread::threadLoop()
{
Command cmd;
if ( getCommand(cmd) )
{
switch (cmd.eId)
{
case Command::eID_EXIT:
//....
case Command::eID_WAKEUP:
default:
//调用的是handler的onThreadloop
//在前面已知DisplayThread的handler被设置成了DisplayClient
mpThreadHandler->onThreadLoop(cmd);
break;
}
}
}
DisplayClient的onThreadLoop()在DisplayClient.BufOps.cpp里,仔细观察下面的函数是不会有似曾相识的感觉,原来下面函数的结构和Preview的onClientThreadLoop的函数结构一模一样,边里面使用的函数名都一样,虽然不是同一个函数
DisplayClient::onThreadLoop(Command const& rCmd)
{
// (0) lock Processor.
sp<IImgBufQueue> pImgBufQueue;
// (1) Prepare all TODO buffers. 准备buf,把buf放入队列里
if ( ! prepareAllTodoBuffers(pImgBufQueue) )
{
return true;
}
// (2) Start 通知开始处理
pImgBufQueue->startProcessor();
// (3) Do until disabled.
while ( 1 )
{
// (.1) 阻塞等待通知,并开始处理buf
waitAndHandleReturnBuffers(pImgBufQueue);
// (.2) break if disabled.
if ( ! isDisplayEnabled() )
{
MY_LOGI("Display disabled");
break;
}
// (.3) re-prepare all TODO buffers, if possible,
// since some DONE/CANCEL buffers return. 准备buf,把buf放入队列里
prepareAllTodoBuffers(pImgBufQueue);
}
//
// (4) Stop
pImgBufQueue->pauseProcessor();
pImgBufQueue->flushProcessor();
pImgBufQueue->stopProcessor();
//
// (5) Cancel all un-returned buffers.
cancelAllUnreturnBuffers();
//
{
Mutex::Autolock _l(mStateMutex);
mState = eState_Suspend;
mStateCond.broadcast();
}
}
根据之前的经验很直觉地找到了waitAndHandleReturnBuffers()函数,正是里面处理了数据,但是又怎么样把数据显示出来的呢?继续看
DisplayClient::waitAndHandleReturnBuffers(sp<IImgBufQueue>const& rpBufQueue)
{
Vector<ImgBufQueNode> vQueNode;
// (1) deque buffers from processor. 阻塞等待通知读取Buf
rpBufQueue->dequeProcessor(vQueNode);
// (2) handle buffers dequed from processor.
ret = handleReturnBuffers(vQueNode);
}
DisplayClient::handleReturnBuffers(Vector<ImgBufQueNode>const& rvQueNode)
{
/*
* Notes:
* For 30 fps, we just enque (display) the latest frame,
* and cancel the others.
* For frame rate > 30 fps, we should judge the timestamp here or source.
*/
//
// (3) Remove from List and enquePrvOps/cancelPrvOps, one by one.
int32_t const queSize = rvQueNode.size();
for (int32_t i = 0; i < queSize; i++)
{
sp<IImgBuf>const& rpQueImgBuf = rvQueNode[i].getImgBuf(); // ImgBuf in Queue.
sp<StreamImgBuf>const pStreamImgBuf = *mStreamBufList.begin(); // ImgBuf in List.
// (.1) Check valid pointers to image buffers in Queue & List
if ( rpQueImgBuf == 0 || pStreamImgBuf == 0 )
{
MY_LOGW("Bad ImgBuf:(Que[%d], List.begin)=(%p, %p)", i, rpQueImgBuf.get(), pStreamImgBuf.get());
continue;
}
// (.2) Check the equality of image buffers between Queue & List.
if ( rpQueImgBuf->getVirAddr() != pStreamImgBuf->getVirAddr() )
{
MY_LOGW("Bad address in ImgBuf:(Que[%d], List.begin)=(%p, %p)", i, rpQueImgBuf->getVirAddr(), pStreamImgBuf->getVirAddr());
continue;
}
// (.3) Every check is ok. Now remove the node from the list.
mStreamBufList.erase(mStreamBufList.begin());
//
// (.4) enquePrvOps/cancelPrvOps
if ( i == idxToDisp ) {
//
if(mpExtImgProc != NULL)
{
if(mpExtImgProc->getImgMask() & ExtImgProc::BufType_Display)
{
IExtImgProc::ImgInfo img;
//
img.bufType = ExtImgProc::BufType_Display;
img.format = pStreamImgBuf->getImgFormat();
img.width = pStreamImgBuf->getImgWidth();
img.height = pStreamImgBuf->getImgHeight();
img.stride[0] = pStreamImgBuf->getImgWidthStride(0);
img.stride[1] = pStreamImgBuf->getImgWidthStride(1);
img.stride[2] = pStreamImgBuf->getImgWidthStride(2);
img.virtAddr = (MUINT32)(pStreamImgBuf->getVirAddr());
img.bufSize = pStreamImgBuf->getBufSize();
//预留的处理接口,用户可自行填充
mpExtImgProc->doImgProc(img);
}
}
//处理将要显示的Buf
enquePrvOps(pStreamImgBuf);
}
else {
//处理被忽略的buf
cancelPrvOps(pStreamImgBuf);
}
}
}
DisplayClient::enquePrvOps(sp<StreamImgBuf>const& rpImgBuf)
{
// [1] unlock buffer before sending to display
GraphicBufferMapper::get().unlock(rpImgBuf->getBufHndl());
// [2] Dump image if wanted.
dumpImgBuf_If(rpImgBuf);
// [3] set timestamp.
err = mpStreamOps->set_timestamp(mpStreamOps, rpImgBuf->getTimestamp());
// [4] set gralloc buffer type & dirty 设置buf的参数
::gralloc_extra_setBufParameter(rpImgBuf->getBufHndl(),
GRALLOC_EXTRA_MASK_TYPE | GRALLOC_EXTRA_MASK_DIRTY, GRALLOC_EXTRA_BIT_TYPE_CAMERA | GRALLOC_EXTRA_BIT_DIRTY);
// [5] unlocks and post the buffer to display.
//此处我们的mpStreamOps在之前的set_preview_stream_ops()被初始化为window,即setWindow()传下来的window参数。
//所以我们得往上找,这个window是什么东西。
err = mpStreamOps->enqueue_buffer(mpStreamOps, rpImgBuf->getBufHndlPtr());
}
再往回找,setPreviewWindow传入了一个window,这个是一个Surface,这个surface通过App层的Surface传下来的buf重新构建的
// set the buffer consumer that the preview will use
status_t CameraClient::setPreviewTarget(
const sp<IGraphicBufferProducer>& bufferProducer) {
sp<IBinder> binder;
sp<ANativeWindow> window;
if (bufferProducer != 0) {
binder = bufferProducer->asBinder();
// Using controlledByApp flag to ensure that the buffer queue remains in
// async mode for the old camera API, where many applications depend
// on that behavior.
window = new Surface(bufferProducer, /*controlledByApp*/ true);
}
return setPreviewWindow(binder, window);
}
setPreviewTarget
()在最开始的
android_hardware_Camera.cpp里被调用,这里传进来 的bufferProduce是从App层的surface里面获取出来的一个buf
static void android_hardware_Camera_setPreviewSurface(JNIEnv *env, jobject thiz, jobject jSurface)
{
sp<IGraphicBufferProducer> gbp;
sp<Surface> surface;
surface = android_view_Surface_getSurface(env, jSurface);
gbp = surface->getIGraphicBufferProducer();
if (camera->setPreviewTarget(gbp) != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "setPreviewTexture failed");
}
}
你会以为上面的pStreamOps->enqueue_buffer用的就是这个surface,其实不是,这里又转了一下
status_t setPreviewWindow(const sp<ANativeWindow>& buf)
{
mPreviewWindow = buf;
mHalPreviewWindow.user = this;
return mDevice->ops->set_preview_window(mDevice,
buf.get() ? &mHalPreviewWindow.nw : 0);
}
这里判断surface的传下来的buf是否为空,如果不为空则把mHalPreviewWindow.nw传下去,这个nw是一个操作方法的集合。相对应的
enqueue_buffer被初始化为下面这个函数
static int __enqueue_buffer(struct preview_stream_ops* w,
buffer_handle_t* buffer)
{
ANativeWindow *a = anw(w);
return a->queueBuffer(a,
container_of(buffer, ANativeWindowBuffer, handle), -1);
}
pStreamOps->enqueue_buffer就是执行了一下上面的方法。其实就是把camera里面的数据填进surface的buf队列里
写过APP的都知道,这个Surface是Android上层用于显示的一个辅助类。而Camera的预览也相当于调用了Surface的操作函数。那问题又来了,调用这些Surface是如何去显示的呢?……我就到此为止了,完成了我做知识储备的目的,日后要是工作有需要深入再深入了,有兴趣的朋友可以自行……….深入。我们还是再继续看,这些数据是如何来的呢?
现在回头看看现在涉及到的几个大类做一下总结。
Cam1DeviceBase(包括其子类和父类)包含了所有的Camera的操作函数,如Open,显示,拍照,录像,自动对焦的操作,以及这些Camera操作和Camera硬件涉及到的参数,可以说,Cam1Device对Frameworks及App层来说就是一个Camera了。
在Cam1DeviceBase里包含了ParamsManager,顾名思义就是Camera的参数管理,我们之前也没去理会他,就让它飘会吧。Cam1DeviceBase还包含了几个Client,用于负责所有的功能操作。DisplayClient用来负责显示,CamClient则是一个大统一,把Camera的操作都归集于此。CamClient又把自己的功能分成几个 Client去负责,其中PreviewClient负责显示,RecordClient负责录制,在拍照的功能里FDClient,OTClient,PreviewClient都参了一脚,具体有什么用,有空再研究。但还有一个CameraAdapter,这也非常重要的