Chapter 16. Windows
Prev |  | Next

## Chapter 16. Windows

Rendering to the graphics hardware requires a window. A window is an allocated area of the screen with associated framebuffer resources.

For IRIX and Linux, the X window system manages the use of shared resources among the different windows. Windows can be requested directly from an X window server. By use of the GLX extension, OpenGL Performer-based OpenGL graphics contexts can render into X windows.

For Microsoft Windows, HWNDs and OpenGL/WGL contexts are used.

This chapter describes how to create, configure, manipulate, and communicate with a window using pfWindow in OpenGL Performer. The extended `libpf` object pfPipeWindow, based on pfWindow, is also mentioned in this chapter as the two objects share much functionality. Likewise, for good understanding of windowing issues, read the next chapter, Chapter 17, “pfPipeWindows and pfPipeVideoChannels”.

## pfWindows

The pfWindow object provides an efficient windowing interface between your application and the X Window System or the Microsoft Windows GUI. pfWindows typically create an X window (an HWND on Microsoft Windows) or can also be configured to embed your rendering area within a window created with Motif® or other windowing toolkits. `libpr` provides utilities to shield you from the differences between the different types of windows and guide you in your dealings with the window system. pfWindows also keep track of your graphics state: they include a pfState which is automatically initialized when you open a window and switched for you when you change windows. Simple `libpr` windowing support centers around the pfWindow. The `libpf` windowing support utilizes a pfWindow as part of a pfPipeWindow.

OpenGL Performer automatically configures and initializes your window so that it will be ready to start rendering efficiently. In the simplest case, pfWindows make creating a graphics application that can run on any SGI machine with OpenGL a snap. pfWindows do not limit your ability to configure any part or all of your windowing environment yourself; you can use the `libpr` pfWindows to manage your GL windows even if you create and configure the actual windows yourself.

## Creating a pfWindow

A pfWindow structure is created with pfNewWin(). It can then be immediately opened with pfOpenWin(). Example 16-1 shows the most basic pfWindow operations in `libpr` program: to open and clear a pfWindow and swap front and back color buffers.

Example 16-1. Opening a pfWindow

    int main (void)
    {
         pfWindow *win;
         /* Initialize Performer */
         pfInit();
         pfInitState(NULL);

         /* Create and open a Window */
         win = pfNewWin(NULL);
         pfWinName(win, “Hello from OpenGL Performer”);
         pfOpenWin();

         /* Rendering loop */
         while (1)
         {
             /* Clear to black and max depth */
             pfClear(PFCL_COLOR | PFCL_DEPTH, NULL);
             ...
             pfSwapWinBuffers(win);
         }
    }

The pfWindow in Example 16-1 will have the following configuration:

Window system interface
| An OpenGL window using the OpenGL/X GLX interface on IRIX and Linux or an OpenGL HWND on Microsoft Windows.
Screen
| On IRIX and Linux, the pfWindow will open a window on the screen specified by the DISPLAY environment variable or else on screen 0. On Microsoft Windows, screen 0 will always be used.
Position and size
| The position and size will be undefined and the window will come up as a rubber-band for the user to place and stretch.
Framebuffer configuration
| The window will be double-buffered RGBA with depth and stencil buffers allocated. The size of these buffers will depend on the available resources of the current graphics hardware platform. pfWindows will also have multisample buffers allocated if they are available on current hardware platform.
`libpr` state
| A pfState will be created and initialized with all modes disabled and no attributes set.
Graphics state
| The pfWindow will be in RGBA color mode with subpixel vertex positioning, depth testing and viewport clipping enabled. The viewing projection will be a two-dimensional one-to-one orthographic mapping from eye coordinates to window coordinates with distances to near and far clipping planes -1 and 1, respectively. The model matrix will be the current matrix and will be initialized to the identity matrix.

Typically, pfWindows go through a bit more initialization than that of Example 16-1. The pfWindow type, set with pfWinType(), is a bitmask that selects the window system interface and the type of rendering window. Table 16-1 lists the possible selectors that can be ORed together for specification of the window type.

Table 16-1. pfWinType() Tokens

