td_fplayer 0.0.1-beta.7
td_fplayer: ^0.0.1-beta.7 copied to clipboard
A Video Player Flutter plugin based on ijkplayer, support most popular protocols and codecs.
td_fplayer #
基于 ijkplayer 的 Flutter 视频播放器插件,支持 Android 和 iOS 平台。
本项目基于 fplayer 进行二次开发,替换为标准 ijkplayer 内核。
特性 #
- ✅ 支持 Android 和 iOS 双平台
- ✅ 支持常见视频格式(MP4、FLV、RTMP、HLS 等)
- ✅ 支持硬件解码
- ✅ 支持倍速播放
- ✅ 支持清晰度切换
- ✅ 支持视频列表播放
- ✅ 支持全屏模式
- ✅ 支持亮度和音量手势调节
- ✅ 支持播放进度手势调节
- ✅ 支持视频截图(iOS)
- ✅ 内置美观的播放控制面板
安装 #
在 pubspec.yaml 中添加依赖:
dependencies:
td_fplayer: ^0.0.1-beta.1
快速开始 #
基本使用 #
import 'package:flutter/material.dart';
import 'package:td_fplayer/td_fplayer.dart';
class VideoPlayerPage extends StatefulWidget {
@override
_VideoPlayerPageState createState() => _VideoPlayerPageState();
}
class _VideoPlayerPageState extends State<VideoPlayerPage> {
final FPlayer player = FPlayer();
@override
void initState() {
super.initState();
_initPlayer();
}
Future<void> _initPlayer() async {
// 基础配置
await player.setOption(FOption.hostCategory, "request-screen-on", 1);
await player.setOption(FOption.hostCategory, "request-audio-focus", 1);
// 硬件解码配置(防止花屏)
await player.setOption(FOption.playerCategory, "mediacodec", 1);
await player.setOption(FOption.playerCategory, "mediacodec-auto-rotate", 1);
await player.setOption(FOption.playerCategory, "mediacodec-handle-resolution-change", 1);
// 缓冲配置(防止花屏)
await player.setOption(FOption.playerCategory, "packet-buffering", 1);
// 设置视频源并播放
await player.setDataSource(
'http://player.alicdn.com/video/aliyunmedia.mp4',
autoPlay: true,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('视频播放器')),
body: FView(
player: player,
width: double.infinity,
height: 200,
color: Colors.black,
panelBuilder: fPanelBuilder(
title: '视频标题',
),
),
);
}
@override
void dispose() {
player.release();
super.dispose();
}
}
完整示例 #
import 'package:flutter/material.dart';
import 'package:td_fplayer/td_fplayer.dart';
import 'package:screen_brightness/screen_brightness.dart';
class VideoScreen extends StatefulWidget {
final String url;
const VideoScreen({super.key, required this.url});
@override
VideoScreenState createState() => VideoScreenState();
}
class VideoScreenState extends State<VideoScreen> {
final FPlayer player = FPlayer();
// 视频列表
List<VideoItem> 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',
),
];
// 倍速列表
Map<String, double> speedList = {
"2.0": 2.0,
"1.5": 1.5,
"1.0": 1.0,
"0.5": 0.5,
};
// 清晰度列表
Map<String, ResolutionItem> 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;
@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);
// soundtouch: 变速播放时的音频处理
// 1 = 变速不变调(音调正常,但直播录制等不规则音频可能有杂音)
// 0 = 变速变调(无杂音,但加速声音变尖、减速声音变低沉)
await player.setOption(FOption.playerCategory, "soundtouch", 0);
// 硬件解码配置
await player.setOption(FOption.playerCategory, "mediacodec", 1);
await player.setOption(FOption.playerCategory, "mediacodec-auto-rotate", 1);
await player.setOption(FOption.playerCategory, "mediacodec-handle-resolution-change", 1);
// 缓冲配置(0=快速首帧,1=稳定但慢)
await player.setOption(FOption.playerCategory, "packet-buffering", 0);
setVideoUrl(videoList[videoIndex].url);
}
Future<void> setVideoUrl(String url) async {
try {
await player.setDataSource(url, autoPlay: true, showCover: true);
} catch (error) {
print("播放异常: $error");
}
}
@override
Widget build(BuildContext context) {
double videoHeight = MediaQuery.of(context).size.width * 9 / 16;
return Scaffold(
appBar: AppBar(title: Text('视频播放')),
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,
isVideos: true,
videoList: videoList,
videoIndex: videoIndex,
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);
}
},
),
),
],
),
);
}
@override
void dispose() async {
super.dispose();
try {
await ScreenBrightness().resetScreenBrightness();
} catch (e) {
print(e);
}
player.release();
}
}
API 说明 #
FPlayer 主要方法 #
| 方法 | 说明 |
|---|---|
setDataSource(url, {autoPlay, showCover}) |
设置视频源 |
start() |
开始播放 |
pause() |
暂停播放 |
stop() |
停止播放 |
reset() |
重置播放器 |
release() |
释放播放器资源 |
seekTo(msec) |
跳转到指定位置 |
setSpeed(speed) |
设置播放速度 |
setVolume(volume) |
设置音量 |
takeSnapShot() |
截图(仅 iOS) |
setOption(category, key, value) |
设置播放器选项 |
FView 参数 #
| 参数 | 类型 | 说明 |
|---|---|---|
player |
FPlayer |
播放器实例 |
width |
double |
播放器宽度 |
height |
double |
播放器高度 |
color |
Color |
背景颜色 |
fit |
FFit |
视频填充模式 |
fsFit |
FFit |
全屏模式填充 |
panelBuilder |
FPanelWidgetBuilder |
控制面板构建器 |
fPanelBuilder 参数 #
| 参数 | 类型 | 说明 |
|---|---|---|
title |
String |
视频标题 |
subTitle |
String |
视频副标题 |
isSnapShot |
bool |
是否显示截图按钮 |
isVideos |
bool |
是否显示视频列表 |
videoList |
List<VideoItem> |
视频列表 |
videoIndex |
int |
当前视频索引 |
speedList |
Map<String, double> |
倍速列表 |
isResolution |
bool |
是否显示清晰度 |
resolutionList |
Map<String, ResolutionItem> |
清晰度列表 |
onError |
Function |
错误回调 |
onVideoEnd |
Function |
播放完成回调 |
onVideoPrepared |
Function |
准备完成回调 |
onVideoTimeChange |
Function |
进度变化回调 |
平台支持 #
| 平台 | 最低版本 | 推荐版本 |
|---|---|---|
| Android | API 21 (Android 5.0) | API 24+ |
| iOS | iOS 12.0 | iOS 13.0+ |
注意事项 #
iOS #
- ⚠️ iOS 模拟器不支持视频播放,请使用真机测试
- 需要在
Info.plist中添加网络权限(如播放 HTTP 视频):
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Android #
- 需要在
AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
花屏问题 #
如果在 Android 上遇到播放开始时花屏(1-2秒后恢复正常),可以尝试以下方案:
方案1:开启缓冲(推荐,首帧会变慢约1-2秒)
await player.setOption(FOption.playerCategory, "packet-buffering", 1);
await player.setOption(FOption.playerCategory, "min-frames", 25);
方案2:关闭硬件解码(最稳定,但耗电)
await player.setOption(FOption.playerCategory, "mediacodec", 0);
鸣谢 #
- fplayer - 原始项目
- fijkplayer - 参考项目
- ijkplayer - 播放内核
- FFmpeg - 音视频处理
许可证 #
MIT License
支持作者 #
如果这个项目对你有帮助,欢迎请作者喝杯咖啡 ☕
| 微信 | 支付宝 | |
|---|---|---|
![]() |
![]() |
联系方式 #
如有问题或建议,欢迎联系作者:📧 [email protected]

