feat(playback-lab): add isolated HarmonyOS app shell
This commit is contained in:
1 parent
75ed9dd2f4
commit
2356e2f67b
22 files changed
+308
No files matched your search
@@ -0,0 +1,6 @@
|
||||
entry/libs/arm64-v8a/*.so*
|
||||
entry/build/
|
||||
build/
|
||||
oh_modules/
|
||||
.hvigor/
|
||||
local.properties
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"app": {
|
||||
"bundleName": "com.velix.playbacklab",
|
||||
"vendor": "Velix",
|
||||
"versionCode": 1,
|
||||
"versionName": "0.1.0",
|
||||
"icon": "$media:icon",
|
||||
"label": "$string:app_name"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# Velix Playback Lab
|
||||
|
||||
独立的 HarmonyOS Native XComponent + OHNativeWindow + EGL + libmpv 播放验证工程。
|
||||
|
||||
## 构建
|
||||
|
||||
```sh
|
||||
./scripts/stage-mpv.sh
|
||||
./hvigorw assembleHap --mode module -p product=default
|
||||
```
|
||||
|
||||
`stage-mpv.sh` 只把本地 Phase 1 产物复制到未跟踪的 HAP native 库目录,不把 34 MB 的二进制提交到仓库。
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"app": {
|
||||
"signingConfigs": [],
|
||||
"products": [
|
||||
{
|
||||
"name": "default",
|
||||
"signingConfig": "default",
|
||||
"targetSdkVersion": "6.1.1(24)",
|
||||
"compatibleSdkVersion": "6.1.1(24)",
|
||||
"runtimeOS": "HarmonyOS"
|
||||
}
|
||||
],
|
||||
"buildModeSet": [
|
||||
{ "name": "debug" },
|
||||
{ "name": "release" }
|
||||
]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"name": "entry",
|
||||
"srcPath": "./entry",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": ["default"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"files": {
|
||||
"ignore": ["**/entry/libs/**"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
build/
|
||||
.cxx/
|
||||
libs/arm64-v8a/*.so*
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"apiType": "stageMode",
|
||||
"buildOption": {
|
||||
"externalNativeOptions": {
|
||||
"path": "./src/main/cpp/CMakeLists.txt",
|
||||
"arguments": "",
|
||||
"cppFlags": "-std=c++17 -fvisibility=hidden",
|
||||
"abiFilters": ["arm64-v8a"]
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{ "name": "default" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: hapTasks,
|
||||
plugins: []
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
# Playback Lab keeps native bridge names stable for NAPI lookup.
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"modelVersion": "6.1.1",
|
||||
"name": "entry",
|
||||
"version": "1.0.0",
|
||||
"description": "Playback Lab entry module"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { UIAbility, Want } from '@kit.AbilityKit';
|
||||
import { window } from '@kit.ArkUI';
|
||||
|
||||
export default class EntryAbility extends UIAbility {
|
||||
onWindowStageCreate(windowStage: window.WindowStage): void {
|
||||
windowStage.loadContent('pages/Index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import playbackLab from 'libentry.so';
|
||||
|
||||
interface PlaybackState {
|
||||
state: string;
|
||||
position: number;
|
||||
duration: number;
|
||||
fps: number;
|
||||
dropped: number;
|
||||
firstFrameMs: number;
|
||||
renderCount: number;
|
||||
lastError: string;
|
||||
surface: string;
|
||||
egl: string;
|
||||
mpv: string;
|
||||
}
|
||||
|
||||
const LOCAL_TEST_URL: string = 'file:///data/storage/el2/base/haps/entry/files/sample.mp4';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct Index {
|
||||
@State url: string = LOCAL_TEST_URL;
|
||||
@State status: string = 'IDLE';
|
||||
@State detail: string = 'Surface waiting';
|
||||
@State state: PlaybackState = {
|
||||
state: 'IDLE', position: 0, duration: 0, fps: 0, dropped: 0,
|
||||
firstFrameMs: -1, renderCount: 0, lastError: '', surface: 'WAITING', egl: 'WAITING', mpv: 'WAITING'
|
||||
};
|
||||
private poller: number = 0;
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.poller = setInterval(() => {
|
||||
this.state = playbackLab.getState() as PlaybackState;
|
||||
this.status = this.state.state;
|
||||
this.detail = this.state.lastError || `position ${this.state.position.toFixed(2)} / ${this.state.duration.toFixed(2)}s`;
|
||||
}, 250);
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
if (this.poller !== 0) {
|
||||
clearInterval(this.poller);
|
||||
this.poller = 0;
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Column({ space: 10 }) {
|
||||
Text('Velix Playback Lab').fontSize(24).fontWeight(FontWeight.Bold).width('100%')
|
||||
Text(`state: ${this.status}`).fontSize(16).fontColor($r('app.color.primary')).width('100%')
|
||||
Text(`surface=${this.state.surface} egl=${this.state.egl} mpv=${this.state.mpv}`)
|
||||
.fontSize(13).fontColor($r('app.color.muted')).width('100%')
|
||||
XComponent({ id: 'playback_surface', type: XComponentType.SURFACE, libraryname: 'entry' })
|
||||
.width('100%').height(250).backgroundColor(Color.Black)
|
||||
TextInput({ text: this.url, placeholder: 'file:///... or https://...' })
|
||||
.width('100%').onChange((value: string) => this.url = value)
|
||||
Row({ space: 8 }) {
|
||||
Button('Load Local Test').onClick(() => {
|
||||
this.url = LOCAL_TEST_URL;
|
||||
playbackLab.load(LOCAL_TEST_URL);
|
||||
})
|
||||
Button('Load URL').onClick(() => playbackLab.load(this.url))
|
||||
}.width('100%')
|
||||
Row({ space: 8 }) {
|
||||
Button('Play').onClick(() => playbackLab.play())
|
||||
Button('Pause').onClick(() => playbackLab.pause())
|
||||
Button('Stop').onClick(() => playbackLab.stop())
|
||||
Button('Release').onClick(() => playbackLab.release())
|
||||
}.width('100%')
|
||||
Row({ space: 8 }) {
|
||||
Button('-10s').onClick(() => playbackLab.seek(-10))
|
||||
Button('+10s').onClick(() => playbackLab.seek(10))
|
||||
}.width('100%')
|
||||
Text(`position=${this.state.position.toFixed(2)} duration=${this.state.duration.toFixed(2)} fps=${this.state.fps.toFixed(2)}`)
|
||||
.fontSize(13).fontColor($r('app.color.muted')).width('100%')
|
||||
Text(`dropped=${this.state.dropped} firstFrameMs=${this.state.firstFrameMs} renderCount=${this.state.renderCount}`)
|
||||
.fontSize(13).fontColor($r('app.color.muted')).width('100%')
|
||||
Text(detailLabel(this.detail)).fontSize(13).fontColor($r('app.color.muted')).width('100%').maxLines(2)
|
||||
}
|
||||
.padding(16).width('100%').height('100%').backgroundColor($r('app.color.background'))
|
||||
}
|
||||
}
|
||||
|
||||
function detailLabel(value: string): string {
|
||||
return `detail: ${value}`;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"module": {
|
||||
"name": "entry",
|
||||
"type": "entry",
|
||||
"description": "$string:module_desc",
|
||||
"mainElement": "EntryAbility",
|
||||
"deviceTypes": ["phone", "tablet"],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
"pages": "$profile:main_pages",
|
||||
"abilities": [
|
||||
{
|
||||
"name": "EntryAbility",
|
||||
"srcEntry": "./ets/entryability/EntryAbility.ets",
|
||||
"description": "$string:ability_desc",
|
||||
"icon": "$media:icon",
|
||||
"label": "$string:app_name",
|
||||
"startWindowIcon": "$media:icon",
|
||||
"startWindowBackground": "$color:start_window_background",
|
||||
"exported": true,
|
||||
"skills": [
|
||||
{
|
||||
"entities": ["entity.system.home"],
|
||||
"actions": ["ohos.want.action.home"]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"requestPermissions": [
|
||||
{
|
||||
"name": "ohos.permission.INTERNET"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"color": [
|
||||
{ "name": "background", "value": "#101318" },
|
||||
{ "name": "start_window_background", "value": "#101318" },
|
||||
{ "name": "panel", "value": "#1A202A" },
|
||||
{ "name": "primary", "value": "#6EA8FE" },
|
||||
{ "name": "muted", "value": "#A9B4C2" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"string": [
|
||||
{ "name": "app_name", "value": "Velix Playback Lab" },
|
||||
{ "name": "module_desc", "value": "Native libmpv playback verification" },
|
||||
{ "name": "ability_desc", "value": "Playback Lab main ability" },
|
||||
{ "name": "status_idle", "value": "IDLE" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg width="96" height="96" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="96" height="96" rx="20" fill="#101318"/>
|
||||
<path d="M38 27v42l32-21z" fill="#6EA8FE"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 173 B |
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"src": ["pages/Index"]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"modelVersion": "6.1.1",
|
||||
"dependencies": {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { appTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: appTasks,
|
||||
plugins: []
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"meta": {
|
||||
"stableOrder": true,
|
||||
"enableUnifiedLockfile": false
|
||||
},
|
||||
"lockfileVersion": 3,
|
||||
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
|
||||
"specifiers": {
|
||||
"@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0",
|
||||
"@ohos/hypium@1.0.25": "@ohos/hypium@1.0.25"
|
||||
},
|
||||
"packages": {
|
||||
"@ohos/hamock@1.0.0": {
|
||||
"name": "@ohos/hamock",
|
||||
"version": "1.0.0",
|
||||
"integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==",
|
||||
"resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har",
|
||||
"registryType": "ohpm"
|
||||
},
|
||||
"@ohos/hypium@1.0.25": {
|
||||
"name": "@ohos/hypium",
|
||||
"version": "1.0.25",
|
||||
"integrity": "sha512-l6uO2pjl8HyEKdekLqQt7tUpWbDqX/42zoAzkagtUVZAW9jT6lMvbe54MVjoLxq/RwQGygRvi6j4GpypSMFSHw==",
|
||||
"resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.25.har",
|
||||
"registryType": "ohpm"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"modelVersion": "6.1.1",
|
||||
"description": "Velix Playback Lab",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@ohos/hypium": "1.0.25",
|
||||
"@ohos/hamock": "1.0.0"
|
||||
}
|
||||
}
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)
|
||||
source_lib="$repo_root/build/ohos-arm64/prefix/lib/libmpv.so.2.5.0"
|
||||
target_dir="$repo_root/playback_lab/entry/libs/arm64-v8a"
|
||||
target_lib="$target_dir/libmpv.so.2"
|
||||
|
||||
if [ ! -f "$source_lib" ]; then
|
||||
echo "missing Phase 1 libmpv: $source_lib" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$target_dir"
|
||||
cp -f "$source_lib" "$target_lib"
|
||||
echo "staged $target_lib ($(stat -f %z "$target_lib") bytes)"
|
||||
Reference in new issue
Block a user