# Playing Media

The most basic case of multimedia integration in a QML application is for it to playback media. The `QtMultimedia` module supports this by providing a dedicated QML component: the `MediaPlayer`.

The `MediaPlayer` component is a non-visual item that connects a media source to one or several output channel(s). Depending on the nature of the media (i.e. audio, image or video) various output channel(s) can be configured.

## Playing audio

In the following example, the `MediaPlayer` plays a mp3 sample audio file from a remote URL in an empty window:

```qml
import QtQuick
import QtMultimedia

Window {
    width: 1024
    height: 768
    visible: true

    MediaPlayer {
        id: player
        source: "https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_2MG.mp3"
        audioOutput: AudioOutput {}
    }

    Component.onCompleted: {
        player.play()
    }
}
```

In this example, the `MediaPlayer` defines two attributes:

* `source`: it contains the URL of the media to play. It can either be embedded (`qrc://`), local (`file://`) or remote (`https://`).
* `audioOutput`: it contains an audio output channel, `AudioOutput`, connected to a physical output device. By default, it will use the default audio output device of the system.

As soon as the main component has been fully initialized, the player’s `play` function is called:

```qml
Component.onCompleted: {
    player.play()
}
```

## Playing a video

If you want to play visual media such as pictures or videos, you must also define a `VideoOutput` element to place the resulting image or video in the user interface.

In the following example, the `MediaPlayer` plays a mp4 sample video file from a remote URL and centers the video content in the window:

```qml
import QtQuick
import QtMultimedia

Window {
    width: 1920
    height: 1080
    visible: true

    MediaPlayer {
        id: player
        source: "https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_1920_18MG.mp4"
        audioOutput: AudioOutput {}
        videoOutput: videoOutput
    }

    VideoOutput {
        id: videoOutput
        anchors.fill: parent
        anchors.margins: 20
    }

    Component.onCompleted: {
        player.play()
    }
}
```

In this example, the `MediaPlayer` defines a third attribute:

* `videoOutput`: it contains the video output channel, `VideoOutput`, representing the visual space reserved to display the video in the user interface.

{% hint style="warning" %}
Please note that the `VideoOutput` component is a visual item. As such, it's essential that it is created within the visual components hierarchy and not within the `MediaPlayer` itself.
{% endhint %}

## Controlling the playback

The `MediaPlayer` component offers several useful properties. For instance, the `duration` and `position` properties can be used to build a progress bar. If the `seekable` property is `true`, it is even possible to update the `position` when the progress bar is tapped.

It's also possible to leverage `AudioOutput` and `VideoOutput` properties to customize the experience and provide, for instance, volume control.

The following example adds custom controls for the playback:

* a volume slider
* a play/pause button
* a progress slider

```qml
import QtQuick
import QtQuick.Controls
import QtMultimedia

Window {
    id: root
    width: 960
    height: 400
    visible: true

    MediaPlayer {
        id: player
        source: "file:///path-to-your-video-file.mp4"
        audioOutput: audioOutput
        videoOutput: videoOutput
    }

    AudioOutput {
        id: audioOutput
        volume: volumeSlider.value
    }

    VideoOutput {
        id: videoOutput
        width: videoOutput.sourceRect.width
        height: videoOutput.sourceRect.height
        anchors.horizontalCenter: parent.horizontalCenter
    }

    Slider {
        id: volumeSlider
        anchors.top: parent.top
        anchors.right: parent.right
        anchors.margins: 20
        orientation: Qt.Vertical
        value: 0.5
    }

    Item {
        height: 50
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        anchors.margins: 20

        Button {
            anchors.horizontalCenter: parent.horizontalCenter
            text: player.playbackState ===  MediaPlayer.PlayingState ? qsTr("Pause") : qsTr("Play")
            onClicked: {
                switch(player.playbackState) {
                    case MediaPlayer.PlayingState: player.pause(); break;
                    case MediaPlayer.PausedState: player.play(); break;
                    case MediaPlayer.StoppedState: player.play(); break;
                }
            }
        }

        Slider {
            id: progressSlider
            width: parent.width
            anchors.bottom: parent.bottom
            enabled: player.seekable
            value: player.duration > 0 ? player.position / player.duration : 0
            background: Rectangle {
                implicitHeight: 8
                color: "white"
                radius: 3
                Rectangle {
                    width: progressSlider.visualPosition * parent.width
                    height: parent.height
                    color: "#1D8BF8"
                    radius: 3
                }
            }
            handle: Item {}
            onMoved: function () {
                player.position = player.duration * progressSlider.position
            }
        }
    }

    Component.onCompleted: {
        player.play()
    }
}
```

