### Install fplayer from Git repository Source: https://github.com/hellofinch/dsm_helper/blob/master/fplayer/README.md This snippet demonstrates how to include the fplayer package directly from its Git repository. You can specify a branch or tag name using the 'ref' field. ```yaml dependencies: fplayer: git: url: https://github.com/FlutterPlayer/fplayer.git ref: develop ``` -------------------------------- ### Dart Video Player Setup and Playback Source: https://github.com/hellofinch/dsm_helper/blob/master/fplayer/README.md This Dart code sets up a video player using the fplayer package in a Flutter application. It configures various player options, loads video data, and handles playback. The example includes setting up a list of videos, playback speed options, and resolution choices. ```dart import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:fplayer/fplayer.dart'; import 'package:screen_brightness/screen_brightness.dart'; import 'app_bar.dart'; class VideoScreen extends StatefulWidget { final String url; const VideoScreen({super.key, required this.url}); @override VideoScreenState createState() => VideoScreenState(); } class VideoScreenState extends State { final FPlayer player = FPlayer(); // 视频列表 List videoList = [ VideoItem( title: '第一集', subTitle: '视频1副标题', url: 'http://player.alicdn.com/video/aliyunmedia.mp4', ), VideoItem( title: '第二集', subTitle: '视频2副标题', url: 'https://www.runoob.com/try/demo_source/mov_bbb.mp4', ), VideoItem( title: '第三集', subTitle: '视频3副标题', url: 'http://player.alicdn.com/video/aliyunmedia.mp4', ), ]; // 倍速列表 Map speedList = { "2.0": 2.0, "1.5": 1.5, "1.0": 1.0, "0.5": 0.5, }; // 清晰度列表 Map resolutionList = { "480P": ResolutionItem( value: 480, url: 'https://www.runoob.com/try/demo_source/mov_bbb.mp4', ), "270P": ResolutionItem( value: 270, url: 'http://player.alicdn.com/video/aliyunmedia.mp4', ), }; // 视频索引,单个视频可不传 int videoIndex = 0; // 模拟播放记录视频初始化完需要跳转的进度 int seekTime = 100000; VideoScreenState(); @override void initState() { super.initState(); startPlay(); } void startPlay() async { // 视频播放相关配置 await player.setOption(FOption.hostCategory, "enable-snapshot", 1); await player.setOption(FOption.hostCategory, "request-screen-on", 1); await player.setOption(FOption.hostCategory, "request-audio-focus", 1); await player.setOption(FOption.playerCategory, "reconnect", 20); await player.setOption(FOption.playerCategory, "framedrop", 20); await player.setOption(FOption.playerCategory, "enable-accurate-seek", 1); await player.setOption(FOption.playerCategory, "mediacodec", 1); await player.setOption(FOption.playerCategory, "packet-buffering", 0); await player.setOption(FOption.playerCategory, "soundtouch", 1); // 播放传入的视频 setVideoUrl(widget.url); // 播放视频列表的第一个视频 // setVideoUrl(videoList[videoIndex].url); } Future setVideoUrl(String url) async { try { await player.setDataSource(url, autoPlay: true, showCover: true); } catch (error) { print("播放-异常: $error"); return; } } @override Widget build(BuildContext context) { MediaQueryData mediaQueryData = MediaQuery.of(context); Size size = mediaQueryData.size; double videoHeight = size.width * 9 / 16; return Scaffold( appBar: const FAppBar.defaultSetting(title: "Video"), body: Column( children: [ FView( player: player, width: double.infinity, height: videoHeight, color: Colors.black, fsFit: FFit.contain, // 全屏模式下的填充 fit: FFit.fill, // 正常模式下的填充 panelBuilder: fPanelBuilder( // 单视频配置 title: '视频标题', subTitle: '视频副标题', // 右下方截屏按钮 isSnapShot: true, // 右上方按钮组开关 isRightButton: true, // 右上方按钮组 rightButtonList: [ InkWell( onTap: () {}, child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Theme.of(context).primaryColorLight, borderRadius: const BorderRadius.vertical( top: Radius.circular(5), ), ), child: Icon( Icons.favorite, color: Theme.of(context).primaryColor, ), ), ), InkWell( onTap: () {}, child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Theme.of(context).primaryColorLight, borderRadius: const BorderRadius.vertical( bottom: Radius.circular(5), ), ), child: Icon( Icons.thumb_up, color: Theme.of(context).primaryColor, ), ), ) ], // 字幕功能:待内核提供api // caption: true, // 视频列表开关 isVideos: true, // 视频列表列表 videoList: videoList, // 当前视频索引 videoIndex: videoIndex, // 全屏模式下点击播放下一集视频按钮 playNextVideoFun: () { ``` -------------------------------- ### Install fplayer via pubspec.yaml Source: https://github.com/hellofinch/dsm_helper/blob/master/fplayer/README.md This snippet shows how to add the fplayer package as a dependency in your Flutter project's pubspec.yaml file. Replace '{{latest version}}' with the actual latest version number. ```yaml dependencies: fplayer: ^{{latest version}} ``` -------------------------------- ### Flutter Video Player Controls and Callbacks Source: https://github.com/hellofinch/dsm_helper/blob/master/fplayer/README.md This snippet details the configuration of a video player, including callbacks for various playback events such as setting state, button clicks, error handling, video completion, time changes, and preparation. It also includes custom lists for playback speed and resolution. ```Dart setState(() { videoIndex += 1; }); }, settingFun: () { print('设置按钮点击事件'); }, // 自定义倍速列表 speedList: speedList, // 清晰度开关 isResolution: true, // 自定义清晰度列表 resolutionList: resolutionList, // 视频播放错误点击刷新回调 onError: () async { await player.reset(); setVideoUrl(videoList[videoIndex].url); }, // 视频播放完成回调 onVideoEnd: () async { var index = videoIndex + 1; if (index < videoList.length) { await player.reset(); setState(() { videoIndex = index; }); setVideoUrl(videoList[index].url); } }, onVideoTimeChange: () { // 视频时间变动则触发一次,可以保存视频播放历史 }, onVideoPrepared: () async { // 视频初始化完毕,如有历史记录时间段则可以触发快进 try { if (seekTime >= 1) { /// seekTo必须在FState.prepared print('seekTo'); await player.seekTo(seekTime); // print("视频快进-$seekTime"); seekTime = 0; } } catch (error) { print("视频初始化完快进-异常: $error"); } }, ), ), // 自定义小屏列表 Container( width: double.infinity, height: 30, margin: const EdgeInsets.all(20), child: ListView.builder( scrollDirection: Axis.horizontal, padding: EdgeInsets.zero, itemCount: videoList.length, itemBuilder: (context, index) { bool isCurrent = videoIndex == index; Color textColor = Theme.of(context).primaryColor; Color bgColor = Theme.of(context).primaryColorDark; Color borderColor = Theme.of(context).primaryColor; if (isCurrent) { textColor = Theme.of(context).primaryColorDark; bgColor = Theme.of(context).primaryColor; borderColor = Theme.of(context).primaryColor; } return GestureDetector( onTap: () async { await player.reset(); setState(() { videoIndex = index; }); setVideoUrl(videoList[index].url); }, child: Container( margin: EdgeInsets.only(left: index == 0 ? 0 : 10), padding: const EdgeInsets.symmetric(horizontal: 5), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: bgColor, border: Border.all( width: 1.5, color: borderColor, ), ), alignment: Alignment.center, child: Text( videoList[index].title, style: TextStyle( fontSize: 15, color: textColor, ), ), ), ); }, ), ), ], ), ); } @override void dispose() async { super.dispose(); try { await ScreenBrightness().resetScreenBrightness(); } catch (e) { print(e); throw 'Failed to reset brightness'; } player.release(); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.