Playing media

Playing media in mm-renderer requires configuring a context, attaching outputs and an input, and then issuing playback commands. These actions are all done with function calls to the Multimedia Renderer Client API.

To play media in mm-renderer:
  1. Connect to mm-renderer using the function mmr_connect().
  2. Create a new context and set the appropriate context parameters. Use the functions mmr_context_create() and mmr_context_parameters().
  3. Attach an output and set its output parameters. Use the functions mmr_output_attach() and mmr_output_parameters(). You can attach multiple outputs.
  4. Attach the input and set the input parameters. Use the functions mmr_input_attach() and mmr_input_parameters().
  5. Start playback for the context by calling mmr_play().

The media starts to play.

Play states

The possible play states of the context are:

Idle
No input is attached.
Stopped
Input is attached but is not playing.
Playing
Input is attached and is playing.

Note that there is no paused play state. Paused playback is represented by a play speed of 0.

Play speed

In mm-renderer, the play speed is represented by an integer. Normal speed is represented by a value of 1000, and 0 means paused. Note that depending on the context's input media, trick play speeds (such as negative, slower than normal or faster than normal) may not be supported.

Use the mmr_speed_set() function to change the current play speed. You can change the speed when the state is stopped; mm-renderer simply saves the setting and applies it when playback restarts.

Seeking to positions

Use the mmr_seek() function to seek to a known position in a single track or a track within a playlist. If the current context input is a track, simply specify the track position in milliseconds (for example "2500"). If the context input is a playlist, the position must be a string in the format "99:9999" (for example "2:1200") where the first number is the track position in the current playlist and the second number is the number of milliseconds from the beginning of the specified track.

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.

This example omits many steps for the sake of simplicity. For the full example, see the Video overlay sample, listed towards the bottom of the Sample apps page on the public BlackBerry website.

To begin, we define the Screen window group and window ID to use for the output. In this example, the same string is used for both: "videosamplewindowgroup_" with a random number appended to ensure uniqueness. The window group and window ID are the same in this example, but they don't have to be. We use these two properties to set the output URL, video_device_url.

app_id = rand();

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

rc = snprintf(video_device_url, PATH_MAX, 
       "screen:?winid=videosamplewindowgroup_%d
        &wingrp=videosamplewindowgroup_%d", app_id, app_id);
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 char video_context_name[PATH_MAX];
...

Using the same random number as before, we put the window group name in a variable that we can pass to the screen_create_window_group() function. Once the window group is created, we connect to mm-renderer and create a context. Finally, we attach the video output to the context by calling mmr_output_attach(), specifying the URL variable we set up earlier. We use the same function to attach the audio output.

// Window group name, with the same random number appended
static char window_group_name[PATH_MAX];

rc = snprintf(window_group_name, PATH_MAX, 
              "videosamplewindowgroup_%d", app_id);
if (rc < 0) {
    fprintf(stderr, "Error building window group name string: \
                    %s\n", strerror(errno));
    return EXIT_FAILURE;
}
else if (rc >= PATH_MAX) {
    fprintf(stderr, "Video context name too long\n");
    return EXIT_FAILURE;
}

// Create the window group for our window. This is important 
// because we pass the group name to mm-renderer, which uses it 
// to 'parent' its CHILD_WINDOW, which contains the video.
if (screen_create_window_group(
        g_screen_win, window_group_name) != 0) {
    fprintf(stderr, "Error creating window group: %s\n", 
            strerror(errno));
    return EXIT_FAILURE;
}

// 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.

Note that the function screen_event_get_event() is from the BlackBerry Platform Services (BPS) API. All other functions for getting event and window properties are from the Screen API.

screen_event_t screen_event = screen_event_get_event(event);
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;
}
...

Once 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;
}
...

Last modified: 2014-06-24



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus