Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Developing for the HDMI port on Linux

How would it be possible to exclusively drive the HDMI output from an application, without allowing the OS to automatically configure it for display output?

For example, using the standard DVI/VGA as the primary display, but sending Mplayer video output to the HDMI using a device file.

It's a difficult question to answer via Google. Almost every result has to do with making audio work over HDMI.

(edited here)

A comment, below, mentioned using separate Xorg servers. Although this is a helpful idea, it doesn't answer one question that I asked, and one that I implied:

1) How do I keep Linux from wanting to put the console on that display, if it's loaded before the other display, or if it's the only display (when only SSH is used for login)? 2) What if there is no X? I want to drive graphics to the adapter directly. Can I do this from code using standard functionality, without interacting with the drivers directly (probably outdated, but using SVGALib or some other non-X graphics layer)?

(edited here)

I looked at SVGALib (which is old) and SDL. The latter works both in and outside of X, and even provides access to OpenGL. I found version 1.3 via a forum link, somewhere, but both the website and the FTP only seem to have up to 1.2 . SDL is a beautiful solution, in general, but it has the following two, specific disadvantages:

1) The general create-device call accepts a device index, but completely ignores it:

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

The driver-specific call seems to have the same flaw. For example, DirectFB (which, I assume, provides graphics under the console):

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

Neither of these functions' bodies seems to have an existing place to set the device-index either... No doubt due to lack of support in the standard interface that they're built for.

2) On whatever adapter happens to be elected, SDL seems to automatically attach all displays together. The example "testsprite2.c" (came with library), accepts a "--display" parameter, which is processed within "common.c" (common functionality for all examples). You can see that all it does with the "--display" parameter is calculates the X/Y coordinate of that screen within one large, combined canvas:

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;
}

So, there's no way to isolate one display from a another if they're on the same adapter. SDL will not work.

Unless there's a comparable solution to SDL, or it turns out to be trivial to set the particular device (devindex) in the appropriate place (which is probably not the case, and, therefore, probably the reason that it was left unimplemented), it seems like the best option for exclusive and completely dedicated use of the screen is to write your own window manager under a separate Xorg instance assigned to your second device.

like image 837
Dustin Oprea Avatar asked Feb 05 '13 22:02

Dustin Oprea


People also ask

How do I enable HDMI on Linux?

HDMI. Connect your projector or ActivPanel to your laptop using an HDMI cable. There may be several HDMI ports on your ActivPanel. Press the Source button on the ActivPanel, or on its remote control, and select the correct HDMI source.

Does HDMI work with Linux?

HDMI Cable This is one of the easiest ways to stream from Linux to a TV. Most smart and non-smart TV sets come with HDMI, or High-Definition Multimedia Interface, ports. With these cables, you can easily stream from your Linux OS to your TV.


1 Answers

You can directly write into the framebuffer device /dev/fb (assuming that your console uses one, by default). To prevent a console from showing on it, just disable all of your virtual terminals (you will then only be able to log-in remotely). You should get more than one framebuffer device if you have multiple adapters (this needs to be confirmed).

A C example that draws a rectangle on the framebuffer is here:

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;
}

As long as you have the build tools available, along with the headers for your system, it should compile. For a thrill, run it from SSH and watch it draw on a physical screen that you haven't logged-in to.

It should be noted that there is a wide array of tools that work against the framebuffer, outside of X11, but they won't access the framebuffer directly. Instead, they work through an additional abstraction layer called DirectFB. DirectFB will allow the same applications to run both in and outside of X11... Including both MPlayer, GStreamer, any app that incorporates SDL (which calls DirectFB), as well as a light, popular fake-X11 container called XDirectFB (I believe that it should run X11 apps, but not be as overburdening as a typical window manager).

like image 180
Dustin Oprea Avatar answered Sep 22 '22 17:09

Dustin Oprea