fix(player): strip the burn-in the server puts back into its own transcode URL
The negotiation asks for no subtitle stream (DR-176), but when PlaybackInfo answers with a TranscodingUrl we played that URL verbatim — and the server built it from its own subtitle verdict. Jellyfin's StreamInfo.ToUrl appends SubtitleStreamIndex and SubtitleMethod whenever it picked a track, so the burn-in we had just declined came straight back through the URL, turning a remux into a full frame-by-frame re-encode. Live TV never declined it at all: open_live_stream sent no index, so the server applied the channel's default track, and broadcast subtitles are DVB bitmaps that NormalizeSubtitleEmbed converts to burn-in on sight. without_server_chosen_subtitle() drops SubtitleStreamIndex, SubtitleMethod, SubtitleCodec and alwaysBurnInSubtitleWhenTranscoding from any URL the server built — matched case-insensitively, as Jellyfin binds query keys — and re-appends the -1 sentinel, because an absent index is not "none", it is "you choose". Applied at both adoption points, plus the sentinel in the live-stream negotiation body and its fallback URL.
This commit is contained in:
@@ -1741,7 +1741,16 @@ impl MediaRepository for OnlineRepository {
|
||||
if let Some(previous) = adopt_video_play_session(response.play_session_id.clone()) {
|
||||
self.stop_transcode(&previous).await;
|
||||
}
|
||||
format!("{}{}", self.server_url, transcoding_url)
|
||||
// The server built this URL from its *own* subtitle verdict, so it can
|
||||
// hand back the burn-in the request above just declined. Strip it: the
|
||||
// negotiated answer only holds for the stream we actually open.
|
||||
//
|
||||
// TRACES: UR-020, UR-004 | DR-176 | UT-168
|
||||
format!(
|
||||
"{}{}",
|
||||
self.server_url,
|
||||
super::device_profile::without_server_chosen_subtitle(transcoding_url)
|
||||
)
|
||||
} else if audio_forces_transcode {
|
||||
warn!(
|
||||
"[PlaybackInfo] Server offered direct play for audio the webview cannot decode ({:?}) — forcing an HLS transcode",
|
||||
@@ -1844,6 +1853,13 @@ impl MediaRepository for OnlineRepository {
|
||||
auto_open_live_stream: bool,
|
||||
is_playback: bool,
|
||||
max_streaming_bitrate: u64,
|
||||
/// "No subtitle", for the same reason as everywhere else: omitting it
|
||||
/// lets the server apply the channel's default track, and broadcast
|
||||
/// subtitles are DVB bitmaps — deliverable only by burning them in,
|
||||
/// which forces a full re-encode of a stream that is already tight.
|
||||
///
|
||||
/// TRACES: UR-020, UR-004 | DR-176 | UT-168
|
||||
subtitle_stream_index: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -1871,6 +1887,7 @@ impl MediaRepository for OnlineRepository {
|
||||
// too — a channel opened at the source bitrate would walk straight
|
||||
// past a limit set for the connection. TRACES: UR-074 | DR-162
|
||||
max_streaming_bitrate: streaming_quality().max_bitrate().unwrap_or(20_000_000),
|
||||
subtitle_stream_index: super::device_profile::playback_subtitle_stream_index(),
|
||||
};
|
||||
|
||||
let response: OpenLiveStreamResponse = self.post_json_response(&endpoint, &request).await?;
|
||||
@@ -1886,14 +1903,21 @@ impl MediaRepository for OnlineRepository {
|
||||
// The transcoding URL is server-relative; make it absolute. If the server
|
||||
// did not provide one (rare for live), fall back to the HLS master endpoint.
|
||||
let stream_url = match source.transcoding_url {
|
||||
Some(url) => format!("{}{}", self.server_url, url),
|
||||
// As in `get_playback_info`: the server chose the subtitle in this
|
||||
// URL, so decline it here too. TRACES: UR-020 | DR-176 | UT-168
|
||||
Some(url) => format!(
|
||||
"{}{}",
|
||||
self.server_url,
|
||||
super::device_profile::without_server_chosen_subtitle(&url)
|
||||
),
|
||||
None => format!(
|
||||
"{}/Videos/{}/master.m3u8?api_key={}&MediaSourceId={}&LiveStreamId={}&VideoCodec=h264&AudioCodec=aac&TranscodingProtocol=hls&TranscodingContainer=ts",
|
||||
"{}/Videos/{}/master.m3u8?api_key={}&MediaSourceId={}&LiveStreamId={}&VideoCodec=h264&AudioCodec=aac&TranscodingProtocol=hls&TranscodingContainer=ts&SubtitleStreamIndex={}",
|
||||
self.server_url,
|
||||
item_id,
|
||||
self.access_token,
|
||||
source.id,
|
||||
source.live_stream_id.clone().unwrap_or_default(),
|
||||
super::device_profile::playback_subtitle_stream_index(),
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user