繁体   English   中英

在Raspberry PI上使用C#/ Mono映射帧缓冲设备内存的问题

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM