Android应用开发(37)LTPO帧率测试基于Surfaceview(暂存)

Android应用开发学习笔记——目录索引

 参考android官网:

  1. Frame rate  |  Android media  |  Android Developers
  2. 多重刷新率  |  Android 开源项目  |  Android Open Source Project
  3. WindowManager.LayoutParams  |  Android Developers

目前市面上旗舰手机基本都是普及了LTPO屏幕,为了验证LTPO屏幕的DDIC(display driver ID)的硬件刷帧行为(屏幕硬件的刷新可以通过屏幕的AVDD电流信号/屏幕硬件内部的Vsync信号检测),写一个可以指定app出图帧率的测试程序(基于Android应用开发(35)SufaceView基本用法 与 Android应用开发(36)帧率API测试基于Surfaceview)。

一、获取屏幕支持的所有帧率

应用程序获取设备实际支持的显示刷新率,可以通过调用 Display.getSupportedModes()获取,Mode.mRefreshRate就是帧率信息,以便安全调用setFrameRate()

// Display.java
Display.Mode[] mSupportedModes = getWindowManager().getDefaultDisplay().getSupportedModes();
for (Display.Mode mode : mSupportedModes) {Log.d(TAG, "getSupportedModes: " + mode.toString());Log.d(TAG, "getRefreshRate: " + mode.getRefreshRate());
}public static final class Mode implements Parcelable {public static final Mode[] EMPTY_ARRAY = new Mode[0];private final int mModeId;private final int mWidth;private final int mHeight;private final float mRefreshRate;@NonNullprivate final float[] mAlternativeRefreshRates;
...
}

二、APP设置帧率的API

setFrameRate( )

Android 公开了多种访问和控制界面的方法,因此有多个版本的setFrameRate()API。每个版本的 API 都采用相同的参数,并且与其他版本的工作方式相同:

  • Surface.setFrameRate()
  • SurfaceControl.Transaction.setFrameRate()
  • ANativeWindow_setFrameRate()
  • ASurfaceTransaction_setFrameRate()

要查看调用 是否会导致setFrameRate()显示刷新率发生更改,请通过调用 DisplayManager.registerDisplayListener() 或 来注册显示更改通知AChoreographer_registerRefreshRateCallback()。 

调用时setFrameRate(),最好传递精确的帧速率,而不是四舍五入为整数。例如,当渲染以 29.97Hz 录制的视频时,请传入 29.97,而不是四舍五入到 30。

对于视频应用程序,传递给的兼容性参数setFrameRate()应设置为Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,以向 Android 平台提供额外提示,即该应用程序将使用pulldown来适应不匹配的显示刷新率(这将导致抖动)。

surface.setFrameRate(contentFrameRate,

    FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,

    CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);

// 调用setFrameRate()时,最好传入准确的帧速率,而不是四舍五入为整数。例如,在渲染以 29.97Hz 录制的视频时,传入 29.97 而不是四舍五入为 30。

参数:Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE仅适用于视频应用程序。对于非视频用途,请使用FRAME_RATE_COMPATIBILITY_DEFAULT.

选择改变帧速率的策略:

google强烈建议应用在显示电影等长时间运行的视频时调用setFrameRate(fps , FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) ,其中 fps 是视频的帧速率。

当您预计视频播放持续几分钟或更短时间时,我们强烈建议您不要调用应用程序setFrameRate()。CHANGE_FRAME_RATE_ALWAYS

SurfaceControl.Transaction.setFrameRate()

参数和1是一样的

setFrameRate( ) 与 PreferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId 是应用程序向平台指示其帧速率的另一种方式。某些应用程序只想更改显示刷新率,而不是更改其他显示模式设置,例如显示分辨率。一般情况下,使用 setFrameRate()代替preferredDisplayModeId. 该setFrameRate() 功能更易于使用,因为应用程序不需要搜索显示模式列表来查找具有特定帧速率的模式。

