Android 从LibVLC-android到自编译ijkplayer播放H265 RTSP

概述

     ijkplayer: Android/iOS video player based on FFmpeg n3.4, with MediaCodec, VideoToolbox support.
官方的描述就这么简单的一句话,但丝毫都不影响它的强大。

从LibVLC 到 ijkplayer

截止到2023.7.20
LibVLC-Android 最大的问题在与OOM,测试了多个版本后最终选择放弃:
3.1.0/3.2.5/3.3.5/3.5.0/3.6.0/4.0.0-eap1到4.0.0-eap11, 内存随着播放次数增加而递增,到最终出现OOM
4.0.0-eap12: OOM 解决了,setVolume不工作了…

PS
4.0.0-eap12: OOM还和绑定的播放窗口有关, 传入SurfaceView/TextureView是内存泄露问题依然存在;
直到使用了org.videolan.libvlc.util.VLCVideoLayout才得以解决。
另外一个问题是,org.videolan.libvlc.util.VLCVideoLayout在画面切换、覆盖时会出现残留、画面比例失调等问题。

下载了源码编译
vlc-android

export ANDROID_NDK=/home/anson/Android/Sdk/ndk/android-ndk-r14b
export ANDROID_SDK=/home/anson/Android/Sdk
buildsystem/compile.sh -l -a arm 

生成AAR只需要加上 -r 参数即可

OOM问题依旧~ 跟4.0.0-eap12还是有区别


当然也考虑过其他的播放插件如
ExoPlayer, 没有H265,android exoplayer rtsp example
在这里插入图片描述
迁移到了 AndroidX Media3 1.1.0 release.

This is the last planned release of the com.google.android.exoplayer2 artifacts. 
This project is now deprecated. All users should migrate to androidx.media3 (which contains the same ExoPlayer code). 
See the migration guide for more details, including a script to help with the migration

SmarterStreaming ,

PS: 视沃科技-大牛直播移动端
之前没试过,然后下载下来试了下,DEMO APK都跑不了,呵呵,非免费
在这里插入图片描述

GSYVideoPlayer
Android–GSYVideoPlayer框架实现播放视频
怎么说好呢,这是个大合集,EXO, IJK…一样解决不了 RTSP + H265

rtsp-client-android
一些兼容性问题,不出图。

使用ijkplayer

ijkplayer接入方式说明

  1. 从gradle导入的ijkplayer 是不能播放RTSP的
implementation "tv.danmaku.ijk.media:ijkplayer-java:0.8.8"
implementation "tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8"
  1. ijkplayer已经停更好几年了,NDK还是用了 NDK10-NDK14
export ANDROID_NDK=/home/anson/Android/Sdk/ndk/android-ndk-r14b
export ANDROID_SDK=/home/anson/Android/Sdk

ARCH=armv7a

echo ">> INIT "
git checkout -B latest k0.8.8
./init-android.sh
./init-android-openssl.sh

cd android/contrib


echo ">> BUILD OPENSSL"
./compile-openssl.sh clean
./compile-openssl.sh ${ARCH}

echo ">> BUILD FFMPEG"
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh ${ARCH}

echo ">> BUILD IJKPLAYER"
cd ..
./compile-ijk.sh clean
./compile-ijk.sh ${ARCH}

源码的一些修改:

git diff config/module-lite.sh android/contrib/tools/do-compile-ffmpeg.sh
diff --git a/android/contrib/tools/do-compile-ffmpeg.sh b/android/contrib/tools/do-compile-ffmpeg.sh
index d6b3ba63..633b89f6 100755
--- a/android/contrib/tools/do-compile-ffmpeg.sh
+++ b/android/contrib/tools/do-compile-ffmpeg.sh
@@ -267,7 +267,7 @@ FF_CFG_FLAGS="$FF_CFG_FLAGS --prefix=$FF_PREFIX"
 # Advanced options (experts only):
 FF_CFG_FLAGS="$FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-"
 FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-cross-compile"
