Flutter视频播放插件flutter_ffplay的使用
Flutter视频播放插件flutter_ffplay的使用
flutter_ffplay
是一个基于 ffmpeg
的视频播放器。
开始使用
此项目是一个使用 ffmpeg
的视频播放器。目前插件支持Android和Windows平台。欢迎在其他平台上引入并使用它。
编译ffmpeg
在使用此插件之前,你需要先编译 ffmpeg
。
对于Android,构建脚本会使用 ANDROID_NDK_HOME
来查找Android NDK。
对于Windows,你需要使用 msys2
和 msvc
,或者使用 mingw64
工具链在Linux上构建。
对于 msys2
,你应该在调用 cxx/build.sh
之前设置 vcvarsall
。例如:
set MSYS2_PATH_TYPE=inherit
call "D:\Apps\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x64
"D:\Apps\msys64\usr\bin\bash.exe" --login cxx/build.sh
基础使用
首先,你需要创建一个 IOHandler
的实例。这里提供了一个 http
协议的示例代码位于 example/lib/iohandler.dart
:
final ioHandler = HttpIOHandler();
接着,创建一个 Playback
实例来保存播放信息。可以传递一个 onFrame
回调来获取当前播放位置:
final playback = await Playback.create(onFrame: (pts) {
setState(() {
if (pts == null) {
_isPlaying = false;
} else {
_isPlaying = true;
_position = _isSeeking ? _position : pts;
}
});
});
Playback
实例有 textureId
和 aspectRatio
参数,用户可以用这些参数来创建 TextureView
:
AspectRatio(
aspectRatio: playback.aspectRatio,
child: Texture(textureId: playback.textureId),
)
然后,创建 FFMpegContext
:
final ctx = FFMpegContext(url, ioHandler, playback);
接下来,调用 getStream
方法来获取 FFMpegContext
的信息:
final streams = await ctx.getStreams();
最后,使用包含 FFMpegStream
列表的 play
方法来开始播放:
await ctx.play(streams);
集成到其他平台
除了播放部分,dart
和 ffmpeg
之间的交互通过 ffi
实现。要将此插件集成到其他平台,你需要使用你的平台代码编译 cxx/ffi.cpp
,并将库路径添加到 ffi.dart
。还需要实现 flutter_ffplay
方法通道来完成播放功能。
完整示例代码
以下是一个完整的示例代码,展示了如何使用 flutter_ffplay
插件:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_ffplay/flutter_ffplay.dart';
import 'iohandler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _controller = TextEditingController(
text: 'http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8',
);
FFMpegContext? _ctx;
Playback? _playback;
final ioHandler = HttpIOHandler();
bool _isPlaying = false;
int _duration = 0;
int _position = 0;
bool _isSeeking = false;
String parseHHMMSS(int pts) {
final sec = pts ~/ AV_TIME_BASE;
final min = sec ~/ 60;
final hour = min ~/ 60;
String ret = (min % 60).toString().padLeft(2, '0') +
':' +
(sec % 60).toString().padLeft(2, '0');
if (hour == 0) return ret;
return '$hour:$ret';
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Material(
type: MaterialType.canvas,
child: SafeArea(
child: Column(children: [
Row(
children: [
const SizedBox(width: 8),
Expanded(
child: TextField(
controller: _controller,
),
),
TextButton(
child: const Text("加载"),
onPressed: () async {
if (_ctx != null) {
final ctx = _ctx;
_ctx = null;
await ctx?.close();
}
final url = _controller.text;
final playback =
_playback ??= await Playback.create(onFrame: (pts) {
setState(() {
if (pts == null) {
_isPlaying = false;
} else {
_isPlaying = true;
_position = _isSeeking ? _position : pts;
}
});
});
final ctx = _ctx = FFMpegContext(
url,
ioHandler,
playback,
);
final streams = await ctx.getStreams();
_duration = await ctx.getDuration();
await ctx.play(streams);
setState(() {});
},
),
],
),
Expanded(
child: (_playback?.textureId ?? -1) != -1
? Center(
child: AspectRatio(
aspectRatio: _playback!.aspectRatio,
child: Texture(textureId: _playback!.textureId),
))
: const SizedBox()),
Row(
children: [
IconButton(
icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow),
onPressed: () async {
_isPlaying ? _ctx?.pause() : _ctx?.resume();
},
),
Expanded(
child: Slider(
value: max(
0, min(_position.toDouble(), _duration.toDouble())),
max: max(0, _duration.toDouble()),
onChanged: (pos) {
_isSeeking = true;
setState(() {
_position = pos.toInt();
});
},
onChangeEnd: (pos) async {
await _ctx?.seekTo(pos.toInt());
_isSeeking = false;
}),
),
Text(_duration < 0
? parseHHMMSS(_position)
: "${parseHHMMSS(_position)}/${parseHHMMSS(_duration)}"),
const SizedBox(width: 8),
],
),
]),
),
),
);
}
}
更多关于Flutter视频播放插件flutter_ffplay的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter视频播放插件flutter_ffplay的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
flutter_ffplay
是一个基于 FFmpeg 的 Flutter 视频播放插件,支持多种视频格式和协议。它使用了 FFmpeg
作为底层引擎,因此能够处理更多的视频格式和编解码器。以下是如何使用 flutter_ffplay
插件来播放视频的步骤。
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 flutter_ffplay
依赖:
dependencies:
flutter:
sdk: flutter
flutter_ffplay: ^0.3.0 # 请使用最新版本
然后运行 flutter pub get
来获取依赖。
2. 导入插件
在你的 Dart 文件中导入 flutter_ffplay
插件:
import 'package:flutter_ffplay/flutter_ffplay.dart';
3. 初始化播放器
创建一个 FFPlayerController
实例,并初始化它。
FFPlayerController _controller = FFPlayerController();
@override
void initState() {
super.initState();
_controller.initialize().then((_) {
setState(() {});
});
}
4. 播放视频
使用 _controller
来播放视频。你可以通过 setDataSource
方法来设置视频源,然后调用 start
方法开始播放。
void _playVideo() async {
await _controller.setDataSource(
"https://www.example.com/path/to/your/video.mp4",
isNetwork: true,
);
_controller.start();
}
5. 显示视频
使用 FFPlayer
widget 来显示视频:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter FFPlay Example'),
),
body: Center(
child: _controller.isInitialized
? FFPlayer(controller: _controller)
: CircularProgressIndicator(),
),
floatingActionButton: FloatingActionButton(
onPressed: _playVideo,
child: Icon(Icons.play_arrow),
),
);
}
6. 控制播放
你可以使用 _controller
来控制视频的播放、暂停、停止等操作:
void _pauseVideo() {
_controller.pause();
}
void _stopVideo() {
_controller.stop();
}
void _seekTo(int milliseconds) {
_controller.seekTo(milliseconds);
}
7. 释放资源
在页面销毁时,记得释放播放器资源:
@override
void dispose() {
_controller.dispose();
super.dispose();
}
8. 处理事件
你可以监听播放器的事件,如播放完成、错误等:
_controller.onPlayerStateChanged.listen((state) {
if (state == FFPlayerState.completed) {
print("Playback completed");
} else if (state == FFPlayerState.error) {
print("Error occurred during playback");
}
});