fix(stream): no copiar AAC multicanal en modo copy (WebKit lo rechaza igual)
El downmix estéreo del re-encode (f89396c) dejaba un agujero simétrico: una
fuente cuyo audio YA es AAC 5.1 se copiaba tal cual, y WebKit rechaza el
AAC multicanal en el primer segmento exactamente igual que el re-encodeado.
Copy de audio ahora solo cuando la pista es AAC con ≤2 canales; cualquier
otra cosa (no-AAC, AAC 5.1+, o canales desconocidos en el probe — fail-safe)
re-encodea a AAC estéreo 48k. La pista multicanal original queda intacta
para reproductor externo. Test smoke nuevo: fuente AAC 5.1 → re-encode.
This commit is contained in:
parent
f89396ceed
commit
a4a6e2f2d6
2 changed files with 29 additions and 8 deletions
|
|
@ -1959,20 +1959,22 @@ func buildHLSCopyArgs(cfg HLSSessionConfig, probe *StreamProbe, tmpDir string) [
|
||||||
args = append(args, "-tag:v", "hvc1")
|
args = append(args, "-tag:v", "hvc1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audio: copy when the SELECTED track is already AAC, else AAC 192k.
|
// Audio: copy ONLY when the selected track is AAC with ≤2 channels —
|
||||||
// (fMP4 HLS carries AAC universally; EAC3/DTS/TrueHD do not.)
|
// WebKit/Apple HLS rejects multichannel AAC at the first media segment
|
||||||
|
// (observed via the Safari access log: master → index → init → seg-0
|
||||||
|
// fetched twice, then silence — every 5.1 movie failed on iPhone while
|
||||||
|
// stereo-AAC episodes played). Anything else (non-AAC, or AAC 5.1+) is
|
||||||
|
// re-encoded mirroring the encode path exactly: AAC stereo 48k. The
|
||||||
|
// original multichannel track stays intact for external players.
|
||||||
audioCodec := probe.AudioCodec
|
audioCodec := probe.AudioCodec
|
||||||
|
audioChannels := 0
|
||||||
if audioIdx < len(probe.AudioTracks) {
|
if audioIdx < len(probe.AudioTracks) {
|
||||||
audioCodec = probe.AudioTracks[audioIdx].Codec
|
audioCodec = probe.AudioTracks[audioIdx].Codec
|
||||||
|
audioChannels = probe.AudioTracks[audioIdx].Channels
|
||||||
}
|
}
|
||||||
if strings.EqualFold(audioCodec, "aac") {
|
if strings.EqualFold(audioCodec, "aac") && audioChannels > 0 && audioChannels <= 2 {
|
||||||
args = append(args, "-c:a", "copy")
|
args = append(args, "-c:a", "copy")
|
||||||
} else {
|
} else {
|
||||||
// Mirror the encode path exactly: AAC stereo 48k. WITHOUT -ac 2 a 5.1
|
|
||||||
// source produces 6-channel ffmpeg-native AAC, which WebKit/Apple HLS
|
|
||||||
// rejects at the first media segment (observed via Safari access log:
|
|
||||||
// master → index → init → seg-0 fetched twice, then silence — every
|
|
||||||
// 5.1 movie failed on iPhone while stereo-AAC episodes played).
|
|
||||||
args = append(args, "-c:a", "aac", "-b:a", "192k", "-ar", "48000", "-ac", "2")
|
args = append(args, "-c:a", "aac", "-b:a", "192k", "-ar", "48000", "-ac", "2")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,25 @@ func TestHLSCopy_Hevc10Eac3_IncidentShape(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHLSCopy_Aac51MustReencode(t *testing.T) {
|
||||||
|
// AAC is NOT copy-safe when multichannel: WebKit rejects 6-channel AAC at
|
||||||
|
// the first media segment exactly like re-encoded 5.1. Source AAC 5.1 →
|
||||||
|
// must re-encode to stereo, never copy.
|
||||||
|
rt := copyTestRuntime(t)
|
||||||
|
src := genSource(t, rt, "aac51.mkv",
|
||||||
|
[]string{"-c:v", "libx264", "-preset", "ultrafast", "-pix_fmt", "yuv420p"},
|
||||||
|
[]string{"-c:a", "aac", "-ac", "6", "-b:a", "256k"}, 8)
|
||||||
|
s, pl := runCopySession(t, rt, src, 0)
|
||||||
|
assertCopyOutput(t, rt, s, pl, "h264", "aac", 8)
|
||||||
|
args := buildHLSCopyArgs(s.cfg, s.probe, s.tmpDir)
|
||||||
|
if containsSeq(args, "-c:a", "copy") {
|
||||||
|
t.Errorf("AAC 5.1 must NOT be copied (WebKit rejects multichannel AAC), args: %v", args)
|
||||||
|
}
|
||||||
|
if !containsSeq(args, "-ac", "2") {
|
||||||
|
t.Errorf("AAC 5.1 must re-encode to stereo, args: %v", args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHLSCopy_ResumeStartSec(t *testing.T) {
|
func TestHLSCopy_ResumeStartSec(t *testing.T) {
|
||||||
rt := copyTestRuntime(t)
|
rt := copyTestRuntime(t)
|
||||||
src := genSource(t, rt, "resume.mkv",
|
src := genSource(t, rt, "resume.mkv",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue