Skip to content

[Playback] : Resume/Seek fails on transcoded HLS streams - StartTimeTicks not allowed on segment requests #87

@MattechIT

Description

@MattechIT

Moonfin version

1.3.3

Platform

Android

OS version

Android 16 (smartphone), Android 11 (tablet)

Device model

Galaxy A54, Galaxy Tab S5e

Server type and version

Jellyfin 10.11.8 Debian

Content type

Episode

Media details (as much as you know, check the info button at the bottom right of the player)

Media details

  • General Note: This issue affects all media that trigger a transcoding session, regardless of the original format.
  • Example File used for logs:
    • Container: MKV (Matroska).
    • Resolution: 1472x1080.
    • Video Codec: HEVC (Main Profile).
    • Audio Codec: AC3 (5.1 channels).
    • Bitrate: 2312 kb/s.
    • HDR Type: SDR (yuv420p).
  • Server Transcoding Setup: Intel Quicksync (QSV) is enabled with H264 and HEVC hardware encoding

Playback path

Transcode

Symptoms (check all that apply)

  • Black screen / endless spinner
  • Audio only (no video)
  • Stuttering / frame drops
  • A/V sync issues
  • Seeking/scrubbing broken
  • Subtitles missing or incorrect
  • Unexpected forced transcode
  • App crashes / exits

Steps to reproduce

  1. Open the Moonfin client on an Android device.
  2. Start playback of any video file that triggers transcoding on the server.
  3. Stop the playback after a few minutes to ensure a "Resume" point is saved.
  4. Go back to the video details page and tap "Resume" to continue from the saved position.
  5. Observe that the player enters an infinite loading loop while the server logs immediately record a System.ArgumentException.
  6. Repeat the same process using the Official Jellyfin App or a web browser to confirm that resume works correctly with the same file and server settings.

Frequency

Always

Logs / errors (optional)

Description

When attempting to resume or seek within a video that requires transcoding, Moonfin enters an infinite loading loop. Server-side logs reveal that the client is appending the StartTimeTicks parameter to individual HLS segment requests (.ts files).

It seems that in the recent Jellyfin versions, the DynamicHlsController explicitly disallows StartTimeTicks on segment requests, as the offset should be managed via the initial playlist (.m3u8) negotiation.

Technical Analysis

  • The Issue: Moonfin requests a specific segment (e.g., 1299.ts) but includes StartTimeTicks in the query string.
  • Server Response: Jellyfin throws a System.ArgumentException: StartTimeTicks is not allowed.
  • Comparison: The Official Jellyfin Client handles this correctly by requesting the playlist with the offset. The server then invokes FFmpeg with the correct -ss (seek) and -start_number parameters, and subsequent segment requests are made without illegal time parameters.

Evidence (Logs)

1. Moonfin Client (FAILED)

When Moonfin tries to fetch a segment, it appends illegal parameters, causing the following server exception:

[2026-04-20 21:13:17.991 +00:00] [ERR] Error processing request. URL "GET" "/videos/.../hls1/main/1299.ts".
System.ArgumentException: StartTimeTicks is not allowed.
   at Jellyfin.Api.Controllers.DynamicHlsController.GetDynamicSegment(StreamingRequestDto streamingRequest, Int32 segmentId)
   at Jellyfin.Api.Controllers.DynamicHlsController.GetHlsVideoSegment(...)

2. Official Client (SUCCESSFUL)

The official client correctly triggers the server to start FFmpeg with the appropriate time offset (-ss) and segment start number (-start_number), without polluting individual segment requests:

[2026-04-20 21:19:15.680 +00:00] [INF] "/usr/lib/jellyfin-ffmpeg/ffmpeg" 
  -ss 00:34:56.094 
  ...
  -start_number 698 
  -hls_segment_filename "/dev/shm/jellyfin-transcode/...%d.ts" 
  ...

Environment

  • Jellyfin Server Version: 10.11.8
  • Client: Moonfin (Android)
  • Playback Method: Transcoding (HLS)

Proposed Fix

Ensure that StartTimeTicks is only sent during the initial HLS playlist/stream negotiation and is stripped from requests for individual .ts segments.

Example of correct behavior:

  1. Playlist request (Negotiation): GET /videos/.../main.m3u8?StartTimeTicks=XXXXXXXX (Offset is passed here).
  2. Segment request (Download): GET /videos/.../hls1/main/1299.ts (No StartTimeTicks parameter).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions