flutter开发实战-ijkplayer视频播放器功能

news2024/11/26 14:52:05

flutter开发实战-ijkplayer视频播放器功能

使用better_player播放器进行播放视频时候,在Android上会出现解码失败的问题,better_player使用的是video_player,video_player很多视频无法解码。最终采用ijkplayer播放器插件,在flutter上使用fijkplayer插件。
在这里插入图片描述
在这里插入图片描述

一、引入fijkplayer

在使用fijkplayer前可以先看下https://fijkplayer.befovy.com/docs/zh/fijkplayer-api.html

在工程的pubspec.yaml中引入插件

  fijkplayer: ^0.11.0
    

fijkPlayer 就是对 native C 层 ijkplayer 的一个 dart 包装,接口都保持一致。 FijkPlayer 处理所有播放相关的工作,实际工作都是由 native C 层 ijkplayer 完成,包含检查 dataSource 中的媒体信息,打开解码器和解码线程、打开音频输出设备、将解码后数据输出给音频设备或显示设备。

二、使用fijkplayer

2.1、IJKVideoPlayerController控制常用操作

使用fijkplayer,这里创建了IJKVideoPlayer来嵌套一下FijkView,使用IJKVideoPlayerController来控制常用功能操作

IJKVideoPlayerController如下

import 'dart:async';

class IJKVideoPlayerController {
  FutureOr Function()? stop;
  FutureOr Function()? pause;
  FutureOr Function()? play;
  FutureOr Function(int msec)? seekTo;
  FutureOr Function(double volume)? setVolume;
  FutureOr Function(double speed)? setSpeed;
  FutureOr Function(int loopCount)? setLoop;
  FutureOr Function()? isPlaying;
}
    

IJKVideoPlayerController来控制停止、暂停、播放、seek、设置音量、设置播放速率、设置循环次数、获取是否在播放中等。

  • 播放视频
  void play() {
    if (videoPlayerController.play != null) {
      videoPlayerController.play!.call();
    }
  }
    
  • 暂停视频播放
  void pause() {
    if (videoPlayerController.pause != null) {
      videoPlayerController.pause!.call();
    }
  }
    
  • 停止视频播放
  void stop() {
    if (videoPlayerController.stop != null) {
      videoPlayerController.stop!.call();
    }
  }
    
  • seek指定位置
  void seekTo(int msec) {
    if (videoPlayerController.seekTo != null) {
      videoPlayerController.seekTo!.call(msec);
    }
  }
    
  • 设置音量
  void setVolume(double volume) {
    if (videoPlayerController.setVolume != null) {
      videoPlayerController.setVolume!.call(volume);
    }
  }
    
  • 设置播放速率
  void setSpeed(double speed) {
    if (videoPlayerController.setSpeed != null) {
      videoPlayerController.setSpeed!.call(speed);
    }
  }
    
  • 设置循环次数
  void setLoop(int loopCount) {
    if (videoPlayerController.setLoop != null) {
      videoPlayerController.setLoop!.call(loopCount);
    }
  }
    
  • 获取是否播放中
  Future<bool?> isPlaying() async {
    if (videoPlayerController.isPlaying != null) {
      bool videoIsPlaying = await videoPlayerController.isPlaying!.call();
      return videoIsPlaying;
    }
    return Future.value(null);
  }
    

2.2、在ijkplayer设置source,使用FijkPlayer

在设置播放器的时候,需要设置source类型。fijkplayer提供了两种方式,一种是本地工程文件、一种是网络视频地址。

  • 设置网络视频源
  /// usage
  /// autoPlay 为 true 时等同于连续调用 setDataSource、prepareAsync、start
  fplayer.setDataSource("http://samplevideo.com/sample.flv", autoPlay: true);
    
  • 设置本地资源作为播放源
  /// pubspec.yml 中需要指定assets 内容
  ///   assets:
  ///     - assets/butterfly.mp4
  ///
  /// scheme 是 `asset`, `://` 是 scheme 分隔符, `/` 是路径起始符号
  fplayer.setDataSource("asset:///assets/butterfly.mp4", autoPlay: true);
    