### The volume slider

A vertical `Slider` component is added on the top right corner of the window, allowing the user to control the volume of the media:

```qml
Slider {
    id: volumeSlider
    anchors.top: parent.top
    anchors.right: parent.right
    anchors.margins: 20
    orientation: Qt.Vertical
    value: 0.5
}
```

The volume attribute of the `AudioOutput` is then mapped to the value of the slider:

```qml
AudioOutput {
    id: audioOutput
    volume: volumeSlider.value
}
```

### Play / Pause

A `Button` component reflects the playback state of the media and allows the user to control this state:

```qml
Button {
    anchors.horizontalCenter: parent.horizontalCenter
    text: player.playbackState ===  MediaPlayer.PlayingState ? qsTr("Pause") : qsTr("Play")
    onClicked: {
        switch(player.playbackState) {
            case MediaPlayer.PlayingState: player.pause(); break;
            case MediaPlayer.PausedState: player.play(); break;
            case MediaPlayer.StoppedState: player.play(); break;
        }
    }
}
```

Depending on the playback state, a different text will be displayed in the button. When clicked, the corresponding action will be triggered and will either play or pause the media.

{% hint style="info" %}
The possible playback states are listed below:

* `MediaPlayer.PlayingState`: The media is currently playing.
* `MediaPlayer.PausedState`: Playback of the media has been suspended.
* `MediaPlayer.StoppedState`: Playback of the media is yet to begin.
  {% endhint %}

### Interactive progress slider

A `Slider` component is added to reflect the current progress of the playback. It also allows the user to control the current position of the playback.

```qml
Slider {
    id: progressSlider
    width: parent.width
    anchors.bottom: parent.bottom
    enabled: player.seekable
    value: player.duration > 0 ? player.position / player.duration : 0
    background: Rectangle {
        implicitHeight: 8
        color: "white"
        radius: 3
        Rectangle {
            width: progressSlider.visualPosition * parent.width
            height: parent.height
            color: "#1D8BF8"
            radius: 3
        }
    }
    handle: Item {}
    onMoved: function () {
        player.position = player.duration * progressSlider.position
    }
}
```

This slider will only be enabled when the media is `seekable`:

```qml
Slider {
    /* ... */
    enabled: player.seekable
    /* ... */
}
```

Its value will be set to the current media progress, i.e. `player.position / player.duration`:

```qml
Slider {
    /* ... */
    value: player.duration > 0 ? player.position / player.duration : 0
    /* ... */
}
```

When the slider is moved by the user, the media position will be updated:

```qml
Slider {
    /* ... */
    onMoved: function () {
        player.position = player.duration * progressSlider.position
    }
    /* ... */
}
```

## The media status

When using `MediaPlayer` to build a media player, it is good to monitor the `status` property of the player. Here is an enumeration of the possible statuses, ranging from `MediaPlayer.Buffered` to `MediaPlayer.InvalidMedia`. The possible values are summarized in the bullets below:

* `MediaPlayer.NoMedia`. No media has been set. Playback is stopped.
* `MediaPlayer.Loading`. The media is currently being loaded.
* `MediaPlayer.Loaded`. The media has been loaded. Playback is stopped.
* `MediaPlayer.Buffering`. The media is buffering data.
* `MediaPlayer.Stalled`. The playback has been interrupted while the media is buffering data.
* `MediaPlayer.Buffered`. The media has been buffered, this means that the player can start playing the media.
* `MediaPlayer.EndOfMedia`. The end of the media has been reached. Playback is stopped.
* `MediaPlayer.InvalidMedia`. The media cannot be played. Playback is stopped.
* `MediaPlayer.UnknownStatus`. The status of the media is unknown.

As mentioned in the bullets above, the playback state can vary over time. Calling `play`, `pause` or `stop` alters the state, but the media in question can also have an effect. For example, the end can be reached, or it can be invalid, causing playback to stop.

{% hint style="info" %}
It is also possible to let the `MediaPlayer` to loop a media item. The `loops` property controls how many times the `source` is to be played. Setting the property to `MediaPlayer.Infinite` causes endless looping. Great for continuous animations or a looping background song.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.novaflowos.com/start/qt6-qml-book/readme/ch11-multimedia/playing-media.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
