Skip to content

Conversation

wischnow
Copy link
Contributor

@wischnow wischnow commented Dec 15, 2024

Hello,

this add support for Vobsub subtitles.

An example file can be found here: https://www.w9y.de/sample.mkv
This is based on this file: https://samples.ffmpeg.org/sub/largeres_vobsub.mkv

The only difference is that I used "mkvmerge -o sample.mkv largeres_vobsub.mkv" to copy the tracks into a new MKV file because the original uses ContentCompAlgo == 0, which is not supported by Exoplayer.

@icbaker
Copy link
Collaborator

icbaker commented Dec 18, 2024

Thanks for the contribution! In order to merge this we need a (very) small test video containing at least one vobsub subtitle that we can use to write a playback test to verify everything works (and continues to work as we change things in future).

This asset needs to be suitably licensed for submission to this repo. The sample.mkv file you've linked to is too large (40MB), and doesn't look suitably licensed. The easiest way to generate these test assets is usually to craft them yourself, maybe by modifying one of our existing MKV assets.

I had a quick look around and didn't find an easy way to synthesise vobsub subtitles. Please can you take a look into this. Once you have the small asset with a vobsub track added to this PR, you can probably just add the file to the list of assets in MkvPlaybackTest and run the test with DumpFIleAsserts.DUMP_FILE_ACTION hard-coded locally to WRITE_TO_LOCAL (this should produce the golden file dump output).

@wischnow
Copy link
Contributor Author

Hello and thanks for your reply!

While searching for a better sample file or how to build one I just saw that ffmpeg can convert other image-based subtitle formats to Vobsub/DVDsub. And since Exoplayer does support PGS and DVBsub subtitles, which are image-based, I thought I'd just use one of your sample files for those and convert them to Vobsub.

But I can't find a sample file with PGS or DVBsub subtitles in the repository or in the old ExoPlayer repository.

Is that correct, or am I missing something? If I could get one of the files you used for those subtitle formats, I can easily create one with Vobsub subtitles.

P.S.: It appears that the Vobsub format ffmpeg outputs is a bit weird in that it doesn't contain the "size:..." line in the embedded IDX file. Never seen that before. My code needs that to be able to calculate the relative positions required by Cue.Builder(). At least I didn't see a way how a subtitle parser could get access to the viewport size. But the output of ffmpeg can easily be fixed by adding the "size:..." line by hand (mkvextract, an editor, and mkvmerge).

@icbaker
Copy link
Collaborator

icbaker commented Jan 2, 2025

Is that correct, or am I missing something?

That's correct, we don't have test assets for these subtitle formats either, and this introduces a maintenance burden when we want to make changes (because we have less confidence that this logic will still work) - which is why I'm afraid we now require test assets for new subtitle formats.


Some quick searching suggests that tsMuxer might be able to convert from SRT to an image-based format, which maybe ffmpeg could then convert to vobsub? I haven't tried this (or ever used this tool).

Or if there's a way to just mux arbitrary images in as subtitles, you could use some of our existing test images (there are other formats too).

@wischnow
Copy link
Contributor Author

wischnow commented Jan 2, 2025

Hello again (and a happy new year),

thanks for pointing me at tsmuxer. This worked. I took the existing sample_with_srt.mkv and converted the subtitle to Vobsub format (via tsmuxer and ffmpeg). This I then added to my fork and also added the file to MkvPlaybackTest.java, as suggested.

