fix(android): stop tunneling 24p video on the Fire TV Stick 4K

Tunneled playback on an AFTMM judders continuously through 23.976p direct play.
The #1802 reporter isolated it: turning off Tunneled Playback with every other
setting unchanged makes it smooth, and their log shows tunneling active for the
whole session with E-AC3 bitstreamed and the decoded-PCM guard never firing.

Audio Passthrough looked like the trigger only because it is the one user-facing
switch that decides it. Passthrough off, or Downmix to Stereo on, both force the
Dolby track to decode to PCM, which trips the #1458 guard and takes tunneling
down with it. Passthrough on with downmix off is the only combination that keeps
a bitstreamed track, so it is the only one that stays tunneled.

Withdraw tunneling on that model for content at or below 30fps. The cut-off
keeps 4K50/60 tunneled, which is the workload Amazon documents the feature for.
The mechanism stays unconfirmed: tunneling fires no VideoFrameMetadataListener
and stops media3 counting frames in the codec, so nothing app-side can measure
the cadence. Only the trigger is established, and the quirk is scoped to it.

That needs a frame rate the app did not have. Neither MatroskaExtractor nor
Mp4Extractor populates Format.frameRate, and a tunneled session renders no
frames back for the native detector, so the server's rate now rides on the open
call. It is sent only for direct play, matching _primeDisplayCriteria: a
transcode's metadata describes the source, not what the server is about to send.

Also move Audio Passthrough out of the in-player settings sheet. It configures
the audio output route rather than the current playback, and applying it
mid-stream bounces the audio renderer and re-decides tunneling. Settings > Video
Playback already owns it, next to Tunneled Playback, which is applied the same
way. That description now mentions stutter, not only black HDR video, so the
workaround is findable on hardware this quirk does not cover.

