flutter开发实战-video_player插件播放抖音直播实现(仅限Android端)

flutter开发实战-video_player插件播放抖音直播实现(仅限Android端)

在之前的开发过程中,遇到video_player播放视频,通过查看video_player插件描述,可以看到video_player在Android端使用exoplayer,在iOS端使用的是AVPlayer。由于iOS的AVPlayer不支持flv、m3u8格式的直播,这里video_player播放抖音直播仅仅在Android有效,在iOS端,如果需要播放抖音直播,可以使用fijkplayer插件进行播放,由于fijkplayer使用的是ijkplayer,可以播放flv、m3u8格式的直播。

一、引入

在pubspec.yaml中引入video_player

  # 播放器video_player: ^2.7.0# fijkplayer: ^0.11.0

二、实现VideoPlayer的Widget

2.1 在iOS中的设置

在iOS工程中info.plist添加一下设置,以便支持Https,HTTP的视频地址

<key>NSAppTransportSecurity</key>
<dict><key>NSAllowsArbitraryLoads</key><true/>
</dict>

2.2 在Android中的设置

需要在/android/app/src/main/AndroidManifest.xml文件中添加网络权限

<uses-permission android:name="android.permission.INTERNET"/>

2.3 播放的VideoPlayer

使用video_player插件,需要使用VideoPlayerController来控制播放、暂停、添加监听

初始化后添加监听,来获取VideoPlayerController中的Value值,可以看到一些状态。例如

VideoPlayerValue(duration: 0:00:00.001000, size: Size(1280.0, 720.0), position: 0:32:14.877000, caption: Caption(number: 0, start: 0:00:00.000000, end: 0:00:00.000000, text: ), captionOffset: 0:00:00.000000, buffered: [DurationRange(start: 0:00:00.000000, end: 0:32:17.868000)], isInitialized: true, isPlaying: true, isLooping: false, isBuffering: false, volume: 1.0, playbackSpeed: 1.0, errorDescription: null, isCompleted: false)

添加监听

// 添加监听void addListener() {if (_controller != null) {_controller!.addListener(videoListenerCallback);}}

移除监听

// 移除监听void removeListener() {if (_controller != null) {_controller!.removeListener(videoListenerCallback);}}

监听的callback回调

