From 79dc4e5f3363db65f9fee921a33b8becc67b662c Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 18 Feb 2024 15:38:37 +0100 Subject: [PATCH] Try to prefer transmux instead of transcode (not sure yet) --- front/apps/web/package.json | 2 +- front/packages/ui/src/player/video.web.tsx | 60 +++++++++++----------- front/yarn.lock | 10 ++-- transcoder/src/filestream.go | 12 ++++- transcoder/src/quality.go | 32 ++++++------ 5 files changed, 61 insertions(+), 55 deletions(-) diff --git a/front/apps/web/package.json b/front/apps/web/package.json index 80edb381..acd29d76 100644 --- a/front/apps/web/package.json +++ b/front/apps/web/package.json @@ -27,7 +27,7 @@ "expo-image-picker": "~14.7.1", "expo-linear-gradient": "^12.7.1", "expo-modules-core": "^1.11.8", - "hls.js": "^1.5.2", + "hls.js": "^1.5.6", "i18next": "^23.7.20", "jassub": "^1.7.15", "jotai": "^2.6.3", diff --git a/front/packages/ui/src/player/video.web.tsx b/front/packages/ui/src/player/video.web.tsx index d1bbe626..72001f1f 100644 --- a/front/packages/ui/src/player/video.web.tsx +++ b/front/packages/ui/src/player/video.web.tsx @@ -49,10 +49,8 @@ function uuidv4(): string { let client_id = typeof window === "undefined" ? "ssr" : uuidv4(); -const initHls = async (): Promise => { +const initHls = (): Hls => { if (hls !== null) return hls; - const token = await getToken(); - const loadPolicy: LoadPolicy = { default: { maxTimeToFirstByteMs: Infinity, @@ -70,12 +68,17 @@ const initHls = async (): Promise => { }, }; hls = new Hls({ - xhrSetup: (xhr) => { + xhrSetup: async (xhr) => { + const token = await getToken(); if (token) xhr.setRequestHeader("Authorization", `Bearer: ${token}`); xhr.setRequestHeader("X-CLIENT-ID", client_id); }, autoStartLoad: false, + startLevel: Infinity, + abrEwmaDefaultEstimate: 35_000_000, + abrEwmaDefaultEstimateMax: 50_000_000, // debug: true, + lowLatencyMode: false, fragLoadPolicy: { default: { maxTimeToFirstByteMs: Infinity, @@ -98,9 +101,6 @@ const initHls = async (): Promise => { manifestLoadPolicy: loadPolicy, steeringManifestLoadPolicy: loadPolicy, }); - hls.on(Hls.Events.MANIFEST_PARSED, () => { - if (hls) hls.startLevel = hls.firstLevel; - }); return hls; }; @@ -149,31 +149,29 @@ const Video = forwardRef<{ seek: (value: number) => void }, VideoProps>(function useSubtitle(ref, subtitle, fonts); useLayoutEffect(() => { - (async () => { - if (!ref?.current || !source.uri) return; - if (!hls || oldHls.current !== source.hls) { - // Reinit the hls player when we change track. - if (hls) hls.destroy(); - hls = null; - hls = await initHls(); - hls.loadSource(source.hls!); - oldHls.current = source.hls; - } - if (!source.uri.endsWith(".m3u8")) { - hls.detachMedia(); - ref.current.src = source.uri; - } else { - hls.attachMedia(ref.current); - hls.startLoad(source.startPosition ? source.startPosition / 1000 : 0); - hls.on(Hls.Events.ERROR, (_, d) => { - if (!d.fatal || !hls?.media) return; - console.warn("Hls error", d); - onError?.call(null, { - error: { errorString: d.reason ?? d.error?.message ?? "Unknown hls error" }, - }); + if (!ref?.current || !source.uri) return; + if (!hls || oldHls.current !== source.hls) { + // Reinit the hls player when we change track. + if (hls) hls.destroy(); + hls = null; + hls = initHls(); + hls.loadSource(source.hls!); + oldHls.current = source.hls; + } + if (!source.uri.endsWith(".m3u8")) { + hls.detachMedia(); + ref.current.src = source.uri; + } else { + hls.attachMedia(ref.current); + hls.startLoad(source.startPosition ? source.startPosition / 1000 : 0); + hls.on(Hls.Events.ERROR, (_, d) => { + if (!d.fatal || !hls?.media) return; + console.warn("Hls error", d); + onError?.call(null, { + error: { errorString: d.reason ?? d.error?.message ?? "Unknown hls error" }, }); - } - })(); + }); + } // onError changes should not restart the playback. // eslint-disable-next-line react-hooks/exhaustive-deps }, [source.uri, source.hls]); diff --git a/front/yarn.lock b/front/yarn.lock index 2762412e..0ca12690 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -8465,10 +8465,10 @@ __metadata: languageName: node linkType: hard -"hls.js@npm:^1.5.2": - version: 1.5.2 - resolution: "hls.js@npm:1.5.2" - checksum: fb03209ca3b691e996c3d0b83dac2bcc63dba468f9c24b7414d1dc9b950c3ac0fdcfc2349d8b16d98a96c6fbe35c2836d5740a832d1844451187be4749469957 +"hls.js@npm:^1.5.6": + version: 1.5.6 + resolution: "hls.js@npm:1.5.6" + checksum: 685564b223955267194ec1089179717e040354a92e0269dd72150598b422448cede1cb4882c0c63b8124f42d823e156b6433bbd3048443c4d4ff29cae3ec4efa languageName: node linkType: hard @@ -14023,7 +14023,7 @@ __metadata: expo-image-picker: ~14.7.1 expo-linear-gradient: ^12.7.1 expo-modules-core: ^1.11.8 - hls.js: ^1.5.2 + hls.js: ^1.5.6 i18next: ^23.7.20 jassub: ^1.7.15 jotai: ^2.6.3 diff --git a/transcoder/src/filestream.go b/transcoder/src/filestream.go index 824e2402..c893b79d 100644 --- a/transcoder/src/filestream.go +++ b/transcoder/src/filestream.go @@ -153,10 +153,18 @@ func (fs *FileStream) GetMaster() string { master := "#EXTM3U\n" // TODO: also check if the codec is valid in a hls before putting transmux if fs.Info.Video != nil { + var transmux_quality Quality + for _, quality := range Qualities { + if quality.Height() >= fs.Info.Video.Quality.Height() || quality.AverageBitrate() >= fs.Info.Video.Bitrate { + transmux_quality = quality + break + } + } if fs.CanTransmux { + bitrate := float64(fs.Info.Video.Bitrate) master += "#EXT-X-STREAM-INF:" - master += fmt.Sprintf("AVERAGE-BANDWIDTH=%d,", fs.Info.Video.Bitrate) - master += fmt.Sprintf("BANDWIDTH=%d,", int(float32(fs.Info.Video.Bitrate)*1.2)) + master += fmt.Sprintf("AVERAGE-BANDWIDTH=%d,", int(math.Min(bitrate*0.8, float64(transmux_quality.AverageBitrate())))) + master += fmt.Sprintf("BANDWIDTH=%d,", int(math.Min(bitrate, float64(transmux_quality.MaxBitrate())))) master += fmt.Sprintf("RESOLUTION=%dx%d,", fs.Info.Video.Width, fs.Info.Video.Height) master += "AUDIO=\"audio\"," master += "CLOSED-CAPTIONS=NONE\n" diff --git a/transcoder/src/quality.go b/transcoder/src/quality.go index 60674abf..68c9aaf2 100644 --- a/transcoder/src/quality.go +++ b/transcoder/src/quality.go @@ -41,21 +41,21 @@ func QualityFromString(str string) (Quality, error) { func (v Quality) AverageBitrate() uint32 { switch v { case P240: - return 400000 + return 400_000 case P360: - return 800000 + return 800_000 case P480: - return 1200000 + return 1_200_000 case P720: - return 2400000 + return 2_400_000 case P1080: - return 4800000 + return 4_800_000 case P1440: - return 9600000 + return 9_600_000 case P4k: - return 16000000 + return 16_000_000 case P8k: - return 28000000 + return 28_000_000 case Original: panic("Original quality must be handled specially") } @@ -65,21 +65,21 @@ func (v Quality) AverageBitrate() uint32 { func (v Quality) MaxBitrate() uint32 { switch v { case P240: - return 700000 + return 700_000 case P360: - return 1400000 + return 1_400_000 case P480: - return 2100000 + return 2_100_000 case P720: - return 4000000 + return 4_000_000 case P1080: - return 8000000 + return 8_000_000 case P1440: - return 12000000 + return 12_000_000 case P4k: - return 28000000 + return 28_000_000 case P8k: - return 40000000 + return 40_000_000 case Original: panic("Original quality must be handled specially") }