flutter_player 0.0.1 flutter_player: ^0.0.1 copied to clipboard
A new flutter plugin project.
example/lib/main.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_player/texture.dart';
import 'package:flutter_player/ffmpeg.dart';
import 'torrent.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
FlutterTexture _texture = FlutterTexture();
TextEditingController _controller = TextEditingController(
text:
'D:/Downloads/System/1df02ba030c3d9102246cc2bbd31911f213814b5.torrent',
);
IsolateFormatContext _ctx;
bool _isPlaying = false;
int _duration = 0;
int _position = 0;
bool seeking = false;
List<int> absentPieces;
int piecesCount;
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
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Material(
type: MaterialType.canvas,
child: Column(children: [
Row(
children: [
SizedBox(width: 8),
Expanded(
child: TextField(
controller: _controller,
),
),
TextButton(
child: Text("load"),
onPressed: () async {
if (_ctx != null) {
await _texture.resetBuffer();
await _ctx.close();
}
int buffer = 0;
final url = _controller.text;
final request = await TorrentRequest.open(url, (torrent) {
setState(() {
absentPieces = torrent.absentPieces();
piecesCount = torrent.pieceCount;
});
});
_ctx = IsolateFormatContext(url, request: request,
onFrame: (frame) {
if (frame == null) {
setState(() {
_isPlaying = false;
});
return;
}
if (buffer == 0 && (frame.buffer?.address ?? 0) != 0) {
buffer = frame.buffer.address;
_texture.attatchBuffer(
frame.buffer, frame.width, frame.height);
} else if (frame.buffer?.address == buffer) {
_texture.onFrame();
}
setState(() {
_isPlaying = true;
_position = seeking ? _position : frame.timeStamp;
});
});
final ctx = _ctx;
final streams = await ctx.getStreams();
final playStream = <IsolateFfmpegStream>[];
final astream = streams.firstWhere(
(infos) =>
infos.codecType == AVMediaType.AVMEDIA_TYPE_AUDIO,
orElse: () => null);
if (astream != null) playStream.add(astream);
final vstream = streams.firstWhere(
(infos) =>
infos.codecType == AVMediaType.AVMEDIA_TYPE_VIDEO,
orElse: () => null);
if (vstream != null) playStream.add(vstream);
_duration = await ctx.duration();
await ctx.play(playStream);
},
),
],
),
Expanded(
child: Stack(
children: [
FutureBuilder(
future: _texture.getTextureId(),
builder: (ctx, snapshot) {
if (snapshot.data == null) return Container();
return Texture(textureId: snapshot.data);
},
)
],
),
),
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) {
seeking = true;
setState(() {
_position = pos.toInt();
});
},
onChangeEnd: (pos) async {
await _ctx?.seekTo(pos.toInt());
seeking = false;
}),
),
Text("${parseHHMMSS(_position)}/${parseHHMMSS(_duration)}"),
SizedBox(width: 8),
],
),
Wrap(
children: List.generate(
piecesCount ?? 0,
(index) => Container(
width: 4,
height: 4,
margin: EdgeInsets.all(1),
color: absentPieces?.contains(index) == true
? Colors.grey
: Colors.green,
)),
),
]),
),
);
}
}