kvideo 0.0.2
kvideo: ^0.0.2 copied to clipboard
Flutter Video Player
import 'package:flutter/material.dart';
import 'package:kvideo/kvideo.dart';
final controller = PlayerController(androidViewMode: AndroidViewMode.texture);
final downloader = DownloadManagerApi();
class EventListener implements DownloadEventListener {
@override
void onCompletion(String id, String location) {
print("Completed: $id $location");
}
@override
void onError(String id, String error) {
print("Error: $id $error");
}
@override
void onProgress(String id, int progress) {
print("Progress: $id $progress");
}
@override
void onRemoved(String id) {
print("Removed: $id");
}
}
final urls = [
"https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8",
"https://stream.mux.com/3x5wDUHxkd8NkEfspLUK3OpSQEJe3pom.m3u8?redundant_streams=true",
"https://storage.googleapis.com/gvabox/media/samples/stock.mp4",
];
final ima =
"https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_skip_ad_samples&sz=640x480&cust_params=sample_ar%3Dmidskiponly&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&cmsid=496&vid=short_onecue&correlator=" ??
"https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&correlator=";
void main() async {
WidgetsFlutterBinding.ensureInitialized();
DownloadEventListener.setUp(EventListener());
downloader.removeAll();
// final id = await downloader.download(
// Media(url: urls[1], headers: {"hi": "bro"}),
// null,
// );
// print(id);
controller
.initialize(configuration: PlayerConfiguration(initializeIMA: true))
.then((_) {
// controller.play(
// Media(
// url: urls[2],
// subtitles: [
// "https://gist.githubusercontent.com/matibzurovski/d690d5c14acbaa399e7f0829f9d6888e/raw/63578ca30e7430be1fa4942d4d8dd599f78151c7/example.srt",
// ],
// ),
// );
});
// runApp(Center(child: PlayerView(controller)));
runApp(MaterialApp(home: PlayerScreen(child: PlayerView(controller))));
}
class PlayerScreen extends StatefulWidget {
final Widget child;
const PlayerScreen({super.key, required this.child});
@override
State<PlayerScreen> createState() => _PlayerScreenState();
}
class _PlayerScreenState extends State<PlayerScreen> {
Offset _offset = Offset.zero;
bool show = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("kVideo")),
body: GestureDetector(
child: Stack(
children: [
Align(
child: ValueListenableBuilder(
valueListenable: controller.state.error,
builder: (context, value, child) {
return Text(value ?? "");
},
),
),
FutureBuilder(
future: controller.getTracks(),
builder: (context, snapshot) {
return ListView(
children: [
TextButton(
child: Text("Auto"),
onPressed: () {
controller.setTrackPreference(null);
},
),
for (final track in snapshot.data ?? <TrackData>[])
TextButton(
child: Text(
"${track.type} ${track.height} ${track.label} ${track.language} ${track.bitrate}",
),
onPressed: () {
controller.setTrackPreference(track);
},
),
],
);
},
),
Positioned(
bottom: 8,
right: 40,
child: ElevatedButton(
onPressed: () {
controller.enterPiPMode();
},
child: Text("PIP"),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
FilledButton(
onPressed: () {
controller.setFit(BoxFitMode.fill);
},
child: Text("FILL"),
),
ElevatedButton(
onPressed: () {
setState(() {
show = false;
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
Hero(tag: "v", child: widget.child),
),
).whenComplete(() {
setState(() {
show = true;
});
});
},
child: Text("Hero"),
),
FilledButton(
onPressed: () {
controller.setFit(BoxFitMode.fit);
},
child: Text("FIT"),
),
],
),
),
Positioned(
bottom: 8,
left: 40,
child: ElevatedButton(
onPressed: () {
controller.play(Media(url: urls[1]));
},
child: Text("MUX"),
),
),
Positioned(
bottom: 8,
left: 120,
child: ElevatedButton(
onPressed: () {
controller.play(Media(url: urls[2], imaTagUrl: ima));
},
child: Text("IMA"),
),
),
Positioned(
top: _offset.dy,
left: _offset.dx,
child: SizedBox(
height: 200,
width: 200,
child: Hero(
tag: "v",
child: show ? Center(child: widget.child) : SizedBox(),
),
),
),
],
),
onPanUpdate: (details) {
setState(() {
_offset = Offset(
_offset.dx + details.delta.dx,
_offset.dy + details.delta.dy,
);
});
},
),
);
}
}