Managing video windows

If you want to render video in a certain area on the display (which you typically want to do when other UI apps are running), you can use the functions from the Screen Graphics Subsystem library to configure the video window and hence, control when and where the content is displayed.

The following example shows how to give mm-renderer a window group and ID to use in creating a window on the application's behalf, configure mm-renderer for audio and video output, and get a handle to the window and use Screen API functions to manipulate the output.

Defining the output URL

To begin, we define a window name to use as the window ID and retrieve the window group name created by Screen. We then use these two properties to define the output URL:
const char *window_name = "appwindow";
char *window_group_name = (char *)malloc(WINGRP_NAME_MAX_LEN);

static char video_device_url[PATH_MAX_LEN];

// Create a window group -- pass in NULL to generate a unique name
if (screen_create_window_group(g_screen_win, NULL) != 0) {
    /* Error-handling code goes here */
    return EXIT_FAILURE:
}

// Get the window group name
rc = screen_get_window_property_cv( g_screen_win, 
                                    SCREEN_PROPERTY_GROUP, 
                                    WINGRP_NAME_MAX_LEN,
                                    window_group_name );
if (rc != 0) {
    /* Error-handling code goes here */
    return EXIT_FAILURE;
}

// Construct the output URL
rc = snprintf( video_device_url, 
               PATH_MAX_LEN,
               "screen:?winid=%s&wingrp=%s", 
               window_name, 
               window_group_name );
if (rc < 0) {
    /* Error-handling code goes here */
    return EXIT_FAILURE;
}
else if (rc >= PATH_MAX_LEN) {
    /* Error-handling code goes here */
    return EXIT_FAILURE;
}

Defining the video and audio outputs

After the window group is created, we connect to the mm-renderer service and create a context. We then attach the video output to the context (by specifying the URL that we set up earlier):
/* Code to connect to mm-renderer and create a context goes here 
   (see "Playing audio content" for an example of doing this) */
const mmr_error_info_t* errorInfo;

// Define the video and audio outputs
video_device_output_id = mmr_output_attach( mmr_context, 
                                            video_device_url,
                                            "video" );

if (video_device_output_id == -1) {
    errorInfo = mmr_error_info(mmr_context);
    /* Remaining error-handling code goes here */
    return EXIT_FAILURE;
}

/* Code to attach the audio output to same context goes here */
The video device URL we defined earlier specifies to use Screen for the output and names the window group and window ID, but there are other parameters you can set. In general, Screen output URLs have this form:
screen:?wingrp=window_group&winid=window_id&nodstviewport=1&initflags=invisible
where:
  • window_group is the window group name of the application's top-level window
  • window_id is the ID for the window where the content will be rendered
  • The parameter setting nodstviewport=1 is optional, and forces mm-renderer to never directly modify the destination viewport of the window. This avoids conflicts between simultaneous application manipulation and mm-renderer manipulation of the destination viewport.
  • The parameter setting initflags=invisible is optional and causes the window to be invisible upon creation. Enabling this flag allows you to adjust window properties such as size, position, and z-order before making it visible. The z-order must be set when you're rendering subtitles on top of a video.

Checking that the ID of a newly created window matches our window's name

Next, we retrieve the handle of the video window from the Screen event received when the window is created, and check that the ID of the window indicated in the event matches our output video window. For more complicated applications, this is necessary to distinguish between our video window and another child window belonging to the same window group.

All functions used here are from the Screen API:
// Create the screen context, which is needed to retrieve the event
screen_context_t screen_ctx = 0;
if ( screen_create_context( &screen_ctx, 
                            SCREEN_APPLICATION_CONTEXT) != 0 ) {
    /* Error-handling code goes here */
    return EXIT_FAILURE;
}

// Create an event object that will hold data from the event
screen_event_t screen_event;
screen_create_event(&screen_event);

// Set a timeout of -1 to block until an event is received
screen_get_event(screen_ctx, screen_event, -1);

// Get the type of the event just received
int event_type;
screen_get_event_property_iv( screen_event, 
                              SCREEN_PROPERTY_TYPE, 
                              &event_type );

// Check if it's a creation event and the video output window 
// has not yet been initialized
if ((event_type == SCREEN_EVENT_CREATE) && 
    (video_window == (screen_window_t)NULL)) {

    // Store a pointer to the window
    rc = screen_get_event_property_pv( screen_event, 
                                       SCREEN_PROPERTY_WINDOW,
                                       (void**)&video_window );
    if (rc != 0) {
        /* Error-handling code goes here */
        return EXIT_FAILURE;
    }
    // Get the window ID using the new pointer
    char id[256];
    rc = screen_get_window_property_cv( video_window, 
                                        SCREEN_PROPERTY_ID_STRING, 
                                        256, 
                                        id );
    if (rc != 0) {
        /* Error-handling code goes here */
        return EXIT_FAILURE;
    }
    // Compare the ID with our window's name
    if (strncmp(
            id, window_group_name, strlen(window_group_name)) != 0) {
        /* Error-handling code goes here */
        return EXIT_FAILURE;
    }
    // At this point, we know the new window's ID matches the expected 
    // name, so this window is the one we want to use
}

Manipulating the video output through Screen

After we have the video window handle, we can manipulate the output with Screen API calls:
// Set the z-order of the video window to put it above or below 
// the main window. Alternate between +1 and -1 to implement
// double-buffering to avoid flickering of output.
app_window_above = !app_window_above;
zorder = (app_window_above ? 1: -1);

if (screen_set_window_property_iv( video_window, 
                                   SCREEN_PROPERTY_ZORDER, 
                                   &zorder ) != 0) {
    /* Error-handling code goes here */
    return EXIT_FAILURE;
}

// Set the video window to be visible
visible = 1;

if (screen_set_window_property_iv( video_window, 
                                   SCREEN_PROPERTY_VISIBLE, 
                                   &visible) != 0 ) {
    /* Error-handling code goes here */
    return EXIT_FAILURE;
}

For a full list of the windows properties that can be set, see the Screen property types section in the Screen API reference.