对于每个人来说,像素这个词并不陌生。在各大手机厂商的新品发布会上经常出现的一个词就是xxx手机有多少像素和高分辨率。那么这里所说的手机像素是什么意思呢?以500万像素为例,是指一英寸CCD面积上有500万像素,500万像素的分辨率为2592*1944或2560*1920。积木就像一个像素。针对像素格式,介绍并分析其在图形显示系统中的实现原理和细节。像素格式基本概念像素格式描述了用于存储像素数据的格式,并定义了像素在内存中的编码方式。像素表示下图标识了在不同应用场景中看到的像素格式的不同表示。尽管像素格式不同,但它们都服务于相同的目的:呈现色彩空间。颜色空间的不同表示bppbpp这个参数在代码中经常可见。例如在申请创建framebuffer函数的libdrm代码中,将bpp作为创建framebuffer的入参。staticstructbo*bo_create_dumb(intfd,unsignedintwidth,unsignedintheight,unsignedintbpp){...arg.bpp=bpp;arg.width=width;arg.height=height;ret=drmIoctl(fd,DRM_IOCTL_MODE_CREATE_DUMB,&arg);...回报;}bpp:bitsperpixel,简称像素深度。其含义是每个像素所占用的二进制位数。比如fourcc中定义的像素格式,会表示它占用的位数。/*8bppRGB*/#defineDRM_FORMAT_RGB332fourcc_code('R','G','B','8')/*16bppRGB*/#defineDRM_FORMAT_XRGB4444fourcc_code('X','R','1','2')/*24bppRGB*/#defineDRM_FORMAT_RGB888fourcc_code('R','G','2','4')/*32bppRGB*/#defineDRM_FORMAT_XRGB8888fourcc_code('X','R','2','4')跨入内核代码它也变成音调。准确的说,stride是framebuffer的概念,它规定了每行像素占用的内存空间。为了内存对齐,通常stride>=bppN。如果使用libdrm,在应用层填充像素数据时不考虑对齐。步幅==bppN。但是步长会在驱动代码中对齐,例如:inti915_gem_dumb_create(structdrm_file*file,structdrm_device*dev,structdrm_mode_create_dumb*args){intcpp=DIV_ROUND_UP(args->bpp,8);.../*havetoworkoutsize/pitchandreturnthem*/args->pitch=ALIGN(args->width*cpp,64);...returni915_gem_create(file,to_i915(dev),&args->size,&args->handle);}创建的framebuffer如图下图:亮度亮度在图形显示系统中称为亮度。YUV格式的像素Y分量在这里变得相关。亮度最低时,画面为黑色;当亮度最高时,画面是白色的。对于bpp小于32的液晶屏,亮度是通过PWM调节背光来实现的。最暗和最亮的RGBRGB是代表红、绿、蓝三个通道的颜色。通过三者不同程度的叠加,构成了人类视觉所能感知的所有颜色。它是使用最广泛的颜色系统之一。RGB按色深分为1位、8位、16位、24位、32位。可以根据RGB数据格式的特点构造图像数据,将构造好的数据填入DRM帧缓冲区,由图形处理器取出并发送给显示设备。代码实现如下。构造RGB16图像代码:staticvoidfill_tiles_rgb16(conststructutil_format_info*info,void*mem,unsignedintwidth,unsignedintheight,unsignedintstride){conststructutil_rgb_info*rgb=&info->rgb;void*mem_base=mem;unsignedintx,y;for(y=0;y;;++y){for(x=0;x>6)+0x000a1120*(d.rem>>6);uint16_tcolor=MAKE_RGBA(rgb,(rgb32>>16)&0xff,(rgb32>>8)&0xff,rgb32&0xff,255);((uint16_t*)mem)[x]=颜色;}mem+=步幅;}make_pwetty(mem_base,width,height,stride,info->format);}构建RGB24图像代码:staticvoidfill_tiles_rgb24(conststructutil_format_info*info,void*mem,unsignedintwidth,unsignedintheight,unsignedintstride){conststructutil_rgb_info*rgb=&info->rgbunsignedintx,y;for(y=0;y>6)+0x000a1120*(d.rem>>6);structcolor_rgb24color=MAKE_RGB24(rgb,(rgb32>>16)&0xff,(rgb32>>8)&0xff,rgb32&0xff);((structcolor_rgb24*)mem)[x]=color;}mem+=stride;}}构建RGB32图像代码:staticvoidfill_tiles_rgb32(conststructutil_format_info*info,void*mem,unsignedintwidth,unsignedinheight,unsignedintstride){conststructutil_rgb_info*rgb=&info->rgb;void*mem_base=mem;unsignedintx,y;for(y=0;y>6)+0x000a1120*(d.rem>>6);uint32_talpha=((y>16)&0xff,(rgb32>>8)&0xff,rgb32&0xff,alpha);((uint32_t*)mem)[x]=color;}mem+=stride;}make_pwetty(mem_base,width,height,stride,info->format);}YUVYUV表示颜色空间中的亮度和色度,主要用于视频传输和显示其中Y表示亮度(Luminance,Luma),U和V代表色度(Chrominance,Chroma)。另外,在视频压缩和传输过程中也会看到YCbCr的概念。其实两者在本质上基本是一样的。YUV的优点之一是色度通道的采样率低于Y通道,而不会显着降低感知质量。YUV采样各个视频设备厂商或编码芯片厂商定义了多种A:B:C格式的YUV采纳规则。4:4:4表示不对色度通道进行下采样,其中圆圈代表Y,X代表UV,以下类似。4:2:2表示2:1水平下采样,没有垂直下采样。每两条扫描线包含四个Y样本,对应两个U或V样本。4:2:0表示水平下采样2:1,垂直下采样2:1。YUV存储YUV存储分为packed格式和planar格式。打包格式将Y、U和V分量打包到一个数组中。像素被组织成一组宏像素,其布局取决于格式。如YUYV,即1平面。planarformatplanarformat就是将Y、U、V三个分量存储为三个独立的平面。如I420、YV12,即3个平面。此外,还可以支持半平面。Y连续存储,U和V交错,如NV21和NV12,即2个平面。对于不同的YUV表示,它们在内存中的排列方式不同。YUV444存储格式YUV422存储格式结构YUV图像结构YUV打包图像代码如下:mem:mem+1;unsignedchar*c_mem=(yuv->order&YUV_CY)?mem:mem+1;unsignedintu=(yuv->order&YUV_YCrCb)?2:0;unsignedintv=(yuv->order&YUV_YCbCr)?2:0;unsignedintx;unsignedinty;for(y=0;y>6)+0x000a1120*(d.rem>>6);structcolor_yuvcolor=MAKE_YUV_601((rgb32>>16)&0xff,(rgb32>>8)&0xff,rgb32&0xff);y_mem[2*x]=颜色。y;c_mem[2*x+u]=color.u;y_mem[2*x+2]=color.y;c_mem[2*x+v]=color.v;}y_mem+=stride;c_mem+=stride;}}构造YUV平面图代码如下:staticvoidfill_tiles_yuv_planar(conststructutil_format_info*info,unsignedchar*y_mem,unsignedchar*u_mem,unsignedchar*v_mem,unsignedintwidth,unsignedinheight,unsignedintstride){conststructutil_yuv_info*yuv=&info->yuv;unsignedintcs=yuv->chroma_stride;unsignedintxsub=yuv->xsub;unsignedintysub=yuv->ysub;unsignedintx;unsignedinty;y>6)+0x000a1120*(d.rem>>6);structcolor_yuvcolor=MAKE_YUV_601((rgb32>>16)&0xff,(rgb32>>8)&0xff,rgb32&0xff);y_mem[x]=color.y;u_mem[x/xsub*cs]=颜色。u;v_mem[x/xsub*cs]=color.v;}y_mem+=stride;if((y+1)%ysub==0){u_mem+=stride*cs/xsub;v_mem+=stride*cs/xsub;}}}本文转载自微信公众号“Linux与SoC”,您可以通过以下二维码关注转载文章,请联系Linux与SoC公众号。