setFrameRate()在存在多个以不同帧速率运行的表面的情况下,使平台有更多机会选择兼容的帧速率。例如,考虑这样一种场景:两个应用程序在 Pixel 4 上以分屏模式运行,其中一个应用程序正在播放 24Hz 视频,另一个应用程序向用户显示可滚动列表。设备支持两种显示刷新率:60Hz 和 90Hz。使用preferredDisplayModeIdAPI,视频表面被迫选择 60Hz 或 90Hz。通过使用 setFrameRate()24Hz 调用,视频表面为平台提供了有关源视频帧速率的更多信息,使平台能够选择 90Hz 的显示刷新率,在此场景中这比 60Hz 更好。

然而,有些场景preferredDisplayModeId应该使用 来代替setFrameRate(),例如:

  • 如果应用程序想要更改分辨率或其他显示模式设置,请使用preferredDisplayModeId
  • setFrameRate()如果模式切换是轻量级的并且不太可能被用户注意到,则平台只会响应调用来切换显示模式 。如果应用程序更喜欢切换显示刷新率,即使它需要大量模式切换(例如,在 Android TV 设备上),请使用preferredDisplayModeId.
  • 无法处理以应用程序帧速率倍数运行的显示的应用程序(这需要在每个帧上设置演示时间戳)应使用preferredDisplayModeId.

WindowManager.LayoutParams params = getWindow().getAttributes();

params.preferredDisplayModeId = mSupportedModes[position].getModeId();

Log.d(TAG, "setRefreshRate:" + mSupportedModes[position].getRefreshRate());

getWindow().setAttributes(params);

setFrameRate( ) 与 PreferredRefreshRate

WindowManager.LayoutParams#preferredRefreshRate 在应用程序窗口上设置首选帧速率,并且该速率适用于窗口内的所有表面。无论设备支持的刷新率如何,应用程序都应指定其首选帧速率,类似于 setFrameRate(),以便为调度程序更好地提示应用程序的预期帧速率。

preferredRefreshRate对于使用 的表面将被忽略setFrameRate()。如果可能的话一般使用setFrameRate()

PreferredRefreshRate 与 PreferredDisplayModeId

如果应用程序只想更改首选刷新率,则最好使用 preferredRefreshRate,而不是preferredDisplayModeId

避免过于频繁地调用setFrameRate( )

尽管该setFrameRate()调用在性能方面的成本并不高,但应用程序应避免setFrameRate()每帧调用或每秒调用多次。调用setFrameRate()可能会导致显示刷新率发生变化,从而可能导致转换期间出现帧丢失。您应该提前计算出正确的帧速率并调用 setFrameRate()一次。

用于游戏或其他非视频应用程序

尽管视频是该 API 的主要用例setFrameRate(),但它也可用于其他应用程序。例如,打算不高于 60Hz 运行的游戏(以减少功耗并实现更长的游戏时间)可以调用 Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT). 这样,默认情况下以 90Hz 运行的设备将在游戏处于活动状态时以 60Hz 运行,这将避免游戏以 60Hz 运行而显示器以 90Hz 运行时出现的抖动。

二、代码分析

1、surface.setFrameRate()

