From 72f23ae39fb888905e50bfafe3df491fe6032bad Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Thu, 1 Aug 2024 16:08:31 -0300 Subject: [PATCH 01/29] Add av1 and h265 support --- .../java/com/fgl27/twitch/PlayerActivity.java | 7 +- .../src/main/java/com/fgl27/twitch/Tools.java | 10 ++- app/specific/OSInterface.js | 10 +-- app/specific/Play.js | 74 ++++++++++++++----- app/specific/PlayHLS.js | 4 +- app/specific/PlayVod.js | 4 +- 6 files changed, 75 insertions(+), 34 deletions(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java index b5ce10d69..d695f7b72 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java +++ b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java @@ -1189,9 +1189,14 @@ public void PlayerObjUpdateTrackSelectorParameters(int ParametersPos, Context co .setAllowVideoNonSeamlessAdaptiveness(true) .setExceedAudioConstraintsIfNecessary(true) .setExceedVideoConstraintsIfNecessary(true) + .setAllowVideoMixedMimeTypeAdaptiveness(true) + .setAllowVideoMixedDecoderSupportAdaptiveness(true) + .setViewportSize(//set this to play resolution bigger then current screen resolution + Integer.MAX_VALUE, + Integer.MAX_VALUE, + false) .setExceedRendererCapabilitiesIfNecessary(true) .build(); - } public void PlayerObjUpdateTrackSelector(int PlayerObjPos, int ParametersPos) { diff --git a/apk/app/src/main/java/com/fgl27/twitch/Tools.java b/apk/app/src/main/java/com/fgl27/twitch/Tools.java index b2bcc4d41..fac0ef60a 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/Tools.java +++ b/apk/app/src/main/java/com/fgl27/twitch/Tools.java @@ -649,7 +649,7 @@ static String getQualities(DefaultTrackSelector trackSelector) { Format format; TrackGroup groupIndex = trackGroupArray.get(0); - result.add(new QualitiesObj("Auto", 0, "avc")); + result.add(new QualitiesObj("Auto", 0, "Auto")); for (int trackIndex = 0; trackIndex < groupIndex.length; trackIndex++) { format = groupIndex.getFormat(trackIndex); @@ -712,9 +712,11 @@ static String GetVideoQuality(Format format) { private static String extractCodec(String codec) { if (codec == null) return ""; - else if (codec.contains("avc")) return " | avc"; - else if (codec.contains("vp9")) return " | vp9"; - else if (codec.contains("mp4a")) return " | mp4"; + else if (codec.contains("avc")) return " | AVC"; + else if (codec.contains("vp9")) return " | VP9"; + else if (codec.contains("hvc")) return " | HECV"; + else if (codec.contains("av01")) return " | AV1"; + else if (codec.contains("mp4a")) return " | MP4"; return ""; } diff --git a/app/specific/OSInterface.js b/app/specific/OSInterface.js index 32dbfddae..ee35c0ada 100644 --- a/app/specific/OSInterface.js +++ b/app/specific/OSInterface.js @@ -323,7 +323,7 @@ function OSInterface_RestartPlayer(who_called, ResumePosition, player) { //Android specific: false in the OS has multi player supports Samsung TV for example don't have //Sets mediaSources and start the player function OSInterface_StartAuto(uri, mainPlaylistString, who_called, ResumePosition, player) { - if (who_called === 1) { + if (who_called === 1 || who_called === 2) { mainPlaylistString = Play_FixQualities(mainPlaylistString); } @@ -339,7 +339,7 @@ function OSInterface_StartAuto(uri, mainPlaylistString, who_called, ResumePositi //Android specific: false in the OS has multi player supports Samsung TV for example don't have //Sets mediaSources and start the player function OSInterface_ReuseFeedPlayer(uri, mainPlaylistString, who_called, ResumePosition, player) { - if (who_called === 1) { + if (who_called === 1 || who_called === 2) { mainPlaylistString = Play_FixQualities(mainPlaylistString); } @@ -769,9 +769,7 @@ function OSInterface_SetPreviewOthersAudio(volume) { //Android specific: true //Start MultiStream at position function OSInterface_StartFeedPlayer(uri, mainPlaylistString, position, resumePosition, isVod) { - if (!isVod) { - mainPlaylistString = Play_FixQualities(mainPlaylistString); - } + mainPlaylistString = Play_FixQualities(mainPlaylistString); Android.StartFeedPlayer(uri, mainPlaylistString, position, resumePosition, Boolean(isVod)); } @@ -815,7 +813,7 @@ function OSInterface_SetPlayerViewSidePanel(bottom, right, left, web_height) { //Android specific: true //Start MultiStream at position function OSInterface_StartScreensPlayer(uri, mainPlaylistString, ResumePosition, bottom, right, left, web_height, who_called) { - if (who_called === 1) { + if (who_called === 1 || who_called === 2) { mainPlaylistString = Play_FixQualities(mainPlaylistString); } diff --git a/app/specific/Play.js b/app/specific/Play.js index 5ef1fd06a..cedec808f 100644 --- a/app/specific/Play.js +++ b/app/specific/Play.js @@ -965,12 +965,20 @@ function Play_getQualities(Who_Called, skipchange) { if (!Main_IsOn_OSInterface) return; var baseQualities = OSInterface_getQualities(); + var result; if (baseQualities) { Play_getQualitiesFail = false; result = JSON.parse(baseQualities); + result.sort(function (a, b) { + if (!a || !b) { + return 0; + } + return parseInt(b.id.split('p')[0]) - parseInt(a.id.split('p')[0]); + }); + if (result.length > 1) { result[1].id += ' | source'; } @@ -1033,6 +1041,7 @@ function Play_FixQualities(input) { if (qualities.length && qualities[0].truebitrate) { input = input.replace(qualities[0].bitrate, qualities[0].truebitrate); } + return input; } @@ -1042,37 +1051,59 @@ function Play_extractQualities(input) { marray, marray2, Regexp = /#EXT-X-MEDIA:(.)*\n#EXT-X-STREAM-INF:(.)*\n(.)*/g, - Regexp2 = /NAME="(.+?)".*BANDWIDTH=(\d+).*CODECS="(.+?)".*(http(.*))/g; + Regexp2 = /NAME="(.+?)".*BANDWIDTH=(\d+).*CODECS="(.+?)".*(http(.*))/g, + id; while ((marray = Regexp.exec(input))) { while ((marray2 = Regexp2.exec(marray[0].replace(/(\r\n|\n|\r)/gm, '')))) { + id = marray2[1]; + if (!result.length) { - if (!Main_A_includes_B(marray2[1], 'ource')) { - marray2[1] = marray2[1] + ' | ' + STR_SOURCE; - } else if (marray2[1]) { + //Live stream may have source word in it + if (Main_A_includes_B(marray2[1], 'ource')) { marray2[1] = marray2[1].replace('(', '| ').replace(')', '').replace('source', STR_SOURCE); } + } + //Prevent duplicated resolution 720p60 source and 720p60 + if (!addedResolution[id]) { result.push({ - id: marray2[1] + Play_extractBand(marray2[2]) + Play_extractCodec(marray2[3]), + id: marray2[1], url: marray2[4], - bitrate: parseInt(marray2[2]) + bitrate: parseInt(marray2[2]), + resolution: parseInt(id.split('p')[0]), + band: Play_extractBand(marray2[2]), + codec: Play_extractCodec(marray2[3]) }); - addedResolution[marray2[1].split(' | ')[0]] = 1; - } else { - //Prevent duplicated resolution 720p60 source and 720p60 - if (!addedResolution[marray2[1]]) { - result.push({ - id: marray2[1] + Play_extractBand(marray2[2]) + Play_extractCodec(marray2[3]), - url: marray2[4], - bitrate: parseInt(marray2[2]) - }); - addedResolution[marray2[1]] = 1; - } + + addedResolution[id] = 1; } } } + //sort base on resolution as it may not come sorted + result.sort(function (a, b) { + if (!a || !b) { + return 0; + } + return b.resolution - a.resolution; + }); + + //some vods dont have the source option + if (!Main_A_includes_B(result[0].id, 'ource')) { + result[0].id += ' | ' + STR_SOURCE; + } + + var i = 0, + len = result.length; + + //remove not needed info from ID + for (i; i < len; i++) { + result[i].id = result[i].id.replace('av1', ''); + result[i].id = result[i].id + result[i].band + result[i].codec; + } + + //Some stream have the wrong bitrate set what causes issue when selecting the best quality on auto playback if (result.length > 1 && result[0].bitrate < result[1].bitrate) { result[0].truebitrate = result[0].bitrate + result[1].bitrate; } @@ -1086,9 +1117,12 @@ function Play_extractBand(input) { } function Play_extractCodec(input) { - if (Main_A_includes_B(input, 'avc')) return ' | avc'; - else if (Main_A_includes_B(input, 'vp9')) return ' | vp9'; - else if (Main_A_includes_B(input, 'mp4')) return ' | mp4'; + if (Main_A_includes_B(input, 'avc')) return ' | AVC'; + else if (Main_A_includes_B(input, 'vp9')) return ' | VP9'; + else if (Main_A_includes_B(input, 'hvc')) return ' | HEVC'; + else if (Main_A_includes_B(input, 'av01')) return ' | AV1'; + else if (Main_A_includes_B(input, 'mp4')) return ' | MP4'; + return ''; } diff --git a/app/specific/PlayHLS.js b/app/specific/PlayHLS.js index 351d05aef..0db1acabd 100644 --- a/app/specific/PlayHLS.js +++ b/app/specific/PlayHLS.js @@ -28,7 +28,7 @@ var Play_live_token = ' videoPlaybackAccessToken(id: $vodID, params: {platform: $platform, playerBackend: \\"mediaplayer\\", playerType: $playerType}) @include(if: $isVod) { value signature __typename }}",' + '"variables":{"isLive":true,"login":"%x","isVod":false,"vodID":"","playerType":"pulsar","platform":"switch_web_tv"}}'; var Play_base_live_links = - 'player_backend=mediaplayer&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&fast_bread=false&cdm=wv&acmb=e30%3D&p=%p&play_session_id=%i&player_version=1.13.0'; + 'player_backend=mediaplayer&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&fast_bread=false&cdm=wv&acmb=e30%3D&p=%p&play_session_id=%i&player_version=1.13.0&supported_codecs=av1,h265,h264'; var Play_original_live_links = 'https://usher.ttvnw.net/api/channel/hls/'; @@ -55,7 +55,7 @@ var proxy_fail_counter_checker = 0; var Play_vod_token_prop = 'videoPlaybackAccessToken'; var Play_vod_token = '{"query":"{videoPlaybackAccessToken(id:\\"%x\\", params:{platform:\\"android\\",playerType:\\"mobile\\"}){value signature}}"}'; var Play_vod_links = - 'https://usher.ttvnw.net/vod/%x.m3u8?&nauth=%t&nauthsig=%s&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&cdm=wv&p=%d'; + 'https://usher.ttvnw.net/vod/%x.m3u8?&nauth=%t&nauthsig=%s&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&cdm=wv&p=%d&supported_codecs=av1,h265,h264'; function PlayHLS_GetPlayListAsync(isLive, Channel_or_VOD_Id, CheckId_y, CheckId_x, callBackSuccess) { // console.log('isLive', isLive); diff --git a/app/specific/PlayVod.js b/app/specific/PlayVod.js index d99af56c1..50d132e11 100644 --- a/app/specific/PlayVod.js +++ b/app/specific/PlayVod.js @@ -846,7 +846,9 @@ function PlayVod_qualityIndexReset() { } } - if (PlayVod_qualities[PlayVod_qualityIndex]) Play_qualityTitleReset(PlayVod_qualities[PlayVod_qualityIndex].id); + if (PlayVod_qualities[PlayVod_qualityIndex]) { + Play_qualityTitleReset(PlayVod_qualities[PlayVod_qualityIndex].id); + } } function PlayVod_SetHtmlQuality(element) { From 53202a17798e52e8ee32cc5543f8aad59bbacc14 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Thu, 1 Aug 2024 16:29:50 -0300 Subject: [PATCH 02/29] add settings to enable extra codecs --- .../src/main/java/com/fgl27/twitch/Tools.java | 2 +- app/languages/0_Strings.js | 4 ++ app/languages/en_US.js | 6 ++ app/specific/PlayHLS.js | 8 ++- app/specific/Settings.js | 56 +++++++++++++++++++ 5 files changed, 73 insertions(+), 3 deletions(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/Tools.java b/apk/app/src/main/java/com/fgl27/twitch/Tools.java index fac0ef60a..8e471f7db 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/Tools.java +++ b/apk/app/src/main/java/com/fgl27/twitch/Tools.java @@ -714,7 +714,7 @@ private static String extractCodec(String codec) { if (codec == null) return ""; else if (codec.contains("avc")) return " | AVC"; else if (codec.contains("vp9")) return " | VP9"; - else if (codec.contains("hvc")) return " | HECV"; + else if (codec.contains("hvc")) return " | HEVC"; else if (codec.contains("av01")) return " | AV1"; else if (codec.contains("mp4a")) return " | MP4"; diff --git a/app/languages/0_Strings.js b/app/languages/0_Strings.js index fcb9e5cee..f90e0c4dd 100644 --- a/app/languages/0_Strings.js +++ b/app/languages/0_Strings.js @@ -765,3 +765,7 @@ var STR_USER_TOKEN_ERROR; var STR_REFRESH_PROBLEM_ENTER_LANG; var STR_PASS_MATURE_ENABLED; var STR_WRONG_PASS; +var STR_PLAYER_EXTRA_CODEC; +var STR_PLAYER_EXTRA_CODEC_SUMMARY; +var STR_PLAYER_CODEC_AV1; +var STR_PLAYER_CODEC_HEVC; diff --git a/app/languages/en_US.js b/app/languages/en_US.js index 53bbf9fd2..439ee87fc 100644 --- a/app/languages/en_US.js +++ b/app/languages/en_US.js @@ -877,4 +877,10 @@ function en_USLang() { STR_WRONG_PASS = 'Wrong password!'; STR_PASS_MATURE_ENABLED = 'Mature content is enabled, old password deleted'; + + STR_PLAYER_EXTRA_CODEC = 'Extra codec support'; + STR_PLAYER_EXTRA_CODEC_SUMMARY = 'Beta codec support that are is being tested by Twitch'; + + STR_PLAYER_CODEC_AV1 = 'AV1 support'; + STR_PLAYER_CODEC_HEVC = 'HEVC support'; } diff --git a/app/specific/PlayHLS.js b/app/specific/PlayHLS.js index 0db1acabd..ac6c6d115 100644 --- a/app/specific/PlayHLS.js +++ b/app/specific/PlayHLS.js @@ -21,6 +21,8 @@ //To pass to Java var Play_Headers; //Live +var play_ExtraCodecsValues; + var Play_live_token_prop = 'streamPlaybackAccessToken'; var Play_live_token = '{"operationName":"PlaybackAccessToken_Template","query":"query PlaybackAccessToken_Template($login: String!, $isLive: Boolean!, $vodID: ID!, $isVod: Boolean!, $playerType: String!, $platform: String!) ' + @@ -28,7 +30,8 @@ var Play_live_token = ' videoPlaybackAccessToken(id: $vodID, params: {platform: $platform, playerBackend: \\"mediaplayer\\", playerType: $playerType}) @include(if: $isVod) { value signature __typename }}",' + '"variables":{"isLive":true,"login":"%x","isVod":false,"vodID":"","playerType":"pulsar","platform":"switch_web_tv"}}'; var Play_base_live_links = - 'player_backend=mediaplayer&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&fast_bread=false&cdm=wv&acmb=e30%3D&p=%p&play_session_id=%i&player_version=1.13.0&supported_codecs=av1,h265,h264'; + 'player_backend=mediaplayer&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&fast_bread=false&cdm=wv&acmb=e30%3D&p=%p&play_session_id=%i&player_version=1.13.0&supported_codecs=' + + play_ExtraCodecsValues; var Play_original_live_links = 'https://usher.ttvnw.net/api/channel/hls/'; @@ -55,7 +58,8 @@ var proxy_fail_counter_checker = 0; var Play_vod_token_prop = 'videoPlaybackAccessToken'; var Play_vod_token = '{"query":"{videoPlaybackAccessToken(id:\\"%x\\", params:{platform:\\"android\\",playerType:\\"mobile\\"}){value signature}}"}'; var Play_vod_links = - 'https://usher.ttvnw.net/vod/%x.m3u8?&nauth=%t&nauthsig=%s&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&cdm=wv&p=%d&supported_codecs=av1,h265,h264'; + 'https://usher.ttvnw.net/vod/%x.m3u8?&nauth=%t&nauthsig=%s&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&cdm=wv&p=%d&supported_codecs=' + + play_ExtraCodecsValues; function PlayHLS_GetPlayListAsync(isLive, Channel_or_VOD_Id, CheckId_y, CheckId_x, callBackSuccess) { // console.log('isLive', isLive); diff --git a/app/specific/Settings.js b/app/specific/Settings.js index 875134f87..a1240c6e8 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -103,6 +103,16 @@ var Settings_value = { values: ['no', 'yes'], defaultValue: 2 }, + av1_codec: { + //Migrated to dialog + values: ['no', 'yes'], + defaultValue: 1 + }, + hevc_codec: { + //Migrated to dialog + values: ['no', 'yes'], + defaultValue: 1 + }, ttv_lolProxy: { //Migrated to dialog values: ['no', 'yes'], @@ -446,6 +456,11 @@ var Settings_value = { set_values: [''], defaultValue: 1 }, + player_extracodecs: { + values: ['None'], + set_values: [''], + defaultValue: 1 + }, player_bitrate: { values: ['None'], set_values: [''], @@ -859,6 +874,7 @@ function Settings_SetSettings() { //Dialog settings //div += Settings_Content('proxy_settings', [STR_ENTER_TO_OPEN], PROXY_SETTINGS, null); + div += Settings_Content('player_extracodecs', [STR_ENTER_TO_OPEN], STR_PLAYER_EXTRA_CODEC, STR_PLAYER_EXTRA_CODEC_SUMMARY); div += Settings_Content('player_bitrate', [STR_ENTER_TO_OPEN], STR_PLAYER_BITRATE, STR_PLAYER_BITRATE_SUMMARY); div += Settings_Content('block_qualities', [STR_ENTER_TO_OPEN], STR_BLOCK_RES, STR_BLOCK_RES_SUMMARY); div += Settings_Content('blocked_codecs', [STR_ENTER_TO_OPEN], STR_BLOCKED_CODEC, STR_BLOCKED_CODEC_SUMMARY); @@ -993,6 +1009,7 @@ function Settings_SetDefaults() { } Settings_SetBuffers(0); + Settings_ExtraCodecs(0); Settings_SetClock(); Settings_HideMainClock(); Settings_HidePlayerClock(); @@ -1257,6 +1274,8 @@ function Settings_SetDefault(position) { else if (position === 'key_up_timeout') Screens_KeyUptimeout = Settings_Obj_values('key_up_timeout'); else if (position === 'buffer_vod') Settings_SetBuffers(2); else if (position === 'buffer_clip') Settings_SetBuffers(3); + else if (position === 'av1_codec') Settings_ExtraCodecs(); + else if (position === 'hevc_codec') Settings_ExtraCodecs(); else if (position === 'end_dialog_counter') Play_EndSettingsCounter = Settings_Obj_default('end_dialog_counter'); else if (position === 'default_quality') Play_SetQuality(); else if (position === 'seek_preview') PlayVod_SetPreviewType(); @@ -1703,6 +1722,21 @@ function Settings_SetResBitRateMin() { OSInterface_SetSmallPlayerBitrate(bitrate, resolution); } +function Settings_ExtraCodecs() { + var ExtraCodecsValuesArray = []; + + if (Settings_Obj_default('av1_codec')) { + ExtraCodecsValuesArray.push('av1'); + } + if (Settings_Obj_default('hevc_codec')) { + ExtraCodecsValuesArray.push('h265'); + } + + ExtraCodecsValuesArray.push('h264'); + + play_ExtraCodecsValues = ExtraCodecsValuesArray.join(','); +} + function Settings_SetBuffers(whocall) { if (!whocall) { Play_Buffer = Settings_Obj_values('buffer_live') * 1000; @@ -1907,6 +1941,7 @@ function Settings_KeyEnter(click) { if (Main_A_includes_B(Settings_value_keys[Settings_cursorY], 'playerend_opt')) Settings_PlayerEnd(click); else if (Main_A_includes_B(Settings_value_keys[Settings_cursorY], 'blocked_codecs')) Settings_CodecsShow(click); else if (Main_A_includes_B(Settings_value_keys[Settings_cursorY], 'player_buffers')) Settings_DialogShowBuffer(click); + else if (Main_A_includes_B(Settings_value_keys[Settings_cursorY], 'player_extracodecs')) Settings_DialogShowExtraCodecs(click); else if (Main_A_includes_B(Settings_value_keys[Settings_cursorY], 'player_bitrate')) Settings_DialogShowBitrate(click); else if (Main_A_includes_B(Settings_value_keys[Settings_cursorY], 'proxy_settings')) Settings_DialogShowProxy(click); else if (Main_A_includes_B(Settings_value_keys[Settings_cursorY], 'vod_seek')) Settings_vod_seek(click); @@ -2256,6 +2291,27 @@ function Settings_DialogShowProxy(click) { Settings_DialogShow(obj, PROXY_SETTINGS + STR_BR + STR_BR + PROXY_SETTINGS_SUMMARY, click); } +function Settings_DialogShowExtraCodecs(click) { + var array_no_yes = [STR_NO, STR_YES]; + Settings_value.av1_codec.values = array_no_yes; + Settings_value.hevc_codec.values = array_no_yes; + + var obj = { + av1_codec: { + defaultValue: Settings_value.av1_codec.defaultValue, + values: Settings_value.av1_codec.values, + title: STR_PLAYER_CODEC_AV1 + }, + hevc_codec: { + defaultValue: Settings_value.hevc_codec.defaultValue, + values: Settings_value.hevc_codec.values, + title: STR_PLAYER_CODEC_HEVC + } + }; + + Settings_DialogShow(obj, STR_PLAYER_EXTRA_CODEC + STR_BR + STR_BR + STR_PLAYER_EXTRA_CODEC_SUMMARY, click); +} + function Settings_DialogShowBitrate(click) { Settings_value.res_max.values[0] = STR_PLAYER_BITRATE_UNLIMITED; Settings_value.res_min.values[0] = STR_PLAYER_BITRATE_UNLIMITED; From c439cd6704da7dd3483cd5d1ab3e9c09af3d628b Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Thu, 1 Aug 2024 16:49:24 -0300 Subject: [PATCH 03/29] clean up --- app/specific/PlayHLS.js | 13 +++++++------ app/specific/Settings.js | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/specific/PlayHLS.js b/app/specific/PlayHLS.js index ac6c6d115..c22e51c21 100644 --- a/app/specific/PlayHLS.js +++ b/app/specific/PlayHLS.js @@ -30,8 +30,7 @@ var Play_live_token = ' videoPlaybackAccessToken(id: $vodID, params: {platform: $platform, playerBackend: \\"mediaplayer\\", playerType: $playerType}) @include(if: $isVod) { value signature __typename }}",' + '"variables":{"isLive":true,"login":"%x","isVod":false,"vodID":"","playerType":"pulsar","platform":"switch_web_tv"}}'; var Play_base_live_links = - 'player_backend=mediaplayer&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&fast_bread=false&cdm=wv&acmb=e30%3D&p=%p&play_session_id=%i&player_version=1.13.0&supported_codecs=' + - play_ExtraCodecsValues; + 'player_backend=mediaplayer&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&fast_bread=false&cdm=wv&acmb=e30%3D&p=%p&play_session_id=%i&player_version=1.13.0&supported_codecs=%c'; var Play_original_live_links = 'https://usher.ttvnw.net/api/channel/hls/'; @@ -58,8 +57,7 @@ var proxy_fail_counter_checker = 0; var Play_vod_token_prop = 'videoPlaybackAccessToken'; var Play_vod_token = '{"query":"{videoPlaybackAccessToken(id:\\"%x\\", params:{platform:\\"android\\",playerType:\\"mobile\\"}){value signature}}"}'; var Play_vod_links = - 'https://usher.ttvnw.net/vod/%x.m3u8?&nauth=%t&nauthsig=%s&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&cdm=wv&p=%d&supported_codecs=' + - play_ExtraCodecsValues; + 'https://usher.ttvnw.net/vod/%x.m3u8?nauth=%t&nauthsig=%s&reassignments_supported=true&playlist_include_framerate=true&allow_source=true&cdm=wv&p=%d&supported_codecs=%c'; function PlayHLS_GetPlayListAsync(isLive, Channel_or_VOD_Id, CheckId_y, CheckId_x, callBackSuccess) { // console.log('isLive', isLive); @@ -157,7 +155,9 @@ function PlayHLS_GetPlayListUrl(isLive, Channel_or_VOD_Id, Token, Sig, useProxy) if (isLive) { var randomId = parseInt(Math.random() * 10000000000000000); var randomInt = parseInt(Math.random() * 100000000); - var URL_parameters = Play_base_live_links.replace('%p', randomInt).replace('%i', randomId + '' + randomId); + var URL_parameters = Play_base_live_links.replace('%p', randomInt) + .replace('%i', randomId + '' + randomId) + .replace('%c', play_ExtraCodecsValues); if (useProxy) { headers = proxy_headers; @@ -174,7 +174,8 @@ function PlayHLS_GetPlayListUrl(isLive, Channel_or_VOD_Id, Token, Sig, useProxy) url = Play_vod_links.replace('%x', Channel_or_VOD_Id) .replace('%t', encodeURIComponent(Token)) .replace('%s', Sig) - .replace('%d', Math.random() * 100000); + .replace('%d', Math.random() * 100000) + .replace('%c', play_ExtraCodecsValues); } return {url: url, headers: headers}; diff --git a/app/specific/Settings.js b/app/specific/Settings.js index a1240c6e8..cc2191714 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -1009,7 +1009,7 @@ function Settings_SetDefaults() { } Settings_SetBuffers(0); - Settings_ExtraCodecs(0); + Settings_ExtraCodecs(); Settings_SetClock(); Settings_HideMainClock(); Settings_HidePlayerClock(); From d7763eadcf99d8f1f26ee6e85d0962bca96cdb9d Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Thu, 1 Aug 2024 17:39:53 -0300 Subject: [PATCH 04/29] build av1 lib --- apk/.idea/vcs.xml | 3 +++ apk/app/build.gradle | 1 + apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java | 2 +- apk/gradle.properties | 4 ++++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apk/.idea/vcs.xml b/apk/.idea/vcs.xml index ae601933c..466d8998f 100644 --- a/apk/.idea/vcs.xml +++ b/apk/.idea/vcs.xml @@ -3,5 +3,8 @@ + + + \ No newline at end of file diff --git a/apk/app/build.gradle b/apk/app/build.gradle index 33d8975ed..f115aee87 100644 --- a/apk/app/build.gradle +++ b/apk/app/build.gradle @@ -79,6 +79,7 @@ dependencies { implementation project(':media-lib-exoplayer') implementation project(':media-lib-ui') implementation project(':media-lib-exoplayer-hls') + implementation project(':media-lib-decoder-av1') //Crashlytics implementation platform('com.google.firebase:firebase-bom:33.1.2') diff --git a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java index d695f7b72..2fbf59d18 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java +++ b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java @@ -608,7 +608,7 @@ private void SetupPlayer(int PlayerObjPosition) { if (BLACKLISTED_CODECS != null) renderersFactory.setMediaCodecSelector(BLACKLISTED_CODECS); - PlayerObj[PlayerObjPosition].player = new ExoPlayer.Builder(this, renderersFactory) + PlayerObj[PlayerObjPosition].player = new ExoPlayer.Builder(this, renderersFactory.setEnableDecoderFallback(true).setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)) .setTrackSelector(PlayerObj[PlayerObjPosition].trackSelector) .setLoadControl( Tools.getLoadControl( diff --git a/apk/gradle.properties b/apk/gradle.properties index b3ce74f9b..2813f3d1c 100644 --- a/apk/gradle.properties +++ b/apk/gradle.properties @@ -22,3 +22,7 @@ android.useAndroidX=true android.enableJetifier=true android.jetifier.ignorelist=bcprov-jdk15on org.gradle.configuration-cache=true + +#Platform version 19 is unsupported by this NDK. Please change minSdk to at least 21 to avoid undefined behavior. +#Android TV only suports 21 and up also the app does that +android.ndk.suppressMinSdkVersionError=21 From 50dec841021f00c4142effeffe86bbef135f7dc8 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Thu, 1 Aug 2024 17:42:56 -0300 Subject: [PATCH 05/29] don't build av1 for now --- apk/app/build.gradle | 2 +- apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apk/app/build.gradle b/apk/app/build.gradle index f115aee87..d15d2f736 100644 --- a/apk/app/build.gradle +++ b/apk/app/build.gradle @@ -79,7 +79,7 @@ dependencies { implementation project(':media-lib-exoplayer') implementation project(':media-lib-ui') implementation project(':media-lib-exoplayer-hls') - implementation project(':media-lib-decoder-av1') + //implementation project(':media-lib-decoder-av1') //Crashlytics implementation platform('com.google.firebase:firebase-bom:33.1.2') diff --git a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java index 2fbf59d18..d695f7b72 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java +++ b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java @@ -608,7 +608,7 @@ private void SetupPlayer(int PlayerObjPosition) { if (BLACKLISTED_CODECS != null) renderersFactory.setMediaCodecSelector(BLACKLISTED_CODECS); - PlayerObj[PlayerObjPosition].player = new ExoPlayer.Builder(this, renderersFactory.setEnableDecoderFallback(true).setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)) + PlayerObj[PlayerObjPosition].player = new ExoPlayer.Builder(this, renderersFactory) .setTrackSelector(PlayerObj[PlayerObjPosition].trackSelector) .setLoadControl( Tools.getLoadControl( From 7408df6c54a8f0e313f98e652ccc9e0fca9b6a34 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Thu, 1 Aug 2024 17:59:54 -0300 Subject: [PATCH 06/29] Update en_US.js --- app/languages/en_US.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/languages/en_US.js b/app/languages/en_US.js index 439ee87fc..32b7432b1 100644 --- a/app/languages/en_US.js +++ b/app/languages/en_US.js @@ -879,7 +879,7 @@ function en_USLang() { STR_PASS_MATURE_ENABLED = 'Mature content is enabled, old password deleted'; STR_PLAYER_EXTRA_CODEC = 'Extra codec support'; - STR_PLAYER_EXTRA_CODEC_SUMMARY = 'Beta codec support that are is being tested by Twitch'; + STR_PLAYER_EXTRA_CODEC_SUMMARY = 'Beta codec support that are being tested by Twitch'; STR_PLAYER_CODEC_AV1 = 'AV1 support'; STR_PLAYER_CODEC_HEVC = 'HEVC support'; From 0ecac71207d8fdd9e2eae2e1440d9c154753542b Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Thu, 1 Aug 2024 22:20:42 -0300 Subject: [PATCH 07/29] improve codec capability and extra codecs support --- .../src/main/java/com/fgl27/twitch/Tools.java | 369 +++++++++++------- app/index.html | 5 + app/languages/0_Strings.js | 4 + app/languages/en_US.js | 14 +- app/specific/Main.js | 12 +- app/specific/Settings.js | 226 +++++++++-- 6 files changed, 452 insertions(+), 178 deletions(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/Tools.java b/apk/app/src/main/java/com/fgl27/twitch/Tools.java index 8e471f7db..ba5c7a4d7 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/Tools.java +++ b/apk/app/src/main/java/com/fgl27/twitch/Tools.java @@ -96,8 +96,10 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Scanner; import java.util.StringTokenizer; @@ -111,21 +113,100 @@ public final class Tools { }.getType(); //https://developer.android.com/reference/android/media/MediaCodecInfo.CodecProfileLevel.html - private static final String[] AvcLevels = { - "1", "1.1", "1.2", "1.3", "1.b", - "2", "2.1", "2.2", - "3", "3.1", "3.2", - "4", "4.1", "4.2", - "5", "5.1", "5.2", - "6", "6.1", "6.2"}; - - private static final Integer[] AvcLevelsEx = { - 1, 4, 8, 16, 2, - 32, 64, 128, - 256, 512, 1024, - 2048, 4096, 8192, - 16384, 32768, 65536, - 131072, 262144, 524288}; + private static final Map AvcLevelsMap = new HashMap() {{ + put(1, "1"); + put(4, "1.1"); + put(8, "1.2"); + put(16, "1.3"); + put(2, "1.b"); + + put(32, "2"); + put(64, "2.1"); + put(128, "2.2"); + + put(256, "3"); + put(512, "3.1"); + put(1024, "3.2"); + + put(2048, "4"); + put(4096, "4.1"); + put(8192, "4.2"); + + put(16384, "5"); + put(32768, "5.1"); + put(65536, "5.2"); + + put(131072, "6"); + put(262144, "6.1"); + put(524288, "6.2"); + }}; + + private static final Map Av1LevelsMap = new HashMap() {{ + put(1, "2"); + put(2, "2.1"); + put(4, "2.2"); + put(8, "2.2"); + + put(16, "3"); + put(32, "3.1"); + put(64, "3.2"); + put(128, "3.3"); + + put(256, "4"); + put(512, "4.1"); + put(1024, "4.2"); + put(2048, "4.3"); + + put(4096, "5"); + put(8192, "5.1"); + put(16384, "5.2"); + put(32768, "5.3"); + + put(65536, "6"); + put(131072, "6.1"); + put(262144, "6.2"); + put(524288, "6.3"); + + put(1048576, "7"); + put(2097152, "7.1"); + put(4194304, "7.2"); + put(8388608, "7.3"); + }}; + + private static final Map HEVCLevelsMap = new HashMap() {{ + put(1, "Main 1"); + put(2, "High 1"); + put(4, "Main 2"); + put(8, "High 2"); + + put(16, "Main 1 2.1"); + put(32, "High 2.1"); + put(64, "Main 3"); + put(128, "High 3"); + + put(256, "Main 3.1"); + put(512, "High 3.1"); + put(1024, "Main 4"); + put(2048, "High 4"); + + put(4096, "Main 4.1"); + put(8192, "High 4.1"); + put(16384, "Main 5"); + put(32768, "High 5"); + + put(65536, "Main 5.1"); + put(131072, "High 5.1"); + put(262144, "Main 5.2"); + put(524288, "High 5.2"); + + put(1048576, "Main 6"); + put(2097152, "High 6"); + put(4194304, "Main 6.1"); + put(8388608, "High 6.1"); + + put(16777216, "Main 6.2"); + put(33554432, "High 6.2"); + }}; private static final Integer[] resolutionsWidth = { 240, @@ -149,21 +230,6 @@ public final class Tools { 2160 }; - public static class ResponseObj { - public final int status; - public final String responseText; - final long checkResult; - final String url; - - ResponseObj(int status, String responseText, long checkResult) { - this.status = status; - this.responseText = responseText; - this.checkResult = checkResult; - this.url = null; - } - - } - static String ResponseObjToString(long checkResult) { return new Gson().toJson( new ResponseObj( @@ -284,27 +350,6 @@ static void closeQuietly(@Nullable Closeable closeable) { } } - @SuppressWarnings({"unused", "FieldCanBeLocal", "RedundantSuppression"}) - private static class CodecList { - private final String type; - private final String name; - private final String maxresolution; - private final String maxbitrate; - private final String maxlevel; - private final int instances; - private final String resolutions; - - CodecList(String type, String name, String maxresolution, String maxbitrate, String maxlevel, int instances, String resolutions) { - this.type = type; - this.name = name; - this.maxresolution = maxresolution; - this.maxbitrate = maxbitrate; - this.maxlevel = maxlevel; - this.instances = instances; - this.resolutions = resolutions; - } - } - //Returns a stringify json obj contain //[{"instances": 32, "maxbitrate": "120 Mbps", "maxlevel": "5.2", "maxresolution": "3840x2176", "name": "OMX.Nvidia.h264.decode", "resolutions": "160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 555 fps | 1080p : 245 fps | 1440p : 138 fps | 2160p : 61 fps", "type": "video/avc"}, {"instances": 32, "maxbitrate": "48 Mbps", "maxlevel": "5.2", "maxresolution": "4080x4080", "name": "OMX.google.h264.decoder", "resolutions": "160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps", "type": "video/avc"}] static String codecCapabilities(String CodecType) { @@ -312,6 +357,8 @@ static String codecCapabilities(String CodecType) { int UperWidth; int instances; + int position; + String maxlevel; String resolutions; @@ -324,16 +371,26 @@ static String codecCapabilities(String CodecType) { MediaCodecInfo.CodecCapabilities codecCapabilities = codec.getCapabilitiesForType(type); MediaCodecInfo.VideoCapabilities videoCapabilities = codecCapabilities.getVideoCapabilities(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { instances = codecCapabilities.getMaxSupportedInstances(); - else instances = -1; + } else { + instances = -1; + } MediaCodecInfo.CodecProfileLevel[] profile = codecCapabilities.profileLevels; + position = profile[profile.length - 1].level; - if (CodecType.contains("avc")) { //check avc arrays others codecs current not used + if (CodecType.contains("avc")) { - int position = Arrays.asList(AvcLevelsEx).indexOf(profile[profile.length - 1].level); - maxlevel = (position > 0) ? AvcLevels[position] : "Unknown level " + profile[profile.length - 1].level; + maxlevel = AvcLevelsMap.containsKey(position) ? AvcLevelsMap.get(position) : "Unknown level " + profile[profile.length - 1].level; + + } else if (CodecType.contains("av1")) { + + maxlevel = Av1LevelsMap.containsKey(position) ? Av1LevelsMap.get(position) : "Unknown level " + profile[profile.length - 1].level; + + } else if (CodecType.contains("hevc")) { + + maxlevel = HEVCLevelsMap.containsKey(position) ? HEVCLevelsMap.get(position) : "Unknown level " + profile[profile.length - 1].level; } else { maxlevel = String.format( @@ -590,15 +647,6 @@ static boolean WR_storage(Context context) { } else return true; } - //https://exoplayer.dev/shrinking.html - private static class Mp4ExtractorsFactory implements ExtractorsFactory { - @Override - @NonNull - public Extractor[] createExtractors() { - return new Extractor[]{new Mp4Extractor(SubtitleParser.Factory.UNSUPPORTED, /* flags= */ FLAG_EMIT_RAW_SUBTITLE_DATA)}; - } - } - private static MediaItem MediaItemBuilder(Uri uri) { return new MediaItem.Builder().setUri(uri).build(); } @@ -675,20 +723,6 @@ static String getQualities(DefaultTrackSelector trackSelector) { return null; } - @SuppressWarnings({"unused", "FieldCanBeLocal", "RedundantSuppression"}) - private static class QualitiesObj { - private final String id; - private final String band; - private final String codec; - - QualitiesObj(String id, int band, String codec) { - this.id = id; - this.band = extractBand(band); - this.codec = extractCodec(codec); - } - - } - private static String extractBand(int band) { return band > 0 ? String.format(Locale.US, " | %.02fMbps", ((float) band / 1000000)) : ""; } @@ -881,65 +915,6 @@ private static boolean deleteDir(File dir) { } } -// static void checkTokens(String UserId, AppPreferences appPreferences) { -// String token = getString(UserId + Constants.PREF_ACCESS_TOKEN, null, appPreferences); -// -// try { -// String urlString = "https://id.twitch.tv/oauth2/validate"; -// -// String[][] HEADERS = { -// {Constants.BASE_HEADERS[1][0], token} -// }; -// -// JsonObject obj; -// int status; -// ResponseObj response; -// -// for (int i = 0; i < 3; i++) { -// -// response = -// Internal_MethodUrl( -// urlString, -// Constants.DEFAULT_HTTP_TIMEOUT + (Constants.DEFAULT_HTTP_EXTRA_TIMEOUT * i), -// null, -// null, -// 0, -// HEADERS -// ); -// -// if (response != null) { -// -// status = response.status; -// -// if (status == 200) { -// obj = parseString(response.responseText).getAsJsonObject(); -// -// if (obj.has("expires_in") && obj.get("expires_in").isJsonNull()) { -// -// appPreferences.put( -// UserId + Constants.PREF_TOKEN_EXPIRES_WHEN, -// (System.currentTimeMillis() + ((obj.get("expires_in").getAsLong() - 100) * 1000)) -// ); -// -// } -// break; -// } else if (status == 401 || status == 403) { -// -// refreshTokens( -// UserId, -// appPreferences -// ); -// break; -// } -// -// } -// -// } -// } catch (Exception e) { -// recordException(TAG, "checkTokens e ", e); -// } -// } - public static boolean hasTokens(String UserId, AppPreferences appPreferences) { return Tools.getString(UserId + Constants.PREF_ACCESS_TOKEN, null, appPreferences) != null; } @@ -1062,6 +1037,65 @@ public static void recordException(String TAG, String message, Throwable e) { } +// static void checkTokens(String UserId, AppPreferences appPreferences) { +// String token = getString(UserId + Constants.PREF_ACCESS_TOKEN, null, appPreferences); +// +// try { +// String urlString = "https://id.twitch.tv/oauth2/validate"; +// +// String[][] HEADERS = { +// {Constants.BASE_HEADERS[1][0], token} +// }; +// +// JsonObject obj; +// int status; +// ResponseObj response; +// +// for (int i = 0; i < 3; i++) { +// +// response = +// Internal_MethodUrl( +// urlString, +// Constants.DEFAULT_HTTP_TIMEOUT + (Constants.DEFAULT_HTTP_EXTRA_TIMEOUT * i), +// null, +// null, +// 0, +// HEADERS +// ); +// +// if (response != null) { +// +// status = response.status; +// +// if (status == 200) { +// obj = parseString(response.responseText).getAsJsonObject(); +// +// if (obj.has("expires_in") && obj.get("expires_in").isJsonNull()) { +// +// appPreferences.put( +// UserId + Constants.PREF_TOKEN_EXPIRES_WHEN, +// (System.currentTimeMillis() + ((obj.get("expires_in").getAsLong() - 100) * 1000)) +// ); +// +// } +// break; +// } else if (status == 401 || status == 403) { +// +// refreshTokens( +// UserId, +// appPreferences +// ); +// break; +// } +// +// } +// +// } +// } catch (Exception e) { +// recordException(TAG, "checkTokens e ", e); +// } +// } + //TODO check deprecation static boolean InstallFromPLay(Context context) { // A list with valid installers package name @@ -1239,4 +1273,63 @@ private static Locale parseLangCode(String langCode) { return new Locale(lang, country); } + + public static class ResponseObj { + public final int status; + public final String responseText; + final long checkResult; + final String url; + + ResponseObj(int status, String responseText, long checkResult) { + this.status = status; + this.responseText = responseText; + this.checkResult = checkResult; + this.url = null; + } + + } + + @SuppressWarnings({"unused", "FieldCanBeLocal", "RedundantSuppression"}) + private static class CodecList { + private final String type; + private final String name; + private final String maxresolution; + private final String maxbitrate; + private final String maxlevel; + private final int instances; + private final String resolutions; + + CodecList(String type, String name, String maxresolution, String maxbitrate, String maxlevel, int instances, String resolutions) { + this.type = type; + this.name = name; + this.maxresolution = maxresolution; + this.maxbitrate = maxbitrate; + this.maxlevel = maxlevel; + this.instances = instances; + this.resolutions = resolutions; + } + } + + //https://exoplayer.dev/shrinking.html + private static class Mp4ExtractorsFactory implements ExtractorsFactory { + @Override + @NonNull + public Extractor[] createExtractors() { + return new Extractor[]{new Mp4Extractor(SubtitleParser.Factory.UNSUPPORTED, /* flags= */ FLAG_EMIT_RAW_SUBTITLE_DATA)}; + } + } + + @SuppressWarnings({"unused", "FieldCanBeLocal", "RedundantSuppression"}) + private static class QualitiesObj { + private final String id; + private final String band; + private final String codec; + + QualitiesObj(String id, int band, String codec) { + this.id = id; + this.band = extractBand(band); + this.codec = extractCodec(codec); + } + + } } diff --git a/app/index.html b/app/index.html index 1e2786cd8..0310e3eb8 100644 --- a/app/index.html +++ b/app/index.html @@ -1831,6 +1831,11 @@ /* When the html code is compressed loaded from js this div and the next have no space in between, adding a margin makes it look ok, but too big when the code is not compresed*/ } + .settings_codec_container { + height: 51vh; + overflow: hidden; + } + .controls_holder { z-index: -100; position: absolute; diff --git a/app/languages/0_Strings.js b/app/languages/0_Strings.js index f90e0c4dd..1f475d3da 100644 --- a/app/languages/0_Strings.js +++ b/app/languages/0_Strings.js @@ -767,5 +767,9 @@ var STR_PASS_MATURE_ENABLED; var STR_WRONG_PASS; var STR_PLAYER_EXTRA_CODEC; var STR_PLAYER_EXTRA_CODEC_SUMMARY; +var STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA; +var STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA2; var STR_PLAYER_CODEC_AV1; var STR_PLAYER_CODEC_HEVC; +var STR_PLAYER_CODEC_SUPPORTED; +var STR_PLAYER_CODEC_NOT_SUPPORTED; diff --git a/app/languages/en_US.js b/app/languages/en_US.js index 32b7432b1..1f40d2abb 100644 --- a/app/languages/en_US.js +++ b/app/languages/en_US.js @@ -491,7 +491,7 @@ function en_USLang() { STR_BLOCKED_CODEC = 'Blocked codecs'; STR_BLOCKED_CODEC_SUMMARY = 'List used codec capabilities and allow blocking a codec from being used.'; STR_CODEC_DIALOG_TITLE = - "Software codecs (OMX.google) usually have the worst performance, but on some devices, they may have the advantage over hardware codecs. Using these ones can block those, so check if the performance of the playback improves, by default, the OMX.google decoder is disabled (if another codec is available). A constant accumulation of skipped frames is an indicative of a codec issue.
The app content only uses avc/h264 decoders, no others are listed."; + "Software codecs (OMX.google) usually have the worst performance, but on some devices, they may have the advantage over hardware codecs. Using these ones can block those, so check if the performance of the playback improves, by default, the OMX.google decoders are disabled (if another codec is available). A constant accumulation of skipped frames is an indicative of a codec issue."; STR_SUPPORTED_CODEC = 'Supported codecs:'; STR_MAX_RES = 'Max resolution:'; STR_MAX_BIT = 'Max bitrate:'; @@ -881,6 +881,14 @@ function en_USLang() { STR_PLAYER_EXTRA_CODEC = 'Extra codec support'; STR_PLAYER_EXTRA_CODEC_SUMMARY = 'Beta codec support that are being tested by Twitch'; - STR_PLAYER_CODEC_AV1 = 'AV1 support'; - STR_PLAYER_CODEC_HEVC = 'HEVC support'; + STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA = 'Most streams only have AVC H.264 support '; + + STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA2 = + 'For the codec to work the device must be capable, check the capability below (must be green), and the stream must be using the codec.'; + + STR_PLAYER_CODEC_AV1 = 'AV1'; + STR_PLAYER_CODEC_HEVC = 'HEVC'; + + STR_PLAYER_CODEC_SUPPORTED = 'supported'; + STR_PLAYER_CODEC_NOT_SUPPORTED = 'Not supported! Enabling this codec can cause playback errors and no playback.'; } diff --git a/app/specific/Main.js b/app/specific/Main.js index 63f5e69fc..f114bfca4 100644 --- a/app/specific/Main.js +++ b/app/specific/Main.js @@ -90,7 +90,7 @@ var Main_values = { DeviceCheck2: false, MiboxRevertCheck: false, Never_run_phone: true, - Codec_is_Check: false, + Codec_is_Check_new: false, OS_is_Check: false, Restore_Backup_Check: false, UserSidePannel_LastPositionId: null, @@ -476,14 +476,18 @@ function Main_CheckDevice() { } //Disable googles OMX.google.h264.decoder and c2.android.avc.decoder if another codec is available - if (!Main_values.Codec_is_Check) { + if (!Main_values.Codec_is_Check_new) { var codecs = null; try { - if (Main_IsOn_OSInterface) codecs = JSON.parse(OSInterface_getcodecCapabilities('avc')); + if (Main_IsOn_OSInterface) { + codecs = JSON.parse(OSInterface_getcodecCapabilities('avc')); + codecs.push.apply(codecs, JSON.parse(OSInterface_getcodecCapabilities('hevc'))); + codecs.push.apply(codecs, JSON.parse(OSInterface_getcodecCapabilities('av01'))); + } } catch (e) {} if (codecs) { - Main_values.Codec_is_Check = true; + Main_values.Codec_is_Check_new = true; if (codecs.length > 1) { var codecsNames = []; diff --git a/app/specific/Settings.js b/app/specific/Settings.js index cc2191714..a5bd6351a 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -34,6 +34,9 @@ var buffer_values = [0.1, 0.25, 0.5, 0.75, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 // }; var Settings_VolumeScale = 5; +var Settings_AV1Supported = 0; +var Settings_HEVCSupported = 0; + var Settings_value = { content_lang: { values: [ @@ -1723,13 +1726,24 @@ function Settings_SetResBitRateMin() { } function Settings_ExtraCodecs() { - var ExtraCodecsValuesArray = []; + var ExtraCodecsValuesArray = [], + av1Enabled = Settings_Obj_default('av1_codec'), + hevcEnabled = Settings_Obj_default('hevc_codec'); - if (Settings_Obj_default('av1_codec')) { + if (av1Enabled) { ExtraCodecsValuesArray.push('av1'); + + if (!Settings_AV1Supported) { + Main_showWarningDialog(STR_PLAYER_CODEC_NOT_SUPPORTED, 3000); + } } - if (Settings_Obj_default('hevc_codec')) { + + if (hevcEnabled) { ExtraCodecsValuesArray.push('h265'); + + if (!Settings_HEVCSupported) { + Main_showWarningDialog(STR_PLAYER_CODEC_NOT_SUPPORTED, 3000); + } } ExtraCodecsValuesArray.push('h264'); @@ -1823,7 +1837,15 @@ function Settings_HideElem(elem, hide) { var Settings_CurY = 0; function Settings_ScrollDown() { - var doc = Main_getElementById('settings_scroll'); + Settings_Do_ScrollDown('settings_scroll'); +} + +function Settings_ScrollUp() { + Settings_Do_ScrollUp('settings_scroll'); +} + +function Settings_Do_ScrollDown(docId) { + var doc = Main_getElementById(docId); doc.scrollTop = doc.scrollHeight; if (Settings_Obj_default('app_animations')) { var position = doc.scrollTop; @@ -1832,8 +1854,8 @@ function Settings_ScrollDown() { } } -function Settings_ScrollUp() { - var doc = Main_getElementById('settings_scroll'); +function Settings_Do_ScrollUp(docId) { + var doc = Main_getElementById(docId); if (Settings_Obj_default('app_animations')) scrollTo(doc, 0, 200); else doc.scrollTop = 0; } @@ -1974,10 +1996,22 @@ function Settings_CodecsShow(click) { DivContent, spacer = ' | '; - dialogContent += STR_CODEC_DIALOG_TITLE + STR_BR + STR_DIV_TITLE + STR_SUPPORTED_CODEC + '' + STR_BR; + dialogContent += + STR_DIV_TITLE + + STR_BLOCKED_CODEC + + '' + + STR_BR + + STR_CODEC_DIALOG_TITLE + + STR_BR + + STR_DIV_TITLE + + STR_SUPPORTED_CODEC + + '' + + STR_BR; var i = 0, len = Settings_CodecsValue.length; + + dialogContent += '
'; for (i; i < len; i++) { Settings_value[Settings_CodecsValue[i].name] = { values: [STR_ENABLED, STR_DISABLED], @@ -1993,11 +2027,12 @@ function Settings_CodecsShow(click) { dialogContent += Settings_DivOptionWithSummary( Settings_CodecsValue[i].name, - Settings_CodecsValue[i].name, + Settings_CodecsValue[i].name + Settings_decoderType(Settings_CodecsValue[i].type), DivContent + STR_BR + STR_BR, 73 ); } + dialogContent += '
'; Main_innerHTML('dialog_codecs_text', dialogContent + STR_DIV_TITLE + (click ? STR_CLOSE_THIS_BROWSER : STR_CLOSE_THIS) + ''); Settings_CodecsDialogSet = true; @@ -2015,6 +2050,14 @@ function Settings_CodecsShow(click) { Main_addEventListener('keydown', Settings_handleKeyDownCodecs); } +function Settings_decoderType(codec) { + if (Main_A_includes_B(codec, 'avc')) return ' - AVC H.264'; + else if (Main_A_includes_B(codec, 'hevc')) return ' - HEVC H.265'; + else if (Main_A_includes_B(codec, 'av01')) return ' - AV1'; + + return ''; +} + function Settings_handleKeyDownReturn() { Settings_RemoveInputFocusKey(Settings_CodecsValue[Settings_CodecsPos].name); Main_HideElement('dialog_codecs'); @@ -2047,16 +2090,36 @@ function Settings_handleKeyDownCodecs(event) { Settings_handleKeyDownCodecsRight(); break; case KEY_UP: - if (Settings_CodecsPos > 0) Settings_CodecsUpDown(-1); + if (Settings_CodecsPos > 0) { + Settings_CodecsUpDown(-1); + if (Settings_CodecsPos === 3) { + Settings_ScrollCodecs(); + } + } break; case KEY_DOWN: - if (Settings_CodecsPos < Settings_CodecsValue.length - 1) Settings_CodecsUpDown(1); + if (Settings_CodecsPos < Settings_CodecsValue.length - 1) { + Settings_CodecsUpDown(1); + if (Settings_CodecsPos === 4) { + Settings_ScrollCodecs(true); + } + } break; default: break; } } +function Settings_ScrollCodecs(down) { + var docId = 'settings_codec_container'; + + if (down) { + Settings_Do_ScrollDown(docId); + } else { + Settings_Do_ScrollUp(docId); + } +} + function Settings_Codecs_isVisible() { return Main_isElementShowing('dialog_codecs'); } @@ -2163,42 +2226,102 @@ function Settings_SetCodecsValue() { if (!Main_IsOn_OSInterface) { // Settings_CodecsValue = [ // { - // "instances": 32, - // "maxbitrate": "120 Mbps", - // "maxlevel": "5.2", - // "maxresolution": "3840x2176", - // "name": "OMX.Nvidia.h264.decode", - // "resolutions": "160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 555 fps | 1080p : 245 fps | 1440p : 138 fps | 2160p : 61 fps", - // "type": "video/avc" + // instances: 32, + // maxbitrate: '120 Mbps', + // maxlevel: '5.2', + // maxresolution: '3840x2176', + // name: 'OMX.Nvidia.h264.decode', + // resolutions: '160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 555 fps | 1080p : 245 fps | 1440p : 138 fps | 2160p : 61 fps', + // type: 'video/avc' // }, // { - // "instances": 32, "maxbitrate": "48 Mbps", - // "maxlevel": "5.2", - // "maxresolution": "4080x4080", - // "name": "OMX.google.h264.decoder", - // "resolutions": "160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps", - // "type": "video/avc" + // instances: 32, + // maxbitrate: '48 Mbps', + // maxlevel: '5.2', + // maxresolution: '4080x4080', + // name: 'OMX.google.h264.decoder', + // resolutions: '160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps', + // type: 'video/avc' // }, // { - // "instances": -1, "maxbitrate": "48 Mbps", - // "maxlevel": "5.2", - // "maxresolution": "4080x4080", - // "name": "OMX.chico.h264.decoder", - // "resolutions": "160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps", - // "type": "video/avc" + // instances: -1, + // maxbitrate: '48 Mbps', + // maxlevel: '5.2', + // maxresolution: '4080x4080', + // name: 'OMX.chico.h264.decoder', + // resolutions: '160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps', + // type: 'video/avc' + // }, + // { + // instances: 32, + // maxbitrate: '120 Mbps', + // maxlevel: 'High 5.2', + // maxresolution: '4096x4096', + // name: 'c2.goldfish.hevc.decoder', + // resolutions: + // '160p : 480 fps | 360p : 480 fps | 480p : 480 fps | 720p : 480 fps | 900p : 364 fps | 1080p : 254 fps | 1440p : 144 fps | 2160p : 64 fps', + // type: 'video/hevc' + // }, + // { + // instances: 32, + // maxbitrate: '10 Mbps', + // maxlevel: 'High 5.2', + // maxresolution: '4096x4096', + // name: 'c2.android.hevc.decoder', + // resolutions: + // '160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps', + // type: 'video/hevc' + // }, + // { + // instances: 32, + // maxbitrate: '10 Mbps', + // maxlevel: 'High 5.2', + // maxresolution: '4096x4096', + // name: 'OMX.google.hevc.decoder', + // resolutions: + // '160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps', + // type: 'video/hevc' + // }, + // { + // instances: 32, + // maxbitrate: '40 Mbps', + // maxlevel: '32768', + // maxresolution: '2048x2048', + // name: 'c2.android.av1.decoder', + // resolutions: '160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps', + // type: 'video/av01' // } // ]; Settings_CodecsValue = JSON.parse( - '[{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"5.2","maxresolution":"3840x2176","name":"OMX.Nvidia.h264.decode","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 555 fps | 1080p : 245 fps | 1440p : 138 fps | 2160p : 61 fps","type":"video/avc"},{"instances":32,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.google.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":-1,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.chico.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"}]' + '[{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"5.2","maxresolution":"3840x2176","name":"OMX.Nvidia.h264.decode","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 555 fps | 1080p : 245 fps | 1440p : 138 fps | 2160p : 61 fps","type":"video/avc"},{"instances":32,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.google.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":-1,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.chico.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.goldfish.hevc.decoder","resolutions":"160p : 480 fps | 360p : 480 fps | 480p : 480 fps | 720p : 480 fps | 900p : 364 fps | 1080p : 254 fps | 1440p : 144 fps | 2160p : 64 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.android.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"OMX.google.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.android.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"}]' ); } else { try { Settings_CodecsValue = JSON.parse(OSInterface_getcodecCapabilities('avc')); + + Settings_CodecsValue.push.apply(Settings_CodecsValue, JSON.parse(OSInterface_getcodecCapabilities('hevc'))); + Settings_CodecsValue.push.apply(Settings_CodecsValue, JSON.parse(OSInterface_getcodecCapabilities('av01'))); } catch (e) { Settings_CodecsValue = []; } } + + Settings_SetSuportedCodecs(Settings_CodecsValue); +} + +function Settings_SetSuportedCodecs(codecs) { + var i = 0, + len = codecs.length; + + for (i; i < len; i++) { + if (Main_A_includes_B(codecs[i].type, 'hevc')) Settings_HEVCSupported = true; + if (Main_A_includes_B(codecs[i].type, 'av01')) Settings_AV1Supported = true; + + if (Settings_HEVCSupported && Settings_AV1Supported) { + break; + } + } } function Settings_QualitiesCheck() { @@ -2309,7 +2432,40 @@ function Settings_DialogShowExtraCodecs(click) { } }; - Settings_DialogShow(obj, STR_PLAYER_EXTRA_CODEC + STR_BR + STR_BR + STR_PLAYER_EXTRA_CODEC_SUMMARY, click); + var red = '#ec0000', + green = '#00c900'; + + Settings_DialogShow( + obj, + STR_DIV_TITLE + + STR_PLAYER_EXTRA_CODEC + + '' + + STR_BR + + STR_PLAYER_EXTRA_CODEC_SUMMARY + + STR_BR + + STR_BR + + STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA + + STR_BR + + STR_BR + + STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA2 + + STR_BR + + STR_BR + + '
AV1 -' + + STR_SPACE_HTML + + (Settings_AV1Supported ? STR_PLAYER_CODEC_SUPPORTED : STR_PLAYER_CODEC_NOT_SUPPORTED) + + STR_BR + + STR_BR + + ' HEVC -' + + STR_SPACE_HTML + + (Settings_HEVCSupported ? STR_PLAYER_CODEC_SUPPORTED : STR_PLAYER_CODEC_NOT_SUPPORTED) + + '
', + click + ); } function Settings_DialogShowBitrate(click) { @@ -3069,10 +3225,14 @@ function Settings_DialoghandleKeyDown(event) { Settings_DialoghandleKeyRight(); break; case KEY_UP: - if (Settings_DialogPos > 0) Settings_DialogUpDown(-1); + if (Settings_DialogPos > 0) { + Settings_DialogUpDown(-1); + } break; case KEY_DOWN: - if (Settings_DialogPos < Settings_DialogValue.length - 1) Settings_DialogUpDown(1); + if (Settings_DialogPos < Settings_DialogValue.length - 1) { + Settings_DialogUpDown(1); + } break; default: break; From 86fef2e45ce9fabf05988b0703e5e5b488e7cc60 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Thu, 1 Aug 2024 22:31:05 -0300 Subject: [PATCH 08/29] improve setting codecs and related --- app/languages/0_Strings.js | 1 + app/languages/en_US.js | 4 +++- app/specific/Settings.js | 17 +++++++++++------ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/languages/0_Strings.js b/app/languages/0_Strings.js index 1f475d3da..98f7e2c1e 100644 --- a/app/languages/0_Strings.js +++ b/app/languages/0_Strings.js @@ -769,6 +769,7 @@ var STR_PLAYER_EXTRA_CODEC; var STR_PLAYER_EXTRA_CODEC_SUMMARY; var STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA; var STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA2; +var STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA3; var STR_PLAYER_CODEC_AV1; var STR_PLAYER_CODEC_HEVC; var STR_PLAYER_CODEC_SUPPORTED; diff --git a/app/languages/en_US.js b/app/languages/en_US.js index 1f40d2abb..b805b0147 100644 --- a/app/languages/en_US.js +++ b/app/languages/en_US.js @@ -488,7 +488,7 @@ function en_USLang() { STR_DPAD_POSTION = 'D-pad screen position'; STR_DPAD_OPACITY = 'D-pad opacity'; STR_DPAD_OPT = 'D-pad options'; - STR_BLOCKED_CODEC = 'Blocked codecs'; + STR_BLOCKED_CODEC = 'Codec capability & Blocked codecs'; STR_BLOCKED_CODEC_SUMMARY = 'List used codec capabilities and allow blocking a codec from being used.'; STR_CODEC_DIALOG_TITLE = "Software codecs (OMX.google) usually have the worst performance, but on some devices, they may have the advantage over hardware codecs. Using these ones can block those, so check if the performance of the playback improves, by default, the OMX.google decoders are disabled (if another codec is available). A constant accumulation of skipped frames is an indicative of a codec issue."; @@ -891,4 +891,6 @@ function en_USLang() { STR_PLAYER_CODEC_SUPPORTED = 'supported'; STR_PLAYER_CODEC_NOT_SUPPORTED = 'Not supported! Enabling this codec can cause playback errors and no playback.'; + + STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA3 = 'To better understand the device capability check the settings option: ' + STR_BLOCKED_CODEC; } diff --git a/app/specific/Settings.js b/app/specific/Settings.js index a5bd6351a..01443f149 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -384,7 +384,7 @@ var Settings_value = { defaultValue: 3 }, default_quality: { - values: ['Auto', 'source', '1080p60', '1080p30', '720p60', '720p30', '480p30', '360p30', '160p30'], + values: ['Auto', 'source', '2160p60', '1440p60', '1080p60', '1080p30', '720p60', '720p30', '480p30', '360p30', '160p30'], defaultValue: 1 }, check_source: { @@ -878,9 +878,11 @@ function Settings_SetSettings() { //Dialog settings //div += Settings_Content('proxy_settings', [STR_ENTER_TO_OPEN], PROXY_SETTINGS, null); div += Settings_Content('player_extracodecs', [STR_ENTER_TO_OPEN], STR_PLAYER_EXTRA_CODEC, STR_PLAYER_EXTRA_CODEC_SUMMARY); - div += Settings_Content('player_bitrate', [STR_ENTER_TO_OPEN], STR_PLAYER_BITRATE, STR_PLAYER_BITRATE_SUMMARY); - div += Settings_Content('block_qualities', [STR_ENTER_TO_OPEN], STR_BLOCK_RES, STR_BLOCK_RES_SUMMARY); div += Settings_Content('blocked_codecs', [STR_ENTER_TO_OPEN], STR_BLOCKED_CODEC, STR_BLOCKED_CODEC_SUMMARY); + + div += Settings_Content('block_qualities', [STR_ENTER_TO_OPEN], STR_BLOCK_RES, STR_BLOCK_RES_SUMMARY); + div += Settings_Content('player_bitrate', [STR_ENTER_TO_OPEN], STR_PLAYER_BITRATE, STR_PLAYER_BITRATE_SUMMARY); + div += Settings_Content('preview_settings', [STR_ENTER_TO_OPEN], STR_SIDE_PANEL_PLAYER, null); div += Settings_Content('vod_seek', [STR_ENTER_TO_OPEN], STR_VOD_SEEK, null); div += Settings_Content('playerend_opt', [STR_ENTER_TO_OPEN], STR_END_DIALOG_OPT, null); @@ -2415,9 +2417,9 @@ function Settings_DialogShowProxy(click) { } function Settings_DialogShowExtraCodecs(click) { - var array_no_yes = [STR_NO, STR_YES]; - Settings_value.av1_codec.values = array_no_yes; - Settings_value.hevc_codec.values = array_no_yes; + var dis_ena = [STR_DISABLED, STR_ENABLED]; + Settings_value.av1_codec.values = dis_ena; + Settings_value.hevc_codec.values = dis_ena; var obj = { av1_codec: { @@ -2447,6 +2449,9 @@ function Settings_DialogShowExtraCodecs(click) { STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA + STR_BR + STR_BR + + STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA3 + + STR_BR + + STR_BR + STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA2 + STR_BR + STR_BR + From 2aff150ca0a03097784981fc183a6d9077ae1986 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 08:43:56 -0300 Subject: [PATCH 09/29] Update PlayerActivity.java --- apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java index d695f7b72..a15d9a80b 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java +++ b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java @@ -1181,7 +1181,7 @@ private void SwitchPlayer() { } public void PlayerObjUpdateTrackSelectorParameters(int ParametersPos, Context context, int width) { - + //https://developer.android.com/reference/kotlin/androidx/media3/exoplayer/trackselection/DefaultTrackSelector.ParametersBuilder trackSelectorParameters[ParametersPos] = DefaultTrackSelector.Parameters.getDefaults(context) .buildUpon() .setMaxVideoBitrate(PlayerBitrate[ParametersPos]) From 11f0b1fefd61ac71c26fd81cbacafa12b5b4e3da Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 08:43:58 -0300 Subject: [PATCH 10/29] Update Tools.java --- apk/app/src/main/java/com/fgl27/twitch/Tools.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/Tools.java b/apk/app/src/main/java/com/fgl27/twitch/Tools.java index ba5c7a4d7..7c3ab5c34 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/Tools.java +++ b/apk/app/src/main/java/com/fgl27/twitch/Tools.java @@ -384,7 +384,7 @@ static String codecCapabilities(String CodecType) { maxlevel = AvcLevelsMap.containsKey(position) ? AvcLevelsMap.get(position) : "Unknown level " + profile[profile.length - 1].level; - } else if (CodecType.contains("av1")) { + } else if (CodecType.contains("av01")) { maxlevel = Av1LevelsMap.containsKey(position) ? Av1LevelsMap.get(position) : "Unknown level " + profile[profile.length - 1].level; From 8044c8b840c187b236ccd26ecad4be092ae1d685 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 09:25:14 -0300 Subject: [PATCH 11/29] Improve Codec capability & Blocked codecs --- app/languages/0_Strings.js | 6 +- app/languages/default.js | 2 + app/languages/en_US.js | 21 +++-- app/languages/es_ES.js | 4 +- app/languages/pt_BR.js | 5 +- app/languages/ru_Ru.js | 5 +- .../untranslated/untranslated_es_ES.txt | 1 - app/specific/Settings.js | 87 ++++++++++--------- 8 files changed, 68 insertions(+), 63 deletions(-) diff --git a/app/languages/0_Strings.js b/app/languages/0_Strings.js index 98f7e2c1e..fd06145cb 100644 --- a/app/languages/0_Strings.js +++ b/app/languages/0_Strings.js @@ -332,13 +332,13 @@ var STR_DPAD_POSTION; var STR_DPAD_OPACITY; var STR_BLOCKED_CODEC; var STR_BLOCKED_CODEC_SUMMARY; -var STR_CODEC_DIALOG_TITLE; -var STR_SUPPORTED_CODEC; +var STR_CODEC_DIALOG_SUMMARY_1; +var STR_CODEC_DIALOG_SUMMARY_2; +var STR_CODEC_DIALOG_SUMMARY_3; var STR_MAX_RES; var STR_MAX_BIT; var STR_MAX_LEVEL; var STR_MAX_FPS; -var STR_ONE_CODEC_ENA; var STR_USER_LIVE; var STR_PP_WORKAROUND; var STR_PP_WORKAROUND_SUMMARY; diff --git a/app/languages/default.js b/app/languages/default.js index b9b4ac579..5f537d82a 100644 --- a/app/languages/default.js +++ b/app/languages/default.js @@ -491,6 +491,8 @@ function DefaultLang() { STR_PROXY_CONTROLS_ARRAY = [STR_K_TWITCH, STR_TTV_LOL, STR_T1080, STR_DISABLED]; SEEK_PREVIEW_ARRAY = [STR_DISABLED, SEEK_PREVIEW_SINGLE, SEEK_PREVIEW_CAROUSEL]; + + STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA3 = STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA3 + STR_BLOCKED_CODEC; } function DefaultReplaceLink(link, string, center) { diff --git a/app/languages/en_US.js b/app/languages/en_US.js index b805b0147..e07ee83e0 100644 --- a/app/languages/en_US.js +++ b/app/languages/en_US.js @@ -488,19 +488,14 @@ function en_USLang() { STR_DPAD_POSTION = 'D-pad screen position'; STR_DPAD_OPACITY = 'D-pad opacity'; STR_DPAD_OPT = 'D-pad options'; - STR_BLOCKED_CODEC = 'Codec capability & Blocked codecs'; - STR_BLOCKED_CODEC_SUMMARY = 'List used codec capabilities and allow blocking a codec from being used.'; - STR_CODEC_DIALOG_TITLE = - "Software codecs (OMX.google) usually have the worst performance, but on some devices, they may have the advantage over hardware codecs. Using these ones can block those, so check if the performance of the playback improves, by default, the OMX.google decoders are disabled (if another codec is available). A constant accumulation of skipped frames is an indicative of a codec issue."; - STR_SUPPORTED_CODEC = 'Supported codecs:'; + STR_MAX_RES = 'Max resolution:'; STR_MAX_BIT = 'Max bitrate:'; STR_MAX_LEVEL = 'Max level:'; STR_MAX_FPS = 'Max fps per resolution:'; STR_MAX_INSTANCES = 'Max instances:'; STR_UNKNOWN = 'Unknown'; - STR_ONE_CODEC_ENA = 'At least one codec must be enabled at all times.'; - STR_USER_LIVE = 'User live side pannel: Left D-pad from the side panel or key 3 from anywhere'; + STR_USER_LIVE = 'User live side panel: Left D-pad from the side panel or key 3 from anywhere'; STR_PP_WORKAROUND = 'Multiplayer, PP and preview mode workaround'; STR_PP_WORKAROUND_SUMMARY = "For some devices usually running old versions of Android, it is necessary to enable this to have multiplayer mode working properly. Usually, the issue is that the player (PP or preview) will not be visible, or even when not in use it is visible as a black box over the main player. Don't enable this if you don't have issues, as it will result in lower image quality and possible loss of performance"; @@ -892,5 +887,15 @@ function en_USLang() { STR_PLAYER_CODEC_SUPPORTED = 'supported'; STR_PLAYER_CODEC_NOT_SUPPORTED = 'Not supported! Enabling this codec can cause playback errors and no playback.'; - STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA3 = 'To better understand the device capability check the settings option: ' + STR_BLOCKED_CODEC; + STR_PLAYER_EXTRA_CODEC_SUMMARY_EXTRA3 = 'To better understand the device capability check the settings option: '; + + STR_BLOCKED_CODEC = 'Codec capability & Blocked codecs'; + STR_BLOCKED_CODEC_SUMMARY = 'List used codec capabilities and allow blocking codecs from being used.'; + + STR_CODEC_DIALOG_SUMMARY_1 = 'This section lists all device-supported codec types AVC H.264, HEVC H.265, and AV1 used by this app.'; + + STR_CODEC_DIALOG_SUMMARY_2 = + 'Software codecs (OMX.google) are disabled by default if a hardware codec is available, if you have a playback problem try to disable the hardware codec and enable the software or vice versa (A constant accumulation of skipped frames is indicative of a codec issue).'; + + STR_CODEC_DIALOG_SUMMARY_3 = 'At least one codec of each type must be enabled at all times.'; } diff --git a/app/languages/es_ES.js b/app/languages/es_ES.js index 9b3c096ea..cece911c7 100644 --- a/app/languages/es_ES.js +++ b/app/languages/es_ES.js @@ -376,9 +376,7 @@ function es_ESLang() { STR_DPAD_OPT = 'Opciones del D-pad'; STR_BLOCKED_CODEC = 'Codecs bloqueados'; STR_BLOCKED_CODEC_SUMMARY = 'Lista de los códecs utilizados y permite bloquear el uso de un códec'; - STR_CODEC_DIALOG_TITLE = - 'Los códecs de software (OMX.google) suelen tener un peor rendimiento, pero en algún dispositivo pueden tener preferencia sobre los códecs de hardware, usando este se pueden bloquear y ver si el rendimiento de la reproducción mejora, por defecto el decodificador OMX.google está desactivado (si hay otro códec disponible) una acumulación constante de fotogramas omitidos es un indicativo de un problema de códec.
El contenido de la aplicación sólo utiliza decodificadores avc/h264 no hay otro en la lista.'; - STR_SUPPORTED_CODEC = 'Códecs soportados:'; + STR_MAX_RES = 'Resolución máxima:'; STR_MAX_BIT = 'Tasa de bits máxima:'; STR_MAX_LEVEL = 'Nivel máximo:'; diff --git a/app/languages/pt_BR.js b/app/languages/pt_BR.js index 3502767f5..ce106e915 100644 --- a/app/languages/pt_BR.js +++ b/app/languages/pt_BR.js @@ -484,16 +484,13 @@ function pt_BRLang() { STR_DPAD_OPT = 'Opções do D-pad'; STR_BLOCKED_CODEC = 'Codecs bloqueados'; STR_BLOCKED_CODEC_SUMMARY = 'Lista as capacidades dos codecs usados ​​e permite bloquear o uso de um codec'; - STR_CODEC_DIALOG_TITLE = - 'Codecs de software (OMX.google) geralmente têm pior desempenho, mas em alguns dispositivos eles podem ter precedência sobre codecs de hardware, usando este pode bloqueá-los e ver se o desempenho da reprodução melhora, por padrão, o decodificador OMX.google está desabilitado (se outro codec estiver disponível) um acúmulo constante de quadros ignorados é um indicativo de um problema de codec.
O conteúdo do aplicativo usa apenas decodificadores avc/h264 nenhum outro está listado.'; - STR_SUPPORTED_CODEC = 'Codecs suportados:'; + STR_MAX_RES = 'Resolução máxima:'; STR_MAX_BIT = 'Taxa de bits máxima:'; STR_MAX_LEVEL = 'Nível máximo:'; STR_MAX_FPS = 'Max fps por resolução:'; STR_MAX_INSTANCES = 'Máximo de instâncias:'; STR_UNKNOWN = 'Desconhecido'; - STR_ONE_CODEC_ENA = 'Pelo menos um codec deve estar habilitado o tempo todo'; STR_USER_LIVE = 'Painel lateral ao vivo: do painel lateral direcional esquerdo ou de qualquer lugar, pressione 3'; STR_PP_WORKAROUND = 'Solução alternativa modo multiplayer, PP e preview'; STR_PP_WORKAROUND_SUMMARY = diff --git a/app/languages/ru_Ru.js b/app/languages/ru_Ru.js index 6af5b153f..e158fa94a 100644 --- a/app/languages/ru_Ru.js +++ b/app/languages/ru_Ru.js @@ -468,16 +468,13 @@ function ru_RULang() { STR_DPAD_OPT = 'Настройки D-Pad'; STR_BLOCKED_CODEC = 'Заблокированные кодеки'; STR_BLOCKED_CODEC_SUMMARY = 'Перечислить возможности используемых кодеков и разрешить/запретить использование кодеков'; - STR_CODEC_DIALOG_TITLE = - 'Программные кодеки (OMX.google) обычно имеют худшую производительность, но на некоторых устройствах они могут иметь приоритет над аппаратными кодеками. Используя это, кодеки можно заблокировать и посмотреть, улучшится ли производительность воспроизведения, по умолчанию декодер OMX.google отключен (если доступен другой кодек). Постоянное накопление пропущенных кадров указывает на проблему с кодеком.
В контенте приложения используются только декодеры avc/h264, другие не предусмотрены.'; - STR_SUPPORTED_CODEC = 'Поддерживаемые кодеки:'; + STR_MAX_RES = 'Макс. разрешение:'; STR_MAX_BIT = 'Макс. битрейт:'; STR_MAX_LEVEL = 'Макс. уровень:'; STR_MAX_FPS = 'Макс. FPS:'; STR_MAX_INSTANCES = 'Макс. экземпляры:'; STR_UNKNOWN = 'Неизвестно'; - STR_ONE_CODEC_ENA = 'Хотя бы один кодек должен быть включен постоянно'; STR_USER_LIVE = 'Боковая панель Акт.каналы: на боковой панели D-pad влево или из любого места кнопка 3'; STR_HISTORY = 'История'; diff --git a/app/languages/untranslated/untranslated_es_ES.txt b/app/languages/untranslated/untranslated_es_ES.txt index 794410630..42f7e0f0d 100644 --- a/app/languages/untranslated/untranslated_es_ES.txt +++ b/app/languages/untranslated/untranslated_es_ES.txt @@ -121,7 +121,6 @@ STR_RUNNINGTIME = "App running for:"; STR_410_ERROR = "Unable to get video link"; STR_ABOUT_PHONE = "This app is design to be used mainly on TVs, the support for other device is limited and may never receive a better support, if you don't have a keyboard or a D-pad + enter and return key controller (ESC works for return key on a computer) use the on screen virtual on screen keys to navigate (only visible on phone/tablet devices), in settings you can change position and opacity of the virtual D-pad, click anywhere on the screen to show the virtual D-pad when it is hidden it doesn't work."; - STR_ONE_CODEC_ENA = "At least one codec must be enable all the time"; STR_USER_LIVE = "User Live side pannel: from side panel D-pad left or from anywhere key 3"; STR_WATCHED = "Watched on"; STR_UNTIL = "until"; diff --git a/app/specific/Settings.js b/app/specific/Settings.js index 01443f149..00e2a2d25 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -2003,11 +2003,14 @@ function Settings_CodecsShow(click) { STR_BLOCKED_CODEC + '' + STR_BR + - STR_CODEC_DIALOG_TITLE + + STR_CODEC_DIALOG_SUMMARY_1 + + STR_BR + + STR_BR + + STR_CODEC_DIALOG_SUMMARY_2 + + STR_BR + + STR_BR + + STR_CODEC_DIALOG_SUMMARY_3 + STR_BR + - STR_DIV_TITLE + - STR_SUPPORTED_CODEC + - '' + STR_BR; var i = 0, @@ -2069,12 +2072,18 @@ function Settings_handleKeyDownReturn() { function Settings_handleKeyDownCodecsLeft() { var key = Settings_CodecsValue[Settings_CodecsPos].name; - if (Settings_Obj_default(key) > 0) Settings_CodecsRightLeft(-1); + + if (Settings_Obj_default(key) > 0) { + Settings_CodecsRightLeft(-1); + } } function Settings_handleKeyDownCodecsRight() { var key = Settings_CodecsValue[Settings_CodecsPos].name; - if (Settings_Obj_default(key) < Settings_Obj_length(key)) Settings_CodecsRightLeft(1); + + if (Settings_Obj_default(key) < Settings_Obj_length(key)) { + Settings_CodecsRightLeft(1); + } } function Settings_handleKeyDownCodecs(event) { @@ -2139,20 +2148,17 @@ function Settings_CodecsUpDownAfter(key) { } function Settings_CodecsRightLeft(offset) { - if (Settings_CodecsValue.length < 2) { - Main_showWarningDialog(STR_ONE_CODEC_ENA, 2000); + if (Settings_CodecsValue.length === 1) { + Main_showWarningDialog(STR_CODEC_DIALOG_SUMMARY_3, 2000); return; } var key = Settings_CodecsValue[Settings_CodecsPos].name, + type = Settings_CodecsValue[Settings_CodecsPos].type, index; Settings_value[key].defaultValue += offset; - Main_setItem(key, Settings_Obj_default(key)); - Main_textContent(key, Settings_Obj_values(key)); - Settings_SetarrowsKey(key); - if (Settings_value[key].defaultValue) { Settings_DisableCodecsNames.push(key); @@ -2162,35 +2168,35 @@ function Settings_CodecsRightLeft(offset) { len = Settings_CodecsValue.length; for (i; i < len; i++) { - if (!Settings_value[Settings_CodecsValue[i].name].defaultValue) { + if (type === Settings_CodecsValue[i].type && !Settings_value[Settings_CodecsValue[i].name].defaultValue) { oneEnable = true; break; } } if (!oneEnable) { - Main_showWarningDialog(STR_ONE_CODEC_ENA, 2000); + Main_showWarningDialog(STR_CODEC_DIALOG_SUMMARY_3, 2000); - i = 0; - len = Settings_CodecsValue.length; - for (i; i < len; i++) { - if (Settings_CodecsPos !== i) { - key = Settings_CodecsValue[i].name; - Settings_value[key].defaultValue += -1; - Main_setItem(key, Settings_Obj_default(key)); - Main_textContent(key, Settings_Obj_values(key)); - index = Settings_DisableCodecsNames.indexOf(Settings_CodecsValue[i].name); - if (index > -1) Settings_DisableCodecsNames.splice(index, 1); - - break; - } + key = Settings_CodecsValue[Settings_CodecsPos].name; + Settings_value[key].defaultValue += -1; + index = Settings_DisableCodecsNames.indexOf(Settings_CodecsValue[Settings_CodecsPos].name); + + if (index > -1) { + Settings_DisableCodecsNames.splice(index, 1); } } } else { index = Settings_DisableCodecsNames.indexOf(key); - if (index > -1) Settings_DisableCodecsNames.splice(index, 1); + + if (index > -1) { + Settings_DisableCodecsNames.splice(index, 1); + } } + Main_setItem(key, Settings_Obj_default(key)); + Main_textContent(key, Settings_Obj_values(key)); + Settings_SetarrowsKey(key); + Main_setItem('Settings_DisableCodecsNames', JSON.stringify(Settings_DisableCodecsNames)); Settings_CodecsSet(); } @@ -2422,15 +2428,16 @@ function Settings_DialogShowExtraCodecs(click) { Settings_value.hevc_codec.values = dis_ena; var obj = { - av1_codec: { - defaultValue: Settings_value.av1_codec.defaultValue, - values: Settings_value.av1_codec.values, - title: STR_PLAYER_CODEC_AV1 - }, hevc_codec: { defaultValue: Settings_value.hevc_codec.defaultValue, values: Settings_value.hevc_codec.values, - title: STR_PLAYER_CODEC_HEVC + title: STR_SPACE_HTML + STR_SPACE_HTML + STR_SPACE_HTML + STR_SPACE_HTML + STR_PLAYER_CODEC_HEVC + }, + + av1_codec: { + defaultValue: Settings_value.av1_codec.defaultValue, + values: Settings_value.av1_codec.values, + title: STR_SPACE_HTML + STR_SPACE_HTML + STR_SPACE_HTML + STR_SPACE_HTML + STR_PLAYER_CODEC_AV1 } }; @@ -2457,17 +2464,17 @@ function Settings_DialogShowExtraCodecs(click) { STR_BR + '
AV1 -' + + (Settings_HEVCSupported ? green : red) + + ';"> HEVC -' + STR_SPACE_HTML + - (Settings_AV1Supported ? STR_PLAYER_CODEC_SUPPORTED : STR_PLAYER_CODEC_NOT_SUPPORTED) + + (Settings_HEVCSupported ? STR_PLAYER_CODEC_SUPPORTED : STR_PLAYER_CODEC_NOT_SUPPORTED) + STR_BR + STR_BR + ' HEVC -' + + (Settings_AV1Supported ? green : red) + + ';"> AV1 -' + STR_SPACE_HTML + - (Settings_HEVCSupported ? STR_PLAYER_CODEC_SUPPORTED : STR_PLAYER_CODEC_NOT_SUPPORTED) + + (Settings_AV1Supported ? STR_PLAYER_CODEC_SUPPORTED : STR_PLAYER_CODEC_NOT_SUPPORTED) + '
', click ); From 637dd3d8342e79546a36792c3f6bb286ab8f6c60 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 10:03:35 -0300 Subject: [PATCH 12/29] Improve Play_extractQualities --- app/specific/Play.js | 46 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/app/specific/Play.js b/app/specific/Play.js index cedec808f..75ad7d4bb 100644 --- a/app/specific/Play.js +++ b/app/specific/Play.js @@ -262,6 +262,7 @@ function Play_Start(offline_chat) { Chat_Disable(); BrowserTestStartLive(Play_data.data[6]); } + Play_extractQualitiesTest(); } //Play_ResetProxy(); @@ -1027,6 +1028,7 @@ function Play_SetExternalQualities(array, startPos, name) { Play_ExternalUrls.push(array[i].url); Play_controls[Play_controlsExternal].values.push(array[i].id); } + Play_controls[Play_controlsExternal].defaultValue = Play_controls[Play_controlsExternal].values.length - 1; Play_controls[Play_controlsExternal].setLabel(); @@ -1045,14 +1047,42 @@ function Play_FixQualities(input) { return input; } +function Play_extractQualitiesTest() { + /* jshint ignore:start */ + var testString = ` +#EXTM3U +#EXT-X-TWITCH-INFO:NODE="video-edge-6205c6.sao03",MANIFEST-NODE-TYPE="weaver_cluster",MANIFEST-NODE="video-weaver.sao03",SUPPRESS="true",SERVER-TIME="1722602179.79",TRANSCODESTACK="2023-Transcode-Gen2-V1",TRANSCODEMODE="cbr_v1",USER-IP="177.22.171.246",SERVING-ID="f",CLUSTER="sao03",ABS="true",VIDEO-SESSION-ID="2118154500142300273",BROADCAST-ID="40914639541",STREAM-TIME="18032.793634",B="false",USER-COUNTRY="BR",MANIFEST-CLUSTER="sao03",ORIGIN="muc03",C="a",D="false" +#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="chunked",NAME="1080p60 (source)",AUTOSELECT=YES,DEFAULT=YES +#EXT-X-STREAM-INF:BANDWIDTH=6857175,RESOLUTION=1920x1080,CODECS="avc1.64002A,mp4a.40.2",VIDEO="chunked",FRAME-RATE=59.000 +https://video-weaver.sao03.hls.ttvnw.net/v1/playlist/C.m3u8 +#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="720p60",NAME="720p60",AUTOSELECT=YES,DEFAULT=YES +#EXT-X-STREAM-INF:BANDWIDTH=3422999,RESOLUTION=1280x720,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="720p60",FRAME-RATE=60.000 +https://video-weaver.sao03.hls.ttvnw.net/v1/playlist/C.m3u8 +#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="480p30",NAME="480p",AUTOSELECT=YES,DEFAULT=YES +#EXT-X-STREAM-INF:BANDWIDTH=1427999,RESOLUTION=852x480,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="480p30",FRAME-RATE=30.000 +https://video-weaver.sao03.hls.ttvnw.net/v1/playlist/C.m3u8 +#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="360p30",NAME="360p",AUTOSELECT=YES,DEFAULT=YES +#EXT-X-STREAM-INF:BANDWIDTH=630000,RESOLUTION=640x360,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="360p30",FRAME-RATE=30.000 +https://video-weaver.sao03.hls.ttvnw.net/v1/playlist/C.m3u8 +#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="160p30",NAME="160p",AUTOSELECT=YES,DEFAULT=YES +#EXT-X-STREAM-INF:BANDWIDTH=230000,RESOLUTION=284x160,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="160p30",FRAME-RATE=27.000 +https://video-weaver.sao03.hls.ttvnw.net/v1/playlist/C.m3u8 09:36:20.90 + `; + + console.log('Play_extractQualitiesTest', Play_extractQualities(testString)); + /* jshint ignore:end */ +} + function Play_extractQualities(input) { var result = [], addedResolution = {}, marray, marray2, Regexp = /#EXT-X-MEDIA:(.)*\n#EXT-X-STREAM-INF:(.)*\n(.)*/g, - Regexp2 = /NAME="(.+?)".*BANDWIDTH=(\d+).*CODECS="(.+?)".*(http(.*))/g, - id; + Regexp2 = /NAME="(.+?)".*BANDWIDTH=(\d+).*CODECS="(.+?)".*FRAME-RATE=(\d+).*(http(.*))/g, + id, + res, + frame; while ((marray = Regexp.exec(input))) { while ((marray2 = Regexp2.exec(marray[0].replace(/(\r\n|\n|\r)/gm, '')))) { @@ -1067,13 +1097,17 @@ function Play_extractQualities(input) { //Prevent duplicated resolution 720p60 source and 720p60 if (!addedResolution[id]) { + res = parseInt(id.split('p')[0]); + frame = Math.ceil(parseInt(marray2[4]) / 10) * 10; + result.push({ - id: marray2[1], - url: marray2[4], + id: res + 'p' + frame, + url: marray2[5], bitrate: parseInt(marray2[2]), - resolution: parseInt(id.split('p')[0]), + resolution: res, band: Play_extractBand(marray2[2]), - codec: Play_extractCodec(marray2[3]) + codec: Play_extractCodec(marray2[3]), + frame: frame }); addedResolution[id] = 1; From 563a58668df9ebd62d7db0bdab7307178d4e0afd Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 11:29:43 -0300 Subject: [PATCH 13/29] play qualities add order to avoid change to the wrong resolution --- app/specific/Play.js | 11 ++++++++++- app/specific/PlayEtc.js | 9 ++++++--- app/specific/PlayExtra.js | 5 ++++- app/specific/PlayVod.js | 8 ++++++-- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/app/specific/Play.js b/app/specific/Play.js index 75ad7d4bb..b9fe47086 100644 --- a/app/specific/Play.js +++ b/app/specific/Play.js @@ -954,7 +954,7 @@ function Play_qualityChanged() { Play_SetHtmlQuality(Play_info_quality); if (Main_IsOn_OSInterface) { - OSInterface_SetQuality(Play_data.qualityIndex - 1); + OSInterface_SetQuality(Play_data.qualities[Play_data.qualityIndex].position); } else { Play_onPlayer(); } @@ -973,6 +973,15 @@ function Play_getQualities(Who_Called, skipchange) { Play_getQualitiesFail = false; result = JSON.parse(baseQualities); + var i = 0, + len = result.length; + + //add the position to the obj, as we may change the order and need the position to use in Play_controls[Play_controlsQuality] + for (i; i < len; i++) { + result[i].position = i - 1; + } + + //sort by resolution result.sort(function (a, b) { if (!a || !b) { return 0; diff --git a/app/specific/PlayEtc.js b/app/specific/PlayEtc.js index bdeb54339..7988ac840 100644 --- a/app/specific/PlayEtc.js +++ b/app/specific/PlayEtc.js @@ -2393,7 +2393,7 @@ function Play_MakeControls() { Play_SetHtmlQuality(Play_info_quality); if (oldQuality !== Play_data.quality) { - OSInterface_SetQuality(Play_data.qualityIndex - 1); //just quality change + OSInterface_SetQuality(Play_data.qualities[Play_data.qualityIndex].position); //just quality change } else { OSInterface_RestartPlayer(1, 0, 0); //restart the player } @@ -2407,8 +2407,11 @@ function Play_MakeControls() { PlayVod_qualityPlaying = PlayVod_quality; PlayVod_SetHtmlQuality(Play_info_quality); - if (oldQuality !== PlayVod_quality) OSInterface_SetQuality(PlayVod_qualityIndex - 1); //just quality change - else OSInterface_RestartPlayer(2, OSInterface_gettime(), 0); //resetart the player + if (oldQuality !== PlayVod_quality) { + OSInterface_SetQuality(PlayVod_qualities[PlayVod_qualityIndex].position); //just quality change + } else { + OSInterface_RestartPlayer(2, OSInterface_gettime(), 0); //resetart the player + } PlayVod_qualityIndexReset(); } else if (PlayVodClip === 3) { diff --git a/app/specific/PlayExtra.js b/app/specific/PlayExtra.js index e5767cdca..df229ee14 100644 --- a/app/specific/PlayExtra.js +++ b/app/specific/PlayExtra.js @@ -63,7 +63,10 @@ function PlayExtra_KeyEnter() { if (Main_IsOn_OSInterface) { //Not on auto mode for change to auto before start picture in picture - if (!Main_A_includes_B(Play_data.quality, 'Auto')) OSInterface_SetQuality(-1); + if (!Main_A_includes_B(Play_data.quality, 'Auto')) { + OSInterface_SetQuality(-1); + } + Play_SetPlayQuality('Auto'); Play_qualityDisplay(Play_getQualitiesCount, 0, Play_SetHtmlQuality, Play_controls[Play_controlsQuality]); PlayExtra_data.quality = 'Auto'; diff --git a/app/specific/PlayVod.js b/app/specific/PlayVod.js index 50d132e11..ce74b9bc5 100644 --- a/app/specific/PlayVod.js +++ b/app/specific/PlayVod.js @@ -552,8 +552,12 @@ function PlayVod_qualityChanged() { PlayVod_qualityPlaying = PlayVod_quality; PlayVod_SetHtmlQuality(Play_info_quality); - if (Main_IsOn_OSInterface) OSInterface_SetQuality(PlayVod_qualityIndex - 1); - else PlayVod_onPlayer(); + + if (Main_IsOn_OSInterface) { + OSInterface_SetQuality(PlayVod_qualities[PlayVod_qualityIndex].position); + } else { + PlayVod_onPlayer(); + } } function PlayVod_onPlayer() { From 9bc8954e7c5789e733c37be336507f3deff4cc88 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 11:40:02 -0300 Subject: [PATCH 14/29] minor visual improve --- app/specific/Play.js | 9 ++++++--- app/specific/PlayVod.js | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/specific/Play.js b/app/specific/Play.js index b9fe47086..83eca9dfd 100644 --- a/app/specific/Play.js +++ b/app/specific/Play.js @@ -1210,8 +1210,9 @@ function Play_SetHtmlQuality(element) { if (Main_IsOn_OSInterface) { quality_string = Play_data.quality.replace('Auto', STR_AUTO); } else { - if (Play_info_quality !== element) quality_string = Play_data.quality.replace('Auto', STR_AUTO); - else { + if (Play_info_quality !== element) { + quality_string = Play_data.quality.replace('Auto', STR_AUTO); + } else { quality_string = Play_data.qualities[1].id.replace('source', STR_AUTO) + Play_data.qualities[1].band + Play_data.qualities[1].codec; } } @@ -1782,7 +1783,9 @@ function Play_ShowVideoQuality(who_called, value) { } else { PlayVod_SetHtmlQuality(Play_info_quality); } - } else Main_innerHTML('stream_quality', value); + } else { + Main_innerHTML('stream_quality', value); + } } function Play_clearHidePanel() { diff --git a/app/specific/PlayVod.js b/app/specific/PlayVod.js index ce74b9bc5..123a72b31 100644 --- a/app/specific/PlayVod.js +++ b/app/specific/PlayVod.js @@ -868,8 +868,9 @@ function PlayVod_SetHtmlQuality(element) { if (Main_IsOn_OSInterface) { quality_string = PlayVod_quality.replace('Auto', STR_AUTO); } else { - if (Play_info_quality !== element) quality_string = PlayVod_quality.replace('Auto', STR_AUTO); - else { + if (Play_info_quality !== element) { + quality_string = PlayVod_quality.replace('Auto', STR_AUTO); + } else { quality_string = PlayVod_qualities[1].id.replace('source', STR_AUTO) + PlayVod_qualities[1].band + PlayVod_qualities[1].codec; } } From 3fc437448fecf3d7266f2b8d21873576853a88a6 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 14:08:19 -0300 Subject: [PATCH 15/29] improve codecs scroll --- app/specific/Settings.js | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/app/specific/Settings.js b/app/specific/Settings.js index 00e2a2d25..5b4fd7cc3 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -2016,7 +2016,8 @@ function Settings_CodecsShow(click) { var i = 0, len = Settings_CodecsValue.length; - dialogContent += '
'; + dialogContent += + '
'; for (i; i < len; i++) { Settings_value[Settings_CodecsValue[i].name] = { values: [STR_ENABLED, STR_DISABLED], @@ -2037,7 +2038,7 @@ function Settings_CodecsShow(click) { 73 ); } - dialogContent += '
'; + dialogContent += '
'; Main_innerHTML('dialog_codecs_text', dialogContent + STR_DIV_TITLE + (click ? STR_CLOSE_THIS_BROWSER : STR_CLOSE_THIS) + ''); Settings_CodecsDialogSet = true; @@ -2068,6 +2069,7 @@ function Settings_handleKeyDownReturn() { Main_HideElement('dialog_codecs'); Main_removeEventListener('keydown', Settings_handleKeyDownCodecs); Main_addEventListener('keydown', Settings_handleKeyDown); + Main_getElementById('settings_codec_container_scroll').style.transform = ''; } function Settings_handleKeyDownCodecsLeft() { @@ -2103,17 +2105,15 @@ function Settings_handleKeyDownCodecs(event) { case KEY_UP: if (Settings_CodecsPos > 0) { Settings_CodecsUpDown(-1); - if (Settings_CodecsPos === 3) { - Settings_ScrollCodecs(); - } + + Settings_ScrollCodecs(Settings_CodecsPos); } break; case KEY_DOWN: if (Settings_CodecsPos < Settings_CodecsValue.length - 1) { Settings_CodecsUpDown(1); - if (Settings_CodecsPos === 4) { - Settings_ScrollCodecs(true); - } + + Settings_ScrollCodecs(Settings_CodecsPos); } break; default: @@ -2121,14 +2121,17 @@ function Settings_handleKeyDownCodecs(event) { } } -function Settings_ScrollCodecs(down) { - var docId = 'settings_codec_container'; +function Settings_ScrollCodecs(pos) { + var center = 3, + doc = Main_getElementById('settings_codec_container_scroll'), + value = 0, + offset = 0; - if (down) { - Settings_Do_ScrollDown(docId); - } else { - Settings_Do_ScrollUp(docId); + if (pos > center) { + value = Main_getElementById(Settings_CodecsValue[pos - center - offset].name).offsetTop; } + + doc.style.transform = 'translateY(-' + value / BodyfontSize + 'em)'; } function Settings_Codecs_isVisible() { @@ -2302,7 +2305,7 @@ function Settings_SetCodecsValue() { // ]; Settings_CodecsValue = JSON.parse( - '[{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"5.2","maxresolution":"3840x2176","name":"OMX.Nvidia.h264.decode","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 555 fps | 1080p : 245 fps | 1440p : 138 fps | 2160p : 61 fps","type":"video/avc"},{"instances":32,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.google.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":-1,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.chico.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.goldfish.hevc.decoder","resolutions":"160p : 480 fps | 360p : 480 fps | 480p : 480 fps | 720p : 480 fps | 900p : 364 fps | 1080p : 254 fps | 1440p : 144 fps | 2160p : 64 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.android.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"OMX.google.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.android.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"}]' + '[{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"5.2","maxresolution":"3840x2176","name":"OMX.Nvidia.h264.decode","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 555 fps | 1080p : 245 fps | 1440p : 138 fps | 2160p : 61 fps","type":"video/avc"},{"instances":32,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.google.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":-1,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.chico.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.goldfish.hevc.decoder","resolutions":"160p : 480 fps | 360p : 480 fps | 480p : 480 fps | 720p : 480 fps | 900p : 364 fps | 1080p : 254 fps | 1440p : 144 fps | 2160p : 64 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.android.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"OMX.google.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.android.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.google.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.test.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c.test2.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"}]' ); } else { try { From c1e5ac915fb3e0c47ead1c98b8dfcc48427cf7c9 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 21:52:15 -0300 Subject: [PATCH 16/29] tools add more resolutions for codecs --- apk/app/src/main/java/com/fgl27/twitch/Tools.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/Tools.java b/apk/app/src/main/java/com/fgl27/twitch/Tools.java index 7c3ab5c34..a95a40ba6 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/Tools.java +++ b/apk/app/src/main/java/com/fgl27/twitch/Tools.java @@ -216,7 +216,9 @@ public final class Tools { 1600, 1920, 2560, - 3840 + 3840, + 7680, + 8192 }; private static final Integer[] resolutionsHeight = { @@ -227,7 +229,9 @@ public final class Tools { 900, 1080, 1440, - 2160 + 2160, + 4320, + 4608 }; static String ResponseObjToString(long checkResult) { From 1669c71cb0d5be44b34b69b2f950233d737e883e Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 22:19:53 -0300 Subject: [PATCH 17/29] improve codecframeRate --- .../src/main/java/com/fgl27/twitch/Tools.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/Tools.java b/apk/app/src/main/java/com/fgl27/twitch/Tools.java index a95a40ba6..6b9ad9cd0 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/Tools.java +++ b/apk/app/src/main/java/com/fgl27/twitch/Tools.java @@ -221,7 +221,20 @@ public final class Tools { 8192 }; - private static final Integer[] resolutionsHeight = { + private static final String[] resolutionsHeight = { + "160p", + "360p", + "480p", + "720p", + "900p", + "1080p", + "1440p", + "4k", + "8k", + "8k" + }; + + private static final Integer[] resolutionsHeightInt = { 160, 360, 480, @@ -409,7 +422,7 @@ static String codecCapabilities(String CodecType) { StringBuilder values = new StringBuilder(); for (int i = 0; i < resolutionsWidth.length; i++) { - resolutions = codecframeRate(videoCapabilities, resolutionsWidth[i], resolutionsHeight[i], lowerWidth, UperWidth); + resolutions = codecframeRate(videoCapabilities, resolutionsWidth[i], resolutionsHeight[i], resolutionsHeightInt[i], lowerWidth, UperWidth); if (resolutions != null) values.append(resolutions); } @@ -447,15 +460,15 @@ static String codecCapabilities(String CodecType) { return new Gson().toJson(result); } - private static String codecframeRate(MediaCodecInfo.VideoCapabilities videoCapabilities, int width, int height, int lowerWidth, int UperWidth) { + private static String codecframeRate(MediaCodecInfo.VideoCapabilities videoCapabilities, int width, String height, int heightInt, int lowerWidth, int UperWidth) { try { //Check if is bigger then smallest and smaller then the biggest return (width >= lowerWidth && width <= UperWidth) ? String.format( Locale.US, - "%dp : %d fps | ", + "%s : %d fps | ", height, - Math.round(videoCapabilities.getSupportedFrameRatesFor(width, height).getUpper()) + Math.round(videoCapabilities.getSupportedFrameRatesFor(width, heightInt).getUpper()) ) : null; } catch (Exception e) { From 1d1fe0cd96a935b6d96b219177d2f92a3ba24b0b Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 22:43:37 -0300 Subject: [PATCH 18/29] Improve settings strings --- app/languages/0_Strings.js | 3 +++ app/languages/en_US.js | 9 ++++++--- app/specific/Settings.js | 16 ++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/app/languages/0_Strings.js b/app/languages/0_Strings.js index fd06145cb..f59c999e0 100644 --- a/app/languages/0_Strings.js +++ b/app/languages/0_Strings.js @@ -181,6 +181,7 @@ var STR_IS_NOW; var STR_OPEN_HOST; var STR_SETTINGS_PLAYER; var STR_SETTINGS_BUFFER_SIZE; +var STR_SETTINGS_BUFFER_SIZE_SHORT_SUMMARY; var STR_SETTINGS_BUFFER_SIZE_SUMMARY; var STR_SETTINGS_BUFFER_LIVE; var STR_SETTINGS_BUFFER_VOD; @@ -264,6 +265,7 @@ var STR_PLAYER_PROBLEM_2; var STR_EXIT_AGAIN_PICTURE; var STR_PLAYER_RESYNC; var STR_PLAYER_BITRATE; +var STR_PLAYER_BITRATE_SHORT_SUMMARY; var STR_PLAYER_BITRATE_SUMMARY; var STR_PLAYER_BITRATE_MAIN; var STR_PLAYER_BITRATE_SMALL; @@ -638,6 +640,7 @@ var STR_LATENCY_TO_BROADCASTER; var STR_CHAT_DELAY_LATENCY_TO_BROADCASTER; var STR_CHAT_SEND_DELAY; var STR_BLOCK_RES; +var STR_BLOCK_RES_SHORT_SUMMARY; var STR_BLOCK_RES_SUMMARY; var STR_BLOCK_RES_SUMMARY_EXTRA; var STR_BLOCKED; diff --git a/app/languages/en_US.js b/app/languages/en_US.js index e07ee83e0..e6af01630 100644 --- a/app/languages/en_US.js +++ b/app/languages/en_US.js @@ -255,6 +255,7 @@ function en_USLang() { STR_OPEN_HOST = 'Open the Hosting'; STR_SETTINGS_PLAYER = 'Player related'; STR_SETTINGS_BUFFER_SIZE = 'Start buffer size:'; + STR_SETTINGS_BUFFER_SIZE_SHORT_SUMMARY = 'Controls start buffer size'; STR_SETTINGS_BUFFER_SIZE_SUMMARY = 'How much is needed to buffer before starting the playback. This is not related to the maximum size that the buffer can reach (the maximum buffer size is based on the amount of RAM on the device). A lower value here will cause the playback to start sooner and that is always recommended. Changing this value to a bigger value will in most cases not cause any improvements, but rather setbacks.'; STR_SETTINGS_BUFFER_LIVE = 'Lives start buffer'; @@ -360,6 +361,7 @@ function en_USLang() { STR_QUALITY_MULTI_BIG = [STR_PLAYER_MULTI_ALL, 'Top', 'Bottom left', 'Bottom center', 'Bottom right']; STR_PLAYER_BITRATE_UNLIMITED = 'Unlimited'; STR_PLAYER_BITRATE = 'Auto quality maximum allowed Resolution/Bitrate'; + STR_PLAYER_BITRATE_SHORT_SUMMARY = 'Allows to set max Resolution/Bitrate used by Auto quality playback'; STR_PLAYER_BITRATE_SUMMARY = "This is used to prevent lag on low-end devices when playing multiple videos at the same time (most devices will lag by skipping frames in that situation, as they are only made to play a single video). Also helps limit the internet bandwidth use in case you need a limit that also sets the 'Default player quality' to auto quality. The recommended resolution/bitrate for all small players is 720p/3 Mbps and unlimited for main or big players for most low-end devices."; STR_PLAYER_BITRATE_SUMMARY_ETC = @@ -371,6 +373,7 @@ function en_USLang() { STR_PLAYER_RES_MAIN = 'Resolution - ' + STR_PLAYER_MAIN; STR_PLAYER_RES_SMALL = 'Resolution - ' + STR_PLAYER_RES_SMALL; STR_BLOCK_RES = 'Blocked resolutions'; + STR_BLOCK_RES_SHORT_SUMMARY = 'Allows to block one or more resolutions from ever being used'; STR_BLOCK_RES_SUMMARY = "When using auto quality, it's possible to block one or more resolutions from ever being used. This is useful for devices that lag playing at a particular resolution. As clips can't be played in auto mode, this will also block the automatic part of this resolution in a clip."; STR_BLOCK_RES_SUMMARY_EXTRA = @@ -387,7 +390,7 @@ function en_USLang() { STR_AUDIO = 'Audio -'; STR_DEF_QUALITY = 'Default player quality'; STR_DEF_QUALITY_SUMMARY = - "This option will always override others when playing a single video. In picture-in-picture or multistream mode, the playback needs to use auto quality. The reason for why that can be found under the settings option '" + + "This option will override all others when playing a single video. In multi-player modes, the playback needs to use auto quality. The reason for this can be found under the settings option '" + STR_PLAYER_BITRATE + "'."; STR_PICTURE_PICTURE = 'Picture in picture, 50/50 or multistream (for lives only):'; @@ -498,7 +501,7 @@ function en_USLang() { STR_USER_LIVE = 'User live side panel: Left D-pad from the side panel or key 3 from anywhere'; STR_PP_WORKAROUND = 'Multiplayer, PP and preview mode workaround'; STR_PP_WORKAROUND_SUMMARY = - "For some devices usually running old versions of Android, it is necessary to enable this to have multiplayer mode working properly. Usually, the issue is that the player (PP or preview) will not be visible, or even when not in use it is visible as a black box over the main player. Don't enable this if you don't have issues, as it will result in lower image quality and possible loss of performance"; + "For some devices, it is necessary to enable this to have multiplayer mode working properly. The issue is usually that one of the two players becomes a black screen. Don't enable it if you don't have issues, as it will cause lower image quality and poor performance."; STR_HISTORY = 'History'; STR_WATCHED = 'Watched on'; STR_UNTIL = 'until'; @@ -621,7 +624,7 @@ function en_USLang() { STR_MULTI_MAIN_WINDOW + ' bigger and chat: Press the down key and after that use the left/right keys to change the big video'; STR_SOURCE_CHECK = 'Automatically change player quality from Source to Auto when the player lags'; STR_SOURCE_CHECK_SUMMARY = - "When this option is enabled, and you aren't using auto quality, the player will switch to auto quality and warn about it if the player is lagging. A player lag is for example when the player is unable to play for over 15 seconds (the algorithm is more complex than just time of course), after this, changing the player will automatically go back to the source when you open a new VOD stream."; + 'When enabled, and not using auto quality, the player will switch to auto quality and warn about it if the player is lagging. A Player lag is when the player is unable to play for a few seconds (the algorithm is more complex than just time), if you play something else it will go back to the original quality.'; STR_PLAYER_LAG = "Player is lagging, quality changed to 'Auto mode'"; STR_PLAYER_SOURCE = 'Player is lagging, quality was lowered'; STR_TOO_ERRORS = 'or too many errors'; diff --git a/app/specific/Settings.js b/app/specific/Settings.js index 5b4fd7cc3..14bec1a86 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -880,13 +880,13 @@ function Settings_SetSettings() { div += Settings_Content('player_extracodecs', [STR_ENTER_TO_OPEN], STR_PLAYER_EXTRA_CODEC, STR_PLAYER_EXTRA_CODEC_SUMMARY); div += Settings_Content('blocked_codecs', [STR_ENTER_TO_OPEN], STR_BLOCKED_CODEC, STR_BLOCKED_CODEC_SUMMARY); - div += Settings_Content('block_qualities', [STR_ENTER_TO_OPEN], STR_BLOCK_RES, STR_BLOCK_RES_SUMMARY); - div += Settings_Content('player_bitrate', [STR_ENTER_TO_OPEN], STR_PLAYER_BITRATE, STR_PLAYER_BITRATE_SUMMARY); + div += Settings_Content('block_qualities', [STR_ENTER_TO_OPEN], STR_BLOCK_RES, STR_BLOCK_RES_SHORT_SUMMARY); + div += Settings_Content('player_bitrate', [STR_ENTER_TO_OPEN], STR_PLAYER_BITRATE, STR_PLAYER_BITRATE_SHORT_SUMMARY); div += Settings_Content('preview_settings', [STR_ENTER_TO_OPEN], STR_SIDE_PANEL_PLAYER, null); div += Settings_Content('vod_seek', [STR_ENTER_TO_OPEN], STR_VOD_SEEK, null); div += Settings_Content('playerend_opt', [STR_ENTER_TO_OPEN], STR_END_DIALOG_OPT, null); - div += Settings_Content('player_buffers', [STR_ENTER_TO_OPEN], STR_SETTINGS_BUFFER_SIZE, STR_SETTINGS_BUFFER_SIZE_SUMMARY); + div += Settings_Content('player_buffers', [STR_ENTER_TO_OPEN], STR_SETTINGS_BUFFER_SIZE, STR_SETTINGS_BUFFER_SIZE_SHORT_SUMMARY); Main_innerHTML('settings_main', div); Settings_positions_length = Settings_value_keys.length; @@ -1864,7 +1864,7 @@ function Settings_Do_ScrollUp(docId) { function Settings_ScrollTable() { var scroolPos = 14, - offset = !Main_isTV || !Main_IsOn_OSInterface ? 1 : 0; + offset = 0; //!Main_isTV || !Main_IsOn_OSInterface ? 1 : 0; if (Settings_CurY < Settings_cursorY && Settings_cursorY === scroolPos + offset) { Settings_ScrollDown(); @@ -2342,7 +2342,9 @@ function Settings_QualitiesCheck() { len = array_values.length; for (i; i < len; i++) { - if (Settings_Obj_default('block_qualities_' + array_values[i])) Settings_DisableQualities.push(array_values[i]); + if (Settings_Obj_default('block_qualities_' + array_values[i])) { + Settings_DisableQualities.push(array_values[i]); + } } Settings_DisableQualitiesLen = Settings_DisableQualities.length; @@ -2355,7 +2357,9 @@ function Settings_QualitiesCheck() { } function Settings_Qualities() { - if (Main_IsOn_OSInterface) OSInterface_setBlackListQualities(Settings_DisableQualities.join()); + if (Main_IsOn_OSInterface) { + OSInterface_setBlackListQualities(Settings_DisableQualities.join()); + } } function Settings_ForceEnableAnimations() { From 7ac4dbf203497e13fd592a98fadc33583fd08193 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Fri, 2 Aug 2024 23:34:26 -0300 Subject: [PATCH 19/29] improve blocked resolutions --- .../java/com/fgl27/twitch/PlayerActivity.java | 6 ++++- app/specific/Settings.js | 24 +++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java index a15d9a80b..b5b99e508 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java +++ b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java @@ -2264,6 +2264,7 @@ public void setEnabledQualities(int position) { TrackGroup groupIndex = trackGroupArray.get(0); int groupIndex_len = groupIndex.length; boolean add; + String[] BLACKLISTED_QUALITIES_LOWER_UPER = null; for (int trackIndex = 0; trackIndex < groupIndex_len; trackIndex++) { format = groupIndex.getFormat(trackIndex); @@ -2272,7 +2273,10 @@ public void setEnabledQualities(int position) { if (format.bitrate <= MaxBitrate && format.height <= MaxResolution) { for (String value : BLACKLISTED_QUALITIES) { - if (Integer.toString(format.height).startsWith(value)) { + BLACKLISTED_QUALITIES_LOWER_UPER = value.split("-");//'4200-4600', '1700-2200', '1500-1700', '1400-1500', '1000-1100', '900-1000', '700-800', '400-500', '300-400' + + if (format.height > Integer.parseInt(BLACKLISTED_QUALITIES_LOWER_UPER[0]) && + format.height < Integer.parseInt(BLACKLISTED_QUALITIES_LOWER_UPER[1])) { add = false; break; } diff --git a/app/specific/Settings.js b/app/specific/Settings.js index 14bec1a86..caa83496b 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -631,6 +631,11 @@ var Settings_value = { values: ['no', 'yes'], defaultValue: 1 }, + block_qualities_43: { + //Migrated to dialog + values: ['enabled', 'disabled'], + defaultValue: 1 + }, block_qualities_21: { //Migrated to dialog values: ['enabled', 'disabled'], @@ -1323,6 +1328,7 @@ function Settings_SetDefault(position) { else if (position === 'vod_seek_max') Settings_check_max_seek(); else if (position === 'auto_minimize_inactive') Settings_SetAutoMinimizeTimeout(); else if ( + position === 'block_qualities_43' || position === 'block_qualities_21' || position === 'block_qualities_16' || position === 'block_qualities_14' || @@ -2337,13 +2343,14 @@ function Settings_SetSuportedCodecs(codecs) { function Settings_QualitiesCheck() { Settings_DisableQualities = []; - var array_values = ['21', '16', '14', '10', '9', '7', '4', '3'], + var array_values = ['43', '21', '16', '14', '10', '9', '7', '4', '3'], + array_blocked_values = ['4200-4600', '1700-2200', '1500-1700', '1400-1500', '1000-1100', '900-1000', '700-800', '400-500', '300-400'], i = 0, len = array_values.length; for (i; i < len; i++) { if (Settings_Obj_default('block_qualities_' + array_values[i])) { - Settings_DisableQualities.push(array_values[i]); + Settings_DisableQualities.push(array_blocked_values[i]); } } @@ -3110,6 +3117,7 @@ function Settings_DialogShowChat(click) { function Settings_block_qualities(click) { var array_ena_dis = [STR_BLOCKED_NOT, STR_BLOCKED]; + Settings_value.block_qualities_43.values = array_ena_dis; Settings_value.block_qualities_21.values = array_ena_dis; Settings_value.block_qualities_16.values = array_ena_dis; Settings_value.block_qualities_14.values = array_ena_dis; @@ -3120,22 +3128,28 @@ function Settings_block_qualities(click) { Settings_value.block_qualities_3.values = array_ena_dis; var obj = { + block_qualities_43: { + defaultValue: Settings_value.block_qualities_43.defaultValue, + values: Settings_value.block_qualities_43.values, + title: '42XXp to 46XXp 8k', + summary: null + }, block_qualities_21: { defaultValue: Settings_value.block_qualities_21.defaultValue, values: Settings_value.block_qualities_21.values, - title: '21XXp', + title: '17XXp to 22XXp 4k', summary: null }, block_qualities_16: { defaultValue: Settings_value.block_qualities_16.defaultValue, values: Settings_value.block_qualities_16.values, - title: '16XXp', + title: '15XXp to 17XXp 2.5k', summary: null }, block_qualities_14: { defaultValue: Settings_value.block_qualities_14.defaultValue, values: Settings_value.block_qualities_14.values, - title: '14XXp', + title: '14XXp 2k', summary: null }, block_qualities_10: { From 029c47916a0b00632143837767b7a36380e5afa1 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Sat, 3 Aug 2024 10:06:36 -0300 Subject: [PATCH 20/29] update git ignore --- apk/.gitignore | 1 + apk/.idea/deploymentTargetSelector.xml | 18 ------------------ 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 apk/.idea/deploymentTargetSelector.xml diff --git a/apk/.gitignore b/apk/.gitignore index d7c602581..1bc010a3d 100644 --- a/apk/.gitignore +++ b/apk/.gitignore @@ -8,6 +8,7 @@ /.idea/workspace.xml /.idea/navEditor.xml /.idea/assetWizardSettings.xml +/.idea/deploymentTargetSelector.xml .DS_Store /build /app/release diff --git a/apk/.idea/deploymentTargetSelector.xml b/apk/.idea/deploymentTargetSelector.xml deleted file mode 100644 index b1fef2e12..000000000 --- a/apk/.idea/deploymentTargetSelector.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - \ No newline at end of file From 06450290abffafa03b9b539aeaf97d828b754958 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Sat, 3 Aug 2024 10:09:40 -0300 Subject: [PATCH 21/29] add a blocked obj for home screen --- .../main/java/com/fgl27/twitch/Constants.java | 3 +++ .../java/com/fgl27/twitch/PlayerActivity.java | 12 +++++++++ app/specific/Main.js | 17 +++++++++++- app/specific/OSInterface.js | 26 ++++++++++++++++--- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/Constants.java b/apk/app/src/main/java/com/fgl27/twitch/Constants.java index 8d0eaf9e5..13401dfa9 100755 --- a/apk/app/src/main/java/com/fgl27/twitch/Constants.java +++ b/apk/app/src/main/java/com/fgl27/twitch/Constants.java @@ -69,6 +69,9 @@ public final class Constants { public static final String CHANNEL_INTENT = "channel_intent";//f update this also update it on the manifest... ChannelsReceiver & PlayerActivity public static final String CHANNEL_TYPE = "channel_type"; + public static final String BLOCKED_CHANNEL = "blocked_channel"; + public static final String BLOCKED_GAMES = "blocked_games"; + public static final String[][] BASE_HEADERS = { {"Client-ID", ""}, {"Authorization", "Bearer "} diff --git a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java index b5b99e508..2c5aebf1c 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java +++ b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java @@ -2724,6 +2724,18 @@ public void setAppToken(String token) { appPreferences.put(Constants.PREF_CLIENT_TOKEN, token); } + public void UpdateBlockedChannels(String channelsJson) { + appPreferences.put(Constants.BLOCKED_CHANNEL, channelsJson); + + RefreshChannel(Constants.CHANNEL_TYPE_LIVE, true, mWebViewContext); + } + + public void UpdateBlockedGames(String gamesJson) { + appPreferences.put(Constants.BLOCKED_GAMES, gamesJson); + + RefreshChannel(Constants.CHANNEL_TYPE_GAMES, true, mWebViewContext); + } + @JavascriptInterface public void UpdateUserId(String id, String name, String access_token) { diff --git a/app/specific/Main.js b/app/specific/Main.js index f114bfca4..ee6b530ef 100644 --- a/app/specific/Main.js +++ b/app/specific/Main.js @@ -2342,6 +2342,7 @@ function Main_Restore_history() { Main_values_History_data = Screens_assign(Main_values_History_data, Main_getItemJson('Main_values_History_data', {})); Main_history_SetVod_Watched(); + Main_UpdateBlockedHomeScreen(); } function Main_History_Sort(array, msort, direction) { @@ -2366,7 +2367,21 @@ function Main_setHistoryItem(time) { function Main_SaveHistoryItem() { var string = JSON.stringify(Main_values_History_data); Main_setItem('Main_values_History_data', string); - if (Main_CanBackup) OSInterface_BackupFile(Main_HistoryBackupFile, string); + + if (Main_CanBackup) { + OSInterface_BackupFile(Main_HistoryBackupFile, string); + } + Main_UpdateBlockedHomeScreen(); +} + +function Main_UpdateBlockedHomeScreen() { + OSInterface_UpdateBlockedChannels(); + OSInterface_UpdateBlockedGames(); +} + +function Main_GetBlockedJson(type) { + var blockedObj = Main_values_History_data[AddUser_UsernameArray[0].id].blocked[type]; + return JSON.stringify(Object.keys(blockedObj)); } //Only works on vectors, matrixs and etc need to use JSON.parse(JSON.stringify(array)) to prevent keeping the iner obj references diff --git a/app/specific/OSInterface.js b/app/specific/OSInterface.js index ee35c0ada..7379c7f96 100644 --- a/app/specific/OSInterface.js +++ b/app/specific/OSInterface.js @@ -373,14 +373,34 @@ function OSInterface_mhideSystemUI() { Android.mhideSystemUI(); } +//public void OSInterface_UpdateBlockedChannels(String channelsJson) +//channelsJson = channelsJson map with all blocked channels +//Sets the map of blocked channels used by home screen content +function OSInterface_UpdateBlockedChannels() { + if (Main_IsOn_OSInterface) { + try { + Android.UpdateBlockedChannels(Main_GetBlockedJson('channel')); + } catch (e) {} + } +} + +//public void UpdateBlockedGames(String gamesJson) +//gamesJson = gamesJson map with all blocked games +//Sets the map of blocked games used by home screen content +function OSInterface_UpdateBlockedGames() { + if (Main_IsOn_OSInterface) { + try { + Android.UpdateBlockedGames(Main_GetBlockedJson('game')); + } catch (e) {} + } +} + //public void setAppToken(String token) //token = token to save //Sets the app token when value is updated from JS function OSInterface_setAppToken() { if (Main_IsOn_OSInterface) { - try { - Android.setAppToken(AddCode_main_token ? AddCode_main_token : null); - } catch (e) {} + Android.setAppToken(AddCode_main_token ? AddCode_main_token : null); } } From 695fa5b5b3b4a0c0499c3ac1b96442325a67186c Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Sat, 3 Aug 2024 11:19:36 -0300 Subject: [PATCH 22/29] live and games home screen check for blocked --- .../java/com/fgl27/twitch/PlayerActivity.java | 18 +++++++++--- .../src/main/java/com/fgl27/twitch/Tools.java | 11 ++++++- .../fgl27/twitch/channels/ChannelsUtils.java | 29 ++++++++++++------- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java index 2c5aebf1c..4ad268e13 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java +++ b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java @@ -2724,16 +2724,26 @@ public void setAppToken(String token) { appPreferences.put(Constants.PREF_CLIENT_TOKEN, token); } + @JavascriptInterface public void UpdateBlockedChannels(String channelsJson) { - appPreferences.put(Constants.BLOCKED_CHANNEL, channelsJson); + String savedChannels = Tools.getString(Constants.BLOCKED_CHANNEL, null, appPreferences); + + if (!Objects.equals(savedChannels, channelsJson)) { + appPreferences.put(Constants.BLOCKED_CHANNEL, channelsJson); + RefreshChannel(Constants.CHANNEL_TYPE_LIVE, true, mWebViewContext); + } - RefreshChannel(Constants.CHANNEL_TYPE_LIVE, true, mWebViewContext); } + @JavascriptInterface public void UpdateBlockedGames(String gamesJson) { - appPreferences.put(Constants.BLOCKED_GAMES, gamesJson); + String savedGames = Tools.getString(Constants.BLOCKED_GAMES, null, appPreferences); + + if (!Objects.equals(savedGames, gamesJson)) { - RefreshChannel(Constants.CHANNEL_TYPE_GAMES, true, mWebViewContext); + appPreferences.put(Constants.BLOCKED_GAMES, gamesJson); + RefreshChannel(Constants.CHANNEL_TYPE_GAMES, true, mWebViewContext); + } } @JavascriptInterface diff --git a/apk/app/src/main/java/com/fgl27/twitch/Tools.java b/apk/app/src/main/java/com/fgl27/twitch/Tools.java index 6b9ad9cd0..3c3e07323 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/Tools.java +++ b/apk/app/src/main/java/com/fgl27/twitch/Tools.java @@ -101,6 +101,7 @@ import java.util.Locale; import java.util.Map; import java.util.Scanner; +import java.util.Set; import java.util.StringTokenizer; @SuppressLint("UnsafeOptInUsageError") @@ -112,6 +113,9 @@ public final class Tools { private static final Type ArrayType = new TypeToken() { }.getType(); + private static final Type setType = new TypeToken>() { + }.getType(); + //https://developer.android.com/reference/android/media/MediaCodecInfo.CodecProfileLevel.html private static final Map AvcLevelsMap = new HashMap() {{ put(1, "1"); @@ -933,7 +937,7 @@ private static boolean deleteDir(File dir) { } public static boolean hasTokens(String UserId, AppPreferences appPreferences) { - return Tools.getString(UserId + Constants.PREF_ACCESS_TOKEN, null, appPreferences) != null; + return getString(UserId + Constants.PREF_ACCESS_TOKEN, null, appPreferences) != null; } public static boolean refreshTokens(String UserId, AppPreferences appPreferences) { @@ -1291,6 +1295,10 @@ private static Locale parseLangCode(String langCode) { return new Locale(lang, country); } + public static Set getBlockedByType(String type, AppPreferences appPreferences) { + return new Gson().fromJson(getString(type, "[]", appPreferences), setType); + } + public static class ResponseObj { public final int status; public final String responseText; @@ -1349,4 +1357,5 @@ private static class QualitiesObj { } } + } diff --git a/apk/app/src/main/java/com/fgl27/twitch/channels/ChannelsUtils.java b/apk/app/src/main/java/com/fgl27/twitch/channels/ChannelsUtils.java index 9fc45df3a..3656db38b 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/channels/ChannelsUtils.java +++ b/apk/app/src/main/java/com/fgl27/twitch/channels/ChannelsUtils.java @@ -595,7 +595,8 @@ public static void SetUserLive(Context context, String userId, AppPreferences ap Streams,//Get the follows array true, Constants.CHANNEL_TYPE_USER_LIVE, - context + context, + new HashSet() ), channelId, CHANNELS_NAMES @@ -734,6 +735,7 @@ private static List GetLiveContent(String url, String object, {Constants.BASE_HEADERS[1][0], Tools.getString(UserId + Constants.PREF_ACCESS_TOKEN, null, appPreferences)} }; int status; + Set blockedChannels = Tools.getBlockedByType(Constants.BLOCKED_CHANNEL, appPreferences); try { Tools.ResponseObj response; @@ -762,7 +764,8 @@ private static List GetLiveContent(String url, String object, obj.get(object).getAsJsonArray(),//Get the follows array sort, screen, - context + context, + blockedChannels ); } @@ -790,12 +793,16 @@ private static List GetLiveContent(String url, String object, } - private static List ProcessLiveArray(JsonArray Streams, boolean sort, int screen, Context context) { + private static List ProcessLiveArray(JsonArray Streams, boolean sort, int screen, Context context, Set blockedChannels) { List content = new ArrayList<>(); int objSize = Streams.size(); - if (objSize < 1) return null; - else content.add(getRefreshContent(context)); + + if (objSize < 1) { + return null; + } else { + content.add(getRefreshContent(context)); + } Set TempArray = new HashSet<>(); @@ -830,8 +837,7 @@ private static List ProcessLiveArray(JsonArray Streams, boole channelId = obj.get("user_id").getAsString(); - if (!TempArray.contains(channelId)) {//Prevent add duplicated - + if (!TempArray.contains(channelId) && !blockedChannels.contains(channelId)) {//Prevent add duplicated TempArray.add(channelId); preview = !obj.get("thumbnail_url").isJsonNull() ? obj.get("thumbnail_url").getAsString() : null; @@ -901,8 +907,9 @@ private static List ProcessLiveArray(JsonArray Streams, boole } private static List GetGamesContent(Context context, String UserId, AppPreferences appPreferences) { + Set blockedGames = Tools.getBlockedByType(Constants.BLOCKED_GAMES, appPreferences); - JsonArray Games = GetLiveGames(UserId, appPreferences, true);//Get the Games array + JsonArray Games = GetLiveGames(UserId, appPreferences, true, blockedGames);//Get the Games array List content = new ArrayList<>(); int objSize = Games != null ? Games.size() : 0; @@ -948,7 +955,7 @@ private static List GetGamesContent(Context context, String U } - private static JsonArray GetLiveGames(String UserId, AppPreferences appPreferences, Boolean tryAgain) { + private static JsonArray GetLiveGames(String UserId, AppPreferences appPreferences, Boolean tryAgain, Set blockedGames) { JsonArray Result = new JsonArray(); int status = 0; @@ -1002,7 +1009,7 @@ private static JsonArray GetLiveGames(String UserId, AppPreferences appPreferenc gameId = !obj.get("id").isJsonNull() ? obj.get("id").getAsString() : null; - if (gameId != null && !TempArray.contains(gameId)) {//Prevent add duplicated + if (gameId != null && !TempArray.contains(gameId) && !blockedGames.contains(gameId)) {//Prevent add duplicated TempArray.add(gameId); Result.add(obj); @@ -1018,7 +1025,7 @@ private static JsonArray GetLiveGames(String UserId, AppPreferences appPreferenc if (tryAgain && Tools.refreshTokens(UserId, appPreferences)) { - return GetLiveGames(UserId, appPreferences, false); + return GetLiveGames(UserId, appPreferences, false, blockedGames); } else if (!tryAgain) { break; From 2f9cb0f7d77e255a2689b232eb604c40ae55bd15 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Sat, 3 Aug 2024 11:33:35 -0300 Subject: [PATCH 23/29] improve Main_GetBlockedJson --- app/specific/Main.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/specific/Main.js b/app/specific/Main.js index ee6b530ef..153a0afd2 100644 --- a/app/specific/Main.js +++ b/app/specific/Main.js @@ -2380,6 +2380,10 @@ function Main_UpdateBlockedHomeScreen() { } function Main_GetBlockedJson(type) { + if (!AddUser_IsUserSet()) { + return '[]'; + } + var blockedObj = Main_values_History_data[AddUser_UsernameArray[0].id].blocked[type]; return JSON.stringify(Object.keys(blockedObj)); } From 5613273391a4f8cccd55981a5f4664bce0eee4c0 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Sat, 3 Aug 2024 22:18:49 -0300 Subject: [PATCH 24/29] Add controls for speed adjust --- .../java/com/fgl27/twitch/PlayerActivity.java | 12 ++++++++++++ apk/app/src/main/java/com/fgl27/twitch/Tools.java | 3 ++- app/general/resize.js | 2 +- app/index.html | 6 +++--- app/languages/0_Strings.js | 2 ++ app/languages/en_US.js | 6 +++++- app/specific/OSInterface.js | 11 +++++++++++ app/specific/Settings.js | 15 +++++++++++++++ 8 files changed, 51 insertions(+), 6 deletions(-) diff --git a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java index 4ad268e13..58ef7294f 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java +++ b/apk/app/src/main/java/com/fgl27/twitch/PlayerActivity.java @@ -187,6 +187,7 @@ public class PlayerActivity extends Activity { private long NetCounter = 0L; private long SpeedCounter = 0L; private int mLowLatency = 0; + private boolean speedAdjustment = false; private boolean AlreadyStarted; private boolean onCreateReady; private boolean IsStopped; @@ -2943,6 +2944,7 @@ public void ReuseFeedPlayer(String uri, String mainPlaylistString, int Type, lon mWebViewContext, Type, mLowLatency, + speedAdjustment, mainPlaylistString, userAgent ); @@ -2986,6 +2988,7 @@ public void StartAuto(String uri, String mainPlaylistString, int Type, long Resu mWebViewContext, Type, mLowLatency, + speedAdjustment, mainPlaylistString, userAgent ); @@ -3239,6 +3242,7 @@ public void StartFeedPlayer(String uri, String mainPlaylistString, int position, mWebViewContext, isVod ? 2 : 1, mLowLatency, + speedAdjustment, mainPlaylistString, userAgent ); @@ -3286,6 +3290,7 @@ public void StartSidePanelPlayer(String uri, String mainPlaylistString) { mWebViewContext, 1, mLowLatency, + speedAdjustment, mainPlaylistString, userAgent ); @@ -3316,6 +3321,7 @@ public void StartScreensPlayer(String uri, String mainPlaylistString, int Resume mWebViewContext, Type, mLowLatency, + speedAdjustment, mainPlaylistString, userAgent ); @@ -3379,6 +3385,11 @@ public void mSetlatency(int LowLatency) { mLowLatency = LowLatency; } + @JavascriptInterface + public void setSpeedAdjustment(boolean pSpeedAdjustment) { + speedAdjustment = pSpeedAdjustment; + } + @JavascriptInterface public void stopVideo() { runOnUiThread(PlayerActivity.this::ResetPlayerState); @@ -3809,6 +3820,7 @@ public void StartMultiStream(int position, String uri, String mainPlaylistString mWebViewContext, 1, mLowLatency, + speedAdjustment, mainPlaylistString, userAgent ); diff --git a/apk/app/src/main/java/com/fgl27/twitch/Tools.java b/apk/app/src/main/java/com/fgl27/twitch/Tools.java index 3c3e07323..04573af58 100644 --- a/apk/app/src/main/java/com/fgl27/twitch/Tools.java +++ b/apk/app/src/main/java/com/fgl27/twitch/Tools.java @@ -529,11 +529,12 @@ static DefaultLoadControl getLoadControl(int buffer, int DeviceRam) { .build(); } - static MediaSource buildMediaSource(Uri uri, Context context, int Type, int LowLatency, String mainPlaylist, String userAgent) { + static MediaSource buildMediaSource(Uri uri, Context context, int Type, int LowLatency, boolean speedAdjustment, String mainPlaylist, String userAgent) { if (Type == 1) { return new HlsMediaSource.Factory(getDefaultDataSourceFactory(mainPlaylist, uri, userAgent)) .setAllowChunklessPreparation(true) .setLowLatency(LowLatency) + .setspeedAdjustment(speedAdjustment) .createMediaSource(MediaItemBuilder(uri)); } else if (Type == 2) { return new HlsMediaSource.Factory(getDefaultDataSourceFactory(mainPlaylist, uri, userAgent)) diff --git a/app/general/resize.js b/app/general/resize.js index a0b79007e..a2b1a6413 100644 --- a/app/general/resize.js +++ b/app/general/resize.js @@ -85,7 +85,7 @@ function calculateFontSize() { //Some sizes are based on VH but some devices have a wrong value for CSS vh var ele = Main_getElementById('settings_scroll'); if (ele) { - ele.style.fontSize = currentHeight * 0.0267 + 'px'; + ele.style.fontSize = currentHeight * 0.0254 + 'px'; } var cssClass = diff --git a/app/index.html b/app/index.html index 0310e3eb8..35d9e9391 100644 --- a/app/index.html +++ b/app/index.html @@ -1731,9 +1731,9 @@ .settings_main { font-family: 'Roboto-Bold'; color: #ffffff; - width: 96%; - margin-left: 2%; - margin-bottom: 1%; + width: 98%; + margin-left: 1%; + margin-bottom: 0.5%; } .hist_div, diff --git a/app/languages/0_Strings.js b/app/languages/0_Strings.js index f59c999e0..eee92cb5d 100644 --- a/app/languages/0_Strings.js +++ b/app/languages/0_Strings.js @@ -777,3 +777,5 @@ var STR_PLAYER_CODEC_AV1; var STR_PLAYER_CODEC_HEVC; var STR_PLAYER_CODEC_SUPPORTED; var STR_PLAYER_CODEC_NOT_SUPPORTED; +var STR_SPEED_ADJUST; +var STR_SPEED_ADJUST_SUMMARY; diff --git a/app/languages/en_US.js b/app/languages/en_US.js index e6af01630..6a6eab4c5 100644 --- a/app/languages/en_US.js +++ b/app/languages/en_US.js @@ -324,7 +324,7 @@ function en_USLang() { STR_LIVE_FEED = 'Live Feed'; STR_VOD_DIALOG = 'VOD start dialog'; STR_VOD_DIALOG_SUMMARY = - "Choose the default behavior, if the VOD info is present in user history when playing one, it can be played from where you last stopped watching. If you set this option to 'Always from the start', this behavior will also be applied to the VOD preview."; + "When playing a VOD saved on the user history, you can choose the default behavior of the VOD dialog. Setting it to 'Always from the start' also applies to the VOD preview."; STR_VOD_DIALOG_START = 'Always from the start'; STR_VOD_DIALOG_LAST = 'Always from the last stop'; STR_VOD_DIALOG_SHOW = 'Always ask'; @@ -901,4 +901,8 @@ function en_USLang() { 'Software codecs (OMX.google) are disabled by default if a hardware codec is available, if you have a playback problem try to disable the hardware codec and enable the software or vice versa (A constant accumulation of skipped frames is indicative of a codec issue).'; STR_CODEC_DIALOG_SUMMARY_3 = 'At least one codec of each type must be enabled at all times.'; + + STR_SPEED_ADJUST = 'Catch-up with low latency'; + STR_SPEED_ADJUST_SUMMARY = + 'When low latency is enabled, auto-adjust the latency if it is off the expected target, by slowing or speeding the stream by 1%, the speed change can cause minor audio noise when the latency is being adjusted.'; } diff --git a/app/specific/OSInterface.js b/app/specific/OSInterface.js index 7379c7f96..e0ff343fe 100644 --- a/app/specific/OSInterface.js +++ b/app/specific/OSInterface.js @@ -395,6 +395,17 @@ function OSInterface_UpdateBlockedGames() { } } +//public void setSpeedAdjustment(boolean speedAdjustment) +//speedAdjustment = boolean to enable auto adjustment of latency base on speed +//Sets speedAdjustment +function OSInterface_setSpeedAdjustment(speedAdjustment) { + if (Main_IsOn_OSInterface) { + try { + Android.setSpeedAdjustment(Boolean(speedAdjustment)); + } catch (e) {} + } +} + //public void setAppToken(String token) //token = token to save //Sets the app token when value is updated from JS diff --git a/app/specific/Settings.js b/app/specific/Settings.js index caa83496b..fd5667405 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -116,6 +116,10 @@ var Settings_value = { values: ['no', 'yes'], defaultValue: 1 }, + speed_adjust: { + values: ['no', 'yes'], + defaultValue: 1 + }, ttv_lolProxy: { //Migrated to dialog values: ['no', 'yes'], @@ -880,6 +884,11 @@ function Settings_SetSettings() { Settings_value[key].values[1] = STR_SOURCE; div += Settings_Content('default_quality', Settings_value[key].values, STR_DEF_QUALITY, STR_DEF_QUALITY_SUMMARY); + key = 'speed_adjust'; + Settings_value[key].values[0] = STR_AUTO; + Settings_value[key].values[1] = STR_SOURCE; + div += Settings_Content('speed_adjust', dis_ena, STR_SPEED_ADJUST, STR_SPEED_ADJUST_SUMMARY); + //Dialog settings //div += Settings_Content('proxy_settings', [STR_ENTER_TO_OPEN], PROXY_SETTINGS, null); div += Settings_Content('player_extracodecs', [STR_ENTER_TO_OPEN], STR_PLAYER_EXTRA_CODEC, STR_PLAYER_EXTRA_CODEC_SUMMARY); @@ -1053,6 +1062,7 @@ function Settings_SetDefaults() { Settings_set_proxy_timeout(); Settings_set_all_notification(); Settings_SetLang(); + Settings_SetSpeed_adjust(); Settings_SetResBitRate(0); @@ -1288,6 +1298,7 @@ function Settings_SetDefault(position) { else if (position === 'hevc_codec') Settings_ExtraCodecs(); else if (position === 'end_dialog_counter') Play_EndSettingsCounter = Settings_Obj_default('end_dialog_counter'); else if (position === 'default_quality') Play_SetQuality(); + else if (position === 'speed_adjust') Settings_SetSpeed_adjust(); else if (position === 'seek_preview') PlayVod_SetPreviewType(); else if (position === 'check_source') OSInterface_SetCheckSource(Settings_Obj_default('check_source') === 1); else if (position === 'thumb_quality') Main_SetThumb(); @@ -1733,6 +1744,10 @@ function Settings_SetResBitRateMin() { OSInterface_SetSmallPlayerBitrate(bitrate, resolution); } +function Settings_SetSpeed_adjust() { + OSInterface_setSpeedAdjustment(Settings_Obj_default('speed_adjust')); +} + function Settings_ExtraCodecs() { var ExtraCodecsValuesArray = [], av1Enabled = Settings_Obj_default('av1_codec'), From eb0ffddd9845f66e56ddf45f64a40d93cce725f0 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Sun, 4 Aug 2024 08:06:48 -0300 Subject: [PATCH 25/29] improve Settings_ExtraCodecs --- app/specific/Settings.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/specific/Settings.js b/app/specific/Settings.js index fd5667405..4321b087f 100644 --- a/app/specific/Settings.js +++ b/app/specific/Settings.js @@ -1028,7 +1028,7 @@ function Settings_SetDefaults() { } Settings_SetBuffers(0); - Settings_ExtraCodecs(); + Settings_ExtraCodecs(false); Settings_SetClock(); Settings_HideMainClock(); Settings_HidePlayerClock(); @@ -1294,8 +1294,7 @@ function Settings_SetDefault(position) { else if (position === 'key_up_timeout') Screens_KeyUptimeout = Settings_Obj_values('key_up_timeout'); else if (position === 'buffer_vod') Settings_SetBuffers(2); else if (position === 'buffer_clip') Settings_SetBuffers(3); - else if (position === 'av1_codec') Settings_ExtraCodecs(); - else if (position === 'hevc_codec') Settings_ExtraCodecs(); + else if (position === 'av1_codec' || position === 'hevc_codec') Settings_ExtraCodecs(true); else if (position === 'end_dialog_counter') Play_EndSettingsCounter = Settings_Obj_default('end_dialog_counter'); else if (position === 'default_quality') Play_SetQuality(); else if (position === 'speed_adjust') Settings_SetSpeed_adjust(); @@ -1748,7 +1747,7 @@ function Settings_SetSpeed_adjust() { OSInterface_setSpeedAdjustment(Settings_Obj_default('speed_adjust')); } -function Settings_ExtraCodecs() { +function Settings_ExtraCodecs(showWarning) { var ExtraCodecsValuesArray = [], av1Enabled = Settings_Obj_default('av1_codec'), hevcEnabled = Settings_Obj_default('hevc_codec'); @@ -1756,7 +1755,7 @@ function Settings_ExtraCodecs() { if (av1Enabled) { ExtraCodecsValuesArray.push('av1'); - if (!Settings_AV1Supported) { + if (!Settings_AV1Supported && showWarning) { Main_showWarningDialog(STR_PLAYER_CODEC_NOT_SUPPORTED, 3000); } } @@ -1764,7 +1763,7 @@ function Settings_ExtraCodecs() { if (hevcEnabled) { ExtraCodecsValuesArray.push('h265'); - if (!Settings_HEVCSupported) { + if (!Settings_HEVCSupported && showWarning) { Main_showWarningDialog(STR_PLAYER_CODEC_NOT_SUPPORTED, 3000); } } From d55b0663a85e58f822a610c7554ff4c87cdbc820 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Sun, 4 Aug 2024 08:12:08 -0300 Subject: [PATCH 26/29] update blocked on home screen when user changes --- app/specific/AddUser.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/specific/AddUser.js b/app/specific/AddUser.js index 82135f396..7e8b68aa1 100644 --- a/app/specific/AddUser.js +++ b/app/specific/AddUser.js @@ -440,6 +440,8 @@ function AddUser_removeUser(position, skipInitUser) { OSInterface_UpdateUserId(null); } + + Main_UpdateBlockedHomeScreen(); } function AddUser_SaveUserArray() { @@ -476,6 +478,7 @@ function AddUser_UserMakeOne(position) { //Reset history obj and check for deleted vod/clips Main_history_SetVod_Watched(); + Main_UpdateBlockedHomeScreen(); Main_setTimeout(Main_RunVODWorker, 10000); Main_setTimeout(Main_RunClipWorker, 30000); From b91549d9605d156bfe1800d2b3bb927bb6957c20 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Mon, 5 Aug 2024 09:42:09 -0300 Subject: [PATCH 27/29] Up version --- apk/versions.gradle | 2 +- app/general/version.js | 33 ++++++++++++--------------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/apk/versions.gradle b/apk/versions.gradle index 9f299f484..5a4d59421 100644 --- a/apk/versions.gradle +++ b/apk/versions.gradle @@ -1,4 +1,4 @@ ext.versions = [ publishVersion : '3.0.', - publishVersionCode: 363 + publishVersionCode: 365 ] \ No newline at end of file diff --git a/app/general/version.js b/app/general/version.js index 72ffa3e76..97a18f170 100644 --- a/app/general/version.js +++ b/app/general/version.js @@ -21,30 +21,21 @@ //Spacing for release maker not trow errors from jshint var version = { VersionBase: '3.0', - publishVersionCode: 363, //Always update (+1 to current value) Main_version_java after update publishVersionCode or a major update of the apk is released - ApkUrl: 'https://github.com/fgl27/SmartTwitchTV/releases/download/363/SmartTV_twitch_3_0_363.apk', - WebVersion: 'July 2024', - WebTag: 679, //Always update (+1 to current value) Main_version_web after update Main_minversion or a major update of the web part of the app + publishVersionCode: 365, //Always update (+1 to current value) Main_version_java after update publishVersionCode or a major update of the apk is released + ApkUrl: 'https://github.com/fgl27/SmartTwitchTV/releases/download/365/SmartTV_twitch_3_0_365.apk', + WebVersion: 'August 2024', + WebTag: 671, //Always update (+1 to current value) Main_version_web after update Main_minversion or a major update of the web part of the app changelog: [ { - title: 'Version March to July 2024 Apk Version 3.0.363', + title: 'Version August 2024 Apk Version 3.0.365', changes: [ - 'Add a red icon when the channel is live for the User channel and channel search screen', - 'Improve User live side panel loading', - 'Improve User channel screen loading', - 'Player: Migrate from Exoplayer to Media3, the Exoplayer changed its name to Media3 and stop received updates on the old project, if anyone has any issue regarding playback please open a GitHub issue or send an email', - 'Change Featured to Front Page (name change only)', - 'Add User Videos section', - 'Improve channel search results order, Twitch provides no order on the result, do a local ordering to show a more constant result', - 'Add search Live', - 'Add Search Videos', - 'Show all counters on all game screens', - 'Fix sometimes opening the wrong VOD for "Open the Last VOD" (the one of the options that show when a live end)', - 'Fix preview animated image not always showing', - 'Fix VOD seek preview image not always showing', - 'Improve exiting a search or search content as Channel content you enter after a search, before the app sometimes exit a search on the wrong section', - 'Improve app exit functionality', - 'Improve disable mature content with a password, now after enabling mature the old pass will be deleted, add a new one if disable again', + 'Add support for HEVC H.265 and AV1 Live and VOD (Settings Extra codec support), it still depends on the streamer to use and is on beta testing only some can', + 'Update Codec capability & Blocked codecs settings section to support new codecs and to show better information', + 'Improve display and section for player quality, sometimes it can come out of order from the server or have missing information', + "Fix Auto quality not playing stream with a resolution bigger than the device's current resolution", + 'Home screen content will no longer show blocked content', + 'Add new settings option "Catch-up with low latency" auto-adjust the latency if it is off the expected target, by slowing or speeding the stream by 1%', + 'Improve progress bar for lives', 'General app text improves, this is an open source app anyone that wanna improve app text or add translations can the process is simple', 'Other General improvements' ] From 6ddf57af4a3a61c7f13a26d30559ea14c74dd5e3 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Tue, 6 Aug 2024 08:31:41 -0300 Subject: [PATCH 28/29] Update en_US.js --- app/languages/en_US.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/languages/en_US.js b/app/languages/en_US.js index 6a6eab4c5..d24d4b7c7 100644 --- a/app/languages/en_US.js +++ b/app/languages/en_US.js @@ -898,7 +898,7 @@ function en_USLang() { STR_CODEC_DIALOG_SUMMARY_1 = 'This section lists all device-supported codec types AVC H.264, HEVC H.265, and AV1 used by this app.'; STR_CODEC_DIALOG_SUMMARY_2 = - 'Software codecs (OMX.google) are disabled by default if a hardware codec is available, if you have a playback problem try to disable the hardware codec and enable the software or vice versa (A constant accumulation of skipped frames is indicative of a codec issue).'; + 'Software codecs (OMX.google) are disabled by default if a hardware codec is available, if you have a playback problem try to disable the software codec and enable the hardware or vice versa (A constant accumulation of skipped frames is indicative of a codec issue).'; STR_CODEC_DIALOG_SUMMARY_3 = 'At least one codec of each type must be enabled at all times.'; From 7df795572beb47911b463ec1dc9ef7a006a816e7 Mon Sep 17 00:00:00 2001 From: Felipe Leon Date: Tue, 6 Aug 2024 09:46:12 -0300 Subject: [PATCH 29/29] update blocked codecs to run by type --- app/specific/Main.js | 140 +++++++++++++++++++++++++++++++++---------- 1 file changed, 107 insertions(+), 33 deletions(-) diff --git a/app/specific/Main.js b/app/specific/Main.js index 153a0afd2..38251b2e5 100644 --- a/app/specific/Main.js +++ b/app/specific/Main.js @@ -475,52 +475,126 @@ function Main_CheckDevice() { } } - //Disable googles OMX.google.h264.decoder and c2.android.avc.decoder if another codec is available if (!Main_values.Codec_is_Check_new) { - var codecs = null; - try { - if (Main_IsOn_OSInterface) { - codecs = JSON.parse(OSInterface_getcodecCapabilities('avc')); - codecs.push.apply(codecs, JSON.parse(OSInterface_getcodecCapabilities('hevc'))); - codecs.push.apply(codecs, JSON.parse(OSInterface_getcodecCapabilities('av01'))); - } - } catch (e) {} + Main_SetBlockedFirstRun(); + } + } else { + if (Main_values.Never_run_new) Settings_ForceEnableAnimations(); + + //Main_TestSetBlockedFirstRun(); + } +} - if (codecs) { - Main_values.Codec_is_Check_new = true; +// function Main_TestSetBlockedFirstRun() { +// var codecs = Main_SetBlockedGetCodecs(); +// console.log('Main_SetBlockedGetCodecs', codecs); - if (codecs.length > 1) { - var codecsNames = []; +// console.log(Main_SetBlockedGetToBlock(codecs)); +// console.log( +// //only one av1 google +// Main_SetBlockedGetToBlock( +// JSON.parse( +// '[{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"5.2","maxresolution":"3840x2176","name":"OMX.Nvidia.h264.decode","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 555 fps | 1080p : 245 fps | 1440p : 138 fps | 2160p : 61 fps","type":"video/avc"},{"instances":32,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.google.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":-1,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.chico.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.goldfish.hevc.decoder","resolutions":"160p : 480 fps | 360p : 480 fps | 480p : 480 fps | 720p : 480 fps | 900p : 364 fps | 1080p : 254 fps | 1440p : 144 fps | 2160p : 64 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.android.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"OMX.google.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.android.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.google.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"}]' +// ) +// ) +// ); +// } - var i = 0, - len = codecs.length; +function Main_SetBlockedFirstRun() { + //Disable googles OMX.google.h264.decoder and c2.android.avc.decoder if another codec is available - for (i; i < len; i++) { - var codec = codecs[i].name ? codecs[i].name.toLowerCase() : ''; + var codecs = Main_SetBlockedGetCodecs(); - if (Main_A_includes_B(codec, 'google') || Main_A_includes_B(codec, 'c2.android')) { - codecsNames.push(codecs[i].name); - } - } + if (codecs && codecs.length > 1) { + var codecsToBlock = Main_SetBlockedGetToBlock(codecs); + //only save if we received codecs + Main_values.Codec_is_Check_new = true; - if (codecsNames.length && codecsNames.length < codecs.length) { - i = 0; - len = codecsNames.length; + if (codecsToBlock.length) { + var i = 0, + len = codecsToBlock.length; - for (i; i < len; i++) { - Main_setItem(codecsNames[i], 1); - } + for (i; i < len; i++) { + Main_setItem(codecsToBlock[i], 1); + } - Main_setItem('Settings_DisableCodecsNames', JSON.stringify(codecsNames)); + Main_setItem('Settings_DisableCodecsNames', JSON.stringify(codecsToBlock)); - OSInterface_setBlackListMediaCodec(codecsNames.join()); - } - } + OSInterface_setBlackListMediaCodec(codecsToBlock.join()); + } + } +} + +function Main_SetBlockedGetCodecs() { + var codecs = null; + try { + if (Main_IsOn_OSInterface) { + codecs = JSON.parse(OSInterface_getcodecCapabilities('avc')); + codecs.push.apply(codecs, JSON.parse(OSInterface_getcodecCapabilities('hevc'))); + codecs.push.apply(codecs, JSON.parse(OSInterface_getcodecCapabilities('av01'))); + } else { + codecs = JSON.parse( + '[{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"5.2","maxresolution":"3840x2176","name":"OMX.Nvidia.h264.decode","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 555 fps | 1080p : 245 fps | 1440p : 138 fps | 2160p : 61 fps","type":"video/avc"},{"instances":32,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.google.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":-1,"maxbitrate":"48 Mbps","maxlevel":"5.2","maxresolution":"4080x4080","name":"OMX.chico.h264.decoder","resolutions":"160p : 960 fps | 360p : 960 fps | 480p : 960 fps | 720p : 546 fps | 1080p : 240 fps | 1440p : 136 fps | 2160p : 60 fps","type":"video/avc"},{"instances":32,"maxbitrate":"120 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.goldfish.hevc.decoder","resolutions":"160p : 480 fps | 360p : 480 fps | 480p : 480 fps | 720p : 480 fps | 900p : 364 fps | 1080p : 254 fps | 1440p : 144 fps | 2160p : 64 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"c2.android.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"10 Mbps","maxlevel":"High 5.2","maxresolution":"4096x4096","name":"OMX.google.hevc.decoder","resolutions":"160p : 960 fps | 360p : 741 fps | 480p : 417 fps | 720p : 139 fps | 900p : 88 fps | 1080p : 62 fps | 1440p : 35 fps | 2160p : 15 fps","type":"video/hevc"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.android.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.google.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c2.test.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"},{"instances":32,"maxbitrate":"40 Mbps","maxlevel":"32768","maxresolution":"2048x2048","name":"c.test2.av1.decoder","resolutions":"160p : 960 fps | 360p : 356 fps | 480p : 205 fps | 720p : 68 fps | 900p : 43 fps | 1080p : 30 fps","type":"video/av01"}]' + ); + } + } catch (e) {} + + return codecs; +} + +function Main_SetBlockedGetToBlock(codecs) { + //creates a map of to block codecs and normal + var codecsMap = { + ToBlock: {}, + Normal: { + av1: [], + avc: [], + hevc: [] } + }, + codecsToBlock = [], + codec; + + var i = 0, + len = codecs.length, + type; + + for (i; i < len; i++) { + codec = codecs[i].name ? codecs[i].name.toLowerCase() : ''; + + type = codecs[i].type; + codecs[i].type = Main_CodecGetType(type); + + if (Main_A_includes_B(codec, 'google') || Main_A_includes_B(codec, 'c2.android')) { + codecsMap.ToBlock[codecs[i].name] = codecs[i]; + } else if (codecsMap.Normal[codecs[i].type]) { + codecsMap.Normal[codecs[i].type].push(codecs[i]); } - } else if (Main_values.Never_run_new) { - Settings_ForceEnableAnimations(); } + + var ToBlockKeys = Object.keys(codecsMap.ToBlock); + + i = 0; + len = ToBlockKeys.length; + + //only block if normals codecs are available for the type + for (i; i < len; i++) { + codec = codecsMap.ToBlock[ToBlockKeys[i]]; + + if (codecsMap.Normal[codec.type].length) { + codecsToBlock.push(codec.name); + } + } + + return codecsToBlock; +} + +function Main_CodecGetType(type) { + if (Main_A_includes_B(type, 'avc')) return 'avc'; + else if (Main_A_includes_B(type, 'hevc')) return 'hevc'; + else if (Main_A_includes_B(type, 'av01')) return 'av1'; + + return null; } function Main_SetStringsMain() {