Playing video

You can use the MediaPlayer to play video files and streams. The MediaPlayer allows your app to play video files, and also provides seek, rewind, and fast forward functionality. You can create one MediaPlayer for every video you want to play, but it's not necessary unless you intend to play more than one video at the same time.

When using BlackBerry 10 OS version 10.1 to perform the concurrent playback of multiple media items, such as local video files or remote streams, you’re only guaranteed to have a maximum of 8 items playing at the same time.

Permissions

You must add the access_shared permission to allow your app to access and play media files that are stored in the shared areas of the device.

For more information about adding permissions to your bar-descriptor.xml file, see The bar-descriptor.xml file.

For more information about the shared data areas of the device, see Working with the file system.

Flow and states

The architectural flow diagram below illustrates the various states of the MediaPlayer class. The MediaPlayer must proceed through various states before going to the Started state where it can play media content.

Unprepared state

The MediaPlayer begins in an Unprepared state, which means that it cannot play content because it doesn't have the necessary resources to do so.

Prepared and Started state

When the MediaPlayer acquires the resources it needs to play the media content, it's in a Prepared state. The Prepared state usually moves quickly into the Started state where it can play media content.

It's not unusual to have an app go from the Unprepared state directly to the Started state and begin playing content. In this case, it may appear that the Prepared state was skipped, but it's not skipped, it's just occurring very briefly.

Flow diagram showing the media player states

Playing a video file

You can use the MediaPlayer to play video by following these steps:

  • Create a MediaPlayer object.
  • Import the multimedia library by using the import bb.multimedia 1.2 import statement.
  • Set the path as the source URL to the video that you want to play. The source path to the video you want to play can point to a local or remote video file.
  • Create a ForeignWindowControl object and set its windowId property.
  • Provide the windowId of the ForeignWindowControl to the MediaPlayer. The MediaPlayer uses this ForeignWindowControl object to display the video.
  • If you're using closed captioning content, create a second ForeignWindowControl object and set its windowId property.
  • Before you trigger your video to play, your closed captioning content in the form of an URL must be set using the setClosedCaptionUrl() function.

    Adding closed captions to your media content files requires the use of third party software. The media content owner is responsible for creating and embedding the closed captioning data into their media content if they wish to add closed captions to their content.

  • Set the videoOutput property of the player, which determines the video out device display. The video output device can be VideoOutput::None, VideoOutput::PrimaryDisplay, or VideoOutput::SecondaryDisplay.
  • Call the player's play() function to play the video file.
  • Call the player's stop() function to stop the video file.

Here's a QML code sample that shows you how to play and stop a video. The sample also shows you how to set up closed captioning that uses an XML file for the closed captioned content.

import bb.cascades 1.2
import bb.multimedia 1.2

Page {
    Container {
        layout: AbsoluteLayout {
        }
        
        attachedObjects:[
            MediaPlayer {
                id: vidPlayer
                sourceUrl: "/path/to/video.mp4"

                videoOutput: VideoOutput.PrimaryDisplay

                // The name of the window to create
                windowId: fwcVideoSurface.windowId

                // Closed Captioning code
                closedCaptionWindowId: fwcCaptionSurface.windowId
            }
        ]
        
        ForeignWindowControl {
            id: fwcVideoSurface
            windowId: "myVideoSurface"

            updatedProperties: WindowProperty.Size | 
                               WindowProperty.Position | 
                               WindowProperty.Visible

            preferredWidth: 1280
            preferredHeight: 768
        }
        
        ForeignWindowControl {
            id: fwcCaptionSurface
            windowId: "myCaptionSurface"
            
            updatedProperties: WindowProperty.Size |
            WindowProperty.Position |
            WindowProperty.Visible
            
            preferredWidth: 1280
            preferredHeight: 768
        }
        
        
        Button {
            text: "Play Video"
            onClicked: {
                // Used for external captioning
                // This URL must be set before prepare/play
                vidPlayer.setClosedCaptionUrl(1, "/path/to/cc.xml");                
                
                if (vidPlayer.play() != MediaError.None) {
                    // Put your error handling code here
                }
            }
        }
        
        Button {
            text: "Stop Video"
            onClicked: {
                if (vidPlayer.stop() != MediaError.None) {
                    // Put your error handing code here
                }
            }
        }
    }
}

Using a video rendering surface

The MediaPlayer creates a rendering surface, outside of Cascades, to play video files. However, the MediaPlayer itself cannot be used as a rendering surface to play videos. Instead, the MediaPlayer uses a ForeignWindowControl as its rendering surface. The ForeignWindowControl is used to embed a window from the Screen Graphics Subsystem (Screen window) into the Cascades scene graph. You must set the windowId and/or windowHandle properties, as well as the windowGroup property to bind the ForeignWindowControl to a Screen window.

The windowId of the ForeignWindowControl is set in the MediaPlayer, which allows the ForeignWindowControl to provide a rendering surface for the MediaPlayer to use. It also allows the ForeignWindowControl to connect to, scale, and manage the rendering surface that is used by the MediaPlayer to play video files.

The ForeignWindowControl has direct access to the graphics hardware of the device. In other words, this allows your app to use the rendering surface of the ForeignWindowControl as a low-level platform window. As a rendering surface, this platform window is very efficient at displaying video. The platform window, or Screen, can also access all of the functionality provided in the libscreen library.