The mpv backend failing to start the same 4K file is a separate defect and is
not addressed here; its uploaded log is no longer retrievable.
This commit is contained in:
edde746
2026-08-06 03:45:09 +02:00
parent 1b6a811c07
commit f93952ba6f
56 changed files with 263 additions and 88 deletions
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Səs çıxışı",
"performanceOverlay": "Məhsuldarlıq paneli",
"audioPassthrough": "Səsin birbaşa ötürülməsi",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Əhatəli səs",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Аудио изход",
"performanceOverlay": "Оверлей за производителност",
"audioPassthrough": "Директно предаване на аудио",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Съраунд",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Lydoutput",
"performanceOverlay": "Ydelsesoverlay",
"audioPassthrough": "Lyd-passthrough",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Audioausgabe",
"performanceOverlay": "Leistungsanzeige",
"audioPassthrough": "Audio-Durchleitung",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
+1 -2
View File
@@ -282,7 +282,7 @@
"matchDynamicRangeDescription": "Switch HDR on for HDR content, then back to SDR",
"displaySwitchDelay": "Display Switch Delay",
"tunneledPlayback": "Tunneled Playback",
"tunneledPlaybackDescription": "Use video tunneling. Disable if HDR playback shows black video.",
"tunneledPlaybackDescription": "Use video tunneling. Disable if HDR playback shows black video or motion stutters.",
"audioPassthrough": "Audio Passthrough",
"audioPassthroughDescription": "Send Dolby/DTS audio to your receiver or TV without re-encoding, preserving surround sound. Turn off if you have no sound.",
"audioPassthroughDescriptionAppleTv": "Use Apple's native Dolby decoder for Dolby Digital Plus, including Atmos. DTS and TrueHD still play as multichannel PCM. Turn off if you have no sound.",
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Audio Output",
"performanceOverlay": "Performance Overlay",
"audioPassthrough": "Audio Passthrough",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Salida de audio",
"performanceOverlay": "Indicador de rendimiento",
"audioPassthrough": "Transferencia directa de audio",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Envolvente",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Sortie audio",
"performanceOverlay": "Données de performance",
"audioPassthrough": "Transmission audio directe",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Hangkimenet",
"performanceOverlay": "Teljesítményadatok",
"audioPassthrough": "Hangtovábbítás (passthrough)",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Térhatású",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Uscita audio",
"performanceOverlay": "Overlay prestazioni",
"audioPassthrough": "Passthrough audio",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
-1
View File
@@ -1641,7 +1641,6 @@
"hdr": "HDR",
"audioOutput": "音声出力",
"performanceOverlay": "パフォーマンスオーバーレイ",
"audioPassthrough": "オーディオパススルー",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "サラウンド",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Аудио шығысы",
"performanceOverlay": "Өнімділік панелі",
"audioPassthrough": "Дыбысты тікелей өткізу",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Көлемді дыбыс",
-1
View File
@@ -1641,7 +1641,6 @@
"hdr": "HDR",
"audioOutput": "오디오 출력",
"performanceOverlay": "성능 오버레이",
"audioPassthrough": "오디오 패스스루",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "서라운드",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Lydutgang",
"performanceOverlay": "Ytelsesoverlegg",
"audioPassthrough": "Direkte lydutgang",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Audio-uitvoer",
"performanceOverlay": "Prestatie-overlay",
"audioPassthrough": "Audio-doorvoer",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
-1
View File
@@ -1668,7 +1668,6 @@
"hdr": "HDR",
"audioOutput": "Wyjście audio",
"performanceOverlay": "Nakładka wydajności",
"audioPassthrough": "Przekazywanie dźwięku",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Przestrzenny",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Saída de áudio",
"performanceOverlay": "Painel de desempenho",
"audioPassthrough": "Passagem direta de áudio",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
-1
View File
@@ -1668,7 +1668,6 @@
"hdr": "HDR",
"audioOutput": "Аудиовыход",
"performanceOverlay": "Оверлей производительности",
"audioPassthrough": "Сквозной вывод аудио",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Объёмный звук",
+1 -1
View File
@@ -4,7 +4,7 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 22
/// Strings: 32759 (1489 per locale)
/// Strings: 32737 (1488 per locale)
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import
-2
View File
@@ -1528,7 +1528,6 @@ class _Translations$videoSettings$az extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Səs çıxışı';
@override String get performanceOverlay => 'Məhsuldarlıq paneli';
@override String get audioPassthrough => 'Səsin birbaşa ötürülməsi';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Əhatəli səs';
@@ -3440,7 +3439,6 @@ extension on TranslationsAz {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Səs çıxışı',
'videoSettings.performanceOverlay' => 'Məhsuldarlıq paneli',
'videoSettings.audioPassthrough' => 'Səsin birbaşa ötürülməsi',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Əhatəli səs',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$bg extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Аудио изход';
@override String get performanceOverlay => 'Оверлей за производителност';
@override String get audioPassthrough => 'Директно предаване на аудио';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Съраунд';
@@ -3418,7 +3417,6 @@ extension on TranslationsBg {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Аудио изход',
'videoSettings.performanceOverlay' => 'Оверлей за производителност',
'videoSettings.audioPassthrough' => 'Директно предаване на аудио',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Съраунд',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$da extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Lydoutput';
@override String get performanceOverlay => 'Ydelsesoverlay';
@override String get audioPassthrough => 'Lyd-passthrough';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Surround';
@@ -3418,7 +3417,6 @@ extension on TranslationsDa {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Lydoutput',
'videoSettings.performanceOverlay' => 'Ydelsesoverlay',
'videoSettings.audioPassthrough' => 'Lyd-passthrough',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$de extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Audioausgabe';
@override String get performanceOverlay => 'Leistungsanzeige';
@override String get audioPassthrough => 'Audio-Durchleitung';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Surround';
@@ -3418,7 +3417,6 @@ extension on TranslationsDe {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Audioausgabe',
'videoSettings.performanceOverlay' => 'Leistungsanzeige',
'videoSettings.audioPassthrough' => 'Audio-Durchleitung',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
+4 -8
View File
@@ -924,8 +924,8 @@ class Translations$settings$en {
/// en: 'Tunneled Playback'
String get tunneledPlayback => 'Tunneled Playback';
/// en: 'Use video tunneling. Disable if HDR playback shows black video.'
String get tunneledPlaybackDescription => 'Use video tunneling. Disable if HDR playback shows black video.';
/// en: 'Use video tunneling. Disable if HDR playback shows black video or motion stutters.'
String get tunneledPlaybackDescription => 'Use video tunneling. Disable if HDR playback shows black video or motion stutters.';
/// en: 'Audio Passthrough'
String get audioPassthrough => 'Audio Passthrough';
@@ -4133,9 +4133,6 @@ class Translations$videoSettings$en {
/// en: 'Performance Overlay'
String get performanceOverlay => 'Performance Overlay';
/// en: 'Audio Passthrough'
String get audioPassthrough => 'Audio Passthrough';
/// en: 'Dolby Atmos'
String get audioOutputDolbyAtmos => 'Dolby Atmos';
@@ -6373,7 +6370,7 @@ extension on Translations {
'settings.matchDynamicRangeDescription' => 'Switch HDR on for HDR content, then back to SDR',
'settings.displaySwitchDelay' => 'Display Switch Delay',
'settings.tunneledPlayback' => 'Tunneled Playback',
'settings.tunneledPlaybackDescription' => 'Use video tunneling. Disable if HDR playback shows black video.',
'settings.tunneledPlaybackDescription' => 'Use video tunneling. Disable if HDR playback shows black video or motion stutters.',
'settings.audioPassthrough' => 'Audio Passthrough',
'settings.audioPassthroughDescription' => 'Send Dolby/DTS audio to your receiver or TV without re-encoding, preserving surround sound. Turn off if you have no sound.',
'settings.audioPassthroughDescriptionAppleTv' => 'Use Apple\'s native Dolby decoder for Dolby Digital Plus, including Atmos. DTS and TrueHD still play as multichannel PCM. Turn off if you have no sound.',
@@ -7605,7 +7602,6 @@ extension on Translations {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Audio Output',
'videoSettings.performanceOverlay' => 'Performance Overlay',
'videoSettings.audioPassthrough' => 'Audio Passthrough',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
@@ -7643,9 +7639,9 @@ extension on Translations {
'performanceOverlay.maxCll' => 'MaxCLL',
'performanceOverlay.maxFall' => 'MaxFALL',
'performanceOverlay.cacheUsed' => 'Cache Used',
'performanceOverlay.cacheLimit' => 'Cache Limit',
_ => null,
} ?? switch (path) {
'performanceOverlay.cacheLimit' => 'Cache Limit',
'performanceOverlay.speed' => 'Speed',
'performanceOverlay.player' => 'Player',
'performanceOverlay.memory' => 'Memory',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$es extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Salida de audio';
@override String get performanceOverlay => 'Indicador de rendimiento';
@override String get audioPassthrough => 'Transferencia directa de audio';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Envolvente';
@@ -3418,7 +3417,6 @@ extension on TranslationsEs {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Salida de audio',
'videoSettings.performanceOverlay' => 'Indicador de rendimiento',
'videoSettings.audioPassthrough' => 'Transferencia directa de audio',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Envolvente',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$fr extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Sortie audio';
@override String get performanceOverlay => 'Données de performance';
@override String get audioPassthrough => 'Transmission audio directe';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Surround';
@@ -3418,7 +3417,6 @@ extension on TranslationsFr {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Sortie audio',
'videoSettings.performanceOverlay' => 'Données de performance',
'videoSettings.audioPassthrough' => 'Transmission audio directe',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$hu extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Hangkimenet';
@override String get performanceOverlay => 'Teljesítményadatok';
@override String get audioPassthrough => 'Hangtovábbítás (passthrough)';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Térhatású';
@@ -3418,7 +3417,6 @@ extension on TranslationsHu {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Hangkimenet',
'videoSettings.performanceOverlay' => 'Teljesítményadatok',
'videoSettings.audioPassthrough' => 'Hangtovábbítás (passthrough)',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Térhatású',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$it extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Uscita audio';
@override String get performanceOverlay => 'Overlay prestazioni';
@override String get audioPassthrough => 'Passthrough audio';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Surround';
@@ -3418,7 +3417,6 @@ extension on TranslationsIt {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Uscita audio',
'videoSettings.performanceOverlay' => 'Overlay prestazioni',
'videoSettings.audioPassthrough' => 'Passthrough audio',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
-2
View File
@@ -1514,7 +1514,6 @@ class _Translations$videoSettings$ja extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => '音声出力';
@override String get performanceOverlay => 'パフォーマンスオーバーレイ';
@override String get audioPassthrough => 'オーディオパススルー';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'サラウンド';
@@ -3415,7 +3414,6 @@ extension on TranslationsJa {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => '音声出力',
'videoSettings.performanceOverlay' => 'パフォーマンスオーバーレイ',
'videoSettings.audioPassthrough' => 'オーディオパススルー',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'サラウンド',
-2
View File
@@ -1528,7 +1528,6 @@ class _Translations$videoSettings$kk extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Аудио шығысы';
@override String get performanceOverlay => 'Өнімділік панелі';
@override String get audioPassthrough => 'Дыбысты тікелей өткізу';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Көлемді дыбыс';
@@ -3440,7 +3439,6 @@ extension on TranslationsKk {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Аудио шығысы',
'videoSettings.performanceOverlay' => 'Өнімділік панелі',
'videoSettings.audioPassthrough' => 'Дыбысты тікелей өткізу',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Көлемді дыбыс',
-2
View File
@@ -1514,7 +1514,6 @@ class _Translations$videoSettings$ko extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => '오디오 출력';
@override String get performanceOverlay => '성능 오버레이';
@override String get audioPassthrough => '오디오 패스스루';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => '서라운드';
@@ -3415,7 +3414,6 @@ extension on TranslationsKo {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => '오디오 출력',
'videoSettings.performanceOverlay' => '성능 오버레이',
'videoSettings.audioPassthrough' => '오디오 패스스루',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => '서라운드',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$nb extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Lydutgang';
@override String get performanceOverlay => 'Ytelsesoverlegg';
@override String get audioPassthrough => 'Direkte lydutgang';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Surround';
@@ -3418,7 +3417,6 @@ extension on TranslationsNb {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Lydutgang',
'videoSettings.performanceOverlay' => 'Ytelsesoverlegg',
'videoSettings.audioPassthrough' => 'Direkte lydutgang',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$nl extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Audio-uitvoer';
@override String get performanceOverlay => 'Prestatie-overlay';
@override String get audioPassthrough => 'Audio-doorvoer';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Surround';
@@ -3418,7 +3417,6 @@ extension on TranslationsNl {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Audio-uitvoer',
'videoSettings.performanceOverlay' => 'Prestatie-overlay',
'videoSettings.audioPassthrough' => 'Audio-doorvoer',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
-2
View File
@@ -1523,7 +1523,6 @@ class _Translations$videoSettings$pl extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Wyjście audio';
@override String get performanceOverlay => 'Nakładka wydajności';
@override String get audioPassthrough => 'Przekazywanie dźwięku';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Przestrzenny';
@@ -3424,7 +3423,6 @@ extension on TranslationsPl {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Wyjście audio',
'videoSettings.performanceOverlay' => 'Nakładka wydajności',
'videoSettings.audioPassthrough' => 'Przekazywanie dźwięku',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Przestrzenny',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$pt extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Saída de áudio';
@override String get performanceOverlay => 'Painel de desempenho';
@override String get audioPassthrough => 'Passagem direta de áudio';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Surround';
@@ -3418,7 +3417,6 @@ extension on TranslationsPt {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Saída de áudio',
'videoSettings.performanceOverlay' => 'Painel de desempenho',
'videoSettings.audioPassthrough' => 'Passagem direta de áudio',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
-2
View File
@@ -1523,7 +1523,6 @@ class _Translations$videoSettings$ru extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Аудиовыход';
@override String get performanceOverlay => 'Оверлей производительности';
@override String get audioPassthrough => 'Сквозной вывод аудио';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Объёмный звук';
@@ -3424,7 +3423,6 @@ extension on TranslationsRu {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Аудиовыход',
'videoSettings.performanceOverlay' => 'Оверлей производительности',
'videoSettings.audioPassthrough' => 'Сквозной вывод аудио',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Объёмный звук',
-2
View File
@@ -1517,7 +1517,6 @@ class _Translations$videoSettings$sv extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Ljudutgång';
@override String get performanceOverlay => 'Prestandaöverlägg';
@override String get audioPassthrough => 'Ljudgenomströmning';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Surround';
@@ -3418,7 +3417,6 @@ extension on TranslationsSv {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Ljudutgång',
'videoSettings.performanceOverlay' => 'Prestandaöverlägg',
'videoSettings.audioPassthrough' => 'Ljudgenomströmning',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
-2
View File
@@ -1528,7 +1528,6 @@ class _Translations$videoSettings$tr extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Ses Çıkışı';
@override String get performanceOverlay => 'Performans Katmanı';
@override String get audioPassthrough => 'Ses Doğrudan Geçişi';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Çevreleyen Ses';
@@ -3440,7 +3439,6 @@ extension on TranslationsTr {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Ses Çıkışı',
'videoSettings.performanceOverlay' => 'Performans Katmanı',
'videoSettings.audioPassthrough' => 'Ses Doğrudan Geçişi',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Çevreleyen Ses',
-2
View File
@@ -1528,7 +1528,6 @@ class _Translations$videoSettings$uz extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => 'Audio chiqishi';
@override String get performanceOverlay => 'Unumdorlik paneli';
@override String get audioPassthrough => 'Ovozni toʻgʻridan-toʻgʻri oʻtkazish';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => 'Surround';
@@ -3440,7 +3439,6 @@ extension on TranslationsUz {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => 'Audio chiqishi',
'videoSettings.performanceOverlay' => 'Unumdorlik paneli',
'videoSettings.audioPassthrough' => 'Ovozni toʻgʻridan-toʻgʻri oʻtkazish',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => 'Surround',
-2
View File
@@ -1514,7 +1514,6 @@ class Translations$videoSettings$zh extends Translations$videoSettings$en {
@override String get hdr => 'HDR';
@override String get audioOutput => '音频输出';
@override String get performanceOverlay => '性能监控';
@override String get audioPassthrough => '音频直通';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => '环绕声';
@@ -3415,7 +3414,6 @@ extension on TranslationsZh {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => '音频输出',
'videoSettings.performanceOverlay' => '性能监控',
'videoSettings.audioPassthrough' => '音频直通',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => '环绕声',
-2
View File
@@ -1515,7 +1515,6 @@ class _Translations$videoSettings$zh_Hant extends Translations$videoSettings$zh
@override String get hdr => 'HDR';
@override String get audioOutput => '音訊輸出';
@override String get performanceOverlay => '效能監控';
@override String get audioPassthrough => '音訊直通';
@override String get audioOutputDolbyAtmos => 'Dolby Atmos';
@override String get audioOutputDolbyAudio => 'Dolby Audio';
@override String get audioOutputSurround => '環繞聲';
@@ -3416,7 +3415,6 @@ extension on TranslationsZhHant {
'videoSettings.hdr' => 'HDR',
'videoSettings.audioOutput' => '音訊輸出',
'videoSettings.performanceOverlay' => '效能監控',
'videoSettings.audioPassthrough' => '音訊直通',
'videoSettings.audioOutputDolbyAtmos' => 'Dolby Atmos',
'videoSettings.audioOutputDolbyAudio' => 'Dolby Audio',
'videoSettings.audioOutputSurround' => '環繞聲',
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Ljudutgång",
"performanceOverlay": "Prestandaöverlägg",
"audioPassthrough": "Ljudgenomströmning",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Ses Çıkışı",
"performanceOverlay": "Performans Katmanı",
"audioPassthrough": "Ses Doğrudan Geçişi",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Çevreleyen Ses",
-1
View File
@@ -1650,7 +1650,6 @@
"hdr": "HDR",
"audioOutput": "Audio chiqishi",
"performanceOverlay": "Unumdorlik paneli",
"audioPassthrough": "Ovozni toʻgʻridan-toʻgʻri oʻtkazish",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "Surround",
-1
View File
@@ -1641,7 +1641,6 @@
"hdr": "HDR",
"audioOutput": "音訊輸出",
"performanceOverlay": "效能監控",
"audioPassthrough": "音訊直通",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "環繞聲",
-1
View File
@@ -1641,7 +1641,6 @@
"hdr": "HDR",
"audioOutput": "音频输出",
"performanceOverlay": "性能监控",
"audioPassthrough": "音频直通",
"audioOutputDolbyAtmos": "Dolby Atmos",
"audioOutputDolbyAudio": "Dolby Audio",
"audioOutputSurround": "环绕声",
@@ -21,6 +21,12 @@ class PlayerAndroid extends PlayerBase {
int _downmixCenterBoostDb = 0;
bool _downmixNormalize = true;
/// Server-reported frame rate for the next item, or null when unknown.
///
/// Rides on `open` rather than a standalone call because it is per-item and
/// must be known before the native side settles tunneling for that item.
double? _contentFrameRate;
/// The native plugin switched from ExoPlayer to its mpv fallback for this
/// session. Sticky for the instance lifetime, mirroring the native flag
/// (which resets only on initialize/dispose).
@@ -200,6 +206,7 @@ class PlayerAndroid extends PlayerBase {
'hasStartPosition': hasStartPosition,
'autoPlay': play,
'isLive': isLive,
if (_contentFrameRate != null) 'contentFrameRate': _contentFrameRate,
if (externalSubtitles != null && externalSubtitles.isNotEmpty)
'externalSubtitles': externalSubtitles
.where((s) => s.uri?.isNotEmpty == true)
@@ -327,6 +334,10 @@ class PlayerAndroid extends PlayerBase {
case 'tunneled-playback':
_tunnelingEnabled = value != 'no';
break;
case 'content-frame-rate':
final fps = double.tryParse(value);
_contentFrameRate = fps != null && fps > 0 ? fps : null;
break;
case 'dv-conversion-mode':
_dvConversionMode = value;
await _applyWhenInitialized(
@@ -710,6 +710,7 @@ extension _VideoPlayerEpisodeNavigationMethods on VideoPlayerScreenState {
preKnownWidth: displayCriteria?.width ?? 0,
preKnownHeight: displayCriteria?.height ?? 0,
hasVideoUrl: true,
isTranscoding: result.isTranscoding,
ensureAudioFocus: () => currentPlayer.requestAudioFocus(),
);
if (frameRatePlan == null || !isCurrentReload()) {
@@ -182,6 +182,7 @@ extension _VideoPlayerOpenMethods on VideoPlayerScreenState {
required SettingsService settingsService,
required double? preKnownFps,
required bool hasVideoUrl,
required bool isTranscoding,
required Future<void> Function() ensureAudioFocus,
int preKnownWidth = 0,
int preKnownHeight = 0,
@@ -192,6 +193,20 @@ extension _VideoPlayerOpenMethods on VideoPlayerScreenState {
// the two Android backends: mpv needs its decoder refreshed after a
// display switch (pre-load path), ExoPlayer switches pre-open instead.
final isAndroidMpv = currentPlayer.needsDecoderRefreshAfterDisplaySwitch;
// Independent of matchContentFrameRate: ExoPlayer needs the rate even when the
// display never switches, because it also decides whether video tunneling is
// safe for this item. Neither the Matroska nor the MP4 extractor populates
// Format.frameRate, and a tunneled session renders no frames back for the
// native FPS detector, so metadata is the only source.
//
// Source-side only, like _primeDisplayCriteria: a transcode's metadata rate
// describes the original file, not what the server is about to send. "0" clears
// a stale rate carried over from the previous item.
if (Platform.isAndroid && !isAndroidMpv) {
final directPlayFps = isTranscoding ? null : preKnownFps;
await currentPlayer.setProperty('content-frame-rate', (directPlayFps ?? 0).toString());
}
final needsMpvPreLoad = willAutoSwitch && isAndroidMpv && hasVideoUrl;
final needsExoPreOpen = willAutoSwitch && !isAndroidMpv && hasVideoUrl;
plan.needsPostOpenSwitch = willAutoSwitch && !needsMpvPreLoad && !needsExoPreOpen;
@@ -198,6 +198,7 @@ extension _VideoPlayerPlaybackStartMethods on VideoPlayerScreenState {
preKnownWidth: displayCriteria?.width ?? 0,
preKnownHeight: displayCriteria?.height ?? 0,
hasVideoUrl: result.videoUrl != null,
isTranscoding: result.isTranscoding,
ensureAudioFocus: ensureAudioFocus,
);
if (frameRatePlan == null) return;
@@ -632,14 +632,10 @@ class _VideoSettingsSheetState extends State<VideoSettingsSheet> {
},
),
// Audio Passthrough (desktop, Android TV, and Apple TV)
if (PlatformDetector.supportsAudioPassthrough())
_SettingsToggleItem(
pref: SettingsService.audioPassthrough,
icon: Symbols.surround_sound_rounded,
title: t.videoSettings.audioPassthrough,
onAfterWrite: widget.player.setAudioPassthrough,
),
// Audio Passthrough is not here: it configures the audio output route rather
// than this playback, and applying it mid-stream bounces the audio renderer and
// re-decides video tunneling. It lives in Settings > Video Playback next to
// Tunneled Playback, which is applied the same way — at the next player start.
// Dolby playback badge. The Dolby application guide requires the app
// to reflect AVAudioSession.renderingMode; Apple only resolves that