PFWIN_TYPE_ Bitmask Token | Description
--- | ---
X | Window will be an X window on IRIX and Linux but will be an HWND on Microsoft Windows. This is the default.
STATS | Window will have framebuffer resources to accommodate hardware statistics modes. This type cannot be combined with PFWIN_TYPE_OVERLAY or PFWIN_TYPE_NOPORT.
OVERLAY | Window will have only overlay planes for rendering. This type cannot be combined with PFWIN_TYPE_STATS or PFWIN_TYPE_NOPORT.
NOPORT | Window will have a graphics context but no physical window or graphics or framebuffer rendering resources and will not be placed on the screen. This token can not be used in combination with any other type token.
PBUFFER | The pfWindow drawable will be created as a pbuffer and will not be visible.
UNMANAGED | Other than select upon open, no unrequested window management operations are done automatically on the pfWindow.

The selection of screen can be done explicitly with pfWinScreen(), or implicitly by opening a connection to the window system using pfOpenScreen() with the desired screen as the default screen. A window system connection can communicate with any screen on the system; the default screen only determines the screen for windows that do not have a screen explicitly set for them. Only one window system connection should be opened for a process. See “Communicating with the Window System” later in this section for details on efficient interaction with the window system.

The position and/or size, is set with pfWinOriginSize(). If the x and y components of the origin are (-1), the window will open with position undefined for the user to place. If the x or y components of the size are (-1), the window will open with both position and size undefined (the default) for the user to place and stretch. On IRIX and Linux, the X window manager may override negative origins and place the window at (0,0). If the window is already opened when pfWinOriginSize() is called, the window will be reconfigured to the specified origin and size upon the next pfSelectWin(). Similarly, pfWinFullScreen() causes a window to open as full screen or to become full screen upon the next call to pfSelectWin(). A full screen window will have its border automatically removed so that the drawing area truly gets the full rendering surface. The routines for querying the position and size work a bit differently than the pattern established by the rest of `libpr` get and set pairs of routines. This is because a user may change the origin or size independently of the program and under certain conditions, querying the true current X window size and origin can be expensive. pfGetWinOrigin() and pfGetWinSize() will always be fast and returns the last explicitly set origin and size, such as by pfOpenWin(), pfWinOriginSize(), or pfWinFullScreen(). If the window origin or size has been changed, but not through a pfWindow routine, the values returned by pfGetWinOrigin() and pfGetWinSize() may not be correct. pfGetWinCurOriginSize() returns an accurate size and origin relative to the pfWindow parent. For X windows, note that it requires an expensive query to the X server and should not be done in real-time situations. pfGetWinCurScreenOriginSize() returns the size and the screen-relative origin of the pfWindow. As with pfGetWinCurOriginSize(), this command will be quite expensive and is not recommended accept for rare use or initialization purposes.

pfPipeWindows, discussed in Chapter 17, “pfPipeWindows and pfPipeVideoChannels”, take advantage of the multiprocessed `libpf` environment to always be able to return an accurate window size and origin relative to the window parent. However, even for pfPipeWindows, getting a screen-relative origin can be an expensive operation.

Write programs that are window-relative and do not depend on knowing the current exact location of a window relative to its parent or screen.

## Configuring the Framebuffer of a pfWindow

OpenGL Performer provides a default framebuffer configurations for the current graphics hardware platform for the standard window types: normal rendering, statistics (stats), and overlay. You may want to define your own framebuffer configuration, such as single-buffered, stereo, etc. You can use utilities in `libpr` to help you with this task, or create your own framebuffer configuration structure with X utilities, or even create the window yourself and apply it to the pfWindow. pfOpenWin() respects any specified framebuffer configuration. Additionally, pfOpenWin() uses any window or graphics context that is assigned to it and only creates what is undefined.

pfWinFBConfigAttrs() can be used to specify an array of framebuffer attribute tokens listed in Table 16-2. The tokens correspond to OpenGL/X tokens. Note that if an attribute array is specified, the tokens modify configuration with no attributes set, not the default OpenGL Performer framebuffer configuration.

Table 16-2. pfWinFBConfigAttrs() Tokens

