kvideo 0.0.22
kvideo: ^0.0.22 copied to clipboard
Flutter Video Player
import 'package:flutter/material.dart';
import 'package:kvideo/gen/pigeon.g.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",
"https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
];
final ima =
"https://ads.deeptoplay.com/fc.php?script=rmVideo&zoneid=594&format=vast3";
// "https://ads.deeptoplay.com/fc.php?script=rmVideo&zoneid=427&format=vast3";
// "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinearvpaid2js&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&correlator=";
// "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());
controller.state.buffer.addListener(() {
print(controller.state.buffer.value.inSeconds);
});
controller.state.pipMode.addListener(() {
print("PiPMode ${controller.state.pipMode.value}");
if (controller.state.pipMode.value == PiPMode.inactive) {
PlayerController.setAutoEnterPiP(true);
}
if (controller.state.pipMode.value == PiPMode.closed) {
PlayerController.setAutoEnterPiP(true);
controller.play(null);
}
// if (WidgetsBinding.instance.lifecycleState != AppLifecycleState.resumed) {
// controller.pause();
// }
});
downloader.removeAll();
// final id = await downloader.download(
// Media(url: urls[1], headers: {"hi": "bro"}),
// null,
// );
// print(id);
PlayerController.setAutoEnterPiP(true);
controller
.initialize(configuration: PlayerConfiguration(initializeIMA: true))
.then((_) {
controller.play(
Media(
url: "",
headers: {
"x-authorization":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiYjNmNzAwN2E4MTNhZDJhYTBiOGVhNzMzMmRmMjkxZTg1OTg4ZDk1NTUwZWUyZjQ5NDg0ZWE3OThkY2MxYTA1ZTc5YjNiZjRhN2U4ZjM5NzgiLCJpYXQiOjE3ODEwMDQxNzEuMjM0MzIzLCJuYmYiOjE3ODEwMDQxNzEuMjM0MzI1LCJleHAiOjE4MTI1NDAxNzEuMjMwMTMzLCJzdWIiOiIxMjIyMzIxODg1NzY3NTk4MDgiLCJwaWQiOiIxMjIyMzIyNTczNjcyMDc5MzYiLCJzY29wZXMiOlsibWFuYWdlX3Byb2ZpbGVzIl19.f2N7urGqflAfkAnsbKxISsFs1g1XEZ2cT8QcbnqB1Pz-oM6EFLDN38qhSEMVEN_mdLPlfZuwk9yw4xBEvOHHM5U3qO8J8dgiXUm8HhuuY1knZ4JLfFMzKRFY_e7Wd6oNNkY_eHZmXdlsLjHl5Sea56wSb15sUBgb7Ri2-NwSAbraUC8K2Cqf-uEQo1WYwTGuluMqET88LmeaJdnI9GpgLQmQ2SFJJ2i2KyTNzEjKMeZwEhFVKjKJ-LmYLT4Q_JWCbl1Kbc_iHOURX8r6ugW_eFlXAbMeJVmMdCq2thtbQMuwIvFraLw_ZTXe7H3gFrcxseVsPHBnnt66V6nujCAFGW-MdrM-nSsDToNPZbf7Djm6p0gwtHXQrS0ZxpYbf1bqcLjx9ETHdCQrjeWmsGPMBFtWFfmvDlR1BDm91h73nSbGsV72SWH-Pc1TOg2cd2jC5vhd4jpsztonR-wTTVI21agjm3LHMq2w1AvKJAUw03yt1Cy3GKKUrZRxBdZYijzOg5U5oJPOjuyksON2xhuXqIMrmxrk7IJCWYtealw8-SdkHJ262W4ToAdtW-pVSumIaJhx8Gs90ArxsN0wRhjTNRBigshwWYbQGJoSES-ESuQfEgDqXiceIOYdRO-O9o-ebGm5TrVS2uk7_bk48dI4PbHVMOQ-ilj8Loe-2JQyKhQ",
},
),
);
});
// 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>
with WidgetsBindingObserver {
Offset _offset = Offset.zero;
bool show = true;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
print("didChangeAppLifecycleState $state");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("kVideo"),
actions: [
IconButton(onPressed: controller.dispose, icon: Text("dispose")),
],
),
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: () {
PlayerController.setAutoEnterPiP(false);
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: 8,
left: 8,
child: ElevatedButton(
onPressed: () {
controller.play(Media(url: urls[3], 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,
);
});
},
),
);
}
}