这里的 arm-linux 裸机指的是,只有基本 C 库和安装了 busybox 的嵌入式系统,没有 X11 或者 wayland 作为底层支援。

这里的实现是基于 framebuffer 的,是将用于 LCD 显示的 /dev/fb* 设备中数据进行了拷贝(其实是 mmap 进行了数据共享,是直接取了 framebuffer 数据缓存),并通过 VNC 协议外发。本文只记录了一个没有键盘鼠标的,基于 framebuffer 的 VNC 桌面实验。本实验中,使用友善之臂设计的 s5pv21 开发板。

今天目的只是实验是否可行,并没有详细 debug。这个明显是还有很大改进空间的。PS: 原来 VNC 的协议本身就是叫 rfb, remote framebuffer。

下面是在 xtightvncviewer 中连接效果:

实现路径:

1. 为 arm 板编译安装了 libvncserver。编译的时候,进行了下面一些特殊操作:

a. 有部分可以在 configure 时候关闭(比如 --without-gnutls)

b. 对 SDL 和 GTK 的需求,我直接编辑了 configure 脚本,找到 HAVE_LIBSDL_FALSE= ,HAVE_LIBGTK_FALSE= 位置,去掉了外面的判断。即默认就是这两个状态。因为我不需要 GTK 和 SDL。

c. 解压出来的工具无法正确判断系统类型,configure 时候指定了系统: build_os=gnu-linux ./configure --host=arm-linux --prefix=/tmp/install

编译下面的文件,将二进制拷贝到开发板。

该文件是从github获得的,作者实现的时候把键盘鼠标都删掉了,不过这个明显是可以添加的。网址:

