数码相册——main_page主界面的显存管理、页面规划、输入控制

  • 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
  • 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
  • 参考资料:《嵌入式Linux应用开发手册》、《嵌入式Linux应用开发手册第2版》
  • 开发环境:Linux 3.4.2内核、arm-linux-gcc 4.3.2工具链
  • 源码仓库:https://gitee.com/d_1254436976/Embedded-Linux-Phase-3

目录

  • 数码相册——main_page主界面的显存管理、页面规划、输入控制
    • 一、前言
    • 二、main_page页面的实现
      • 1、关键的结构体
      • 2、显存管理
        • 2.1 思想
        • 2.2 具体的实现
      • 3、页面规划与显示
        • 3.1 思想
        • 3.2 具体的实现
      • 4、触摸输入的设置
        • 4.1 思想
        • 4.2 具体实现
    • 三、编译与运行
      • 1、编译
      • 2、运行

一、前言

在【1.9 数码相册—在LCD上显示BMP图片】中,实现了在LCD中显示bmp图片,对bmp图片的二进制数据有了一定的了解,在这篇博文中,实现page_manager页面管理者的相关函数以及main_page主页面的测试,实现如下目的:

  1. 有效的管理内存,实现页面的快速刷新
  2. 合理的规划页面空间,达到较好的显示效果
  3. 有效的输入区域实现触控的效果

二、main_page页面的实现

由于需要程序改动的地方过多,所以这篇博文会比较侧重于描述思想与方法,其思想与方法同样适用于其他页面,这里只是用main_page来介绍。

1、关键的结构体

/* 描述图片信息 */
typedef struct PixelDatas{int bpp;                   //图片的bppint width;                 //图片的宽度int height;                 //图片的高度int linebytes;              //图片每行占据的字节数int TotalBytes;                //图片总大小unsigned char *PixelDatas;   //存储图片具体像素数据的首地址
}T_PixelDatas, *PT_PixelDatas;/* 页面内存数据是否被使用 */
typedef enum {VMS_FREE = 0,               //空闲VMS_USED_FOR_PREPARE,     //子线程占用VMS_USED_FOR_CURMAIN,      //当前主线程占用
}E_VideoMemState;/* 页面内存数据是否已准备好 */
typedef enum {PS_BLANK = 0,               //数据空白PS_GENERATING,              //数据生成中PS_GENERATED,              //数据完毕
}E_PicState;/* 描述页面内存块 */
typedef struct VideoMem {int id;                         //页面内存的idint isDevFB;                   //当前描述的内存是否为Framebuffer:1-是,2-否E_VideoMemState eVideoMemState; //描述该页面内存数据的使用状态E_PicState ePicState;         //描述该页面内存数据是否已准备好T_PixelDatas tPixelDatas;        //描述图片信息struct VideoMem *ptNext;       //指向下一结点的指针
}T_VideoMem, *PT_VideoMem;

2、显存管理

2.1 思想

对于页面的显示LCD与Framebuffer之间通过LCD控制器来进行像素信息的传递,当我们需要显示图片时,只需要在Framebuffer中写入颜色信息就可以在LCD上显示出来。
应用程序过大,会导致显示的很慢,此时需要优化措施

  1. 在内存中开辟一个与Framebuffer大小相同的内存空间
  2. 提前把需要显示的内容写到新开辟的内存空间中;(3、页面规划与显示中介绍)
  3. 需要显示时,直接把新开辟的内存空间memcpyFramebuffer。(3、页面规划与显示中介绍)

2.2 具体的实现

  • 步骤描述:
/*---------------------------显存管理----------------------------------------*/
页面管理内存 = 页面描述信息 + 显存int AllocVideoMem(int num)函数:1. 获得LCD显示设备的分辨率以及bpp,计算得到需要开辟内存空间的大小(单位:byte)以及行宽(单位:byte)2. 先把设备本身的Framebuffer放入链表2.1 开辟一个大小为sizeof(T_VideoMem)内存,用来存放页面描述信息,地址放在ptNew结构体指针中2.2 根据1中获取的信息设置该内存的描述信息,以及把Framebuffer的地址放入结构体变量中2.3 强制设置其eVideoMemState状态位为占用状态2.4 采用头插法插入链表3. 后根据num分配用于页面管理的内存并设置结构体3.1 开辟一个大小为sizeof(T_VideoMem) + VMSize内存,用来存放页面描述信息与显存,地址放在ptNew结构体指针中3.2 根据1获得的信息,设置该内存的描述信息与显存的地址3.3 采用头插法插入链表
  • 代码实现:
