FFmpeg编译4

CPU=x86-64
TOOLCHAIN= N D K / t o o l c h a i n s / x 8 6 6 4 − 4.9 / p r e b u i l t / l i n u x − x 8 6 6 4 S Y S R O O T = NDK/toolchains/x86_64-4.9/prebuilt/linux-x86_64 SYSROOT= NDK/toolchains/x86644.9/prebuilt/linuxx8664SYSROOT=NDK/platforms/android-21/arch- A R C H / C R O S S P R E F I X = ARCH/ CROSS_PREFIX= ARCH/CROSSPREFIX=TOOLCHAIN/bin/x86_64-linux-android-
PREFIX= ( p w d ) / a n d r o i d / (pwd)/android/ (pwd)/android/CPU
OPTIMIZE_CFLAGS=“-march=$CPU -msse4.2 -mpopcnt -m64 -mtune=intel”
build_android

注意:当执行./build_android.sh的时候,出现权限不足,那么一定要给这个文件添加可执行权限

chmod 777 build_android.sh

这样就可以进行编译生成Android下的ffmpeg

如果在编译的时候出现如下问题:

ffbuild/common.mak:60: recipe for target ‘libavformat/udp.o’ failed
make: *** [libavformat/udp.o] Error 1

libavformat/udp.c 第290~295行进行注释

// mreqs.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
// if (local_addr)
// mreqs.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr;
// else
// mreqs.imr_interface.s_addr= INADDR_ANY;
// mreqs.imr_sourceaddr.s_addr = ((struct sockaddr_in *)&sources[i])->sin_addr.s_addr;

这样之后,基本就是ok的,在我们ffmpeg的文件夹下,会生成一个ffmpeg/android/armv7-a的文件目录,里面内容如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将编译后的ffmpeg移植到Android

准备

  • 在任何地方新建一个jni的文件夹。
  • 将我们刚刚编译的ffmpeg/android/armv7-a/include下的所有文件拷贝进入jni文件夹。
  • jni下新建一个prebuilt的文件夹,将ffmpeg/android/armv7-a/lib下的so文件全部拷贝到prebuilt之下。
  • 然后将ffmpeg/fftools文件下的如下文件拷贝进入jni
  • cmdutils.c
  • cmdutils.h
  • config.h
  • ffmpeg_filter.c
  • ffmpeg_hw.c
  • ffmpeg_opt.c
  • ffmpeg.c
  • ffmpeg.h

修改ffmpeg文件

  • 修改刚刚拷贝的ffmpeg.c文件,找到int main(int argc, char **argv)函数,将其替换为int run(int argc, char **argv)
  • 在修改后的run(int argc, char **argv) 末尾(retrun 之前)加上如上如下代码:

nb_filtergraphs = 0;
progress_avio = NULL;

input_streams = NULL;
nb_input_streams = 0;
input_files = NULL;
nb_input_files = 0;

output_streams = NULL;
nb_output_stream​
s = 0;
output_files = NULL;
nb_output_files = 0;

  • 并在ffmpeg.h文件末尾加上

int run(int argc, char **argv);

  • 再次打开ffmpeg.c文件,注释掉run(int argc, char **argv)下的所有exit_program函数,大致代码如下:

int run(int argc, char **argv)
{
int i, ret;
BenchmarkTimeStamps ti;

init_dynload();

register_exit(ffmpeg_cleanup);

setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */

av_log_set_flags(AV_LOG_SKIP_REPEATED);
parse_loglevel(argc, argv, options);

if(argc>1 && !strcmp(argv[1], “-d”)){
run_as_daemon=1;
av_log_set_callback(log_callback_null);
argc–;
argv++;
}

#if CONFIG_AVDEVICE
avdevice_register_all();
#endif
avformat_network_init();

show_banner(argc, argv, options);

/* parse options and open all input/output files */
ret = ffmpeg_parse_options(argc, argv);
if (ret < 0);
// exit_program(1);

if (nb_output_files <= 0 && nb_input_files == 0) {
show_usage();
av_log(NULL, AV_LOG_WARNING, “Use -h to get full help or, even better, run ‘man %s’\n”, program_name);
// exit_program(1);
}

/* file converter / grab */
if (nb_output_files <= 0) {
av_log(NULL, AV_LOG_FATAL, “At least one output file must be specified\n”);
// exit_program(1);
}

// if (nb_input_files == 0) {
// av_log(NULL, AV_LOG_FATAL, “At least one input file must be specified\n”);
// exit_program(1);
// }

for (i = 0; i < nb_output_files; i++) {
if (strcmp(output_files[i]->ctx->oformat->name, “rtp”))
want_sdp = 0;
}

current_time = ti = get_benchmark_time_stamps();
if (transcode() < 0);
// exit_program(1);
if (do_benchmark) {
int64_t utime, stime, rtime;
current_time = get_benchmark_time_stamps();
utime = current_time.user_usec - ti.user_usec;
stime = current_time.sys_usec - ti.sys_usec;
rtime = current_time.real_usec - ti.real_usec;
av_log(NULL, AV_LOG_INFO,
“bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n”,
utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);
}
av_log(NULL, AV_LOG_DEBUG, “%“PRIu64” frames successfully decoded, %“PRIu64” decoding errors\n”,
decode_error_stat[0], decode_error_stat[1]);
if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1]);
// exit_program(69);

// exit_program(received_nb_signals ? 255 : main_return_code);

nb_filtergraphs = 0;
progress_avio = NULL;

input_streams = NULL;
nb_input_streams = 0;
input_files = NULL;
nb_input_files = 0;

output_streams = NULL;
nb_output_streams = 0;
output_files = NULL;
nb_output_files = 0;

return main_return_code;
}

新建ffmpeg-invoke

jni文件下新建一个ffmpeg-invoke.cpp的c++文件,将如下代码写入

#include <jni.h>
#include <string.h>
#include “android/log.h”

#define LOGD(…) __android_log_print(ANDROID_LOG_DEBUG, “ffmpeg-invoke”, VA_ARGS)

extern “C”{
#include “ffmpeg.h”
#include “libavcodec/jni.h”
}

extern “C”
JNIEXPORT jint JNICALL
Java_com_coder_ffmpeg_jni_FFmpegCmd_run(JNIEnv *env, jclass type, jint cmdLen,
jobjectArray cmd) {
//set java vm
JavaVM *jvm = NULL;
env->GetJavaVM(&jvm);
av_jni_set_java_vm(jvm, NULL);

char *argCmd[cmdLen] ;
jstring buf[cmdLen];

for (int i = 0; i < cmdLen; ++i) {
buf[i] = static_cast(env->GetObjectArrayElement(cmd, i));
char *string = const_cast<char *>(env->GetStringUTFChars(buf[i], JNI_FALSE));
argCmd[i] = string;
LOGD(“argCmd=%s”,argCmd[i]);
}

int retCode = run(cmdLen, argCmd);
LOGD(“ffmpeg-invoke: retCode=%d”,retCode);

return retCode;

}

需注意的是 Java_com_coder_ffmpeg_jni_FFmpegCmd_runcom_coder_ffmpeg_jni表示FFmpegCmd所在你Android项目的位置。

新建Android.mk

jni文件夹下,新建Android.mk的文件,将如下代码拷贝,但是需要注意的是将 LOCAL_C_INCLUDES路径替换成你源码所在位置。

