Managing video windows

You can render video to a display using the Screen Graphics Subsystem library.

The following example shows how to give mm-renderer a window group and window 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 the Screen API functions to manipulate the output.

To begin, we define a window name to use as the window ID and retrieve the unique group name created by screen_create_window_group(). We use these two properties to set the output URL, video_device_url.

const char *window_name = "appwindow";
char *window_group_name;
int MAX_WINGRP_NAME_LEN = 49;
window_group_name = (char *)malloc(MAX_WINGRP_NAME_LEN);

// Create the video URL for mm-renderer
static char video_device_url[PATH_MAX];

// Create a window group. 
// Pass NULL to generate a unique window group name.
if (screen_create_window_group(g_screen_win, NULL) != 0) {
    return EXIT_FAILURE:
}

// Get the window group name.
rc = screen_get_window_property_cv( g_screen_win, 
                                    SCREEN_PROPERTY_GROUP, 
                                    PATH_MAX,
                                    window_group_name );
if (rc != 0) {
    fprintf( stderr, 
     "screen_get_window_property(SCREEN_PROPERTY_GROUP) failed.\n" );
    return EXIT_FAILURE;
}
rc = snprintf( video_device_url, 
               PATH_MAX,
               "screen:?winid=%s&wingrp=%s", 
               window_name, 
               window_group_name );

if (rc < 0) {
    fprintf(stderr, "Error building video device URL string\n");
    return EXIT_FAILURE;
}
else if (rc >= PATH_MAX) {
    fprintf(stderr, "Video device URL too long\n");
    return EXIT_FAILURE;
}

// Create the video context name for mm-renderer
static const char *video_context_name = "videoContext";

After the window group is created, we connect to mm-renderer and create a context. We then attach the video output to the context by calling mmr_output_attach(), specifying the URL variable that we set up earlier. We use the same function to attach the audio output.

// Configure mm-renderer
mmr_connection = mmr_connect(NULL);
if (mmr_connection == NULL) {
    fprintf(stderr, "Error connecting to renderer service: %s\n", 
            strerror(errno));
    return EXIT_FAILURE;
}

mmr_context = mmr_context_create( mmr_connection, 
                                  video_context_name, 
                                  0, 
                                  S_IRWXU|S_IRWXG|S_IRWXO );
if (mmr_context == NULL) {
    fprintf(stderr, "Error creating renderer context: %s\n", 
            strerror(errno));
    return EXIT_FAILURE;
}

// Configure video and audio output
const mmr_error_info_t* errorInfo;
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);
    fprintf(stderr, "Attaching video output produced error code \
            %d\n", errorInfo->error_code); 
    return EXIT_FAILURE;
}

audio_device_output_id = mmr_output_attach( mmr_context, 
                                            audio_device_url, 
                                            "audio" );
if (audio_device_output_id == -1) {
    // Call mmr_error_info(), display an error message, and exit
    ...
}

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 important so that we can 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 ) {
    fprintf(stderr, "Error creating screen context: %s\n", 
            strerror(errno));
    return EXIT_FAILURE;
}

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);
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)) {
    char id[256];

    rc = screen_get_event_property_pv( screen_event, 
                                       SCREEN_PROPERTY_WINDOW,
                                       (void**)&video_window );
    if (rc != 0) {
        fprintf(stderr, "Error reading event window: %s\n", 
                strerror(errno));
        return EXIT_FAILURE;
    }

    rc = screen_get_window_property_cv( video_window, 
                                        SCREEN_PROPERTY_ID_STRING, 
                                        256, 
                                        id );
    if (rc != 0) {
        fprintf(stderr, "Error reading window ID: %s\n", 
            strerror(errno));
        return EXIT_FAILURE;
    }

    if (strncmp(
            id, window_group_name, strlen(window_group_name)) != 0)
        fprintf(stderr, "Mismatch in window group names\n");
        return EXIT_FAILURE;
}

After we have this handle, we can manipulate the video window directly 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;
if (app_window_above) {
    screen_val = 1;
}
else {
    screen_val = -1;
}

if (screen_set_window_property_iv( video_window, 
                                   SCREEN_PROPERTY_ZORDER, 
                                   &screen_val ) != 0) {
    fprintf(stderr, "Error setting z-order of video window: %s\n", 
            strerror(errno));
    return EXIT_FAILURE;
}

// Set the video window to be visible.
screen_val = 1;
if (screen_set_window_property_iv( video_window, 
                                   SCREEN_PROPERTY_VISIBLE, 
                                   &screen_val) != 0 ) {
    fprintf(stderr, "Error making window visible: %s\n", 
            strerror(errno));
    return EXIT_FAILURE;
}
...