int AllocVideoMem(int num)
{int i;int bpp;int linebytes;int xres, yres;int VMSize;PT_VideoMem ptNew;PT_VideoMem ptTmp;bpp = yres = xres = 0;GetDispResolution(&xres, &yres, &bpp);VMSize    = xres * yres * bpp / 8;linebytes = xres * bpp / 8;/* 1、先把设备本身的Framebuffer放入链表 */ptNew = (PT_VideoMem)malloc(sizeof(T_VideoMem));if (ptNew == NULL) {DebugPrint(APP_ERR"Framebuffer set fail!\n");goto fail;}/* 设置该内存所描述页面的信息 */ptNew->id                       = 0;ptNew->isDevFB                  = 1;ptNew->eVideoMemState         = VMS_FREE;ptNew->ePicState              = PS_BLANK;ptNew->tPixelDatas.bpp        = bpp;ptNew->tPixelDatas.height     = yres;ptNew->tPixelDatas.width      = xres;ptNew->tPixelDatas.linebytes  = linebytes;       ptNew->tPixelDatas.PixelDatas = s_ptDefaultDispOpr->pDispMem;ptNew->tPixelDatas.TotalBytes = VMSize;/* 强制设置设备本身的Framebuffer状态为被占用 */if (num != 0)ptNew->eVideoMemState = VMS_USED_FOR_CURMAIN;/* 头插法插入链表 */ptNew->ptNext = s_ptVieoMemHead;s_ptVieoMemHead = ptNew;/* 2、后分配用于页面管理的内存并设置结构体,组成:页面描述 + 显存 */for (i = 0; i < num; i++) {ptNew = (PT_VideoMem)malloc(sizeof(T_VideoMem) + VMSize);if (ptNew == NULL) {DebugPrint(APP_ERR"ptNew malloc fail,already malloc num: %d!\n", i);goto fail;}/* 设置该内存所描述页面的信息 */ptNew->id                    = 0;ptNew->isDevFB                  = 0;ptNew->eVideoMemState         = VMS_FREE;ptNew->ePicState              = PS_BLANK;ptNew->tPixelDatas.bpp        = bpp;ptNew->tPixelDatas.height     = yres;ptNew->tPixelDatas.width      = xres;ptNew->tPixelDatas.linebytes  = linebytes;       ptNew->tPixelDatas.PixelDatas = (unsigned char *)(ptNew + 1);ptNew->tPixelDatas.TotalBytes = VMSize;/* 头插法插入链表 */ptNew->ptNext = s_ptVieoMemHead;s_ptVieoMemHead = ptNew;}return 0;fail:while (s_ptVieoMemHead) {ptTmp = s_ptVieoMemHead->ptNext;free(s_ptVieoMemHead);s_ptVieoMemHead = ptTmp;}return -1;
}

3、页面规划与显示