// 将此处的路径改为你ffmepg源码所在位置
LOCAL_C_INCLUDES := /home/anjoiner/Documents/AnJoiner/ffmpeg

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := libavdevice
LOCAL_SRC_FILES := prebuilt/libavdevice.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libavutil
LOCAL_SRC_FILES := prebuilt/libavutil.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libswresample
LOCAL_SRC_FILES := prebuilt/libswresample.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libswscale
LOCAL_SRC_FILES := prebuilt/libswscale.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libavcodec
LOCAL_SRC_FILES := prebuilt/libavcodec.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libavformat
LOCAL_SRC_FILES := prebuilt/libavformat.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libavfilter
LOCAL_SRC_FILES := prebuilt/libavfilter.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libpostproc
LOCAL_SRC_FILES := prebuilt/libpostproc.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg-invoke

LOCAL_SRC_FILES :=ffmpeg-invoke.cpp
cmdutils.c
ffmpeg_filter.c
ffmpeg_opt.c
ffmpeg_hw.c
ffmpeg.c

// 将此处的路径改为你ffmepg源码所在位置
LOCAL_C_INCLUDES := /home/anjoiner/Documents/AnJoiner/ffmpeg

LOCAL_LDLIBS := -llog -ljnigraphics -lz -landroid -lm -pthread -L$(SYSROOT)/usr/lib
LOCAL_SHARED_LIBRARIES := libavdevice libavcodec libavfilter libavformat libavutil libswresample libswscale libpostproc

include $(BUILD_SHARED_LIBRARY)

新建Application.mk

jni文件夹下,新建Application.mk并将如下代码拷贝进入

APP_ABI := armeabi-v7a
APP_PLATFORM := android-21
APP_OPTIM := release
APP_STL := stlport_static

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

到此基本上的配置已经完成,然后在jni文件下运行ndk-build

/home/anjoiner/Documents/AnJoiner/build/jni# /home/anjoiner/Documents/AnJoiner/ffmpeg/ndk/ndk-build

当出现如下代码就表示成功了

[armeabi-v7a] SharedLibrary : libffmpeg-invoke.so
[armeabi-v7a] Install : libffmpeg-invoke.so => libs/armeabi-v7a/libffmpeg-invoke.so
[armeabi-v7a] Install : libpostproc.so => libs/armeabi-v7a/libpostproc.so
[armeabi-v7a] Install : libswresample.so => libs/armeabi-v7a/libswresample.so
[armeabi-v7a] Install : libswscale.so => libs/armeabi-v7a/libswscale.so

测试

  • 新建一个支持C++项目,注意包名需是上述ava_com_coder_ffmpeg_jni_FFmpegCmd_run中的com.coder.ffmpeg
  • jni的同级目录下,会生成一个libs的目录,将这个目录下的armeabi-v7a文件拷贝到你所在的Android项目中的app/src/main/jniLibs
  • 新建一个jni的文件目录,在此目录下新建一个FFmpegCmd

/**

  • @author: AnJoiner
  • @datetime: 19-7-30
    */
    public class FFmpegCmd {
    static {
    System.loadLibrary(“avdevice”);
    System.loadLibrary(“avutil”);
    System.loadLibrary(“avcodec”);
    System.loadLibrary(“swresample”);
    System.loadLibrary(“avformat”);
    System.loadLibrary(“swscale”);
    System.loadLibrary(“avfilter”);
    System.loadLibrary(“postproc”);
    System.loadLibrary(“ffmpeg-invoke”);
    }

private static native int run(int cmdLen, String[] cmd);

public static int runCmd(String[] cmd){
return run(cmd.length,cmd);
}
}

拷贝进来run方法名会出现红色,不用管他,

  • 在我们的MainActivity中进行调用,此方法是将音频进行剪切

public class MainActivity extends AppCompatActivity {

// Used to load the ‘native-lib’ library on application startup.
static {
System.loadLibrary(“native-lib”);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
100);
}

// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
tv.setText(stringFromJNI());

findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ffmpegTest();
}
});
}

/**

  • A native method that is implemented by the ‘native-lib’ native library,
  • which is packaged with this application.
    */
    public native String stringFromJNI();