// Surface.java (frameworks\base\core\java\android\view)/*** Sets the intended frame rate for this surface.** <p>On devices that are capable of running the display at different refresh rates,* the system may choose a display refresh rate to better match this surface's frame* rate. Usage of this API won't introduce frame rate throttling, or affect other* aspects of the application's frame production pipeline. However, because the system* may change the display refresh rate, calls to this function may result in changes* to Choreographer callback timings, and changes to the time interval at which the* system releases buffers back to the application.</p>** <p>Note that this only has an effect for surfaces presented on the display. If this* surface is consumed by something other than the system compositor, e.g. a media* codec, this call has no effect.</p>** @param frameRate The intended frame rate of this surface, in frames per second. 0* is a special value that indicates the app will accept the system's choice for the* display frame rate, which is the default behavior if this function isn't* called. The <code>frameRate</code> parameter does <em>not</em> need to be a valid refresh* rate for this device's display - e.g., it's fine to pass 30fps to a device that can only run* the display at 60fps.** @param compatibility The frame rate compatibility of this surface. The* compatibility value may influence the system's choice of display frame rate.* This parameter is ignored when <code>frameRate</code> is 0.** @param changeFrameRateStrategy Whether display refresh rate transitions caused by this* surface should be seamless. A seamless transition is one that doesn't have any visual* interruptions, such as a black screen for a second or two. This parameter is ignored when* <code>frameRate</code> is 0.** @throws IllegalArgumentException If <code>frameRate</code>, <code>compatibility</code> or* <code>changeFrameRateStrategy</code> are invalid.*/public void setFrameRate(@FloatRange(from = 0.0) float frameRate,@FrameRateCompatibility int compatibility,@ChangeFrameRateStrategy int changeFrameRateStrategy) {synchronized (mLock) {checkNotReleasedLocked();int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility,changeFrameRateStrategy);if (error == -EINVAL) {throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");} else if (error != 0) {throw new RuntimeException("Failed to set frame rate on Surface");}}}/*** Sets the intended frame rate for this surface. Any switching of refresh rates is* most probably going to be seamless.** @see #setFrameRate(float, int, int)*/public void setFrameRate(@FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) {setFrameRate(frameRate, compatibility, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);}
// android_view_Surface.cpp (frameworks\base\core\jni)
static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate,jint compatibility, jint changeFrameRateStrategy) {Surface* surface = reinterpret_cast<Surface*>(nativeObject);ANativeWindow* anw = static_cast<ANativeWindow*>(surface);// Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and// NATIVE_WINDOW_SET_FRAME_RATE takes an// ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The values are identical// though, so no need to explicitly convert.return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, double(frameRate), compatibility,int(changeFrameRateStrategy));
}
// Surface.cpp (frameworks\native\libs\gui)
int Surface::perform(int operation, va_list args)
{case NATIVE_WINDOW_SET_FRAME_RATE:res = dispatchSetFrameRate(args);break;int Surface::dispatchSetFrameRate(va_list args) {float frameRate = static_cast<float>(va_arg(args, double));int8_t compatibility = static_cast<int8_t>(va_arg(args, int));int8_t changeFrameRateStrategy = static_cast<int8_t>(va_arg(args, int));return setFrameRate(frameRate, compatibility, changeFrameRateStrategy);
}status_t Surface::setFrameRate(float frameRate, int8_t compatibility,int8_t changeFrameRateStrategy) {ATRACE_CALL();ALOGV("Surface::setFrameRate");if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy,"Surface::setFrameRate")) {return BAD_VALUE;}return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility,changeFrameRateStrategy);
}
// ISurfaceComposer.cpp (frameworks\native\libs\gui)status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,int8_t compatibility, int8_t changeFrameRateStrategy) override {..status_t err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply);}
status_t BnSurfaceComposer::onTransact(
...setFrameRate(surface, frameRate, compatibility, changeFrameRateStrategy);// SurfaceFlinger.cpp (miui\frameworks\native\services\surfaceflinger)
status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,int8_t compatibility, int8_t changeFrameRateStrategy)layer->setFrameRate(Layer::FrameRate(Fps{frameRate}, Layer::FrameRate::convertCompatibility(compatibility), strategy))

1、surfaceflinger layerinfo保存app传递下来的结构体是FrameRatestruct FrameRate {using Seamlessness = scheduler::Seamlessness;Fps rate;FrameRateCompatibility type;Seamlessness seamlessness;
}enum class FrameRateCompatibility {Default, // 图层没有指定任何具体的处理策略Exact, // 图层需要准确的帧速率。如视频类ExactOrMultiple, // 图层需要精确的帧速率(或它的倍数)来呈现内容。 任何其他值都将导致下拉。NoVote, // 图层对刷新率没有任何要求,不考虑显示刷新率
};// The seamlessness requirement of a Layer.
enum class Seamlessness {// Indicates a requirement for a seamless mode switch.OnlySeamless,// Indicates that both seamless and seamed mode switches are allowed.SeamedAndSeamless,// Indicates no preference for seamlessness. For such layers the system will// prefer seamless switches, but also non-seamless switches to the group of the// default config are allowed.Default
};

