Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析(6)

简介:
     函数fb_device_open在打开fb设备的过程中,会调用另外一个函数mapFrameBuffer来获得系统帧缓冲区的信息,并且将这些信息保存在参数module所描述的一个private_module_t结构体的各个成员变量中。有了系统帧缓冲区的信息之后,函数fb_device_open接下来就可以对前面所打开的一个fb设备的各个成员变量进行初始化。这些成员变量的含义可以参考前面对结构体framebuffer_device_t的介绍。接下来我们只简单介绍一下结构体framebuffer_device_t的成员变量stride和format的初始化过程。
        变量m的成员变量finfo的类型为fb_fix_screeninfo,它是在函数mapFrameBuffer中被始化的。fb_fix_screeninfo是在内核中定义的一个结构体,用来描述设备显示屏的固定属性信息,其中,它的成员变量line_length用来描述显示屏一行像素总共所占用的字节数。
        变量m的另外一个成员变量info的类型为fb_var_screeninfo,它也是在函数mapFrameBuffer中被始化的。fb_var_screeninfo也是内核中定义的一个结构体,用来描述可以动态设置的显示屏属性信息,其中,它的成员变量bits_per_pixel用来描述显示屏每一个像素所占用的位数。
        这样,我们将m->info.bits_per_pixel的值向右移3位,就可以得到显示屏每一个像素所占用的字节数。用显示屏每一个像素所占用的字节数去除显示屏一行像素总共所占用的字节数m->finfo.line_length,就可以得到显示屏一行有多少个像素点。这个值最终就可以保存在前面所打开的fb设备的成员变量stride中。
        当显示屏每一个像素所占用的位数等于32的时候,那么前面所打开的fb设备的像素格式format就会被设置为HAL_PIXEL_FORMAT_RGBX_8888,否则的话,就会被设置为HAL_PIXEL_FORMAT_RGB_565。另一方面,如果在编译的时候定义了NO_32BPP宏,即不要使用32位来描述一个像素,那么函数fb_device_open就会强制将前面所打开的fb设备的像素格式format设置为HAL_PIXEL_FORMAT_RGB_565。
        函数mapFrameBuffer除了用来获得系统帧缓冲区的信息之外,还会将系统帧缓冲区映射到当前进程的地址空间来。在Android系统中,Gralloc模块中的fb设备是由SurfaceFlinger服务来负责打开和管理的,而SurfaceFlinger服是运行System进程中的,因此,系统帧缓冲区实际上是映射到System进程的地址空间中的。
        函数mapFrameBuffer实现在文件hardware/libhardware/modules/gralloc/framebuffer.cpp,如下所示:
  1. static int mapFrameBuffer(struct private_module_t* module)  
  2. {  
  3.     pthread_mutex_lock(&module->lock);  
  4.     int err = mapFrameBufferLocked(module);  
  5.     pthread_mutex_unlock(&module->lock);  
  6.     return err;  
  7. }  
       这个函数调用了同一个文件中的另外一个函数mapFrameBufferLocked来初始化参数module以及将系统帧缓冲区映射到当前进程的地址空间来。
 
       函数mapFrameBufferLocked的实现比较长,我们分段来阅读:
  1. int mapFrameBufferLocked(struct private_module_t* module)  
  2. {  
  3.     // already initialized...  
  4.     if (module->framebuffer) {  
  5.         return 0;  
  6.     }  
  7.   
  8.     char const * const device_template[] = {  
  9.             "/dev/graphics/fb%u",  
  10.             "/dev/fb%u",  
  11.             0 };  
  12.   
  13.     int fd = -1;  
  14.     int i=0;  
  15.     char name[64];  
  16.   
  17.     while ((fd==-1) && device_template[i]) {  
  18.         snprintf(name, 64, device_template[i], 0);  
  19.         fd = open(name, O_RDWR, 0);  
  20.         i++;  
  21.     }  
  22.     if (fd < 0)  
  23.         return -errno;  

        这段代码在首先在系统中检查是否存在设备文件/dev/graphics/fb0或者/dev/fb0。如果存在的话,那么就调用函数open来打开它,并且将得到的文件描述符保存在变量fd中。这样,接下来函数mapFrameBufferLocked就可以通过文件描述符fd来与内核中的帧缓冲区驱动程序交互。
 
        继续往下看函数mapFrameBufferLocked:
  1. struct fb_fix_screeninfo finfo;  
  2. if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)  
  3.     return -errno;  
  4.   
  5. struct fb_var_screeninfo info;  
  6. if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)  
  7.     return -errno;  
       这几行代码分别通过IO控制命令FBIOGET_FSCREENINFO和FBIOGET_VSCREENINFO来获得系统帧缓冲区的信息,分别保存在fb_fix_screeninfo结构体finfo和fb_var_screeninfo结构体info中。
 
        再往下看函数mapFrameBufferLocked:
  1.     info.reserved[0] = 0;  
  2.     info.reserved[1] = 0;  
  3.     info.reserved[2] = 0;  
  4.     info.xoffset = 0;  
  5.     info.yoffset = 0;  
  6.     info.activate = FB_ACTIVATE_NOW;  
  7.   
  8. #if defined(NO_32BPP)  
  9.     /* 
  10.      * Explicitly request 5/6/5 
  11.      */  
  12.     info.bits_per_pixel = 16;  
  13.     info.red.offset     = 11;  
  14.     info.red.length     = 5;  
  15.     info.green.offset   = 5;  
  16.     info.green.length   = 6;  
  17.     info.blue.offset    = 0;  
  18.     info.blue.length    = 5;  
  19.     info.transp.offset  = 0;  
  20.     info.transp.length  = 0;  
  21. #endif  
  22.   
  23.     /* 
  24.      * Request NUM_BUFFERS screens (at lest 2 for page flipping) 
  25.      */  
  26.     info.yres_virtual = info.yres * NUM_BUFFERS;  
  27.   
  28.   
  29.     uint32_t flags = PAGE_FLIP;  
  30.     if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {  
  31.         info.yres_virtual = info.yres;  
  32.         flags &= ~PAGE_FLIP;  
  33.         LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");  
  34.     }  
  35.   
  36.     if (info.yres_virtual < info.yres * 2) {  
  37.         // we need at least 2 for page-flipping  
  38.         info.yres_virtual = info.yres;  
  39.         flags &= ~PAGE_FLIP;  
  40.         LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",  
  41.                 info.yres_virtual, info.yres*2);  
  42.     }  
       这段代码主要是用来设置设备显示屏的虚拟分辨率。在前面 Android系统的开机画面显示过程分析 一文提到,结构体fb_var_screeninfo的成员变量xres和yres用来描述显示屏的可视分辨率,而成员变量xres_virtual和yres_virtual用来描述显示屏的虚拟分辨率。这里保持可视分辨率以及虚拟分辨率的宽度值不变,而将虚拟分辨率的高度值设置为可视分辨率的高度值的NUM_BUFFERS倍。NUM_BUFFERS是一个宏,它的值被定义为2。这样,我们就可以将系统帧缓冲区划分为两个图形缓冲区来使用,即可以通过硬件来实现双缓冲技术。
 
       在结构体fb_var_screeninfo中,与显示屏的可视分辨率和虚拟分辨率相关的另外两个成员变量是xoffset和yoffset,它们用来告诉帧缓冲区当前要渲染的图形缓冲区是哪一个,它们的使用方法可以参考前面 Android系统的开机画面显示过程分析 一文。
       这段代码在设置设备显示屏的虚拟分辨率之前,还会检查是否定义了宏NO_32BPP。如果定义了的话,那么就说明系统显式地要求将帧缓冲区的像素格式设置为HAL_PIXEL_FORMAT_RGB_565。在这种情况下,这段代码就会通过fb_var_screeninfo结构体info的成员变量bits_per_pixel、red、green、blue和transp来通知帧缓冲区驱动程序使用HAL_PIXEL_FORMAT_RGB_565像素格式来渲染显示屏。
        这段代码最终是通过IO控制命令FBIOPUT_VSCREENINFO来设置设备显示屏的虚拟分辨率以及像素格式的。如果设置失败,即调用函数ioctl的返回值等于-1,那么很可能是因为系统帧缓冲区在硬件上不支持双缓冲,因此,接下来的代码就会重新将显示屏的虚拟分辨率的高度值设置为可视分辨率的高度值,并且将变量flags的PAGE_FLIP位置为0。

        另一方面,如果调用函数ioctl成功,但是最终获得的显示屏的虚拟分辨率的高度值小于可视分辨率的高度值的2倍,那么也说明系统帧缓冲区在硬件上不支持双缓冲。在这种情况下,接下来的代码也会重新将显示屏的虚拟分辨率的高度值设置为可视分辨率的高度值,并且将变量flags的PAGE_FLIP位置为0。
        再继续往下看函数mapFrameBufferLocked:
  1. if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)  
  2.     return -errno;  
  3.   
  4. uint64_t  refreshQuotient =  
  5. (  
  6.         uint64_t( info.upper_margin + info.lower_margin + info.yres )  
  7.         * ( info.left_margin  + info.right_margin + info.xres )  
  8.         * info.pixclock  
  9. );  
  10.   
  11. /* Beware, info.pixclock might be 0 under emulation, so avoid a 
  12.  * division-by-0 here (SIGFPE on ARM) */  
  13. int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;  
  14.   
  15. if (refreshRate == 0) {  
  16.     // bleagh, bad info from the driver  
  17.     refreshRate = 60*1000;  // 60 Hz  
  18. }  

        这段代码再次通过IO控制命令FBIOGET_VSCREENINFO来获得系统帧缓冲区的可变属性信息,并且保存在fb_var_screeninfo结构体info中,接下来再计算设备显示屏的刷新频率。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/967078,如需转载请自行联系原作者