private void ffmpegTest() {
new Thread() {
@Override
public void run() {
long startTime = System.currentTimeMillis();
String input =
Environment.getExternalStorageDirectory().getPath() + File.separator +
“DCIM” + File.separator + “test.mp3”;
String output =
Environment.getExternalStorageDirectory().getPath() + File.separator +
“DCIM” + File.separator + “output.mp3”;

String cmd = “ffmpeg -y -i %s -vn -acodec copy -ss %s -t %s %s”;
String result = String.format(cmd, input, “00:00:30”, “00:00:40”, output);
FFmpegCmd.runCmd(result.split(" "));
Log.d(“FFmpegTest”, “run: 耗时:” + (System.currentTimeMillis() - startTime));
}
}.start();

}

如果上述步骤不出错,基本没什么问题,在资料的参考下,我也弄了好几天,但幸好结果还是好的~

使用 NDK-r20 编译FFmpeg

前面使用过老版本NDK-r14b编译FFmpeg,其实质是通过gcc去进行编译,但是最新的NDK版本中已经不使用gcc去编译,而是使用clang去进行编译.这里贴上最新配置文件代码

  • 下载最新版本NDK-r20
  • 下载FFmpeg-4.2.1

#!/bin/bash

清空上次的编译

make clean
#你自己的NDK路径.
export NDK=/home/anjoiner/Android/Sdk/ndk-bundle
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64/
API=29

function build_android
{
echo “Compiling FFmpeg for C P U " . / c o n f i g u r e − − p r e f i x = CPU" ./configure \ --prefix= CPU"./configure prefix=PREFIX
–enable-neon
–enable-hwaccels
–enable-gpl
–enable-postproc
–enable-shared
–enable-jni
–enable-mediacodec
–enable-decoder=h264_mediacodec
–disable-static
–disable-doc
–enable-ffmpeg
–disable-ffplay
–disable-ffprobe
–enable-avdevice
–disable-doc
–disable-symver
–cross-prefix= C R O S S P R E F I X − − t a r g e t − o s = a n d r o i d − − a r c h = CROSS_PREFIX \ --target-os=android \ --arch= CROSSPREFIX targetos=android arch=ARCH
–cpu= C P U − − c c = CPU \ --cc= CPU cc=CC
–cxx= C X X − − e n a b l e − c r o s s − c o m p i l e − − s y s r o o t = CXX --enable-cross-compile \ --sysroot= CXXenablecrosscompile sysroot=SYSROOT
–extra-cflags=”-Os -fpic O P T I M I Z E C F L A G S " − − e x t r a − l d f l a g s = " OPTIMIZE_CFLAGS" \ --extra-ldflags=" OPTIMIZECFLAGS" extraldflags="ADDI_LDFLAGS"
$ADDITIONAL_CONFIGURE_FLAG
make clean

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取
= C X X − − e n a b l e − c r o s s − c o m p i l e − − s y s r o o t = CXX --enable-cross-compile \ --sysroot= CXXenablecrosscompile sysroot=SYSROOT
–extra-cflags=“-Os -fpic O P T I M I Z E C F L A G S " − − e x t r a − l d f l a g s = " OPTIMIZE_CFLAGS" \ --extra-ldflags=" OPTIMIZECFLAGS" extraldflags="ADDI_LDFLAGS”
$ADDITIONAL_CONFIGURE_FLAG
make clean

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-qhQAkwk2-1719088014991)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

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

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

相关文章

Java | Leetcode Java题解之第174题地下城游戏

题目&#xff1a; 题解&#xff1a; class Solution {public int calculateMinimumHP(int[][] dungeon) {int n dungeon.length, m dungeon[0].length;int[][] dp new int[n 1][m 1];for (int i 0; i < n; i) {Arrays.fill(dp[i], Integer.MAX_VALUE);}dp[n][m - 1] …

QML 实现上浮后消失的提示框