-FF_CFG_FLAGS="$FF_CFG_FLAGS --target-os=linux"
+FF_CFG_FLAGS="$FF_CFG_FLAGS --target-os=android"
 FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-pic"
 # FF_CFG_FLAGS="$FF_CFG_FLAGS --disable-symver"
 
@@ -292,6 +292,8 @@ case "$FF_BUILD_OPT" in
     ;;
 esac
 
+
+
 #--------------------
 echo ""
 echo "--------------------"
diff --git a/config/module-lite.sh b/config/module-lite.sh
index d5ba3d0f..64c4b05a 100755
--- a/config/module-lite.sh
+++ b/config/module-lite.sh
@@ -42,7 +42,10 @@ export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swscale"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-postproc"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avfilter"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avresample"
-# export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-pthreads"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-pthreads"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-mediacodec"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-jni"
+
 # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-w32threads"
 # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-os2threads"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-network"
@@ -146,7 +149,8 @@ export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmst"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtmp*"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmp"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmpt"
-export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtp"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"
+export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=sctp"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=srtp"
 export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=subfile"

编译完成后:

JAVA

android/ijkplayer/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/
├── AbstractMediaPlayer.java
├── AndroidMediaPlayer.java
├── annotations
│   ├── AccessedByNative.java
│   └── CalledByNative.java
├── exceptions
│   └── IjkMediaException.java
├── ffmpeg
│   └── FFmpegApi.java
├── IjkLibLoader.java
├── IjkMediaCodecInfo.java
├── IjkMediaMeta.java
├── IjkMediaPlayer.java
├── IjkTimedText.java
├── IMediaPlayer.java
├── ISurfaceTextureHolder.java
├── ISurfaceTextureHost.java
├── MediaInfo.java
├── MediaPlayerProxy.java
├── misc
│   ├── AndroidMediaFormat.java
│   ├── AndroidTrackInfo.java
│   ├── IAndroidIO.java
│   ├── IjkMediaFormat.java
│   ├── IjkTrackInfo.java
│   ├── IMediaDataSource.java
│   ├── IMediaFormat.java
│   └── ITrackInfo.java
├── pragma
│   ├── DebugLog.java
│   └── Pragma.java
└── TextureMediaPlayer.java

SO 库

android/ijkplayer/ijkplayer-armv7a/src/main/libs/armeabi-v7a/
├── libijkffmpeg.so
├── libijkplayer.so
└── libijksdl.so

这里偷个懒,使用so库即可,build.gradle:

implementation "tv.danmaku.ijk.media:ijkplayer-java:0.8.8"
//这个不要,直接使用编译出来的so库
//implementation "tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8"

一些问题

编译完成后,可以尝试在AndroidStudio中打开ijkplayer的示例项目。AndroidStudio和gradle已经物是人非,使用一些需要修改成一些兼容的版本等配置信息。

android/ijkplayer/build.gradle