目录
相关文章
|
4月前
|
存储 编解码 网络协议
Android平台GB28181执法记录仪硬件选型和国标技术实现探讨
前几年,我们在做Android平台GB28181设备接入模块的时候,第一个使用场景想到的就是用在公检法应急指挥等场景下的执法记录仪,本篇blog,我们主要围绕Android平台GB28181执法记录仪的硬件选型、设备接入、音视频流配置、流媒体传输、存储和管理、控制与控制中心等方面进行设计,探讨下Android平台GB28181设备接入模块在执法记录仪行业的应用。
Android平台GB28181执法记录仪硬件选型和国标技术实现探讨
|
4月前
|
编解码 网络协议 前端开发
如何实现Android平台GB28181设备接入模块按需打开摄像头并回传数据
后台采集摄像头,如果想再进一步扩展,可以把android平台gb28181的camera2 demo,都移植过来,实现功能更强大的国标设备侧,这里主要是展示,收到国标平台侧的回传请求后,才打开摄像头,才开始编码打包,最大限度的减少资源的占用
|
4月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
4月前
|
监控 Java 开发工具
如何快速对接Android平台GB28181接入模块(SmartGBD)
大牛直播SDK推出的Android平台GB28181接入SDK(SmartGBD),可实现不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181—2016服务,可用于如执法记录仪、智能安全帽、智能监控、智慧零售、智慧教育、远程办公、明厨亮灶、智慧交通、智慧工地、雪亮工程、平安乡村、生产运输、车载终端等场景,可能是业内为数不多功能齐全性能优异的商业级水准GB28181接入SDK。
|
4月前
|
编解码 开发工具 Android开发
Android平台RTMP直播推送模块技术接入说明
大牛直播SDK跨平台RTMP直播推送模块,始于2015年,支持Windows、Linux(x64_64架构|aarch64)、Android、iOS平台,支持采集推送摄像头、屏幕、麦克风、扬声器、编码前、编码后数据对接,功能强大,性能优异,配合大牛直播SDK的SmartPlayer播放器,轻松实现毫秒级的延迟体验,满足大多数行业的使用场景。RTMP直播推送模块数据源,支持编码前、编码后数据对接
|
4月前
|
监控 开发工具 Android开发
结合GB/T28181规范探讨Android平台设备接入模块心跳实现
本文介绍了GB28181标准中的状态信息报送机制,即心跳机制,用于监控设备与服务器间的连接状态。根据国标GB/T28181-2016,设备在异常时需立即发送状态信息,在正常状态下则按固定间隔(默认60秒)定期发送。若连续三次(默认值)未收到心跳,则视为离线。文章展示了在Android平台的GB28181设备接入模块(SmartGBD)中,如何调整心跳间隔为20秒及超时次数为3次,并给出了心跳消息的示例和异常处理代码片段。对于希望深入了解或遇到问题的开发者,作者提供了进一步交流的机会。
|
4月前
|
编解码 API 开发工具
Android平台轻量级RTSP服务模块二次封装版调用说明
本文介绍了Android平台上轻量级RTSP服务模块的二次封装实践,旨在简化开发流程,让开发者能更专注于业务逻辑。通过`LibPublisherWrapper`类提供的API,可在应用中轻松初始化RTSP服务、配置视频参数(如分辨率、编码类型)、启动与停止RTSP服务及流发布,并获取RTSP会话数量。此外,还展示了如何处理音频和视频数据的采集与推送。最后,文章提供了从启动服务到销毁资源的完整示例,帮助开发者快速集成实时流媒体功能。
|
4月前
|
编解码 开发工具 Android开发
Android平台轻量级RTSP服务模块技术接入说明
为满足内网无纸化/电子教室等内网超低延迟需求,避免让用户配置单独的服务器,大牛直播SDK在推送端发布了轻量级RTSP服务SDK。 轻量级RTSP服务解决的核心痛点是避免用户或者开发者单独部署RTSP或者RTMP服务,实现本地的音视频数据(如摄像头、麦克风),编码后,汇聚到内置RTSP服务,对外提供可供拉流的RTSP URL,轻量级RTSP服务,适用于内网环境下,对并发要求不高的场景,支持H.264/H.265,支持RTSP鉴权、单播、组播模式,考虑到单个服务承载能力,我们支持同时创建多个RTSP服务,并支持获取当前RTSP服务会话连接数。
|
7月前
|
Android开发
Android 集成vendor下的模块
Android 集成vendor下的模块
63 0
|
7月前
|
Java 物联网 Linux
Android硬件通信之 串口通信
Android硬件通信之 串口通信
115 0