Repository navigation
fix(playback): keep the requested version when only its subtitle is blocked #2081
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
23162cb
ea8c9f4
cddfe71
1111ca8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1807,13 +1807,28 @@ func (h *PlaybackHandler) startPlaybackApplicationV3(r *http.Request, body []byt | |
| firstFailureAudioIndex = candidateAudioIndex | ||
| } | ||
| } | ||
| subtitleNotShown := false | ||
| if result.Terminal != nil && droppedSubtitle != nil && subtitleRefusalV3(result.Terminal) { | ||
| // The planner pinned the requested file's refusal on the | ||
| // subtitle, and every sibling that plays drops the subtitle | ||
| // too. Playing the requested file without it keeps its | ||
| // picture, when that plan can run. | ||
| if candidate := h.planWithoutSubtitleV3(r.Context(), playback.PlannerInputV3{Request: baseReq, RequestedFile: requestedFile, EffectiveFile: effectiveFile, LowerVersion: lowerVersionForFileV3(lowerVersion, effectiveFile), ServerBitrateCapKbps: serverBitrateCapV3(r.Context()), AudioTrackIndex: baseAudioIndex, Settings: settings, Registry: h.transformationRegistryV3(r.Context()), DVRPUStrippable: h.lazyDVRPUStrippableV3(r.Context(), effectiveFile), Now: time.Now(), AdditionalSubtitles: h.downloadedSubtitleInventoryV3(r.Context(), effectiveFile)}); candidate != nil { | ||
| droppedSubtitle = candidate | ||
| subtitleNotShown = true | ||
| } | ||
| } | ||
| if result.Terminal != nil && droppedSubtitle != nil { | ||
| req = droppedSubtitle.request | ||
| effectiveFile = droppedSubtitle.file | ||
| audioIndex = droppedSubtitle.audioIndex | ||
| result = droppedSubtitle.result | ||
| toneMapCapabilityErr = droppedSubtitle.toneMapErr | ||
| warnings = append(warnings, playback.SubtitleTrackUnavailableWarningV3()) | ||
| if subtitleNotShown { | ||
| warnings = append(warnings, playback.SubtitleNotShownWarningV3()) | ||
| } else { | ||
| warnings = append(warnings, playback.SubtitleTrackUnavailableWarningV3()) | ||
| } | ||
| } else if result.Terminal != nil && firstFailureFile != nil { | ||
| req = firstFailureReq | ||
| effectiveFile = firstFailureFile | ||
|
|
@@ -4842,6 +4857,9 @@ func (h *PlaybackHandler) executeReplanV3(r *http.Request, record *playback.Atte | |
| r = r.WithContext(withServerBitrateCapV3(r.Context(), record.ServerBitrateCapKbps)) | ||
| audioDegraded := false | ||
| subtitleDegraded := false | ||
| // subtitleNotShown marks a subtitle the effective file has but cannot | ||
| // show, as opposed to one the file lacks. | ||
| subtitleNotShown := false | ||
| reservationHeld := false | ||
| reservationHandedOff := false | ||
| cancelReservation := func() { | ||
|
|
@@ -5196,8 +5214,10 @@ func (h *PlaybackHandler) executeReplanV3(r *http.Request, record *playback.Atte | |
| } | ||
| if candidateResult.Terminal == nil && subtitleDropped { | ||
| // Prefer a version that keeps the viewer's subtitle; hold | ||
| // this one back in case none does. | ||
| if droppedSubtitle == nil { | ||
| // this one back in case none does. The requested edition, | ||
| // listed last when it was passed over only for the | ||
| // subtitle, outranks any other version held back. | ||
| if droppedSubtitle == nil || candidateFile.ID == requestedFile.ID { | ||
| droppedSubtitle = &alternateCandidateV3{file: candidateFile, request: candidateStart, audioIndex: candidateAudioIndex, result: candidateResult, toneMapErr: candidateToneMapErr} | ||
|
Comment on lines
+5220
to
5221
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Candidate overwrite replaces an executable sibling before verifying that the requested subtitle-dropped candidate's route is executable. When the requested edition plans as a progressive remux rejected by the header-authenticated worker-only policy, this causes the later // Do not replace an executable held-back sibling with the requested edition until the requested route has been validated by the same escalation logic used before committing the plan.
if droppedSubtitle == nil {
droppedSubtitle = &alternateCandidateV3{file: candidateFile, request: candidateStart, audioIndex: candidateAudioIndex, result: candidateResult, toneMapErr: candidateToneMapErr}
}Prompt for LLMTalk to Kody by mentioning @kody Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction. |
||
| } | ||
| continue | ||
|
|
@@ -5218,6 +5238,18 @@ func (h *PlaybackHandler) executeReplanV3(r *http.Request, record *playback.Atte | |
| firstFailureAudioIndex = candidateAudioIndex | ||
| } | ||
| } | ||
| // A held-back requested edition is already the picture the | ||
| // viewer asked for, so it keeps its place. | ||
| if result.Terminal != nil && droppedSubtitle != nil && droppedSubtitle.file.ID != requestedFile.ID && subtitleRefusalV3(result.Terminal) { | ||
|
Quick104 marked this conversation as resolved.
|
||
| // The planner pinned the effective file's refusal on the | ||
| // subtitle, and every sibling that plays drops the subtitle | ||
| // too. Playing the effective file without it keeps its | ||
| // picture, when that plan can run. | ||
| if candidate := h.planWithoutSubtitleV3(r.Context(), playback.PlannerInputV3{Request: baseStart, RequestedFile: plannerRequestedFile, EffectiveFile: baseEffectiveFile, LowerVersion: lowerVersionForFileV3(lowerVersion, baseEffectiveFile), ServerBitrateCapKbps: serverBitrateCapV3(r.Context()), AudioTrackIndex: baseAudioIndex, Settings: plannerSettings, Registry: h.transformationRegistryV3(r.Context()), DVRPUStrippable: h.lazyDVRPUStrippableV3(r.Context(), baseEffectiveFile), Now: time.Now(), AttemptedKeys: attemptedKeys, AdditionalSubtitles: h.downloadedSubtitleInventoryV3(r.Context(), baseEffectiveFile)}); candidate != nil { | ||
| droppedSubtitle = candidate | ||
| subtitleNotShown = true | ||
| } | ||
| } | ||
| if result.Terminal != nil && droppedSubtitle != nil { | ||
| start = droppedSubtitle.request | ||
| effectiveFile = droppedSubtitle.file | ||
|
|
@@ -5267,7 +5299,11 @@ func (h *PlaybackHandler) executeReplanV3(r *http.Request, record *playback.Atte | |
| result.Plan.DegradationWarnings = append(result.Plan.DegradationWarnings, playback.AudioTrackUnavailableWarningV3()) | ||
| } | ||
| if subtitleDegraded { | ||
| result.Plan.DegradationWarnings = appendWarningOnceV3(result.Plan.DegradationWarnings, playback.SubtitleTrackUnavailableWarningV3()) | ||
| warning := playback.SubtitleTrackUnavailableWarningV3() | ||
| if subtitleNotShown { | ||
| warning = playback.SubtitleNotShownWarningV3() | ||
| } | ||
| result.Plan.DegradationWarnings = appendWarningOnceV3(result.Plan.DegradationWarnings, warning) | ||
| } | ||
| session, err := h.sessionMgr.GetSession(record.SessionID) | ||
| if err != nil { | ||
|
|
@@ -6040,6 +6076,31 @@ func terminalAllowsAlternateFileV3(terminal *playback.TerminalV3) bool { | |
| } | ||
| } | ||
|
|
||
| // subtitleRefusalV3 reports a refusal the planner pinned on the selected | ||
| // subtitle: a burn-in that was the only reason for an adaptation the file | ||
| // cannot take, or a subtitle the fidelity policy cannot serve. The file may | ||
| // then play with the subtitle cleared; callers re-plan it to find out. | ||
| func subtitleRefusalV3(terminal *playback.TerminalV3) bool { | ||
| return terminal != nil && terminal.Reason == terminalSubtitleConversionUnsupportedV3 | ||
| } | ||
|
|
||
| // planWithoutSubtitleV3 plans input's file again with the selected subtitle | ||
| // cleared. It returns nil unless that plan can run: a progressive remux this | ||
| // attempt cannot reach must escalate here, because the caller drops a sibling | ||
| // that already plays in favor of the result. | ||
| func (h *PlaybackHandler) planWithoutSubtitleV3(ctx context.Context, input playback.PlannerInputV3) *alternateCandidateV3 { | ||
| input.Request.SubtitleTrackID, input.Request.SubtitleTrackIndex = "", nil | ||
| result, toneMapErr := h.planPlaybackWithCapabilitiesV3(ctx, input) | ||
| if result.Terminal != nil { | ||
| return nil | ||
| } | ||
| result, escalateErr := h.escalateRefusedProgressiveRemuxV3(ctx, headerAuthenticatedMediaV3(input.Request.ClientFeatures), func() playback.PlannerInputV3 { return input }, result) | ||
| if escalateErr != nil { | ||
| return nil | ||
| } | ||
| return &alternateCandidateV3{file: input.EffectiveFile, request: input.Request, audioIndex: input.AudioTrackIndex, result: result, toneMapErr: toneMapErr} | ||
| } | ||
|
|
||
| // alternateCandidateV3 is a planned alternate version held back while the | ||
| // fallback loop looks for a better one. | ||
| type alternateCandidateV3 struct { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.