The MediaPlayer has a series of signals that you can connect signal handlers to in order to manage your video player's behavior. These signals give you the opportunity to handle signals like onMediaStateChanged, which indicates that the state of the media player has changed. A state change can happen when the media player is playing a video and it's paused or stopped by the user. It can also happen if the media player loses the resources that it requires to continue playing the video.

The MediaPlayer emits many other signals that you can use to control its behavior, and here's a QML code sample that shows you how to work with the onMediaStateChanged signal handler. In this case, the code sample uses our custom onMediaStatedChanged signal handler and a switch statement with a case for each MediaState type. The code sample uses only the Unprepared signal. In this case, it just hides the ForeignWindowControl to make is disappear.

MediaPlayer {
    // ...
    
    onMediaStateChanged: {
        switch (vidPlayer.mediaState) {
            case 0:
                // Unprepared = 0.
                fwcVideoSurface.visible = false;
                break;

            case 1:
                // Prepared = 1.
                break;

            case 2:
                // Started = 2.
                break;

            case 3:
                // Paused = 3.
                break;

            case 4:
                // Stopped = 4.
                break;
        }
    }
    
    // ...
}

Here's a C++ code sample that shows you how to use the ForeignWindowControl. When you use C++ code to set up a ForeignWindowControl, you must set a value for the windowGroup property to make it all work. You can use the setWindowGroup() function to set the windowGroup.

Setting the windowGroup property alone, without setting the windowId or windowHandle property, is not sufficient for binding the ForeignWindowControl to a Screen window. Both the windowGroup and windowId or windowHandle properties must be set in order to bind a Screen window to the ForeignWindowControl.

Here's the C++ header file which shows you how to set everything up.

#ifndef ApplicationUI_HPP_
#define ApplicationUI_HPP_

#include <QObject>
#include <bb/cascades/ForeignWindowControl>
#include <bb/cascades/Container>
#include <bb/multimedia/MediaPlayer>
#include <bb/system/SystemToast>

namespace bb {namespace cascades {class Application;}}

class ApplicationUI: public QObject {
	Q_OBJECT
public:
	ApplicationUI(bb::cascades::Application *app);
	virtual ~ApplicationUI() {}

private slots:
	void onForeignWindowBoundingChanged(bool isBound);
	void showToast(QString message);

private:
	bb::cascades::Container *m_container;
	bb::cascades::ForeignWindowControl *m_foreignWindowControl;
	bb::multimedia::MediaPlayer *m_mediaPlayer;
};

#endif /* ApplicationUI_HPP_ */

Here's the C++ source file which shows you how to set the windowId and windowGroup properties to bind the ForeignWindowControl to a Screen window.

#include "applicationui.hpp"

#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
#include <bb/multimedia/VideoOutput>
#include <bb/multimedia/MediaError>
#include <bb/cascades/Window>

using namespace bb::cascades;

ApplicationUI::ApplicationUI(bb::cascades::Application *app) :
    QObject(app) 
{
    // Create scene document from main.qml asset, the parent is set
    // to ensure the document gets destroyed properly at shut down
    QmlDocument *qml = QmlDocument::create("asset:///main.qml")
        .parent(this);

    // Create root object for the UI
    AbstractPane *root = qml->createRootObject<AbstractPane>();

    m_container = root->findChild<Container*>("mainContainer");

    // Set created root object as the application scene
    app->setScene(root);

    // Find the Container where the ForeignWindowControl will be
    // created
    if (m_container) {
      // Create the ForeignWindowControl
      m_foreignWindowControl = ForeignWindowControl::create()
          .windowId("MyWindow")
          .updatedProperties(WindowProperty::Size
              | WindowProperty::Position
              | WindowProperty::Visible);

      // Add the ForeignWindowControl to the main container
      m_container->add(m_foreignWindowControl);

      m_foreignWindowControl->
          setVisible(m_foreignWindowControl->isBoundToWindow());

      // If any Q_ASSERT statement(s) indicate that the slot
      // failed to connect to the signal, make sure you know
      // exactly why this happened. This is not normal, and 
      // will cause your app to stop working
      bool connResult;

      // Since the variable is not used in the app, this is
      // added to avoid a compiler warning
      Q_UNUSED(connResult);

      connResult = connect(m_foreignWindowControl,
          SIGNAL(boundToWindowChanged(bool)),
          this, SLOT(onForeignWindowBoundingChanged(bool)));

      Q_ASSERT(connResult);

      m_mediaPlayer = new bb::multimedia::MediaPlayer(this);
      m_mediaPlayer->setWindowId(m_foreignWindowControl->windowId());

      // Set the windowGroup property
      m_mediaPlayer->
        setWindowGroupId(m_foreignWindowControl->windowGroup());
      m_mediaPlayer->
       setVideoOutput(bb::multimedia::VideoOutput::PrimaryDisplay);
      m_mediaPlayer->setSourceUrl(QUrl("asset:///myVideo.wmv"));

      // Play the video
      m_mediaPlayer->play();
    }
    else {
        // Could not find Container
        showToast("An error has occurred");
    }
}

// Displays a message in a toast
void ApplicationUI::showToast(QString message) 
{
  bb::system::SystemToast *toast = new bb::system::SystemToast(this);

  toast->setBody(message);
  toast->setPosition(bb::system::SystemUiPosition::MiddleCenter);
  toast->show();
}

void ApplicationUI::onForeignWindowBoundingChanged(bool isBound) 
{
    m_foreignWindowControl->setVisible(isBound);

    if (!isBound) {
        showToast("ForeignWindowControl is not bound");
    }
}

Last modified: 2014-02-25

comments powered by Disqus