基本效果&#xff1a;上浮逐渐显示&#xff0c;短暂停留后上浮逐渐消失 为了能同时显示多个提示框&#xff0c;一是需要动态创建每个弹框 Item&#xff0c;二是弹出位置问题&#xff0c;如果是底部为基准位置就把已经弹出的往上移动。 效果展示&#xff1a; 主要实现代码&…

46、基于自组织映射神经网络的鸢尾花聚类(matlab)

1、自组织映射神经网络的鸢尾花聚类的原理及流程 自组织映射神经网络&#xff08;Self-Organizing Map, SOM&#xff09;是一种用于聚类和数据可视化的人工神经网络模型。在鸢尾花聚类中&#xff0c;SOM 可以用来将鸢尾花数据集分成不同的类别&#xff0c;同时保留数据间的拓扑…

动态规划——买卖股票的最佳时机含冷冻期

1、题目链接 leetcode 309. 买卖股票的最佳时机含冷冻期 2、题目分析 该题有我们可以定义三种状态&#xff0c;买入状态&#xff0c;可交易状态 &#xff0c;冷冻期状态 我们可以建立一个n*3的二维数组来表示这三种状态&#xff1a; 根据这个图可以看出&#xff0c; 可以从…

不到3毛钱的SOT23和SOT89封装18V耐压低功耗高PSRR高精度LDO稳压芯片ME6231电流0.5A电压3.3V和1.8V

前言 SOT23-5封装ME6231外观和丝印 一款国产LDO&#xff0c;某些场合&#xff0c;要把1117扔了吧&#xff0c;SOT23封装&#xff0c;虽然不是最小&#xff0c;但也是够小的了。 参考价格&#xff1a;约0.25元 概述 ME6231 系列是以 CMOS 工艺制造的 18V 耐压、低功耗、高 PSR…

2024-06-23 操作系统实验5——模拟页式存储管理

文章目录 一、实验目的二、实验内容三、实验过程四、结果测试五、实验总结和说明 补录与分享本科实验&#xff0c;以示纪念。 一、实验目的 通过编写和调试请求页式存储管理的模拟程序以加深对请求页式存储管理方案的理解。 二、实验内容 页面淘汰算法可采用FIFO置换算法&a…

从理论到实践掌握UML

统一建模语言&#xff08;UML&#xff09;是软件工程师用来设计软件系统的一种工具&#xff0c;就像是一套图形化的说明书。它让开发团队能够以图形化的方式来理解、设计和开发软件系统&#xff0c;比起用文字来描述&#xff0c;更加直观易懂。本文通过UML实例化的理论和实践相…

ROS | 常见故障排查

1.开启后发出一个WIFI WIFI名字&#xff1a;WHEELTEC接数字 安全密钥&#xff1a;dongguan 2.显示屏接口 USB接口接键鼠 3.远程登录命令 ssh -Y wheeltec192.168.0.100 是小车发出的WIFI的一个IP地址 4. 登录后确保IP地址 ip a 看一下 当前ip地址 倒数第四行-当前ip地址 1…

django学习入门系列之第三点《CSS基础样式介绍3》

文章目录 浮动什么是浮动浮动的特性清除浮动 往期回顾 浮动 什么是浮动 float属性用于创建浮动框&#xff0c;将其移动到一边&#xff0c;直到左边缘或右边缘触及包含块或另一个浮动框的边缘。 浮动的特性 浮动元素会脱离标准流(脱标) 浮动的元素会一行内显示并且元素顶部对…

51单片机STC89C52RC——6.3 定时器/计数器 实现计时功能(定时器+中断系统+LCD1602液晶显示器)

目录 目的/效果 一&#xff0c;STC单片机模块 二&#xff0c;定时器 中断系统LCD1602显示 三&#xff0c;创建Keil项目 四&#xff0c;代码 五&#xff0c;代码编译、下载到51单片机 ​ 目的/效果 用定时器实现系统中断&#xff0c;计时信息显示在LCD1602上。效果如下 …

