What happened?
While playing a video with an embedded SRT subtitle track, I seek forward by 10 seconds and then immediately seek backward by 10 seconds using AetherEngine.seek(to:).
I expected AetherEngine to continue publishing each subtitle cue once.
Instead, each seek replays and appends previously decoded cues to subtitleCues. After the forward seek, the cue count increased from 4 to 7. After seeking backward, it increased from 7 to 11. The duplicated cues have identical text and timestamps, and some also reuse existing cue IDs.
Because the host renders subtitleCues using ForEach(cues, id: \.id), the duplicated entries cause subtitles to appear multiple times.
Steps to reproduce
- Load a video containing an embedded SRT subtitle track.
- Select the subtitle track using selectSubtitleTrack(index:).
- Start playback and wait until subtitles are displayed.
- Seek forward by 10 seconds using seek(to:).
- Immediately seek backward by 10 seconds using seek(to:).
- Inspect the engine’s published subtitleCues array.
The issue reproduces with this sequence:
await engine.seek(to: currentTime + 10)
await engine.seek(to: currentTime)
The cue count increases after each seek, and previously decoded cues are inserted again with identical timestamps and text. In the captured reproduction, the count progressed from 4 to 7, then from 7 to 11.
AetherEngine version or commit SHA
5.0.1
Host app
Custom / my own integration
Platform
iOS
OS version
iOS 26.5
Device / chip
iPhone 17 Pro
Playback path
Native AVPlayer
Source media (for playback bugs)
Metadata:
title : Dune Part Two (2024)
encoder : libebml v1.4.5 + libmatroska v1.7.1
creation_time : 2024-07-19T17:24:15.000000Z
Duration: 02:45:49.02, start: 0.000000, bitrate: 6874 kb/s
Chapters:
Chapter #0:0: start 0.000000, end 554.220000
Metadata:
title : Chapitre 01
Chapter #0:1: start 554.220000, end 1288.913000
Metadata:
title : Chapitre 02
Chapter #0:2: start 1288.913000, end 1770.018000
Metadata:
title : Chapitre 03
Chapter #0:3: start 1770.018000, end 2407.905000
Metadata:
title : Chapitre 04
Chapter #0:4: start 2407.905000, end 3039.912000
Metadata:
title : Chapitre 05
Chapter #0:5: start 3039.912000, end 3633.129000
Metadata:
title : Chapitre 06
Chapter #0:6: start 3633.129000, end 4193.523000
Metadata:
title : Chapitre 07
Chapter #0:7: start 4193.523000, end 4779.483000
Metadata:
title : Chapitre 08
Chapter #0:8: start 4779.483000, end 5438.933000
Metadata:
title : Chapitre 09
Chapter #0:9: start 5438.933000, end 5945.064000
Metadata:
title : Chapitre 10
Chapter #0:10: start 5945.064000, end 6574.860000
Metadata:
title : Chapitre 11
Chapter #0:11: start 6574.860000, end 7179.422000
Metadata:
title : Chapitre 12
Chapter #0:12: start 7179.422000, end 7823.607000
Metadata:
title : Chapitre 13
Chapter #0:13: start 7823.607000, end 8329.279000
Metadata:
title : Chapitre 14
Chapter #0:14: start 8329.279000, end 8658.233000
Metadata:
title : Chapitre 15
Chapter #0:15: start 8658.233000, end 9464.789000
Metadata:
title : Chapitre 16
Chapter #0:16: start 9464.789000, end 9949.023000
Metadata:
title : Chapitre 17
Stream #0:0: Video: hevc (Main 10), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 3840x1608, SAR 1:1 DAR 160:67, 23.98 fps, 23.98 tbr, 1k tbn (default)
Metadata:
BPS : 5322182
DURATION : 02:45:49.023000000
NUMBER_OF_FRAMES: 238538
NUMBER_OF_BYTES : 6618815047
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Side data:
DOVI configuration record: version: 1.0, profile: 8, level: 6, rpu flag: 1, el flag: 0, bl flag: 1, compatibility id: 1
Stream #0:1(fre): Audio: eac3, 48000 Hz, 5.1(side), fltp, 768 kb/s (default)
Metadata:
title : FR VFF : DDP 5.1 Atmos
BPS : 768000
DURATION : 02:45:47.008000000
NUMBER_OF_FRAMES: 310844
NUMBER_OF_BYTES : 954912768
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:2(eng): Audio: eac3, 48000 Hz, 5.1(side), fltp, 768 kb/s
Metadata:
title : ENG VO : DDP 5.1 Atmos
BPS : 768000
DURATION : 02:45:47.008000000
NUMBER_OF_FRAMES: 310844
NUMBER_OF_BYTES : 954912768
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:3(fre): Subtitle: subrip (default) (forced)
Metadata:
title : FR Forced : SRT
BPS : 5
DURATION : 02:39:05.452000000
NUMBER_OF_FRAMES: 222
NUMBER_OF_BYTES : 6861
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:4(fre): Subtitle: subrip
Metadata:
title : FR Full : SRT
BPS : 30
DURATION : 02:45:36.843000000
NUMBER_OF_FRAMES: 1353
NUMBER_OF_BYTES : 38444
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:5(eng): Subtitle: subrip
Metadata:
title : ENG Full : SRT
BPS : 31
DURATION : 02:36:41.573000000
NUMBER_OF_FRAMES: 1277
NUMBER_OF_BYTES : 37552
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:6(fre): Subtitle: hdmv_pgs_subtitle, 1920x1080 (forced)
Metadata:
title : FR Forced : PGS
BPS : 2786
DURATION : 02:39:05.452000000
NUMBER_OF_FRAMES: 444
NUMBER_OF_BYTES : 3325083
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:7(fre): Subtitle: hdmv_pgs_subtitle, 1920x1080
Metadata:
title : FR Full : PGS
BPS : 17457
DURATION : 02:45:36.843000000
NUMBER_OF_FRAMES: 2706
NUMBER_OF_BYTES : 21683861
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:8(eng): Subtitle: hdmv_pgs_subtitle, 1920x1080 (hearing impaired)
Metadata:
title : ENG Full SDH : PGS
BPS : 25282
DURATION : 02:37:36.155000000
NUMBER_OF_FRAMES: 3604
NUMBER_OF_BYTES : 29884804
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Error codes / log lines
[LagDiag] clk=4641.56 dclk=1.03 tcs=playing rate=1.00 wait=- fwd=5.9 keepUp=y empty=n drop=0+0 stall=0 ready=y thermal=nominal net=65.7 restarts=1
[LagDiag] clk=4642.57 dclk=1.01 tcs=playing rate=1.00 wait=- fwd=4.9 keepUp=y empty=n drop=0+0 stall=0 ready=y thermal=nominal net=36.0 restarts=1
[SubtitleDebug] before seek to 4653.200 position=4643.200 sourcePosition=4643.200 track={id=4 codec=srt language=fre} cueCount=4
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[HLSLocalServer] GET /seg1163.mp4 HTTP/1.1
[HLSSegmentProducer] #65 ledger seg-1171 base=1158 itemAxis=4687.725s sourceStart=4687.725s planSource=4687.808s drift=-0.083s shift=0.000s
[HLSLocalServer] -> 200 /seg1163.mp4 bytes=4615335 type=video/mp4 [filestream]
[HLSSegmentProducer] seg-1171.m4s captured (1697489 B)
[HLSSegmentProducer] #65 ledger seg-1172 base=1158 itemAxis=4689.685s sourceStart=4689.685s planSource=4689.768s drift=-0.083s shift=0.000s
[HLSSegmentProducer] #65 ledger seg-1173 base=1158 itemAxis=4692.104s sourceStart=4692.104s planSource=4692.271s drift=-0.167s shift=0.000s
[HLSSegmentProducer] seg-1172.m4s captured (2340623 B)
[HLSSegmentProducer] seg-1173.m4s captured (8276000 B)
[NativeAVPlayerHost] #1 timeControlStatus=waitingToPlay reason=AVPlayerWaitingWhileEvaluatingBufferingRateReason t+78.63s
[NativeAVPlayerHost] #1 timeControlStatus=waitingToPlay reason=AVPlayerWaitingToMinimizeStallsReason t+78.63s
<<<< PlayerRemoteXPC >>>> signalled err=-12860 at <>:1538
[LagDiag] clk=4653.20 dclk=10.63 tcs=waiting rate=1.00 wait=AVPlayerWaitingToMinimizeStallsReason fwd=- keepUp=n empty=n drop=0+0 stall=0 ready=y thermal=nominal net=12.4 restarts=1
[HLSLocalServer] GET /seg1164.mp4 HTTP/1.1
[HLSSegmentProducer] #65 ledger seg-1174 base=1158 itemAxis=4698.027s sourceStart=4698.027s planSource=4698.110s drift=-0.083s shift=0.000s
[HLSLocalServer] -> 200 /seg1164.mp4 bytes=8658534 type=video/mp4 [filestream]
[SubtitleDebug] after seek to 4653.200 position=4653.200 sourcePosition=4653.200 track={id=4 codec=srt language=fre} cueCount=4
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[HLSSegmentProducer] seg-1174.m4s captured (3818993 B)
[NativeAVPlayerHost] #1 timeControlStatus=playing reason=- t+78.92s
[SubtitleDebug] subtitle cues published position=4653.200 sourcePosition=4653.200 track={id=4 codec=srt language=fre} cueCount=7
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=0 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[0, 1] start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] DUPLICATE ids=[1, 2] start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[2, 3] start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] subtitle cues published position=4653.200 sourcePosition=4653.200 track={id=4 codec=srt language=fre} cueCount=7
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=0 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[0, 1] start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] DUPLICATE ids=[1, 2] start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[2, 3] start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] subtitle cues published position=4653.200 sourcePosition=4653.200 track={id=4 codec=srt language=fre} cueCount=7
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=0 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[0, 1] start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] DUPLICATE ids=[1, 2] start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[2, 3] start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] before seek to 4643.200 position=4653.200 sourcePosition=4653.200 track={id=4 codec=srt language=fre} cueCount=7
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=0 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[2, 3] start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[0, 1] start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] DUPLICATE ids=[1, 2] start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[HLSLocalServer] GET /seg1160.mp4 HTTP/1.1
[HLSVideoEngine] declareTarget backward jump 1164 -> 1160: resident in cache, no restart
[HLSLocalServer] -> 200 /seg1160.mp4 bytes=8160030 type=video/mp4 [filestream]
[NativeAVPlayerHost] #1 timeControlStatus=waitingToPlay reason=AVPlayerWaitingWhileEvaluatingBufferingRateReason t+79.25s
[NativeAVPlayerHost] #1 timeControlStatus=waitingToPlay reason=AVPlayerWaitingToMinimizeStallsReason t+79.25s
[SubtitleDebug] subtitle cues published position=4643.200 sourcePosition=4643.200 track={id=4 codec=srt language=fre} cueCount=11
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=0 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=1 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=2 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[2, 1, 2] start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[3, 2, 3] start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[0, 0] start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] DUPLICATE ids=[1, 0, 1] start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] subtitle cues published position=4643.200 sourcePosition=4643.200 track={id=4 codec=srt language=fre} cueCount=11
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=0 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=1 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=2 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[2, 1, 2] start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[3, 2, 3] start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[0, 0] start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] DUPLICATE ids=[1, 0, 1] start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] subtitle cues published position=4643.200 sourcePosition=4643.200 track={id=4 codec=srt language=fre} cueCount=11
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=0 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=1 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=2 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[2, 1, 2] start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[3, 2, 3] start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[0, 0] start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] DUPLICATE ids=[1, 0, 1] start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] subtitle cues published position=4643.200 sourcePosition=4643.200 track={id=4 codec=srt language=fre} cueCount=11
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=0 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=1 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=2 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[2, 1, 2] start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[3, 2, 3] start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[0, 0] start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] DUPLICATE ids=[1, 0, 1] start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] after seek to 4643.200 position=4643.200 sourcePosition=4643.200 track={id=4 codec=srt language=fre} cueCount=11
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=0 start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=0 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=1 start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=1 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=2 start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=2 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] cue id=3 start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[2, 1, 2] start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[3, 2, 3] start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] DUPLICATE ids=[0, 0] start=4637.174 end=4638.926 body="Ils n\'arrêtent pas le combat ?"
[SubtitleDebug] DUPLICATE ids=[1, 0, 1] start=4639.093 end=4640.302 body="Les plans dans les plans."
[HLSLocalServer] GET /seg1161.mp4 HTTP/1.1
[HLSLocalServer] -> 200 /seg1161.mp4 bytes=2245877 type=video/mp4 [filestream]
<<<< PlayerRemoteXPC >>>> signalled err=-12860 at <>:1538
[NativeAVPlayerHost] #1 timeControlStatus=playing reason=- t+79.60s
[LagDiag] clk=4643.37 dclk=-9.83 tcs=playing rate=1.00 wait=- fwd=6.0 keepUp=y empty=n drop=0+0 stall=0 ready=y thermal=nominal net=15.8 restarts=1
[LagDiag] clk=4644.40 dclk=1.03 tcs=playing rate=1.00 wait=- fwd=5.0 keepUp=y empty=n drop=0+0 stall=0 ready=y thermal=nominal net=15.8 restarts=1
[HLSLocalServer] GET /seg1162.mp4 HTTP/1.1
[HLSLocalServer] -> 200 /seg1162.mp4 bytes=4477646 type=video/mp4 [filestream]
[LagDiag] clk=4645.42 dclk=1.02 tcs=playing rate=1.00 wait=- fwd=4.0 keepUp=y empty=n drop=0+0 stall=0 ready=y thermal=nominal net=15.8 restarts=1
ForEach<Array<SubtitleCue>, Int, Optional<ModifiedContent<ModifiedContent<Image, _FrameLayout>, _OffsetEffect>>>: the ID 2 occurs multiple times within the collection, this will give undefined results!
[LagDiag] clk=4646.43 dclk=1.00 tcs=playing rate=1.00 wait=- fwd=6.6 keepUp=y empty=n drop=0+0 stall=0 ready=y thermal=nominal net=14.1 restarts=1
[NativeAVPlayerHost] #1 rate=0.0
[NativeAVPlayerHost] #1 timeControlStatus=paused reason=- t+83.48s
[LagDiag] clk=4646.96 dclk=0.53 tcs=paused rate=0.00 wait=- fwd=6.1 keepUp=y empty=n drop=0+0 stall=0 ready=y thermal=nominal net=14.1 restarts=1
[LagDiag] clk=4646.96 dclk=0.00 tcs=paused rate=0.00 wait=- fwd=6.1 keepUp=y empty=n drop=0+0 stall=0 ready=y thermal=nominal net=14.1 restarts=1
[LagDiag] clk=4646.96 dclk=0.00 tcs=paused rate=0.00 wait=- fwd=6.1 keepUp=y empty=n drop=0+0 stall=0 ready=y thermal=nominal net=14.1 restarts=1
Anything else
To investigate, I added temporary custom logging to my host app’s Aether player controller. It records subtitleCues before and after each seek and whenever AetherEngine publishes an updated cue array.
The DUPLICATE lines are generated by the host by grouping cues with identical timestamps and normalized text. The cue IDs, timestamps, text, cue count, and contents of subtitleCues come directly from AetherEngine.
Relevant trace:
[SubtitleDebug] before seek to 4653.200 position=4643.200 sourcePosition=4643.200
track={id=4 codec=srt language=fre} cueCount=4
[SubtitleDebug] after seek to 4653.200 position=4653.200 sourcePosition=4653.200
track={id=4 codec=srt language=fre} cueCount=4
[SubtitleDebug] subtitle cues published position=4653.200 sourcePosition=4653.200
track={id=4 codec=srt language=fre} cueCount=7
[SubtitleDebug] DUPLICATE ids=[0, 1]
start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] DUPLICATE ids=[1, 2]
start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[2, 3]
start=4664.451 end=4665.870 body="Le voilà !"
[SubtitleDebug] before seek to 4643.200 position=4653.200 sourcePosition=4653.200
track={id=4 codec=srt language=fre} cueCount=7
[SubtitleDebug] subtitle cues published position=4643.200 sourcePosition=4643.200
track={id=4 codec=srt language=fre} cueCount=11
[SubtitleDebug] DUPLICATE ids=[0, 0]
start=4637.174 end=4638.926 body="Ils n'arrêtent pas le combat ?"
[SubtitleDebug] DUPLICATE ids=[1, 0, 1]
start=4639.093 end=4640.302 body="Les plans dans les plans."
[SubtitleDebug] DUPLICATE ids=[2, 1, 2]
start=4645.891 end=4647.268 body="Montre-moi qui tu es."
[SubtitleDebug] DUPLICATE ids=[3, 2, 3]
start=4664.451 end=4665.870 body="Le voilà !"
The cue-count progression is 4 → 7 → 11. Cue IDs also restart and collide with IDs already present in the array.
My hunch is that the embedded subtitle reader is replaying cues after each seek and inserting them into the retained text-cue store without deduplication. The decoder’s cue ID counter also appears to restart during that process.
Tested with AetherEngine 5.0.1.
What happened?
While playing a video with an embedded SRT subtitle track, I seek forward by 10 seconds and then immediately seek backward by 10 seconds using
AetherEngine.seek(to:).I expected AetherEngine to continue publishing each subtitle cue once.
Instead, each seek replays and appends previously decoded cues to
subtitleCues. After the forward seek, the cue count increased from 4 to 7. After seeking backward, it increased from 7 to 11. The duplicated cues have identical text and timestamps, and some also reuse existing cue IDs.Because the host renders
subtitleCuesusingForEach(cues, id: \.id), the duplicated entries cause subtitles to appear multiple times.Steps to reproduce
The issue reproduces with this sequence:
The cue count increases after each seek, and previously decoded cues are inserted again with identical timestamps and text. In the captured reproduction, the count progressed from 4 to 7, then from 7 to 11.
AetherEngine version or commit SHA
5.0.1
Host app
Custom / my own integration
Platform
iOS
OS version
iOS 26.5
Device / chip
iPhone 17 Pro
Playback path
Native AVPlayer
Source media (for playback bugs)
Metadata:
title : Dune Part Two (2024)
encoder : libebml v1.4.5 + libmatroska v1.7.1
creation_time : 2024-07-19T17:24:15.000000Z
Duration: 02:45:49.02, start: 0.000000, bitrate: 6874 kb/s
Chapters:
Chapter #0:0: start 0.000000, end 554.220000
Metadata:
title : Chapitre 01
Chapter #0:1: start 554.220000, end 1288.913000
Metadata:
title : Chapitre 02
Chapter #0:2: start 1288.913000, end 1770.018000
Metadata:
title : Chapitre 03
Chapter #0:3: start 1770.018000, end 2407.905000
Metadata:
title : Chapitre 04
Chapter #0:4: start 2407.905000, end 3039.912000
Metadata:
title : Chapitre 05
Chapter #0:5: start 3039.912000, end 3633.129000
Metadata:
title : Chapitre 06
Chapter #0:6: start 3633.129000, end 4193.523000
Metadata:
title : Chapitre 07
Chapter #0:7: start 4193.523000, end 4779.483000
Metadata:
title : Chapitre 08
Chapter #0:8: start 4779.483000, end 5438.933000
Metadata:
title : Chapitre 09
Chapter #0:9: start 5438.933000, end 5945.064000
Metadata:
title : Chapitre 10
Chapter #0:10: start 5945.064000, end 6574.860000
Metadata:
title : Chapitre 11
Chapter #0:11: start 6574.860000, end 7179.422000
Metadata:
title : Chapitre 12
Chapter #0:12: start 7179.422000, end 7823.607000
Metadata:
title : Chapitre 13
Chapter #0:13: start 7823.607000, end 8329.279000
Metadata:
title : Chapitre 14
Chapter #0:14: start 8329.279000, end 8658.233000
Metadata:
title : Chapitre 15
Chapter #0:15: start 8658.233000, end 9464.789000
Metadata:
title : Chapitre 16
Chapter #0:16: start 9464.789000, end 9949.023000
Metadata:
title : Chapitre 17
Stream #0:0: Video: hevc (Main 10), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 3840x1608, SAR 1:1 DAR 160:67, 23.98 fps, 23.98 tbr, 1k tbn (default)
Metadata:
BPS : 5322182
DURATION : 02:45:49.023000000
NUMBER_OF_FRAMES: 238538
NUMBER_OF_BYTES : 6618815047
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Side data:
DOVI configuration record: version: 1.0, profile: 8, level: 6, rpu flag: 1, el flag: 0, bl flag: 1, compatibility id: 1
Stream #0:1(fre): Audio: eac3, 48000 Hz, 5.1(side), fltp, 768 kb/s (default)
Metadata:
title : FR VFF : DDP 5.1 Atmos
BPS : 768000
DURATION : 02:45:47.008000000
NUMBER_OF_FRAMES: 310844
NUMBER_OF_BYTES : 954912768
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:2(eng): Audio: eac3, 48000 Hz, 5.1(side), fltp, 768 kb/s
Metadata:
title : ENG VO : DDP 5.1 Atmos
BPS : 768000
DURATION : 02:45:47.008000000
NUMBER_OF_FRAMES: 310844
NUMBER_OF_BYTES : 954912768
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:3(fre): Subtitle: subrip (default) (forced)
Metadata:
title : FR Forced : SRT
BPS : 5
DURATION : 02:39:05.452000000
NUMBER_OF_FRAMES: 222
NUMBER_OF_BYTES : 6861
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:4(fre): Subtitle: subrip
Metadata:
title : FR Full : SRT
BPS : 30
DURATION : 02:45:36.843000000
NUMBER_OF_FRAMES: 1353
NUMBER_OF_BYTES : 38444
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:5(eng): Subtitle: subrip
Metadata:
title : ENG Full : SRT
BPS : 31
DURATION : 02:36:41.573000000
NUMBER_OF_FRAMES: 1277
NUMBER_OF_BYTES : 37552
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:6(fre): Subtitle: hdmv_pgs_subtitle, 1920x1080 (forced)
Metadata:
title : FR Forced : PGS
BPS : 2786
DURATION : 02:39:05.452000000
NUMBER_OF_FRAMES: 444
NUMBER_OF_BYTES : 3325083
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:7(fre): Subtitle: hdmv_pgs_subtitle, 1920x1080
Metadata:
title : FR Full : PGS
BPS : 17457
DURATION : 02:45:36.843000000
NUMBER_OF_FRAMES: 2706
NUMBER_OF_BYTES : 21683861
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:8(eng): Subtitle: hdmv_pgs_subtitle, 1920x1080 (hearing impaired)
Metadata:
title : ENG Full SDH : PGS
BPS : 25282
DURATION : 02:37:36.155000000
NUMBER_OF_FRAMES: 3604
NUMBER_OF_BYTES : 29884804
_STATISTICS_WRITING_APP: mkvmerge v86.0 ('Winter') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2024-07-19 17:24:15
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Error codes / log lines
Anything else
To investigate, I added temporary custom logging to my host app’s Aether player controller. It records
subtitleCuesbefore and after each seek and whenever AetherEngine publishes an updated cue array.The
DUPLICATElines are generated by the host by grouping cues with identical timestamps and normalized text. The cue IDs, timestamps, text, cue count, and contents ofsubtitleCuescome directly from AetherEngine.Relevant trace:
The cue-count progression is
4 → 7 → 11. Cue IDs also restart and collide with IDs already present in the array.My hunch is that the embedded subtitle reader is replaying cues after each seek and inserting them into the retained text-cue store without deduplication. The decoder’s cue ID counter also appears to restart during that process.
Tested with AetherEngine 5.0.1.