在setDataSource还有autoPlay(自动播放),showCover(是否显示视频封面,视频默认获取第一帧作为视频封面)

2.3、FijkView显示视频的控件Widget

在fijkplayer中,使用FijkView来显示视频。

  FijkView({
    required this.player,
    this.width,
    this.height,
    this.fit = FijkFit.contain,
    this.fsFit = FijkFit.contain,
    this.panelBuilder = defaultFijkPanelBuilder,
    this.color = const Color(0xFF607D8B),
    this.cover,
    this.fs = true,
    this.onDispose,
  });
    

可以设置显示fit、全屏的fit、背景颜色color、封面图(设置之后会显示在视频播放的上面)、是否全屏等。

在这里我们如果需要自定义样式,可以替换掉panelBuilder。

2.4、自定义控件IJKVideoPanel

在这里我们如果需要自定义样式,可以替换掉panelBuilder。我们自定义一个IJKVideoPanel,这个大部分代码来源default,这里调整了部分样式。

IJKVideoPanel完整代码如下

import 'dart:async';
import 'dart:math';

import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/material.dart';

class IJKVideoPanel extends StatefulWidget {
  const IJKVideoPanel({
    super.key,
    required this.player,
    required this.buildContext,
    required this.viewSize,
    required this.texturePos,
  });

  final FijkPlayer player;
  final BuildContext buildContext;
  final Size viewSize;
  final Rect texturePos;

  @override
  State<IJKVideoPanel> createState() => _IJKVideoPanelState();
}

class _IJKVideoPanelState extends State<IJKVideoPanel> {
  FijkPlayer get player => widget.player;

  Duration _duration = Duration();
  Duration _currentPos = Duration();
  Duration _bufferPos = Duration();

  bool _playing = false;
  bool _prepared = false;
  String? _exception;

  // bool _buffering = false;

  double _seekPos = -1.0;

  StreamSubscription? _currentPosSubs;

  StreamSubscription? _bufferPosSubs;

  //StreamSubscription _bufferingSubs;

  Timer? _hideTimer;
  bool _hideStuff = true;

  double _volume = 1.0;

  final barHeight = 40.0;

  @override
  void initState() {
    super.initState();

    _duration = player.value.duration;
    _currentPos = player.currentPos;
    _bufferPos = player.bufferPos;
    _prepared = player.state.index >= FijkState.prepared.index;
    _playing = player.state == FijkState.started;
    _exception = player.value.exception.message;
    // _buffering = player.isBuffering;

    player.addListener(_playerValueChanged);

    _currentPosSubs = player.onCurrentPosUpdate.listen((v) {
      setState(() {
        _currentPos = v;
      });
    });

    _bufferPosSubs = player.onBufferPosUpdate.listen((v) {
      setState(() {
        _bufferPos = v;
      });
    });
  }

  void _playerValueChanged() {
    FijkValue value = player.value;
    if (value.duration != _duration) {
      setState(() {
        _duration = value.duration;
      });
    }

    bool playing = (value.state == FijkState.started);
    bool prepared = value.prepared;
    String? exception = value.exception.message;
    if (playing != _playing ||
        prepared != _prepared ||
        exception != _exception) {
      setState(() {
        _playing = playing;
        _prepared = prepared;
        _exception = exception;
      });
    }
  }

  void _playOrPause() {
    if (_playing == true) {
      player.pause();
    } else {
      player.start();
    }
  }

  @override
  void dispose() {
    super.dispose();
    _hideTimer?.cancel();

    player.removeListener(_playerValueChanged);
    _currentPosSubs?.cancel();
    _bufferPosSubs?.cancel();
  }

  void _startHideTimer() {
    _hideTimer?.cancel();
    _hideTimer = Timer(const Duration(seconds: 3), () {
      setState(() {
        _hideStuff = true;
      });
    });
  }