2、SurfaceControl.Transaction.setFrameRate()

// SurfaceControl.java (frameworks\base\core\java\android\view)/*** Sets the intended frame rate for this surface. Any switching of refresh rates is* most probably going to be seamless.** @see #setFrameRate(SurfaceControl, float, int, int)*/@NonNullpublic Transaction setFrameRate(@NonNull SurfaceControl sc,@FloatRange(from = 0.0) float frameRate,@Surface.FrameRateCompatibility int compatibility) {return setFrameRate(sc, frameRate, compatibility,Surface.CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);}
// android_view_SurfaceControl.cpp (frameworks\base\core\jni)
static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,jfloat frameRate, jint compatibility, jint changeFrameRateStrategy) {auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);const auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);// Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and// Transaction::setFrameRate() takes an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The// values are identical though, so no need to convert anything.transaction->setFrameRate(ctrl, frameRate, static_cast<int8_t>(compatibility),static_cast<int8_t>(changeFrameRateStrategy));
}
// SurfaceComposerClient.cpp (frameworks\native\libs\gui)
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate(const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility,int8_t changeFrameRateStrategy) {layer_state_t* s = getLayerState(sc);if (!s) {mStatus = BAD_INDEX;return *this;}// Allow privileged values as well here, those will be ignored by SF if// the caller is not privilegedif (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy,"Transaction::setFrameRate",/*privileged=*/true)) {mStatus = BAD_VALUE;return *this;}s->what |= layer_state_t::eFrameRateChanged;s->frameRate = frameRate;s->frameRateCompatibility = compatibility;s->changeFrameRateStrategy = changeFrameRateStrategy;return *this;
}
// SurfaceFlinger.cpp (frameworks\native\services\surfaceflinger)
applyTransactionStatesetClientStateLockeduint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState,int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions,std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& outListenerCallbacks) {
...if (what & layer_state_t::eFrameRateChanged) {if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, s.changeFrameRateStrategy,"SurfaceFlinger::setClientStateLocked", privileged)) {const auto compatibility =Layer::FrameRate::convertCompatibility(s.frameRateCompatibility);const auto strategy =Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy);if (layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), compatibility, strategy))) {flags |= eTraversalNeeded;}}}

3、preferredDisplayModeId

// RefreshRatePolicy.java (mframeworks\base\services\core\java\com\android\server\wm)int getPreferredModeId(WindowState w) {// If app is animating, it's not able to control refresh rate because we want the animation// to run in default refresh rate.if (w.isAnimating(TRANSITION | PARENTS)) {return 0;}return w.mAttrs.preferredDisplayModeId;}
// DisplayContent.java (frameworks\base\services\core\java\com\android\server\wm)
会保存到   
private static final class ApplySurfaceChangesTransactionState 的preferredModeIdvoid applySurfaceChangesTransaction() {if (!mWmService.mDisplayFrozen) {mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,mLastHasContent,mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,mTmpApplySurfaceChangesTransactionState.preferredModeId,mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate,mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,true /* inTraversal, must call performTraversalInTrans... below */);}
// DisplayManagerService.java (frameworks\base\services\core\java\com\android\server\display)public void setDisplayProperties(int displayId, boolean hasContent,float requestedRefreshRate, int requestedMode, float requestedMinRefreshRate,float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,boolean inTraversal) {setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,requestedMode, requestedMinRefreshRate, requestedMaxRefreshRate,requestedMinimalPostProcessing, inTraversal);}
setDisplayPropertiesInternal
|--> mDisplayModeDirector.getAppRequestObserver().setAppRequest(displayId, requestedModeId, requestedMinRefreshRate, requestedMaxRefreshRate);// DisplayModeDirector.java (frameworks\base\services\core\java\com\android\server\display)public void setAppRequest(int displayId, int modeId, float requestedMinRefreshRateRange,float requestedMaxRefreshRateRange) {synchronized (mLock) {setAppRequestedModeLocked(displayId, modeId);setAppPreferredRefreshRateRangeLocked(displayId, requestedMinRefreshRateRange,requestedMaxRefreshRateRange);}}setAppRequest 最后通过:
updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE, vote);
还就是最后调用surfaceflinger的:
setDesiredDisplayModeSpecs // surface的标准API接口

