1

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.

Lurù
  • 31
  • 5
  • Are you sure that the subtitles are included in the file? What format do they use? Note that by default QMediaPlayer uses the system multimedia backend (gst on Linux, DirectShow on Windows, CoreAudio/Video on macOS, IIRC), so Qt has little control over that aspect: if the system doesn't natively support it (through installed plugins), the subtitles are not available. Note that `setActiveSubtitleTrack()` doesn't return nothing anyway (`void` in the C++ documentation equals to returning `None`). – musicamante Mar 17 '23 at 20:19
  • @musicamente I tried this code on Windows 10 and verified that the video actually has two subtitles with "Films & tv" player and VLC. I removed output of `setActiveSubtitleTrack()` from question. PS: subtitles are srt file which i included in the video. – Lurù Mar 17 '23 at 20:45
  • I don't know about that "Film&tv" program, but VLV always uses its bundled libraries for everything, so it's not usable as a reference test for this: you probably need to check your system configuration (maybe the accessibility settings in Windows Media Player, but that's just a hunch). – musicamante Mar 17 '23 at 22:03

1 Answers1

2

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

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • I tried this solution (which I think is correct) but with my video it doesn't work (it shows 'No subtitle tracks'). I put subtitles (srt files) in the video using ffmpeg and I can set them correctly with VLC. Maybe qmediaplayer is not the best tool to do this.. – Lurù Mar 20 '23 at 12:04
  • @Lurù Can you share your video so I can test it myself? Also, please state which platform you are on and the exact versions of PySide6/Qt6 you are using. – ekhumoro Mar 20 '23 at 12:07
  • @Lurù PS: if you can't share the video, please edit your question and show the *exact* commands you used to add the srt files to the video. – ekhumoro Mar 20 '23 at 12:12
  • @Lurù I downloaded a sample mkv video from [here](https://filesamples.com/formats/mkv) and added an srt file to it using the command `ffmpeg -i sample_1280x720.mkv -vf subtitles=test-en.srt test.mkv`. This did not work for me either, so I think you should try using `mkvmerge` to add the subtitles, which definitely does work with Qt6. (PS: I managed to get ffmpeg to work by converting the srt to a different format first, like this: `ffmpeg -i test-en.srt test-en.ass`. However, I still think mkvmerge is more reliable). – ekhumoro Mar 20 '23 at 12:47
  • I tried to add subtitles to the sample video `sample_640x360.mkv` (downloaded from your source) with `mkvmerge` but it still doesn't work. Specifically, I used this command: `mkvmerge -o output.mkv sample_640x360.mkv --language 0:en --track-name 0:en 1.srt` – Lurù Mar 20 '23 at 14:15
  • I've updated the question with more details. – Lurù Mar 20 '23 at 14:29
  • @Lurù It looks like there must be some bugs in Qt6. I can't test on Windows, so I can't really offer any other suggestions regarding that. But I'm certain my answer is essentially correct, so it *should* work. One other thing I noticed when using ffmpeg, is that on my system the subtitles *are* displayed, even though `subtitleTracks()` still returns empty! So there's certainly something flaky with Qt's implementation that affects *all* platforms. – ekhumoro Mar 20 '23 at 16:47
  • @Lurù PS: did you try any other video formats? It would be interesting to know if this only affects mkv files. – ekhumoro Mar 20 '23 at 16:50
  • I also tried with an mp4 file, but the output is the same. – Lurù Mar 22 '23 at 15:11
  • @Lurù Okay. The only other thing I can suggest to to try some other tools that can set subtitles on videos. You probably need to use something that is more Windows-specific so that it works with the backend Qt uses on your system. – ekhumoro Mar 22 '23 at 15:16