diff --git a/README.md b/README.md
index eb5a68a7c..459b9f390 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ KanTV("Kan", aka Chinese PinYin "Kan" or Chinese HanZi "看" or English "watch/l
- Watch encrypted live stream(Google Widevine, Huawei WisePlay, ChinaDRM......)
-- Real-time English subtitle by excellent&amazing whisper.cpp for unencrypted/clear online TV (not finished)
+- Real-time English subtitle for online TV by excellent&amazing whisper.cpp (not finished)
- UI refactor
@@ -104,13 +104,13 @@ bazel is **NOT** used currently but put it here for further usage in the future.
[Android Studio 4.2.1](https://developer.android.google.cn/studio)
- [Android NDK-r21e](https://developer.android.com/ndk/downloads)
+ [Android NDK-r26c](https://developer.android.com/ndk/downloads)
- then put Android NDK-r21e into /opt/kantv-toolchain accordingly
+ then put Android NDK-r26c into /opt/kantv-toolchain accordingly
```
- ls /opt/kantv-toolchain/android-ndk-r21e
+ ls /opt/kantv-toolchain/android-ndk-r26c
```
@@ -176,7 +176,7 @@ time ./build-all.sh
- Build APK from source code by Android Studio IDE manually
- Please attention ![some source codes in ASRFragment.java](https://github.com/cdeos/kantv/blob/master/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/fragment/ASRFragment.java#L131) which affect the running of the ASR demo and the size of the generated APK.
+ Please attention ![some source codes in ASRFragment.java](https://github.com/cdeos/kantv/blob/kantv-poc-with-whispercpp/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/fragment/ASRFragment.java#L155) which affect the running of the ASR demo and the size of the generated APK.
- Latest prebuit APK could be found here [![Github](https://user-images.githubusercontent.com/6889919/122489234-c13db400-d011-11eb-9d8c-8e4b2555dabe.png)](https://github.com/cdeos/kantv/raw/master/release/kantv-latest.apk)(the size of the prebuilt APK is about 90M because it contains **dependent model file of DeepSpeech** for purpose of make ASR demo happy).
@@ -192,11 +192,10 @@ The following is some English snapshots.
![Screenshot_20240301_000503_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/07653f3d-1e7a-4208-a3d8-90b3aecc30b4)
![Screenshot_20240301_000509_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/28d549ba-2fd5-434f-bf7a-b66d82d6dde3)
-![990238413](https://github.com/zhouwg/kantv/assets/6889919/44054d57-0149-4d45-8762-46ec80682c66)
+![1210108450](https://github.com/cdeos/kantv/assets/6889919/9f82c290-2ed6-444c-98d4-ef840cdd9083)
-![Screenshot_20240301_114059_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/b0171435-44a5-48bf-9b59-a4b5fbcaa39f)
![Screenshot_20240301_114116_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/10224799-cdf8-46f7-acd0-6df64f0fc674)
![Screenshot_2024_0304_131033](https://github.com/zhouwg/kantv/assets/6889919/6c5bd531-5577-4570-bc87-aa3a87822d6b)
@@ -216,9 +215,9 @@ Changelog could be found VLC is also excellent and gstreamer is more complicated than VLC but gstreamer was supported by many semiconductor companies. anyway, they are both born in/come from EU)
@@ -310,15 +309,16 @@ Report issue in various Android-based phone or even submit PR to this project is
### Acknowledgement
-Many/sincerely thanks to all contributors of the great open source community, especially all original authors and all contributors of the great Linux & Android & FFmpeg and other excellent projects.
+Many/sincerely thanks to all contributors of the great open source community, especially all original authors and all contributors of the great Linux & Android & FFmpeg && whisper.cpp and other excellent projects.
Project KanTV has used/tried following open-source projects(list in here is not incomplete):
+ - Linux
- Android
- FFmpeg
- - ijkplayer
- - ExoPlayer
- whisper.cpp
+ - ijkplayer
+ - ExoPlayer
- libx264/libx265
- DeepSpeech
- SVT-AV1
diff --git a/build/envsetup.sh b/build/envsetup.sh
index a080e749f..9113c51de 100755
--- a/build/envsetup.sh
+++ b/build/envsetup.sh
@@ -46,7 +46,25 @@ export LOCAL_WHISPERCPP_PATH=${PROJECT_ROOT_PATH}/external/whispercpp
#modify following lines to adapt to local dev envs
#export KANTV_TOOLCHAIN_PATH=${PROJECT_ROOT_PATH}/toolchain
export KANTV_TOOLCHAIN_PATH=/opt/kantv-toolchain
-export ANDROID_NDK=${KANTV_TOOLCHAIN_PATH}/android-ndk-r21e
+#API21:Android 5.0 (Android L)Lollipop
+#API22:Android 5.1 (Android L)Lollipop
+#API23:Android 6.0 (Android M)Marshmallow
+#API24: Android 7.0 (Android N)Nougat
+#API25: Android 7.1 (Android N)Nougat
+#API26:Android 8.0 (Android O)Oreo
+#API27:Android 8.1 (Android O)Oreo
+#API28:Android 9.0 (Android P)Pie
+#API29:Android 10
+#API30:Android 11
+#API31:Android 12
+#API31:Android 12L
+#API33:Android 13
+#API34:Android 14
+export ANDROID_PLATFORM=android-34
+#export ANDROID_NDK=${KANTV_TOOLCHAIN_PATH}/android-ndk-r18b
+#export ANDROID_NDK=${KANTV_TOOLCHAIN_PATH}/android-ndk-r21e
+#export ANDROID_NDK=${KANTV_TOOLCHAIN_PATH}/android-ndk-r24
+export ANDROID_NDK=${KANTV_TOOLCHAIN_PATH}/android-ndk-r26c
export LOCAL_BAZEL_PATH=${HOME_PATH}/.cache/bazel/_bazel_${BUILD_USER}/d483cd2a2d9204cb5bb4d870c2729238
export UPSTREAM_WHISPERCPP_PATH=~/cdeos/whisper.cpp
diff --git a/build/public.sh b/build/public.sh
index 1a2881d29..8b7b8a018 100755
--- a/build/public.sh
+++ b/build/public.sh
@@ -216,14 +216,14 @@ function dump_global_envs()
echo -e "PROJECT_HOME_PATH: ${PROJECT_HOME_PATH}"
echo -e "PROJECT_ROOT_PATH: ${PROJECT_ROOT_PATH}"
echo -e "KANTV_TOOLCHAIN_PATH: ${KANTV_TOOLCHAIN_PATH}"
-
echo -e "host cpu counts: ${HOST_CPU_COUNTS}"
if [ "${BUILD_TARGET}" = "android" ]; then
echo -e "\n"
- echo -e "ANDROID_NDK: ${ANDROID_NDK}"
- echo -e "LOCAL_WHISPERCPP_PATH: ${LOCAL_WHISPERCPP_PATH}"
- echo -e "UPSTREAM_WHISPERCPP_PATH: ${UPSTREAM_WHISPERCPP_PATH}"
+ echo -e "${TEXT_RED}ANDROID_PLATFORM: ${ANDROID_PLATFORM}${TEXT_RESET}"
+ echo -e "${TEXT_RED}ANDROID_NDK: ${ANDROID_NDK}${TEXT_RESET}"
+ echo -e "LOCAL_WHISPERCPP_PATH: ${LOCAL_WHISPERCPP_PATH}"
+ echo -e "UPSTREAM_WHISPERCPP_PATH: ${UPSTREAM_WHISPERCPP_PATH}"
echo -e "\n"
fi
diff --git a/cdeosplayer/build.gradle b/cdeosplayer/build.gradle
index 0746b5428..84b6ecea2 100644
--- a/cdeosplayer/build.gradle
+++ b/cdeosplayer/build.gradle
@@ -8,7 +8,7 @@ buildscript {
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.0.2'
+ classpath 'com.android.tools.build:gradle:7.0.3'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
}
@@ -30,30 +30,5 @@ task clean(type: Delete) {
}
wrapper {
- gradleVersion = '7.0.2'
+ gradleVersion = '7.0.3'
}
-
-
-
-/*
-API14: Android 4.0-4.0.2 – Ice Cream Sandwich, released October 2011. Build version
-API15:Android 4.0.3 - 4.0.4 Ice Cream Sandwich
-API16:Android 4.1 Jelly Bean
-API17:Android 4.2 Jelly Bean
-API18:Android 4.3 Jelly Bean
-API19:Android 4.4 KitKat
-API20:Android 4.4W Kitkat Watch
-API21:Android 5.0 (Android L)Lollipop
-API22:Android 5.1 (Android L)Lollipop
-API23:Android 6.0 (Android M)Marshmallow
-API24: Android 7.0 (Android N)Nougat
-API25: Android 7.1 (Android N)Nougat
-API26:Android 8.0 (Android O)Oreo
-API27:Android 8.1 (Android O)Oreo
-API28:Android 9.0 (Android P)Pie
-API29:Android 10.0 (Android Q)
-API30:Android 11.0 (Android R)
-API31:Android 12.0
-API32:Android 13.0
-API33:Android 14.0
-*/
diff --git a/cdeosplayer/cdeosplayer-lib/src/main/java/cdeos/media/player/FFmpegMediaPlayer.java b/cdeosplayer/cdeosplayer-lib/src/main/java/cdeos/media/player/FFmpegMediaPlayer.java
index a7eb5d720..252c84741 100755
--- a/cdeosplayer/cdeosplayer-lib/src/main/java/cdeos/media/player/FFmpegMediaPlayer.java
+++ b/cdeosplayer/cdeosplayer-lib/src/main/java/cdeos/media/player/FFmpegMediaPlayer.java
@@ -211,13 +211,13 @@ public static void loadLibrariesOnce(IjkLibLoader libLoader) {
if (libLoader == null)
libLoader = sLocalLibLoader;
- CDELog.j(TAG, "load library kantv-ffmpeg-jni");
- libLoader.loadLibrary("kantv-ffmpeg-jni");
- CDELog.j(TAG, "after load library kantv-ffmpeg-jni");
+ CDELog.j(TAG, "load library kantv-play-jni");
+ libLoader.loadLibrary("kantv-play-jni");
+ CDELog.j(TAG, "after load library kantv-play-jni");
- CDELog.j(TAG, "load library kantv-ffmpeg");
- libLoader.loadLibrary("kantv-ffmpeg");
- CDELog.j(TAG, "after load library kantv-ffmpeg");
+ CDELog.j(TAG, "load library kantv-play");
+ libLoader.loadLibrary("kantv-play");
+ CDELog.j(TAG, "after load library kantv-play");
mIsLibLoaded = true;
}
}
diff --git a/cdeosplayer/cdeosplayer-lib/src/main/java/cdeos/media/player/KANTVVersion.java b/cdeosplayer/cdeosplayer-lib/src/main/java/cdeos/media/player/KANTVVersion.java
index ddc114323..46f3a8f23 100755
--- a/cdeosplayer/cdeosplayer-lib/src/main/java/cdeos/media/player/KANTVVersion.java
+++ b/cdeosplayer/cdeosplayer-lib/src/main/java/cdeos/media/player/KANTVVersion.java
@@ -19,7 +19,7 @@
final class KANTVVersion
{
- public static final String KANTV_VERSION="KANTV-v1.3.0";
+ public static final String KANTV_VERSION="KANTV-v1.3.1";
public static native int kantv_anti_tamper();
}
diff --git a/cdeosplayer/cdeosplayer-lib/src/main/java/org/ggml/whispercpp/whispercpp.java b/cdeosplayer/cdeosplayer-lib/src/main/java/org/ggml/whispercpp/whispercpp.java
index 53a096031..6a1c3775e 100644
--- a/cdeosplayer/cdeosplayer-lib/src/main/java/org/ggml/whispercpp/whispercpp.java
+++ b/cdeosplayer/cdeosplayer-lib/src/main/java/org/ggml/whispercpp/whispercpp.java
@@ -8,13 +8,15 @@ public class whispercpp {
public static native String get_systeminfo();
+ public static native int get_cpu_core_counts();
+
public static native void set_benchmark_status(int bExitBenchmark);
/**
*
* @param modelPath
* @param audioFile
- * @param nBenchType 0: memcpy 1: mulmat 2: asr 3: full/whisper_encoder
+ * @param nBenchType 0: asr 1: memcpy 2: mulmat 3: full/whisper_encode
* @param nThreadCounts
* @return
*/
diff --git a/cdeosplayer/constants.gradle b/cdeosplayer/constants.gradle
index 4fa720c38..e70ea0d3f 100644
--- a/cdeosplayer/constants.gradle
+++ b/cdeosplayer/constants.gradle
@@ -1,4 +1,4 @@
-// Copyright 2017 The Android Open Source Project
+// Copyright 2024 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -11,18 +11,40 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+/*
+API14: Android 4.0-4.0.2 – Ice Cream Sandwich, released October 2011. Build version
+API15:Android 4.0.3 - 4.0.4 Ice Cream Sandwich
+API16:Android 4.1 Jelly Bean
+API17:Android 4.2 Jelly Bean
+API18:Android 4.3 Jelly Bean
+API19:Android 4.4 KitKat
+API20:Android 4.4W Kitkat Watch
+API21:Android 5.0 (Android L)Lollipop
+API22:Android 5.1 (Android L)Lollipop
+API23:Android 6.0 (Android M)Marshmallow
+API24: Android 7.0 (Android N)Nougat
+API25: Android 7.1 (Android N)Nougat
+API26:Android 8.0 (Android O)Oreo
+API27:Android 8.1 (Android O)Oreo
+API28:Android 9.0 (Android P)Pie
+API29:Android 10
+API30:Android 11
+API31:Android 12
+API32: Android 12L
+API33:Android 13
+API34:Android 14
+*/
project.ext {
- compileSdkVersion = 30
- buildToolsVersion = "30.0.3"
- targetSdkVersion = 28
- minSdkVersion = 19
- //minSdkVersion = 16
+ //weiguo:2024-03-10, attention here,only validated ok on Xiaomi 14
+ compileSdkVersion = 34
+ buildToolsVersion = "34.0.0"
+ targetSdkVersion = 34
+ minSdkVersion = 34
appTargetSdkVersion = 29
- ndkVersion = "21.4.7075529"
//version and version code of KanTV
- releaseVersion = '1.3.0'
- releaseVersionCode = 1000300
+ releaseVersion = '1.3.1'
+ releaseVersionCode = 1000301
//version and version code of internal Exoplayer2 playEngine
releaseVersionExoplayer = '2.15.1'
@@ -44,4 +66,4 @@ project.ext {
if (gradle.ext.has('exoplayerModulePrefix')) {
modulePrefix += gradle.ext.exoplayerModulePrefix
}
-}
+}
\ No newline at end of file
diff --git a/cdeosplayer/kantv/build.gradle b/cdeosplayer/kantv/build.gradle
index 5c89c469a..7914b05f5 100644
--- a/cdeosplayer/kantv/build.gradle
+++ b/cdeosplayer/kantv/build.gradle
@@ -44,7 +44,9 @@ android {
}
}
- ndkVersion '21.1.6352462'
+ //weiguo:2024-03-10, attention here
+ //ndkVersion '21.1.6352462'
+ ndkVersion '26.2.11394342'
sourceSets {
main {
diff --git a/cdeosplayer/kantv/src/main/assets/config.json b/cdeosplayer/kantv/src/main/assets/config.json
index 818021659..ee5bb1c9a 100644
--- a/cdeosplayer/kantv/src/main/assets/config.json
+++ b/cdeosplayer/kantv/src/main/assets/config.json
@@ -1,6 +1,6 @@
{
"kantvServer": "www.cde-os.com",
- "releaseMode": "0",
- "apkVersion": "1.3.0",
+ "releaseMode": "1",
+ "apkVersion": "1.3.1",
"apkForTV": "0"
}
diff --git a/cdeosplayer/kantv/src/main/assets/ggml-tiny.bin b/cdeosplayer/kantv/src/main/assets/ggml-tiny.bin
deleted file mode 100644
index 9dd1a6b40..000000000
Binary files a/cdeosplayer/kantv/src/main/assets/ggml-tiny.bin and /dev/null differ
diff --git a/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/activities/MainActivity.java b/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/activities/MainActivity.java
index 797a6b570..86c269b25 100755
--- a/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/activities/MainActivity.java
+++ b/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/activities/MainActivity.java
@@ -267,7 +267,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
CDEUtils.dumpDeviceInfo();
- if (CDEUtils.isEmulator(this)) {
+ //if (CDEUtils.isEmulator(this))
+ if (false)
+ {
showWarningDialog(this, "can't running this app in emulator");
navigationView.getMenu().findItem(R.id.navigation_play).setEnabled(false);
navigationView.getMenu().findItem(R.id.navigation_home).setEnabled(false);
@@ -320,6 +322,15 @@ private void switchFragment(Class clazz) {
getFragmentTransaction().hide(previousFragment).commit();
}
+ if (previousFragment != null) {
+ String fragmentName = previousFragment.getClass().getName();
+ if (fragmentName.contains("ASRFragment")) {
+ CDELog.j(TAG, "release ASR resource");
+ asrFragment.release();
+ }
+ }
+
+
if (clazz == TVGridFragment.class) {
if (homeFragment == null) {
homeFragment = TVGridFragment.newInstance();
@@ -385,4 +396,4 @@ public void onClick(DialogInterface dialog, int which) {
}
public static native int kantv_anti_tamper();
-}
\ No newline at end of file
+}
diff --git a/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/fragment/ASRFragment.java b/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/fragment/ASRFragment.java
index 1b5cee5ac..1a9e70f6b 100755
--- a/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/fragment/ASRFragment.java
+++ b/cdeosplayer/kantv/src/main/java/com/cdeos/kantv/ui/fragment/ASRFragment.java
@@ -89,10 +89,11 @@ public class ASRFragment extends BaseMvpFragment implements ASRVie
Button _btnBenchmark;
- private static final int BECHMARK_MEMCPY = 0;
- private static final int BECHMARK_MULMAT = 1;
- private static final int BECHMARK_ASR = 2;
- private static final int BECHMARK_FULL = 3; //very slow on Android phone
+ //keep sync with kantv_asr.h
+ private static final int BECHMARK_ASR = 0;
+ private static final int BECHMARK_MEMCPY = 1;
+ private static final int BECHMARK_MULMAT = 2;
+ private static final int BECHMARK_FULL = 3; //very slow on Android phone
private int nThreadCounts = 1;
private int benchmarkIndex = 0;
@@ -160,7 +161,13 @@ public void initView() {
_txtASRInfo.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
displayFileStatus(CDEUtils.getDataPath() + ggmlSampleFileName, CDEUtils.getDataPath() + ggmlModelFileName);
- CDELibraryLoader.load("whispercpp");
+ try {
+ CDELibraryLoader.load("whispercpp");
+ CDELog.j(TAG, "cpu core counts:" + whispercpp.get_cpu_core_counts());
+ } catch (Exception e) {
+ CDELog.j(TAG, "failed to initialize whispercpp jni");
+ return;
+ }
try {
initKANTVMgr();
@@ -216,6 +223,24 @@ public void onNothingSelected(AdapterView> parent) {
}
});
+ /*
+ - tiny
+ - tiny.en
good
+ - tiny.en-q5_1
good
+ - tiny.en-q8_0
+ - tiny-q5_1
+ - base
+ - base.en
+ - base-q5_1
+ - small
+ - small.en
+ - small.en-q5_1
+ - small-q5_1
+ - medium
+ - medium.en
+ - medium.en-q5_0
+ - large
+ */
Spinner spinnerModelName = mActivity.findViewById(R.id.spinnerModelName);
String[] arrayModelName = getResources().getStringArray(R.array.modelName);
ArrayAdapter adapterModel = new ArrayAdapter(mActivity, android.R.layout.simple_spinner_dropdown_item, arrayModelName);
@@ -247,7 +272,7 @@ public void onNothingSelected(AdapterView> parent) {
File sampleFile = new File(CDEUtils.getDataPath() + ggmlSampleFileName);
if (!selectModeFile.exists() || (!sampleFile.exists())) {
- showMsgBox(mActivity, "pls check whether model file or sample file exist in /sdcard/kantv/");
+ showMsgBox(mActivity, "pls check whether GGML's model file and sample file(jfk.wav) exist in /sdcard/kantv/");
return;
}
@@ -290,10 +315,6 @@ public void run() {
initKANTVMgr();
whispercpp.set_benchmark_status(0);
- if (mKANTVMgr != null) {
- mKANTVMgr.initASR();
- mKANTVMgr.startASR();
- }
while (isBenchmarking.get()) {
beginTime = System.currentTimeMillis();
@@ -481,6 +502,10 @@ private void initKANTVMgr() {
try {
mKANTVMgr = new KANTVMgr(mEventListener);
+ if (mKANTVMgr != null) {
+ mKANTVMgr.initASR();
+ mKANTVMgr.startASR();
+ }
CDELog.j(TAG, "KANTVMgr version:" + mKANTVMgr.getMgrVersion());
} catch (KANTVException ex) {
String errorMsg = "An exception was thrown because:\n" + " " + ex.getMessage();
diff --git a/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-core.so b/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-core.so
index 91e3a5ac9..c02c793dc 100755
Binary files a/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-core.so and b/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-core.so differ
diff --git a/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-ffmpeg-jni.so b/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-play-jni.so
similarity index 99%
rename from cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-ffmpeg-jni.so
rename to cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-play-jni.so
index d153a02cd..e62639b05 100755
Binary files a/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-ffmpeg-jni.so and b/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-play-jni.so differ
diff --git a/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-ffmpeg.so b/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-play.so
similarity index 72%
rename from cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-ffmpeg.so
rename to cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-play.so
index 1b735d67d..e0681154a 100755
Binary files a/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-ffmpeg.so and b/cdeosplayer/kantv/src/main/jniLibs/arm64-v8a/libkantv-play.so differ
diff --git a/cdeosplayer/kantv/src/main/res/values-en/strings_pref.xml b/cdeosplayer/kantv/src/main/res/values-en/strings_pref.xml
index 498ee9619..95971a630 100755
--- a/cdeosplayer/kantv/src/main/res/values-en/strings_pref.xml
+++ b/cdeosplayer/kantv/src/main/res/values-en/strings_pref.xml
@@ -284,7 +284,7 @@
About
pref.version
Current Version
- 1.3.0
+ 1.3.1
pref.versionhistory
Version history
diff --git a/cdeosplayer/kantv/src/main/res/values-zh/strings_pref.xml b/cdeosplayer/kantv/src/main/res/values-zh/strings_pref.xml
index 85bce7baf..c6ad6dba9 100755
--- a/cdeosplayer/kantv/src/main/res/values-zh/strings_pref.xml
+++ b/cdeosplayer/kantv/src/main/res/values-zh/strings_pref.xml
@@ -284,7 +284,7 @@
关于
pref.version
当前版本
- 1.3.0
+ 1.3.1
pref.versionhistory
版本历史
diff --git a/cdeosplayer/kantv/src/main/res/values/arrays.xml b/cdeosplayer/kantv/src/main/res/values/arrays.xml
index 3a50aa18c..7edf439f9 100755
--- a/cdeosplayer/kantv/src/main/res/values/arrays.xml
+++ b/cdeosplayer/kantv/src/main/res/values/arrays.xml
@@ -73,32 +73,39 @@
+ - asr
- mempcpy
- mulmat
- - asr
- full
- - 1
- - 2
- - 3
- - 4
- - 5
- - 6
- - 7
- 8
+ - 7
+ - 6
+ - 5
+ - 4
+ - 3
+ - 2
+ - 1
- tiny
- tiny.en
+ - tiny.en-q5_1
+ - tiny.en-q8_0
+ - tiny-q5_1
- base
- base.en
+ - base-q5_1
- small
- small.en
+ - small.en-q5_1
+ - small-q5_1
- medium
- medium.en
+ - medium.en-q5_0
- large
\ No newline at end of file
diff --git a/cdeosplayer/kantv/src/main/res/values/strings_pref.xml b/cdeosplayer/kantv/src/main/res/values/strings_pref.xml
index 6f5d7866a..efb216e34 100755
--- a/cdeosplayer/kantv/src/main/res/values/strings_pref.xml
+++ b/cdeosplayer/kantv/src/main/res/values/strings_pref.xml
@@ -289,7 +289,7 @@
About
pref.version
Current Version
- 1.3.0
+ 1.3.1
pref.versionhistory
Version history
diff --git a/docs/NXP-AN12628-Optimizing Memory Copy Routines.pdf b/docs/NXP-AN12628-OptimizingMemoryCopyRoutines.pdf
similarity index 100%
rename from docs/NXP-AN12628-Optimizing Memory Copy Routines.pdf
rename to docs/NXP-AN12628-OptimizingMemoryCopyRoutines.pdf
diff --git a/docs/Snapdragon_8_gen_3_Mobile_Platform_Product_Brief.pdf b/docs/Snapdragon_8_gen_3_Mobile_Platform_Product_Brief.pdf
new file mode 100644
index 000000000..f645d1186
Binary files /dev/null and b/docs/Snapdragon_8_gen_3_Mobile_Platform_Product_Brief.pdf differ
diff --git a/docs/arm_cortex_a78_TechnicalReferenceManual.pdf b/docs/arm_cortex_a78_TechnicalReferenceManual.pdf
new file mode 100644
index 000000000..524967d1b
Binary files /dev/null and b/docs/arm_cortex_a78_TechnicalReferenceManual.pdf differ
diff --git a/docs/arm_cortex_x4_core_Software_Optimization_Guide.pdf b/docs/arm_cortex_x4_core_Software_Optimization_Guide.pdf
new file mode 100644
index 000000000..a7ba18f3b
Binary files /dev/null and b/docs/arm_cortex_x4_core_Software_Optimization_Guide.pdf differ
diff --git a/docs/arm_cortex_x4_core_TechnicalReferenceManual.pdf b/docs/arm_cortex_x4_core_TechnicalReferenceManual.pdf
new file mode 100644
index 000000000..e3eafb03d
Binary files /dev/null and b/docs/arm_cortex_x4_core_TechnicalReferenceManual.pdf differ
diff --git a/docs/arm_cortex_x4_core_crypto_TechnicalReferenceManual.pdf b/docs/arm_cortex_x4_core_crypto_TechnicalReferenceManual.pdf
new file mode 100644
index 000000000..a72c09d4e
Binary files /dev/null and b/docs/arm_cortex_x4_core_crypto_TechnicalReferenceManual.pdf differ
diff --git a/external/OpenBLAS/CMakeLists.txt b/external/OpenBLAS/CMakeLists.txt
index 07e5cb973..48736e21c 100644
--- a/external/OpenBLAS/CMakeLists.txt
+++ b/external/OpenBLAS/CMakeLists.txt
@@ -5,6 +5,7 @@
cmake_minimum_required(VERSION 2.8.5)
project(OpenBLAS C ASM)
+set(CMAKE_VERBOSE_MAKEFILE on)
set(OpenBLAS_MAJOR_VERSION 0)
set(OpenBLAS_MINOR_VERSION 3)
@@ -24,6 +25,15 @@ set(NO_FORTRAN 1)
set(BUILD_WITHOUT_LAPACK 1)
set(BUILD_TESTING 0)
+add_definitions(-DNDEBUG)
+add_definitions(-O3)
+#add_definitions(-funsafe-math-optimizations)
+#add_definitions(-march=armv8.6-a+simd)
+#add_definitions(-mcpu=cortex-a78)
+add_definitions(-march=armv9+simd)
+add_definitions(-mcpu=cortex-x3)
+add_definitions(-mfloat-abi=hard -mfpu=neon-fp-armv8)
+
option(BUILD_LAPACK_DEPRECATED "When building LAPACK, include also some older, deprecated routines" ON)
option(BUILD_TESTING "Build LAPACK testsuite when building LAPACK" OFF)
@@ -327,7 +337,7 @@ endif()
if (NOT NO_CBLAS)
if (NOT ONLY_CBLAS)
# Broken without fortran on unix
- add_subdirectory(utest)
+ #add_subdirectory(utest)
endif()
endif()
diff --git a/external/OpenBLAS/build.sh b/external/OpenBLAS/build.sh
index 9fde94a6d..a0e6c56b8 100755
--- a/external/OpenBLAS/build.sh
+++ b/external/OpenBLAS/build.sh
@@ -38,9 +38,10 @@ fi
function build_arm64
{
-cmake -H. -B./out/arm64-v8a -DPROJECT_ROOT_PATH=${PROJECT_ROOT_PATH} -DTARGET_NAME=${TARGET} -DCMAKE_BUILD_TYPE=${PROJECT_BUILD_TYPE} -DBUILD_TARGET="android" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-21 -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DLOCAL_WHISPERCPP_PATH=${LOCAL_WHISPERCPP_PATH}
+cmake -H. -B./out/arm64-v8a -DPROJECT_ROOT_PATH=${PROJECT_ROOT_PATH} -DTARGET_NAME=${TARGET} -DCMAKE_BUILD_TYPE=${PROJECT_BUILD_TYPE} -DBUILD_TARGET="android" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=${ANDROID_PLATFORM} -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DLOCAL_WHISPERCPP_PATH=${LOCAL_WHISPERCPP_PATH}
cd ./out/arm64-v8a
-make -j${HOST_CPU_COUNTS} NO_LAPACK=1 NO_FORTRAN=1 BUILD_TESTING=0 BUILD_WITHOUT_LPACK=1
+#make -j${HOST_CPU_COUNTS} NO_LAPACK=1 NO_FORTRAN=1 BUILD_TESTING=0 BUILD_WITHOUT_LPACK=1
+make -j${HOST_CPU_COUNTS} NO_LAPACK=1 NO_FORTRAN=1 BUILD_TESTING=0 BUILD_WITHOUT_LPACK=1
ls -l lib/lib${TARGET}.so
ls -lah lib/lib${TARGET}.so
@@ -51,7 +52,7 @@ cd -
function build_armv7a
{
-cmake -H. -B./out/armeabi-v7a -DPROJECT_ROOT_PATH=${PROJECT_ROOT_PATH} -DTARGET_NAME=${TARGET} -DCMAKE_BUILD_TYPE=${PROJECT_BUILD_TYPE} -DBUILD_TARGET="android" -DANDROID_ABI=armeabi-v7a -DANDROID_PLATFORM=android-21 -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DLOCAL_WHISPERCPP_PATH=${LOCAL_WHISPERCPP_PATH}
+cmake -H. -B./out/armeabi-v7a -DPROJECT_ROOT_PATH=${PROJECT_ROOT_PATH} -DTARGET_NAME=${TARGET} -DCMAKE_BUILD_TYPE=${PROJECT_BUILD_TYPE} -DBUILD_TARGET="android" -DANDROID_ABI=armeabi-v7a -DANDROID_PLATFORM=${ANDROID_PLATFORM} -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DLOCAL_WHISPERCPP_PATH=${LOCAL_WHISPERCPP_PATH}
cd ./out/armeabi-v7a
make
diff --git a/external/whispercpp/CMakeLists.txt b/external/whispercpp/CMakeLists.txt
index 0b19b9f6c..fd6d5d415 100644
--- a/external/whispercpp/CMakeLists.txt
+++ b/external/whispercpp/CMakeLists.txt
@@ -9,9 +9,9 @@ project(whispercpp)
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_STANDARD 11)
-set(WHISPERCPP_SRC_DIR ${CMAKE_SOURCE_DIR}/)
-set(PREBUIT_LIB_PATH ${CMAKE_SOURCE_DIR}/../../cdeosplayer/kantv/src/main/jniLibs/${ANDROID_ABI}/)
-set(PREBUIT_INC_PATH ${CMAKE_SOURCE_DIR}/../../prebuilts/include/)
+set(WHISPERCPP_SRC_DIR ${CMAKE_SOURCE_DIR}/)
+set(PREBUIT_LIB_PATH ${CMAKE_SOURCE_DIR}/../../cdeosplayer/kantv/src/main/jniLibs/${ANDROID_ABI}/)
+set(PREBUIT_INC_PATH ${CMAKE_SOURCE_DIR}/../../prebuilts/include/)
set(SOURCE_FILES
${WHISPERCPP_SRC_DIR}/ggml.c
@@ -21,7 +21,7 @@ set(SOURCE_FILES
${WHISPERCPP_SRC_DIR}/whisper.cpp
${WHISPERCPP_SRC_DIR}/cde_log.c
${WHISPERCPP_SRC_DIR}/jni/whispercpp-jni.c
-)
+ )
message("WHISPERCPP_SRC_DIR : ${WHISPERCPP_SRC_DIR}")
message("PREBUIT_INC_PATH : ${PREBUIT_INC_PATH}")
@@ -37,17 +37,32 @@ include_directories(${PREBUIT_INC_PATH}/)
add_definitions(-DTARGET_ANDROID)
add_definitions(-D__ARM_NEON)
+#add_definitions(-DGGML_USE_ACCELERATE)
#add_definitions(-DGGML_USE_CLBLAST)
-add_definitions(-DGGML_USE_OPENBLAS)
-IF(CMAKE_BUILD_TYPE MATCHES "Debug")
- add_definitions(-O0 -g)
-ELSE()
- add_definitions(-DNDEBUG)
- add_definitions(-O3)
- #add_definitions(-fvisibility=hidden -fvisibility-inlines-hidden)
-ENDIF()
+#weiguo,2024-03-11, mightbe slower when armv8/armv9 + simd is enabled
+#add_definitions(-DGGML_USE_OPENBLAS)
+add_definitions(-DNDEBUG)
+add_definitions(-O3)
+
+#weiguo:2024-03-10
+#add_definitions(-mcpu=cortex-a72 -mfloat-abi=hard -mfpu=neon-fp-armv8)
+
+#both not supported with latest android-ndk-r26c
+#add_definitions(-march=armv9.2+simd)
+#add_definitions(-mcpu=cortex-x4)
+#only validated ok on Xiaomi 14
+add_definitions(-march=armv8+simd)
+add_definitions(-mcpu=cortex-a78)
+
+##SF(segment fault) or instruction exception
+#add_definitions(-march=armv9+simd)
+#add_definitions(-mcpu=cortex-x3)
+
+add_definitions(-mfloat-abi=hard -mfpu=neon-fp-armv8)
+#add_definitions(-fvisibility=hidden -fvisibility-inlines-hidden)
+#add_definitions(-funsafe-math-optimizations)
find_library(LOG_LIB log)
@@ -72,13 +87,13 @@ set_target_properties(openblas
function(build_library target_name)
add_library(
- ${target_name}
- SHARED
- ${SOURCE_FILES}
+ ${target_name}
+ SHARED
+ ${SOURCE_FILES}
)
- target_link_libraries(${target_name} ${LOG_LIB} kantvcore openblas android)
+ target_link_libraries(${target_name} ${LOG_LIB} kantvcore openblas android)
endfunction()
-build_library("whispercpp")
\ No newline at end of file
+build_library("whispercpp")
diff --git a/external/whispercpp/build.sh b/external/whispercpp/build.sh
index 3abb4c868..7ee0683f0 100755
--- a/external/whispercpp/build.sh
+++ b/external/whispercpp/build.sh
@@ -42,7 +42,7 @@ fi
function build_arm64
{
-cmake -H. -B./out/arm64-v8a -DPROJECT_ROOT_PATH=${PROJECT_ROOT_PATH} -DTARGET_NAME=${TARGET} -DCMAKE_BUILD_TYPE=${PROJECT_BUILD_TYPE} -DBUILD_TARGET="android" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-21 -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DLOCAL_WHISPERCPP_PATH=${LOCAL_WHISPERCPP_PATH}
+cmake -H. -B./out/arm64-v8a -DPROJECT_ROOT_PATH=${PROJECT_ROOT_PATH} -DTARGET_NAME=${TARGET} -DCMAKE_BUILD_TYPE=${PROJECT_BUILD_TYPE} -DBUILD_TARGET="android" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=${ANDROID_PLATFORM} -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DLOCAL_WHISPERCPP_PATH=${LOCAL_WHISPERCPP_PATH}
cd ./out/arm64-v8a
make
@@ -56,7 +56,7 @@ cd -
function build_armv7a
{
-cmake -H. -B./out/armeabi-v7a -DPROJECT_ROOT_PATH=${PROJECT_ROOT_PATH} -DTARGET_NAME=${TARGET} -DCMAKE_BUILD_TYPE=${PROJECT_BUILD_TYPE} -DBUILD_TARGET="android" -DANDROID_ABI=armeabi-v7a -DANDROID_PLATFORM=android-21 -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DLOCAL_WHISPERCPP_PATH=${LOCAL_WHISPERCPP_PATH}
+cmake -H. -B./out/armeabi-v7a -DPROJECT_ROOT_PATH=${PROJECT_ROOT_PATH} -DTARGET_NAME=${TARGET} -DCMAKE_BUILD_TYPE=${PROJECT_BUILD_TYPE} -DBUILD_TARGET="android" -DANDROID_ABI=armeabi-v7a -DANDROID_PLATFORM=${ANDROID_PLATFORM} -DANDROID_NDK=${ANDROID_NDK} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DLOCAL_WHISPERCPP_PATH=${LOCAL_WHISPERCPP_PATH}
cd ./out/armeabi-v7a
make
diff --git a/external/whispercpp/jni/whispercpp-jni.c b/external/whispercpp/jni/whispercpp-jni.c
index d205f94ed..1c78d83e9 100644
--- a/external/whispercpp/jni/whispercpp-jni.c
+++ b/external/whispercpp/jni/whispercpp-jni.c
@@ -71,19 +71,19 @@ Java_org_ggml_whispercpp_whispercpp_bench(JNIEnv *env, jclass clazz, jstring mod
num_threads = 1;
switch (bench_type) {
- case 0: // memcpy
- case 1: // mulmat
- case 3: // whisper encoder
+ case BECHMARK_MEMCPY: // memcpy
+ case BECHMARK_MULMAT: // mulmat
+ case BECHMARK_FULL: // whisper encode
whispercpp_bench(sz_model_path, bench_type, num_threads);
break;
- case 2: // asr
+ case BECHMARK_ASR: // asr
bench_result = whisper_transcribe_from_file(sz_model_path, sz_audio_path, num_threads);
break;
default:
break;
}
- if (2 == bench_type) { // asr
+ if (BECHMARK_ASR == bench_type) { // asr
if (NULL == bench_result) {
LOGGW("failed to get asr result, pls check why?");
goto failure;
@@ -107,4 +107,12 @@ Java_org_ggml_whispercpp_whispercpp_bench(JNIEnv *env, jclass clazz, jstring mod
jstring string = (*env)->NewStringUTF(env, sz_bench_result);
return string;
+}
+
+JNIEXPORT jint JNICALL
+Java_org_ggml_whispercpp_whispercpp_get_1cpu_1core_1counts(JNIEnv *env, jclass clazz) {
+ UNUSED(env);
+ UNUSED(clazz);
+
+ return whisper_get_cpu_core_counts();
}
\ No newline at end of file
diff --git a/external/whispercpp/kantv_asr.h b/external/whispercpp/kantv_asr.h
index 1135d93d4..818542531 100644
--- a/external/whispercpp/kantv_asr.h
+++ b/external/whispercpp/kantv_asr.h
@@ -27,6 +27,11 @@ void kantv_asr_notify(std::string &info);
extern "C" {
#endif
+#define BECHMARK_ASR 0
+#define BECHMARK_MEMCPY 1
+#define BECHMARK_MULMAT 2
+#define BECHMARK_FULL 3
+
void kantv_asr_notify_c(const char *info);
#ifdef __cplusplus
diff --git a/external/whispercpp/whisper.cpp b/external/whispercpp/whisper.cpp
index 74160f753..a6746a6e1 100644
--- a/external/whispercpp/whisper.cpp
+++ b/external/whispercpp/whisper.cpp
@@ -3182,7 +3182,7 @@ struct whisper_context * whisper_init_from_file_with_params_no_state(const char
auto fin = std::ifstream(path_model, std::ios::binary);
if (!fin) {
- WHISPER_LOG_ERROR("%s: failed to open '%s'\n", __func__, path_model);
+ WHISPER_LOG_ERROR("%s: failed to open '%s', reason %s\n", __func__, path_model, strerror(errno));
return nullptr;
}
@@ -3886,7 +3886,8 @@ const char * whisper_print_system_info(void) {
s += "VSX = " + std::to_string(ggml_cpu_has_vsx()) + " | ";
s += "CUDA = " + std::to_string(ggml_cpu_has_cublas()) + " | ";
s += "COREML = " + std::to_string(whisper_has_coreml()) + " | ";
- s += "OPENVINO = " + std::to_string(whisper_has_openvino()) ;
+ s += "OPENVINO = " + std::to_string(whisper_has_openvino()) + " | ";
+ s += "counts = " + std::to_string(std::thread::hardware_concurrency());
return s.c_str();
}
@@ -7155,13 +7156,13 @@ void whispercpp_bench(const char *model_path, int bench_type, int n_threads) {
LOGGD("model path:%s\n", model_path);
switch (bench_type) {
- case 3: // whisper encoder
+ case BECHMARK_FULL: // whisper encode
whisper_bench_full(params);
break;
- case 0: // memcpy
+ case BECHMARK_MEMCPY:
whisper_bench_memcpy(n_threads);
break;
- case 1: // mulmat
+ case BECHMARK_MULMAT:
whisper_bench_ggml_mul_mat(n_threads);
break;
default:
@@ -7169,4 +7170,8 @@ void whispercpp_bench(const char *model_path, int bench_type, int n_threads) {
}
}
//end borrow from examples/bench/bench.cpp
+
+int whisper_get_cpu_core_counts() {
+ return std::thread().hardware_concurrency();
+}
//------------------------------------ end added by zhou.weiguo -------------------------------------
diff --git a/external/whispercpp/whisper.h b/external/whispercpp/whisper.h
index f7f7fe863..6434b58fd 100644
--- a/external/whispercpp/whisper.h
+++ b/external/whispercpp/whisper.h
@@ -622,6 +622,8 @@ extern "C" {
WHISPER_API const char * whisper_transcribe_from_file(const char *model_path, const char *audio_path, int num_threads);
+ WHISPER_API int whisper_get_cpu_core_counts(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/release/README.md b/release/README.md
index e28ff2ac2..b666a9207 100644
--- a/release/README.md
+++ b/release/README.md
@@ -138,9 +138,17 @@
- start integrating whisper.cpp to project kantv. breankdown task in PoC
- PoC stage-1 is finished and works well as expected
- - PoC stage-2 is finished and works well as expected, it's a milestone
+ - PoC stage-2 is finished and works well as expected, it's the first milestone
+- v1.3.1 2024-03-11,
+
+ - ASR performance improved from 21 secs to 2 secs on Xiaomi 14 by build optimization, it's the second milestone for POC
+ - add some technical docs to prepared empty directory doc
+ - refine regular codes and prepare for coding work of implement real-time English subtitle for online English TV
+
+
+
### Screenshots(一些屏幕截图)
@@ -149,7 +157,12 @@ English UI(英文界面,海外地区默认为英文界面)
![Screenshot_20240301_000503_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/07653f3d-1e7a-4208-a3d8-90b3aecc30b4)
![Screenshot_20240301_000509_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/28d549ba-2fd5-434f-bf7a-b66d82d6dde3)
![990238413](https://github.com/zhouwg/kantv/assets/6889919/44054d57-0149-4d45-8762-46ec80682c66)
-![Screenshot_20240301_114059_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/b0171435-44a5-48bf-9b59-a4b5fbcaa39f)
+
+
+![1210108450](https://github.com/cdeos/kantv/assets/6889919/9f82c290-2ed6-444c-98d4-ef840cdd9083)
+
+
+
![Screenshot_20240301_114116_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/10224799-cdf8-46f7-acd0-6df64f0fc674)
![Screenshot_2024_0304_131033](https://github.com/zhouwg/kantv/assets/6889919/6c5bd531-5577-4570-bc87-aa3a87822d6b)
@@ -163,7 +176,7 @@ Chinese UI(中文界面,国内默认为中文界面)
![Screenshot_20240301_000319_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/c48ebec5-4942-4e93-9e3a-a8626d553e9e)
![Screenshot_20240301_000324_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/66185ef2-f7e0-4b0f-b01b-ab097167bf8b)
![Screenshot_20240301_000330_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/c0f6a0a0-f150-4126-876a-021465406819)
-![Screenshot_20240301_114156_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/51f1292e-0bea-4ffc-98bf-0b4463d48dc4)
+![1210108450](https://github.com/cdeos/kantv/assets/6889919/9f82c290-2ed6-444c-98d4-ef840cdd9083)
![Screenshot_20240301_114203_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/adbff52c-c0fb-48dd-85c9-4e740c736d7a)
![Screenshot_20240301_114210_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/c48bff82-ed27-47cc-aeee-bc3183707690)
![Screenshot_20240301_000403_com cdeos kantv](https://github.com/zhouwg/kantv/assets/6889919/ebdaa2b6-d177-40c0-9d31-1e583088dd5b)