本人做视频监控项目的时候,需要去展示视频流到用户端,一开始使用flutter自带的VideoPlayer播放监控视频,一开始没有发现有什么问题,因为使用多的是Android模拟器,一直没有使用iso模拟器或者真机测试能不能播放,直到开发接近尾声,在ios模拟器上测试的时候发现了问题,视频流为H264的时候能正常播放,但是视频流为H265的时候一直转圈,模拟器和真机播放不了(Android模拟器和真机都是可以播放的)。后来就打算换一个三方插件来调整播放。
- # 视频解码器 软解码
- 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();
- }
- }
- 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