public void parseIdx(String idx) {
for (String line : idx.trim().split("\\r?\\n")) {
if (line.startsWith("palette: ")) {
String[] values = line.substring(9).split(",");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Util.split to avoid the weird behaviour of the single-arg variant of String.split

related: https://github.com/google/guava/wiki/StringsExplained#splitter

Same elsewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Collaborator

@icbaker icbaker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made a few changes as part of preparing this for internal review, but also found a couple of questions I want your input on (see individual comments). I'm happy to make any resulting code changes, so feel free to just reply in the comments.

/**
* Parse run-length encoded data into the {@code bitmapData} array. The
* subtitle bitmap is encoded in two blocks of interlaced lines, {@code y}
* gives the index of the starting line (0 or 1).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if y is always zero or one, what about making it a boolean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should have written the comment better: the function is called with y being 0 or 1, basically telling it whether it will decode the even or odd lines. Inside the function it will then increase y in the loop.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotcha - I've made the parameter a boolean and made the y arithmetic an implementation detail inside the method.

@icbaker
Copy link
Collaborator

icbaker commented Jan 6, 2025

thanks for pointing me at tsmuxer. This worked. I took the existing sample_with_srt.mkv and converted the subtitle to Vobsub format (via tsmuxer and ffmpeg). This I then added to my fork and also added the file to MkvPlaybackTest.java, as suggested.

Thanks for adding this test file - that's great you got tsmuxer working. Unfortunately when I ran the MkvPlaybackTest to try and generate an output dump file to add to this PR, it timed out:

java.util.concurrent.TimeoutException
	at androidx.media3.test.utils.robolectric.RobolectricUtil.runLooperUntil(RobolectricUtil.java:149)
	at androidx.media3.test.utils.robolectric.RobolectricUtil.runMainLooperUntil(RobolectricUtil.java:98)
	at androidx.media3.test.utils.robolectric.RobolectricUtil.runMainLooperUntil(RobolectricUtil.java:76)
	at androidx.media3.test.utils.robolectric.TestPlayerRunHelper$PlayerRunResult.runUntil(TestPlayerRunHelper.java:307)
	at androidx.media3.test.utils.robolectric.TestPlayerRunHelper$PlayerRunResult.untilState(TestPlayerRunHelper.java:122)
	at androidx.media3.test.utils.robolectric.TestPlayerRunHelper.runUntilPlaybackState(TestPlayerRunHelper.java:608)
	at androidx.media3.exoplayer.e2etest.MkvPlaybackTest.test(MkvPlaybackTest.java:82)

Did you get the test running successfully with this file?

@wischnow
Copy link
Contributor Author

wischnow commented Jan 6, 2025

I had uploaded the sample file to https://www.w9y.de/sample.mkv, added that to the media.exolist.json file of the demo app and tested it with that. I just tried it again and it still works, no error messages in the log, including no timeout (debug compile, btw.).

Hm, weird. How does one run those tests?

@wischnow
Copy link
Contributor Author

wischnow commented Jan 6, 2025

Correction: If I pull the latest version with your changes, the demo player doesn't display the subtitle...

Debugging...

It's this line: buffer.skipBytes(buffer.readUnsignedShort());

It should be: buffer.skipBytes(buffer.readUnsignedShort() - 2);

Because we have to subtract the two bytes we just read ;-)

Fixed in the repository now.

@wischnow
Copy link
Contributor Author

wischnow commented Jan 6, 2025

And before I forget this again: from that conversion with tsmuxer I still have to sample file with PGS subtitles. Since this PR is about Vobsub/DVDsub I'm reluctant to add it here. You can get it here, if you're interested to finally have sample file with PGS: https://www.w9y.de/sample-with-pgs.mkv. Exoplayer can play this file.

And while I was at it, I also used ffmpeg to convert the subtitles to DVBsub: https://www.w9y.de/sample-with-dvbsub.mkv. The interesting bit about this one is that Exoplayer (demo app) can't play the file, but ffplay and vlc on my Laptop here can. I don't know anything about DVBsub, though...

@icbaker
Copy link
Collaborator

icbaker commented Jan 10, 2025

You can get it here, if you're interested to finally have sample file with PGS: https://www.w9y.de/sample-with-pgs.mkv. Exoplayer can play this file.

Amazing, thanks! I've added this to MkvPlaybackTest and sent it for review internally.


Because we have to subtract the two bytes we just read ;-)

Oops, thanks for spotting and fixing that. I wasn't clear in my original comment but the test timed out both with and without my additional changes (and still times out with the latest fix too). It times out waiting for the player state to get to IDLE.

I tried playing the file in the demo app (thanks for the suggestion), it also doesn't ever stop - the UI says the file is 1193h02m47s long. In VLC (on Linux) I also see the same duration briefly, but playback does complete quickly (and so the UI gets hidden again).

mediainfo thinks it's specifically the VobSub track that is 1193h long [1].

And mkvinfo agrees:

|  + Simple
|   + Name: DURATION
|   + String: 1193:02:47.29500000

mkvinfo -s shows the single mega-long sample:

I frame, track 3, timestamp 00:00:00.000000000, duration 1193:02:47.295000000, size 10013, adler 0xa4986a81

Is it possible there was some time unit conversion problem when you were extracting and re-muxing?


[1]

$ mediainfo sample.mkv
General
Unique ID                                : 332219147464344373212352680433495465372 (0xF9EF14966859026D72420C95EBAA5D9C)
Complete name                            : sample.mkv
Format                                   : Matroska
Format version                           : Version 4
File size                                : 111 KiB
Duration                                 : 1193 h
Overall bit rate                         : 0 b/s
Frame rate                               : 612.245 FPS
Writing application                      : Lavf61.7.100
Writing library                          : Lavf61.7.100
ErrorDetectionType                       : Per level 1

Video
ID                                       : 1
Format                                   : AVC
Format/Info                              : Advanced Video Codec
Format profile                           : High@L5.2
Format settings                          : CABAC / 4 Ref Frames
Format settings, CABAC                   : Yes
Format settings, Reference frames        : 4 frames
Codec ID                                 : V_MPEG4/ISO/AVC
Duration                                 : 49 ms
Bit rate                                 : 14.3 Mb/s
Width                                    : 1 080 pixels
Height                                   : 720 pixels
Display aspect ratio                     : 3:2
Frame rate mode                          : Variable
Frame rate                               : 612.245 FPS
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Bits/(Pixel*Frame)                       : 0.030
Stream size                              : 87.4 KiB (79%)
Writing library                          : x264 core 148 r2601 a0cd7d3
Encoding settings                        : cabac=1 / ref=3 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=7 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=12 / lookahead_threads=2 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=25 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=crf / mbtree=1 / crf=23.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00
Default                                  : Yes
Forced                                   : No

Audio
ID                                       : 2
Format                                   : AC-3
Format/Info                              : Audio Coding 3
Commercial name                          : Dolby Digital
Codec ID                                 : A_AC3
Duration                                 : 1 s 9 ms
Bit rate mode                            : Constant
Bit rate                                 : 96.0 kb/s
Channel(s)                               : 1 channel
Channel layout                           : M
Sampling rate                            : 44.1 kHz
Frame rate                               : 28.711 FPS (1536 SPF)
Bit depth                                : 32 bits
Compression mode                         : Lossy
Stream size                              : 11.8 KiB (11%)
Service kind                             : Complete Main
Default                                  : Yes
Forced                                   : No
Dialog Normalization                     : -31 dB
dialnorm_Average                         : -31 dB
dialnorm_Minimum                         : -31 dB
dialnorm_Maximum                         : -31 dB

Text
ID                                       : 3
Format                                   : VobSub
Codec ID                                 : S_VOBSUB
Codec ID/Info                            : Picture based subtitle format used on DVDs
Duration                                 : 1193 h
Bit rate                                 : 162 kb/s
Frame rate                               : 0.000 (0/1000) FPS
Count of elements                        : 2
Stream size                              : 24.6 KiB (22%)
Writing library                          : Lavc61.19.100 dvdsub
Language                                 : English
Default                                  : Yes
Forced                                   : No

@wischnow
Copy link
Contributor Author

Oops. Indeed, ffmpeg messed up the track duration when converting PGS to Vobsub. I've just pushed the fixed version into the repository.

This also made me look at the DVBsub example again (see the URL above, the one Exoplayer couldn't play). That was messed up even more and the URL now points to the fixed version. Exoplayer still can't play it, though.

@icbaker
Copy link
Collaborator

icbaker commented Jan 10, 2025

That's great, thanks for fixing the file - I've used this in the test and it now completes successfully.

@icbaker icbaker linked an issue Jan 10, 2025 that may be closed by this pull request
@copybara-service copybara-service bot merged commit d18ad57 into androidx:main Jan 13, 2025
1 check passed
copybara-service bot pushed a commit that referenced this pull request Jan 13, 2025
Transformed from `sample_with_srt.mkv` and provided in
#1979 (comment)

PiperOrigin-RevId: 714955725
@androidx androidx locked and limited conversation to collaborators Mar 15, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support VobSub subtitles
2 participants