/*
* $Id$
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* This project is an adaptation of the original fbvncserver for the iPAQ
* and Zaurus.
*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h> #include <sys/stat.h>
#include <sys/sysmacros.h> /* For makedev() */ #include <fcntl.h>
#include <linux/fb.h>
#include <linux/input.h> #include <assert.h>
#include <errno.h> /* libvncserver */
#include "rfb/rfb.h"
//#include "rfb/keysym.h" /*****************************************************************************/
//#define LOG_FPS #define BITS_PER_SAMPLE 5
#define SAMPLES_PER_PIXEL 2 static char fb_device[] = "/dev/fb0";
static struct fb_var_screeninfo scrinfo;
static int fbfd = -;
static unsigned short int *fbmmap = MAP_FAILED;
static unsigned short int *vncbuf;
static unsigned short int *fbbuf; static int vnc_port = ;
static rfbScreenInfoPtr server;
static size_t bytespp; /* No idea, just copied from fbvncserver as part of the frame differerencing
* algorithm. I will probably be later rewriting all of this. */
static struct varblock_t
{
int min_i;
int min_j;
int max_i;
int max_j;
int r_offset;
int g_offset;
int b_offset;
int rfb_xres;
int rfb_maxy;
} varblock; /*****************************************************************************/ static void init_fb(void)
{
size_t pixels; if ((fbfd = open(fb_device, O_RDONLY)) == -)
{
fprintf(stderr, "cannot open fb device %s\n", fb_device);
exit(EXIT_FAILURE);
} if (ioctl(fbfd, FBIOGET_VSCREENINFO, &scrinfo) != )
{
fprintf(stderr, "ioctl error\n");
exit(EXIT_FAILURE);
} pixels = scrinfo.xres * scrinfo.yres;
bytespp = scrinfo.bits_per_pixel / ; fprintf(stderr, "xres=%d, yres=%d, xresv=%d, yresv=%d, xoffs=%d, yoffs=%d, bpp=%d\n",
(int)scrinfo.xres, (int)scrinfo.yres,
(int)scrinfo.xres_virtual, (int)scrinfo.yres_virtual,
(int)scrinfo.xoffset, (int)scrinfo.yoffset,
(int)scrinfo.bits_per_pixel);
fprintf(stderr, "offset:length red=%d:%d green=%d:%d blue=%d:%d \n",
(int)scrinfo.red.offset, (int)scrinfo.red.length,
(int)scrinfo.green.offset, (int)scrinfo.green.length,
(int)scrinfo.blue.offset, (int)scrinfo.blue.length
); fbmmap = mmap(NULL, pixels * bytespp, PROT_READ, MAP_SHARED, fbfd, ); if (fbmmap == MAP_FAILED)
{
fprintf(stderr, "mmap failed\n");
exit(EXIT_FAILURE);
}
} static void cleanup_fb(void)
{
if(fbfd != -)
{
close(fbfd);
}
} /*****************************************************************************/ static void init_fb_server(int argc, char **argv)
{
fprintf(stderr, "Initializing server...\n"); /* Allocate the VNC server buffer to be managed (not manipulated) by
* libvncserver. */
vncbuf = calloc(scrinfo.xres * scrinfo.yres, bytespp);
assert(vncbuf != NULL); /* Allocate the comparison buffer for detecting drawing updates from frame
* to frame. */
fbbuf = calloc(scrinfo.xres * scrinfo.yres, bytespp);
assert(fbbuf != NULL); /* TODO: This assumes scrinfo.bits_per_pixel is 16. */
server = rfbGetScreen(&argc, argv, scrinfo.xres, scrinfo.yres, BITS_PER_SAMPLE, SAMPLES_PER_PIXEL, bytespp);
assert(server != NULL); server->desktopName = "framebuffer";
server->frameBuffer = (char *)vncbuf;
server->alwaysShared = TRUE;
server->httpDir = NULL;
server->port = vnc_port; // server->kbdAddEvent = keyevent;
// server->ptrAddEvent = ptrevent; rfbInitServer(server); /* Mark as dirty since we haven't sent any updates at all yet. */
rfbMarkRectAsModified(server, , , scrinfo.xres, scrinfo.yres); /* No idea. */
varblock.r_offset = scrinfo.red.offset + scrinfo.red.length - BITS_PER_SAMPLE;
varblock.g_offset = scrinfo.green.offset + scrinfo.green.length - BITS_PER_SAMPLE;
varblock.b_offset = scrinfo.blue.offset + scrinfo.blue.length - BITS_PER_SAMPLE;
varblock.rfb_xres = scrinfo.yres;
varblock.rfb_maxy = scrinfo.xres - ;
} // sec
#define LOG_TIME 5 int timeToLogFPS() {
static struct timeval now={,}, then={,};
double elapsed, dnow, dthen;
gettimeofday(&now,NULL);
dnow = now.tv_sec + (now.tv_usec /1000000.0);
dthen = then.tv_sec + (then.tv_usec/1000000.0);
elapsed = dnow - dthen;
if (elapsed > LOG_TIME)
memcpy((char *)&then, (char *)&now, sizeof(struct timeval));
return elapsed > LOG_TIME;
} /*****************************************************************************/
//#define COLOR_MASK 0x1f001f
#define COLOR_MASK (((1 << BITS_PER_SAMPLE) << 1) - 1)
#define PIXEL_FB_TO_RFB(p,r_offset,g_offset,b_offset) ((p>>r_offset)&COLOR_MASK) | (((p>>g_offset)&COLOR_MASK)<<BITS_PER_SAMPLE) | (((p>>b_offset)&COLOR_MASK)<<(2*BITS_PER_SAMPLE)) static void update_screen(void)
{
#ifdef LOG_FPS
static int frames = ;
frames++;
if(timeToLogFPS())
{
double fps = frames / LOG_TIME;
fprintf(stderr, " fps: %f\n", fps);
frames = ;
}
#endif varblock.min_i = varblock.min_j = ;
varblock.max_i = varblock.max_j = -; uint32_t *f = (uint32_t *)fbmmap; /* -> framebuffer */
uint32_t *c = (uint32_t *)fbbuf; /* -> compare framebuffer */
uint32_t *r = (uint32_t *)vncbuf; /* -> remote framebuffer */ int xstep = /bytespp; int y;
for (y = ; y < (int)scrinfo.yres; y++)
{
/* Compare every 1/2/4 pixels at a time */
int x;
for (x = ; x < (int)scrinfo.xres; x += xstep)
{
uint32_t pixel = *f; if (pixel != *c)
{
*c = pixel; #if 0
/* XXX: Undo the checkered pattern to test the efficiency
* gain using hextile encoding. */
if (pixel == 0x18e320e4 || pixel == 0x20e418e3)
pixel = 0x18e318e3;
#endif
*r = PIXEL_FB_TO_RFB(pixel,
varblock.r_offset, varblock.g_offset, varblock.b_offset); if (x < varblock.min_i)
varblock.min_i = x;
else
{
if (x > varblock.max_i)
varblock.max_i = x; if (y > varblock.max_j)
varblock.max_j = y;
else if (y < varblock.min_j)
varblock.min_j = y;
}
} f++;
c++;
r++;
}
} if (varblock.min_i < )
{
if (varblock.max_i < )
varblock.max_i = varblock.min_i; if (varblock.max_j < )
varblock.max_j = varblock.min_j; fprintf(stderr, "Dirty page: %dx%d+%d+%d...\n",
(varblock.max_i+) - varblock.min_i, (varblock.max_j+) - varblock.min_j,
varblock.min_i, varblock.min_j); rfbMarkRectAsModified(server, varblock.min_i, varblock.min_j,
varblock.max_i + , varblock.max_j + ); rfbProcessEvents(server, );
}
} /*****************************************************************************/ void print_usage(char **argv)
{
fprintf(stderr, "%s [-f device] [-p port] [-h]\n"
"-p port: VNC port, default is 5900\n"
"-f device: framebuffer device node, default is /dev/fb0\n"
"-h : print this help\n"
, *argv);
} int main(int argc, char **argv)
{
if(argc > )
{
int i=;
while(i < argc)
{
if(*argv[i] == '-')
{
switch(*(argv[i] + ))
{
case 'h':
print_usage(argv);
exit();
break;
case 'f':
i++;
strcpy(fb_device, argv[i]);
break;
case 'p':
i++;
vnc_port = atoi(argv[i]);
break;
}
}
i++;
}
} fprintf(stderr, "Initializing framebuffer device %s...\n", fb_device);
init_fb(); fprintf(stderr, "Initializing VNC server:\n");
fprintf(stderr, " width: %d\n", (int)scrinfo.xres);
fprintf(stderr, " height: %d\n", (int)scrinfo.yres);
fprintf(stderr, " bpp: %d\n", (int)scrinfo.bits_per_pixel);
fprintf(stderr, " port: %d\n", (int)vnc_port);
init_fb_server(argc, argv); /* Implement our own event loop to detect changes in the framebuffer. */
while ()
{
while (server->clientHead == NULL)
rfbProcessEvents(server, ); rfbProcessEvents(server, );
update_screen();
} fprintf(stderr, "Cleaning up...\n");
cleanup_fb();
}

