Start your video

Now we're ready to start playing our video! Assuming the video is located somewhere on your device (it will be if you've bundled it in your app's package), we need to let mm-renderer know where it is and tell it to start playing. First, we create a temporary render buffer to fill with color.

screen_buffer_t temp_buffer[1];
screen_get_window_property_pv(screen_window,
    SCREEN_PROPERTY_RENDER_BUFFERS, (void**)temp_buffer);

Then, we fill the temporary render buffer with the color black.

int fill_attributes[3] = {SCREEN_BLIT_COLOR, 0x0, SCREEN_BLIT_END};
screen_fill(screen_context, temp_buffer[0], fill_attributes);

Next, we define a rectangle that bounds the area to change (in this case, the entire width and height of the window). The buffer is then made visible through the window by calling screen_post_window().

screen_get_window_property_iv(screen_window, SCREEN_PROPERTY_SIZE, screen_size);
int temp_rectangle[4] = {0, 0, screen_size[0], screen_size[1]};
screen_post_window(screen_window, temp_buffer[0], 1, temp_rectangle, 0);

If you were to run the app at this point, you would see a black screen:

Device image showing the black screen.

There are a few more steps to get something really playing. We want to make sure that the screen doesn't dim while the user is enjoying the video. We set the SCREEN_PROPERTY_IDLE_MODE property to SCREEN_IDLE_MODE_KEEP_AWAKE. You don't need to do this step for videos that are actively playing but it's something useful to know for your other apps.

int idle_mode = SCREEN_IDLE_MODE_KEEP_AWAKE;
screen_set_window_property_iv(screen_window,
    SCREEN_PROPERTY_IDLE_MODE, &idle_mode);

We then create the path that represents the location of the media file on your device. In this case, we use the location of the bundled app resource but it could be in the shared folder as well.

char cwd[PATH_MAX];
char media_file[PATH_MAX];
getcwd(cwd,PATH_MAX);

snprintf(media_file, PATH_MAX, "file://%s/app/native/pb_sample.mp4", cwd);

Configure the aspect ratio

We ensure that the video is displayed in the best possible way by checking the aspect ratio.

We use the function set_video_aspect_ratio() to calculate the lower-left coordinate, width, and height of the rectangle that the video is displayed in. This information is based on the source video's resolution. The calculation maximizes the source video so that it fits into the actual screen of the device (because the video may have a different size).

set_video_aspect_ratio(screen_size[0], screen_size[1], video_window);

Let's have a look at what's happening in set_video_aspect_ratio(). The video that we're playing in this tutorial is an .mp4 file with a resolution of 640 x 480. The aspect ratio of the video is 1.33 (calculated by 640/480) and we allow an aspect ratio tolerance of .1. Our app assumes we're using a BlackBerry Z10, which has a resolution of 1280 x 768, and an aspect ratio of 1.66. We need to calculate a new video size to make it fit the dimensions of the screen while maintaining the proportions of the video, so that the image doesn't seem stretched or shrunk. When you create your app, the sizes of your video and device may differ and you want to perform queries to get their resolutions and calculate their aspect ratios.

The function set_video_aspect_ratio() uses the width and height of the screen as parameters. We calculate the aspect ratio of the video by dividing the width by the height.

void set_video_aspect_ratio(int width, int height, screen_window_t video_window) {
    const int video_width = 640;
    const int video_height = 480;
    const float video_aspect = (float)video_width / (float)video_height;
    const float aspect_tolerance = 0.1;

    int win_position[2] = {0, 0};
    int win_size[2] = {width, height};
    

We want to adapt the size of the video frame to the size of the device screen that the video plays on. We want to make it the biggest possible size that fits on the screen of the device.

We calculate the screen aspect ratio by dividing the screen's width by its height. If the difference between the screen aspect ratio and the video aspect ratio is less than our tolerance value of 0.1, we consider the video a full-screen video. If the first if statement evaluates to true, no operations are performed, execution falls through, and the desired aspect ratio remains full screen.

float screen_aspect = (float)width/(float)height;
    if (fabs(screen_aspect - video_aspect) < aspect_tolerance) {
       
    } else if (screen_aspect < video_aspect) {

If the screen height is taller than the video's height, we need to center the video vertically and set the video width to be the same as the screen width while maintaining the aspect ratio. We have to figure out how to map the video to the narrow screen. To do that, we change the y position of the video window rectangle. We take the difference between the screen height and the video height and divide by two so we get an equal amount of unused space above and below. We adjust the height of the video image by dividing the screen width by the video aspect ratio to scale it down. This operation adjusts the video height so that it appears in the same aspect ratio.

win_position[1] = (height - video_height) / 2;
win_size[1] = width / video_aspect;

If the screen width is wider than the video's width, we need to center the video horizontally and set the video height to be the same as the screen height while maintaining the aspect ratio. We have to map the video to the wider screen. To do that, we change the x position of the video window rectangle. We need to take the difference between the screen width and the video width and divide by two so that we get an equal amount of unused space on the right and left. We adjust the width of the video image by multiplying the screen height by the video aspect ratio to scale it up. This operation stretches the video width so that it appears in the same aspect ratio.

                win_position[0] = (width - video_width) / 2;
                win_size[0] = height * video_aspect;
            

We set the updated position and size of the video window.

screen_set_window_property_iv(video_window, SCREEN_PROPERTY_POSITION, win_position);
screen_set_window_property_iv(video_window, SCREEN_PROPERTY_SIZE, win_size);
            

Play the video

Next, we attach the media file as the input for the mm-renderer context you created. Because we're playing only one file, we use the track input type which plays one track in isolation from the rest of the media.

if (mmr_input_attach(mmr_context, media_file, "track"));

Now, we can start playing the video.

mmr_play(mmr_context);

Stop the video

Now that the video is playing, you probably want to allow the user to stop it. Before your app can do that, it needs the ability to listen for screen events and handle any user input. When the user indicates that they've had enough of the video, the app can stop playback and close the window.

To allow the user to tell the app to stop playing the video, we need to set up an event handling loop and request events from the screen and the navigator:

screen_request_events(screen_context);
navigator_request_events(0);

for (;;) {
    bps_event_t *event = NULL;
    if (bps_get_event(&event, -1) != BPS_SUCCESS) {
    	return EXIT_FAILURE;
    }

    if (event) {
        if (bps_event_get_domain(event) == navigator_get_domain() &&
                bps_event_get_code(event) == NAVIGATOR_EXIT) {

                exit_application = 1;
            }
        if (exit_application) {
            break;
        }
    }
}

We pass -1 to bps_get_event() to block until an event is available. This action prevents the loop from running continuously and consuming processor cycles. When the app receives an event, we check for the event where the user swiped up from the bezel to close the app from the navigator (NAVIGATOR_EXIT). It would look something like the following image:

Device image showing the video playback window sample.

When we know that the user wants to close the app, we can stop the video and clean up all the app services that we've created.

screen_stop_events(screen_context);
mmr_stop(mmr_context);
mmr_output_detach(mmr_context, audio_device_output_id);
mmr_output_detach(mmr_context, video_device_output_id);
mmr_context_destroy(mmr_context);
mmr_context = 0;
video_device_output_id = -1;
audio_device_output_id = -1;
mmr_disconnect(mmr_connection);
mmr_connection = 0;
bps_shutdown();
screen_destroy_window(screen_window);
screen_destroy_context(screen_context);
screen_context = 0;
screen_window = 0;

That's it, you can now play a video! You can try altering the app to use different videos or perhaps add user interface elements to control playback.

Last modified: 2015-07-24



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

comments powered by Disqus