--- a/android/ijkplayer/build.gradle
+++ b/android/ijkplayer/build.gradle
@@ -3,9 +3,11 @@
 buildscript {
     repositories {
         jcenter()
+        maven { url 'https://maven.google.com/'}
+        maven { url 'https://maven.aliyun.com/repository/jcenter' }
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.1.3'
+        classpath 'com.android.tools.build:gradle:4.0.1'
 
         classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
         classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
@@ -17,6 +19,8 @@ buildscript {
 allprojects {
     repositories {
         jcenter()
+        maven { url 'https://maven.google.com/'}
+        maven { url 'https://maven.aliyun.com/repository/jcenter' }
     }
 }

android/ijkplayer/gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
-#Wed Aug 24 16:26:25 CST 2016
+#Wed Jul 19 10:32:59 CST 2023
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip

android/ijkplayer/ijkplayer-example/build.gradle

--- a/android/ijkplayer/ijkplayer-example/build.gradle
+++ b/android/ijkplayer/ijkplayer-example/build.gradle
@@ -16,6 +16,12 @@ android {
         targetSdkVersion rootProject.ext.targetSdkVersion
         versionCode rootProject.ext.versionCode
         versionName rootProject.ext.versionName
+
+        externalNativeBuild{
+            ndk{
+                abiFilters  'armeabi-v7a'
+            }
+        }
     }
     buildTypes {
         release {
@@ -23,36 +29,35 @@ android {
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
         }
     }
-    productFlavors {
+    /*productFlavors {
         all32 { minSdkVersion 9 }
         all64 { minSdkVersion 21 }
         // armv5 {}
         // armv7a {}
         // arm64 { minSdkVersion 21 }
         // x86 {}
-    }
+    }*/
 }
 
 dependencies {
-    compile fileTree(include: ['*.jar'], dir: 'libs')
-    compile 'com.android.support:appcompat-v7:23.0.1'
-    compile 'com.android.support:preference-v7:23.0.1'
-    compile 'com.android.support:support-annotations:23.0.1'
-
+            }
+        }
     }
     buildTypes {
         release {
@@ -23,36 +29,35 @@ android {
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
         }
     }
-    productFlavors {
+    /*productFlavors {
         all32 { minSdkVersion 9 }
         all64 { minSdkVersion 21 }
         // armv5 {}
         // armv7a {}
         // arm64 { minSdkVersion 21 }
         // x86 {}
-    }
+    }*/
 }
 
 dependencies {
-    compile fileTree(include: ['*.jar'], dir: 'libs')
-    compile 'com.android.support:appcompat-v7:23.0.1'
-    compile 'com.android.support:preference-v7:23.0.1'
-    compile 'com.android.support:support-annotations:23.0.1'
-
-    compile 'com.squareup:otto:1.3.8'
+    implementation fileTree(include: ['*.jar'], dir: 'libs')
+    implementation 'com.android.support:appcompat-v7:23.0.1'
+    implementation 'com.android.support:preference-v7:23.0.1'
+    implementation 'com.android.support:support-annotations:23.0.1'
 
-    compile project(':ijkplayer-java')
-    compile project(':ijkplayer-exo')
+    implementation 'com.squareup:otto:1.3.8'
 
-    all32Compile project(':ijkplayer-armv5')
-    all32Compile project(':ijkplayer-armv7a')
-    all32Compile project(':ijkplayer-x86')
+    implementation project(':ijkplayer-java')
+    implementation project(':ijkplayer-exo')
 
-    all64Compile project(':ijkplayer-armv5')
-    all64Compile project(':ijkplayer-armv7a')
-    all64Compile project(':ijkplayer-arm64')
-    all64Compile project(':ijkplayer-x86')
-    all64Compile project(':ijkplayer-x86_64')
+    //all32Compile project(':ijkplayer-armv5')
+    implementation project(':ijkplayer-armv7a')
+    //all32Compile project(':ijkplayer-x86')
+    //all64Compile project(':ijkplayer-armv5')
+    //all64Implementation project(':ijkplayer-armv7a')
+    //all64Compile project(':ijkplayer-arm64')
+    //all64Compile project(':ijkplayer-x86')
+    //all64Compile project(':ijkplayer-x86_64')
 
     // compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
     // compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'

android/ijkplayer/settings.gradle

--- a/android/ijkplayer/settings.gradle
+++ b/android/ijkplayer/settings.gradle
@@ -1,7 +1,7 @@
-include ':ijkplayer-armv5', ':ijkplayer-x86_64'
+//include ':ijkplayer-armv5', ':ijkplayer-x86_64'
 include ':ijkplayer-armv7a'
-include ':ijkplayer-arm64'
-include ':ijkplayer-x86'
+//include ':ijkplayer-arm64'
+//include ':ijkplayer-x86'
 
 include ':ijkplayer-java'
 include ':ijkplayer-exo'
  • cvc-complex-type.2.4.a: Invalid content was found starting with element ‘base-extension’. One of ‘{layoutlib}’ is expected

  • 解决No version of NDK matched the requested version编译报错的问题
    设置NDK路径即可

  • 找不到库:

    defaultConfig {
        applicationId "tv.danmaku.ijk.media.example"
        minSdkVersion 9
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode rootProject.ext.versionCode
        versionName rootProject.ext.versionName

        externalNativeBuild{
            ndk{
                abiFilters  'armeabi-v7a'
            }
        }
    }
  • tv…ia.example W ‘circular_buffer_size’ option was set but it is not supported on this build (pthread support is required)
    FFmpeg在Window上出现’circular_buffer_size’问题解决方法
    最终加上了也没有解决,测试过程中也没有发现有什么问题,放过。

|–/home/anson/work/importProjs/ijkplayer/android/contrib/build/ffmpeg-armv7a/toolchain/bin//arm-linux-androideabi-gcc
ERROR: jni not found

播放 H265 RTSP

  • 如果播放不了,尝试检查下播放器的配置:
 ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-all-videos", 1);
 ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-hevc", 1);
 ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "rtsp_transport", "tcp");

总的来说,ijkplayer 的使用与系统的MediaPlayer很相近。一些优化和延迟可以参考文末的链接。

PS: 若需要频繁切换播放源,特别是一些在线视频,不要吝啬多创建几个ijkplayer的实例,实例的复用不见得可以省多少资源,反而会带来许多意料之外的问题。

参考

  • ijkplayer接入方式说明

  • ijkplayer基于rtsp直播延时的深度优化

  • 移动端开源播放器对比与选型(ExoPlayer/ijkplayer/VLC/GStreamer/SmarterPlayer)

  • How to fix build ffmpeg enable-jni error “jni not found”, support for hard decoding

  • ijkplayer开启rtsp与MJPEG的支持

  • ijkplayer框架的集成( 从开始到优化秒开)

  • ijkplayer播放器剖析(一)从应用层分析至Jni层的流程分析

  • IJKPlayer问题集锦之不定时更新

  • IJKPlayer相关指南

  • ijkplayer 编译与使用

  • IJKPlayer GitHub

  • ijkplayer工程编译FFMPEG+x264+H265解码器支持(iOS环境下)

  • Android 最新(2021-06-10)编译IJKPlayer支持rtsp,延时稳定500ms

  • android exoplayer rtsp example

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/60825.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring框架】Spring AOP

目录 什么是AOP?AOP组成Spring AOP 实现步骤Spring AOP实现原理JDK Proxy VS CGLIB 什么是AOP? AOP(Aspect Oriented Programming):⾯向切⾯编程,它是⼀种思想,它是对某⼀类事情的集中处理。⽐如…

打开的idea项目maven不生效

方法一:CtrlshiftA(或者help---->find action), 输入maven, 点击add maven projects,选择本项目中的pom.xml配置文件,等待加载........ 方法二:view->tools windows->mave…

SpringBoot 日志文件

一、日志的作用 日志是程序的重要组成部分,想象一下,如果程序报错了,不让你打开控制台看日志,那么你能找到报错的原因吗 答案是否定的,写程序不是买彩票,不能完全靠猜,因此日志对于我们来说&a…

K8s实战入门(三)

文章目录 3. 实战入门3.1 Namespace3.1.1 测试两个不同的名称空间之间的 Pod 是否连通性 3.2 Pod3.3 Label3.4 Deployment3.5 Service 3. 实战入门 本章节将介绍如何在kubernetes集群中部署一个nginx服务,并且能够对其进行访问。 3.1 Namespace Namespace是kuber…

echarts 图例组件legend配置

legend 图例组件展示不同系列的图表类型标记、颜色、和名称。可以通过点击来控制哪个系列不展示。对于饼图来说,控制哪个数据不展示。 $> echarts5.4.0简单画一个饼图作为示例,设置legend:{show:true}展示图例。 const options {legend: {show: true,},series…

Qt视频播放器

一、设置好ui界面二、打开文件槽函数1.QDir::homePath()作用介绍2.QFileDialog::getOpenFileName()介绍3.QFileInfo介绍4.player 指针解释5.打开文件槽函数完整代码 三、视频播放器初始化1.QMediaPlayer()函数2.设置时间间隔的作用3. QGraphicsScene介绍4.QGraphicsVideoItem介…

Python:Spider爬虫工程化入门到进阶(1)创建Scrapy爬虫项目

Python:Spider爬虫工程化入门到进阶系列: Python:Spider爬虫工程化入门到进阶(1)创建Scrapy爬虫项目Python:Spider爬虫工程化入门到进阶(2)使用Spider Admin Pro管理scrapy爬虫项目 本文通过简…

LeetCode--剑指Offer75(3)

目录 题目描述:剑指 Offer 20. 表示数值的字符串(中等)题目接口解题思路什么是有限状态自动机?如何使用? 代码 PS: 题目描述:剑指 Offer 20. 表示数值的字符串(中等) 请实现一个函数…

【LeetCode 75】第十九题(724)寻找数组的中心下标

目录 题目: 示例: ​分析: 代码运行结果: 题目: 示例: 分析: 给一个数组,让我们找出一个下标,在这个下标左边的元素总和等于这个下标右边的元素总和. 我们可以把整个数组的总和求出来,然后再从左往右遍历一次数组,遍历的同时将遍历过的数累加记录到一个变量中.若遍历到一…

CentOS安装podman-compose

1. 安装python3的依赖 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel 如果当前登录的是普通用户,需要在命令前加sudo,否则不用&…

外边距实现居中的写法

1、代码实例 2、默认是贴到左侧对齐的,但我们想要把他贴到中间对齐 3、居中的写法 4、这样就可以保证盒子居中了 5、以上写法仅适于行内元素和行内块元素的写法,有没有什么方法适用于行内块元素:可以添加text-align:center进行添加&#xff0…

【关于反馈电路的放电问题】2022-1-16

缘由关于反馈电路的放电问题 - 电源技术论坛 - 电子技术论坛 - 广受欢迎的专业电子论坛!图中的副绕组反馈给三极管基极,一般都是说通过三极管充电正反馈三极管导通,放电时负反馈三极管截止,负反馈时,电容C3是通过哪个回路放电的呢…

用msys2安装verilator并用spinal进行仿真

一 参考 SpinalHDL 开发环境搭建一步到位(图文版) - 极术社区 - 连接开发者与智能计算生态 (aijishu.com)https://aijishu.com/a/1060000000255643Setup and installation of Verilator — SpinalHDL documentation

将python源代码打包成.exe可执行文件

步骤 1、安装pyinstaller2、打开终端或命令提示符窗口并进入解释器的虚拟环境3、从解释器的虚拟环境进入包含要打包Python文件的目录4、通过以下命令打包5、打包后文件存放位置 1、安装pyinstaller pip install pyinstaller2、打开终端或命令提示符窗口并进入解释器的虚拟环境…

HTML中元素和标签有什么区别?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 标签(Tag)⭐元素(Element)⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&a…

Java:如何破坏类加载器的双亲委派机制?

本文重点 我们前面分析过loadClass方法,我们可以发现,这个方法的逻辑就是双亲委派机制,也就是说只要不破坏这个方法,那么就不会破坏双亲委派机制。如果要想破坏双亲委派机制,我们需要在类中重写loadClass方法,只要这样,那么就不会走双亲委派机制了。 破坏还是不破坏双…

一文详解:自动化测试工具——Selenium

前言 Selenium是一个用于Web应用程序测试的工具。是一个开源的Web的自动化测试工具,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动操作,不同是Selenium可以直接运行在浏览器上,…

合并两个有序链表(leetcode)

题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 输入:l1 [1,2,4], l2 [1,3,4] 输出:[1,1,2,3,4,4]思路 每次递归都会比较当前两个节点的值,选择较小的节点作为合并后的链…

搜索是什么

1、什么是搜索? 搜索:计算机根据用户输入的关键词进行匹配,从已有的数据库中摘录出相关的记录反馈给用户。 常见的全网搜索引擎,有百度、谷歌这样搜索网站。 除此,搜索技术在垂直领域也有广泛的使用,比如淘…

Kylin v10基于cephadm工具离线部署ceph分布式存储

1. 环境: ceph:octopus OS:Kylin-Server-V10_U1-Release-Build02-20210824-GFB-x86_64、CentOS Linux release 7.9.2009 2. ceph和cephadm 2.1 ceph简介 Ceph可用于向云平台提供对象存储、块设备服务和文件系统。所有Ceph存储集群部署都从…