三、写一个APP验证API

运行界面介绍

        

 

四、测试程序

完整源码

百度网盘链接:百度网盘 请输入提取码 提取码:test

RefreshRateSurfaceViewTest目录

点此查看Android应用开发学习笔记的完整目录

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[保研/考研机试] KY56 数制转换 北京大学复试上机题 C++实现

题目链接&#xff1a; 数制转换https://www.nowcoder.com/share/jump/437195121691734210665 描述 求任意两个不同进制非负整数的转换&#xff08;2进制&#xff5e;16进制&#xff09;&#xff0c;所给整数在long所能表达的范围之内。 不同进制的表示符号为&#xff08;0&a…

腾讯云COS的快速接入

背景 最近在研究一个剪贴板粘贴工具&#xff0c;实现粘贴图片&#xff0c;返回可访问的地址&#xff0c;这个在我的哔哩哔哩上有出一期视频&#x1f92d;。但是&#xff0c;我发现部分博客平台不能正常的转载我的图片链接&#xff0c;于是研究了一下腾讯云的COS&#xff08;阿…

Oracle 知识篇+会话级全局临时表在不同连接模式中的表现

标签&#xff1a;会话级临时表、全局临时表、幻读释义&#xff1a;Oracle 全局临时表又叫GTT ★ 结论 ✔ 专用服务器模式&#xff1a;不同应用会话只能访问自己的数据 ✔ 共享服务器模式&#xff1a;不同应用会话只能访问自己的数据 ✔ 数据库驻留连接池模式&#xff1a;不同应…

“冰箭卫士·IP发布会”首次亮相第14届海峡两岸(厦门)文博会

2023年8月6日,“冰箭卫士IP发布会”首次亮相海峡两岸文博会思明馆。此次发布会由厦门市文化创意产业协会、厦门理工&#xff08;集美区&#xff09;政产学研基地主办&#xff0c;厦门市文化创意产业协会IP设计研究院、厦门一笔之上文化发展有限公司、冰箭应急安全科技研究院承办…

(vue)获取对象的键遍历,同时循环el-tab页展示key及内容

(vue)获取对象的键遍历&#xff0c;同时循环el-tab页展示key及内容 效果&#xff1a; 数据结构&#xff1a; "statusData": {"订购广度": [ {"id": 11, "ztName": "广", …

[保研/考研机试] KY183 素数 北京航空航天大学复试上机题 C++实现

题目链接&#xff1a; 素数https://www.nowcoder.com/share/jump/437195121691718444910 描述 输入一个整数n(2<n<10000)&#xff0c;要求输出所有从1到这个整数之间(不包括1和这个整数)个位为1的素数&#xff0c;如果没有则输出-1。 输入描述&#xff1a; 输入有多…

PowerShell 使用SqlScriptDOM对T-SQL做规则校验

对于数据项目来说&#xff0c;编写Sql是一项基本任务同时也是数量最多的代码。为了统一项目代码规范同时降低Code Review的成本&#xff0c;因此需要通过自动化的方式来进行规则校验。由于本人所在的项目以SQL Server数据库为基础&#xff0c;于是本人决定通过使用SqlScriptDom…

