Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions internal/playback/remux.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const (

// buildRemuxArgs constructs the ffmpeg argument list for a remux operation.
// The args perform codec copy (-c copy) into the target container format,
// using fragmented output for streaming (frag_keyframe+delay_moov+default_base_moof) and
// using fragmented output for streaming (frag_keyframe+delay_moov) and
// pipe:1 for stdout output.
// When transcodeAudio is true, video is copied but audio is transcoded to
// stereo AAC (handles cases like DTS/TrueHD that browsers cannot decode).
Expand Down Expand Up @@ -266,7 +266,14 @@ func buildRemuxArgsWithAudioV3(filePath, outputFormat string, seekSeconds float6
// delay_moov lets the MP4 muxer inspect the first audio packet before
// writing codec configuration. empty_moov fails immediately for copied
// E-AC-3/Atmos tracks because their frame size is not known at header time.
"-movflags", "frag_keyframe+delay_moov+default_base_moof",
//
// No default_base_moof: this is one progressive byte stream, not MSE/CMAF
// segments, so explicit tfhd base data offsets are correct and every
// progressive demuxer reads them. Samsung Tizen's native player does not
// follow moof-relative offsets: it plays the first fragment, then stalls
// with no audio (verified on a QN700B, Tizen 6.5, with the same copied
// HEVC + AAC 5.1 stream with and without the flag).
"-movflags", "frag_keyframe+delay_moov",
"pipe:1",
)

Expand All @@ -276,7 +283,7 @@ func buildRemuxArgsWithAudioV3(filePath, outputFormat string, seekSeconds float6
// StartRemux starts an ffmpeg process that copies codecs to a new container.
// When transcodeAudio is false the command is:
//
// ffmpeg -i {input} -c copy -f {format} -movflags frag_keyframe+delay_moov+default_base_moof pipe:1
// ffmpeg -i {input} -c copy -f {format} -movflags frag_keyframe+delay_moov pipe:1
//
// When transcodeAudio is true video is copied but audio is transcoded to AAC.
// The caller must call Close() when done to clean up resources.
Expand Down
11 changes: 10 additions & 1 deletion internal/playback/remux_dv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,20 @@ func TestStartRemuxRejectsUnknownModeForAllProfiles(t *testing.T) {

func TestBuildRemuxArgsDelaysMoovForCopiedAtmosConfiguration(t *testing.T) {
args := buildRemuxArgs("/x.mkv", "mp4", 0, false, -1, 8, false, false)
if !argsContainPair(args, "-movflags", "frag_keyframe+delay_moov+default_base_moof") {
if !argsContainPair(args, "-movflags", "frag_keyframe+delay_moov") {
t.Fatalf("remux must delay moov until copied audio is parsed, args=%v", strings.Join(args, " "))
}
}

// Tizen's native player stalls after the first fragment when tfhd offsets are
// moof-relative, so the progressive stream must not set default_base_moof.
func TestBuildRemuxArgsOmitsDefaultBaseMoof(t *testing.T) {
args := buildRemuxArgs("/x.mkv", "mp4", 0, true, -1, 8, false, false)
if strings.Contains(strings.Join(args, " "), "default_base_moof") {
t.Fatalf("progressive remux must not use default_base_moof, args=%v", strings.Join(args, " "))
}
}

// writeProbeAwareFFmpeg stands in for an ffmpeg that carries the dovi_rpu
// filter but cannot parse this source's RPU: it advertises the filter, fails
// the probe the way the real one does (rejecting packets while exiting 0), and
Expand Down
3 changes: 3 additions & 0 deletions scripts/prairie-invariants.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ web/src/api/client.ts 1 X-Prairie- client identity headers
web/src/player/components/PlaybackInfoOverlay.tsx 1 Recent events web stats overlay shows the player event log
web/src/player/components/VideoPlayer.tsx 1 new PlaybackEventLog\( web player records events for the stats overlay
internal/api/handlers/stream.go 1 userID == 0 && !apimw\.IsStreamTokenAuthorized\( v2 progressive/direct delivery honors st (Tizen direct play)

# --- Progressive remux that Samsung Tizen native players can follow.
internal/playback/remux.go 1 "-movflags", "frag_keyframe\+delay_moov", no default_base_moof: Tizen stalls after the first fragment (Iron Man, QN700B)
Loading