springAI(一)

目录 一、spring AI 目的 二、spring AI 来源 三、sprig AI 是什么&#xff1f; 四、spring AI中的 概念 4.1、模型&#xff08;Models&#xff09; 4.2、提示&#xff08;Prompts&#xff09; 4.3、提示模板&#xff08;Prompt Templates&#xff09; 4.4、令 牌&#…

Axios-入门

介绍 Axios对原生Ajax进行了封装&#xff0c;简化书写&#xff0c;快速开发 官网&#xff1a;Axios中文文档 | Axios中文网 (axios-http.cn) 入门 1引入Axios的js文件 <script src"js/axios.js"></script> 2使用Axios发送请求&#xff0c;并获取响应…

系统架构师考点--嵌入式技术

​大家好。今天来总结一下嵌入式技术的考点。该考点分值3-5分&#xff0c;上午场选择题和下午场案例题都可能会考&#xff0c;但不是每年都考。 一、嵌入式微处理体系结构 冯诺依曼结构&#xff1a;传统计算机采用冯诺依曼(Von Neumann)结构&#xff0c;也称普林斯顿结构是一…

【代码随想录】【算法训练营】【第45天】 [198]打家劫舍 [213]打家劫舍II [337]打家劫舍III

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 45&#xff0c;周五&#xff0c;坚持不了一点~ 题目详情 [198] 打家劫舍 题目描述 198 打家劫舍 解题思路 前提&#xff1a; 思路&#xff1a; 重点&#xff1a; 代码实现 C语言 虚拟头…

中国科学院西北生态环境资源研究院联合多单位在《PNAS》发文:气候变暖对多年冻土区地上与地下生物量分布的影响

文章简介 论文名称&#xff1a;Changes in above-versus belowground biomass distribution in permafrost regions in response to climate warming&#xff08;气候变暖对多年冻土区地上与地下生物量分布的影响&#xff09; 第一作者及单位&#xff1a;贠汉伯&#xff08;研…

SCI一区TOP|双曲正弦余弦优化算法(SCHO)原理及实现【免费获取Matlab代码】

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2023年&#xff0c;J Bai受到双曲正弦余弦函数启发&#xff0c;提出了双曲正弦余弦优化算法&#xff08;Sinh Cosh optimizer, SCHO&#xff09;。 2.算法原理 2.1算法思想 SCHO灵感来源…

1panel + Pbootcms 设置伪静态规则

这里确保我们引用的样式路径是否是这样的&#xff0c;&#xff08;不然可能会设置了伪静态无法加载样式&#xff09; //这种格式在不开起伪静态是可以引入的&#xff0c;一旦开启就不行了,一定要在static 前面加上反斜杠 /<link rel"stylesheet" href"{pbo…

【数据分享】《中国法律年鉴》1987-2022

而今天要免费分享的数据就是1987-2022年间出版的《中国法律年鉴》并以多格式提供免费下载。&#xff08;无需分享朋友圈即可获取&#xff09; 数据介绍 自1987年起&#xff0c;《中国法律年鉴》作为一部全面记录中国法律发展进程的重要文献&#xff0c;见证了中国法治建设的每…

Linux服务升级:Almalinux 升级 WebCatlog桌面程序

目录 一、实验 1.环境 2.Almalinux 升级 WebCatlog桌面程序 二、问题 1.Ubuntu如何升级 WebCatlog桌面程序 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统版本软件IP备注Almalinux9.4 WebCatlog 192.168.204.150 &#xff08;2&#xff09;Termi…

odoo17 小变更4

odoo17 小变更4 1、代码中去除了访问私人地址权限,但翻译中均还有,怪不 model:res.groups,name:base.group_private_addresses msgid "Access to Private Addresses" msgstr "" 代码也查看了,的确没有了此权限组 --><record model="res.g…