2022年06月 C/C++(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;倒序输出 依次输入4个整数a、b、c、d,将他们倒序输出&#xff0c;即依次输出d、c、b、a这4个数。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 输入 一行4个整数a、b、c、d&#xff0c;以空格分隔。 0 < a,b,c,d < 108 输出 一行4个整数d、c、…

快速上手React:从概述到组件与事件处理

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

ElasticSearch学习

一&#xff0c;简介 ES&#xff08;elaticsearch简写&#xff09;&#xff0c; Elasticsearch是一个开源的高扩展的分布式全文检索引擎&#xff0c;它可以近乎实时的存储、检索数据&#xff1b;本身扩展性很好&#xff0c;可以扩展到上百台服务器&#xff0c;处理PB级别的数据…

使用 AndroidX 增强 WebView 的能力

在App开发过程中&#xff0c;为了在多个平台上保持一致的用户体验和提高开发效率&#xff0c;许多应用程序选择使用 H5 技术。在 Android 平台上&#xff0c;通常使用 WebView 组件来承载 H5 内容以供展示。 一.WebView 存在的问题 自 Android Lollipop 起&#xff0c;WebVie…

lab1 utilities

测试和运行 参考大佬 修改grade-lab-util文件中的python为python3xv6.out这个文件的所有者可能是root&#xff0c;需要修改为用户&#xff0c;sudo chown woaixiaoxiao xv6.out 每完成一个函数&#xff0c;执行下面的步骤在Makefile中加入新增的程序$U/_sleep\make qemu&…

linux 命令- systemctl

systemctl 参数说明 1、使用语法 用法&#xff1a;systemctl [OPTIONS…] {COMMAND} … 2 、参数说明 参数参数说明start立刻启动后面接的unitstop立刻关闭后面接的unitrestart立刻关闭后启动后面接的unit&#xff0c;亦即执行stop再start的意思reload不关闭后面接的unit的…

PyTorch深度学习环境安装(Anaconda、CUDA、cuDNN)及关联PyCharm

1. 关系讲解 Tytorch&#xff1a;Python机器学习库&#xff0c;基于Torch&#xff0c;用于自然语言处理等应用程序 Anaconda&#xff1a;是默认的python包和环境管理工具&#xff0c;安装了anaconda&#xff0c;就默认安装了conda CUDA&#xff1a;CUDA是一种由显卡厂商NVIDI…

取个对象值导致系统崩溃

取个对象值导致系统崩溃 前言 想必各位小伙经常在项目中遇到一些错误&#xff0c;取对象值的时候&#xff0c;经常报错,又或者某些项目突然就挂经常都是出现在一些对象取值上面&#xff0c;然后就被领导一顿训斥 报错分析 例如&#xff1a; 下面这个报错大家想必不会陌生&am…

后端开发8.品牌模块

概述 简介 效果图 数据库设计 DROP TABLE IF EXISTS `goods_brand`;CREATE TABLE `goods_brand` ( `goodsBrandId` int(11) NOT NULL AUTO_IN

浅谈机器人流程自动化(RPA)

1.什么是RPA RPA代表机器人流程自动化&#xff08;Robotic Process Automation&#xff09;&#xff0c;是一种利用软件机器人或机器人工作流程来执行重复性、规范性和高度可预测性的业务流程的技术。这些流程通常涉及许多繁琐的、重复的任务&#xff0c;例如数据输入、数据处…

系统架构设计专业技能 · 网络规划与设计(三)【系统架构设计师】

系列文章目录 系统架构设计专业技能 网络规划与设计&#xff08;三&#xff09;【系统架构设计师】 系统架构设计专业技能 系统安全分析与设计&#xff08;四&#xff09;【系统架构设计师】 系统架构设计高级技能 软件架构设计&#xff08;一&#xff09;【系统架构设计师…

0基础学习VR全景平台篇 第79篇:全景相机-泰科易如何直播推流

泰科易科技是中国的一家研发全景相机的高科技公司&#xff0c;前不久&#xff0c;在2020世界VR产业大会上发布了新一代5G VR直播影像采集终端--360starlight。以其出色的夜景成像效果和一“部”到位的直播方案重新定义了VR慢直播相机&#xff0c;对行业具有高度借鉴意义。 本文…

Uniapp使用腾讯地图并进行标点创建和设置保姆教程

使用Uniapp内置地图 首先我们需要创建一个uniapp项目 首先我们需要创建一个uniapp项目 我们在HBuilder左上角点击文件新建创建一个项目 然后下面这张图的话就是uniapp创建项目过程当中需要注意的一些点和具体的操作 然后我们创建完项目之后进入到项目pages文件夹下&#xff…