想要知道Driver回来的数据是如何显示出来的吗?
这个工作是在哪一层做的?
跟踪代码就可以理清楚这一过程,这里代码版本是Jelly Bean。
CameraHardwareInterface初始化的时候会初始化好window有关的数据
struct camera_preview_window {
struct preview_stream_ops nw;
void *user;
};
struct camera_preview_window mHalPreviewWindow;
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);
if (rc != OK) {
ALOGE("Could not open camera %s: %d", mName.string(), rc);
return rc;
}
initHalPreviewWindow();
return rc;
}
void initHalPreviewWindow()
{
mHalPreviewWindow.nw.cancel_buffer = __cancel_buffer;
mHalPreviewWindow.nw.lock_buffer = __lock_buffer;
mHalPreviewWindow.nw.dequeue_buffer = __dequeue_buffer;
mHalPreviewWindow.nw.enqueue_buffer = __enqueue_buffer;
mHalPreviewWindow.nw.set_buffer_count = __set_buffer_count;
mHalPreviewWindow.nw.set_buffers_geometry = __set_buffers_geometry;
mHalPreviewWindow.nw.set_crop = __set_crop;
mHalPreviewWindow.nw.set_timestamp = __set_timestamp;
mHalPreviewWindow.nw.set_usage = __set_usage;
mHalPreviewWindow.nw.set_swap_interval = __set_swap_interval;
mHalPreviewWindow.nw.get_min_undequeued_buffer_count =
__get_min_undequeued_buffer_count;
}
static int __dequeue_buffer(struct preview_stream_ops* w,
buffer_handle_t** buffer, int *stride)
{
int rc;
ANativeWindow *a = anw(w);
ANativeWindowBuffer* anb;
rc = native_window_dequeue_buffer_and_wait(a, &anb);
if (!rc) {
*buffer = &anb->handle;
*stride = anb->stride;
}
return rc;
}
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);
}
继而在Vendor的HAL当中,这里以TI为例子
/**
@brief Sets ANativeWindow object.
Preview buffers provided to CameraHal via this object. DisplayAdapter will be interfacing with it
to render buffers to display.
@param[in] window The ANativeWindow object created by Surface flinger
@return NO_ERROR If the ANativeWindow object passes validation criteria
@todo Define validation criteria for ANativeWindow object. Define error codes for scenarios
*/
status_t CameraHal::setPreviewWindow(struct preview_stream_ops *window)
{
status_t ret = NO_ERROR;
CameraAdapter::BuffersDescriptor desc;
LOG_FUNCTION_NAME;
mSetPreviewWindowCalled = true;
///If the Camera service passes a null window, we destroy existing window and free the DisplayAdapter
if(!window)
{
if(mDisplayAdapter.get() != NULL)
{
///NULL window passed, destroy the display adapter if present
CAMHAL_LOGDA("NULL window passed, destroying display adapter");
mDisplayAdapter.clear();
///@remarks If there was a window previously existing, we usually expect another valid window to be passed by the client
///@remarks so, we will wait until it passes a valid window to begin the preview again
mSetPreviewWindowCalled = false;
}
CAMHAL_LOGDA("NULL ANativeWindow passed to setPreviewWindow");
return NO_ERROR;
}else if(mDisplayAdapter.get() == NULL)
{
// Need to create the display adapter since it has not been created
// Create display adapter
mDisplayAdapter = new ANativeWindowDisplayAdapter();
...
// DisplayAdapter needs to know where to get the CameraFrames from inorder to display
// Since CameraAdapter is the one that provides the frames, set it as the frame provider for DisplayAdapter
mDisplayAdapter->setFrameProvider(mCameraAdapter);
...
// Update the display adapter with the new window that is passed from CameraService
// 这里的window(ANativeWindowDisplayAdapter::mANativeWindow)就是CameraHardwareInterface::mHalPreviewWindow::nw
ret = mDisplayAdapter->setPreviewWindow(window);
if(ret!=NO_ERROR)
{
CAMHAL_LOGEB("DisplayAdapter setPreviewWindow returned error %d", ret);
}
if(mPreviewStartInProgress)
{
CAMHAL_LOGDA("setPreviewWindow called when preview running");
// Start the preview since the window is now available
ret = startPreview();
}
} else {
// Update the display adapter with the new window that is passed from CameraService
ret = mDisplayAdapter->setPreviewWindow(window);
if ( (NO_ERROR == ret) && previewEnabled() ) {
restartPreview();
} else if (ret == ALREADY_EXISTS) {
// ALREADY_EXISTS should be treated as a noop in this case
ret = NO_ERROR;
}
}
LOG_FUNCTION_NAME_EXIT;
return ret;
}
注意看setPreviewWindow之前我加的一行中文注释
在TI的HAL当中有去做包一些adaper出来,实际就是取数据的(比如V4L2CameraAdapter,也就是CameraAdapter),和数据发其他地方(比如ANativeWindowDisplayAdapter,也就是DisplayAdapter)去用的。
在TI的HW当中,有previewThread(位于V4LCameraAdapter当中),previewThread会不断的通过IOCTL从V4L2获取frame
int V4LCameraAdapter::previewThread()
{
status_t ret = NO_ERROR;
int width, height;
CameraFrame frame;
if (mPreviewing)
{
int index = 0;
char *fp = this->GetFrame(index);
uint8_t* ptr = (uint8_t*) mPreviewBufs.keyAt(index);
int width, height;
uint16_t* dest = (uint16_t*)ptr;
uint16_t* src = (uint16_t*) fp;
mParams.getPreviewSize(&width, &height);
...
mParams.getPreviewSize(&width, &height);
frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC;
frame.mBuffer = ptr;
...
ret = sendFrameToSubscribers(&frame);
}
return ret;
}
char * V4LCameraAdapter::GetFrame(int &index)
{
int ret;
mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
/* DQ */
ret = ioctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf);
if (ret < 0) {
CAMHAL_LOGEA("GetFrame: VIDIOC_DQBUF Failed");
return NULL;
}
nDequeued++;
index = mVideoInfo->buf.index;
return (char *)mVideoInfo->mem[mVideoInfo->buf.index];
}
class CameraFrame
{
public:
enum FrameType
{
PREVIEW_FRAME_SYNC = 0x1, ///SYNC implies that the frame needs to be explicitly returned after consuming in order to be filled by camera again
PREVIEW_FRAME = 0x2 , ///Preview frame includes viewfinder and snapshot frames
IMAGE_FRAME_SYNC = 0x4, ///Image Frame is the image capture output frame
IMAGE_FRAME = 0x8,
VIDEO_FRAME_SYNC = 0x10, ///Timestamp will be updated for these frames
VIDEO_FRAME = 0x20,
FRAME_DATA_SYNC = 0x40, ///Any extra data assosicated with the frame. Always synced with the frame
FRAME_DATA= 0x80,
RAW_FRAME = 0x100,
SNAPSHOT_FRAME = 0x200,
ALL_FRAMES = 0xFFFF ///Maximum of 16 frame types supported
};
enum FrameQuirks
{
ENCODE_RAW_YUV422I_TO_JPEG = 0x1 << 0,
HAS_EXIF_DATA = 0x1 << 1,
};
//default contrustor
CameraFrame():
...
{
...
}
//copy constructor
CameraFrame(const CameraFrame &frame) :
...
{
...
}
void *mCookie;
void *mCookie2;
void *mBuffer;
int mFrameType;
nsecs_t mTimestamp;
unsigned int mWidth, mHeight;
uint32_t mOffset;
unsigned int mAlignment;
int mFd;
size_t mLength;
unsigned mFrameMask;
unsigned int mQuirks;
unsigned int mYuv[2];
///@todo add other member vars like stride etc
};
对于ANativeWindowDisplayAdapter,它有给自己配置一个FrameProvider,实际就是会去注册一种callback,当从driver回来数据的时候会去通知对应的callback,当然这个时候还没有真正的去注册
int ANativeWindowDisplayAdapter::setFrameProvider(FrameNotifier *frameProvider)
{
LOG_FUNCTION_NAME;
// Check for NULL pointer
if ( !frameProvider ) {
CAMHAL_LOGEA("NULL passed for frame provider");
LOG_FUNCTION_NAME_EXIT;
return BAD_VALUE;
}
//Release any previous frame providers
if ( NULL != mFrameProvider ) {
delete mFrameProvider;
}
/** Dont do anything here, Just save the pointer for use when display is
actually enabled or disabled
*/
mFrameProvider = new FrameProvider(frameProvider, this, frameCallbackRelay);
LOG_FUNCTION_NAME_EXIT;
return NO_ERROR;
}
并且我们在开始start preview的时候会去注册这个callback,当然同时在start preview的时候我们也会去分配一块buffer,这样driver回来的数据才有地方放,申请buffer如下
CameraHal::allocateBuffer(…) __dequeue_buffer
下面是启动living preview,注册callback
int ANativeWindowDisplayAdapter::enableDisplay(int width, int height, struct timeval *refTime, S3DParameters *s3dParams)
{
Semaphore sem;
TIUTILS::Message msg;
LOG_FUNCTION_NAME;
if ( mDisplayEnabled )
{
CAMHAL_LOGDA("Display is already enabled");
LOG_FUNCTION_NAME_EXIT;
return NO_ERROR;
}
#if 0 //TODO: s3d is not part of bringup...will reenable
if (s3dParams)
mOverlay->set_s3d_params(s3dParams->mode, s3dParams->framePacking,
s3dParams->order, s3dParams->subSampling);
#endif
#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
if ( NULL != refTime )
{
Mutex::Autolock lock(mLock);
memcpy(&mStandbyToShot, refTime, sizeof(struct timeval));
mMeasureStandby = true;
}
#endif
//Send START_DISPLAY COMMAND to display thread. Display thread will start and then wait for a message
sem.Create();
msg.command = DisplayThread::DISPLAY_START;
// Send the semaphore to signal once the command is completed
msg.arg1 = &sem;
///Post the message to display thread
mDisplayThread->msgQ().put(&msg);
///Wait for the ACK - implies that the thread is now started and waiting for frames
sem.Wait();
// Register with the frame provider for frames
mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC);
mDisplayEnabled = true;
mPreviewWidth = width;
mPreviewHeight = height;
CAMHAL_LOGVB("mPreviewWidth = %d mPreviewHeight = %d", mPreviewWidth, mPreviewHeight);
LOG_FUNCTION_NAME_EXIT;
return NO_ERROR;
}
int FrameProvider::enableFrameNotification(int32_t frameTypes)
{
LOG_FUNCTION_NAME;
status_t ret = NO_ERROR;
///Enable the frame notification to CameraAdapter (which implements FrameNotifier interface)
mFrameNotifier->enableMsgType(frameTypes<<MessageNotifier::FRAME_BIT_FIELD_POSITION
, mFrameCallback
, NULL
, mCookie
);
// 把frameCallbackRelay这个callback添加到BaseCameraAdapter::mFrameSubscribers当中
// 详见 preview_stream_ops_t* mANativeWindow; 以及 ANativeWindowDisplayAdapter::PostFrame(...)
// __enqueue_buffer
// 最终会把数据更新到CameraHardwareInterface的sp<ANativeWindow> mPreviewWindow;
// 这样每过来一个frame,也就是去更新我们看到的preview数据
LOG_FUNCTION_NAME_EXIT;
return ret;
}
见上面代码中嵌的中文注释,这是我加的。
另外displayThread(位于ANativeWindowDisplayAdapter当中),displayThread会听一些从Camera HAL来的消息,然后执行,这个不是很复杂。
也就是说数据是怎么贴到view上去,这是HAL这层做掉的,虽然只是一个调用ANativeWindow的过程!
这只是一个粗糙的过程,再深层细节的我们暂时不研究。