[英]Problem Mapping Framebuffer Device Memory using C#/Mono on Raspberry PI
我正在尝试使用通过Mono运行的C#代码直接访问Raspberry Pi上帧缓冲视频设备的视频内存。 我有一个运行良好的C程序,但是当我将其移植到C#时,它在“映射到内存”步骤中始终失败。
工作中的C程序(由tasanakorn提供)如下所示:
#include <stdio.h>
#include <syslog.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <bcm_host.h>
int process() {
DISPMANX_DISPLAY_HANDLE_T display;
DISPMANX_MODEINFO_T display_info;
DISPMANX_RESOURCE_HANDLE_T screen_resource;
VC_IMAGE_TRANSFORM_T transform;
uint32_t image_prt;
VC_RECT_T rect1;
int ret;
int fbfd = 0;
char *fbp = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
bcm_host_init();
display = vc_dispmanx_display_open(0);
if (!display) {
syslog(LOG_ERR, "Unable to open primary display");
return -1;
}
ret = vc_dispmanx_display_get_info(display, &display_info);
if (ret) {
syslog(LOG_ERR, "Unable to get primary display information");
return -1;
}
syslog(LOG_INFO, "Primary display is %d x %d", display_info.width, display_info.height);
fbfd = open("/dev/fb1", O_RDWR);
if (fbfd == -1) {
syslog(LOG_ERR, "Unable to open secondary display");
return -1;
}
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
syslog(LOG_ERR, "Unable to get secondary display information");
return -1;
}
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
syslog(LOG_ERR, "Unable to get secondary display information");
return -1;
}
syslog(LOG_INFO, "Second display is %d x %d %dbps\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, vinfo.xres, vinfo.yres, &image_prt);
if (!screen_resource) {
syslog(LOG_ERR, "Unable to create screen buffer");
close(fbfd);
vc_dispmanx_display_close(display);
return -1;
}
fbp = (char*) mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if (fbp <= 0) {
syslog(LOG_ERR, "Unable to create mamory mapping");
close(fbfd);
ret = vc_dispmanx_resource_delete(screen_resource);
vc_dispmanx_display_close(display);
return -1;
}
vc_dispmanx_rect_set(&rect1, 0, 0, vinfo.xres, vinfo.yres);
while (1) {
ret = vc_dispmanx_snapshot(display, screen_resource, 0);
vc_dispmanx_resource_read_data(screen_resource, &rect1, fbp, vinfo.xres * vinfo.bits_per_pixel / 8);
usleep(25 * 1000);
}
munmap(fbp, finfo.smem_len);
close(fbfd);
ret = vc_dispmanx_resource_delete(screen_resource);
vc_dispmanx_display_close(display);
}
int main(int argc, char **argv) {
setlogmask(LOG_UPTO(LOG_DEBUG));
openlog("fbcp", LOG_NDELAY | LOG_PID, LOG_USER);
return process();
}
C#代码(我曾尝试移植与/ dev / fb1相关的所有C代码)是:
using System;
using System.Runtime.InteropServices;
namespace MainProgram {
class MainClass {
static void Main(string[] args) {
int fbfd = -1; // file descriptor for framebuffer device
int fbp = -1; // pointer to mapped framebuffer memory
uint fbs = 0; // size of mapped framebuffer memory
int result = 0; // utility result variable
try {
// Initialize (not sure if this is needed, but...).
Libc.bcm_host_init();
// Open the device. (Command line param is device, e.g. "/dev/fb0" or "/dev/fb1".)
fbfd = Libc.open(args[0], Libc.O_RDWR);
if (fbfd < 0)
throw new Exception("open: error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbfd=" + fbfd);
// Get fixed screen info.
Libc.fb_fix_screeninfo fixInfo = new Libc.fb_fix_screeninfo();
result = Libc.ioctl1(fbfd, Libc.FBIOGET_FSCREENINFO, ref fixInfo);
if (result < 0)
throw new Exception("ioctl1: error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbfix: mem start=" + fixInfo.smem_start.ToString("X8") + ", len=" + fixInfo.smem_len);
// Get variable screen info.
Libc.fb_var_screeninfo varInfo = new Libc.fb_var_screeninfo();
result = Libc.ioctl2(fbfd, Libc.FBIOGET_VSCREENINFO, ref varInfo);
if (result < 0)
throw new Exception("ioctl2: error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbvar: res=" + varInfo.xres + "x" + varInfo.yres + ", bpp=" + varInfo.bits_per_pixel);
// Map framebuffer memory to virtual space.
fbs = fixInfo.smem_len;
Console.WriteLine("Confirm non-zero size: fbs=" + fbs);
fbp = Libc.mmap(0, fbs, Libc.PROT_READ | Libc.PROT_WRITE, Libc.MAP_SHARED, fbfd, 0);
if (fbp < 0)
throw new Exception("mmap: error " + Marshal.GetLastWin32Error());
Console.WriteLine("mmap: location=" + fbp.ToString("X8"));
}
catch (Exception ex) {
Console.WriteLine("*** Error: " + ex.Message);
}
finally {
if (fbp >= 0)
result = Libc.munmap(fbp, fbs);
if (fbfd >= 0)
result = Libc.close(fbfd);
};
}
public static class Libc {
public const int O_RDWR = 0x0002;
public const int PROT_READ = 0x04;
public const int PROT_WRITE = 0x02;
public const int MAP_FILE = 0x0001;
public const int MAP_SHARED = 0x0010;
public const int FBIOGET_VSCREENINFO = 0x4600;
public const int FBIOGET_FSCREENINFO = 0x4602;
[DllImport("libbcm_host.so", EntryPoint = "bcm_host_init")]
public static extern void bcm_host_init();
[DllImport("libc", EntryPoint="open", SetLastError = true)]
public static extern int open(
[MarshalAs(UnmanagedType.LPStr)] string filename,
[MarshalAs(UnmanagedType.I4)] int flags
);
[DllImport("libc", EntryPoint="close", SetLastError = true)]
public static extern int close(
[MarshalAs(UnmanagedType.I4)] int filedes
);
[DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
public static extern int ioctl1(
[MarshalAs(UnmanagedType.I4)] int filedes,
[MarshalAs(UnmanagedType.I4)] int command,
ref fb_fix_screeninfo data
);
[DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
public static extern int ioctl2(
[MarshalAs(UnmanagedType.I4)] int filedes,
[MarshalAs(UnmanagedType.I4)] int command,
ref fb_var_screeninfo data
);
[DllImport("libc", EntryPoint = "mmap", SetLastError = true)]
public static extern int mmap(
[MarshalAs(UnmanagedType.U4)] uint addr,
[MarshalAs(UnmanagedType.U4)] uint length,
[MarshalAs(UnmanagedType.I4)] int prot,
[MarshalAs(UnmanagedType.I4)] int flags,
[MarshalAs(UnmanagedType.I4)] int fdes,
[MarshalAs(UnmanagedType.I4)] int offset
);
[DllImport("libc", EntryPoint = "munmap", SetLastError = true)]
public static extern int munmap(
[MarshalAs(UnmanagedType.I4)] int addr,
[MarshalAs(UnmanagedType.U4)] uint length
);
[StructLayout(LayoutKind.Sequential)]
public struct fb_fix_screeninfo {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] id;
[MarshalAs(UnmanagedType.U4)] public uint smem_start;
[MarshalAs(UnmanagedType.U4)] public uint smem_len;
[MarshalAs(UnmanagedType.U4)] public uint type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] public byte[] stuff;
};
[StructLayout(LayoutKind.Sequential)]
public struct fb_var_screeninfo {
[MarshalAs(UnmanagedType.U4)] public uint xres;
[MarshalAs(UnmanagedType.U4)] public uint yres;
[MarshalAs(UnmanagedType.U4)] public uint xres_virtual;
[MarshalAs(UnmanagedType.U4)] public uint yres_virtual;
[MarshalAs(UnmanagedType.U4)] public uint xoffset;
[MarshalAs(UnmanagedType.U4)] public uint yoffset;
[MarshalAs(UnmanagedType.U4)] public uint bits_per_pixel;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 132)] public byte[] stuff;
};
}
}
}
当我尝试在Pi上运行编译后的代码时,得到以下信息:
$ sudo mono ConsoleApp6.exe /dev/fb1
fbfd=4
fbfix: mem start=00000000, len=307200
fbvar: res=480x320, bpp=16
Confirm non-zero size: fbs=307200
*** Error: mmap: error 22
(我在主监视器和帧缓冲设备上尝试了相同的操作,并得到以下相同的错误。)
$ sudo mono ConsoleApp6.exe /dev/fb0
fbfd=4
fbfix: mem start=1E876000, len=3686400
fbvar: res=1280x720, bpp=32
Confirm non-zero size: fbs=3686400
*** Error: mmap: error 22
错误22是EINVAL,mmap()文档将其描述为“我们不喜欢addr,长度或偏移量(例如,它们太大或在页面边界上未对齐)。” [这也可能意味着:a)length参数为零(不是),或b)MAP_SHARED和MAP_PRIVATE都被设置了(不是)。 但是,我传入的值应与C代码使用的值相同。
有人知道我在做什么错吗?
解决了。 问题是Raspberry Pi上的常量PROT_READ,PROT_WRITE,MAP_SHARED等与我通过Google搜索发现的值(顶空)不同。 我通过查看/ usr / include中的.h文件找到了正确的值。 此外,我发现mmap的负值不一定表示错误; 我需要专门寻找MAP_FAILED(-1)。
如果有人可以使用以下代码,则可以使用它:
using System;
using System.Runtime.InteropServices;
namespace MainProgram {
class MainClass {
static void Main(string[] args) {
int fbfd = -1; // file descriptor for framebuffer device
int fbp = -1; // pointer to mapped framebuffer memory
uint fbs = 0; // size of mapped framebuffer memory
int result = 0; // utility result variable
try {
// Initialize (not sure if this is needed, but...).
Libc.bcm_host_init();
// Open the device. (Command line param is device, e.g. "/dev/fb0" or "/dev/fb1".)
fbfd = Libc.open(args[0], Libc.O_RDWR);
if (fbfd == -1)
throw new Exception("open: result=" + fbfd + ", error=" + Marshal.GetLastWin32Error());
Console.WriteLine("fbfd=" + fbfd);
// Get fixed screen info.
Libc.fb_fix_screeninfo fixInfo = new Libc.fb_fix_screeninfo();
result = Libc.ioctl1(fbfd, Libc.FBIOGET_FSCREENINFO, ref fixInfo);
if (result == -1)
throw new Exception("ioctl1: result=" + result + ", error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbfix: mem start=" + fixInfo.smem_start.ToString("X8") + ", len=" + fixInfo.smem_len);
// Get variable screen info.
Libc.fb_var_screeninfo varInfo = new Libc.fb_var_screeninfo();
result = Libc.ioctl2(fbfd, Libc.FBIOGET_VSCREENINFO, ref varInfo);
if (result == -1)
throw new Exception("ioctl2: result=" + result + ", error " + Marshal.GetLastWin32Error());
Console.WriteLine("fbvar: res=" + varInfo.xres + "x" + varInfo.yres + ", bpp=" + varInfo.bits_per_pixel);
// Map framebuffer memory to virtual space.
fbp = Libc.mmap(0, fixInfo.smem_len, Libc.PROT_READ | Libc.PROT_WRITE, Libc.MAP_SHARED, fbfd, 0);
if (fbp == Libc.MAP_FAILED)
throw new Exception("mmap: result=" + fbp + ", error " + Marshal.GetLastWin32Error());
Console.WriteLine("mmap: location=" + fbp.ToString("X8"));
}
catch (Exception ex) {
Console.WriteLine("*** Error: " + ex.Message);
}
finally {
if (fbp != -1)
result = Libc.munmap(fbp, fbs);
if (fbfd != -1)
result = Libc.close(fbfd);
};
}
public static class Libc {
public const int O_RDWR = 0x0002;
public const int PROT_READ = 0x1;
public const int PROT_WRITE = 0x2;
public const int MAP_SHARED = 0x01;
public const int MAP_FAILED = -1;
public const int FBIOGET_VSCREENINFO = 0x4600;
public const int FBIOGET_FSCREENINFO = 0x4602;
[DllImport("libbcm_host.so", EntryPoint = "bcm_host_init")]
public static extern void bcm_host_init();
[DllImport("libc", EntryPoint="open", SetLastError = true)]
public static extern int open(
[MarshalAs(UnmanagedType.LPStr)] string filename,
[MarshalAs(UnmanagedType.I4)] int flags
);
[DllImport("libc", EntryPoint="close", SetLastError = true)]
public static extern int close(
[MarshalAs(UnmanagedType.I4)] int filedes
);
[DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
public static extern int ioctl1(
[MarshalAs(UnmanagedType.I4)] int filedes,
[MarshalAs(UnmanagedType.I4)] int command,
ref fb_fix_screeninfo data
);
[DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
public static extern int ioctl2(
[MarshalAs(UnmanagedType.I4)] int filedes,
[MarshalAs(UnmanagedType.I4)] int command,
ref fb_var_screeninfo data
);
[DllImport("libc", EntryPoint = "mmap", SetLastError = true)]
public static extern int mmap(
[MarshalAs(UnmanagedType.U4)] uint addr,
[MarshalAs(UnmanagedType.U4)] uint length,
[MarshalAs(UnmanagedType.I4)] int prot,
[MarshalAs(UnmanagedType.I4)] int flags,
[MarshalAs(UnmanagedType.I4)] int fdes,
[MarshalAs(UnmanagedType.I4)] int offset
);
[DllImport("libc", EntryPoint = "munmap", SetLastError = true)]
public static extern int munmap(
[MarshalAs(UnmanagedType.I4)] int addr,
[MarshalAs(UnmanagedType.U4)] uint length
);
[StructLayout(LayoutKind.Sequential)]
public struct fb_fix_screeninfo {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] id;
[MarshalAs(UnmanagedType.U4)] public uint smem_start;
[MarshalAs(UnmanagedType.U4)] public uint smem_len;
[MarshalAs(UnmanagedType.U4)] public uint type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] public byte[] stuff;
};
[StructLayout(LayoutKind.Sequential)]
public struct fb_var_screeninfo {
[MarshalAs(UnmanagedType.U4)] public uint xres;
[MarshalAs(UnmanagedType.U4)] public uint yres;
[MarshalAs(UnmanagedType.U4)] public uint xres_virtual;
[MarshalAs(UnmanagedType.U4)] public uint yres_virtual;
[MarshalAs(UnmanagedType.U4)] public uint xoffset;
[MarshalAs(UnmanagedType.U4)] public uint yoffset;
[MarshalAs(UnmanagedType.U4)] public uint bits_per_pixel;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 132)] public byte[] stuff;
};
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.