void videoListenerCallback() {// 监听结果if (_controller != null) {if (_controller!.value.hasError) {// 出现错误setState(() {});}if (_controller!.value.isCompleted) {// 直播完成setState(() {});}if (_controller!.value.isBuffering) {// 正在buffer}if (_controller!.value.hasError || _controller!.value.isCompleted) {// 是否处于错误状态 或者 播放完成if (widget.liveController.onOutLinkPlayerCompleted != null) {widget.liveController.onOutLinkPlayerCompleted!();}}if (_controller!.value.hasError == false) {// 可播放,隐藏封面if (widget.liveController.onOutLinkPlayerCanPlay != null) {widget.liveController.onOutLinkPlayerCanPlay!();}}}}

播放

Future<void> play() async {
if (_controller != null) {await _controller?.play();}
}

暂停

Future<void> play() async {
if (_controller != null) {await _controller?.pause();}
}

完整代码如下

//  视频播放测试
class VideoPlayerSkeleton extends StatefulWidget {const VideoPlayerSkeleton({Key? key,required this.videoUrl,required this.isLooping,this.autoPlay = true,required this.width,required this.height,}) : super(key: key);final String videoUrl;final bool isLooping;final bool autoPlay;final double width;final double height;State<VideoPlayerSkeleton> createState() => _VideoPlayerSkeletonState();
}class _VideoPlayerSkeletonState extends State<VideoPlayerSkeleton> {VideoPlayerController? _controller;void initState() {super.initState();videoPlay();print("_VideoPlayerSkeletonState videoUrl:${widget.videoUrl}");}// 添加监听void addListener() {if (_controller != null) {_controller!.addListener(videoListenerCallback);}}void videoListenerCallback() {// 监听结果if (_controller != null) {if (_controller!.value.hasError) {// 出现错误setState(() {});}if (_controller!.value.isCompleted) {// 直播完成setState(() {});}if (_controller!.value.isBuffering) {// 正在buffer}}}// 移除监听void removeListener() {if (_controller != null) {_controller!.removeListener(videoListenerCallback);}}// 播放视频Future<void> videoPlay() async {_controller?.dispose();_controller = VideoPlayerController.networkUrl(Uri.parse(widget.videoUrl),videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true,allowBackgroundPlayback: false,),);addListener();await _controller?.initialize().then((_) {// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.setState(() {});}).catchError((error) {// 是否处于错误状态 或者 播放完成if (widget.liveController.onOutLinkPlayerCompleted != null) {widget.liveController.onOutLinkPlayerCompleted!();}}).whenComplete(() {// print('checkAnimationTimeout whenComplete');});await _controller!.setLooping(widget.isLooping);if (widget.autoPlay) {await _controller?.play();} else {await _controller?.pause();}}Widget build(BuildContext context) {return Container(width: widget.width,height: widget.height,color: Colors.black87,child: Stack(alignment: Alignment.center,children: [buildVideoPlayer(context),buildStateIntro(context),],),);}// 播放视频Widget buildVideoPlayer(BuildContext context) {if (_controller != null && _controller!.value.isInitialized) {return AspectRatio(aspectRatio: _controller!.value.aspectRatio,child: VideoPlayer(_controller!),);}return Container();}// 播放过程中出现errorWidget buildStateIntro(BuildContext context) {if (_controller != null) {String title = "";String message = "";bool showIntro = false;if (_controller!.value.hasError) {showIntro = true;title = "播放出现错误";message = _controller!.value.errorDescription ?? "";} else {if (_controller!.value.isCompleted) {showIntro = true;title = "播放结束";}}if (showIntro) {return Container(padding: EdgeInsets.symmetric(vertical: 50.r, horizontal: 50.r),color: Colors.transparent,child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [Expanded(child: Container()),Text(title,textAlign: TextAlign.center,softWrap: true,style: TextStyle(fontSize: 28.r,fontWeight: FontWeight.w500,fontStyle: FontStyle.normal,color: Colors.white,decoration: TextDecoration.none,),),SizedBox(height: 25.r,),Text(message,textAlign: TextAlign.center,softWrap: true,style: TextStyle(fontSize: 22.r,fontWeight: FontWeight.w500,fontStyle: FontStyle.normal,color: Colors.white,decoration: TextDecoration.none,),),Expanded(child: Container()),],),);}}return Container();}void dispose() {// TODO: implement disposeremoveListener();_controller?.dispose();super.dispose();}
}

三、从抖音网站上找到直播地址

由于使用抖音播放地址,这里简单描述一下从抖音网站上找到直播的flv地址。

进入抖音直播间,在网页点击鼠标右键,看到检查。
https://live.douyin.com/567752440034
在这里插入图片描述

找到网络,刷新页面,可以看到stream的一条,
在这里插入图片描述

复制地址即可,使用该地址播放直播
在这里插入图片描述

https://pull-hs-spe-f5.douyincdn.com/fantasy/stream-728687306789918920718_sd.flv?_neptune_token=MIGlBAxGexWdmRAYAAGs67QEgYIZi9nqbdY3bbfeK9dCVFBnlFTJNF1WNGRZ3AVrQ1ixrE_54JzkGsfuBjGER_2RhP5Qy_GzELSQuct4bK5aktJ2P2xnNznJG87KKhybkeCuefBAkOCI9Tx8eA1mz2GcmfcfqFNeR8DFPDcbzFp_sKyyJRnytmILegqrqjcjxgW04GYwBBDMFIKjhmF1jpi96O53wH7v&expire=1696731973&sign=38f51d46dcd5828fdbc212372bbb3522&volcSecret=38f51d46dcd5828fdbc212372bbb3522&volcTime=1696731973

四、查看直播结果

之后,我们将地址复制到VideoPlayerSkeleton中,运行后,可以看到播放的效果

在这里插入图片描述

注意:直接在Container上设置大小后,child是AspectRatio(
aspectRatio: _controller!.value.aspectRatio,
child: VideoPlayer(_controller!),
);
会出现画面变形,可以使用Stack嵌套一下。

五、小结

flutter开发实战-video_player插件播放抖音直播实现(仅限Android端)。描述可能不是特别准确,请见谅。

https://blog.csdn.net/gloryFlow/article/details/133634186

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

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

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

相关文章

笔记34:转置卷积 Transposed Convolution 的由来

注&#xff1a;该文章为视频课的笔记补充 视频课&#xff1a;转置卷积&#xff08;transposed convolution&#xff09;_哔哩哔哩_bilibili 更详细的推导在&#xff1a;抽丝剥茧&#xff0c;带你理解转置卷积&#xff08;反卷积&#xff09;_逆卷积-CSDN博客 a a a 补充1…

九大装修收纳空间的设计,收藏备用!福州中宅装饰,福州装修

如果房子面积不大&#xff0c;收纳设计就显得非常重要。其实装修房子中很多地方都可以做收纳&#xff0c;九大空间每一处都可以放下你的东西&#xff0c;让你摆脱收纳烦恼。 收纳空间少的话&#xff0c;装修完后住久了怕会乱成一窝&#xff0c;因此装修的时候&#xff0c;收纳…

java spring cloud 工程企业管理软件-综合型项目管理软件-工程系统源码

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…

3D模型格式转换工具HOOPS Exchange助力Halocline开发VR

挑战&#xff1a; 支持客户群使用各种CAD系统和CAD文件格式。快速准确的加载可视化硬件数据。提供访问模型详细信息&#xff0c;同时确保高帧频性能。 结果&#xff1a; 确保支持标准文件格式和来自领先工程软件包的CAD数据。 通过查看简化模型或根据需要访问高层次的细节&am…

Flutter安卓混淆的相关问题

当你执行 build apk 后&#xff0c;flutter会默认进行混淆&#xff0c;若你的应用中引用了第三方的sdk&#xff0c;在debug模式下没问题&#xff0c;但在release下可能就会出现各种各样的问题&#xff0c;找不到某个类&#xff0c;或者某个功能无法使用&#xff0c;甚至直接崩溃…

【多线程案例】设计模式-单例模式

1.单例模式 什么是单例模式&#xff1f; 所谓单例&#xff0c;即单个实例。通过编码技巧约定某个类只能有唯一一个实例对象&#xff0c;并且提前在类里面创建好一个实例对象&#xff0c;把构造方法私有化&#xff0c;再对外提供获取这个实例对象的方法&#xff0c;&#xff0…

嵌入式养成计划-31-网络编程----TCP的并发服务器模型------IO模型--IO多路复用

六十七、 TCP的并发服务器模型 67.1 循环服务器模型 一次只能处理一个客户端&#xff0c;当上一个客户端退出后&#xff0c;才能处理下一个客户端缺点&#xff1a;无法同时处理多个客户端 代码模型 sfd socket(); bind(); listen(); while(1){newfd accept();while(1){re…

vue-3

一、文章内容概括 1.生命周期 生命周期介绍生命周期的四个阶段生命周期钩子声明周期案例 2.工程化开发入门 工程化开发和脚手架项目运行流程组件化组件注册 二、Vue生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09…

取消激光雷达/不升级Orin,小鹏P5改款背后的行业「痛点」

9月25日&#xff0c;小鹏汽车正式发布了旗下改款车型—2024款小鹏P5&#xff08;15.69-17.49万元&#xff09;。车型精简、降本增效&#xff08;减配&#xff09;成为新亮点。 在配置变化方面&#xff0c;智驾成为牺牲品。其中&#xff0c;高配Pro车型继续保留英伟达Xavier&…

如何领取京东优惠券用微信支付还是用支付宝支付购买商品?

京东用微信支付还是用支付宝支付&#xff1f; 京东商城购物不支持支付宝支付&#xff0c;现京东商城支持的支付方式包括&#xff1a;京东支付、银行卡、信用卡、微信支付、云闪付等&#xff1b; 京东如何领取优惠券用微信支付购物&#xff1f; 1、打开京东APP&#xff0c;挑选…

存档&改造【04】二维码操作入口设置细节自动刷新设置后的交互式网格

因为数据库中没有数据无法查看设置效果&#xff0c;于是自己创建了个测试数据表&#xff0c;用来给demo测试 -- 二维码操作入口设置 create table JM_QR_CODE(QR_CODE_ID NUMBER generated as identity primary key,SYSTEM_ID NUMBER(20) not null,IS_ENAB…

安装torchtext遇到的坑及解决办法

刚开始秉着需要什么就pip install什么的原则直接pip install torchtext&#xff0c;结果&#xff1a; 把我这个环境打乱了&#xff0c;自作主张的删掉之前的很多包重新安装了其他版本的包而不是自适应的安装当前torch所对应的torchtext。因为这个环境比较重要也用在其他的工程…

【FreeRTOS】【STM32】01从零开始的freertos之旅 浏览源码下的文件夹

基于野火以及正点原子 在打开正点原子的资料pdf时&#xff0c;我遇到了pdf无法复制粘贴的问题&#xff0c;这里有个pdf解锁文字复制功能的网址&#xff0c;mark一下。超级pdf 参考资料《STM32F429FreeRTOS开发手册_V1.2》 官方资料 FreeRTOS 的源码和相应的官方书籍均可从官…

机器人中的数值优化(二十一)—— 伴随灵敏度分析、线性方程组求解器的分类和特点、优化软件

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考&#xff0c;主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等&#xff0c;本系列文章篇数较多&#xff0c;不定期更新&#xff0c;上半部分介绍无约束优化&#xff0c;…

模型训练环境相关(CUDA、PyTorch)

模型训练环境相关&#xff08;CUDA、PyTorch&#xff09; 1. 查看当前 GPU 所能支持的最高版本的 CUDA2. 如何判断是否安装了 CUDA3. 安装 PyTorch3.1 创建虚拟环境3.2 激活并进入虚拟环境3.3 安装 PyTorch 1. 查看当前 GPU 所能支持的最高版本的 CUDA 打开 NVIDIA 控制面板&a…

QT基础入门——文件操作(六)

前言&#xff1a; 文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库&#xff0c;提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象&#xff0c;这些设备具有读写字节块的能力。 目录 一、QFile文件读写操作 1.QFile file( path 文件路径) 2…

Flink状态管理与检查点机制

1.状态分类 相对于其他流计算框架,Flink 一个比较重要的特性就是其支持有状态计算。即你可以将中间的计算结果进行保存,并提供给后续的计算使用: 具体而言,Flink 又将状态 (State) 分为 Keyed State 与 Operator State: 1.1 算子状态 算子状态 (Operator State):顾名思义…

Vue Router的进阶

进阶 导航守卫 官方文档上面描述的会比较深奥&#xff0c;而守卫类型也比较多&#xff0c;其中包含了全局前置守卫、全局解析守卫、全局后置钩子、路由独享守卫、组件内守卫。每一种守卫的作用和用法都不相同。这会使得大家去学习的时候觉得比较困难&#xff0c;这边主要介绍…

北邮22级信通院数电:Verilog-FPGA(5)第四第五周实验 密码保险箱的设计

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 一.密码箱的功能和安全性 显示&#xff1a;…

VxeTable 表格组件推荐

VxeTable 表格组件推荐 https://vxetable.cn 在前端开发中&#xff0c;表格组件是不可或缺的一部分&#xff0c;它们用于展示和管理数据&#xff0c;为用户提供了重要的数据交互功能。VxeTable 是一个优秀的 Vue 表格组件&#xff0c;它提供了丰富的功能和灵活的配置选项&…