PFFB_ Token | Value | Description
--- | --- | ---
BUFFER_SIZE | integer > 0 | The size of the color index buffer.
LEVEL | integer > 0 | The color plane level: normal color planes have level = 0 overlay color planes have level > 0 underlay color planes have level < 0 There may be only one or no levels for overlay and underlay color planes on some graphics hardware configurations.
RGBA | Boolean: true if present | Use RGBA color planes (instead of color index).
DOUBLEBUFFER | Boolean: true if present | Use double-buffered color buffers.
STEREO | Boolean: true if present | Allocate left and right stereo color buffers (allocates back left and back right if DOUBLEBUFFER is specified.
AUX_BUFFER | integer > 0 | Number of additional color buffers to allocate.
RED_SIZE GREEN_SIZE BLUE_SIZE ALPHA_SIZE | integer > 0 | Minimum number of bits color for components R, G, and B will all be the same and be the maximum specified. Alpha may be different.
DEPTH_SIZE | integer > 0 | Number of bits in the depth buffer.
STENCIL | integer > 0 | Number of bits allocated for stencil. One is used by pfDecal rendering and three or four are used by the hardware fill statistics in pfStats.
ACCUM_RED_SIZE ACCUM_GREEN_SIZE ACCUM_BLUE_SIZE ACCUM_ALPHA_SIZE | integer > 0 | Number of bits per RGBA component for the accumulation color buffer.
USE_GL | Boolean: true if present | Exists for historical reasons. Has no effect.

If you desire more control over the exact framebuffer configuration of your pfWindow, you have several options. For OpenGL/X windows you can provide the appropriate framebuffer description for the current GL operation to the pfWindow using pfWinFBConfig(). X uses visuals to describe available framebuffer configurations. XVisualInfo pointer with XGetVisualInfo() returns a list of all visuals on the system and you can search through them to find the appropriate configuration. On IRIX-based systems, OpenGL/X also uses GLXFBConfigSGIX to describe framebuffer configurations. You can select either the visual or the GLXFBConfigSGIX for your window and set it on the pfWindow with pfWinFBConfig(). pfGetWinFBConfig() always returns the corresponding X visual.

`libpr` also offers utilities for creating framebuffer configurations (pfFBConfig) independently of a pfWindow. pfChooseFBConfig() takes an attribute array of tokens from Table 16-2 and will return a pfFBConfig structure that can be used with your pfWindows, or with X Windows created outside of `libpr`, such as with Motif. You may get back a framebuffer configuration that is better than the one you requested. OpenGL Performer will give you back the maximum framebuffer configuration that meets your request that will not add any serious performance degradations. There are specific machine-dependent instances where, for performance reasons, we do limit the framebuffer configuration. See the man page for pfChooseWinFBConfig() for the specific details. The `libpfutil` utility pfuChooseFBConfig() in `/usr/share/Performer/src/lib/libpfutil/xwin.c` (IRIX and Linux) and `%PFROOT%\Src\lib\libpfutil\xwin.c` (Microsoft Windows) provides a limiting framebuffer configuration selector, complete with source code.

You can use pfQuerySys() to query particular framebuffer resources in the current hardware configuration and then use pfQueryWin() to query your resulting framebuffer configuration.

## pfWindows and GL Windows

| Note: This is an advanced topic.

For IRIX and Linux, `libpr` allows you to use X window handles and OpenGL/X graphics contexts to create your own windows and to set them on the pfWindow. These handles can be assigned to the pfWindow with pfWinWSDrawable() or pfWinGLCxt(). For Microsoft Windows, you can do the same, but you must use HWNDs (instead of X window handles) and OpenGL/WGL graphics contexts.

pfOpenWin() will automatically call pfInitGfx() and will automatically create a new pfState for your window. If you have your own window management and do not call pfOpenWin(), then you should definitely call pfInitGfx() to initialize the window's graphics state for OpenGL Performer rendering. You will also need to call pfNewState() to create a pfState for OpenGL Performer's state management.

For X windows, OpenGL Performer maintains two windows and a graphics context. The top level X window is placed on the screen and is the one that you should use in your application for selecting X events. This top level window is very lightweight and has minimal resources allocated to it. OpenGL Performer then maintains a separate X window that is a child of the parent X window and is the one that is attached to the graphics context. This allows you to select different framebuffer resources for the same drawing area by just selecting a different graphics window and graphics context pair for the parent X window. pfWindows directly support this functionality and this is discussed in the next section, “Manipulating a pfWindow”. Finally, with OpenGL, you may choose to draw to a different X Drawable than a window. X windows are created with the X function XCreateWindow(). OpenGL graphics contexts are created with glXCreateContext(). The parent X Window can be set with pfWinWSWindow(), the graphics window or X Drawable is set with pfWinWSDrawable() and can be an X window, pbuffer, or pixmap. The graphics context is set with pfWinGLCxt(). OpenGL Performer defines the following window-system-independent types defined in Table 16-3. If you create your own window but want to use pfQueryWin(), you must also provide the framebuffer configuration information with pfWinFBConfig(). pfQueryWin() uses the internally stored visual.

Table 16-3. Window System Types

pfWS Type | X Type | pfWindow Set/Get Routine
--- | --- | ---
pfWSWindow | X Window for IRIX and Linux HWND for Microsoft Windows | pfWinWSWindow() pfGetWinWSWindow()
pfWSDrawable | Drawable (window, pbuffer, pixmap) for IRIX and Linux HANDLE (to window or buffer) for Microsoft Windows | pfWinWSDrawable() pfGetWinWSDrawable()
pfGLContext | OpenGL: GLXContext for IRIX and Linux HGLRC for Microsoft Windows | pfWinGLCxt() pfGetWinGLCxt()
pfFBConfig | XVisualInfo* or GLXFBConfigSGIX* for IRIX and Linux `int` (pixel format ID) for Microsoft Windows | pfWinFBConfig() pfGetWinFBConfig()
pfWSConnection | Display* for IRIX and Linux only | pfGetCurWSConnection()

## Manipulating a pfWindow

Windows are opened with pfOpenWin() and closed with pfCloseWin(). When a window is closed, its graphics context is deleted. If you have multiple windows, you select the window to draw to with pfSelectWin(). Multiple windows can be made more efficient using share groups configured with pfWinShare() to share hardware resources. Multiple windows can be made to have swapbuffers execute simultaneously through window swap groups created with pfAttachWinSwapGroup(). There are also some additional modes on pfWindows to control their behavior under various operations. This section goes through the basics of these important features.

There are some modes you can set that can effect the general look and behavior of your window and alternate configuration windows. These boolean modes can be individually set and changed at any time with pfWinMode() and the tokens in Table 16-4.

Table 16-4. pfWinMode() Tokens

PFWIN_ Token | Description
--- | ---
NOBORDER | Window will be without normal window system border
HAS_OVERLAY | Overlay alternate configuration window will be managed by the pfWindow. pfOpenWin() will automatically create an overlay window if one has not already been set. pfWinIndex(win, PFWIN_OVERLAY_WIN) will also automatically create and open an overlay window if one has not already been set.
HAS_STATS | Statistics alternate configuration window will be managed by the pfWindow. pfOpenWin() will automatically create a statistics window if one has not already been set. pfWinIndex(win, PFWIN_OVERLAY_WIN) will also automatically create and open a statistics window if one has not already been set and if the current window cannot support statistics.
AUTO_RESIZE | The graphics window and active alternate configuration windows are automatically resized to match the parent pfWinWSWindow(). This mode is enabled by default.
ORIGIN_LL | The origin of the pfWindow, for placement purposes, will be the lower-left corner. X and the Microsoft Windows GUI use the upper left corner as the origin. This mode is enabled by default.
EXIT | The application will receive a DeleteWindow message upon selection of the “Exit” from the window system menu on the window border.

### Alternate Framebuffer Configuration Windows

OpenGL Performer supports multiple framebuffer configurations for the same drawing area with alternate configuration windows. An OpenGL Performer alternate configuration window has the same window parent ( pfWinWSWindow()) but may have a different drawable and graphics context. There are standard alternate configuration windows for overlay and statistics windows that can be automatically created upon demand.

An alternate configuration window is created as a full pfWindow and is an alternate configuration window by virtue of being given to a base window in a pfList of alternate configuration windows, or being directly assigned as one of the standard alternate configuration windows with either of pfWinOverlayWin() or pfWinStatsWin(). A pfWindow may be an alternate configuration window of only one base window at a time; alternate configuration windows may not be instanced between base windows. The sharing of window attributes between alternate configuration windows, such as the parent X window and GL objects (for OpenGL windows), must be set with pfWinShare() on the base window and applied to the alternate configuration windows with pfAttachWin(). You select the desired alternate configuration window to draw into with pfWinIndex() and provide an index into your alternate configuration window list or one of the standard indices ( PFWIN_GFX_WIN, PFWIN_OVERLAY_WIN, or PFWIN_STATS_WIN). PFWIN_GFX_WIN is the default window index and selects the base window. If the alternate configuration window has not been opened, it will be opened automatically upon being selected for rendering. Example 16-2 demonstrates creating a pfWindow using the default overlay window. The graphics drawable and graphics context of an alternate configuration window of a pfWindow can be closed with pfCloseWinGL(). This can be called on the base window, in which case the active alternate configuration window's GL window and context will be closed, or it can be called on the alternate configuration window pfWindow directly. The main parent window will remain on the screen and a new alternate configuration window can be applied to it or pfOpenWin() can be called to create a new graphics window and context.

### Window Share Groups

Multiple windows on a screen will require duplicate processing and resources unless they are set up as share groups. A pfWindow is attached to the group of another with pfAttachWin(groupWin, attachee). The attributes to be shared are set with pfWinShare() on any of the windows in the group. The full list of attributes are in the man page for pfWindow (and similarly for pfPipeWindow) but most notably are PFWIN_SHARE_GL_CXT for using the same graphics context across multiple windows, PFWIN_SHARE_STATE for sharing full state information, and PFWIN_SHARE_GL_OBJS for sharing display lists and textures across windows. In particular, sharing GL objects is important if a display list (such as for fonts) are to be created for one context and used in multiple contexts. When default alternate configuration windows are automatically created (overlay and stats) they are configured to share GL objects with the base window. A `libpf` pfPipeWindow example of window share groups is in `/usr/share/Performer/src/pguide/libpf/C/multiwin.c` for IRIX and Linux and in `%PFROOT%\Src\pguide\libpf\C\multiwin.c` for Microsoft Windows.

### Synchronization of Buffer Swap for Multiple Windows

On IRIX systems, double-buffered pfWindows in window swap groups will have simultaneous hardware execution of the buffer swap. There is a similar mechanism for pfPipeWindows activated through pfChannel share groups sharing PFCHAN_SWAPBUFFERS_HW that is discussed in Chapter 2, “Setting Up the Display Environment”.

A window swap group is created by attaching windows with pfAttachWinSwapGroup(groupWin, attachee). There is no global list maintained for the swap group and their status so you cannot get back a list of windows in the group. However, pfWinInSwapGroup() returns 1 if the specified window as been synchronized to a swap group and 0 otherwise. This synchronization configuration will actually take place upon a call to pfSelectWin() for the window. Windows of separate screens can be attached but this also requires a BNC cable (of any Ohms) to be attached to the swap ready connectors of the graphics pipelines. Detach from swap groups is not supported. GLX barriers are used for multi-pipeline synchronization. If necessary, you can have a pfWindow explicitly join a specific barrier group with pfWinSwapBarrier(). When windows of multiple screens are attached, the video vertical retrace of those screens should also be syncrhonized with `genlock(7)`.

## Communicating with the Window System

You can communicate with a local or remote window server by means of a window system connection, a pfWSConnection (in X, also known as a Display connection). You can use your pfWSConnection for selecting X events for your window, as is demonstrated in Example 16-4.

`libpr` offers several utilities for creating a connection to a window server. A given connection can communicate with any screen managed by that window server so usually a process only needs one connection. A process should not share the connection of another process, so you will need a connection per process. Typically, there is exactly one window server on a machine but that is not required. l`ibpr` maintains a pfWSConnection for the current process. By default, this connection obeys the setting of the DISPLAY environment variable which can point to a window server on a local or a remote machine. The current connection can be requested with pfGetCurWSConnection() and can be set with pfSelectWSConnection(). Whenever possible, use this connection to limit the total number of open connections. pfOpenScreen() is a convenient mechanism for opening a connection with a specified default screen. pfOpenWSConnection() allows you to specify the exact name specifying the desired target for the connection. Both pfOpenScreen() and pfOpenWSConnection() allow you to specify if you would like the new connection to automatically be made the current `libpr` pfWSConnection; this is recommended.

## More pfWindow Examples

Example 16-2 demonstrates the creation of a window with a default overlay window.

Example 16-2. Using the Default Overlay Window

    int main (void)
    {
        pfWindow *win, *over;
        /* Initialize Performer */
        pfInit();
        pfInitState(NULL);

        /* Initialize the window. */
         win = pfNewWin(NULL);
         pfWinOriginSize(win, 100, 100, 500, 500);
         pfWinName(win, “OpenGL Performer”);
         pfWinType(win, PFWIN_TYPE_X);
         pfWinMode(win, PFWIN_HAS_OVERLAY, 1);
         pfOpenWin(win);
         /* First select and draw into the overlay window */
         pfWinIndex(win, PFWIN_OVERLAY_WIN);
         /* Select causes the index to be applied */
         pfSelectWin(win);
         ...
         /* Then select the main gfx window */
         pfWinIndex(win, PFWIN_GFX_WIN);
         pfSelectWin(win);
         ...
    }

Example 16-3 demonstrates creating a custom overlay window and is taken from the sample program `/usr/share/Performer/src/pguide/libpr/C/winfbconfig.c` for IRIX and Linux and `%PFROOT%\Src\pguide\libpr\C\winfbconfig.c` for Microsoft Windows.

Example 16-3. Creating a Custom Overlay Window

    static int OverlayAttrs[] = {
     PFFB_LEVEL, 1, /* Level 1 indicates overlay visual */
     PFFB_BUFFER_SIZE, 8,
     None,
    };

    int main (void)
    {
        pfWindow *win, *over;
        /* Initialize Performer */
        pfInit();
        pfInitState(NULL);

        /* Initialize the window. */
         win = pfNewWin(NULL);
         pfWinOriginSize(win, 100, 100, 500, 500);
         pfWinName(win, “OpenGL Performer”);
         pfWinType(win, PFWIN_TYPE_X);
         pfWinMode(win, PFWIN_HAS_OVERLAY, 1);

         over = pfNewWin(NULL);
         pfWinName(over, “OpenGL Performer Overlay”);
         pfWinType(over, PFWIN_TYPE_X | PFWIN_TYPE_OVERLAY);
         /* See if we can get the desired overlay visual */
         if (!(pfChooseWinFBConfig(over, OverlayAttrs)))
             pfNotify(PFNFY_NOTICE, PFNFY_PRINT,
                “pfChooseWinFBConfig failed for OVERLAY win”);
         pfOpenWin(win);
         /* First select and draw into the overlay window */
         pfWinIndex(win, PFWIN_OVERLAY_WIN);
         /* Select causes the index to be applied */
         pfSelectWin(win);
         ...
         /* Then select the main gfx window */
         pfWinIndex(win, PFWIN_GFX_WIN);
         pfSelectWin(win);
         ...
    }

Example 16-4 demonstrates the selection of X input events on a pfWindow. This example is taken from `/usr/share/Performer/src/pguide/libpr/C/hlcube.c` for IRIX and Linux and from `%PFROOT%\Src\pguide\libpr\C\hlcube.c` for Microsoft Windows.`.` See the `/usr/share/Performer/src/pguide/libpf/C/complex.c` sample program for a detailed example of using either standard or forked X input on pfWindows for IRIX and Linux and sample program `%PFROOT%\Src\pguide\libpf\C\complex.c` for Microsoft Windows.

Example 16-4. pfWindows and X Input

        pfWSConnection Dsp;

    void main (void)
    {
        pfWindow *win;
        pfWSWindow xwin;

        /* Initialize Performer */
        pfInit();
        pfInitState(NULL);

        /* Initialize the window. */
         win = pfNewWin(NULL);
         pfWinOriginSize(win, 100, 100, 500, 500);
         pfWinName(win, “OpenGL Performer”);
         pfWinType(win, PFWIN_TYPE_X);
         pfOpenWin(win);
         ...
         /* set up X input event handling on pfWindow */
         Dsp = pfGetCurWSConnection();
         xwin = pfGetWinWSWindow(win);
         XSelectInput(Dsp, xwin, KeyPressMask );
         XMapWindow(Dsp, xwin);
         XSync(Dsp,FALSE);
         ...
         do_events(win);
    }
    static void
    do_events(pfWindow *win)
    {
        while (1) {
        while (XPending(dsp))
        {
             XEvent event;
             XNextEvent(Dsp, &event);
             switch (event.type)
             {
             case KeyPress:
              ....
              }
         }
    }

Prev | Table of Contents | Next
Chapter 15. ClipTextures |  | Chapter 17. pfPipeWindows and pfPipeVideoChannels