Set subtitles for a video using QMediaPlayer (PySide6)

410 Views Asked by At

I'm trying to make a program that plays a video and displays its subtitles in case these are available. The problem is that the subtitle functions don't work as I expected.

Small reproducible example:

import sys
from PySide6.QtCore import QUrl
from PySide6.QtWidgets import (QApplication,QMainWindow)
from PySide6.QtMultimedia import (QAudioOutput, QMediaPlayer)
from PySide6.QtMultimediaWidgets import QVideoWidget

if __name__ == '__main__':
    app = QApplication(sys.argv)

    audio_output = QAudioOutput()
    video_widget = QVideoWidget()
    player = QMediaPlayer()

    player.setAudioOutput(audio_output)
    player.setVideoOutput(video_widget)

    player.setSource(QUrl("video_subs.mkv"))
    player.play()

    # trying to view subtitles..
    print("1: ", player.activeSubtitleTrack())
    player.setActiveSubtitleTrack(0)
    print("2: ", player.subtitleTracks())

    main_win = QMainWindow()
    main_win.setCentralWidget(video_widget)
    available_geometry = main_win.screen().availableGeometry()
    main_win.show()
    sys.exit(app.exec())

output:

1: -1
2: []

As you can see from the output the functions appear to be malfunctioning. What am I doing wrong?

Other details:

  • System: Windows 10
  • Python version: 3.10.10
  • PySide version: 6.4.2

I tried setting the srt files as subtitles using ffmpeg-python in this way.

1

There are 1 best solutions below

10
ekhumoro On

The subtitle tracks won't become available until the media has finished loading. So you should use the mediaStatusChanged signal to query the available tracks once the appropriate state has been reached, and only then try to set the subtitle track.

Here's a basic demo based on your example:

import sys
from PySide6.QtCore import QUrl
from PySide6.QtWidgets import (QApplication,QMainWindow)
from PySide6.QtMultimedia import (QAudioOutput, QMediaPlayer)
from PySide6.QtMultimediaWidgets import QVideoWidget

if __name__ == '__main__':
    app = QApplication(sys.argv)

    audio_output = QAudioOutput()
    video_widget = QVideoWidget()
    player = QMediaPlayer()

    player.setAudioOutput(audio_output)
    player.setVideoOutput(video_widget)

    def status_changed(state):
        if state == QMediaPlayer.MediaStatus.LoadedMedia:
            if tracks := player.subtitleTracks():
                for index, track in enumerate(tracks):
                    print(f'Track ({index}):')
                    for key in track.keys():
                        print(f'  {track.metaDataKeyToString(key)} = '
                              f'{track.stringValue(key)}')
                player.setActiveSubtitleTrack(0)
            else:
                print('No subtitle tracks')

    player.mediaStatusChanged.connect(status_changed)

    player.setSource(QUrl("video_subs.mkv"))
    player.play()

    main_win = QMainWindow()
    main_win.setCentralWidget(video_widget)
    available_geometry = main_win.screen().availableGeometry()
    main_win.show()
    sys.exit(app.exec())

Output:

Track (0):
  Audio bit rate = 70
  Date = 2023-03-18T20:32:27.000Z
  Language = Default
  Title = English Subtitles
Track (1):
  Audio bit rate = 80
  Date = 2023-03-18T20:32:27.000Z
  Language = Default
  Title = German Subtitles

PS: I used mkvmerge to add the subtitle tracks to an mkv, and explicitly set the language for each one. However, although the mkvinfo tool shows the language correctly, Qt does not. The platform multimedia backend used by Qt on my system is gstreamer - and that also displays the correct language tags for the subtitle tracks. So it seems there may be a bug in Qt somewhere...