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

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.mfbz.cn/a/378006.html

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

相关文章

PyTorch 2.2 中文官方教程(二)

在 YouTube 上介绍 PyTorch PyTorch 介绍 - YouTube 系列 原文&#xff1a;pytorch.org/tutorials/beginner/introyt.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 介绍 || 张量 || 自动微分 || 构建模型 || TensorBoard 支持 || 训练模型 || 模型理解 作者&a…

BUGKU-WEB 留言板

题目描述 题目无需登录后台&#xff01;需要xss平台接收flag&#xff0c; http协议需要http协议的xss平台打开场景后界面如下&#xff1a; 解题思路 看到此类的题目&#xff0c;应该和存储型xss有关&#xff0c;也就是将恶意代码保存到服务器端即然在服务器端&#xff0c;那就…

next项目页面性能调优

next项目页面性能调优 一般来说性能优化可以分为加载时、运行时两部分的优化。 扩展参考链接&#xff1a; 前端性能优化 24 条建议 Webpack 4进阶–从前的日色变得慢 &#xff0c;一下午只够打一次包 Webpack 分包优化首屏加载 参考指标 FCP&#xff08;First Contentful P…

fghbbbbbbbbbb

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 磁盘满的本质分析 专栏&#xff1a;《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具…

双非本科准备秋招(19.2)—— 设计模式之保护式暂停

一、wait & notify wait能让线程进入waiting状态&#xff0c;这时候就需要比较一下和sleep的区别了。 sleep vs wait 1) sleep 是 Thread 方法&#xff0c;而 wait 是 Object 的方法 2) sleep 不需要强制和 synchronized 配合使用&#xff0c;但 wait 强制和 s…

初识C语言·预处理详解

目录 1 预定义符号 2 define定义常量 3 #define定义宏 4 带有副作用的宏 5 宏替换的规则 6 宏和函数的对比 7 # 和 ## i) #运算符 ii) ##运算符 8 命名约定 9 命令行定义 10 条件编译 条件编译1&#xff1a; 条件编译2&#xff1a; 条件编译3&#xff1a; 条件…

数字IC实践项目(9)— Tang Nano 20K: I2C OLED Driver

Tang Nano 20K: I2C OLED Driver 写在前面的话硬件模块RTL电路和相关资源报告SSD1306 OLED 驱动芯片SSD1306 I2C协议接口OLED 驱动模块RTL综合实现 总结 写在前面的话 之前在逛淘宝的时候偶然发现了Tang Nano 20K&#xff0c;十分感慨国产FPGA替代方案的进步之快&#xff1b;被…

CrystalDiskInfo:一款免费的硬盘健康检测软件

CrystalDiskInfo&#xff1a;一款免费的硬盘健康检测软件&#xff0c;可以显示出硬盘的使用时间、温度、剩余寿命和健康状态等。该软件支持多种语言和多种硬盘类型&#xff0c;使用简单&#xff0c;操作直观。 感觉真正有用的是读取到的硬盘通电时间&#xff0c;其他的估计意义…

Unity类银河恶魔城学习记录4-1,4-2 Attack Logic,Collider‘s collision excepetion源代码 P54 p55

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Entity.cs using System.Collections; using System.Collections.Generic; u…

2024年阿里云服务器活动价格表

2024年2月阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核…

LEETCDE 220. 存在重复元素 III

class Solution { public:long long size;bool containsNearbyAlmostDuplicate(vector<int>& nums, int indexDiff, int valueDiff) {//桶排序unordered_map<long,long> m;sizevalueDiff1;for(int i0;i<nums.size();i){//控制数值long long idxgetID(nums[i…

双非本科准备秋招(20.1)—— 并发编程之生产者消费者

生产者消费者 与保护性暂停中的不同&#xff0c;不需要产生结果和消费结果的线程一一对应。 生产者仅负责产生结果数据&#xff0c;不关心数据该如何处理&#xff0c;而消费者专心处理结果数据 JDK 中各种阻塞队列&#xff0c;采用的就是这种模式 代码实现&#xff1a; 首先…

RK3588平台开发系列讲解(AI 篇)什么是NPU

文章目录 一、什么是NPU二、什么是RKNPU沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要讲解什么是NPU。 一、什么是NPU 📢什么是 NPU 呢? 在谈这个问题之前,可以先来看看什么是 CPU 和 GPU,CPU 就是中央处理器,中央处理器就好像是人类的大脑,主要负…

IntelliJ IDEA 2023.3发布,AI 助手出世,新特性杀麻了!!

目录 关键亮点 对 Java 21 功能的完全支持 调试器中的 Run to Cursor&#xff08;运行到光标)嵌入选项 带有编辑操作的浮动工具栏 用户体验优化 Default&#xff08;默认&#xff09;工具窗口布局选项 默认颜色编码编辑器标签页 适用于 macOS 的新产品图标 Speed Sear…

【开源】基于JAVA+Vue+SpringBoot的停车场收费系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 停车位模块2.2 车辆模块2.3 停车收费模块2.4 IC卡模块2.5 IC卡挂失模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 停车场表3.2.2 车辆表3.2.3 停车收费表3.2.4 IC 卡表3.2.5 IC 卡挂失表 四、系统实现五、核心代码…

Stable Diffusion 模型下载:Samaritan 3d Cartoon(撒玛利亚人 3d 卡通)

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十 下载地址 模型介绍 由“PromptSharingSamaritan”创作的撒玛利亚人 3d 卡通类型的大模型&#xff0c;该模型的基础模型为 SD 1.5。 条目内容类型大模型基础模型SD 1.5来源CIVITAI作者…

DFS深度优先搜索与回溯算法

目录 递归遍历的三步骤&#xff1a; DFS/回溯模板 练习 1.三角形路径和最大搜索 &#xff08;一&#xff09;前序DFS&#xff08;从上至下搜索&#xff0c;实际是暴力解法&#xff0c;测试超时&#xff09; &#xff08;二&#xff09;后序DFS&#xff08;自底向上搜索&am…

复制和粘贴文本时剥离格式的5种方法(MacWindows)

您可能每天复制和粘贴多次。虽然它是一个非常方便的功能&#xff0c;但最大的烦恼之一就是带来了特殊的格式。从网络上获取一些文本&#xff0c;您经常会发现粘贴到文档中时&#xff0c;它保持原始样式。 我们将展示如何使用一些简单的技巧在不格式化的情况下复制和粘贴。 1.…

ubuntu20安装mongodb

方法一&#xff1a;直接安装(命令是直接从mongo官网Install MongoDB Community Edition on Ubuntu — MongoDB Manual复制的&#xff09; cat /etc/lsb-release sudo apt-get install -y gnupg curl curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \sudo gp…

Qt 字符串类应用与常用基本数据类型

目录 操作字符串 查询字符串 Qt 常见数据类型 操作字符串 创建一个控制台项目 &#xff08;1&#xff09;QString提供一个二元的 “” 操作符&#xff0c;主要用于组合两个字符串。QString str1 "Hello World 传递给QString一个 const char* 类型的ASCII字符串 “He…
最新文章