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))),);}
}