【问题标题】:Developing for the HDMI port on Linux在 Linux 上开发 HDMI 端口
【发布时间】:2013-01-21 00:09:18
【问题描述】:

如何才能从应用程序中独占驱动 HDMI 输出,而不允许操作系统自动配置它以进行显示输出?

例如,使用标准 DVI/VGA 作为主显示器,但使用设备文件将 Mplayer 视频输出发送到 HDMI。

这是一个很难通过 Google 回答的问题。几乎所有结果都与通过 HDMI 进行音频工作有关。

(在此处编辑)

下面的评论提到了使用单独的 Xorg 服务器。尽管这是一个有用的想法,但它并没有回答我提出的一个问题,也没有回答我暗示的一个问题:

1) 如果控制台在另一个显示器之前加载,或者它是唯一的显示器(仅使用 SSH 登录时),我如何防止 Linux 将控制台放在该显示器上? 2)如果没有X怎么办?我想直接将图形驱动到适配器。我可以使用标准功能从代码中执行此操作,而不直接与驱动程序交互(可能已经过时,但使用 SVGALib 或其他一些非 X 图形层)?

(在此处编辑)

我查看了 SVGALib(它是旧的)和 SDL。后者在 X 内部和外部都可以工作,甚至提供对 OpenGL 的访问。我在某个地方通过论坛链接找到了 1.3 版本,但网站和 FTP 似乎都只有 1.2 版本。总的来说,SDL 是一个很好的解决方案,但它有以下两个具体的缺点:

1) 一般的 create-device 调用接受设备索引,但完全忽略它:

(src/video/bwindow/SDL_bvideo.cc)
BE_CreateDevice(int devindex)

驱动程序特定的调用似乎有同样的缺陷。例如,DirectFB(我假设它在控制台下提供图形):

(src/video/directfb/SDL_DirectFB_video.c)
DirectFB_CreateDevice(int devindex)

这些函数的主体似乎都没有设置设备索引的现有位置...毫无疑问是因为它们所构建的标准接口缺乏支持。

2) 无论选择何种适配器,SDL 似乎都会自动将所有显示器连接在一起。示例“testsprite2.c”(与库一起提供)接受“--display”参数,该参数在“common.c”(所有示例的通用功能)中处理。您可以看到,它使用“--display”参数所做的只是在一个大的组合画布中计算该屏幕的 X/Y 坐标:

if (SDL_strcasecmp(argv[index], "--display") == 0) {
    ++index;
    if (!argv[index]) {
        return -1;
    }
    state->display = SDL_atoi(argv[index]);
    if (SDL_WINDOWPOS_ISUNDEFINED(state->window_x)) {
        state->window_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->display);
        state->window_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(state->display);
    }
    if (SDL_WINDOWPOS_ISCENTERED(state->window_x)) {
        state->window_x = SDL_WINDOWPOS_CENTERED_DISPLAY(state->display);
        state->window_y = SDL_WINDOWPOS_CENTERED_DISPLAY(state->display);
    }
    return 2;
}

因此,如果它们在同一个适配器上,则无法将它们与另一台显示器隔离开来。 SDL 将不起作用。

除非有与 SDL 类似的解决方案,或者将特定设备 (devindex) 设置在适当的位置是微不足道的(这可能不是这种情况,因此可能是它的原因未实现),似乎独占和完全专用使用屏幕的最佳选择是在分配给您的第二台设备的单独 Xorg 实例下编写您自己的窗口管理器。

【问题讨论】:

  • HDMI 端口由硬件设备(例如:视频卡)控制。为了使其工作,您必须与硬件交谈,这意味着它是特定于供应商的。在操作系统上直接与复杂硬件交互是一项艰巨的任务,无论是在内核空间还是用户空间,尤其是如果您的设备同时被操作系统(用于 DVI/VGA)和您的程序(用于 HDMI)使用。
  • 一点也不。我不介意与司机交谈,或者更一般地说,与整个操作系统交谈。我只是在寻找一种方法来防止它被立即声称为控制台显示设备,以便我可以从代码中独占访问它。
  • python 如何适合这项任务超出了我的理解
  • Python 和 C 都作为标签给出,因为我想引起开发人员的注意,而不仅仅是管理员,因为这是我对这个问题感兴趣的地方。
  • 配置并启动额外的 Xorg 服务器以在该 HDMI 端口上显示...

标签: python c linux kernel hdmi


【解决方案1】:

您可以直接写入帧缓冲设备 /dev/fb(假设您的控制台默认使用一个)。要防止控制台显示在其上,只需禁用所有虚拟终端(然后您将只能远程登录)。如果您有多个适配器,您应该获得多个帧缓冲设备(这需要确认)。

在帧缓冲区上绘制矩形的 C 示例如下:

Paint Pixels to Screen via Linux FrameBuffer

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

int main()
{
    int fbfd = 0;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    long int screensize = 0;
    char *fbp = 0;
    int x = 0, y = 0;
    long int location = 0;

    // Open the file for reading and writing
    fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd == -1) {
        perror("Error: cannot open framebuffer device");
        exit(1);
    }
    printf("The framebuffer device was opened successfully.\n");

    // Get fixed screen information
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
        perror("Error reading fixed information");
        exit(2);
    }

    // Get variable screen information
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
        perror("Error reading variable information");
        exit(3);
    }

    printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

    // Figure out the size of the screen in bytes
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

    // Map the device to memory
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
    if ((int)fbp == -1) {
        perror("Error: failed to map framebuffer device to memory");
        exit(4);
    }
    printf("The framebuffer device was mapped to memory successfully.\n");

    x = 100; y = 100;       // Where we are going to put the pixel

    // Figure out where in memory to put the pixel
    for (y = 100; y < 300; y++)
        for (x = 100; x < 300; x++) {

            location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
                       (y+vinfo.yoffset) * finfo.line_length;

            if (vinfo.bits_per_pixel == 32) {
                *(fbp + location) = 100;        // Some blue
                *(fbp + location + 1) = 15+(x-100)/2;     // A little green
                *(fbp + location + 2) = 200-(y-100)/5;    // A lot of red
                *(fbp + location + 3) = 0;      // No transparency
        //location += 4;
            } else  { //assume 16bpp
                int b = 10;
                int g = (x-100)/6;     // A little green
                int r = 31-(y-100)/16;    // A lot of red
                unsigned short int t = r<<11 | g << 5 | b;
                *((unsigned short int*)(fbp + location)) = t;
            }

        }
    munmap(fbp, screensize);
    close(fbfd);
    return 0;
}

只要您有可用的构建工具以及系统的标头,它就应该可以编译。如果想要刺激一下,可以从 SSH 运行它,然后在您尚未登录的物理屏幕上观看它的绘制。

应该注意的是,在 X11 之外有很多工具可以处理帧缓冲区,但它们不会直接访问帧缓冲区。相反,它们通过称为 DirectFB 的附加抽象层工作。 DirectFB 将允许相同的应用程序在 X11 内外运行......包括 MPlayer、GStreamer、任何包含 SDL(称为 DirectFB)的应用程序,以及一个名为 XDirectFB 的轻量级、流行的假 X11 容器(我相信它应该运行 X11 应用程序,但不像典型的窗口管理器那样负担过重)。

【讨论】:

  • 据我了解,有帧缓冲区,它内置在内核中,是没有硬件加速时最好的可用选项,然后是 DirectFB,它将使用帧缓冲区,硬件加速,OpenGL,等等,取决于你需要什么,以及什么是可用的。请参阅上面的最后一段。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多