3.1 思想

  • 页面规划:
    为了适应多种尺寸的LCD设备以及良好的视觉感受,所以图标的尺寸计算如下:(不通用于其他页面,每个页面都需要制定不同的方案
  • 显示:
    对于多个页面的显示与切换,需要大致做到以下步骤:
    1、获得该页面的显存
    2、描画该页面内存的显示数据
    3、刷新到显示设备的Framebuffer

3.2 具体的实现

  • 部分使用到的函数介绍
/*---------------------GetPixelDatasForIcon()函数-获取图标的像素数据---------------------*/
// 函数的实现步骤:
int GetPixelDatasForIcon(char *strFileName, int DevBpp, PT_PixelDatas ptPixelDatas)函数:1. 根据strFileName变量以及宏定义的图标存放目录,组织出图标的具体位置2. 调用MapFile()函数,获取图标文件信息并进行内存映射3. 判断该文件是否符合bpp编码不符合则返回,不进行下面的处理符合则进行图标文件像素信息的获取4. 调用GetPixelDatasFrmBMP(),获取图片的bmp像素信息// 函数的代码实现:
int GetPixelDatasForIcon(char *strFileName, int DevBpp, PT_PixelDatas ptPixelDatas)
{int error;T_FileMap tFileMap;/* 存入文件的目录名字与文件名 */snprintf(tFileMap.strFileName, 128, "%s/%s", ICON_PATH, strFileName);tFileMap.strFileName[127] = '\0';/* 获取文件信息并进行映射 */error = MapFile(&tFileMap);if (error != 0) {DebugPrint(APP_ERR"MapFile err! File:%s Line:%d \n", __FILE__, __LINE__);return -1;}/* 判断文件是否支持 */error = s_tBMPParser.isSupport(tFileMap.pFileMem);if (error != 1) {DebugPrint(APP_ERR"Can not support %s! File:%s Line:%d \n", tFileMap.strFileName , __FILE__, __LINE__);return -1;}ptPixelDatas->bpp = DevBpp;/* 获取图片像素信息 */error = s_tBMPParser.GetPixelDatas(tFileMap.pFileMem, ptPixelDatas);if (error == -1) {DebugPrint(APP_ERR"File:%s Function:%s Line:%d err!\n", __FILE__, __FUNCTION__, __LINE__);return -1;}return 0;
}/*-------------MapFile()函数-获取文件信息,并对文件进行映射----------------*/
// 函数的实现步骤:
MapFile(PT_FileMap ptFileMap)函数:1. open()打开图标文件,获得文件描述符2. fstat()获得文件大小信息3. 根据以上得到的数据,进行内存的映射4. 设置该映射文件的ptFileMap结构体的信息:文件描述符与文件大小// 函数的代码实现:
int MapFile(PT_FileMap ptFileMap)
{int fd;   struct stat tStat;/* 打开bmp文件 */fd = open(ptFileMap->strFileName, O_RDWR);if (fd == -1) {DebugPrint(APP_ERR"can not open %s! File:%s Line:%d \n\n", ptFileMap->strFileName, __FILE__, __LINE__);return -1;}/* 获得文件的大小 */fstat(fd, &tStat);/* 直接映射到内存 */ptFileMap->pFileMem = (unsigned char *)mmap(NULL, tStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (ptFileMap->pFileMem == (unsigned char *)-1) {DebugPrint(APP_ERR"ptFileMap->pFileMem mmap err! \File:%s Line:%d \n", __FILE__, __LINE__);return -1;}/* 设置结构体信息 */ptFileMap->FileFd   = fd;ptFileMap->FileSize = tStat.st_size;return 0;
}/*-----------------GetPixelDatasFrmBMP()函数---------------------------------------------*-----------从bmp文件中获取像素数据,并分配缓冲区存放像素信息,供外部文件调用---------------*/// 函数的实现步骤:
int GetPixelDatasFrmBMP(unsigned char *pFileHead, PT_PixelDatas ptPixelDatas)1. 根据bmp的编码规范,利用结构体表示bmp二进制数据中每几个字节所代表的含义2. 根据上述结构体的信息,获得bmp文件的高度、宽度、行宽(单位:byte),存储在ptPixelDatas结构体对应的变量中3. 根据上述高度、宽度、行宽计算得到整个bmp文件的大小,分配对应内存,首地址存储在ptPixelDatas结构体对应的变量中4. 由于bmp编码的特殊性(开始存储的是左下角图片的像素信息),通过数学计算找到bmp源文件左上角的像素信息,存储到源文件的像素信息到3中开辟的内存中// 函数的代码实现:
int GetPixelDatasFrmBMP(unsigned char *pFileHead, PT_PixelDatas ptPixelDatas)
{int y;int width;int height;int BMPbpp;int LineWidthReal;int LineWidthAlign;unsigned char *pSrc;unsigned char *pDest;BITMAPFILEHEADER *ptBITMAPFILEHEADER;BITMAPINFOHEADER *ptBITMAPINFOHEADER;ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)pFileHead;ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(pFileHead + sizeof(BITMAPFILEHEADER));/* 获取bmp文件信息 */width  = ptBITMAPINFOHEADER->biWidth;height = ptBITMAPINFOHEADER->biHeight;BMPbpp = ptBITMAPINFOHEADER->biBitCount;if (BMPbpp != 24) {DebugPrint(APP_ERR"can not support %d bpp\n", BMPbpp);return -1;}/* 设置结构体 */ptPixelDatas->height      = height;ptPixelDatas->width       = width;ptPixelDatas->linebytes   = width * ptPixelDatas->bpp / 8;/* 分配缓冲区 */ptPixelDatas->PixelDatas = (unsigned char *)malloc(width * height * ptPixelDatas->bpp / 8);if (ptPixelDatas->PixelDatas == NULL) {DebugPrint(APP_ERR"malloc ptPixelDatas->PixelDatas err\n");return -1;}/* 获取bmp像素信息:存储像素的起始是图片左下角 */LineWidthReal  = width * BMPbpp / 8; //每行像素所占的字节LineWidthAlign = (LineWidthReal + 3) & ~0x3;     //向4取整后的每行像素所占的字节pSrc = pFileHead + ptBITMAPFILEHEADER->bfOffBits; //像素信息的源地址pSrc = pSrc + LineWidthAlign * (height- 1);         //移动到存储图片左上角的数据地址pDest = ptPixelDatas->PixelDatas; //数据最终的去向for (y = 0; y < height; y++) {//memcpy(pDest, pSrc, LineWidthReal);CoverOneLine(width, BMPbpp, ptPixelDatas->bpp, pSrc, pDest);pSrc  -= LineWidthAlign;    //bmp二进制数据pDest += ptPixelDatas->linebytes;        //LCD显示数据}return 0;
}
  • 步骤描述:
/*---------------------------页面规划----------------------------------------*/
// 步骤1:获得显存ptVideoMem = GetVideoMem(ID("main"), 1);遍历寻找对应页面内存:1.1 优先策略:取出空闲并页面ID相同的videomem页面内存,设置其eVideoMemState状态位注意:一开始链表中所有节点页面ID都为01.2 择优策略:1.1条件不成立,取出任意一个空闲的videomem页面内存,设置其id、eVideoMemState状态位、ePicState页面数据状态位// 步骤2:描画数据需要判断ePicState页面数据状态位是否处于准备完毕状态:若是则表示数据已经准备好,则直接进行步骤3否则进行如下措施:2.1 获得LCD显示设备的分辨率以及bpp2.2 根据事先约定的LCD上的页面规划,进行图标的尺寸计算2.3 根据上述数据,计算并设置该页面内存的描述信息:height高度、width宽度、bpp、linebytes行宽(单位:byte)、TotalBytes显示页面的内存大小(单位:byte)2.4 根据TotalBytes的数据来malloc分配存储LCD显示的图片数据的内存,把内存的首地址存储到页面内存的PixelDatas2.5 描绘该页面的需要显示的图标源bmp信息 2.5.1 调用GetPixelDatasForIcon(),获取每个图标的bmp像素信息2.5.2 调用PicZoom(),根据2.2中获得的LCD显示的图标信息与2.5.1获得的源bmp文件信息,采用近邻取样插值,对LCD显示的图标的像素信息进设置2.5.3 调用PicMerge(),根据2.5.2获得的LCD显示的图标信息,把数据整合到2.4中的页面内存的PixelDatas所指向的内存中2.5.4 调用FreePixelDatasForIcon(),释放2.5.1中所开辟的内存移动到下一个图标的在LCD中显示的位置2.6 释放2.4中所开辟的内存,并更新该页面的ePicState页面数据状态位为数据完毕位// 步骤3:刷新设备FlushVideoMemToDev(ptVideoMem);根据ptVideoMem->isDevFB位判断是否直接操作Framebuffer显存是则不进行下步骤不是则:3.1 获得显示设备的结构体3.2 调用该结构体的ShowPage(),进行memcpy内存块的拷贝
  • 函数的实现
static void ShowMainPage(PT_Layout ptLayout)
{int xres;int yres;int bpp;int error;int IconX;int IconY;int IconWidth;int IconHeight;PT_VideoMem ptVideoMem;T_PixelDatas tOriginIconPixelDatas;T_PixelDatas tZoomIconPixelDatas;/* 获得显存 */ptVideoMem = GetVideoMem(ID("main"), 1);if (ptVideoMem == NULL) {DebugPrint(APP_ERR"Can not get video mem for main_page!\n");return ;}/* 描画数据 */if (ptVideoMem->ePicState != PS_GENERATED) {GetDispResolution(&xres, &yres, &bpp);/* 计算图标尺寸信息 */IconHeight = yres * 1 / 5;IconWidth  = yres * 2 / 5;IconX      = (xres - IconWidth) / 2;IconY      = yres / 10;/* 设置LCD显示的图片的信息 */tZoomIconPixelDatas.height     = IconHeight;tZoomIconPixelDatas.width      = IconWidth;tZoomIconPixelDatas.bpp        = bpp;tZoomIconPixelDatas.linebytes  = IconWidth * bpp / 8;tZoomIconPixelDatas.TotalBytes = tZoomIconPixelDatas.linebytes * IconHeight;/* 分配存储LCD显示的图片数据的内存 */tZoomIconPixelDatas.PixelDatas = (unsigned char *)malloc(tZoomIconPixelDatas.TotalBytes);if (tZoomIconPixelDatas.PixelDatas == NULL) {free(tZoomIconPixelDatas.PixelDatas);  //释放内存DebugPrint(APP_ERR"Malloc err! File:%s Line:d\n", __FILE__, __LINE__);return ;}/* 描绘每个图片的坐标信息 */while (ptLayout->strIconName) {/* 计算图标坐标信息 */ptLayout->TopLeftX  = IconX;ptLayout->TopLeftY  = IconY;ptLayout->BotRightX = IconX + IconWidth  - 1;ptLayout->BotRightY = IconY + IconHeight - 1;/* 获取图片像素信息 */error = GetPixelDatasForIcon(ptLayout->strIconName, bpp, &tOriginIconPixelDatas);if (error == -1) {DebugPrint(APP_ERR"GetPixelDatasForIcon err! File:%s Line:%d\n", __FILE__, __LINE__);return ;}/* 对图片的缩放参数进行设置 */PicZoom(&tOriginIconPixelDatas, &tZoomIconPixelDatas);/* 把缩放后的图片信息整合到ptVideoMem.tPixelDatas中 */PicMerge(IconX, IconY, &tZoomIconPixelDatas, &ptVideoMem->tPixelDatas);FreePixelDatasForIcon(&tOriginIconPixelDatas);IconY +=  yres * 3 / 10;ptLayout++;}free(tZoomIconPixelDatas.PixelDatas); //释放内存ptVideoMem->ePicState = PS_GENERATED;    //更新状态}/* 刷新/加载到设备 */FlushVideoMemToDev(ptVideoMem);/* 设置页面内存为空闲状态 */PutVideoMem(ptVideoMem);
}

4、触摸输入的设置

4.1 思想

对于页面中需要显示的图标,每个图标都有对应的有效触摸区域。当用户触摸到对应的区域时,进入不同的页面(未实现,下篇博客实现)且该图标的颜色变化
由于这里使用到输入系统,即【1.7 数码相册—电子书(5)—多线程支持多输入】中介绍的,会使用到触摸屏子线程与tslib库

4.2 具体实现

  • 部分使用的函数介绍
/*---------------MainPageGetInputEvent()-main页面输入事件函数------------------------*/
// 函数的实现步骤:
static int MainPageGetInputEvent(PT_Layout ptLayout, PT_InputEvent ptInputEvent)函数:1. 调用之前写的GetInputEvent(),进入输入事件子线程,获得原始的输入事件数据2. 限制条件:只允许输入事件的类型为INPUT_TYPE_TOUCHSCREEN触摸屏输入事件3. 根据调用tslib库所获得触点的坐标,比较与"步骤2:描画数据"2.2获得的每个图标的LCD页面规划坐标定位触点所在的图标,返回该图标的索引4. 寻找不到则返回-1// 函数的代码实现:
static int MainPageGetInputEvent(PT_Layout ptLayout, PT_InputEvent ptInputEvent)
{int i;int ret;T_InputEvent tInputEvent;/* 调用input_manager.c的函数,获得原始的输入数据 */ret = GetInputEvent(&tInputEvent);if (ret != 0) {DebugPrint(APP_ERR"GetInputEvent err! File:%s Line:%d\n", __FILE__, __LINE__);return -1;}*ptInputEvent = tInputEvent;/* 限制条件 */if (tInputEvent.type != INPUT_TYPE_TOUCHSCREEN)return -1;/* 处理数据 *//* 确定触点位于哪个图标上 */i = 0;while (ptLayout[i].strIconName) {if ((tInputEvent.x >= ptLayout[i].TopLeftX) && (tInputEvent.x <= ptLayout[i].BotRightX) \&& (tInputEvent.y >= ptLayout[i].TopLeftY) && (tInputEvent.y <= ptLayout[i].BotRightY))return i;elsei++;}/* 找不到对应图标 */return -1;
}
  • 步骤描述
/*---------------------------------输入触摸----------------------------------*/// 步骤1:获取输入事件与图标索引
index = MainPageGetInputEvent(s_tMainPageLayout, &tInputEvent);1. 调用MainPageGetInputEvent(),获得该页面的输入事件与对应图标的索引,由于调用到之前的输入事件子线程,所以在这里程序会处于休眠,有输入事件才唤醒index = -1;
indexPressured = -1;
pressured = 0;
//步骤2:根据反馈的情况进行不同的处理为了支持按下和松开的位置不一的情况,进行如下处理:pressured: 1-曾经按下 0-一直为按下indexPressured: 按下图标的索引2.1 若输入事件得到的压力值为0(松开) 且 pressured==1曾经按下,则调用ReleaseButton(),根据indexPressured,把图标颜色取反2.2 若输入事件得到的压力值为1(按下) 且 已经获得了按键的index索引 且 pressured==0未按下,则pressured= 1;indexPressured = index;PressButton(&s_tMainPageLayout[indexPressured]);把图标颜色取反
  • 代码实现
static int MainPageRun(void)
{int index;int pressured;int indexPressured;T_InputEvent tInputEvent;/* 显示页面 */ShowMainPage(s_tMainPageLayout);index = -1;indexPressured = -1;pressured = 0;/* 调用GetInputEvent(), 获得输入事件,进而处理 */while (1) {index = MainPageGetInputEvent(s_tMainPageLayout, &tInputEvent);/* 松开和按下不在同一个图标范围内 */if (tInputEvent.pressure == 0) {/* 曾经有按键按下 */if (pressured) {ReleaseButton(&s_tMainPageLayout[indexPressured]);pressured = 0;indexPressured = -1;}} else {/* 松开和按下都在同一个图标范围内 *//* 按下 */if (index != -1) {/* 之前未按下 */if (!pressured) {pressured = 1;indexPressured = index;PressButton(&s_tMainPageLayout[indexPressured]);}}}}return 0;
}

三、编译与运行

1、编译

执行make生成可执行文件digitpic文件

2、运行

  1. 可执行文件digitpic放入到根文件系统
  2. icon目录下的图标文件放入到根文件系统的/etc/digitpic/icons(程序打开图标文件时需要用到)
  3. 执行可执行文件,得到以下的效果:
    程序一开始进入main_page主界面按下与松开3个图标的位置,图标的颜色会反转



第三阶段应用层——1.10 数码相册—main_page主界面的显存管理、页面规划、输入控制相关推荐

  1. 计算机专业要用多大显卡,10条解答:玩LOL电脑显存一般需要多大啊?

    10个答案 1.播放LOL计算机通常需要多少视频内存 宿舍使用512.没关系.显卡为520m.它是独立的.如果网络速度不错,则完全不会卡死.当网络速度不佳时,您将无法行走.最好是图形卡为610或更高. ...

  2. 第三阶段应用层——2.7 视频监控—从零写CMOS摄像头驱动

    视频监控-从零写CMOS摄像头驱动 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3),OV7740摄像头 软件平台:运行于VMware Workstation 12 Player下Ubu ...

  3. 第三阶段应用层——2.6 视频监控—CMOS摄像头的硬件原理

    视频监控-CMOS摄像头的硬件原理 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3) 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.0 ...

  4. 第三阶段应用层——2.4 视频监控—从0写USB摄像头驱动(1)-描述符的分析与打印

    视频监控-从0写USB摄像头驱动(1)-描述符的分析与打印 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3) 软件平台:运行于VMware Workstation 12 Player下U ...

  5. 【Linux云计算架构:第三阶段-Linux高级运维架构】第25章—— 搭建jumperserver管理王者荣耀数万台游戏服务器

    本节内容: 34.1 Jumpserver堡垒机概述-部署Jumpserver运行环境 34.2 安装Coco组件 34.3 安装Web-Terminal前端-Luna组件-配置Nginx整合各组件 ...

  6. cuda第一次计算耗时_CUDA优化的冷知识10 | GPU卡和Jetson上显存优化的特色

    这一系列文章面向CUDA开发者来解读<CUDA C Best Practices Guide> (CUDA C最佳实践指南) 大家可以访问: 这是一本很经典的手册. CUDA优化的冷知识| ...

  7. 三种实现Android主界面Tab的方式

    转载于:https://www.cnblogs.com/caobotao/p/5103673.html 在平时的Android开发中,我们经常会使用Tab来进行主界面的布局.由于手机屏幕尺寸的限制,合 ...

  8. Linux运维 第三阶段 (一) 网络配置及openssl加密

    Linux运维 第三阶段 (一) 网络配置及openssl加密 主机接入网络:IP,netmask,gateway,hostname,DNS1,DNS2,DNS3,route,dhcp(dynamic ...

  9. 中国石油大学(北京)-《计算机网络应用基础》第三阶段在线作业

    第三阶段在线作业 单选题 (共20道题) 收起 1.(2.5分) 以下关于VPN说法正确的是 A.VPN指的是用户自己租用线路,和公共网络物理上完全隔离的.安全的线路 B.VPN指的是用户通过公用网络 ...

  10. 中国石油大学《计算机应用基础#》第三阶段在线作业

    第三阶段在线作业 单选题 (共20道题) 收起 1.(2.5分) PowerPoint演示文稿的作者必须非常注意幻灯片集的两个要素是(). A.内容和设计 B.内容和模板 C.内容和视觉效果 D.问题 ...

最新文章

  1. Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用
  2. 【第11周复盘】小朋友们 100% 闯关成功!
  3. 各种基本的排序算法在Object-C实现
  4. ha apache mysql_apache-2.2 – Apache和MySQL的HAProxy平衡算法
  5. “三农”谋定金融 中国农民丰收节交易会金融服务研讨会
  6. Java系统资源消耗定位概述
  7. 基于IdentityServer4的单点登录——项目基本结构与流程
  8. Red5边源服务器集群部署
  9. 约翰·冯·诺依曼:一个向上帝买了挂的男人!!
  10. c++一本通在线测评网站 1002:输出第二个整数
  11. 3D GAME PROGRAMMING WITH DIRECTX11(3)
  12. 模拟信号幅度调制之AM
  13. 人月神话札记:编程的苦恼和乐趣
  14. 史上最详细的HashMap红黑树解析
  15. 易观千帆 | 2022年11月银行APP月活跃用户规模盘点
  16. Android极速从视频里提取音频
  17. 最近项目用到Dubbo框架,临时抱佛脚分享一下共探讨。
  18. vc驿站视频教程笔记1
  19. 为什么内马尔要离开巴萨去巴黎?
  20. CardSlidePanel卡片左右划效果

热门文章

  1. 通用国籍,民族,亲属关系,证件类型,常见银行数组,可用于选择框,下拉框等
  2. 阿里巴巴国际站统计国家来源小方法
  3. 【黑灰产犯罪研究】流量劫持
  4. 华盛顿道格拉斯县计划建立区块链创新园区
  5. HU6206稳压芯片
  6. 数据分析师是什么,深度解析数据分析师
  7. 2020年10月计算机语言排名,最新!2020年10月编程语言排行榜出炉
  8. Monte-Carlo(蒙特卡罗)算法
  9. Halcon区域region系列(1)相关的算子
  10. 赫茨伯格工作丰富化模型(转载)