本人做视频监控项目的时候,需要去展示视频流到用户端,一开始使用flutter自带的VideoPlayer播放监控视频,一开始没有发现有什么问题,因为使用多的是Android模拟器,一直没有使用iso模拟器或者真机测试能不能播放,直到开发接近尾声,在ios模拟器上测试的时候发现了问题,视频流为H264的时候能正常播放,但是视频流为H265的时候一直转圈,模拟器和真机播放不了(Android模拟器和真机都是可以播放的)。后来就打算换一个三方插件来调整播放。
- 在pubspec.yaml导入引用的fijkplayer插件
# 视频解码器 软解码
fijkplayer: ^0.10.1
- 状态详解
状态名 |
播放器表现 |
idle |
闲置状态,刚完成构造的 FijkPlayer 处于此状态。 此状态下播放器占用少量内存,无额外线程启动。 idle 状态只能通过 setDataSource 转换为 initialized 状态 |
initialized |
初始化完成状态,和 idle 状态相比,仅是多了输入媒体数据源的信息。 同样无额外线程打开。 |
asyncPreparing |
异步准备状态,在 initialized 状态调用 prepareAsync 到达此状态。 这不是一个稳定状态,此状态等待特定任务完成后自动转化为 prepared 状态。 这一状态的主要准备工作是 探测媒体文件类型,打开媒体文件,打开解码器以及新建解码线程,新建数据 read 线程,打开音频输出设备,新建视频输出线程等。 |
prepared |
asyncPreparing 完成指定任务后自动转化为此状态。 此状态下已经开始缓冲解码了一部分音视频数据,可以随时进行播放。 |
started |
媒体(视频、音频)正在播放中。 |
paused |
媒体(视频、音频)播放暂停。 |
completed |
媒体(视频、音频)播放完成。 可重新从头开始播放。 |
stopped |
播放器各种线程占用资源都已经释放。 音频设备关闭。 |
end |
播放器中所有需要手动释放的内存都释放完成。 处于此状态的播放器只能等待垃圾回收进行内存释放。 |
error |
播放器出现错误。 |
- 简单使用代码如下
import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/material.dart';
class VideoScreen extends StatefulWidget {
final String url;//视频地址
VideoScreen({@required this.url});
@override
_VideoScreenState createState() => _VideoScreenState();
}
class _VideoScreenState extends State<VideoScreen> {
final FijkPlayer player = FijkPlayer();
_VideoScreenState();
@override
void initState() {
super.initState();
//传入视频地址,视频是否自动播放
player.setDataSource(widget.url, autoPlay: true);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("视频监控")),
body: Container(
alignment: Alignment.center,
child: FijkView(
player: player,
),
));
}
@override
void dispose() {
super.dispose();
player.release();
}
}
- 使用后能够正常播放,但是你发现UI界面太丑了,或者功能不够自己使用,需要更多的功能使用才行,别急!三方提供者早就想到了这里,所以提供了可以自己定的UI界面设置。需要修改panelBuilder更改UI界面,废话不多说,上代码。 首先加入自定的UI界面代码
class CustomFijkPanel extends StatefulWidget {
final FijkPlayer player;
final BuildContext buildContext;
final Size viewSize;
final Rect texturePos;
const CustomFijkPanel({
@required this.player,
this.buildContext,
this.viewSize,
this.texturePos,
});
@override
_CustomFijkPanelState createState() => _CustomFijkPanelState();
}
class _CustomFijkPanelState extends State<CustomFijkPanel> {
FijkPlayer get player => widget.player;
bool _playing = false;
@override
void initState() {
super.initState();
widget.player.addListener(_playerValueChanged);
}
void _playerValueChanged() {
FijkValue value = player.value;
bool playing = (value.state == FijkState.started);
if (playing != _playing) {
setState(() {
_playing = playing;
});
}
}
@override
Widget build(BuildContext context) {
Rect rect = Rect.fromLTRB(
max(0.0, widget.texturePos.left),
max(0.0, widget.texturePos.top),
min(widget.viewSize.width, widget.texturePos.right),
min(widget.viewSize.height, widget.texturePos.bottom));
return Positioned.fromRect(
rect: rect,
child: Container(
alignment: Alignment.bottomLeft,
child: IconButton(
icon: Icon(
_playing ? Icons.pause : Icons.play_arrow,
color: Colors.white,
),
onPressed: () {
_playing ? widget.player.pause() : widget.player.start();
},
),
),
);
}
@override
void dispose() {
super.dispose();
player.removeListener(_playerValueChanged);
}
}
这里是使用时候的代码
FijkView(
player: player,
panelBuilder: (FijkPlayer player, FijkData data, BuildContext context, Size viewSize, Rect texturePos) {
return CustomFijkPanel(
player: player,
buildContext: context,
viewSize: viewSize,
texturePos: texturePos);
},
)
到这里就完成了,简单使用、自定义使用,如果还需要看详细信息,可参考他们提供的官方文档,地址如下:fijkplayer -- Flutter plugin for ijkplayer - fijkplayer -- Flutter plugin for ijkplayer