arm-linux 裸机下 VNC 的实现的更多相关文章

  1. arm+linux 裸机环境搭建之初试minicom+dnw烧写uboot

    下面的步骤将会实现在linux下面使用dnw+minicom来烧写uboot 一.安装minicom 下载地址:http://download.csdn.net/detail/king_bingge/ ...

  2. arm+linux 裸机环境搭建之安装工具篇(eclipse)

    之前已经讲述如何安装gcc和gdb,在此不赘述! 一.所需要的软件有两个: jre-7u25-linux-i586.rpm(虚拟机) eclipse-cpp-kepler-R-linux-gtk .t ...

  3. linux下VNC的配置及使用

    我们知道在windows里面有远程桌面(著名的有pcanywhere,网络人等)对吧,在linux下我们同样有这个东西,其中最流行的一种就是VNC,其实VNC是一种协议,它的全称是virtual ne ...

  4. 编译Linux系统下的jrtplib3.9和jthread1.3(arm和ubuntu)

    最近由于学习需要,需要编译jrtplib,网上的资料基本上都是关于3.9以前的版本,而以前的版本基本上都是通过confiugre来配置生成Makefile,而最近的版本却没有这一项,而是使用cmake ...

  5. Linux下VNC配置多个桌面和修改密码 不会当系统重启vnc失效

    1:vncserver 2:iptables -I INPUT -p tcp --dport 5901 -j ACCEPT   客户端方式 3:iptables -I INPUT -p tcp --d ...

  6. Linux下VNC配置使用总结:开启+桌面配置+安全访问

    操作环境:CentOS 5.3 + Windows XP SP3 32bit + RealVNC 4.1.2 i386 + TigerVNC. 参考:潇湘隐者-Linux系统VNC配置实践总结,萨米的 ...

  7. 移植ARM linux下远程连接工具dropbear

    移植ARM linux下远程连接工具dropbear 原文地址:http://www.cnblogs.com/NickQ/p/9010529.html 移植zlib 下载地址:https://gith ...

  8. VNC CentOS Linux下VNC Server远程桌面配置详解

    VNC概述 VNC (Virtual Network Console)是虚拟网络控制台的缩写.VNC 是一款优秀的远程控制工具软件,由著名的 AT&T 的欧洲研究实验室开发的.VNC 是在基于 ...

  9. [转帖]Linux系统下x86和ARM的区别有哪些?

    Linux系统下x86和ARM的区别有哪些? https://www.cnblogs.com/alantu2018/p/9209143.html 其实界限 越来越小了.. 问题: 最近在用三星的一款i ...