  void _cancelAndRestartTimer() {
    if (_hideStuff == true) {
      _startHideTimer();
    }
    setState(() {
      _hideStuff = !_hideStuff;
    });
  }

  Widget _buildVolumeButton() {
    IconData iconData;
    if (_volume <= 0) {
      iconData = Icons.volume_off;
    } else {
      iconData = Icons.volume_up;
    }
    return IconButton(
      icon: Icon(iconData, color: Colors.white),
      padding: EdgeInsets.only(left: 10.0, right: 10.0),
      onPressed: () {
        setState(() {
          _volume = _volume > 0 ? 0.0 : 1.0;
          player.setVolume(_volume);
        });
      },
    );
  }

  AnimatedOpacity _buildBottomBar(BuildContext context) {
    double duration = _duration.inMilliseconds.toDouble();
    double currentValue =
        _seekPos > 0 ? _seekPos : _currentPos.inMilliseconds.toDouble();
    currentValue = min(currentValue, duration);
    currentValue = max(currentValue, 0);
    return AnimatedOpacity(
      opacity: _hideStuff ? 0.0 : 0.8,
      duration: Duration(milliseconds: 400),
      child: Container(
        height: barHeight,
        decoration: BoxDecoration(
          gradient: LinearGradient(
            colors: [Colors.transparent, Colors.black45],
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
          ),
        ),
        child: Row(
          children: <Widget>[
            _buildVolumeButton(),
            Padding(
              padding: EdgeInsets.only(right: 5.0, left: 5),
              child: Text(
                '${_duration2String(_currentPos)}',
                style: TextStyle(fontSize: 14.0, color: Colors.white),
              ),
            ),

            _duration.inMilliseconds == 0
                ? Expanded(child: Center())
                : Expanded(
                    child: Padding(
                      padding: EdgeInsets.only(right: 0, left: 0),
                      child: FijkSlider(
                        value: currentValue,
                        cacheValue: _bufferPos.inMilliseconds.toDouble(),
                        min: 0.0,
                        max: duration,
                        onChanged: (v) {
                          _startHideTimer();
                          setState(() {
                            _seekPos = v;
                          });
                        },
                        onChangeEnd: (v) {
                          setState(() {
                            player.seekTo(v.toInt());
                            print("seek to $v");
                            _currentPos =
                                Duration(milliseconds: _seekPos.toInt());
                            _seekPos = -1;
                          });
                        },
                      ),
                    ),
                  ),

            // duration / position
            _duration.inMilliseconds == 0
                ? Container(child: const Text("LIVE"))
                : Padding(
                    padding: EdgeInsets.only(right: 5.0, left: 5),
                    child: Text(
                      '${_duration2String(_duration)}',
                      style: TextStyle(fontSize: 14.0, color: Colors.white),
                    ),
                  ),

//             IconButton(
//               icon: Icon(widget.player.value.fullScreen
//                   ? Icons.fullscreen_exit
//                   : Icons.fullscreen),
//               padding: EdgeInsets.only(left: 10.0, right: 10.0),
// //              color: Colors.transparent,
//               onPressed: () {
//                 widget.player.value.fullScreen
//                     ? player.exitFullScreen()
//                     : player.enterFullScreen();
//               },
//             )
            //
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    // Rect rect = player.value.fullScreen
    //     ? Rect.fromLTWH(0, 0, widget.viewSize.width, widget.viewSize.height)
    //     : Rect.fromLTRB(
    //     max(0.0, widget.texturePos.left),
    //     max(0.0, widget.texturePos.top),
    //     min(widget.viewSize.width, widget.texturePos.right),
    //     min(widget.viewSize.height, widget.texturePos.bottom));
    Rect rect =
        Rect.fromLTWH(0, 0, widget.viewSize.width, widget.viewSize.height);

    return Positioned.fromRect(
      rect: rect,
      child: GestureDetector(
        onTap: _cancelAndRestartTimer,
        child: AbsorbPointer(
          absorbing: _hideStuff,
          child: Column(
            children: <Widget>[
              Container(height: barHeight),
              Expanded(
                child: GestureDetector(
                  onTap: () {
                    _cancelAndRestartTimer();
                  },
                  child: Container(
                    color: Colors.transparent,
                    height: double.infinity,
                    width: double.infinity,
                    child: Center(
                        child: _exception != null
                            ? Text(
                                _exception!,
                                style: TextStyle(
                                  color: Colors.white,
                                  fontSize: 25,
                                ),
                              )
                            : (_prepared ||
                                    player.state == FijkState.initialized)
                                ? AnimatedOpacity(
                                    opacity: _hideStuff ? 0.0 : 0.85,
                                    duration: Duration(milliseconds: 400),
                                    child: IconButton(
                                        iconSize: barHeight * 2,
                                        icon: Icon(
                                          _playing
                                              ? Icons.pause
                                              : Icons.play_arrow,
                                          color: Colors.white,
                                          size: 44,
                                        ),
                                        padding: EdgeInsets.only(
                                            left: 10.0, right: 10.0),
                                        onPressed: _playOrPause))
                                : SizedBox(
                                    width: barHeight * 1.5,
                                    height: barHeight * 1.5,
                                    child: CircularProgressIndicator(
                                        valueColor: AlwaysStoppedAnimation(
                                            Colors.white)),
                                  )),
                  ),
                ),
              ),
              _buildBottomBar(context),
            ],
          ),
        ),
      ),
    );
  }
}

String _duration2String(Duration duration) {
  if (duration.inMilliseconds < 0) return "-: negtive";

  String twoDigits(int n) {
    if (n >= 10) return "$n";
    return "0$n";
  }

  String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
  String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
  int inHours = duration.inHours;
  return inHours > 0
      ? "$inHours:$twoDigitMinutes:$twoDigitSeconds"
      : "$twoDigitMinutes:$twoDigitSeconds";
}

    

2.5、嵌套FijkView的IJKVideoPlayer

在使用时候,使用了IJKVideoPlayer来封装了一层FijkView。
在IJKVideoPlayer中设置了videoPlayerController控制播放的操作 如停止、暂停、播放、seek、设置音量、设置播放速率、设置循环次数、获取是否在播放中。

IJKVideoPlayer完整代码如下

  import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app_demolab/ijk_player/ijk_video_panel.dart';

import 'ijk_video_player_controller.dart';

/// usage
/// autoPlay 为 true 时等同于连续调用 setDataSource、prepareAsync、start
/// fplayer.setDataSource("http://samplevideo.com/sample.flv", autoPlay: true);
///
/// 设置本地资源作为播放源,
/// pubspec.yml 中需要指定assets 内容
///   assets:
///     - assets/butterfly.mp4
///
/// scheme 是 `asset`, `://` 是 scheme 分隔符, `/` 是路径起始符号
/// fplayer.setDataSource("asset:///assets/butterfly.mp4", autoPlay: true);

class IJKVideoPlayer extends StatefulWidget {
  const IJKVideoPlayer({
    super.key,
    required this.path,
    this.autoPlay = false,
    this.showCover = true,
    this.fit = FijkFit.contain,
    this.cover,
    this.color = Colors.black,
    this.width,
    this.height,
    this.videoPlayerController,
  });

  final double? width;
  final double? height;

  final String path;
  final bool autoPlay;
  final bool showCover;
  final FijkFit fit;
  final Widget? cover;
  final Color color;
  final IJKVideoPlayerController? videoPlayerController;

  @override
  State<IJKVideoPlayer> createState() => _IJKVideoPlayerState();
}

class _IJKVideoPlayerState extends State<IJKVideoPlayer> {
  final FijkPlayer player = FijkPlayer();

  @override
  void initState() {
    super.initState();
    player.setDataSource(
      widget.path,
      autoPlay: widget.autoPlay,
      showCover: widget.showCover,
    );
    addVideoPlayerFun();
  }

  void addVideoPlayerFun() {
    if (widget.videoPlayerController != null) {
      widget.videoPlayerController!.play = () {
        // 触发播放
        player.start();
      };

      widget.videoPlayerController!.stop = () {
        // 触发停止
        player.stop();
      };

      widget.videoPlayerController!.pause = () {
        // 触发暂停
        player.pause();
      };

      widget.videoPlayerController!.setLoop = (int loopCount) {
        // 触发setLoop
        if (loopCount < 0) {
          loopCount = 1;
        }
        player.setLoop(loopCount);
      };

      widget.videoPlayerController!.seekTo = (int msec) {
        // 触发seek
        if (msec < 0) {
          msec = 0;
        }
        player.seekTo(msec);
      };

      widget.videoPlayerController!.setVolume = (double volume) {
        // 触发setVolume
        if (volume < 0.0) {
          volume = 0.0;
        }

        player.setVolume(volume);
      };

      widget.videoPlayerController!.setSpeed = (double speed) {
        // 触发setSpeed
        if (speed < 0.0) {
          speed = 1.0;
        }

        player.setSpeed(speed);
      };

      widget.videoPlayerController!.isPlaying = () {
        // 触发setVolume
        if (FijkState.started == player.state) {
          return true;
        } else {
          return false;
        }
      };
    }
  }

  @override
  void dispose() {
    super.dispose();
    player.release();
  }

  void onIJKDispose(FijkData fijkData) {}

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      child: Stack(
        alignment: Alignment.center,
        children: [
          widget.cover != null ? widget.cover! : Container(),
          FijkView(
            width: widget.width,
            height: widget.height,
            player: player,
            fit: widget.fit,
            fsFit: widget.fit,
            color: widget.color,
            onDispose: onIJKDispose,
            panelBuilder: (FijkPlayer player, FijkData data,
                BuildContext context, Size viewSize, Rect texturePos) {
              return IJKVideoPanel(
                player: player,
                buildContext: context,
                viewSize: viewSize,
                texturePos: texturePos,
              );
            },
          ),
        ],
      ),
    );
  }
}

    

三、最后使用IJKVideoPlayer的IJKVideoPage页面

这里我创建了一个IJKVideoPage来使用IJKVideoPlayer视频播放,IJKVideoPlayer中需要path与videoPlayerController

IJKVideoPage完整代码如下

  import 'dart:async';

import 'package:flutter/material.dart';

import 'ijk_player/ijk_video_player.dart';
import 'ijk_player/ijk_video_player_controller.dart';

class IJKVideoPage extends StatefulWidget {
  const IJKVideoPage({
    super.key,
    required this.url,
  });

  final String url;

  @override
  State<IJKVideoPage> createState() => _IJKVideoPageState();
}

class _IJKVideoPageState extends State<IJKVideoPage> {
  final IJKVideoPlayerController videoPlayerController =
      IJKVideoPlayerController();

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Scaffold(
      appBar: AppBar(title: Text("Fijkplayer Example")),
      body: Center(
        child: Container(
          width: size.width,
          height: size.width * 9.0 / 16.0,
          alignment: Alignment.center,
          child: IJKVideoPlayer(
            path: widget.url,
            videoPlayerController: videoPlayerController,
            color: Colors.black,
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
  }
}

    

如果外面的页面跳转到播放页面,需要设置url

  void testIJKVideoPage(BuildContext context) {
    Navigator.of(context)
        .push(MaterialPageRoute(builder: (BuildContext context) {
      return IJKVideoPage(
          url: "https://vd2.bdstatic.com/mda-maif0tt1rirqp27q/540p/h264_cae/1611052585/mda-maif0tt1rirqp27q.mp4");
    }));
  }
    

https://brucegwo.blog.csdn.net/article/details/136024588

四、小结

flutter开发实战-ijkplayer视频播放器功能

学习记录,每天不停进步。

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

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

相关文章

C# OMRON PLC FINS TCP协议简单测试

FINS(factory interface network service)通信协议是欧姆龙公司开发的用于工业自动化控制网络的指令&#xff0f;响应系统。运用 FINS指令可实现各种网络间的无缝通信&#xff0c;包括用于信息网络的 Etherne(以太网)&#xff0c;用于控制网络的Controller Link和SYSMAC LINK。…

前端框架学习 Vue(3)vue生命周期,钩子函数,工程化开发脚手架CLI,组件化开发,组件分类

Vue 生命周期 和生命周期的四个阶段 Vue生命周期:一个Vue实例从创建 到 销毁 的整个过程 生命周期四个阶段 :(1)创建 (2)挂载 (3)更新 (4)销毁 Vue生命周期函数(钩子函数) Vue生命周期过程中,会自动运行一些函数,被称为[生命周期钩子] ->让开发者可以在[特定阶段] 运行自…

[MFC] MFC消息机制的补充

之前写了[MFC] 消息映射机制的使用和原理浅析&#xff0c;还有些需要补充的&#xff0c;都记在这里。 MFC 消息的分类 MFC消息分为系统消息和自定义消息。 图片来源&#xff1a;C语言/C教程 大型源码案例分析&#xff1a;MFC消息系统的代码解析 易道云编程 系统消息分为窗口…

【SpringBoot】SpringBoot的web开发

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;SpringBoot ⛺️稳重求进&#xff0c;晒太阳 Wbe开发 使用Springboot 1&#xff09;、创建SpringBoot应用&#xff0c;选中我们需要的模块&#xff1b; 2&#xff09;、SpringBoot已经默…

用友GRP-U8 listSelectDialogServlet SQL注入漏洞复现

0x01 产品简介 用友GRP-U8R10行政事业内控管理软件是用友公司专注于国家电子政务事业,基于云计算技术所推出的新一代产品,是我国行政事业财务领域最专业的政府财务管理软件。 0x02 漏洞概述 用友GRP-U8R10行政事业内控管理软件 listSelectDialogServlet 接口处存在SQL注入…

chisel RegInit/UInt/U

val reg RegInit(0.U(8.W)) //ok val reg RegInit(0.UInt(8.W)) //errU 使用在数字 . 后边50.U UInt 使用在IO(new Bundle val a Input(UInt(8.W)) 或者 def counter(max:UInt, a1:UInt) package emptyimport chisel3._ import chisel3.util._class MyCounter extends …

操作系统-【预备学习-1】(Linux 文件目录)

文章目录 相关知识目录结构进入目录补充查看目录创建文件删除文件创建文件夹删除文件夹文件和文件夹拷贝文件和文件夹移动/重命名 任务要求 相关知识 目录结构 Linux 文件系统是树形层次结构&#xff0c;具体如下图所示&#xff0c;最重要的是根目录&#xff08;/&#xff09…

06 - python操作xml

认识XML 与HTML很像&#xff0c;是一种将数据存储在标记之间的标记语言&#xff0c;用户可以自定义自己的标记。 XML文件可以表示称为&#xff1a;XML树。这个XML树从根元素开始&#xff0c;根元素进一步分支到子元素。XML文件的每个元素都是XML树的一个节点&#xff0c;没有…

服务器和云服务器哪个更安全?

随着云计算技术的不断发展&#xff0c;越来越多的企业开始选择使用云服务器来存储和处理数据。然而&#xff0c;对于一些企业来说&#xff0c;他们可能更倾向于使用传统的服务器。在这种情况下&#xff0c;安全性成为了一个重要的考虑因素。那么&#xff0c;服务器和云服务器哪…

arm 汇编积累

C语言函数与汇编对应关系 一、MOV 系列指令 1、指令格式 MOV{条件}{S} 目的寄存器&#xff0c;源操作数 2、含义解析&#xff1a; &#xff08;1&#xff09;&#xff1a;mov 指令传送数据 案例&#xff1a; MOV R0,R1 ; R0 R1; MOV PC,R14 ;PC R14; MOV R0,R…

[Angular 基础] - 数据绑定(databinding)

[Angular 基础] - 数据绑定(databinding) 上篇笔记&#xff0c;关于 Angular 的渲染过程及组件的创建&简单学习&#xff1a;[Angular 基础] - Angular 渲染过程 & 组件的创建 Angular 之中的 databinding 是一个相对而言更加复杂&#xff0c;以及我个人觉得相对而言比…

Java on Azure Tooling 2024年1月更新|Azure Key Vault 支持、示例项目创建支持及更多

作者&#xff1a;Jialuo Gan - Program Manager, Developer Division At Microsoft 排版&#xff1a;Alan Wang 大家好&#xff0c;欢迎来到 2024 年 Java on Azure 工具的首次更新。在本次更新中&#xff0c;我们将介绍对于 Azure Key Vault 支持、基于 Azure 示例项目的创建支…

C++ 调用lua 脚本

需求&#xff1a; 使用Qt/C 调用 lua 脚本 扩展原有功能。 步骤&#xff1a; 1&#xff0c;工程中引入 头文件&#xff0c;库文件。lua二进制下载地址&#xff08;Lua Binaries&#xff09; 2&#xff0c; 调用脚本内函数。 这里调用lua 脚本中的process函数&#xff0c;并…

如何让虚拟机拥有愉快网络环境,vmware,ubuntu,centos

博客原文 文章目录 前言拥有愉快网络环境步骤:测试网关连接 Ubuntu修改 http 与 sock 代理地址修改 /etc/resolv.conf配置 apt 使用代理测试连接 Centos设置代理地址修改 NetworkManager最后重启网卡&#xff1a;测试代理 前言 相信计算机专业的同学在学习 linux 时, 一定会被无…

Element UI+Spring Boot进行CRUD的实例

ElementUI安装与使用指南 前端代码&#xff1a;点击查看learnelementuispringboot项目源码 后端代码&#xff1a;点击查看 LearnElementUiAndSpringBoot 一、前端配置 安装axios Gitee的axios介绍与使用 GitHub的axios介绍与使用 方式一&#xff1a;使用npm安装 $ npm in…

2024年最新幻兽帕鲁服务器搭建教程

玩转幻兽帕鲁服务器&#xff0c;阿里云推出新手0基础一键部署幻兽帕鲁服务器教程&#xff0c;傻瓜式一键部署&#xff0c;3分钟即可成功创建一台Palworld专属服务器&#xff0c;成本仅需26元&#xff0c;阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…

回归预测 | Matlab实现WOA-CNN-LSTM-Attention鲸鱼算法优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制)

回归预测 | Matlab实现WOA-CNN-LSTM-Attention鲸鱼算法优化卷积长短期记忆网络注意力多变量回归预测&#xff08;SE注意力机制&#xff09; 目录 回归预测 | Matlab实现WOA-CNN-LSTM-Attention鲸鱼算法优化卷积长短期记忆网络注意力多变量回归预测&#xff08;SE注意力机制&…

谷歌产品大更新:Bard可生成图像;文生音乐平台等5大免费功能

2月2日&#xff0c;谷歌在官网对生成式AI产品进行了大更新&#xff0c;包括类ChatGPT聊天助手Bard可以通过文本提示生成图像&#xff1b; 全新的文生音乐平台MusicFX&#xff1b;新的文生图像平台ImageFX&#xff1b;新的文本扩写平台TextFX&#xff1b;在谷歌地图中增加生成式…

docker搭建Mysql集群准备(一)

docker搭建Mysql集群准备 Linux基本知识&#xff1a; 修改机器 IP&#xff0c;变成静态 IP vim /etc/sysconfig/network-scripts/ifcfg-ens33 文件 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic IPADDR192.168.190.67 NETMASK255.255.255.0 GAT…

第六讲:文件操作

第六讲:文件操作 文件夹创建文件夹移动文件夹复制文件夹删除文件夹文件操作文件读取文件写入文件文件夹 创建文件夹 定义创建文件夹函数:chmk_path()定义一个函数 chmk_path(),这个函数的功能是创建文件夹。 首先需要导入操作系统接口模块——os 模块,这个模块中包含某些函…