fijkplayer flutter 直播流播放
fijkplayer 是 ijkplayer 的 Flutter 封装, 是一款支持 android 和 iOS 的 Flutter 媒体播放器插件, 由 ijkplayer 底层驱动。
通过纹理(Texture)接入播放器视频渲染到 Flutter 中。
前言
目前使用的服务端是 srs_stack
我的本地环境
[✓] Flutter (Channel stable, 3.13.1, on macOS 13.6.1 22G313 darwin-x64, locale zh-Hans-CN)
• Flutter version 3.13.1 on channel stable at /Users/wangq/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision e1e47221e8 (4 months ago), 2023-08-22 21:43:18 -0700
• Engine revision b20183e040
• Dart version 3.1.0
• DevTools version 2.25.0
• Pub download mirror https://pub.flutter-io.cn
• Flutter download mirror https://storage.flutter-io.cn
加入依赖
pubspec.yaml
中加入依赖 -> 官方地址
fijkplayer: ^0.11.0
配置(解决延迟)
连上视频流可能会发现有差不多10秒的播放延迟, 以下是有一些调整参数可以试下调整
我测试配置了analyzeduration: 1)
后延迟就有很大改善(大概1秒多rtmp
方案)
如果需要做到1秒
内的延迟可能得用srt协议
注意:需要做到1秒内,录制端,传输和播放端均需要做好优化
player.setOption(FijkOption.playerCategory, "fflags", 'nobuffer');
player.setOption(FijkOption.playerCategory, "fast", 1);
player.setOption(FijkOption.playerCategory, "framedrop", 5);
player.setOption(FijkOption.playerCategory, "start-on-prepared", 1);
player.setOption(FijkOption.formatCategory, "max-buffer-size", 0);
player.setOption(FijkOption.playerCategory, "packet-buffering", 0);
player.setOption(FijkOption.formatCategory, "analyzeduration", 1);
player.setOption(FijkOption.formatCategory, "analyzemaxduration", 100);
player.setOption(FijkOption.formatCategory, "rtsp_transport", 'tcp');
player.setOption(FijkOption.formatCategory, "probesize", 100);
player.setOption(FijkOption.formatCategory, "flush_packets", 0);
player.setOption(FijkOption.playerCategory, "reconnect", 5);
测试源码
官方的
demo
可能是基于久版本的flutter
的,我无法直接用, 遇到有问题的可以用以下源码测试
import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/material.dart';
void main() {
runApp(VideoScreen(url: 'rtmp://192.168.31.91/live/test110'));
// runApp(VideoScreen(url: 'http://192.168.31.91:2022/live/test110.flv'));
// runApp(VideoScreen(url: 'http://192.168.31.91:2022/live/livestream-trans.flv'));
}
class VideoScreen extends StatefulWidget {
final String url;
VideoScreen({required this.url});
_VideoScreenState createState() => _VideoScreenState();
}
class _VideoScreenState extends State<VideoScreen> {
final FijkPlayer player = FijkPlayer();
_VideoScreenState();
void initState() {
super.initState();
player.setDataSource(widget.url, autoPlay: true);
// 解决播放延迟
// player.setOption(FijkOption.playerCategory, "fflags", 'nobuffer');
// player.setOption(FijkOption.playerCategory, "fast", 1);
player.setOption(FijkOption.playerCategory, "framedrop", 1);
// player.setOption(FijkOption.playerCategory, "framedrop", 5);
// player.setOption(FijkOption.playerCategory, "start-on-prepared", 1);
// player.setOption(FijkOption.formatCategory, "max-buffer-size", 0);
// player.setOption(FijkOption.playerCategory, "packet-buffering", 0);
player.setOption(FijkOption.formatCategory, "analyzeduration", 1);
// player.setOption(FijkOption.formatCategory, "analyzemaxduration", 100);
// player.setOption(FijkOption.formatCategory, "rtsp_transport", 'tcp');
// player.setOption(FijkOption.formatCategory, "probesize", 100);
// player.setOption(FijkOption.formatCategory, "flush_packets", 0);
// player.setOption(FijkOption.playerCategory, "reconnect", 5);
}
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.from(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.red,
brightness: Brightness.light,
),
useMaterial3: true,
),
home: Scaffold(
appBar: AppBar(
title: const Text('测试视频流播放'),
),
body: Builder(
builder: (context) {
return Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () {
// player.dispose();
player.reset();
player.setDataSource(widget.url, autoPlay: true);
// player.start();
},
icon: Icon(Icons.not_started),
color: Colors.green,
),
IconButton(
onPressed: () {
player.stop();
},
icon: Icon(Icons.stop),
color: Colors.red,
),
IconButton(
onPressed: () {
var playable = player.isPlayable();
print('playable: ${playable}');
showSnackBar('playable: ${playable}', context: context);
},
icon: Icon(Icons.safety_check),
color: Colors.blueAccent,
),
],
),
FijkView(
player: player,
width: 400,
height: 300,
),
]);
},
),
),
);
}
void dispose() {
super.dispose();
player.release();
}
void showSnackBar(String text, {required BuildContext context}) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(text, style: const TextStyle(fontSize: 12))),
);
}
}