BccmPlayer - a flutter video player package
This is a video player primarily designed for video-heavy apps that need features like background playback, PiP, casting, analytics, etc.
Used by the open source apps Bible Kids and BCC Media. (source code here).
_
Documentation
For all the features to work correctly, it's vital that you read the docs.
Documentation: https://bcc-code.github.io/bccm-player/
Create an issue on github if you need help.
Difference from video_player/chewie/betterplayer, etc.
A major difference is that BccmPlayer uses hybrid composition platform views to display the video instead of textures. This means the video is rendered in the native view hierarchy without any intermediate steps, which has several benefits:
- Native video performance
- Subtitles are rendered by the native player (avplayer/exoplayer)
- Can use native controls (
showControls
on VideoPlatformView)
Platforms
x
iOSx
AndroidWeb. Some groundwork is there, but it's not complete and it's not supported.
Features
x
Native video via hybrid compositionx
HLS, DASH, MP4 (anything exoplayer and avplayer supports)x
Chromecastx
Background playbackx
Picture in picturex
Notification centerx
Audio track selectionx
Subtitle track selectionx
Fullscreenx
NPAW/Youbora analyticsx
Metadatax
HDR content (read HDR in the docs)
Example
import 'package:bccm_player/bccm_player.dart';
import 'package:flutter/material.dart';
class SimplePlayer extends StatefulWidget {
const SimplePlayer({super.key});
@override
State<SimplePlayer> createState() => _SimplePlayerState();
}
class _SimplePlayerState extends State<SimplePlayer> {
late BccmPlayerController playerController;
@override
void initState() {
// You can also use the global "primary" controller: BccmPlayerController.primary;
// The primary player has superpowers like notification player, background playback, casting, etc.
playerController = BccmPlayerController(
MediaItem(
url: 'https://devstreaming-cdn.apple.com/videos/streaming/examples/adv_dv_atmos/main.m3u8',
mimeType: 'application/x-mpegURL',
metadata: MediaMetadata(title: 'Apple advanced (HLS/HDR)'),
),
);
playerController.initialize().then((_) => playerController.setMixWithOthers(true)); // if you want to play together with other videos
super.initState();
}
@override
void dispose() {
playerController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ListView(
children: [
Column(
children: [
BccmPlayerView(
playerController,
//config: BccmPlayerViewConfig()
),
ElevatedButton(
onPressed: () {
playerController.setPrimary();
},
child: const Text('Make primary'),
),
ElevatedButton(
onPressed: () {
final currentMs = playerController.value.playbackPositionMs;
if (currentMs != null) {
playerController.seekTo(Duration(milliseconds: currentMs + 20000));
}
},
child: const Text('Skip 20 seconds'),
),
],
),
],
);
}
}
Contributing
Thank you for the interest in contributing! We want to improve the codebase so that it's usable for others too, so we are very open for PRs and issues. The docs has a page about architecture details to help you understand the codebase.
Before starting on a bigger change it might be a good idea to create an issue about your ideas so that we can help you out and become aligned.