转自:http://www.eoeandroid.com/thread-29278-1-1.html
Overlay 分析
1 overlay 代码结构
Overlay 是个相对简单的模块,主要的文件有:
/hardware/libhardware/include/hardware/overlay.h
主要定义了两个 struct, 定义为 data device 和 control device.
提供针对data device 和 control device 的 open 和 close 函数。
这两个函数就是注册到device_module 里面的函数了。
./frameworks/base/include/ui/IOverlay.h
定义了两个类 一个是 IOverlay, 一个是 BnOverlay.
IOverlay 只定义了destroy 一个函数,用于回收 control device资源。
BnOverlay native binder overlay
./frameworks/base/include/ui/Overlay.h
真正定义 overlay 接口的部分,下面具体介绍
如果我们先不考虑 surface 的话,上面就是比较主要的文件了,下面可以一个一个看一看。
Overlay 使用的driver 是 framebuffer。
2 overlay.h 实现
在 overlay.h 中定义的就是 overlay 的 hal 层了。也是我们需要实现的部分,下面仔细的看一看。
enum {
OVERLAY_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888,
OVERLAY_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565,
OVERLAY_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888,
OVERLAY_FORMAT_YCbCr_422_SP = HAL_PIXEL_FORMAT_YCbCr_422_SP,
OVERLAY_FORMAT_YCbCr_420_SP = HAL_PIXEL_FORMAT_YCbCr_420_SP,
OVERLAY_FORMAT_YCbYCr_422_I = HAL_PIXEL_FORMAT_YCbCr_422_I,
OVERLAY_FORMAT_YCbYCr_420_I = HAL_PIXEL_FORMAT_YCbCr_420_I,
OVERLAY_FORMAT_CbYCrY_422_I = HAL_PIXEL_FORMAT_CbYCrY_422_I,
OVERLAY_FORMAT_CbYCrY_420_I = HAL_PIXEL_FORMAT_CbYCrY_420_I,
OVERLAY_FORMAT_DEFAULT = 99 // The actual color format is determined
// by the overlay
};
一个enum, 定义了所有支援的format,framebuffer 会根据 format 和 width, height来决定buffer(framebuffer里面用来显示的buffer) 的大小。
typedef struct overlay_t {
uint32_t w;
uint32_t h;
int32_t format;
uint32_t w_stride;
uint32_t h_stride;
uint32_t reserved[3];
/* returns a reference to this overlay's handle (the caller doesn't
* take ownership) */
overlay_handle_t (*getHandleRef)(struct overlay_t* overlay);
uint32_t reserved_procs[7];
} overlay_t;
overlay 的一些信息:
w width
h height
format 格式
w_stride h_stride 不知道
getHandleRef 函数返回一个 overlay_handle_t,这个函数很重要。
struct overlay_module_t {
struct hw_module_t common;
};
定义一个结构体,和 hw_module_t 可以混用的,基本上就是个别名,每一个module 都会对应一个, common 里面会注册一个 open 函数
struct overlay_control_device_t {
struct hw_device_t common;
int (*get)(struct overlay_control_device_t *dev, int name);
overlay_t* (*createOverlay)(struct overlay_control_device_t *dev,
uint32_t w, uint32_t h, int32_t format);
void (*destroyOverlay)(struct overlay_control_device_t *dev,
overlay_t* overlay);
int (*setPosition)(struct overlay_control_device_t *dev,
overlay_t* overlay,
int x, int y, uint32_t w, uint32_t h);
int (*getPosition)(struct overlay_control_device_t *dev,
overlay_t* overlay,
int* x, int* y, uint32_t* w, uint32_t* h);
int (*setParameter)(struct overlay_control_device_t *dev,
overlay_t* overlay, int param, int value);
int (*stage)(struct overlay_control_device_t *dev, overlay_t* overlay);
int (*commit)(struct overlay_control_device_t *dev, overlay_t* overlay);
};
结构体定义了一个 control device, 成员除了 common 都是函数,这些函数就是我们需要去实现的,在实现的时候我们会基于这个结构体扩展出一个 关于 control device 的context的结构体,context结构体内部会扩充一些信息并且包含control device 。
Common 每一个device 都必须有,而且必须放到第一位,目的只是为了overlay_control_device_t 和 hw_device_t 做匹配。
int (*get)(struct overlay_control_device_t *dev, int name);
函数为了获取属性,也可以不实现
overlay_t* (*createOverlay)(struct overlay_control_device_t *dev,
uint32_t w, uint32_t h, int32_t format);
一个很重要的函数,用于生成overlay_t(内部需要做open 等操作,并获取相应的句柄)
void (*destroyOverlay)(struct overlay_control_device_t *dev,
overlay_t* overlay);
释放资源,分配的handle, 和 control device 的内存。
int (*setPosition)(struct overlay_control_device_t *dev,
overlay_t* overlay,
int x, int y, uint32_t w, uint32_t h);
设置overlay 的显示范围。(如果是camera 的 preview, 那么 h, w 要和preview h, w 一致)
int (*getPosition)(struct overlay_control_device_t *dev,
overlay_t* overlay,
int* x, int* y, uint32_t* w, uint32_t* h);
获取 overlay 的显示范围。
int (*setParameter)(struct overlay_control_device_t *dev,
overlay_t* overlay, int param, int value);
没有实现,可以根据自己的driver ,选择一些参数。
int (*stage)(struct overlay_control_device_t *dev, overlay_t* overlay);
int (*commit)(struct overlay_control_device_t *dev, overlay_t* overlay);
framebuffer 中我没有实现这两个函数,不过我看 l4v2 有实现。
struct overlay_data_device_t {
struct hw_device_t common;
int (*initialize)(struct overlay_data_device_t *dev,
overlay_handle_t handle);
int (*resizeInput)(struct overlay_data_device_t *dev,
uint32_t w, uint32_t h);
int (*setCrop)(struct overlay_data_device_t *dev,
uint32_t x, uint32_t y, uint32_t w, uint32_t h) ;
int (*getCrop)(struct overlay_data_device_t *dev,
uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) ;
int (*setParameter)(struct overlay_data_device_t *dev,
int param, int value);
int (*dequeueBuffer)(struct overlay_data_device_t *dev,
overlay_buffer_t *buf);
int (*queueBuffer)(struct overlay_data_device_t *dev,
overlay_buffer_t buffer);
void* (*getBufferAddress)(struct overlay_data_device_t *dev,
overlay_buffer_t buffer);
int (*getBufferCount)(struct overlay_data_device_t *dev);
int (*getBufferCount)(struct overlay_data_device_t *dev);
};
common 同上
int (*initialize)(struct overlay_data_device_t *dev,
overlay_handle_t handle);
函数通过 参数handle 来初始化 data device.
int (*resizeInput)(struct overlay_data_device_t *dev,
uint32_t w, uint32_t h);
函数重新配置显示参数 w, h。 这两个参数生效我这里需要 close 然后重新 open.
很麻烦不知道有没有别的办法了。
int (*setCrop)(struct overlay_data_device_t *dev,
uint32_t x, uint32_t y, uint32_t w, uint32_t h) ;
int (*getCrop)(struct overlay_data_device_t *dev,
uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) ;
设置显示的区域,和获取显示的区域,当播放的时候,需要这是 坐标和 宽高来定义如何显示这些数据。
int (*dequeueBuffer)(struct overlay_data_device_t *dev,
overlay_buffer_t *buf);
int (*queueBuffer)(struct overlay_data_device_t *dev,
overlay_buffer_t buffer);
l4v2 的driver 用来管理内存。我的是FB 所以我不需要这两个函数。
void* (*getBufferAddress)(struct overlay_data_device_t *dev,
overlay_buffer_t buffer);
函数返回 framebuffer 内部用于显示的内存。通过 mmap 拿到 内存地址。
以上的两个 data 和 control device是我们需要实现的。
3 Overlay.h 实现
函数实现 的更像是 data device 的功能,和一些外界的接口,我们来看一下。
内部实现的主要的类是 Overlay 和 overlayRef。
OverlayRef 主要需要和surface 配合使用,
通过 Isurface 可以创建出OverlayRef
而 Overlay 是通过OverlayRef 来创建出来的。
下面来看看 Overlay
class Overlay : public virtual RefBase
{
public:
Overlay(const sp<OverlayRef>& overlayRef);
void destroy();
overlay_handle_t getHandleRef() const;
status_t dequeueBuffer(overlay_buffer_t* buffer);
status_t queueBuffer(overlay_buffer_t buffer);
status_t resizeInput(uint32_t width, uint32_t height);
status_t setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) ;
status_t getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) ;
status_t setParameter(int param, int value);
void* getBufferAddress(overlay_buffer_t buffer);
/* get physical informations about the overlay */
uint32_t getWidth() const;
uint32_t getHeight() const;
int32_t getFormat() const;
int32_t getWidthStride() const;
int32_t getHeightStride() const;
int32_t getBufferCount() const;
status_t getStatus() const;
private:
virtual ~Overlay();
sp<OverlayRef> mOverlayRef;
overlay_data_device_t *mOverlayData;
status_t mStatus;
};
Overlay(const sp<OverlayRef>& overlayRef);
很厉害的设计,通过surface 来控制 overlay 或者 在不使用 overlay 的情况下统一的来管理。
这里就是通过 overlayRef 来创建 overlay , 一旦我们拿到了overlay ,我们就可以通过这个overlay 来获取到 用来显示的address, 向 address 中写入数据,就可以显示我们的图像了。
void destroy();
释放 data device 的资源。 我们通过这里就能看到了,实际上一旦 control device 设置结束之后,我们以后使用 control device 的机会是没有的。
overlay_handle_t getHandleRef() const;
获取overlay handle,可以根据自己的需要扩展,扩展之后就有很多数据了。
status_t dequeueBuffer(overlay_buffer_t* buffer);
status_t queueBuffer(overlay_buffer_t buffer);
配合 linux4vedio2 使用的函数,我的是framebuffer 并不使用。
status_t resizeInput(uint32_t width, uint32_t height);
重新配置overlay 的区域属性。
status_t setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) ;
status_t getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) ;
设置播放的属性。
void* getBufferAddress(overlay_buffer_t buffer);
获取framebuffer 用于显示的内存地址。
uint32_t getWidth() const;
uint32_t getHeight() const;
int32_t getFormat() const;
int32_t getWidthStride() const;
int32_t getHeightStride() const;
int32_t getBufferCount() const;
status_t getStatus() const;
获取属性的信息。
以上的这些接口是我们以后需要使用的,我们只需要知道如何使用就可以了。
4 与 surface 相关的属性
这个研究了好一会,比较费劲。
首先是这样的:
status_t SurfaceFlinger::readyToRun()
函数在 android 启动的时候就会去调用的函数,在函数的内部有这么一句
DisplayHardware* const hw = new DisplayHardware(this, dpy);
实例化一个DisplayHardware
DisplayHardware:isplayHardware(
const sp<SurfaceFlinger>& flinger,
uint32_t dpy)
: DisplayHardwareBase(flinger, dpy)
{
init(dpy);
}
这个是 DisplayHardware 构造函数的实现
我们关心他调用的函数 init。
Init 函数有这么几句
if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
overlay_control_open(module, &mOverlayEngine);
}
这个就是我们最关心的,获取到 overlay 的 module 参数,调用 overlay_control_open 获取
control device( mOverlayEngine).
这里就是一切的开始。拥有了control device。
下面就是获取 control device 的handle 了,通过调用 Isurface的createOverlay。
这个流程是这样的, Isurface->BnOverlay->LayerBuffer->OverlaySource->OverLayChannel
这样就得到了 control device handle。
我们还需要一个 data device:
data device 是定义在class Overlay 的一个成员,通过 overlayRef来构造
Overlay(const sp<OverlayRef>& overlayRef);
这里通过 overlayRef::mOverlayHandle 在它的内部保存这 control device 的信息。
从而初始化 data device 的信息。得到 data device。
1、 测试代码
frameworks/base/libs/surfaceflinger/tests/overlays/overlays.cpp提供了一个简单的overlay调用流程,可惜这个测试程序有错误,
在sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240, PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);
这句话编译不过去,错误在Surface的申请,和overlay无关。
我们来看看这段代码:
int main(int argc, char** argv)
{
// set up the thread-pool 建立线程池
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create a client to surfaceflinger 创建一个SurfaceFlinger client
sp<SurfaceComposerClient> client = new SurfaceComposerClient();
// create pushbuffer surface 创建一个surface,最后那个参数是类型?
sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240,
PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);
// get to the isurface 取得isurface接口
sp<ISurface> isurface = Test::getISurface(surface);
printf("isurface = %p/n", isurface.get());
// now request an overlay 创建一个overlay
sp<OverlayRef> ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);
sp<Overlay> overlay = new Overlay(ref);
/*
* here we can use the overlay API 创建好overlay后,即可使用overlay的API,这些都对应到overlay HAL的具体实现
*/
overlay_buffer_t buffer;
overlay->dequeueBuffer(&buffer);
printf("buffer = %p/n", buffer);
void* address = overlay->getBufferAddress(buffer);
printf("address = %p/n", address);
overlay->queueBuffer(buffer);//最重要的操作就是通过queueBuffer将buffer列队
return 0;
}
2、Android系统创建中Overlay(调用createOverlay)
1)摄像头相关 CameraService.cpp (frameworks/base/camera/libcameraservice)
setPreviewDisplay()、startPreviewMode()
|
setOverlay()
|
creatOverlay()
2)界面相关 ISurface.cpp (frameworks/base/libs/ui)
LayerBaseClient::Surface::onTransact() <--该函数位于LayerBase.cpp,好像是用于ibind进程通讯的函数
|
BnSurface::onTransact() //有5种方式,只有确定有overlay硬件支持时才会调用case CREATE_OVERLAY
|
... ...
switch(code) {
case REQUEST_BUFFER: {
CHECK_INTERFACE(ISurface, data, reply);
int bufferIdx = data.readInt32();
int usage = data.readInt32();
sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));
return GraphicBuffer::writeToParcel(reply, buffer.get());
}
case REGISTER_BUFFERS: {
CHECK_INTERFACE(ISurface, data, reply);
BufferHeap buffer;
buffer.w = data.readInt32();
buffer.h = data.readInt32();
buffer.hor_stride = data.readInt32();
buffer.ver_stride= data.readInt32();
buffer.format = data.readInt32();
buffer.transform = data.readInt32();
buffer.flags = data.readInt32();
buffer.heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
status_t err = registerBuffers(buffer);
reply->writeInt32(err);
return NO_ERROR;
} break;
case UNREGISTER_BUFFERS: {
CHECK_INTERFACE(ISurface, data, reply);
unregisterBuffers();
return NO_ERROR;
} break;
case POST_BUFFER: {
CHECK_INTERFACE(ISurface, data, reply);
ssize_t offset = data.readInt32();
postBuffer(offset);
return NO_ERROR;
} break;
case CREATE_OVERLAY: {
CHECK_INTERFACE(ISurface, data, reply);
int w = data.readInt32();
int h = data.readInt32();
int f = data.readInt32();
sp<OverlayRef> o = createOverlay(w, h, f);
return OverlayRef::writeToParcel(reply, o);
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
... ...
3)LayerBuffer.cpp (frameworks/base/libs/surfaceflinger) 这儿其实是createOverlay的实现
sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t format)
|
sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f)
|
sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f); //通过OverlaySource来创建overlay
LayerBuffer::OverlaySource::OverlaySource()//该函数调用了Overlay HAL的API createOverlay
{
overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine();//get HAL
overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);//HAL API
// enable dithering...
overlay_dev->setParameter(overlay_dev, overlay, OVERLAY_DITHER, OVERLAY_ENABLE);
//设置参数,初始化OverlayRef类,OverlayRef的构造函数在Overlay.cpp中
mOverlay = overlay;
mWidth = overlay->w;
mHeight = overlay->h;
mFormat = overlay->format;
mWidthStride = overlay->w_stride;
mHeightStride = overlay->h_stride;
mInitialized = false;
... ...
*overlayRef = new OverlayRef(mOverlayHandle, channel,mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
}
3、Overlay HAL模块管理
Overlay.cpp (frameworks/base/libs/ui)负责管理overlay HAL,并对HAL的API进行封装
1)打开Overlay HAL模块
Overlay::Overlay(const sp<OverlayRef>& overlayRef)
: mOverlayRef(overlayRef), mOverlayData(0), mStatus(NO_INIT)
{
mOverlayData = NULL;
hw_module_t const* module;
if (overlayRef != 0) {
if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
if (overlay_data_open(module, &mOverlayData) == NO_ERROR) {
mStatus = mOverlayData->initialize(mOverlayData,
overlayRef->mOverlayHandle);
}
}
}
}
2)Overlay HAL的初始化
参考上一段,overlayRef = new OverlayRef(mOverlayHandle, channel,mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
构造函数位于Overlay.cpp
OverlayRef::OverlayRef(overlay_handle_t handle, const sp<IOverlay>& channel,
uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs)
: mOverlayHandle(handle), mOverlayChannel(channel),
mWidth(w), mHeight(h), mFormat(f), mWidthStride(ws), mHeightStride(hs),
mOwnHandle(false)
{
}
3)封装了很多的API,但是没有查到那儿有调用,看来还需要大改框架才能真正将overlay利用起来
比如TI自己写的opencore函数中到时有用到,主要负责视频输出。
Android_surface_output_omap34xx.cpp (hardware/ti/omap3/libopencorehw)
4、总结
Overlay的输出对象有两种,一种是视频(主要是YUV格式,调用系统的V4L2),另外一个是ISurface的一些图像数据(RGB格式,直接写framebuffer)
从代码实现角度看,目前Android系统默认并没有使用Overlay功能,虽然提供了Skeleton的Overlay HAL,并对其进行封装,但是上层几乎没有调用到封装的API。
如果要用好Overlay HAL,需要大量修改上层框架,这对视屏播放可能比较重要,可参考TI的Android_surface_output_omap34xx.cpp。
此外Surface实现的Overlay功能和Copybit的功能有部分重复,从TI的代码看主要是实现V4L2的Overlay功能
这部分spec的内容没有全看懂,但是根据FSL的代码能知道这其中的sequence,下面就结合着FSL的代码来描述下video overlay过程的sequence。
首先介绍一下video overlay,vieo overlay不同于video capture,是指不需要对video信号的帧进行copy,直接将视频信号转化成显卡的VGA信号或者将捕获到的视频帧直接存放在显卡的内存中,具体过程就是将视频帧直接写入framebuffer中,不需要经过android 平台的处理。实际上看过FSL的camera preview过程之后就知道,它就是直接将视频数据 写入framebuffer,而没有经过android的surfaceflinger的处理。Video overlay需要硬件的支持,必须是支持video overlay的camera才能使用这套overlay interface。
因为video overlay直接使用linux 的framebuffer来显示捕获到的image,所以和capture相比它更具有效率,而不是将捕获到的image拷贝以后通过其他的方式(android surfaceflinger)来显示。Viedo overlay只用来preview,又被称为framebuffer overlay或previwing。
从spec上来看,实际上video capture interface也能实现preview,只是没有overlay有效率,因为video capture是将数据经过copy以后由android surfaceflinger来控制进行显示(实际上最后surfaceflinger还是通过framebuffer来显示的)。
Video overlay和Video capture使用同样的device,overlay的功能只有在调用VIDIOC_S_FMT后才会有效。下面就看看overlay流程的sequcence。
1、open device
这部分同video capture,首先是要打开设备。如果是同时进行overlay和capture,应该尽量不使用同一个文件 描述符,比如说如果此时在overlay,要拍照的话应该再打开设备,使用一个分开的文件描述符来进行capture。如果driver支持同时进行overlay和capture的话,必须支持使用分开的文件描述符来分别进行overlay和capture 。
camera_device = open(VIDEO_DEVICE, O_RDWR)) ;
2、set output
对于这个设置 输出不是太理解,但overlay换个角度来说是将捕获的image重新组合成能在屏幕上显示的视频信号,在这里的设置输出应该是如果device有多个输出的话,选择一个输出来将数据输入到屏幕,也就是framebuffer。
ioctl(camera_device, VIDIOC_S_OUTPUT, &g_display_lcd) ;
3、set control[可选]
设置用户控制参数,FSL在这里使用了他们驱动自定义的控制参数,不是很理解这个参数设置是想实现什么操作,我觉得这个应该是可选的。
ioctl(camera_device, VIDIOC_S_CTRL, &ctl) ;
4、set crop
这个同video capture是一样的,只是type由V4L2_BUF_TYPE_VIDEO_CAPTURE换成了V4L2_BUF_TYPE_VIDEO_OVERLAY,然后是取景参数的设置:left,top,width,height。
ioctl(camera_device, VIDIOC_S_CROP, &crop) ;
5、set format
这个format应该是最后preview我们在屏幕上看到的image的格式,如果在video capture中,这个就是我们拍照时image的格式。
ioctl(camera_device, VIDIOC_S_FMT, fmt) ;
6、 get video std
这个我觉得肯定是可选的,取得当前视频标准
ioctl(camera_device, VIDIOC_G_STD, &id) ;
7、set stream param
设置流参数,这个和video capture是相同的,这里的param.type是V4L2_BUF_TYPE_VIDEO_CAPTURE,其中timeperframe的分母是需要设定的帧率,而分子是1。
ioctl(camera_device, VIDIOC_S_PARM, &parm) ;
[PS]这里补充一点stream param方面的spec:
一般来说当前的帧率是由当前的视频标准来决定的,如果默认采用视频标准的帧率就不需要设置流参数,但是如果想获得或者设定自己的帧率就需要使用VIDIOC_G_PARM, VIDIOC_S_PARM:
int ioctl(int fd, int request, v4l2_streamparm *argp);
struct v4l2_stramparam包含以下主要成员:
enum v4l2_buf_type type
union param
struct v4l2_captureparm capture
struct v4l2_outputparam output
//要注意的是在这里,不管是overaly还是capture,这里的buffer type都是选择的V4L2_BUF_TYPE_VIDEO_CAPTURE。
Struct v4l2_captureparam包含以下主要成员:
__u32 capturemode
//是否支持高质量图像捕捉
struct v4l2_fract timeperframe
//设置帧率,通过分母分子实现
这里要注意的是,通过 VIDIOC_S_PARM设置帧率不一定成功,driver会根据硬件限制来设置这些参数,所以一般设置以后可以通过VIDIOC_G_PARM来看设定是否成功。
前面从1-8都是设置overlay的参数,然后需要设置framebuufer的参数,framebuffer参数部分的设置通过VIDIOC_G_FBUF,VIDIOC_S_FBUF来实现,这里的参数也是比较复杂,具体可以去参照这个spec:http://v4l2spec.bytesex.org/spec/r10595.htm
我看FSL的代码,它也是采用了默认的framebuffer的参数,唯一的就是改变了一下flag:
ioctl(camera_device, VIDIOC_G_FBUF, &fb_v4l2) ;
fb_v4l2.flags = V4L2_FBUF_FLAG_OVERLAY;
ioctl(camera_device, VIDIOC_S_FBUF, &fb_v4l2) ;
在设置framebubffer参数之前,FSL打开了framebuffer设备,并对屏幕进行了一系列的配置,因为overlay状态下是直接写屏,所以它这里加入了对framebuffer设备的配置工作。
完成这一系列的配置以后通过调用overlay即开始了overlay过程,在这里overlay的数为0时为关闭overlay,为1时为打开overlay。
ioctl(camera_device, VIDIOC_OVERLAY, &overlay) ;
实际上看FSL的preview代码,虽然也加入了线程的概念,但线程内没有作什么实际性的内容,在preview线程起来之前,overlay实际上已经开始了。个人觉得这个preview线程是一个多余的操作。而且它也没有用到android内部的memory,因此在overlay preview的启动过程中对initHeapLocked()的调用也完全是多余的,没有进行实质性的操作。由此可见FSL code完全就是通过linux和v4l2来实现了camera preview的功能,甚至连previewcallback都省去了。
FSL camera take picture with v4l2
首先说明一下可能是因为FSL 的camera 不支持autofocus ,所以它没有实现对autofocus 的支持,autofucus 线程直接调用了callback ,没有进行操作。
FSL 对拍照提供了一套它自己的jpeg 编码,获得的数据可以进行jpeg 编码,也可以直接将捕获的raw data 以call back 返回。Take picture 是建立在preview 的基础 上的,实际上就是将preview 中捕获的某个image 保存下来。在FSL code 中是在overlay 的基础上,重新打开设备,在新的文件描述符上设置take picture 相关的参数,从设备中读到数据以后,再将参数还原到overlay 的状态。下面我们看看take picture 的sequence :
1 、shutter callback
因为拍照是通过快门事件激发的,所以首先会调用mShutterCallback ;
2 、open device
打开一个新的文件描述符来进行take picture 的操作
3 、set format
设置capture 的image format ,可以看看它对参数的设置:
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = g_still_pixelformat;
fmt.fmt.pix.width = g_width;
fmt.fmt.pix.height = g_height;
fmt.fmt.pix.sizeimage = fmt.fmt.pix.width * fmt.fmt.pix.height * g_still_bpp / 8;
fmt.fmt.pix.bytesperline = g_width * g_still_bpp / 8;
其中bpp 是每个像素所占有的比特位
ioctl(fd_v4l, VIDIOC_S_FMT, &fmt) ;
4 、set crop
同样可以看看设置的crop parameter :
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c.left = 0;
crop.c.top = 0;
crop.c.width = g_width;
crop.c.height = g_height;
ioctl(fd_v4l, VIDIOC_S_CROP, &crop) ;
5 、set stream paramter
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm.parm.capture.timeperframe.numerator = 1;
parm.parm.capture.timeperframe.denominator = g_still_camera_framerate;
parm.parm.capture.capturemode = g_capture_mode;
ioctl(fd_v4l, VIDIOC_S_PARM, &parm) ;
6 、read image data
read(camera_device, buf1, fmt.fmt.pix.sizeimage) ;
这里存在一点疑问,这个camera_device 中的数据是从何而来的,根据v4l2 协议 就是当前overlay 到的数据么?
7 、将数据直接以rawcallback 返回或者压缩成jpeg 返回。