diff --git a/front/packages/ui/src/player/video.web.tsx b/front/packages/ui/src/player/video.web.tsx index 1dd1046f..754fc0c5 100644 --- a/front/packages/ui/src/player/video.web.tsx +++ b/front/packages/ui/src/player/video.web.tsx @@ -34,7 +34,7 @@ import { useAtomValue, useSetAtom, useAtom } from "jotai"; import { useYoshiki } from "yoshiki"; import SubtitleOctopus from "libass-wasm"; import { playAtom, PlayMode, playModeAtom, subtitleAtom } from "./state"; -import Hls from "hls.js"; +import Hls, { Level } from "hls.js"; import { useTranslation } from "react-i18next"; import { Menu } from "@kyoo/primitives"; @@ -58,6 +58,7 @@ const initHls = async () => { xhr.setRequestHeader("X-CLIENT-ID", client_id); }, }); + // hls.currentLevel = hls.startLevel; }; const Video = forwardRef<{ seek: (value: number) => void }, VideoProps>(function _Video( @@ -262,6 +263,12 @@ export const QualitiesMenu = (props: ComponentProps) => { return () => hls!.off(Hls.Events.LEVEL_SWITCHED, rerender); }); + const levelName = (label: Level, auto?: boolean): string => { + const height = `${label.height}p` + if (auto) return height; + return label.uri.includes("original") ? `${t("player.transmux")} (${height})` : height; + } + return ( ) => { = 0 - ? `${t("player.auto")} (${hls.levels[hls.currentLevel].height}p)` + ? `${t("player.auto")} (${levelName(hls.levels[hls.currentLevel], true)})` : t("player.auto") } selected={hls?.autoLevelEnabled && mode === PlayMode.Hls} onSelect={() => { setPlayMode(PlayMode.Hls); - if (hls) hls.nextLevel = -1; + if (hls) hls.currentLevel = -1; }} /> {hls?.levels .map((x, i) => ( { setPlayMode(PlayMode.Hls); - hls!.nextLevel = i; + hls!.currentLevel = i; }} /> )) diff --git a/front/translations/en.json b/front/translations/en.json index b5c470c6..a3e4d298 100644 --- a/front/translations/en.json +++ b/front/translations/en.json @@ -49,6 +49,7 @@ "subtitle-none": "None", "fullscreen": "Fullscreen", "direct": "Pristine", + "transmux": "Original", "auto": "Auto" }, "search": { diff --git a/front/translations/fr.json b/front/translations/fr.json index 6d5aa62d..e33b041e 100644 --- a/front/translations/fr.json +++ b/front/translations/fr.json @@ -49,6 +49,7 @@ "subtitle-none": "Aucun", "fullscreen": "Plein-écran", "direct": "Pristine", + "transmux": "Original", "auto": "Auto" }, "search": { diff --git a/transcoder/src/audio.rs b/transcoder/src/audio.rs index 6052f8a1..f321cd7f 100644 --- a/transcoder/src/audio.rs +++ b/transcoder/src/audio.rs @@ -28,10 +28,10 @@ async fn get_audio_transcoded( .await .map_err(|_| ApiError::NotFound)?; - transcoder - .transcode_audio(path, audio) - .await - .map_err(|_| ApiError::InternalError) + transcoder.transcode_audio(path, audio).await.map_err(|e| { + eprintln!("Error while transcoding audio: {}", e); + ApiError::InternalError + }) } /// Get audio chunk diff --git a/transcoder/src/state.rs b/transcoder/src/state.rs index 2cdbc26b..6df4deec 100644 --- a/transcoder/src/state.rs +++ b/transcoder/src/state.rs @@ -1,7 +1,7 @@ use crate::identify::identify; use crate::paths::get_path; -use crate::utils::Signalable; use crate::transcode::*; +use crate::utils::Signalable; use std::collections::HashMap; use std::path::PathBuf; use std::sync::RwLock; @@ -30,7 +30,9 @@ impl Transcoder { master.push_str("#EXT-X-STREAM-INF:"); master.push_str(format!("AVERAGE-BANDWIDTH={},", info.video.bitrate).as_str()); // Approximate a bit more because we can't know the maximum bandwidth. - master.push_str(format!("BANDWIDTH={},", (info.video.bitrate as f32 * 1.2) as u32).as_str()); + master.push_str( + format!("BANDWIDTH={},", (info.video.bitrate as f32 * 1.2) as u32).as_str(), + ); master.push_str( format!("RESOLUTION={}x{},", info.video.width, info.video.height).as_str(), ); @@ -42,7 +44,9 @@ impl Transcoder { } let aspect_ratio = info.video.width as f32 / info.video.height as f32; - for quality in Quality::iter().filter(|x| x.height() <= info.video.quality.height()) { + // Do not include a quality with the same height as the original (simpler for automatic + // selection on the client side.) + for quality in Quality::iter().filter(|x| x.height() < info.video.quality.height()) { // Doc: https://developer.apple.com/documentation/http_live_streaming/example_playlists_for_http_live_streaming/creating_a_multivariant_playlist master.push_str("#EXT-X-STREAM-INF:"); master.push_str(format!("AVERAGE-BANDWIDTH={},", quality.average_bitrate()).as_str()); diff --git a/transcoder/src/transcode.rs b/transcoder/src/transcode.rs index 45cb4296..f00e112d 100644 --- a/transcoder/src/transcode.rs +++ b/transcoder/src/transcode.rs @@ -219,7 +219,7 @@ async fn start_transcode( let mut cmd = Command::new("ffmpeg"); cmd.args(&["-progress", "pipe:1"]) - .arg("-nostats") + .args(&["-nostats", "-hide_banner", "-loglevel", "warning"]) .args(&["-ss", start_time.to_string().as_str()]) .args(&["-i", path.as_str()]) .args(&["-f", "hls"]) @@ -250,7 +250,8 @@ async fn start_transcode( let value = &value[1..]; // Can't use ms since ms and us are both set to us /shrug if key == "out_time_us" { - let _ = tx.send(value.parse::().unwrap() / 1_000_000); + // Sometimes, the value is invalid (or negative), default to 0 in those cases + let _ = tx.send(value.parse::().unwrap_or(0) / 1_000_000); } } }