Managing video windows

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

The following example shows how to:
  • Create the Screen window and window group using the Screen API
  • Direct mm-renderer video output to that Screen window and window group
  • Define the video and audio outputs
  • Check that the ID of a newly created window matches the output window's name
  • Manipulate the video output through Screen using Screen API functions.

Creating the Screen window and window group

We begin by creating a Screen context, and then use this context to create an application window. We then use the new window's handle to create the window group:

    screen_context_t g_screen_ctxt;
    
    if (screen_create_context(&g_screen_ctxt, SCREEN_APPLICATION_CONTEXT) != 0) {
    ERROR_HANDLING_CODE(); /* Error-handling code (e.g., printing an error message) goes here */
    return EXIT_FAILURE;
    }
    
    screen_window_t g_screen_win;
    
    if (screen_create_window_type(&g_screen_win,
    g_screen_ctxt,
    SCREEN_APPLICATION_WINDOW) != 0) {
    /* Error-handling code goes here */
    return EXIT_FAILURE;
    }
    
    // Create a window group -- pass in NULL to generate a unique group name
    if (screen_create_window_group(g_screen_win, NULL) != 0) {
    /* Error-handling code goes here */
    return EXIT_FAILURE;
    }
    
    // Create a window group -- pass in NULL to generate a unique group name
    if (screen_create_window_group(g_screen_win, NULL) != 0) {
    /* Error-handling code goes here */
    return EXIT_FAILURE;
    }

Directing mm-renderer video output to the new window and window group

Next, we retrieve the window group name created by Screen and define a window name to use as the window ID. We then use these two properties to define the output URL:
    char *window_group_name = (char*)malloc(WINGRP_NAME_MAX_LEN);
    
    // 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;
    }
    
    static char video_device_url[PATH_MAX_LEN];
    const char *window_name = "appwindow";
    
    // 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 playback context. We then attach the video output to the context (by specifying the URL that we defined 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 goes here; see "Playing audio content" */
The video device URL specifies to use Screen for the output and has this form:
screen:?wingrp=window_group&winid=window_id&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
  • initflags=invisible is an optional parameter setting which 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 the window visible.

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

Next, we call mmr_input_attach() to attach the input for playback. The mm-renderer creates a window in our window group, generating the Screen event and the handle of the video window. We then check that the ID of the window indicated in the event matches our output video window. This step is important for more complicated applications, because it allows us 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 0 to prevent blocking -- the event is already waiting for us
    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_name, strlen(window_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;
    }
    
    visible = 1; // Set the video window to be visible
    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, refer to the Screen property types section in the Screen API reference.

Page updated: