更新记录
1.0.3(2026-08-06)
- 清理插件发布目录中的外部方案调研和内部审计资料,客户文档仅保留接入说明、真实能力和平台边界。
- 完善发布检查,禁止内部验收报告、外部产品对比信息和误导性平台支持声明进入插件市场包。
- 补充横版市场封面素材,并保持 Android 已支持、iOS/HarmonyOS 尚未开放的真实宣传口径。
1.0.2(2026-08-06)
- 修复 Android FFmpeg 在部分 ABI 转译模拟器中出现 MediaCodec 丢弃全部视频缓冲、命令仍以
exitCode=0结束时误回调成功的问题;显式视频输出现在必须反查到可读视频轨,否则返回明确失败。 - 修正 Android H264/H265 能力判断:当内置 FFmpeg 二进制 ABI 与系统首选 ABI 不一致时,不再把仅能创建 MediaCodec 对象误报为可用编码能力,并在能力说明中返回 ABI 兼容状态。
- 增强 Android FFmpeg manifest 读取:系统首选 ABI 没有对应资源时会继续读取实际随插件发布的 ABI manifest,避免诊断字段为空。
平台兼容性
uni-app(4.84)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | √ | √ | √ | × | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
uni-app x(4.84)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | √ | × | × | × |
lizhao-video-editor
lizhao-video-editor 是面向 uni-app / uni-app x 的视频编辑 UTS 插件,目标能力包括视频裁剪 UI、无界面压缩、FFmpeg 命令、FFprobe 命令、视频宽高/时长、视频取帧、取消任务和缓存清理。
插件已提供稳定的 UTS 接口、错误码、平台入口、示例页和发布守卫。Android 已先打通“本地/授权视频 -> 读取宽高时长 -> 真实 FFprobe -> 提取帧图到插件缓存 -> 原生裁剪 UI 预览/时间轴/比例确认 -> 无 UI 时间裁剪输出 MP4 -> FFmpeg 画面区域裁剪 -> compressVideo codec=copy 全量/时间段兼容输出 -> H264/H265 硬编码压缩预检 -> FFmpeg/FFprobe 原生命令执行层 -> FFmpeg H264/H265 真实压缩 -> FFprobe 反查压缩输出 -> FFmpeg copy/trim 命令 -> FFmpeg 单帧/序列帧取图命令 -> 取消取帧/元数据/探测/裁剪/压缩兼容输出/原生命令任务 -> 按裁剪/压缩/取帧/FFmpeg 类型清理缓存”的真实闭环;Android 会从应用 nativeLibraryDir 解析插件私有的 liblizhao_video_editor_ffmpeg.so 和 liblizhao_video_editor_ffprobe.so,存在且可执行时运行真实命令,不存在时公共 FFmpeg/FFprobe 命令直接 fail,避免伪造成完整命令成功;接入或替换原生二进制、裁剪 UI 或平台 UTS 原生逻辑后需要重新打对应平台自定义基座。
功能特色
- 双层 API:保留
crop / compress / ffmpegCommand / ffprobeCommand等迁移友好接口,同时提供openVideoCropper / compressVideo / executeFfmpeg / executeFfprobe等类型化接口。 - Android 真实闭环:
getVideoMetadata / executeFfprobe / extractVideoFrames / openVideoCropper / compressVideo(codec=copy 全量/时间段) / compressVideo(有 FFmpeg 二进制时 h264/h265 真实压缩,缺失时预检失败) / executeFfmpeg / cancelVideoTask / clearVideoEditorCache已可处理本地路径、_doc、static、file://、路径空格和content://授权视频;示例页提供uni.chooseVideo({ sourceType: ['album'] })相册选择入口,会把系统返回的tempFilePath/content://授权路径直接写入sampleVideo并调用getVideoMetadata,便于客户验证 Android 10/11+ 分区存储路径;裁剪、压缩、FFmpeg 输出和单帧取图支持自定义_doc / file:// / 绝对路径 / content://输出,未传输出路径时默认写入插件分类型缓存目录,嵌套父目录会自动创建,同名文件按覆盖语义重写,Android 10/11+ 公共绝对路径会通过 MediaStore 写入公共目录并在结果诊断里带回contentUri=content://media/...证据,普通自动验收还会用该contentUri再调用getVideoMetadata反查宽高和时长;普通自动验收会对cropWidth/cropHeight区域裁剪输出追加 FFprobe 反查宽高,确认 160x90 产物真实生成,并对 H264/H265/AAC 压缩输出追加 FFprobe 反查压缩输出,确认输出流包含h264 / hevc / aac等目标编码名;缓存已支持crop / compress / frame / ffmpeg / all分类型清理,清理结果会返回deleted=与bytes=统计,便于定位缓存是否实际被扫描和删除。 - 统一
success / fail / complete / progress回调结构,Android 元数据、取帧、无 UI 时间裁剪、压缩 copy 兼容输出、真实 FFmpeg/FFprobe 原生命令已支持taskId取消和日志关联;公共executeFfmpeg/executeFfprobe缺少二进制时走fail/complete,不再回退到兼容子集伪造成功。 - 统一错误码段
9070001起,覆盖平台不支持、路径不可读、FFmpeg 缺失、编码不支持、任务取消、缓存失败和原生 UI 不可用。 - 当前能力矩阵会真实声明 Android
metadata=true / frame=true / cancel=true / cropUi=true,h264/h265来自设备MediaCodec.createEncoderByType('video/avc' / 'video/hevc')动态预检;ffmpeg与ffprobe不再写死,而是分别由ffmpegReady/ffprobeReady检测应用nativeLibraryDir下两个插件私有原生文件是否已随自定义基座安装且可执行;compress跟随ffmpegReady,二进制存在时compressVideo/compress会生成h264_mediacodec / hevc_mediacodecFFmpeg 命令并支持width / height / bitrate / fps / audioCodec;androidRuntimeBuild用于真机 smoke 识别旧 UTS 自定义基座;openVideoCropper/crop默认打开 Android 原生裁剪 UI,提供视频预览、开始/结束时间轴、自由/1:1/4:3/16:9 比例选择和确认/取消回调,自动验收或无界面业务可传showUi:false直接执行裁剪。 - Android 默认包仅在
app-android/libs/<abi>/放置私有命名的liblizhao_video_editor_ffmpeg.so与liblizhao_video_editor_ffprobe.so,安装时通过android:extractNativeLibs="true"解压到应用nativeLibraryDir后直接执行,避免 Android 10+ 从 cache 执行 ELF 被 SELinux 拒绝;插件不注册共享包名或通用libffmpeg.so,LGPL 默认包不含 GPL/nonfree 外部编解码扩展,如后续提供 GPL 或 vendor SDK 扩展包,应独立发包并重新打自定义基座。
接入方式选择
| 场景 | 推荐接口 | 说明 |
|---|---|---|
| 需要迁移既有调用 | crop / compress / ffmpegCommand / ffprobeCommand |
保留兼容方法名,内部代理到类型化 API |
| 新项目接入 | openVideoCropper / compressVideo |
Android openVideoCropper 默认打开原生裁剪 UI,确认后按时间轴和比例输出新视频;传 showUi:false 可无界面执行,且有 FFmpeg 二进制时支持 cropWidth/cropHeight/aspectRatio 画面区域裁剪;compressVideo 已支持 codec: 'copy' 全量/时间段兼容输出,有 FFmpeg 二进制时支持 H264/H265、码率、分辨率、帧率和音频 copy/AAC/移除音频 |
| 自定义命令 | executeFfmpeg / executeFfprobe |
Android 已接入原生命令执行层;必须在 app-android/libs/<abi>/ 内置两个插件私有原生执行文件并由安装器解压到 nativeLibraryDir,缺失或不可执行时返回 9070005/9070006,不伪造成功 |
| 读取视频信息 | getVideoMetadata |
获取宽高、时长、方向、编码等信息 |
| 提取帧图 | extractVideoFrames |
Android 已支持多时间点、图片格式、文件和 Base64 输出 |
| 取消长任务 | cancelVideoTask |
Android 已支持取消元数据、取帧、时间裁剪、压缩 copy 兼容输出和真实 FFmpeg/FFprobe 进程任务;原生命令取消会调用 Process.destroy() 并回调 9070012;未知或已清理 taskId 会走 fail/complete,普通 smoke 已覆盖该边界 |
| 清理缓存 | clearVideoEditorCache |
Android 已按 crop / compress / frame / ffmpeg / all 清理,结果 stdout 包含 deleted= 和 bytes= 统计 |
Android 原生包与冲突边界
| 场景 | 是否放入默认包 | 推荐做法 | 验收方式 |
|---|---|---|---|
| LGPL FFmpeg/FFprobe 默认能力 | 是 | 使用 app-android/libs/arm64-v8a/liblizhao_video_editor_ffmpeg.so 和 liblizhao_video_editor_ffprobe.so 两个私有名称,不加载通用 libffmpeg.so |
运行 Android 基座检查脚本或在重打基座后检查 APK/设备,确认 PT_LOAD p_align=0x4000、SHA256、LGPL、私有名称和 nativeLibraryDir 解压策略 |
第三方 FFmpeg AAR 或通用 libffmpeg.so |
否 | 不放进默认包,避免与客户项目、其它视频插件或系统加载路径冲突 | 基座检查脚本发现非私有路径 FFmpeg/AAR/JAR/SO 会失败 |
| GPL 编解码扩展、厂商硬编 SDK、其它 ABI | 否 | 使用独立扩展包名、独立文档和 16KB page-size 兼容构建,客户明确选择后重新打 Android 自定义基座 | 扩展包单独验收,不与默认 LGPL 包混放 |
| 客户已有视频 SDK 或其它 FFmpeg 插件 | 默认包可共存 | 本插件不注册全局 FFmpeg 包名,不加载共享 libffmpeg.so,只解析 nativeLibraryDir 下两个插件私有文件名 |
getVideoEditorCapabilities() 的 conflictBoundary / androidRuntimeBuild 字段和 ADB smoke 的 AUTO_VIDEO_EDITOR_SMOKE_BINARY_READY 可查看当前边界与基座版本 |
最小可运行示例
import { getVideoEditorCapabilities, getVideoMetadata, executeFfprobe, extractVideoFrames } from '@/uni_modules/lizhao-video-editor'
// 先读取真实能力矩阵;Android 会按当前自定义基座是否包含 FFmpeg/FFprobe 二进制返回 ffmpeg/ffprobe。
const capabilities = getVideoEditorCapabilities()
console.log('视频编辑能力矩阵', capabilities)
// Android 首个真实闭环:读取本地视频宽高和时长。
getVideoMetadata({
src: 'static/video/flower.mp4',
progress(event) {
console.log('视频信息进度', event.progress, event.message)
},
success(res) {
console.log('视频宽高时长', res.width, res.height, res.duration)
},
fail(err) {
console.log('视频信息失败', err.errCode, err.errMsg)
}
})
// Android FFprobe 原生命令:需要自定义基座内置 FFprobe 二进制,缺失时返回 9070006。
executeFfprobe({
command: ['-v', 'quiet', '-print_format', 'json', '-show_format', '-show_streams', 'static/video/flower.mp4'],
success(res) {
console.log('ffprobe stdout', res.stdout)
},
fail(err) {
console.error('探测失败', err)
}
})
// Android 首个真实闭环:提取 0ms 帧图并写入插件缓存目录。
extractVideoFrames({
src: 'static/video/flower.mp4',
timesMs: [0],
format: 'jpg',
outputType: 'file',
success(res) {
console.log('帧图路径', res.frames[0].imagePath)
}
})
常见增强示例
import { openVideoCropper, executeFfmpeg, compressVideo, clearVideoEditorCache } from '@/uni_modules/lizhao-video-editor'
// Android 默认打开原生裁剪 UI:预览视频,调整开始/结束时间和比例,点击确认后输出 MP4。
openVideoCropper({
src: 'static/video/flower.mp4',
outputPath: '_doc/demo-crop.mp4',
startTimeMs: 0,
endTimeMs: 1500,
aspectRatio: '16:9',
codec: 'h264',
hardware: 'auto',
success(res) {
console.log('裁剪输出路径', res.outputPath)
},
fail(err) {
console.log('裁剪失败', err.errCode, err.errMsg)
}
})
// Android 无界面裁剪:适合自动验收或业务自定义 UI,直接按参数输出。
openVideoCropper({
src: 'static/video/flower.mp4',
outputPath: '_doc/demo-crop-headless.mp4',
showUi: false,
startTimeMs: 0,
endTimeMs: 1500,
aspectRatio: '16:9',
success(res) {
console.log('无界面裁剪输出路径', res.outputPath)
}
})
// Android FFmpeg 原生命令:需要自定义基座内置 FFmpeg 二进制,缺失时返回 9070005。
executeFfmpeg({
command: ['-y', '-ss', '0', '-t', '1.5', '-i', 'static/video/flower.mp4', '-map', '0:v:0', '-map', '0:a?', '-c:v', 'copy', '-c:a', 'copy', '-movflags', '+faststart', '_doc/demo-ffmpeg-copy.mp4'],
progress(event) {
console.log('FFmpeg 原生命令进度', event.progress, event.message)
},
success(res) {
console.log('FFmpeg 原生命令输出路径', res.outputPath)
},
fail(err) {
console.log('FFmpeg 原生命令失败', err.errCode, err.errMsg)
}
})
// Android FFmpeg 单帧取图:通过真实 FFmpeg 二进制输出图片。
executeFfmpeg({
command: ['-y', '-ss', '0.6', '-i', 'static/video/flower.mp4', '-frames:v', '1', '-q:v', '2', '_doc/demo-ffmpeg-frame.jpg'],
progress(event) {
console.log('FFmpeg 取帧进度', event.progress, event.message)
},
success(res) {
console.log('FFmpeg 取帧输出路径', res.outputPath, res.stdout)
},
fail(err) {
console.log('FFmpeg 取帧命令失败', err.errCode, err.errMsg)
}
})
// Android FFmpeg 序列帧命令:通过真实 FFmpeg 二进制输出序列帧。
executeFfmpeg({
command: ['-y', '-ss', '0', '-i', 'static/video/flower.mp4', '-vf', 'fps=1', '-q:v', '3', '_doc/demo-ffmpeg-seq_d.jpg'],
progress(event) {
console.log('FFmpeg 序列帧进度', event.progress, event.message)
},
success(res) {
console.log('FFmpeg 序列帧数量', res.frames.length, res.stdout)
},
fail(err) {
console.log('FFmpeg 序列帧命令失败', err.errCode, err.errMsg)
}
})
// Android compressVideo:未内置 FFmpeg 时 codec=copy 走系统兼容输出;内置 FFmpeg 时可执行真实压缩。
compressVideo({
src: 'static/video/flower.mp4',
outputPath: '_doc/demo-compress-trim-copy.mp4',
startTimeMs: 300,
endTimeMs: 1800,
codec: 'copy',
success(res) {
console.log('压缩时间段兼容输出路径', res.outputPath, res.duration, res.stdout)
},
fail(err) {
console.log('压缩兼容输出失败', err.errCode, err.errMsg)
}
})
// Android H264 压缩:新自定义基座内置 FFmpeg 时会真实压缩;旧基座缺失二进制时返回 9070009 预检失败。
compressVideo({
src: 'static/video/flower.mp4',
outputPath: '_doc/demo-compress-h264.mp4',
width: 720,
bitrate: 1200000,
fps: 30,
codec: 'h264',
audioCodec: 'aac',
hardware: 'auto',
progress(event) {
console.log('H264 压缩进度', event.progress, event.message)
},
fail(err) {
console.log('硬编码预检诊断', err.errCode, err.errMsg)
}
})
// 缓存清理按类型执行,Android 已映射到裁剪/压缩/取帧/FFmpeg 缓存目录。
clearVideoEditorCache({
// 可选 crop / compress / frame / ffmpeg / all;兼容 API clearCropVideoCache 等会自动映射到对应目录。
// 传入其它字符串会返回 9070003,并同时触发 fail / complete,避免把错误类型静默当成清理成功。
type: 'all',
complete(res) {
console.log('缓存清理完成', res)
}
})
完整示例源码路径
| 示例 | 路径 | 说明 |
|---|---|---|
| uni-app 示例 | uni_modules/lizhao-video-editor/example/uniapp/videoEditor.vue |
覆盖能力矩阵、兼容 API、新 API、取消任务和缓存清理 |
| uni-app x 示例 | uni_modules/lizhao-video-editor/example/uniappx/index.uvue |
用于 uni-app x 项目中做平台入口和回调验收 |
| 相册选择验收 | 示例页按钮“选择相册视频并读取信息” | 真实调用 uni.chooseVideo({ sourceType: ['album'] }),将系统返回路径写入 sampleVideo 后读取视频信息,用于验证 Android 10/11+ 分区存储授权视频输入 |
| Android 自动验收脚本 | scripts/acceptance-lizhao-video-editor-android.ps1 |
自定义基座安装后通过 ADB 打开 autoVideoEditorSmoke=1,等待 AUTO_VIDEO_EDITOR_SMOKE_DONE;脚本会先拉取已安装 base.apk 检查 ffmpeg、ffprobe 和 manifest 是否进入自定义基座,并调用基座 assets 检查脚本解析 ELF PT_LOAD p_align=0x4000、SHA256 与 LGPL 标记,旧基座缺二进制或 16KB 不兼容时直接提示重新打 Android 自定义基座;随后强制检查真实 FFmpeg/FFprobe、真实 FFmpeg 进度回调 AUTO_VIDEO_EDITOR_SMOKE_FFMPEG_PROGRESS_OK、路径空格 FFmpeg 输出 AUTO_VIDEO_EDITOR_SMOKE_SPACE_PATH_FFMPEG_OK、路径空格 FFprobe 输入 AUTO_VIDEO_EDITOR_SMOKE_SPACE_PATH_FFPROBE_OK、直接 executeFfmpeg H264 转码命令 AUTO_VIDEO_EDITOR_SMOKE_FFMPEG_TRANSCODE_H264_OK 及 FFprobe 反查 AUTO_VIDEO_EDITOR_SMOKE_FFMPEG_TRANSCODE_H264_PROBE_OK、画面区域裁剪输出 AUTO_VIDEO_EDITOR_SMOKE_CROP_AREA_OK 及 FFprobe 宽高反查 AUTO_VIDEO_EDITOR_SMOKE_CROP_AREA_PROBE_OK、真实 H264 压缩成功 AUTO_VIDEO_EDITOR_SMOKE_COMPRESS_REAL_OK、H264 输出 FFprobe 反查 AUTO_VIDEO_EDITOR_SMOKE_COMPRESS_H264_PROBE_OK、H265 能力分支 AUTO_VIDEO_EDITOR_SMOKE_COMPRESS_H265_CHECK_OK、AAC 音频转码分支 AUTO_VIDEO_EDITOR_SMOKE_COMPRESS_AAC_OK、AAC 输出 FFprobe 反查 AUTO_VIDEO_EDITOR_SMOKE_COMPRESS_AAC_PROBE_OK、真实压缩失败 fail 回调 AUTO_VIDEO_EDITOR_SMOKE_COMPRESS_FAIL_OK、输出路径父目录创建和同名覆盖 AUTO_VIDEO_EDITOR_SMOKE_OUTPUT_STRATEGY_OK、不支持输出扩展名 fail/complete 回调 AUTO_VIDEO_EDITOR_SMOKE_OUTPUT_INVALID_FAIL_OK / AUTO_VIDEO_EDITOR_SMOKE_OUTPUT_INVALID_COMPLETE_OK、公共目录 MediaStore 输出 AUTO_VIDEO_EDITOR_SMOKE_PUBLIC_OUTPUT_CONTENT_URI_OK / AUTO_VIDEO_EDITOR_SMOKE_PUBLIC_OUTPUT_CONTENT_URI_METADATA_OK / AUTO_VIDEO_EDITOR_SMOKE_PUBLIC_OUTPUT_OK、FFmpeg 失败 fail 回调 AUTO_VIDEO_EDITOR_SMOKE_FFMPEG_FAIL_OK、FFprobe 失败 fail 回调 AUTO_VIDEO_EDITOR_SMOKE_FFPROBE_FAIL_OK、crop / compress / frame / ffmpeg / all 分类型缓存清理和兼容清理 API marker、每个清理结果的 *_STATS_OK 统计 marker、原生裁剪 UI 打开并自动取消 AUTO_VIDEO_EDITOR_SMOKE_CROP_UI_OK、原生裁剪 UI 自动确认输出 AUTO_VIDEO_EDITOR_SMOKE_CROP_UI_CONFIRM_OK、原生裁剪 UI 1:1 比例输出 FFprobe 反查 AUTO_VIDEO_EDITOR_SMOKE_CROP_UI_RATIO_PROBE_OK、原生裁剪 UI 时间轴输出时长反查 AUTO_VIDEO_EDITOR_SMOKE_CROP_UI_DURATION_PROBE_OK、无 UI 裁剪和真实进程取消 AUTO_VIDEO_EDITOR_SMOKE_CANCEL_OK;取消链路还要求 AUTO_VIDEO_EDITOR_SMOKE_CANCEL_REQUEST_OK、AUTO_VIDEO_EDITOR_SMOKE_CANCEL_CLEANUP_OK、AUTO_VIDEO_EDITOR_SMOKE_CANCEL_UNKNOWN_OK 和 AUTO_VIDEO_EDITOR_SMOKE_CANCEL_UNKNOWN_COMPLETE_OK,证明取消请求成功发出、同一 taskId 已从运行任务表清理,且未知任务也稳定走 fail/complete |
| Android 压力验收脚本 | scripts/acceptance-lizhao-video-editor-android-stress.ps1 |
自定义基座安装后通过 ADB 打开 autoVideoEditorStress=1,等待 AUTO_VIDEO_EDITOR_STRESS_DONE;脚本会先拉取已安装 base.apk 检查 lib/arm64-v8a/liblizhao_video_editor_ffmpeg.so、liblizhao_video_editor_ffprobe.so 和 manifest,并解析 ELF PT_LOAD p_align=0x4000,避免旧基座缺二进制或 16KB 不兼容时误判;随后检查长视频 copy、4K 转码稳定回调、高码率压缩稳定回调、音视频同步/静音音频 mux 稳定回调、连续压缩输出互不污染、连续两次 FFmpeg 任务取消、缓存清理和崩溃关键字;成功产物会继续走 FFprobe 反查,取消链路要求 AUTO_VIDEO_EDITOR_STRESS_CANCEL_1_REQUEST_OK / AUTO_VIDEO_EDITOR_STRESS_CANCEL_1_FAIL_OK / AUTO_VIDEO_EDITOR_STRESS_CANCEL_1_COMPLETE_OK / AUTO_VIDEO_EDITOR_STRESS_CANCEL_2_REQUEST_OK / AUTO_VIDEO_EDITOR_STRESS_CANCEL_2_FAIL_OK / AUTO_VIDEO_EDITOR_STRESS_CANCEL_2_COMPLETE_OK / AUTO_VIDEO_EDITOR_STRESS_CANCEL_STABLE_OK,并校验 errCode=9070012、processKill=destroy,destroyForcibly、processKilled=true;核心 marker 包含 AUTO_VIDEO_EDITOR_STRESS_LONG_OK、AUTO_VIDEO_EDITOR_STRESS_LONG_PROBE_OK、AUTO_VIDEO_EDITOR_STRESS_4K_PROBE_CHECK_OK、AUTO_VIDEO_EDITOR_STRESS_4K_STABLE_OK、AUTO_VIDEO_EDITOR_STRESS_HIGH_BITRATE_PROBE_CHECK_OK、AUTO_VIDEO_EDITOR_STRESS_HIGH_BITRATE_STABLE_OK、AUTO_VIDEO_EDITOR_STRESS_AV_SYNC_PROBE_CHECK_OK、AUTO_VIDEO_EDITOR_STRESS_AV_SYNC_STABLE_OK、AUTO_VIDEO_EDITOR_STRESS_REPEAT_STABLE_OK、AUTO_VIDEO_EDITOR_STRESS_CANCEL_STABLE_OK |
| Android 基座原生文件检查脚本 | scripts/check-lizhao-video-editor-android-base-assets.ps1 |
可检查插件 utssdk/app-android 目录、重打后的自定义基座 APK 或当前设备安装包,直接校验两个私有原生执行文件、ELF PT_LOAD p_align=0x4000、LGPL、SHA256 和冲突边界;支持 -ResourceRoot <app-android目录>、-ApkPath <apk> 和 -DeviceId <设备ID> 三种用法 |
支持平台
| 平台 | 是否支持 | 说明 |
|---|---|---|
| Android | 部分支持 | 已支持本地/授权视频信息读取、真实 FFprobe、取帧、原生裁剪 UI、无 UI 时间裁剪、FFmpeg 二进制画面区域裁剪、compressVideo codec=copy 全量/时间段兼容输出、H264/H265 硬编码压缩预检、FFmpeg 二进制真实压缩、完整 FFmpeg 命令和真实 FFprobe 原生命令执行层、content:// 输入和单目标输出回写、Android 10/11+ 公共目录 MediaStore 输出、真实 FFmpeg/FFprobe 进程取消、兼容清理 API 和缓存清理;接入 16KB page-size 兼容 FFmpeg 二进制或修改 Android 原生逻辑后必须重新打 Android 自定义基座 |
| iOS | 接口已就绪,原生二进制待接入 | 当前返回明确失败;后续接入 LizhaoFFmpeg.xcframework 后需要重新打 iOS 自定义基座 |
| HarmonyOS | 接口已就绪,原生二进制待接入 | 当前返回明确失败;后续接入 Harmony FFmpeg/NAPI/ArkTS 原生库后需要重新打 Harmony 自定义基座 |
| Web | 明确不支持 | 当前返回 9070001/9070005/9070006 等结构化错误,不伪造成功 |
| 微信小程序 | 明确不支持 | 当前返回结构化错误,不伪造成功 |
| 支付宝小程序 | 明确不支持 | 当前返回结构化错误,不伪造成功 |
API 列表
| API | 说明 |
|---|---|
crop(options) |
兼容裁剪 API |
compress(options) |
兼容压缩 API |
ffmpegCommand(options) |
兼容 FFmpeg 命令 API |
ffprobeCommand(options) |
兼容 FFprobe 命令 API |
getVideoWidthAndHeight(options) |
兼容获取宽高 API |
getVideoDuration(options) |
兼容获取时长 API |
getVideoFrame(options) |
兼容取帧 API |
cancel(options) |
兼容取消任务 API |
clearCompressVideoCache(options) |
清理压缩缓存 |
clearCropVideoCache(options) |
清理裁剪缓存 |
clearVideoFrameCache(options) |
清理取帧缓存 |
openVideoCropper(options) |
类型化裁剪 API;Android 默认打开原生裁剪 UI,支持视频预览、开始/结束时间轴、比例选择、确认/取消;传 showUi:false 时执行无界面时间裁剪,有 FFmpeg 二进制时支持画面区域裁剪 |
compressVideo(options) |
类型化无界面压缩 API;Android 支持 codec: 'copy' 全量/时间段兼容输出;有 FFmpeg 二进制时支持 H264/H265、码率、分辨率、帧率和音频策略 |
executeFfmpeg(options) |
类型化 FFmpeg 命令 API;Android 已接入真实二进制执行层,未内置二进制时返回 9070005,不回退兼容子集 |
executeFfprobe(options) |
类型化 FFprobe 命令 API |
getVideoMetadata(options) |
类型化视频信息 API |
extractVideoFrames(options) |
类型化视频取帧 API |
cancelVideoTask(options) |
类型化取消任务 API |
clearVideoEditorCache(options) |
类型化缓存清理 API;Android 支持 crop / compress / frame / ffmpeg / all,未知类型返回 9070003 |
getVideoEditorCapabilities() |
当前平台能力矩阵 |
openVideoCropper(options)
说明
打开视频裁剪能力。Android 默认打开原生裁剪 UI,支持视频预览、开始/结束时间轴、自由/1:1/4:3/16:9 比例选择、确认裁剪和取消回调;确认后复用真实裁剪命令,未传画面区域参数时使用系统 MediaExtractor + MediaMuxer 按关键帧附近复制视频/音频轨道并输出 MP4,不重编码、不改变码率或分辨率;传入 cropWidth / cropHeight / aspectRatio 或在 UI 中选择固定比例时,会优先使用 FFmpeg 二进制生成 crop= 滤镜做居中区域裁剪,可叠加 startTimeMs / endTimeMs / bitrate / fps / codec,缺少 FFmpeg 二进制时返回 9070005,不伪造成只裁时间成功;传 showUi:false 可绕过原生 UI 直接执行裁剪。
支持平台 Android。iOS / HarmonyOS 当前仅保留类型入口,调用会明确返回平台不支持。
参数
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| options | OpenVideoCropperOptions | 是 | 裁剪参数对象 | 无 | src / showUi / startTimeMs / endTimeMs / aspectRatio / success / fail / complete |
| options.src | string | 是 | 视频地址 | 无 | _doc / file:// / content:// / 绝对路径 |
| options.outputPath | string | 否 | 输出路径;Android 支持 _doc / file:// / 绝对路径 / content://,content:// 会先写临时文件再回写目标 Uri;/storage/emulated/0/Movies、/sdcard/Movies、Download 等公共绝对路径会通过 MediaStore 写入公共目录 |
插件缓存目录 | 无 |
| options.showUi | boolean | 否 | 是否打开 Android 原生裁剪 UI;传 false 时直接按参数执行无界面裁剪 | true |
true / false |
| options.autoCancelUiAfterMs | number | 否 | Android 自动验收辅助:原生裁剪 UI 打开后延迟自动取消,客户业务无需传入 | 0 |
大于 0 |
| options.autoConfirmUiAfterMs | number | 否 | Android 自动验收辅助:原生裁剪 UI 打开后延迟自动确认并输出裁剪结果,客户业务无需传入 | 0 |
大于 0 |
| options.autoSelectUiStartTimeMs | number | 否 | Android 自动验收辅助:原生裁剪 UI 打开后模拟选择开始时间,客户业务无需传入 | 无 | 大于等于 0 |
| options.autoSelectUiEndTimeMs | number | 否 | Android 自动验收辅助:原生裁剪 UI 打开后模拟选择结束时间,客户业务无需传入 | 无 | 大于 autoSelectUiStartTimeMs |
| options.autoSelectUiAspectRatio | string | 否 | Android 自动验收辅助:原生裁剪 UI 打开后模拟选择比例,客户业务无需传入 | 无 | free / 1:1 / 4:3 / 16:9 |
| options.startTimeMs | number | 否 | 裁剪开始时间,单位毫秒 | 0 |
大于等于 0 |
| options.endTimeMs | number | 否 | 裁剪结束时间,单位毫秒 | 视频结尾 | 大于 startTimeMs |
| options.cropWidth | number | 否 | 画面区域裁剪宽度;有 FFmpeg 二进制时生成居中 crop 滤镜 |
原视频宽度 | 大于 0 |
| options.cropHeight | number | 否 | 画面区域裁剪高度;有 FFmpeg 二进制时生成居中 crop 滤镜 |
原视频高度 | 大于 0 |
| options.aspectRatio | string | 否 | 裁剪比例;有 FFmpeg 二进制且未传固定宽高时按比例居中裁切 | free |
1:1 / 4:3 / 16:9 / free |
| options.bitrate | number | 否 | 画面区域裁剪重编码输出码率 | 原视频码率 | 大于 0 |
| options.fps | number | 否 | 画面区域裁剪输出帧率 | 原视频帧率 | 大于 0 |
| options.codec | VideoEditorCodec | 否 | 编码策略 | auto |
auto / h264 / h265 / copy |
| options.hardware | VideoEditorHardwareMode | 否 | 硬件加速策略 | auto |
auto / on / off |
| options.progress | function | 否 | 进度回调 | 无 | 无 |
| options.success | function | 否 | 成功回调 | 无 | 无 |
| options.fail | function | 否 | 失败回调 | 无 | 无 |
| options.complete | function | 否 | 完成回调 | 无 | 无 |
返回值
| 字段 | 类型 | 说明 |
|---|---|---|
| success | boolean | 是否成功 |
| platform | VideoEditorPlatform | 当前平台 |
| taskId | string | 任务 ID |
| outputPath | string | 输出视频路径 |
| duration | number | 输出视频时长,单位毫秒 |
| width | number | 输出视频宽度 |
| height | number | 输出视频高度 |
| stdout | string | 命令标准输出 |
| stderr | string | 命令错误输出 |
| exitCode | number | 原生命令退出码 |
| message | string | 中文说明 |
compressVideo(options)
说明
执行无界面压缩能力。Android codec: 'copy' 会使用系统 MediaExtractor + MediaMuxer 复制原视频/音频轨道并输出 MP4/M4V,可通过 startTimeMs / endTimeMs 输出指定时间段,不改变码率、分辨率或帧率;未传 outputPath 时写入 compress 缓存目录,传入嵌套 _doc / file:// / 绝对路径 时会创建父目录并覆盖同名文件,传入单目标 content:// 或公共目录绝对路径时会先写插件私有临时文件,再回写客户目标;当传入 width / height / bitrate / fps 或 codec: 'auto' / 'h264' / 'h265' 时,如果当前自定义基座的 nativeLibraryDir 包含插件私有 FFmpeg 文件,会生成 FFmpeg 命令执行真实压缩,默认优先 h264_mediacodec / hevc_mediacodec,支持 -b:v、-vf scale/fps、audioCodec: 'copy' / 'aac' / 'none';如果未内置二进制,则继续执行 H264/H265 硬编码压缩预检并返回 9070009 诊断,不伪造压缩成功。
支持平台 Android。iOS / HarmonyOS 当前仅保留类型入口,调用会明确返回平台不支持。
参数
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| options | CompressVideoOptions | 是 | 压缩参数对象 | 无 | src / outputPath / startTimeMs / endTimeMs / width / height / bitrate / fps / codec / audioCodec / success / fail / complete |
| options.src | string | 是 | 视频地址 | 无 | _doc / file:// / content:// / 绝对路径 |
| options.outputPath | string | 否 | 输出路径;Android 支持 _doc / file:// / 绝对路径 / content://,本地视频输出仍建议 .mp4/.m4v;content:// 会先写临时文件再回写目标 Uri,公共绝对路径会通过 MediaStore 写入公共目录 |
插件压缩缓存目录 | 无 |
| options.startTimeMs | number | 否 | copy 兼容模式下的截取开始时间,单位毫秒;不触发重编码 | 0 |
大于等于 0 |
| options.endTimeMs | number | 否 | copy 兼容模式下的截取结束时间,单位毫秒;不填或小于等于开始时间时输出到视频结尾 | 视频结尾 | 大于 startTimeMs |
| options.width | number | 否 | 目标宽度;有 FFmpeg 二进制时生成 scale 滤镜,缺失时触发预检失败 |
无 | 大于 0 |
| options.height | number | 否 | 目标高度;有 FFmpeg 二进制时生成 scale 滤镜,缺失时触发预检失败 |
无 | 大于 0 |
| options.bitrate | number | 否 | 目标码率;有 FFmpeg 二进制时生成 -b:v |
无 | 大于 0 |
| options.fps | number | 否 | 目标帧率;有 FFmpeg 二进制时生成 fps=N 滤镜 |
无 | 大于 0 |
| options.codec | VideoEditorCodec | 否 | 编码策略;copy 使用系统转封装,auto/h264/h265 在 FFmpeg 二进制存在时真实压缩 |
auto |
auto / h264 / h265 / copy |
| options.hardware | VideoEditorHardwareMode | 否 | 硬件加速策略;默认优先 h264_mediacodec / hevc_mediacodec,off 使用可选 GPL 扩展编码器名 |
auto |
auto / on / off |
| options.audioCodec | VideoEditorAudioCodec | 否 | 音频处理策略;copy 复制音频,aac 转 AAC,none 移除音频 |
copy |
copy / aac / none |
| options.progress | function | 否 | 进度回调 | 无 | 无 |
| options.success | function | 否 | 成功回调 | 无 | 无 |
| options.fail | function | 否 | 失败回调 | 无 | 无 |
| options.complete | function | 否 | 完成回调 | 无 | 无 |
返回值
| 字段 | 类型 | 说明 |
|---|---|---|
| success | boolean | 是否成功 |
| taskId | string | 任务 ID |
| outputPath | string | 输出视频路径 |
| duration | number | 输出视频时长,单位毫秒 |
| stdout | string | Android copy 兼容模式会包含 mode=android-compress-copy;真实 FFmpeg 压缩会返回原生命令输出 |
| message | string | 中文说明 |
executeFfmpeg(options)
说明
执行 FFmpeg 命令。Android 会解析应用 nativeLibraryDir 下的 liblizhao_video_editor_ffmpeg.so 并通过原生进程直接执行,不会复制到 cache;命令 stdout 会收集到返回值,time=、out_time=、out_time_us=、out_time_ms= 和 progress=end 会解析为真实进度,调用 cancelVideoTask 会真实销毁进程并返回 9070012。如果当前自定义基座未内置 FFmpeg 二进制或文件不可执行,会返回 9070005 并触发 fail/complete,不会回退 copy/trim、取帧或其它系统兼容子集伪造成功。
支持平台 Android。iOS / HarmonyOS 当前仅保留类型入口,调用会明确返回平台不支持。
参数
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| options | FfmpegCommandOptions | 是 | FFmpeg 命令参数对象 | 无 | command / taskId / progress / success / fail / complete |
| options.command | Array |
是 | 命令参数数组,不包含 ffmpeg 可执行文件名;路径含空格时作为单个数组元素传入;Android 直接传递给真实 FFmpeg 二进制执行,缺少二进制时明确失败 |
无 | FFmpeg 原生命令参数,例如 -c:v copy、-frames:v 1、-vf fps=N、jpg/png/webp 输出 |
| options.taskId | string | 否 | 自定义任务 ID,可用于 cancelVideoTask 取消 |
自动生成 | 无 |
| options.progress | function | 否 | 进度回调 | 无 | 无 |
| options.success | function | 否 | 成功回调 | 无 | 无 |
| options.fail | function | 否 | 失败回调 | 无 | 无 |
| options.complete | function | 否 | 完成回调 | 无 | 无 |
返回值
| 字段 | 类型 | 说明 |
|---|---|---|
| success | boolean | 是否成功 |
| taskId | string | 任务 ID |
| outputPath | string | 输出视频、单帧图片路径或序列帧第一张图片路径 |
| frames | Array |
取图命令会返回每张帧图的 imagePath / width / height / timeMs |
| stdout | string | 真实 FFmpeg/FFprobe 原生命令输出;失败时错误信息进入 fail.errMsg |
| stderr | string | 错误输出;Android 已合并到 stdout 读取,失败时错误摘要进入 fail.errMsg |
| exitCode | number | 真实 FFmpeg 进程退出码,成功为 0 |
| message | string | 中文说明 |
错误码
| 错误码 | 含义 | 说明 |
|---|---|---|
| 9070001 | platform unsupported | 当前平台暂不支持 |
| 9070002 | native context unavailable | 原生上下文不可用 |
| 9070003 | invalid source or output path | 视频地址为空、格式不合法、输出路径封装格式不支持,或缓存清理传入未知 type |
| 9070004 | video path inaccessible | 视频路径无法读取 |
| 9070005 | ffmpeg binary unavailable | 未内置 FFmpeg 二进制 |
| 9070006 | ffprobe binary unavailable | 未内置 FFprobe 二进制 |
| 9070007 | unsupported codec or format | 编码或封装格式不支持 |
| 9070008 | video crop failed | 视频裁剪失败 |
| 9070009 | video compress failed | 视频压缩失败 |
| 9070010 | frame extraction failed | 视频取帧失败 |
| 9070011 | operation timeout | 操作超时 |
| 9070012 | task cancelled | 任务已取消 |
| 9070013 | cache operation failed | 缓存操作失败 |
| 9070014 | native crop UI unavailable | 原生裁剪 UI 不可用 |
自定义基座说明
当前版本新增了 utssdk/app-android/index.uts、utssdk/app-ios/index.uts、utssdk/app-harmony/index.uts 和 Android AndroidManifest.xml。Android 视频信息读取、真实 FFprobe、取帧、原生裁剪 UI、无 UI 裁剪 showUi:false、FFmpeg 画面区域裁剪、compressVideo codec=copy 兼容输出、content:// 输入/输出回写、MediaStore 写入公共目录、FFmpeg 二进制真实压缩、H264/H265 硬编码压缩预检、完整 FFmpeg 命令、真实 FFprobe 原生命令、任务取消和分类型缓存清理属于平台 UTS 原生逻辑,真机要使用该闭环需要重新运行 Android 原生联编或重新打 Android 自定义基座;后续只要接入新的 FFmpeg AAR/so、iOS xcframework、Harmony 原生库或继续修改平台 UTS 原生逻辑,也都必须重新打 Android/iOS/Harmony 自定义基座;仅更新 wgt/appResource 不能替换旧基座中的原生能力。
Android 自定义基座安装到真机后,可以在项目根目录执行下面的脚本做一键回归。脚本不会执行 HBuilderX launch,只会通过 ADB 打开示例页并读取 logcat 标记,当前覆盖能力矩阵、视频信息、取帧、真实 FFprobe、真实 FFmpeg copy/trim 与进度回调、路径空格 FFmpeg 输出与 FFprobe 输入、直接 executeFfmpeg H264 转码命令与 FFprobe 反查、真实 FFmpeg 取消请求、9070012 取消回调、取消后同一 taskId 清理验证、真实 FFmpeg 单帧、真实 FFmpeg 序列帧、原生裁剪 UI 打开取消与自动确认输出、无 UI 裁剪 showUi:false、compress copy 全量/时间段、真实 H264 压缩、H264 输出 FFprobe 反查、H265 可用时真实压缩并反查 hevc 输出或不可用时明确 marker、AAC 音频转码并反查 aac 输出、输出路径父目录创建、同名覆盖、不支持扩展名 fail/complete 回调、公共目录 MediaStore 输出及 content://media Uri 证据、该 content://media 产物的 getVideoMetadata 反查、FFmpeg 失败 fail 回调、缓存清理和每个清理结果的 deleted=/bytes= 统计、非法缓存类型 9070003 的 fail/complete 边界:
发布前推荐优先执行最终编排脚本。它会先运行本地发布守卫、生成 Kotlin P0/P1 门禁和源码私有原生文件门禁,再按顺序运行已安装自定义基座原生文件检查、普通 smoke、stress、USB evidence 和 release readiness;总闸通过后才输出 PASS Android video editor final acceptance orchestration。如果设备未授权或某个步骤失败,脚本也会写入 final-acceptance-summary.json,用 status / completedSteps / failedStep / failureLogPath 标明已完成的前置门禁和阻塞步骤:
powershell -ExecutionPolicy Bypass -File scripts/run-lizhao-video-editor-android-final-acceptance.ps1 -DeviceId 9fc5a9b8
powershell -ExecutionPolicy Bypass -File scripts/acceptance-lizhao-video-editor-android.ps1
需要额外验证大文件稳定性时,再执行压力脚本。它会先抽查已安装 Android 自定义基座的 base.apk 是否包含 lib/arm64-v8a/liblizhao_video_editor_ffmpeg.so 和 liblizhao_video_editor_ffprobe.so,并确认 manifest 元数据仍在插件私有 assets 路径。如果任一私有原生文件缺失,会直接提示重新打 Android 自定义基座,因为 wgt/appResource 不能补进这些原生文件。预检通过后,脚本会通过 autoVideoEditorStress=1 单独进入长视频、4K、大码率和音视频同步场景;其中长视频 copy 成功后必须输出 AUTO_VIDEO_EDITOR_STRESS_LONG_PROBE_OK,4K、高码率和音视频同步场景会输出 AUTO_VIDEO_EDITOR_STRESS_4K_PROBE_CHECK_OK、AUTO_VIDEO_EDITOR_STRESS_HIGH_BITRATE_PROBE_CHECK_OK、AUTO_VIDEO_EDITOR_STRESS_AV_SYNC_PROBE_CHECK_OK,用于确认成功产物已通过 FFprobe 反查或不支持路径已进入 fail 回调。该脚本独立于普通 smoke,避免拖慢日常回归:
powershell -ExecutionPolicy Bypass -File scripts/acceptance-lizhao-video-editor-android-stress.ps1
如果只想先确认插件源码、新基座 APK 或当前已安装包是否带上 FFmpeg/FFprobe 私有原生文件,可以单独运行基座检查脚本。它不会打开页面,只检查两个 lib/arm64-v8a/liblizhao_video_editor_*.so、assets manifest 的 16KB / LGPL / no GPL/nonfree 标记、源码 manifest 中的 SHA256,以及是否出现通用 FFmpeg 原生库名或共享包名:
powershell -ExecutionPolicy Bypass -File scripts/check-lizhao-video-editor-android-base-assets.ps1 -ResourceRoot E:\test\lizhao-plugin\unpackage\resources
powershell -ExecutionPolicy Bypass -File scripts/check-lizhao-video-editor-android-base-assets.ps1 -ApkPath <新基座.apk>
powershell -ExecutionPolicy Bypass -File scripts/check-lizhao-video-editor-android-base-assets.ps1 -DeviceId 9fc5a9b8
注意事项
- 当前首版已内置 Android arm64-v8a FFmpeg/FFprobe 二进制并通过 16KB
0x4000对齐校验,支持 Android 原生裁剪 UI、无 UI 裁剪、视频信息读取、真实 FFprobe、取帧、content://输入/输出回写、MediaStore 写入公共目录、画面区域裁剪、compressVideo codec=copy 全量/时间段兼容输出、FFmpeg 真实压缩、H264/H265 硬编码压缩预检、完整 FFmpeg 命令、真实 FFprobe 原生命令、任务取消和分类型缓存清理闭环;其它 ABI、iOS xcframework 和 Harmony 原生库仍待后续接入。 - Android 默认包只允许两个插件私有
.so执行文件;不要把第三方 FFmpeg AAR、通用libffmpeg.so、libav*、x264/x265或共享包名直接放进默认包。基座检查脚本会扫描最终 APK,并在缺少私有文件或发现冲突型 FFmpeg/AAR/JAR/SO 时失败。需要接入其它 ABI、GPL 编解码、厂商硬编 SDK 或额外.so扩展时,应使用独立扩展包名和 16KB page-size 兼容构建,并重新打 Android 自定义基座。 - 所有暂不可用能力都会触发
fail和complete,不会伪造成功。 - 客户侧应先调用
getVideoEditorCapabilities()判断当前基座是否包含原生能力。
作者系列UTS插件
以下为已在 DCloud 插件市场上架的作者系列 UTS 插件,可按业务场景组合使用。未列出的插件表示当前未确认公开市场页,后续上架后再补充。
| 插件 | 能力方向 | 插件市场 |
|---|---|---|
lizhao-nfc-pro |
NFC 标签读写、NDEF、IsoDep 与诊断 | 查看插件 |
lizhao-float-window |
悬浮窗、画中画、权限与诊断 | 查看插件 |
lizhao-device-id |
设备标识、隐私策略与诊断 | 查看插件 |
lizhao-scan-pro |
原生扫码、连续扫码、相册识别 | 查看插件 |
lizhao-choose-file |
原生文件选择、上传、进度与取消 | 查看插件 |
lizhao-bg-audio |
背景音频播放、队列、倍速与事件 | 查看插件 |
lizhao-smart-tts |
系统 TTS、云端合成、听书方案 | 查看插件 |
lizhao-share-plus |
系统分享、远程文件下载后分享 | 查看插件 |
lizhao-sqlite-pro |
原生 SQLite、迁移、备份与诊断 | 查看插件 |
lizhao-icon-pro |
SVG 图标组件、多主题与缓存 | 查看插件 |
lizhao-cast-screen |
DLNA 投屏、AirPlay 路由入口 | 查看插件 |
lizhao-call-kit |
电话、短信、通讯录原生能力 | 查看插件 |
lizhao-app-keepalive |
应用保活、唤醒、自愈与报告 | 查看插件 |
lizhao-doc-corrector |
文档扫描、矫正、增强与识别 | 查看插件 |
lizhao-emu-detect |
模拟器环境检测、风险评分与证据 | 查看插件 |
lizhao-gallery-pro |
相册媒体分页、筛选、缩略图与导出 | 查看插件 |
lizhao-video-thumb |
视频封面、批量取帧与 Base64 返回 | 查看插件 |
lizhao-ble |
BLE 扫描、连接、读写、通知与自动重连 | 查看插件 |
lizhao-sse-pro |
SSE、Line、JSONL 与 Raw 流式请求 | 查看插件 |

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 6485
赞赏 5
下载 12487011
赞赏 1938
赞赏
京公网安备:11010802035340号