随机推荐

  1. Unity3d-Particle System系统的学习(二)

    这节我们继续上节没讲完的Particle参数. 上节我们讲了Emission发射器参数,我们接着往下讲Shape: 可以看到这个子模块的参数是跟形状有关: 1.Shape:发射形状.粒子被约束在这个形 ...

  2. 《Google Glass开发指南》

    <Google Glass开发指南> 基本信息 作者: BestApp工作室 丛书名: 图灵原创 出版社:人民邮电出版社 ISBN:9787115349477 上架时间:2014-3-19 ...

  3. [Nginx] Nginx 配置location总结

    cp from : https://www.cnblogs.com/coder-yoyo/p/6346595.html location匹配顺序 "="前缀指令匹配,如果匹配成功, ...

  4. [Web 前端] 解决因inline-block元素导致的空白间距和元素下沉

    cp from : https://www.jianshu.com/p/617e78a27c88 ** 前言: ** CSS 中的 display:inline-block 是笔者最为喜欢的元素之一, ...

  5. Maven 快速入门

    安装 Maven是一个Java工具,因此你的电脑上必须安装有JAVA环境(JDK或者JRE) 首先,从官方下载 Maven ,我这里下载的是 3.5 的版本. 本文是在Mac环境中安装的,首先创建一个 ...

  6. JAVA基础知识之编译、运行、打包

    一:java环境设置在环境变量中设置以下三个变量: JAVA_HOME=C:\j2sdk1.4.1 //可以改为相应的目录CLASSPATH=%JAVA_HOME%\lib\tools.jar;%JA ...

  7. [转]CENTOS LINUX安装并使用NFS共享文件

    FROM :http://www.qiansw.com/centos-linux-nfs.html NFS是linux常用的一种文件分享工具. 下面介绍安装及使用方法. CentOS 5.5 yum ...

  8. Spring的AsyncHandlerInterceptor

    AsyncHandlerInterceptor提供了一个afterConcurrentHandlingStarted()方法, 这个方法会在Controller方法异步执行时开始执行, 而Interc ...

  9. 解决Web部署 svg/woff/woff2字体 404错误 iis 解决Web部署 svg/woff/woff2字体 404错误

    问题:最近在IIS上部署web项目的时候,发现浏览器总是报找不到woff.woff2字体的错误.导致浏览器加载字体报404错误,白白消耗了100-200毫秒的加载时间. 原因:因为服务器IIS不认SV ...

  10. 未能加载文件或程序集“Newtonsoft.Json”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

    "/"应用程序中的服务器错误. 未能加载文件或程序集"Newtonsoft.Json"或它的某一个依赖项.找到的程序集清单定义与程序集引用不匹配. (异常来自 ...