Files
silo-server/internal/playback/protocol_v3_test.go
T
ee9356aab3 fix(playback): claim Safari DV/HDR10 decode evidence and preserve dvvC in remuxes (#617)
* fix(playback): claim Safari DV/HDR10 decode evidence and preserve dvvC

Follow-up to #613 for #609: Safari 26 reports dynamic-range: standard even
on an XDR display, and answers canPlayType "probably" only for dvh1/hvc1
sample entries, never dvhe/hev1. The web probe gated every structured HDR
claim on that media query and probed only dvhe, so the planner still saw
empty hdr_details and terminated with hdr_transcode_unsupported.

- Run the Dolby Vision and HDR10 shape probes unconditionally; the
  dynamic-range query survives only as the best-effort hdr output boolean.
- Probe dvh1+dvhe per DV profile and hvc1+hev1 for the exact HDR10
  Media Capabilities shape; either definitive answer earns the claim.
- Tag preserved-DV remuxes dvh1 with -strict unofficial: FFmpeg omits the
  dvvC configuration record under either tag without it, so the previous
  dvhe output carried no DV signaling at all.
- Scale the screen-derived max_resolution by devicePixelRatio so 2x
  panels stop advertising 1080p.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(playback): align DV/HDR10 claims with the sample entries the remux emits

Review follow-ups on #617 (Codex P1s):

- Probe only dvh1: a browser answering "probably" solely for dvhe has
  given no evidence for the dvh1-tagged file the preserve remux delivers,
  so that answer no longer earns a Dolby Vision claim; such browsers keep
  the validated HDR10 fallback.
- Label the explicit v3 HDR10 strip output hvc1 so the file matches the
  hvc1 evidence the web probe accepts; legacy/auto strips keep hev1.
- Cover preserve tagging for profiles 5 and 8, and exercise the
  mode-to-argument mapping through StartRemuxWithDVMode instead of
  passing the tag flag directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(playback): name the subtitle when burn-in alone forces a refused transcode

Selecting a PGS/VOBSUB track on a client without a bitmap renderer forces
a burn-in transcode. When that transcode cannot run, the terminal blamed
the HDR pipeline (hdr_transcode_unsupported) or the 4K policy
(no_alternate_version) — problems that were not blocking playback, since
deselecting the subtitle restores the previous route.

- When the burn requirement is the sole trigger of the adaptation, the
  HDR and 4K-policy terminals emit subtitle_conversion_unsupported with
  a message naming the burn requirement and the actual blocker. A range
  the client genuinely cannot take keeps the HDR terminal.
- describePlanTerminal passes the server's subtitle message through
  instead of flattening every subtitle_* reason to one generic sentence.
- The web player toasts the refusal when it rolls the subtitle selection
  back; previously the only surface was the quality menu, which a user
  who just picked a subtitle has no reason to open.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(playback): require decode evidence for the exact hvc1 entry and gate the disabled-transcode subtitle terminal

Review follow-ups on #617:

- The HDR10 probe accepts only hvc1.2.4.L153.B0: the explicit v3 strip
  remux labels its output hvc1, so an hev1-only decodingInfo answer is
  evidence for bytes Silo never sends and earns no claim (Codex P1).
- The disabled-transcode branch blames the subtitle only when the burn
  requirement was the sole adaptation trigger; other causes keep
  transcoding_disabled. In practice a bitmap selection without transcode
  terminals in the subtitle policy before this branch, but the guard
  keeps the sole-cause invariant if that ordering ever changes
  (CodeRabbit / Codex P2).
- Protocol doc scopes the hvc1 labeling to the explicit v3 strip path;
  legacy/auto strips keep hev1 (CodeRabbit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 21:14:52 -04:00

2242 lines
114 KiB
Go

package playback
import (
"encoding/json"
"os"
"strings"
"testing"
"github.com/Silo-Server/silo-server/internal/models"
)
func hasDegradationWarningV3(warnings []DegradationWarningV3, code string) bool {
for _, warning := range warnings {
if warning.Code == code {
return true
}
}
return false
}
func TestServerFeaturesV3ReturnsCompleteIndependentSlices(t *testing.T) {
first := ServerFeaturesV3()
second := ServerFeaturesV3()
expected := map[string]struct{}{
FeaturePlaybackPlanV3: {},
FeatureNeutralContractV3: {},
FeatureLayoutPassthrough: {},
FeatureRouteDiagnostics: {},
FeatureDeviceQuirksV3: {},
FeatureSeekReanchorV3: {},
FeatureOutputChangeV3: {},
FeatureDirectStreamResumeV3: {},
FeaturePlanSourceDurationV3: {},
}
if len(first) != len(expected) {
t.Fatalf("server features = %v, want %d entries", first, len(expected))
}
seen := make(map[string]struct{}, len(first))
for _, feature := range first {
if _, ok := expected[feature]; !ok {
t.Fatalf("server features contain unexpected %q: %v", feature, first)
}
if _, duplicate := seen[feature]; duplicate {
t.Fatalf("server features contain duplicate %q: %v", feature, first)
}
seen[feature] = struct{}{}
}
for feature := range expected {
if _, ok := seen[feature]; !ok {
t.Fatalf("server features omitted %q: %v", feature, first)
}
}
first[0] = "mutated"
if second[0] != FeaturePlaybackPlanV3 {
t.Fatalf("feature slices share backing storage: %v", second)
}
}
func TestStartRequestV3Validation(t *testing.T) {
index := 1
req := validStartRequestV3()
req.AudioTrackIndex = &index
req.AudioTrackID = TrackIDV3(req.FileID, "audio", index)
warnings, err := req.NormalizeAndValidate()
if err != nil {
t.Fatalf("NormalizeAndValidate: %v", err)
}
if len(warnings) != 0 {
t.Fatalf("warnings = %#v, want none", warnings)
}
req.AudioTrackID = TrackIDV3(req.FileID, "audio", 2)
if _, err := req.NormalizeAndValidate(); err == nil {
t.Fatal("mismatched track id/index accepted")
}
}
func TestStartRequestV3ProgressPersistenceValidation(t *testing.T) {
req := validStartRequestV3()
if _, err := req.NormalizeAndValidate(); err != nil {
t.Fatal(err)
}
if req.ProgressPersistence != ProgressPersistenceServerV3 {
t.Fatalf("omitted progress_persistence normalized to %q", req.ProgressPersistence)
}
req = validStartRequestV3()
req.ProgressPersistence = ProgressPersistenceClientV3
req.StartPosition = nil
if _, err := req.NormalizeAndValidate(); err == nil {
t.Fatal("client progress persistence without explicit start_position was accepted")
}
zero := 0.0
req.StartPosition = &zero
if _, err := req.NormalizeAndValidate(); err != nil {
t.Fatalf("explicit zero must remain distinguishable and valid: %v", err)
}
}
func TestStartRequestV3UnknownQualityFallsBackToAuto(t *testing.T) {
req := validStartRequestV3()
req.QualityPreference = "future-super-quality"
warnings, err := req.NormalizeAndValidate()
if err != nil {
t.Fatalf("NormalizeAndValidate: %v", err)
}
if req.QualityPreference != "auto" || len(warnings) != 1 || warnings[0].Code != "quality_preference_normalized" {
t.Fatalf("quality=%q warnings=%#v", req.QualityPreference, warnings)
}
}
func TestReplanRequestV3OperationDefaultsAndValidates(t *testing.T) {
start := validStartRequestV3()
request := ReplanRequestV3{
ProtocolVersion: ProtocolV3,
PlaybackAttemptID: start.PlaybackAttemptID,
ReplanRequestID: "replan-operation-0001",
FailedPlanID: "plan:operation-0001",
PlanAttemptID: "plan-attempt-operation-0001",
PlanAttemptKey: "v3:0000000000000001",
AttemptCount: 1,
QualityPreference: start.QualityPreference,
Failure: FailureV3{Classification: "parser_failure"},
Capabilities: start.Capabilities,
ClientPlaybackContext: start.ClientPlaybackContext,
}
if request.EffectiveOperation() != ReplanOperationFailureRecoveryV3 {
t.Fatalf("missing operation = %q", request.EffectiveOperation())
}
if err := request.Validate(); err != nil {
t.Fatalf("backward-compatible default operation: %v", err)
}
request.Operation = ReplanOperationSeekReanchorV3
request.Failure.Classification = ""
if err := request.Validate(); err != nil {
t.Fatalf("seek reanchor operation without fake failure: %v", err)
}
body, err := json.Marshal(request)
if err != nil {
t.Fatal(err)
}
var wire map[string]any
if err := json.Unmarshal(body, &wire); err != nil {
t.Fatal(err)
}
if wire["operation"] != string(ReplanOperationSeekReanchorV3) {
t.Fatalf("serialized operation = %#v", wire["operation"])
}
if _, ok := wire["failure"]; ok {
t.Fatalf("seek reanchor serialized a synthetic failure = %#v", wire["failure"])
}
request.Operation = ReplanOperationSeekFailureRecoveryV3
if err := request.Validate(); err == nil {
t.Fatal("seek failure recovery without a classification was accepted")
}
request.Failure.Classification = "decoder_failure"
if err := request.Validate(); err != nil {
t.Fatalf("seek failure recovery operation: %v", err)
}
request.Operation = ReplanOperationTrackChangeV3
request.Failure = FailureV3{}
if err := request.Validate(); err != nil {
t.Fatalf("track change without a failure classification: %v", err)
}
for _, operation := range []ReplanOperationV3{
ReplanOperationTrackChangeV3,
ReplanOperationQualityChangeV3,
ReplanOperationOutputChangeV3,
} {
request.Operation = operation
request.QualityPreference = "720p"
request.Failure = FailureV3{Classification: "decoder_failure"}
if err := request.Validate(); err == nil {
t.Fatalf("%s with failure was accepted", operation)
}
}
request.Failure = FailureV3{}
request.Operation = ReplanOperationQualityChangeV3
request.QualityPreference = ""
if err := request.Validate(); err == nil {
t.Fatal("quality change without a quality_preference was accepted")
}
request.QualityPreference = "720p"
if err := request.Validate(); err != nil {
t.Fatalf("quality change without a failure classification: %v", err)
}
request.Operation = ReplanOperationOutputChangeV3
request.QualityPreference = ""
if err := request.Validate(); err != nil {
t.Fatalf("output change without a failure classification: %v", err)
}
request.Operation = "future_operation"
if err := request.Validate(); err == nil {
t.Fatal("unknown replan operation was accepted")
}
}
func TestHDR10CapabilityLimitsBoundTheClaimedStreamClass(t *testing.T) {
width, height, frameRate, bitrate := 3840, 2160, 24.0, 80_000
plan := PlanV3{EffectiveRecipe: EffectiveRecipeV3{
VideoCodec: "hevc", Width: &width, Height: &height, FrameRate: &frameRate,
BitrateKbps: &bitrate, DynamicRange: DynamicRangeHDR10V3,
}}
hdr := HDRCapabilitiesV3{
HDR10: true, HDR10MaxWidth: 3840, HDR10MaxHeight: 2160,
HDR10MaxFrameRate: 24, HDR10MaxBitrateKbps: 80_000,
}
if !hdrDetailsSupportPlanV3(hdr, plan) {
t.Fatal("the exactly probed HDR10 stream class was rejected")
}
tooFast := 60.0
plan.EffectiveRecipe.FrameRate = &tooFast
if hdrDetailsSupportPlanV3(hdr, plan) {
t.Fatal("an HDR10 stream above the probed frame-rate ceiling was accepted")
}
}
func TestReplanRequestV3RejectsInvalidNetworkAndTrackEvidence(t *testing.T) {
start := validStartRequestV3()
request := ReplanRequestV3{
ProtocolVersion: ProtocolV3,
PlaybackAttemptID: start.PlaybackAttemptID,
ReplanRequestID: "replan-validation-0001",
FailedPlanID: "plan:validation-0001",
PlanAttemptID: "plan-attempt-validation-0001",
PlanAttemptKey: "v3:0000000000000001",
AttemptCount: 1,
QualityPreference: start.QualityPreference,
Failure: FailureV3{Classification: "parser_failure"},
Capabilities: start.Capabilities,
ClientPlaybackContext: start.ClientPlaybackContext,
}
negative := -1
request.SelectedTracks.Subtitle = &TrackIdentityV3{ID: "file:42:subtitle:-1", Index: &negative}
if err := request.Validate(); err == nil {
t.Fatal("negative subtitle index was accepted")
}
request.SelectedTracks.Subtitle = nil
tooLow := 99
request.BandwidthEstimateKbps = &tooLow
if err := request.Validate(); err == nil {
t.Fatal("out-of-range bandwidth estimate was accepted")
}
}
func TestPlanAttemptKeyV3Fixture(t *testing.T) {
type fixture struct {
Name string `json:"name"`
ServerPlanAttemptKey string `json:"server_plan_attempt_key"`
ReplanEcho string `json:"replan_echo"`
AttemptedPlanKeys []string `json:"attempted_plan_keys"`
ExpectedServerAction string `json:"expected_server_action"`
}
body, err := os.ReadFile("testdata/protocol_v3/attempt_keys.json")
if err != nil {
t.Fatal(err)
}
var fixtures []fixture
if err := json.Unmarshal(body, &fixtures); err != nil {
t.Fatal(err)
}
for _, value := range fixtures {
t.Run(value.Name, func(t *testing.T) {
if value.ServerPlanAttemptKey == "" || value.ReplanEcho != value.ServerPlanAttemptKey {
t.Fatalf("opaque echo drifted: %#v", value)
}
if len(value.AttemptedPlanKeys) != 1 || value.AttemptedPlanKeys[0] != value.ServerPlanAttemptKey {
t.Fatalf("attempted plan keys do not echo the server token: %#v", value)
}
if value.ExpectedServerAction != "reject_already_attempted_plan" {
t.Fatalf("server action = %q", value.ExpectedServerAction)
}
})
}
}
func TestProtocolV3ConformanceMatrixCoversReleaseTrain(t *testing.T) {
var matrix ConformanceMatrixV3
body, err := os.ReadFile("testdata/protocol_v3/conformance_matrix.json")
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(body, &matrix); err != nil {
t.Fatal(err)
}
if matrix.SchemaVersion != 1 {
t.Fatalf("schema version = %d", matrix.SchemaVersion)
}
categories := make(map[string]bool)
names := make(map[string]bool)
plannerByName := make(map[string]PlannerScenarioV3)
for _, value := range matrix.Planner {
plannerByName[value.Name] = value
}
recordScenario := func(name, category string) {
t.Helper()
if name == "" || category == "" {
t.Fatalf("unnamed scenario: %q/%q", name, category)
}
if names[name] {
t.Fatalf("duplicate scenario name %q", name)
}
names[name] = true
categories[category] = true
}
for _, value := range matrix.Planner {
recordScenario(value.Name, value.Category)
}
for _, value := range matrix.Replans {
recordScenario(value.Name, value.Category)
if err := value.Request.Validate(); err != nil {
t.Errorf("replan scenario %q is invalid: %v", value.Name, err)
}
}
for _, value := range matrix.Protocol {
recordScenario(value.Name, value.Category)
if value.Input.StartRequest != nil {
request := *value.Input.StartRequest
if _, err := request.NormalizeAndValidate(); err != nil {
t.Errorf("protocol scenario %q has invalid start request: %v", value.Name, err)
}
}
if value.Input.ReplanRequest != nil {
if err := value.Input.ReplanRequest.Validate(); err != nil {
t.Errorf("protocol scenario %q has invalid replan request: %v", value.Name, err)
}
}
}
for _, required := range []string{
"evidence_tier_gating", "deliveries_negotiation", "attempt_key_echo_and_loop",
"track_change_replan", "quality_change_replan", "output_change_replan", "idempotent_replan",
"concurrent_replan", "mid_seek_replan", "available_qualities",
"audio_only_planning", "output_context_invalidation", "legacy_426",
"hdr_dv_matrix", "audio_matrix", "subtitle_matrix", "recovery_matrix",
"restart_matrix", "capacity_matrix", "route_event_limits",
} {
if !categories[required] {
t.Errorf("conformance matrix omits %q", required)
}
}
for name, delivery := range map[string]DeliveryV3{
"evidence_exact": DeliveryTranscodeHLSV3,
"evidence_platform_attested": DeliveryOriginalHTTPV3,
"evidence_declared": DeliveryOriginalHTTPV3,
"delivery_original": DeliveryOriginalHTTPV3,
"delivery_progressive": DeliveryRemuxProgressiveV3,
"delivery_hls": DeliveryRemuxHLSV3,
"delivery_transcode": DeliveryTranscodeHLSV3,
"audio_only_original": DeliveryOriginalHTTPV3,
"hdr10_exact_direct": DeliveryOriginalHTTPV3,
"dolby_vision_8_exact_direct": DeliveryOriginalHTTPV3,
"dolby_vision_7_hdr10_fallback": DeliveryRemuxProgressiveV3,
"truehd_audio_conversion": DeliveryRemuxProgressiveV3,
"truehd_exact_layout_passthrough": DeliveryOriginalHTTPV3,
"embedded_pgs_sidecar": DeliveryOriginalHTTPV3,
"embedded_ass_authored_render": DeliveryOriginalHTTPV3,
"embedded_dvd_burn_in": DeliveryTranscodeHLSV3,
} {
value, ok := plannerByName[name]
if !ok || value.Expected.Outcome != OutcomePlayableV3 || value.Expected.Delivery != delivery {
t.Errorf("scenario %q = %#v, want playable %q", name, value.Expected, delivery)
}
}
if value := plannerByName["available_qualities"]; len(value.Expected.AvailableQualities) < 2 || value.Expected.AvailableQualities[0].Label != QualityOriginalV3 {
t.Errorf("available quality fixture = %#v", value.Expected.AvailableQualities)
}
transformationNamed := func(value PlannerScenarioV3, name string) bool {
t.Helper()
for _, transformation := range value.Expected.Transformations {
if transformation.Name == name {
return true
}
}
return false
}
if value := plannerByName["hdr10_exact_direct"]; value.Source.DynamicRange != DynamicRangeHDR10V3 || value.Source.BitDepth != 10 {
t.Errorf("HDR10 scenario source = %#v", value.Source)
}
if value := plannerByName["dolby_vision_8_exact_direct"]; value.Source.DynamicRange != DynamicRangeDolbyVisionV3 || value.Source.DVProfile != 8 || len(value.Expected.Transformations) != 0 {
t.Errorf("Dolby Vision 8 scenario = %#v", value)
}
if value := plannerByName["dolby_vision_7_hdr10_fallback"]; value.Source.DVProfile != 7 || !transformationNamed(value, TransformationServerDV7HDR10V3) {
t.Errorf("Dolby Vision 7 fallback scenario = %#v", value)
}
if value := plannerByName["truehd_audio_conversion"]; value.Source.AudioCodec != "truehd" || !transformationNamed(value, TransformationAudioToAACV3) {
t.Errorf("TrueHD conversion scenario = %#v", value)
}
if value := plannerByName["truehd_exact_layout_passthrough"]; value.Source.AudioCodec != "truehd" || value.Expected.Claims == nil || !value.Expected.Claims.Audio.Passthrough {
t.Errorf("TrueHD passthrough scenario = %#v", value)
}
for name, mode := range map[string]SubtitleModeV3{
"embedded_pgs_sidecar": SubtitleRenderV3,
"embedded_ass_authored_render": SubtitleRenderV3,
"embedded_dvd_burn_in": SubtitleBurnInV3,
} {
value := plannerByName[name]
if value.Request.SubtitleTrackID == "" || value.Expected.SelectedTracks == nil || value.Expected.SelectedTracks.Subtitle == nil ||
value.Expected.SelectedTracks.Subtitle.ID != value.Request.SubtitleTrackID || value.Expected.Subtitle == nil ||
value.Expected.Subtitle.Mode != mode || value.Expected.Subtitle.TrackID != value.Request.SubtitleTrackID {
t.Errorf("subtitle scenario %q = %#v", name, value)
}
}
replansByName := make(map[string]ReplanScenarioV3, len(matrix.Replans))
for _, value := range matrix.Replans {
replansByName[value.Name] = value
}
for _, operation := range []struct {
prefix string
value ReplanOperationV3
}{
{prefix: "track_change", value: ReplanOperationTrackChangeV3},
{prefix: "quality_change", value: ReplanOperationQualityChangeV3},
} {
base := replansByName[operation.prefix]
if base.Request.EffectiveOperation() != operation.value || base.Expected.HTTPStatus != 200 {
t.Errorf("%s base scenario = %#v", operation.prefix, base)
}
duplicate := replansByName[operation.prefix+"_idempotent_duplicate"]
if duplicate.Request.EffectiveOperation() != operation.value || duplicate.Expected.SameRequestAndBodyStatus != 200 ||
!duplicate.Expected.ResponseReplayedVerbatim || duplicate.Expected.ChangedBodyStatus != 409 || duplicate.Expected.ChangedBodyError != "idempotency_key_reused" {
t.Errorf("%s duplicate scenario = %#v", operation.prefix, duplicate)
}
concurrent := replansByName[operation.prefix+"_concurrent_duplicate"]
if concurrent.Request.EffectiveOperation() != operation.value || concurrent.Expected.WhileFirstLeaseActiveStatus != 409 ||
concurrent.Expected.ConcurrentError != "replan_in_progress" || concurrent.Expected.AfterCompletionStatus != 200 || !concurrent.Expected.ResponseReplayedVerbatim {
t.Errorf("%s concurrent scenario = %#v", operation.prefix, concurrent)
}
midSeek := replansByName[operation.prefix+"_mid_seek"]
if midSeek.Request.EffectiveOperation() != operation.value || midSeek.Request.PositionSeconds != 321.25 ||
midSeek.Expected.PositionSeconds != midSeek.Request.PositionSeconds || !midSeek.Expected.PositionPreserved {
t.Errorf("%s mid-seek scenario = %#v", operation.prefix, midSeek)
}
}
protocolByName := make(map[string]ProtocolScenarioV3, len(matrix.Protocol))
for _, value := range matrix.Protocol {
protocolByName[value.Name] = value
}
legacy := protocolByName["legacy_start_requires_upgrade"]
if legacy.Input.LegacyStartBody == nil || legacy.Input.LegacyStartBody.FileID <= 0 || legacy.Expected.HTTPStatus != 426 || legacy.Expected.Error != "client_upgrade_required" {
t.Errorf("legacy protocol scenario = %#v", legacy)
}
output := protocolByName["output_context_change_invalidates_attempt"]
if output.Input.FirstOutputContextID == output.Input.SecondOutputContextID || !output.Expected.PlanIDUnchanged || !output.Expected.PlanAttemptKeyChanged {
t.Errorf("output-context scenario = %#v", output)
}
loop := protocolByName["opaque_attempt_key_loop"]
if loop.Input.ServerPlanAttemptKey == "" || loop.Input.ReplanEcho != loop.Input.ServerPlanAttemptKey ||
len(loop.Input.AttemptedPlanKeys) != 1 || loop.Input.AttemptedPlanKeys[0] != loop.Input.ServerPlanAttemptKey || loop.Expected.Action != "reject_already_attempted_plan" {
t.Errorf("opaque loop scenario = %#v", loop)
}
recovery := protocolByName["failure_recovery_preserves_intent"]
if recovery.Input.ReplanRequest == nil || recovery.Input.ReplanRequest.SelectedTracks.Subtitle == nil ||
!recovery.Expected.SelectionPreserved || !recovery.Expected.PositionPreserved || recovery.Expected.HTTPStatus != 200 {
t.Errorf("failure-recovery scenario = %#v", recovery)
}
restart := protocolByName["restart_replays_terminal_attempt"]
if restart.Input.StartRequest == nil || restart.Input.PersistedDecision == nil || !restart.Input.Restarted ||
restart.Expected.HTTPStatus != 201 || restart.Expected.Outcome != OutcomeAdaptationUnavailableV3 ||
restart.Expected.TerminalReason != "transcode_start_failed" || !restart.Expected.ResponseReplayedVerbatim ||
restart.Expected.CapacityDelta == nil || *restart.Expected.CapacityDelta != 0 {
t.Errorf("restart replay scenario = %#v", restart)
}
capacity := protocolByName["capacity_unavailable_cleans_up"]
if capacity.Input.StartRequest == nil || capacity.Input.CapacityAvailable == nil || *capacity.Input.CapacityAvailable ||
capacity.Expected.HTTPStatus != 201 || capacity.Expected.TerminalReason != "capacity_unavailable" ||
capacity.Expected.CapacityDelta == nil || *capacity.Expected.CapacityDelta != 0 || !capacity.Expected.CleanupComplete {
t.Errorf("capacity scenario = %#v", capacity)
}
limit := protocolByName["route_event_diagnostic_limit"]
if limit.Input.RouteEvent == nil || len(limit.Input.RouteEvent.Diagnostics) != 33 || limit.Expected.HTTPStatus != 400 ||
limit.Expected.Error != "bad_request" || limit.Expected.Action != "reject_without_persisting" {
t.Errorf("route-event limit scenario = %#v", limit)
}
}
func TestProtocolV3GoldenWireFixtures(t *testing.T) {
startBody, err := os.ReadFile("testdata/protocol_v3/start_request.json")
if err != nil {
t.Fatal(err)
}
var start StartRequestV3
if err := json.Unmarshal(startBody, &start); err != nil {
t.Fatal(err)
}
if _, err := start.NormalizeAndValidate(); err != nil {
t.Fatalf("golden start request: %v", err)
}
replanBody, err := os.ReadFile("testdata/protocol_v3/replan_request.json")
if err != nil {
t.Fatal(err)
}
var replan ReplanRequestV3
if err := json.Unmarshal(replanBody, &replan); err != nil {
t.Fatal(err)
}
if err := replan.Validate(); err != nil {
t.Fatalf("golden replan request: %v", err)
}
if replan.BandwidthEstimateKbps == nil || *replan.BandwidthEstimateKbps != 3_500 ||
replan.BandwidthCapKbps == nil || *replan.BandwidthCapKbps != 4_000 || !replan.Metered {
t.Fatalf("golden replan network evidence = %#v", replan)
}
responseBody, err := os.ReadFile("testdata/protocol_v3/decision_response.json")
if err != nil {
t.Fatal(err)
}
var response DecisionResponseV3
if err := json.Unmarshal(responseBody, &response); err != nil {
t.Fatal(err)
}
if response.ProtocolVersion != ProtocolV3 || response.Outcome != OutcomePlayableV3 || response.PlaybackPlan == nil || response.PlaybackPlan.Stream.Protocol != StreamHTTPProgressiveV3 {
t.Fatalf("golden response = %#v", response)
}
if !strings.HasPrefix(response.PlaybackPlan.PlanAttemptKey, "v3:") {
t.Fatalf("golden plan attempt key = %q, want an opaque server-owned v3: token", response.PlaybackPlan.PlanAttemptKey)
}
if replan.FailedPlanID != response.PlaybackPlan.PlanID || replan.PlanAttemptKey != response.PlaybackPlan.PlanAttemptKey ||
len(replan.AttemptedPlanKeys) != 1 || replan.AttemptedPlanKeys[0] != response.PlaybackPlan.PlanAttemptKey {
t.Fatalf("golden replan does not echo the golden decision identity: replan=%#v plan=%#v", replan, response.PlaybackPlan)
}
}
func TestStartRequestV3RequiresCapabilityEvidenceTiers(t *testing.T) {
req := validStartRequestV3()
req.Capabilities.VideoEvidence = ""
if _, err := req.NormalizeAndValidate(); err == nil {
t.Fatal("missing video_evidence was accepted")
}
req = validStartRequestV3()
req.Capabilities.AudioEvidence = "guessed"
if _, err := req.NormalizeAndValidate(); err == nil {
t.Fatal("unknown audio_evidence was accepted")
}
req = validStartRequestV3()
req.Capabilities.VideoEvidence = EvidenceDeclaredV3
req.Capabilities.AudioEvidence = EvidencePlatformAttestedV3
if _, err := req.NormalizeAndValidate(); err != nil {
t.Fatalf("valid evidence tiers rejected: %v", err)
}
}
// The same SDR source must reach a tier-appropriate route for each evidence
// tier: exact and platform_attested validate against decode entries (the
// latter without profile/level matching), declared grants the copy route on
// the flat codec+container match alone.
func TestPlanPlaybackV3EvidenceTiersReachTierAppropriateRoutes(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].BitDepth = 8
file.VideoTracks[0].Profile = "Main"
base := validStartRequestV3()
base.Capabilities.Containers = []string{"mkv"}
// exact: a decode entry with a non-matching profile blocks the direct route.
exact := base
exact.Capabilities.VideoEvidence = EvidenceExactV3
exact.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{8}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
result := PlanPlaybackV3(PlannerInputV3{Request: exact, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery == DeliveryOriginalHTTPV3 {
t.Fatalf("exact tier with mismatched profile = %s", ExplainPlannerResultV3(result))
}
// platform_attested: the identical capability set skips profile/level
// matching and earns the direct route.
attested := exact
attested.Capabilities.VideoEvidence = EvidencePlatformAttestedV3
result = PlanPlaybackV3(PlannerInputV3{Request: attested, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 {
t.Fatalf("platform_attested tier = %s", ExplainPlannerResultV3(result))
}
// declared: no decode entries at all; the flat codec list carries the day.
declared := base
declared.Capabilities.VideoEvidence = EvidenceDeclaredV3
result = PlanPlaybackV3(PlannerInputV3{Request: declared, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 {
t.Fatalf("declared tier = %s", ExplainPlannerResultV3(result))
}
}
// A tier that cannot validate a stream the flat lists claim must say so:
// the adapted plan carries evidence_insufficient_for_direct rather than
// looking like a device refusal.
func TestPlanPlaybackV3ExactTierWithoutDecodeEntryReportsEvidenceInsufficiency(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].BitDepth = 8
req := validStartRequestV3()
req.Capabilities.Containers = []string{"mkv"}
req.Capabilities.VideoDecode = nil
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryTranscodeHLSV3 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if !hasDegradationWarningV3(result.Plan.DegradationWarnings, EvidenceInsufficientForDirectV3) {
t.Fatalf("warnings = %#v", result.Plan.DegradationWarnings)
}
if result.Plan.DecisionReason != EvidenceInsufficientForDirectV3 {
t.Fatalf("decision reason = %q", result.Plan.DecisionReason)
}
}
// Only exact audio evidence earns passthrough claims; platform_attested
// evidence still qualifies for a copy route via decode support.
func TestAudioEligibilityV3PassthroughRequiresExactEvidence(t *testing.T) {
source := SourceDescriptorV3{AudioCodec: "eac3", AudioChannels: 6, AudioLayout: "5.1"}
req := validStartRequestV3()
req.ClientFeatures = append(req.ClientFeatures, FeatureLayoutPassthrough)
req.Capabilities.CodecsAudio = []string{"eac3"}
req.Capabilities.AudioPassthrough = &AudioPassthroughV3{
PassthroughCodecs: []string{"eac3"}, MaxChannels: 8,
Entries: []AudioPassthroughEntryV3{{Codec: "eac3", ChannelCounts: []int{6}, Layouts: []string{"5.1"}}},
}
copyOK, passthrough, claim := audioEligibilityV3(source, req)
if !copyOK || !passthrough || !claim.Passthrough {
t.Fatalf("exact evidence passthrough = %v %v %#v", copyOK, passthrough, claim)
}
req.Capabilities.AudioEvidence = EvidencePlatformAttestedV3
copyOK, passthrough, claim = audioEligibilityV3(source, req)
if !copyOK || passthrough || claim.Passthrough {
t.Fatalf("platform_attested evidence = %v %v %#v", copyOK, passthrough, claim)
}
}
func TestPlanPlaybackV3DirectRequiresDetailedEvidence(t *testing.T) {
file := detailedFixtureFileV3()
req := validStartRequestV3()
req.ClientFeatures = append(req.ClientFeatures, FeatureLayoutPassthrough)
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
req.ClientPlaybackContext.Output.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
// Exact-tier evidence with no validating decode entry cannot earn a
// direct route; without a transcode fallback the plan terminates.
req.Capabilities.VideoDecode = nil
result = PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: false, Allow4KTranscode: true}})
if result.Terminal == nil || result.Terminal.Reason != "transcoding_disabled" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestSourceDescriptorV3NormalizesLegacyHEVCMetadata(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].BitDepth = 0
file.VideoTracks[0].PixelFormat = "yuv420p10le"
file.VideoTracks[0].DVProfile = 7
file.VideoTracks[0].DVELPresent = false
file.VideoTracks[0].DVEnhancementLayer = ""
file.VideoTracks[0].VideoRangeType = "DOVIWithEL"
source := SourceDescriptorFromFileV3(file, 0)
if source.BitDepth != 10 {
t.Fatalf("bit depth = %d, want inferred 10", source.BitDepth)
}
if source.DVEnhancementLayer != EnhancementUnknownV3 {
t.Fatalf("enhancement layer = %q, want unknown", source.DVEnhancementLayer)
}
}
func TestSourceDescriptorV3PreservesCanonicalColorRange(t *testing.T) {
for _, test := range []struct {
name string
input string
want string
}{
{name: "limited", input: "tv", want: "tv"},
{name: "full", input: "pc", want: "pc"},
{name: "unspecified", input: "unknown", want: "unknown"},
{name: "normalizes case and whitespace", input: " PC ", want: "pc"},
{name: "rejects non-ffmpeg value", input: "limited", want: ""},
} {
t.Run(test.name, func(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].ColorRange = test.input
if got := SourceDescriptorFromFileV3(file, 0).ColorRange; got != test.want {
t.Fatalf("color range = %q, want %q", got, test.want)
}
})
}
}
func TestPlanPlaybackV3DirectPlaysLegacyHDR10WithInferredBitDepth(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].BitDepth = 0
file.VideoTracks[0].PixelFormat = "yuv420p10le"
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
req.ClientPlaybackContext.Output.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 || !result.Plan.Claims.Video.HDR10 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestPlanPlaybackV3DirectPlaysLegacyDolbyVisionProfile8(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].BitDepth = 0
file.VideoTracks[0].PixelFormat = "yuv420p10le"
file.VideoTracks[0].DVProfile = 8
file.VideoTracks[0].DVBLCompatID = 1
file.VideoTracks[0].VideoRange = "DolbyVision"
file.VideoTracks[0].VideoRangeType = "DOVIWithHDR10"
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true, DolbyVisionProfiles: []int{8}}
req.ClientPlaybackContext.Output.HDRDetails = req.Capabilities.HDRDetails
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 || !result.Plan.Claims.Video.DolbyVision {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.Plan.RequestedMediaFileID != file.ID || result.Plan.EffectiveMediaFileID != file.ID {
t.Fatalf("source ids = requested %d effective %d", result.Plan.RequestedMediaFileID, result.Plan.EffectiveMediaFileID)
}
}
func TestPlanPlaybackV3RejectsTrulyIncompleteVideoMetadata(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].BitDepth = 0
file.VideoTracks[0].PixelFormat = ""
file.VideoTracks[0].Profile = ""
req := validStartRequestV3()
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Terminal == nil || result.Terminal.Reason != "source_metadata_incomplete" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestPlanPlaybackV3TranscodesVP9WithUnknownCodecLevel(t *testing.T) {
file := detailedFixtureFileV3()
file.CodecVideo = "vp9"
file.CodecAudio = "opus"
file.Resolution = "2160p"
file.Bitrate = 2_797
file.VideoTracks[0] = models.VideoTrack{
Codec: "vp9", Profile: "Profile 0", Level: -99,
Width: 1080, Height: 1920, FrameRate: "24.000", Bitrate: 2_797,
BitDepth: 8, PixelFormat: "yuv420p", VideoRange: "SDR",
VideoRangeType: "SDR", ColorRange: "tv", ColorTransfer: "bt709",
}
file.AudioTracks[0] = models.AudioTrack{Codec: "opus", Channels: 2, Layout: "stereo"}
// An exact client that constrains VP9 levels must not earn a direct route
// from the unknown ffprobe sentinel. The level is optional for planning a
// server transcode, but it cannot satisfy a concrete decoder bound.
source := SourceDescriptorFromFileV3(file, 0)
exact := validStartRequestV3()
exact.Capabilities.CodecsVideo = []string{"vp9"}
exact.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{
Codec: "vp9", Profiles: []string{"profile 0"}, Levels: []int{41},
BitDepths: []int{8}, MaxWidth: 3840, MaxHeight: 2160, Hardware: true,
}}
if direct, _ := videoEligibleV3(source, exact); direct {
t.Fatal("an unknown VP9 level satisfied an exact decoder level bound")
}
// Empty exact-tier bounds are an affirmative claim that every variant is
// supported, not missing evidence. Keep this distinct from the concrete
// level constraint above so relaxing transcode metadata requirements cannot
// accidentally weaken a bound the client actually supplied.
unconstrained := exact
unconstrained.Capabilities.VideoDecode[0].Profiles = nil
unconstrained.Capabilities.VideoDecode[0].Levels = nil
if direct, _ := videoEligibleV3(source, unconstrained); !direct {
t.Fatal("an exact decoder's explicitly unconstrained profile/level claim was rejected")
}
req := validStartRequestV3()
req.Capabilities.VideoEvidence = EvidencePlatformAttestedV3
req.Capabilities.AudioEvidence = EvidencePlatformAttestedV3
result := PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3(),
})
if result.Plan == nil || result.Plan.Delivery != DeliveryTranscodeHLSV3 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.TargetVideoCodec != "h264" || result.TargetAudioCodec != "aac" {
t.Fatalf("targets = video %q audio %q", result.TargetVideoCodec, result.TargetAudioCodec)
}
}
func TestPlanPlaybackV3BlocksUltrawide4KTranscode(t *testing.T) {
file := detailedFixtureFileV3()
file.Resolution = "2160p"
file.VideoTracks[0].Width = 3840
file.VideoTracks[0].Height = 1626
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].ColorTransfer = "bt709"
req := validStartRequestV3()
req.QualityPreference = "1080p"
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: false}, Registry: testTransformationRegistryV3()})
if result.Terminal == nil || result.Terminal.Reason != "no_alternate_version" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestPlanPlaybackV3Profile7FallsBackToHDR10WithoutNativeP7(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].DVProfile = 7
file.VideoTracks[0].DVBLCompatID = 6
file.VideoTracks[0].DVELPresent = false
file.VideoTracks[0].DVEnhancementLayer = ""
file.VideoTracks[0].VideoRange = "DolbyVision"
file.VideoTracks[0].VideoRangeType = "DOVIWithEL"
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true, DolbyVisionProfiles: []int{5, 8}}
req.ClientPlaybackContext.Output.HDRDetails = req.Capabilities.HDRDetails
registry := NewTransformationRegistryV3([]TransformationSpecV3{{Name: "server_dv7_to_hdr10", Available: true}})
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: registry})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 || !result.Plan.Claims.Video.HDR10 || result.Plan.Claims.Video.DolbyVision {
t.Fatalf("result = %#v", result)
}
if len(result.Plan.Transformations) != 1 || result.Plan.Transformations[0].Name != "server_dv7_to_hdr10" {
t.Fatalf("transformations = %#v", result.Plan.Transformations)
}
}
func TestPlanPlaybackV3Profile7UsesVersionedClientTransformationsOnSameFile(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].DVProfile = 7
file.VideoTracks[0].DVBLCompatID = 1
file.VideoTracks[0].DVELPresent = true
file.VideoTracks[0].DVEnhancementLayer = "unknown"
file.VideoTracks[0].VideoRange = "DolbyVision"
file.VideoTracks[0].VideoRangeType = "DOVIWithEL"
req := validStartRequestV3()
req.ClientFeatures = append(req.ClientFeatures, FeatureClientVideoTransforms)
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true, DolbyVisionProfiles: []int{8}}
req.ClientPlaybackContext.Output.HDRDetails = req.Capabilities.HDRDetails
direct := req.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3]
direct.Transformations = []TransformationV3{
{Name: ClientDV7ToDV81V3, Executor: "client", RecipeVersion: ClientDVTransformVersionV3},
{Name: ClientDV7ToHDR10V3, Executor: "client", RecipeVersion: ClientDVTransformVersionV3},
}
req.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = direct
first := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if first.Plan == nil || first.Plan.Delivery != DeliveryOriginalHTTPV3 || first.Plan.EffectiveMediaFileID != file.ID || first.Plan.DecisionReason != "client_dv7_to_dv81" {
t.Fatalf("first = %#v", first)
}
if got := first.Plan.Transformations; len(got) != 1 || got[0].Name != ClientDV7ToDV81V3 || got[0].Executor != "client" || got[0].RecipeVersion != "1" {
t.Fatalf("first transformations = %#v", got)
}
failedKey := PlanAttemptKeyV3(*first.Plan, req.ClientPlaybackContext.Output.OutputContextID, nil)
second := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3(), AttemptedKeys: []string{failedKey}})
if second.Plan == nil || second.Plan.Delivery != DeliveryOriginalHTTPV3 || second.Plan.EffectiveMediaFileID != file.ID || second.Plan.DecisionReason != "client_dv7_to_hdr10" || !second.Plan.Claims.Video.HDR10 {
t.Fatalf("second = %#v", second)
}
}
func TestPlanPlaybackV3Profile7DoesNotInferClientTransformFromHDRProfile(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].DVProfile = 7
file.VideoTracks[0].VideoRange = "DolbyVision"
file.VideoTracks[0].VideoRangeType = "DOVIWithEL"
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true, DolbyVisionProfiles: []int{7, 8}}
req.ClientPlaybackContext.Output.HDRDetails = req.Capabilities.HDRDetails
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: false}})
if result.Plan != nil && result.Plan.Delivery == DeliveryOriginalHTTPV3 {
t.Fatalf("Profile 7 must not direct-play from codec claims alone: %#v", result.Plan)
}
}
func TestPlanPlaybackV3AudioAdaptationCopiesVideo(t *testing.T) {
file := detailedFixtureFileV3()
file.AudioTracks[0] = models.AudioTrack{Codec: "truehd", Channels: 8, Layout: "7.1"}
file.CodecAudio = "truehd"
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 || !result.TranscodeAudio || result.TargetVideoCodec != "" {
t.Fatalf("result = %#v", result)
}
}
// copyUnsafeFixtureV3 returns an SDR source that would normally take a
// video-copy remux (its audio needs conversion, its container is not offered),
// with the copy-safety flag settable by the caller.
func copyUnsafeFixtureV3(multiPPS bool) (*models.MediaFile, StartRequestV3) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].ColorTransfer = "bt709"
file.AudioTracks[0] = models.AudioTrack{Codec: "truehd", Channels: 8, Layout: "7.1"}
file.CodecAudio = "truehd"
file.VideoTracks[0].MultiplePPS = &multiPPS
req := validStartRequestV3()
req.Capabilities.Containers = []string{"mp4"}
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
return file, req
}
func TestPlanPlaybackV3CopyUnsafeSourceForcesTranscode(t *testing.T) {
// The source carries conflicting in-band PPS, so the video stream-copy remux
// is disqualified and planning must fall through to a real transcode.
file, req := copyUnsafeFixtureV3(true)
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.PlayMethod != PlayTranscode {
t.Fatalf("PlayMethod = %q, want transcode; result = %s", result.PlayMethod, ExplainPlannerResultV3(result))
}
if result.Plan == nil || result.Plan.DecisionReason != "copy_routes_exhausted" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestPlanPlaybackV3CopySafeSourceStillCopies(t *testing.T) {
// The identical source with the copy-safety scan resolved to safe keeps the
// cheap video stream-copy remux.
file, req := copyUnsafeFixtureV3(false)
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 || !result.TranscodeAudio || result.TargetVideoCodec != "" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestPlanPlaybackV3FallsBackFromProgressiveToHLSWithoutRepeatingKey(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].ColorTransfer = "bt709"
req := validStartRequestV3()
req.Capabilities.Containers = []string{"mp4"}
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
first := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}})
if first.Plan == nil || first.Plan.Delivery != DeliveryRemuxProgressiveV3 {
t.Fatalf("first = %s", ExplainPlannerResultV3(first))
}
failedKey := PlanAttemptKeyV3(*first.Plan, req.ClientPlaybackContext.Output.OutputContextID, nil)
second := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, AttemptedKeys: []string{failedKey}})
if second.Plan == nil || second.Plan.Delivery != DeliveryRemuxHLSV3 || second.TargetVideoCodec != "copy" {
t.Fatalf("second = %#v", second)
}
secondKey := PlanAttemptKeyV3(*second.Plan, req.ClientPlaybackContext.Output.OutputContextID, nil)
third := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3(), AttemptedKeys: []string{failedKey, secondKey}})
if third.Plan == nil || third.Plan.Delivery != DeliveryTranscodeHLSV3 || third.Plan.DecisionReason != "copy_routes_exhausted" {
t.Fatalf("third = %#v", third)
}
}
// pgsBurnRequestV3 selects the single embedded PGS track on a client that
// cannot render bitmap subtitles anywhere, so every route but a burn-in
// transcode is closed by the subtitle alone.
func pgsBurnRequestV3(file *models.MediaFile) StartRequestV3 {
file.SubtitleTracks = []models.SubtitleTrack{{Index: 0, Codec: "hdmv_pgs_subtitle"}}
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
req.ClientPlaybackContext.Output.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
selected := 0
req.SubtitleTrackIndex = &selected
req.SubtitleTrackID = TrackIDV3(file.ID, "subtitle", selected)
return req
}
// A user who just picked a bitmap subtitle can undo that choice; an HDR or 4K
// reason points them at a problem that is not blocking them.
func TestPlanPlaybackV3NamesTheSubtitleWhenItAloneForcedTheTranscode(t *testing.T) {
file := detailedFixtureFileV3()
req := pgsBurnRequestV3(file)
result := PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true},
})
if result.Terminal == nil || result.Terminal.Reason != "subtitle_conversion_unsupported" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if !strings.Contains(strings.ToLower(result.Terminal.Message), "subtitle") {
t.Errorf("terminal message = %q, want the subtitle named", result.Terminal.Message)
}
}
// The subtitle only owns the terminal when it is the sole blocker: a client
// that cannot take the source range at all still gets the range cause.
func TestPlanPlaybackV3KeepsTheHDRTerminalWhenTheRangeIsAlsoUnsupported(t *testing.T) {
file := detailedFixtureFileV3()
req := pgsBurnRequestV3(file)
req.Capabilities.HDRDetails = nil
req.ClientPlaybackContext.Output.HDRDetails = nil
result := PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true},
})
if result.Terminal == nil || result.Terminal.Reason != "hdr_transcode_unsupported" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
// With transcoding disabled, the subtitle policy itself terminals a bitmap
// selection (burn-in is never offered), so the reason names the subtitle
// before the planner ever weighs range or quality causes. The selection is
// genuinely undeliverable, so that attribution is accurate for every cause mix.
func TestPlanPlaybackV3DisabledTranscodeStillNamesAnUndeliverableSubtitle(t *testing.T) {
file := detailedFixtureFileV3()
req := pgsBurnRequestV3(file)
req.Capabilities.HDRDetails = nil
req.ClientPlaybackContext.Output.HDRDetails = nil
result := PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, AudioTrackIndex: 0,
EffectiveFile: file,
Settings: PlannerSettingsV3{TranscodeEnabled: false, Allow4KTranscode: true},
})
if result.Terminal == nil || result.Terminal.Reason != "subtitle_conversion_unsupported" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestPlanPlaybackV3NamesTheSubtitleOverThe4KPolicy(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].ColorTransfer = "bt709"
req := pgsBurnRequestV3(file)
result := PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: false},
})
if result.Terminal == nil || result.Terminal.Reason != "subtitle_conversion_unsupported" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if !strings.Contains(strings.ToLower(result.Terminal.Message), "subtitle") {
t.Errorf("terminal message = %q, want the subtitle named", result.Terminal.Message)
}
}
func TestPlanPlaybackV3NeverClaimsUnimplementedHDRTranscode(t *testing.T) {
file := detailedFixtureFileV3()
req := validStartRequestV3()
req.QualityPreference = "1080p"
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}})
if result.Terminal == nil || result.Terminal.Reason != "hdr_transcode_unsupported" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestPlanPlaybackV3ReportsHDRLimitationBefore4KPolicy(t *testing.T) {
file := detailedFixtureFileV3()
file.Resolution = "2160p"
file.VideoTracks[0].Width = 3840
file.VideoTracks[0].Height = 2160
req := validStartRequestV3()
req.Capabilities.HDRDetails = nil
req.ClientPlaybackContext.Output.HDRDetails = nil
result := PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: false},
})
if result.Terminal == nil || result.Terminal.Reason != "hdr_transcode_unsupported" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestPlanPlaybackV3HonorsDolbyVisionLevelBound(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "DolbyVision"
file.VideoTracks[0].VideoRangeType = "DOVIWithHDR10"
file.VideoTracks[0].DVProfile = 8
file.VideoTracks[0].DVLevel = 7
file.VideoTracks[0].DVBLCompatID = 1
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{
Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10},
MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true,
}}
hdr := &HDRCapabilitiesV3{
DolbyVisionProfiles: []int{8},
DolbyVisionProfileLevels: []DolbyVisionProfileCapabilityV3{{
Profile: 8, MaxLevel: 6, BLCompatibilityIDs: []int{1},
}},
}
req.Capabilities.HDRDetails = hdr
req.ClientPlaybackContext.Output.HDRDetails = hdr
result := PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true},
})
if result.Terminal == nil || result.Terminal.Reason != "hdr_transcode_unsupported" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
file.VideoTracks[0].DVLevel = 6
result = PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true},
})
if result.Plan == nil || !result.Plan.Claims.Video.DolbyVision {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
file.VideoTracks[0].DVBLCompatID = 4
result = PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true},
})
if result.Terminal == nil || result.Terminal.Reason != "hdr_transcode_unsupported" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestSourceDescriptorV3OmitsInvalidDolbyVisionLevel(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].DVLevel = 14
if got := SourceDescriptorFromFileV3(file, 0).DVLevel; got != 0 {
t.Fatalf("DVLevel = %d, want omitted", got)
}
}
func TestPlanPlaybackV3Profile7StripFallsBackToValidatedHLSCopy(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].DVProfile = 7
file.VideoTracks[0].DVBLCompatID = 1
file.VideoTracks[0].DVELPresent = true
file.VideoTracks[0].DVEnhancementLayer = "mel"
file.VideoTracks[0].VideoRange = "DolbyVision"
file.VideoTracks[0].VideoRangeType = "DOVIWithEL"
req := validStartRequestV3()
req.Capabilities.Containers = []string{"mp4"}
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true, DolbyVisionProfiles: []int{7}}
registry := NewTransformationRegistryV3([]TransformationSpecV3{{Name: "server_dv7_to_hdr10", Available: true}})
first := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: registry})
if first.Plan == nil || first.Plan.Delivery != DeliveryRemuxProgressiveV3 || len(first.Plan.Transformations) != 1 {
t.Fatalf("first = %#v", first)
}
failedKey := PlanAttemptKeyV3(*first.Plan, req.ClientPlaybackContext.Output.OutputContextID, nil)
second := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: registry, AttemptedKeys: []string{failedKey}})
if second.Plan == nil || second.Plan.Delivery != DeliveryRemuxHLSV3 || second.TargetVideoCodec != "copy" || len(second.Plan.Transformations) != 1 || second.Plan.Transformations[0].Name != "server_dv7_to_hdr10" {
t.Fatalf("second = %#v", second)
}
}
func TestPlanPlaybackV3Profile8CompatibleBaseLayerStripsToHDR10(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].DVProfile = 8
file.VideoTracks[0].DVBLCompatID = 1
file.VideoTracks[0].VideoRange = "DolbyVision"
file.VideoTracks[0].VideoRangeType = "DOVI"
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
registry := NewTransformationRegistryV3([]TransformationSpecV3{{Name: "server_dv7_to_hdr10", Available: true}})
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: registry})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 || result.Plan.EffectiveRecipe.DynamicRange != "hdr10" || len(result.Plan.Transformations) != 1 || result.Plan.Transformations[0].Name != "server_dv7_to_hdr10" {
t.Fatalf("result = %#v", result)
}
}
func TestPlanPlaybackV3PassthroughRequiresExactLayoutEntry(t *testing.T) {
file := detailedFixtureFileV3()
file.CodecAudio = "truehd"
file.AudioTracks[0] = models.AudioTrack{Codec: "truehd", Channels: 8, Layout: "7.1"}
req := validStartRequestV3()
req.ClientFeatures = append(req.ClientFeatures, FeatureLayoutPassthrough)
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
req.Capabilities.AudioPassthrough = &AudioPassthroughV3{PassthroughCodecs: []string{"truehd"}, MaxChannels: 8, Entries: []AudioPassthroughEntryV3{{Codec: "truehd"}}}
withoutLayout := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if withoutLayout.Plan == nil || !withoutLayout.TranscodeAudio {
t.Fatalf("without exact layout = %#v", withoutLayout)
}
req.Capabilities.AudioPassthrough.Entries[0].ChannelCounts = []int{8}
req.Capabilities.AudioPassthrough.Entries[0].Layouts = []string{"7.1"}
withLayout := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}})
if withLayout.Plan == nil || withLayout.Plan.Delivery != DeliveryOriginalHTTPV3 || !withLayout.Plan.Claims.Audio.Passthrough {
t.Fatalf("with exact layout = %#v", withLayout)
}
}
func TestPlanPlaybackV3DownloadedSubtitleCarriesStableIdentity(t *testing.T) {
file := detailedFixtureFileV3()
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
index := 0
req.SubtitleTrackIndex = &index
req.SubtitleTrackID = TrackIDV3(file.ID, "subtitle", index)
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, AdditionalSubtitles: []SubtitleInventoryEntryV3{{CombinedIndex: 0, Codec: "srt", Source: "downloaded", DownloadedSubtitleID: 71}}})
if result.Plan == nil || result.Plan.Subtitle.Mode != SubtitleRenderV3 || result.Plan.SelectedTracks.Subtitle == nil || result.Plan.SelectedTracks.Subtitle.ID != req.SubtitleTrackID || result.DownloadedSubtitleID != 71 {
t.Fatalf("result = %#v", result)
}
}
// The plan carries the whole ordinal space, so a client never has to rebuild it
// from the track arrays it happens to be able to render.
func TestPlanPlaybackV3PublishesTheCompleteSubtitleInventory(t *testing.T) {
file := detailedFixtureFileV3()
file.ExternalSubtitles = []models.ExternalSubtitle{{Path: "/media/movie.en.srt", Language: "en", Format: "srt"}}
file.SubtitleTracks = []models.SubtitleTrack{
{Index: 0, Language: "ja", Codec: "hdmv_pgs_subtitle"},
{Index: 1, Language: "de", Codec: "dvd_subtitle"},
}
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
additional := []SubtitleInventoryEntryV3{{CombinedIndex: 3, Codec: "srt", Source: SubtitleSourceDownloadedV3, Language: "es"}}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, AdditionalSubtitles: additional})
if result.Plan == nil {
t.Fatalf("result = %#v, want a plan", result)
}
inventory := result.Plan.Subtitle.Inventory
if len(inventory) != 4 {
t.Fatalf("inventory = %+v, want 4 entries (1 external + 2 embedded + 1 downloaded)", inventory)
}
for i, item := range inventory {
if item.CombinedIndex != i {
t.Errorf("entry %d has combined_index %d; the published space must be dense", i, item.CombinedIndex)
}
}
// The burn-in-only track is present with no URL rather than dropped.
if inventory[2].Delivery != SubtitleDeliveryBurnInOnlyV3 || inventory[2].URL != "" {
t.Errorf("the DVD track should be published as burn-in only with no URL, got %+v", inventory[2])
}
if inventory[3].Source != SubtitleSourceDownloadedV3 {
t.Errorf("the downloaded track should hold the last ordinal, got %+v", inventory[3])
}
}
func TestPlanPlaybackV3AdaptedRoutesPreservePGSCombinedInventory(t *testing.T) {
file := detailedFixtureFileV3()
for range 8 {
file.ExternalSubtitles = append(file.ExternalSubtitles, models.ExternalSubtitle{Format: "srt"})
}
// The scanner index is the absolute probed stream index. The client-facing
// combined ordinal is 8, while ffmpeg addresses this first embedded
// subtitle as 0:s:0 (transport index 0).
file.SubtitleTracks = []models.SubtitleTrack{{Index: 4, Codec: "hdmv_pgs_subtitle"}}
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
req.ClientPlaybackContext.Output.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
for _, deliveryClass := range []string{DeliveryClassOriginalHTTPV3, DeliveryClassProgressiveV3, DeliveryClassHLSV3} {
delivery := req.ClientPlaybackContext.Deliveries[deliveryClass]
delivery.Subtitles.EmbeddedBitmap = true
req.ClientPlaybackContext.Deliveries[deliveryClass] = delivery
}
selectedIndex := 8
req.SubtitleTrackIndex = &selectedIndex
req.SubtitleTrackID = TrackIDV3(file.ID, "subtitle", selectedIndex)
input := PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3(),
}
direct := PlanPlaybackV3(input)
if direct.Plan == nil || direct.Plan.Delivery != DeliveryOriginalHTTPV3 {
t.Fatalf("direct plan = %#v", direct)
}
input.AttemptedKeys = []string{PlanAttemptKeyV3(*direct.Plan, req.ClientPlaybackContext.Output.OutputContextID, nil)}
progressive := PlanPlaybackV3(input)
if progressive.Plan == nil || progressive.Plan.Delivery != DeliveryRemuxProgressiveV3 {
t.Fatalf("progressive fallback = %#v", progressive)
}
input.AttemptedKeys = append(input.AttemptedKeys, PlanAttemptKeyV3(*progressive.Plan, req.ClientPlaybackContext.Output.OutputContextID, nil))
hls := PlanPlaybackV3(input)
if hls.Plan == nil || hls.Plan.Delivery != DeliveryRemuxHLSV3 {
t.Fatalf("HLS fallback = %#v", hls)
}
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].ColorTransfer = "bt709"
input.Request.QualityPreference = "1080p"
input.AttemptedKeys = nil
transcode := PlanPlaybackV3(input)
if transcode.Plan == nil || transcode.Plan.Delivery != DeliveryTranscodeHLSV3 {
t.Fatalf("transcode route = %#v", transcode)
}
for name, result := range map[string]PlannerResultV3{"progressive": progressive, "HLS": hls, "transcode": transcode} {
if result.SubtitleTrackIndex != selectedIndex || result.SubtitleTransportTrackIndex != 0 {
t.Errorf("%s subtitle selection = combined %d / transport %d, want 8 / 0", name, result.SubtitleTrackIndex, result.SubtitleTransportTrackIndex)
}
inventory := result.Plan.Subtitle.Inventory
if len(inventory) != 9 {
t.Errorf("%s inventory = %+v, want all 9 combined ordinals", name, inventory)
continue
}
selected := inventory[selectedIndex]
if selected.CombinedIndex != selectedIndex || selected.TrackID != req.SubtitleTrackID || selected.Source != SubtitleSourceEmbeddedV3 || selected.Codec != "hdmv_pgs_subtitle" || selected.Delivery != SubtitleDeliverySidecarV3 {
t.Errorf("%s selected inventory entry = %+v", name, selected)
}
}
}
// Adding the inventory to the plan must not perturb plan identity: replans
// would otherwise miss the cache and clients would see spurious new attempts.
func TestPlanAttemptKeyV3IgnoresTheSubtitleInventory(t *testing.T) {
file := detailedFixtureFileV3()
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}})
if result.Plan == nil {
t.Fatalf("result = %#v, want a plan", result)
}
before := PlanAttemptKeyV3(*result.Plan, "output-1", nil)
withInventory := *result.Plan
withInventory.Subtitle.Inventory = []SubtitleInventoryItemV3{{TrackID: "file:42:subtitle:0", CombinedIndex: 0, Source: SubtitleSourceEmbeddedV3, Codec: "subrip", Delivery: SubtitleDeliverySidecarV3}}
if after := PlanAttemptKeyV3(withInventory, "output-1", nil); after != before {
t.Errorf("attempt key changed with the inventory attached: %q -> %q", before, after)
}
}
func TestSubtitleBurnInUsesEmbeddedOrdinalAndRejectsUnsupportedSources(t *testing.T) {
file := detailedFixtureFileV3()
file.ExternalSubtitles = []models.ExternalSubtitle{{Format: "ass"}}
file.SubtitleTracks = []models.SubtitleTrack{{Codec: "hdmv_pgs_subtitle"}}
req := validStartRequestV3()
embeddedCombinedIndex := 1
req.SubtitleTrackIndex = &embeddedCombinedIndex
req.SubtitleTrackID = TrackIDV3(file.ID, "subtitle", embeddedCombinedIndex)
result := ResolveSubtitlePolicyV3(file, req, true, DeliveryClassOriginalHTTPV3, nil)
if !result.RequiresBurn || result.SelectedIndex != 1 || result.TransportIndex != 0 {
t.Fatalf("embedded burn-in result = %#v", result)
}
externalIndex := 0
req.SubtitleTrackIndex = &externalIndex
req.SubtitleTrackID = TrackIDV3(file.ID, "subtitle", externalIndex)
req.SubtitleFidelityPreference = SubtitleFidelityPreserveV3
result = ResolveSubtitlePolicyV3(file, req, true, DeliveryClassOriginalHTTPV3, nil)
if result.Terminal == nil || result.Terminal.Reason != "subtitle_burn_in_source_unsupported" {
t.Fatalf("external burn-in result = %#v", result)
}
}
func TestResolveQualityPolicyV3HonorsBandwidthCapInAllModes(t *testing.T) {
source := SourceDescriptorV3{Width: 3840, Height: 2160, BitrateKbps: 20_000}
cap := 5_000
req := validStartRequestV3()
req.QualityPreference = "original"
req.BandwidthCapKbps = &cap
result := ResolveQualityPolicyV3(req, source)
if !result.RequiresTranscode || result.Height != 720 || result.Reason != "quality_bandwidth_cap" || result.ExplicitRung {
t.Fatalf("original over cap = %#v", result)
}
if !hasDegradationWarningV3(result.Warnings, "bandwidth_cap_applied") {
t.Fatalf("missing cap warning: %#v", result.Warnings)
}
lowBitrateSource := SourceDescriptorV3{Width: 1920, Height: 1080, BitrateKbps: 4_000}
result = ResolveQualityPolicyV3(req, lowBitrateSource)
if !result.PreservesSource || result.RequiresTranscode || len(result.Warnings) != 0 {
t.Fatalf("original under cap = %#v", result)
}
req.QualityPreference = "1080p"
result = ResolveQualityPolicyV3(req, source)
if result.Height != 720 || result.Reason != "quality_bandwidth_cap" || !result.ExplicitRung || !result.RequiresTranscode {
t.Fatalf("fixed rung over cap = %#v", result)
}
if !hasDegradationWarningV3(result.Warnings, "bandwidth_cap_applied") {
t.Fatalf("missing cap warning: %#v", result.Warnings)
}
req.QualityPreference = "480p"
result = ResolveQualityPolicyV3(req, source)
if result.Height != 480 || result.Reason != "quality_fixed_rung" || hasDegradationWarningV3(result.Warnings, "bandwidth_cap_applied") {
t.Fatalf("fixed rung under cap = %#v", result)
}
req.QualityPreference = "auto"
result = ResolveQualityPolicyV3(req, source)
if !result.RequiresTranscode || result.Height != 720 || result.PreservesSource {
t.Fatalf("auto with cap = %#v", result)
}
}
func TestResolveQualityPolicyV3MeteredWithoutEvidencePrefersConservativeRung(t *testing.T) {
source := SourceDescriptorV3{Width: 3840, Height: 2160, BitrateKbps: 20_000}
req := validStartRequestV3()
req.QualityPreference = "auto"
req.Metered = true
result := ResolveQualityPolicyV3(req, source)
if result.Height != 720 || !result.RequiresTranscode || result.Reason != "quality_metered_limit" || result.ExplicitRung {
t.Fatalf("metered auto = %#v", result)
}
estimate := 30_000
req.BandwidthEstimateKbps = &estimate
result = ResolveQualityPolicyV3(req, source)
if !result.PreservesSource || result.Reason != "quality_bandwidth_limit" {
t.Fatalf("metered with estimate = %#v", result)
}
req.BandwidthEstimateKbps = nil
req.Metered = false
result = ResolveQualityPolicyV3(req, source)
if !result.PreservesSource || result.RequiresTranscode {
t.Fatalf("unmetered auto = %#v", result)
}
}
func TestPlanPlaybackV3HDRDeviceCapFallsBackToOriginalQuality(t *testing.T) {
file := detailedFixtureFileV3()
req := validStartRequestV3()
req.QualityPreference = "auto"
req.Capabilities.MaxResolution = "1080p"
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
req.ClientPlaybackContext.Output.HDRDetails = req.Capabilities.HDRDetails
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 || !result.Plan.Claims.Video.HDR10 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.Plan.EffectiveRecipe.Height == nil || *result.Plan.EffectiveRecipe.Height != 2160 {
t.Fatalf("recipe = %#v", result.Plan.EffectiveRecipe)
}
if !hasDegradationWarningV3(result.Plan.DegradationWarnings, "quality_reduction_unavailable") {
t.Fatalf("warnings = %#v", result.Plan.DegradationWarnings)
}
}
func TestPlanPlaybackV3HDRBandwidthCapFallsBackToOriginalQuality(t *testing.T) {
file := detailedFixtureFileV3()
req := validStartRequestV3()
req.QualityPreference = "auto"
cap := 5_000
req.BandwidthCapKbps = &cap
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
req.ClientPlaybackContext.Output.HDRDetails = req.Capabilities.HDRDetails
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 || !result.Plan.Claims.Video.HDR10 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if !hasDegradationWarningV3(result.Plan.DegradationWarnings, "quality_reduction_unavailable") {
t.Fatalf("warnings = %#v", result.Plan.DegradationWarnings)
}
}
func TestPlanPlaybackV3CapWithoutTranscodeRouteFallsBackToOriginal(t *testing.T) {
file := detailedFixtureFileV3()
file.Resolution = "1080p"
file.VideoTracks[0].Width = 1920
file.VideoTracks[0].Height = 1080
file.VideoTracks[0].Bitrate = 8_000
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].ColorTransfer = "bt709"
req := validStartRequestV3()
req.QualityPreference = "original"
cap := 4_000
req.BandwidthCapKbps = &cap
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
// The client has no HLS engine, so the cap-induced transcode cannot run.
delete(req.ClientPlaybackContext.Deliveries, DeliveryClassHLSV3)
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if !hasDegradationWarningV3(result.Plan.DegradationWarnings, "quality_reduction_unavailable") {
t.Fatalf("warnings = %#v", result.Plan.DegradationWarnings)
}
}
func TestPlanPlaybackV3LegacyHDRUnknownAssumesHDR10ForCapableClients(t *testing.T) {
file := detailedFixtureFileV3()
file.HDR = true
file.VideoTracks[0].VideoRange = ""
file.VideoTracks[0].VideoRangeType = ""
file.VideoTracks[0].ColorTransfer = ""
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true}
req.ClientPlaybackContext.Output.HDRDetails = req.Capabilities.HDRDetails
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 || !result.Plan.Claims.Video.HDR10 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if !hasDegradationWarningV3(result.Plan.DegradationWarnings, "hdr_range_assumed_hdr10") {
t.Fatalf("warnings = %#v", result.Plan.DegradationWarnings)
}
// Without HDR10 output support the legacy row keeps the previous
// (ineligible) behavior instead of guessing at the client's range.
req.Capabilities.HDRDetails = nil
req.ClientPlaybackContext.Output.HDRDetails = nil
result = PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Terminal == nil || result.Terminal.Reason != "hdr_transcode_unsupported" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestSourceDescriptorV3NormalizesLegacyFileBitrateFallback(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].Bitrate = 0
file.Bitrate = 60_000_000 // legacy rows stored bps
source := SourceDescriptorFromFileV3(file, 0)
if source.BitrateKbps != 60_000 {
t.Fatalf("file-level bitrate = %d, want normalized 60000", source.BitrateKbps)
}
file.VideoTracks[0].Bitrate = 45_000_000
source = SourceDescriptorFromFileV3(file, 0)
if source.BitrateKbps != 45_000 {
t.Fatalf("track-level bitrate = %d, want normalized 45000", source.BitrateKbps)
}
}
func TestPlanAttemptedV3RequiresExactKeyMatch(t *testing.T) {
plan := PlanV3{PlanID: "plan:exact", Delivery: DeliveryOriginalHTTPV3, Stream: StreamV3{Protocol: StreamHTTPProgressiveV3, Container: "mkv"}, Subtitle: SubtitleDecisionV3{Mode: SubtitleOffV3}}
key := PlanAttemptKeyV3(plan, "1", nil)
if !planAttemptedV3(plan, "1", []string{" " + key + " "}) {
t.Fatal("whitespace-trimmed exact key must match")
}
if planAttemptedV3(plan, "1", []string{strings.ToUpper(key)}) {
t.Fatal("case-folded attempt key must not match an exact hash")
}
}
func TestStartRequestV3ValidationBoundsInnerLists(t *testing.T) {
longValue := strings.Repeat("x", 65)
cases := []struct {
name string
mutate func(*StartRequestV3)
}{
{"video_decode_profile_count", func(r *StartRequestV3) {
r.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "h264", Hardware: true, Profiles: make([]string, 65)}}
}},
{"video_decode_profile_length", func(r *StartRequestV3) {
r.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "h264", Hardware: true, Profiles: []string{longValue}}}
}},
{"video_decode_level_count", func(r *StartRequestV3) {
r.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "h264", Hardware: true, Levels: make([]int, 65)}}
}},
{"video_decode_bit_depth_count", func(r *StartRequestV3) {
r.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "h264", Hardware: true, BitDepths: make([]int, 65)}}
}},
{"capability_dolby_vision_profiles", func(r *StartRequestV3) {
r.Capabilities.HDRDetails = &HDRCapabilitiesV3{DolbyVisionProfiles: make([]int, 17)}
}},
{"output_dolby_vision_profiles", func(r *StartRequestV3) {
r.ClientPlaybackContext.Output.HDRDetails = &HDRCapabilitiesV3{DolbyVisionProfiles: make([]int, 17)}
}},
{"delivery_dolby_vision_profiles", func(r *StartRequestV3) {
delivery := r.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3]
delivery.HDRDetails = &HDRCapabilitiesV3{DolbyVisionProfiles: make([]int, 17)}
r.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = delivery
}},
{"capability_dolby_vision_profile_levels", func(r *StartRequestV3) {
r.Capabilities.HDRDetails = &HDRCapabilitiesV3{DolbyVisionProfileLevels: make([]DolbyVisionProfileCapabilityV3, 17)}
}},
{"invalid_dolby_vision_profile_level", func(r *StartRequestV3) {
r.Capabilities.HDRDetails = &HDRCapabilitiesV3{DolbyVisionProfileLevels: []DolbyVisionProfileCapabilityV3{{Profile: 8, MaxLevel: 14}}}
}},
{"duplicate_dolby_vision_profile_level", func(r *StartRequestV3) {
r.Capabilities.HDRDetails = &HDRCapabilitiesV3{DolbyVisionProfileLevels: []DolbyVisionProfileCapabilityV3{{Profile: 8, MaxLevel: 6}, {Profile: 8, MaxLevel: 7}}}
}},
{"dolby_vision_bl_compatibility_count", func(r *StartRequestV3) {
r.Capabilities.HDRDetails = &HDRCapabilitiesV3{DolbyVisionProfileLevels: []DolbyVisionProfileCapabilityV3{{Profile: 8, MaxLevel: 6, BLCompatibilityIDs: make([]int, 17)}}}
}},
{"invalid_dolby_vision_bl_compatibility_id", func(r *StartRequestV3) {
r.Capabilities.HDRDetails = &HDRCapabilitiesV3{DolbyVisionProfileLevels: []DolbyVisionProfileCapabilityV3{{Profile: 8, MaxLevel: 6, BLCompatibilityIDs: []int{16}}}}
}},
{"duplicate_dolby_vision_bl_compatibility_id", func(r *StartRequestV3) {
r.Capabilities.HDRDetails = &HDRCapabilitiesV3{DolbyVisionProfileLevels: []DolbyVisionProfileCapabilityV3{{Profile: 8, MaxLevel: 6, BLCompatibilityIDs: []int{1, 1}}}}
}},
{"delivery_container_length", func(r *StartRequestV3) {
delivery := r.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3]
delivery.Containers = []string{longValue}
r.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = delivery
}},
{"delivery_validated_claim_length", func(r *StartRequestV3) {
delivery := r.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3]
delivery.ValidatedClaims = []string{longValue}
r.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = delivery
}},
{"delivery_feature_length", func(r *StartRequestV3) {
delivery := r.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3]
delivery.Features = []string{longValue}
r.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = delivery
}},
{"audio_track_id_length", func(r *StartRequestV3) {
r.AudioTrackID = strings.Repeat("a", 129)
}},
{"subtitle_track_id_length", func(r *StartRequestV3) {
r.SubtitleTrackID = strings.Repeat("s", 129)
}},
}
for _, value := range cases {
t.Run(value.name, func(t *testing.T) {
req := validStartRequestV3()
value.mutate(&req)
if _, err := req.NormalizeAndValidate(); err == nil {
t.Fatal("oversized capability accepted")
}
})
}
}
func TestResolveQualityPolicyV3PreservesNonStandardSourceHeight(t *testing.T) {
req := validStartRequestV3()
req.QualityPreference = "auto"
result := ResolveQualityPolicyV3(req, SourceDescriptorV3{Width: 2560, Height: 1440, BitrateKbps: 12_000})
if !result.PreservesSource || result.RequiresTranscode || result.Width != 2560 || result.Height != 1440 || result.Label != "1440p" {
t.Fatalf("quality result = %#v", result)
}
}
func TestPlanPlaybackV3SeekedHLSCopyPreservesVideo(t *testing.T) {
file := detailedFixtureFileV3()
file.Resolution = "1080p"
file.VideoTracks[0].Width = 1920
file.VideoTracks[0].Height = 1080
file.VideoTracks[0].BitDepth = 8
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].ColorTransfer = "bt709"
req := validStartRequestV3()
start := 20.0
req.StartPosition = &start
req.Capabilities.Containers = []string{"mp4"}
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{8}, MaxWidth: 1920, MaxHeight: 1080, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = DeliveryCapabilityV3{}
req.ClientPlaybackContext.Deliveries[DeliveryClassProgressiveV3] = DeliveryCapabilityV3{}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxHLSV3 || result.TargetVideoCodec != "copy" || result.Plan.Timeline.SourceStartSeconds != start {
t.Fatalf("result = %#v", result)
}
}
func TestPlanPlaybackV3TimelineChangePreservesRouteIdentity(t *testing.T) {
file := detailedFixtureFileV3()
request := validStartRequestV3()
request.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
hdr := &HDRCapabilitiesV3{HDR10: true}
request.Capabilities.HDR = true
request.Capabilities.HDRDetails = hdr
request.ClientPlaybackContext.Output.HDRDetails = hdr
startAtZero := 0.0
request.StartPosition = &startAtZero
first := PlanPlaybackV3(PlannerInputV3{
Request: request, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3(),
})
if first.Plan == nil {
t.Fatalf("initial plan = %#v", first)
}
startAtSeek := 321.25
request.StartPosition = &startAtSeek
second := PlanPlaybackV3(PlannerInputV3{
Request: request, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3(),
})
if second.Plan == nil {
t.Fatalf("seeked plan = %#v", second)
}
if first.Plan.PlanID != second.Plan.PlanID ||
PlanAttemptKeyV3(*first.Plan, request.ClientPlaybackContext.Output.OutputContextID, nil) != PlanAttemptKeyV3(*second.Plan, request.ClientPlaybackContext.Output.OutputContextID, nil) {
t.Fatalf("timeline changed route identity: first=%#v second=%#v", first.Plan, second.Plan)
}
if first.Plan.PlanAttemptKey == "" || first.Plan.PlanAttemptKey != PlanAttemptKeyV3(*first.Plan, request.ClientPlaybackContext.Output.OutputContextID, nil) {
t.Fatalf("plan attempt key not carried on the plan: %q", first.Plan.PlanAttemptKey)
}
if first.Plan.Timeline.SourceStartSeconds != 0 || second.Plan.Timeline.SourceStartSeconds != startAtSeek {
t.Fatalf("timeline positions: first=%#v second=%#v", first.Plan.Timeline, second.Plan.Timeline)
}
}
func TestPlanPlaybackV3DroppingFallbackHistoryReintroducesRejectedRoute(t *testing.T) {
file := detailedFixtureFileV3()
file.FilePath = "/media/movie.mp4"
file.Container = "mp4"
file.CodecVideo = "h264"
file.Resolution = "1080p"
file.Bitrate = 8_000
file.VideoTracks[0] = models.VideoTrack{Codec: "h264", Profile: "high", Level: 41, Width: 1920, Height: 1080, FrameRate: "24000/1001", Bitrate: 8_000, BitDepth: 8, VideoRange: "SDR", VideoRangeType: "SDR"}
request := validStartRequestV3()
request.Capabilities.CodecsVideo = []string{"h264"}
request.Capabilities.CodecsVideoHardware = []string{"h264"}
request.Capabilities.Containers = []string{"mp4"}
request.Capabilities.MaxResolution = "1080p"
request.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "h264", Profiles: []string{"high"}, Levels: []int{41}, BitDepths: []int{8}, MaxWidth: 1920, MaxHeight: 1080, MaxFrameRate: 60, MaxBitrateKbps: 20_000, Hardware: true}}
input := PlannerInputV3{
Request: request, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3(),
}
direct := PlanPlaybackV3(input)
if direct.Plan == nil || direct.Plan.Delivery != DeliveryOriginalHTTPV3 {
t.Fatalf("direct plan = %#v", direct)
}
input.AttemptedKeys = []string{PlanAttemptKeyV3(*direct.Plan, request.ClientPlaybackContext.Output.OutputContextID, nil)}
progressive := PlanPlaybackV3(input)
if progressive.Plan == nil || progressive.Plan.Delivery != DeliveryRemuxProgressiveV3 {
t.Fatalf("progressive fallback = %#v", progressive)
}
input.AttemptedKeys = append(input.AttemptedKeys, PlanAttemptKeyV3(*progressive.Plan, request.ClientPlaybackContext.Output.OutputContextID, nil))
hls := PlanPlaybackV3(input)
if hls.Plan == nil || hls.Plan.Delivery != DeliveryRemuxHLSV3 {
t.Fatalf("HLS fallback = %#v", hls)
}
seek := 321.25
input.Request.StartPosition = &seek
input.AttemptedKeys = nil // This is what the old seek-reanchor path did.
replanned := PlanPlaybackV3(input)
if replanned.Plan == nil || replanned.Plan.PlanID != direct.Plan.PlanID || replanned.Plan.PlanID == hls.Plan.PlanID {
t.Fatalf("dropped fallback history did not reproduce identity drift: direct=%#v hls=%#v replanned=%#v", direct.Plan, hls.Plan, replanned.Plan)
}
if replanned.Plan.Delivery != DeliveryOriginalHTTPV3 ||
replanned.Plan.Stream.Protocol != StreamHTTPProgressiveV3 || replanned.Plan.Stream.Container != "mp4" {
t.Fatalf("reintroduced route = %#v", replanned.Plan)
}
}
func TestPlanPlaybackV3AppliesDeliverySpecificCodecAndChannelLimits(t *testing.T) {
file := detailedFixtureFileV3()
file.FilePath = "/media/movie.mp4"
file.Container = "mp4"
file.CodecVideo = "h264"
file.Resolution = "1080p"
file.Bitrate = 8_000
file.AudioChannels = 6
file.VideoTracks[0] = models.VideoTrack{Codec: "h264", Profile: "high", Level: 41, Width: 1920, Height: 1080, FrameRate: "24000/1001", Bitrate: 8_000, BitDepth: 8, VideoRange: "SDR", VideoRangeType: "SDR"}
file.AudioTracks[0] = models.AudioTrack{Codec: "aac", Channels: 6, Layout: "5.1"}
request := validStartRequestV3()
request.Capabilities.CodecsVideo = []string{"h264"}
request.Capabilities.CodecsVideoHardware = []string{"h264"}
request.Capabilities.CodecsAudio = []string{"aac"}
request.Capabilities.Containers = []string{"mp4"}
request.Capabilities.MaxResolution = "1080p"
request.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "h264", Profiles: []string{"high"}, Levels: []int{41}, BitDepths: []int{8}, MaxWidth: 1920, MaxHeight: 1080, MaxFrameRate: 60, MaxBitrateKbps: 20_000, Hardware: true}}
maxStereo := 2
request.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = DeliveryCapabilityV3{
Enabled: true, SupportedOnDevice: true, Containers: []string{"mp4"}, VideoCodecs: []string{"h264"}, AudioDecodeCodecs: []string{"aac"}, MaxChannels: &maxStereo,
}
request.ClientPlaybackContext.Deliveries[DeliveryClassProgressiveV3] = DeliveryCapabilityV3{
Enabled: true, SupportedOnDevice: true, Containers: []string{"mp4"}, VideoCodecs: []string{"h264"}, AudioDecodeCodecs: []string{"aac"},
}
result := PlanPlaybackV3(PlannerInputV3{Request: request, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 {
t.Fatalf("delivery-specific stereo ceiling did not exclude original_http: %#v", result)
}
original := request.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3]
original.MaxChannels = nil
original.AudioDecodeCodecs = []string{"opus"}
request.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = original
result = PlanPlaybackV3(PlannerInputV3{Request: request, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 {
t.Fatalf("delivery-specific audio codec list did not exclude original_http: %#v", result)
}
original.AudioDecodeCodecs = nil
original.AudioPassthroughCodecs = []string{"aac"}
request.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = original
result = PlanPlaybackV3(PlannerInputV3{Request: request, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 {
t.Fatalf("passthrough-only delivery must not claim AAC decode support: %#v", result)
}
}
func TestPlanPlaybackV3AppliesDeliverySpecificHDRDetails(t *testing.T) {
file := detailedFixtureFileV3()
request := validStartRequestV3()
hdr := &HDRCapabilitiesV3{HDR10: true}
request.Capabilities.HDRDetails = hdr
request.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
request.ClientPlaybackContext.Output.HDRDetails = hdr
request.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = DeliveryCapabilityV3{
Enabled: true, SupportedOnDevice: true, Containers: []string{"mkv"}, VideoCodecs: []string{"hevc"}, AudioDecodeCodecs: []string{"aac"}, HDRDetails: &HDRCapabilitiesV3{},
}
request.ClientPlaybackContext.Deliveries[DeliveryClassProgressiveV3] = DeliveryCapabilityV3{
Enabled: true, SupportedOnDevice: true, Containers: []string{"mp4"}, VideoCodecs: []string{"hevc"}, AudioDecodeCodecs: []string{"aac"}, HDRDetails: hdr,
}
result := PlanPlaybackV3(PlannerInputV3{Request: request, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 {
t.Fatalf("delivery-specific HDR override did not exclude original_http: %#v", result)
}
}
func validStartRequestV3() StartRequestV3 {
return StartRequestV3{
ProtocolVersion: ProtocolV3,
ClientFeatures: []string{FeaturePlaybackPlanV3},
FileID: 42,
ProfileID: "profile-1",
PlaybackAttemptID: "attempt-0001",
QualityPreference: "original",
SubtitleFidelityPreference: SubtitleFidelityCompatibleV3,
Capabilities: ClientCodecCapabilitiesV3{VideoEvidence: EvidenceExactV3, AudioEvidence: EvidenceExactV3, CodecsVideo: []string{"hevc"}, CodecsAudio: []string{"aac"}, Containers: []string{"mkv"}, MaxResolution: "2160p"},
ClientPlaybackContext: ClientPlaybackContextV3{ProtocolVersion: ProtocolV3, FormFactor: "tv", AppVersion: "test", Device: DeviceContextV3{Platform: "android", OSVersion: "15"}, Output: OutputContextV3{OutputContextID: "route-1"}, Deliveries: map[string]DeliveryCapabilityV3{
DeliveryClassOriginalHTTPV3: {Enabled: true, SupportedOnDevice: true, Subtitles: DeliverySubtitleCapabilitiesV3{EmbeddedText: true, SidecarText: true}},
DeliveryClassProgressiveV3: {Enabled: true, SupportedOnDevice: true},
DeliveryClassHLSV3: {Enabled: true, SupportedOnDevice: true},
}},
}
}
func detailedFixtureFileV3() *models.MediaFile {
return &models.MediaFile{ID: 42, FilePath: "/media/movie.mkv", Container: "mkv", CodecVideo: "hevc", CodecAudio: "aac", Resolution: "2160p", Bitrate: 60_000, AudioChannels: 2, VideoTracks: []models.VideoTrack{{Codec: "hevc", Profile: "Main 10", Level: 153, Width: 3840, Height: 2160, FrameRate: "24000/1001", Bitrate: 60_000, BitDepth: 10, VideoRange: "HDR", VideoRangeType: "HDR10", ColorRange: "tv"}}, AudioTracks: []models.AudioTrack{{Codec: "aac", Channels: 2, Layout: "stereo"}}}
}
func testTransformationRegistryV3() *TransformationRegistryV3 {
return NewTransformationRegistryV3([]TransformationSpecV3{
{Name: "audio_to_aac", Available: true},
{Name: "video_to_h264", Available: true},
{Name: "server_dv7_to_hdr10", Available: true},
})
}
// A source whose RPU ffmpeg cannot parse must lose the strip in the plan, not
// at the transport. The plan is what promises HDR10, and the durable session's
// RemuxDVMode — re-read by every later restart, seek and audio switch — is
// derived from it, so a plan that still names server_dv7_to_hdr10 puts the
// hanging filter back no matter what the start path did with it. With no
// tone-map recipe in the tree there is no route left for an HDR10-only client,
// and the terminal has to name the real cause.
func TestPlanPlaybackV3AbandonsStripForAnUnstrippableSource(t *testing.T) {
file := unstrippableProfile7FixtureV3()
req := hdr10OnlyProfile7RequestV3()
registry := NewTransformationRegistryV3([]TransformationSpecV3{{Name: "server_dv7_to_hdr10", Available: true}})
input := PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: registry}
// Baseline: with a parseable RPU this is the validated HDR10 remux.
if healthy := PlanPlaybackV3(input); healthy.Plan == nil || len(healthy.Plan.Transformations) != 1 || healthy.Plan.Transformations[0].Name != "server_dv7_to_hdr10" {
t.Fatalf("the strip route regressed for a healthy source: %#v", healthy)
}
input.DVRPUStrippable = func() bool { return false }
result := PlanPlaybackV3(input)
if result.Plan != nil {
t.Fatalf("a source that cannot be stripped was still planned onto a route: %#v", result.Plan)
}
if result.Terminal == nil || result.Terminal.Reason != "dv_conversion_unsupported" {
t.Fatalf("terminal = %#v, want the Dolby Vision cause rather than a generic HDR message", result.Terminal)
}
}
// The strip is a server capability, not the only one: a client that can do the
// conversion itself must still get its route, with the reason the server route
// was dropped attached.
func TestPlanPlaybackV3KeepsTheClientTransformWhenTheSourceCannotBeStripped(t *testing.T) {
file := unstrippableProfile7FixtureV3()
req := hdr10OnlyProfile7RequestV3()
req.ClientFeatures = append(req.ClientFeatures, FeatureClientVideoTransforms)
direct := req.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3]
direct.Transformations = []TransformationV3{{Name: ClientDV7ToHDR10V3, Executor: "client", RecipeVersion: ClientDVTransformVersionV3}}
req.ClientPlaybackContext.Deliveries[DeliveryClassOriginalHTTPV3] = direct
registry := NewTransformationRegistryV3([]TransformationSpecV3{{Name: "server_dv7_to_hdr10", Available: true}})
result := PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: registry,
DVRPUStrippable: func() bool { return false },
})
if result.Plan == nil {
t.Fatalf("terminal = %#v, want the client-side transformation route", result.Terminal)
}
for _, transformation := range result.Plan.Transformations {
if transformation.Name == "server_dv7_to_hdr10" {
t.Fatalf("the unusable server strip survived: %#v", result.Plan.Transformations)
}
}
if !hasDegradationWarningV3(result.Plan.DegradationWarnings, "dolby_vision_strip_unsupported_by_source") {
t.Fatalf("the client was not told why the server route was dropped: %#v", result.Plan.DegradationWarnings)
}
}
func unstrippableProfile7FixtureV3() *models.MediaFile {
file := detailedFixtureFileV3()
file.VideoTracks[0].DVProfile = 7
file.VideoTracks[0].DVBLCompatID = 6
file.VideoTracks[0].DVELPresent = false
file.VideoTracks[0].DVEnhancementLayer = ""
file.VideoTracks[0].VideoRange = "DolbyVision"
file.VideoTracks[0].VideoRangeType = "DOVIWithEL"
return file
}
func hdr10OnlyProfile7RequestV3() StartRequestV3 {
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
req.Capabilities.HDRDetails = &HDRCapabilitiesV3{HDR10: true, DolbyVisionProfiles: []int{5, 8}}
req.ClientPlaybackContext.Output.HDRDetails = req.Capabilities.HDRDetails
return req
}
// The probe is expensive, so it must sit behind every cheap gate: a source
// nobody would strip anyway must never spawn one.
func TestPlanPlaybackV3DoesNotProbeWhenNoStripIsOnTheTable(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].BitDepth = 8
req := validStartRequestV3()
probed := false
result := PlanPlaybackV3(PlannerInputV3{
Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true},
Registry: testTransformationRegistryV3(),
DVRPUStrippable: func() bool { probed = true; return true },
})
if result.Plan == nil {
t.Fatalf("terminal = %#v", result.Terminal)
}
if probed {
t.Fatal("an ordinary SDR source paid for a Dolby Vision RPU probe")
}
}
// availableQualities must publish the transcode ladder below the source height
// plus the source-preserving "original" entry, and shrink to "original" alone
// when the transcode route cannot execute.
func TestPlanPlaybackV3PublishesAvailableQualities(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.VideoTracks[0].BitDepth = 8
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{8}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
labels := make([]string, 0, len(result.Plan.AvailableQualities))
for _, quality := range result.Plan.AvailableQualities {
labels = append(labels, quality.Label)
}
if len(labels) != 4 || labels[0] != "original" || labels[1] != "1080p" || labels[2] != "720p" || labels[3] != "480p" {
t.Fatalf("labels = %v", labels)
}
if !result.Plan.AvailableQualities[0].PreservesSource || result.Plan.AvailableQualities[0].Height != 2160 {
t.Fatalf("original entry = %#v", result.Plan.AvailableQualities[0])
}
if result.Plan.AvailableQualities[2].BitrateKbps != 2_000 {
t.Fatalf("720p bitrate = %#v", result.Plan.AvailableQualities[2])
}
// Without an HLS delivery the ladder cannot execute: menu shrinks to
// original only.
noHLS := validStartRequestV3()
noHLS.Capabilities.VideoDecode = req.Capabilities.VideoDecode
delete(noHLS.ClientPlaybackContext.Deliveries, DeliveryClassHLSV3)
result = PlanPlaybackV3(PlannerInputV3{Request: noHLS, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || len(result.Plan.AvailableQualities) != 1 || result.Plan.AvailableQualities[0].Label != "original" {
t.Fatalf("no-HLS qualities = %#v (%s)", result.Plan, ExplainPlannerResultV3(result))
}
}
func TestAvailableQualitiesV3UnknownSourceHeightPublishesNoFixedRungs(t *testing.T) {
request := validStartRequestV3()
qualities := availableQualitiesV3(PlannerInputV3{
Request: request,
Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true},
}, SourceDescriptorV3{VideoCodec: "h264", BitrateKbps: 8_000})
if len(qualities) != 1 || qualities[0].Label != QualityOriginalV3 || !qualities[0].PreservesSource {
t.Fatalf("unknown-height qualities = %#v, want original only", qualities)
}
}
func audioOnlyFixtureFileV3() *models.MediaFile {
return &models.MediaFile{ID: 77, BaseType: "audiobook", FilePath: "/media/audiobook.m4b", Container: "mp4", CodecAudio: "aac", Bitrate: 128, AudioChannels: 2, Duration: 39_600, AudioTracks: []models.AudioTrack{{Codec: "aac", Channels: 2, Layout: "stereo"}}}
}
// An audio-only source with client-decodable audio must plan the validated
// original route, skipping every video/HDR/subtitle gate.
func TestPlanPlaybackV3AudioOnlyPlansOriginalHTTP(t *testing.T) {
file := audioOnlyFixtureFileV3()
req := validStartRequestV3()
req.FileID = file.ID
req.Capabilities.Containers = []string{"mp4"}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 || result.PlayMethod != PlayDirect {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.Plan.DecisionReason != "validated_original_playback" {
t.Fatalf("decision reason = %q", result.Plan.DecisionReason)
}
if result.Plan.EffectiveRecipe.VideoCodec != "" || result.Plan.Subtitle.Mode != SubtitleOffV3 {
t.Fatalf("audio-only plan carried video state: %#v", result.Plan)
}
if len(result.Plan.AvailableQualities) != 1 || result.Plan.AvailableQualities[0].Label != "original" || !result.Plan.AvailableQualities[0].PreservesSource {
t.Fatalf("audio-only qualities = %#v", result.Plan.AvailableQualities)
}
if !strings.HasPrefix(result.Plan.PlanAttemptKey, "v3:") {
t.Fatalf("attempt key = %q", result.Plan.PlanAttemptKey)
}
}
func TestPlanPlaybackV3AudioOnlyHonorsBandwidthCap(t *testing.T) {
for _, test := range []struct {
name string
bitrate int
capKbps *int
wantDirect bool
wantAAC int
}{
{name: "source exceeds cap", bitrate: 1_200, capKbps: intPointerV3(256), wantAAC: 192},
{name: "cap below AAC default", bitrate: 1_200, capKbps: intPointerV3(96), wantAAC: 96},
{name: "source is below cap", bitrate: 128, capKbps: intPointerV3(256), wantDirect: true},
{name: "uncapped", bitrate: 1_200, wantDirect: true},
{name: "unknown source bitrate", capKbps: intPointerV3(256), wantDirect: true},
} {
t.Run(test.name, func(t *testing.T) {
file := audioOnlyFixtureFileV3()
file.Bitrate = test.bitrate
req := validStartRequestV3()
req.FileID = file.ID
req.Capabilities.Containers = []string{"mp4"}
req.BandwidthCapKbps = test.capKbps
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if test.wantDirect {
if result.Plan == nil || result.Plan.Delivery != DeliveryOriginalHTTPV3 || result.TranscodeAudio {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
return
}
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 || !result.TranscodeAudio || result.TargetAudioCodec != "aac" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.Plan.DecisionReason != "quality_bandwidth_cap" || !hasDegradationWarningV3(result.Plan.DegradationWarnings, "audio_converted") || !hasDegradationWarningV3(result.Plan.DegradationWarnings, "bandwidth_cap_applied") {
t.Fatalf("capped plan = %#v", result.Plan)
}
if result.TargetAudioBitrateKbps != test.wantAAC || result.Plan.EffectiveRecipe.BitrateKbps == nil || *result.Plan.EffectiveRecipe.BitrateKbps != test.wantAAC {
t.Fatalf("AAC bitrate = target %d recipe %#v, want %d", result.TargetAudioBitrateKbps, result.Plan.EffectiveRecipe.BitrateKbps, test.wantAAC)
}
})
}
}
func TestPlanPlaybackV3NonDefaultAudioSelectionCannotUseOriginalHTTP(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.AudioTracks = []models.AudioTrack{
{Codec: "aac", Channels: 2, Layout: "stereo", Default: true},
{Codec: "aac", Channels: 2, Layout: "stereo"},
}
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 1, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 || result.PlayMethod != PlayRemux || result.TranscodeAudio {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.Plan.SelectedTracks.Audio == nil || result.Plan.SelectedTracks.Audio.Index == nil || *result.Plan.SelectedTracks.Audio.Index != 1 {
t.Fatalf("selected audio = %#v", result.Plan.SelectedTracks.Audio)
}
}
func TestPlanPlaybackV3HLSAudioConversionHonorsChannelCeiling(t *testing.T) {
file := detailedFixtureFileV3()
file.VideoTracks[0].VideoRange = "SDR"
file.VideoTracks[0].VideoRangeType = "SDR"
file.CodecAudio = "dts"
file.AudioChannels = 8
file.AudioTracks[0] = models.AudioTrack{Codec: "dts", Channels: 8, Layout: "7.1", Default: true}
req := validStartRequestV3()
req.Capabilities.VideoDecode = []VideoDecodeCapabilityV3{{Codec: "hevc", Profiles: []string{"main 10"}, Levels: []int{153}, BitDepths: []int{10}, MaxWidth: 3840, MaxHeight: 2160, MaxFrameRate: 60, MaxBitrateKbps: 80_000, Hardware: true}}
delete(req.ClientPlaybackContext.Deliveries, DeliveryClassOriginalHTTPV3)
delete(req.ClientPlaybackContext.Deliveries, DeliveryClassProgressiveV3)
maxChannels := 2
hls := req.ClientPlaybackContext.Deliveries[DeliveryClassHLSV3]
hls.MaxChannels = &maxChannels
req.ClientPlaybackContext.Deliveries[DeliveryClassHLSV3] = hls
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true, Allow4KTranscode: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxHLSV3 || !result.TranscodeAudio || result.TargetAudioChannels != 2 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.Plan.EffectiveRecipe.AudioChannels == nil || *result.Plan.EffectiveRecipe.AudioChannels != 2 || result.Plan.EffectiveRecipe.AudioLayout != "stereo" {
t.Fatalf("AAC recipe = %#v", result.Plan.EffectiveRecipe)
}
}
// An audio-only source whose codec the client cannot decode must take the
// progressive audio_to_aac conversion route, and keep an accurate retryable
// terminal when the toolchain is missing.
func TestPlanPlaybackV3AudioOnlyConvertsUnsupportedCodec(t *testing.T) {
file := audioOnlyFixtureFileV3()
file.CodecAudio = "flac"
file.AudioTracks[0].Codec = "flac"
req := validStartRequestV3()
req.FileID = file.ID
req.Capabilities.Containers = []string{"mp4"}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 || !result.TranscodeAudio || result.TargetAudioCodec != "aac" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.Plan.DecisionReason != "audio_adaptation" || len(result.Plan.Transformations) != 1 || result.Plan.Transformations[0].Name != "audio_to_aac" {
t.Fatalf("plan = %#v", result.Plan)
}
noToolchain := NewTransformationRegistryV3([]TransformationSpecV3{{Name: "audio_to_aac", RecipeVersion: "1"}})
result = PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: noToolchain})
if result.Terminal == nil || result.Terminal.Reason != "audio_conversion_unsupported" || !result.Terminal.Retryable {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
func TestPlanPlaybackV3AudioOnlyConvertsForProgressiveCodecSubset(t *testing.T) {
file := audioOnlyFixtureFileV3()
file.CodecAudio = "flac"
file.AudioChannels = 2
file.AudioTracks[0].Codec = "flac"
req := validStartRequestV3()
req.FileID = file.ID
req.Capabilities.CodecsAudio = []string{"aac", "flac"}
req.Capabilities.Containers = []string{"mp4"}
delete(req.ClientPlaybackContext.Deliveries, DeliveryClassOriginalHTTPV3)
maxChannels := 1
req.ClientPlaybackContext.Deliveries[DeliveryClassProgressiveV3] = DeliveryCapabilityV3{
Enabled: true, SupportedOnDevice: true, Containers: []string{"mp4"}, AudioDecodeCodecs: []string{"aac"}, MaxChannels: &maxChannels,
}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 || !result.TranscodeAudio || result.TargetAudioCodec != "aac" || result.TargetAudioChannels != 1 {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.Plan.EffectiveRecipe.AudioChannels == nil || *result.Plan.EffectiveRecipe.AudioChannels != 1 || result.Plan.EffectiveRecipe.AudioLayout != "mono" {
t.Fatalf("AAC recipe = %#v", result.Plan.EffectiveRecipe)
}
if result.Plan.DecisionReason != "audio_adaptation" || len(result.Plan.Transformations) != 1 || result.Plan.Transformations[0].Name != TransformationAudioToAACV3 || !hasDegradationWarningV3(result.Plan.DegradationWarnings, "audio_converted") {
t.Fatalf("converted plan = %#v", result.Plan)
}
}
// A container mismatch on decodable audio is a remux, not a conversion, and a
// client with neither route left gets an honest terminal. An audio-only file
// with no probed audio codec keeps its own metadata terminal.
func TestPlanPlaybackV3AudioOnlyRemuxesForeignContainerAndTerminals(t *testing.T) {
file := audioOnlyFixtureFileV3()
file.Container = "ogg"
file.FilePath = "/media/audiobook.ogg"
req := validStartRequestV3()
req.FileID = file.ID
req.Capabilities.Containers = []string{"mp4"}
result := PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Plan == nil || result.Plan.Delivery != DeliveryRemuxProgressiveV3 || result.TranscodeAudio {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
if result.Plan.DecisionReason != "container_normalization" {
t.Fatalf("decision reason = %q", result.Plan.DecisionReason)
}
progressiveless := validStartRequestV3()
progressiveless.FileID = file.ID
progressiveless.Capabilities.Containers = []string{"mkv"}
delete(progressiveless.ClientPlaybackContext.Deliveries, DeliveryClassProgressiveV3)
result = PlanPlaybackV3(PlannerInputV3{Request: progressiveless, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Terminal == nil || result.Terminal.Reason != "adaptation_unavailable" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
unprobed := audioOnlyFixtureFileV3()
unprobed.CodecAudio = ""
unprobed.AudioTracks = nil
result = PlanPlaybackV3(PlannerInputV3{Request: req, RequestedFile: unprobed, EffectiveFile: unprobed, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()})
if result.Terminal == nil || result.Terminal.Reason != "source_metadata_incomplete" {
t.Fatalf("result = %s", ExplainPlannerResultV3(result))
}
}
// Loop prevention applies to audio-only routes exactly like video routes: an
// attempted original route falls to the conversion remux, and an exhausted
// route family terminals.
func TestPlanPlaybackV3AudioOnlyHonorsAttemptedKeys(t *testing.T) {
file := audioOnlyFixtureFileV3()
req := validStartRequestV3()
req.FileID = file.ID
req.Capabilities.Containers = []string{"mp4"}
input := PlannerInputV3{Request: req, RequestedFile: file, EffectiveFile: file, AudioTrackIndex: 0, Settings: PlannerSettingsV3{TranscodeEnabled: true}, Registry: testTransformationRegistryV3()}
first := PlanPlaybackV3(input)
if first.Plan == nil || first.Plan.Delivery != DeliveryOriginalHTTPV3 {
t.Fatalf("first = %s", ExplainPlannerResultV3(first))
}
input.AttemptedKeys = []string{first.Plan.PlanAttemptKey}
second := PlanPlaybackV3(input)
if second.Plan == nil || second.Plan.Delivery != DeliveryRemuxProgressiveV3 {
t.Fatalf("second = %s", ExplainPlannerResultV3(second))
}
input.AttemptedKeys = append(input.AttemptedKeys, second.Plan.PlanAttemptKey)
third := PlanPlaybackV3(input)
if third.Terminal == nil || third.Terminal.Reason != "adaptation_exhausted" {
t.Fatalf("third = %s", ExplainPlannerResultV3(third))
}
}