Displaying Video With the ev1 Video to Screen Path

By Michael Portuesi.

Introduction

Because the VL supports so many different pieces of video hardware, you might be tempted to think that for a given task, such as displaying incoming video on the workstation screen, that you may write one piece of code for all the devices VL supports. Unfortnately you cannot, and nowhere is this more apparent than when you are programming video display using Galileo (ev1) and its relatives.

With most video devices that support a full rate video path to memory, you can create a video to memory path and display the video in your application using OpenGL. Your application wakes up whenever the transfer buffer is full, retrieves a frame from the buffer, and draws the frame to the display.

Galileo does not offer you this option; its video to memory path does not support a full-rate stream into memory. Instead, it offers a VL screen node. You create a video to screen path using the VL, set some controls on the path to tell the screen node the X window it should use and where the video should be located, then call vlBeginTransfer() to display the video to the user.

The code to display video using ev1 differs from other devices not only in the path setup, but in the maintenance work your application must perform. Using ev1, the display work is handled automatically; your application need never service a transfer buffer. But your application must keep the video positioned and sized appropriately, and update its position if the user moves the window. This task is the central topic of this document.

The ev1 Screen Drain Nodes

The ev1 video device (in all its forms) provides the programmer with three screen drain nodes. Here's how they are described by vlinfo:

lipstick.esd.sgi.com % vlinfo
name of server: 
number of devices on server: 2

device: ev1 1
 nodes = 14

[entries omitted]

 Screen Drain A, type = Drain, kind = Screen, number = 0
 Screen Drain B, type = Drain, kind = Screen, number = 1
 Screen Drain C, type = Drain, kind = Screen, number = 2

[entries omitted]

However, in practical use, you will likely use only the first two nodes - numbers 0 and 1. Node 1 can be divided into two half-sized 12-bit screen displays. When you divide screen drain node 1, the second of the two half-displays is denoted by node number 2. This special "half size" mode is not discussed in this document, and judging from the restrictions on its use over and above those discussed here, it seems inappropriate at best for general-purpose application software.

Positioning Video, or Why Does videoin Jump All Around the Screen?

By far, the biggest headache facing the ev1 programmer is simply positioning the video at the right place on the screen. The video drain doesn't render into the framebuffer, as does all other visual display on the system. Instead, the ev1 device provides a hardware-generated "overlay" which is merged with the contents of the frame buffer. As such, all attributes of the video display including screen position and size are controlled through the VL, rather than through X or OpenGL.

To make matters worse, the ev1 hardware imposes a raft of restrictions on where and and under what circumstances the video overlay can be positioned. None of them are particularly friendly to the application developer. Here is a list of the problems:

How to Position Video Properly in a Motif application

A civilized application program must allow its windows to go where the user places them. We can forgive videoin due to its simplicity. But a better solution for most applications is to put the window where the user wants it, but to post a notifier if the ev1 video display cannot be placed to match the window location. This might disappoint the user, but nevertheless it still leaves them feeling like they have control over the windows on their screen.

Sizing Video

Get Out of Jail For Free (almost)

Yet another unpleasant side effect of the ev1 video overlay are the "jailbars" which appear when the window is larger than the video, or when the user moves around on the screen a window containing ev1 video.

The "jailbars" happen when you assign an X window to the video node by setting the VL_WINDOW control on the path. The graphics hardware ignores the framebuffer contents for that region of the display, replicating the last value that was in its hardware registers. That last value is usually the pattern for the window manager border, which when replicated looks like a row of brass bars on the display.

If the window is larger than the video overlay, the regions of the window above and below the video overlay which don't contain video information will display jailbars. There is no way around this. There are a few ways to deal with the problem:

IMPACT Graphics do not display jailbars when used with ev1. But unless you know your application will run only on IMPACT, you need to worry about jailbars.

Finally, once a window is used with the ev1 video display node, it cannot be used for anything else. You cannot render into the window using X or GL drawing operations, even if you destroy the ev1 path which was displaying into the window. Once a window is in jail, it's a life sentence. The only surefire way to "get out of jail" is to destroy the window and create one anew.

Why Can't I See the Video?

There is a very common problem encountered by people who try to display ev1 video within an X or Motif program. If you call vlBeginTransfer() before the window intended to display it is fully created and mapped (shown) to the screen, the video will not display.

This problem occurs because the X window system is asynchronous. The X server does not immediately create and display windows when the application invokes the appropriate calls. Instead, the requests are queued up for the server, which performs them at some arbitrary point in the future. If you start the transfer immediately after calling a function like XtManageChild() or XMapWindow(), the video display won't work.

There are two ways to deal with the problem.

Handling Signal Preemption

When your code receives a VLStreamAvailable event for the display path, your code should do the following: