flutter_hls_video_player
Flutter 애플리케이션용으로 매우 사용자 정의가 가능하고 효율적인 HLS(m3u8) 비디오 플레이어입니다. 적응형 비트레이트, 사용자 지정 UI 컨트롤 및 안드로이드 및 iOS에서 원활한 스트리밍을 지원합니다.
무중단 HTTP 라이브 스트리밍(HLS) 재생을 위한 플러터 HLS 비디오 플레이어입니다. 적응형 비트레이트, 사용자 정의 UI 컨트롤 및 안드로이드 및 iOS에서 원활한 성능을 지원합니다.
{"sdk":"flutter"}^6.1.5{"sdk":"flutter"}^4.0.0아래는 영문 원문 스냅샷입니다. 최신 내용은 GitHub에서 확인하세요.
Flutter HLS Video Player is a highly customizable and efficient m3u8 video player for Flutter applications, enabling seamless HLS (HTTP Live Streaming) playback. It offers adaptive quality selection, smooth streaming, and interactive controls, providing an optimal viewing experience across iOS and Android devices.
Add the dependency in your pubspec.yaml:
dependencies:
flutter_hls_video_player: latest_version
Run:
flutter pub get
Check out the player in action:
Portrait GIF
Check out the player in action:
Landscape GIF
import 'package:flutter/material.dart';
import 'package:flutter_hls_video_player/controller/flutter_hls_video_player_controller.dart';
import 'package:flutter_hls_video_player/view/flutter_hls_video_player.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_hlf_video_player/flutter_hls_video_player/controller/flutter_hls_video_controls.dart';
import 'package:flutter_hlf_video_player/flutter_hls_video_player/controller/flutter_hls_video_player_controller.dart';
import 'package:flutter_hlf_video_player/flutter_hls_video_player/controller/flutter_hls_video_player_state.dart';
import 'package:flutter_hlf_video_player/flutter_hls_video_player/view/flutter_hls_video_player.dart';
class HomeView extends StatefulWidget {
const HomeView({super.key});
@override
State<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
List<String> demoM3u8VideoUrls = [
"https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8",
"https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8",
"https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8",
"https://cph-p2p-msl.akamaized.net/hls/live/2000341/test/master.m3u8",
"https://moctobpltc-i.akamaihd.net/hls/live/571329/eight/playlist.m3u8",
"http://d3rlna7iyyu8wu.cloudfront.net/skip_armstrong/skip_armstrong_stereo_subs.m3u8 "
];
ValueNotifier<int> activeVideoIndexValueNotifier = ValueNotifier(-1);
FlutterHLSVideoPlayerController flutterHLSVideoPlayerController =
FlutterHLSVideoPlayerController();
@override
void initState() {
Future.delayed(const Duration(seconds: 3), () {
_playVideoFromList(0);
});
super.initState();
}
void _playVideoFromList(int index) {
activeVideoIndexValueNotifier.value = index;
flutterHLSVideoPlayerController.loadHlsVideo(demoM3u8VideoUrls[index]);
flutterHLSVideoPlayerController.play();
}
void _showPopupMenu({required BuildContext mContext}) {
final RenderBox overlay =
Overlay.of(context).context.findRenderObject() as RenderBox;
FlutterHLSVideoPlayerState videoState =
flutterHLSVideoPlayerController.initialState;
showMenu(
context: mContext,
position: RelativeRect.fromLTRB(overlay.size.width - 50, 100, 10, 0),
items: [
PopupMenuItem(
child: Column(
mainAxisSize: MainAxisSize.min,
children: List.generate((videoState.availableQualities ?? []).length,
(index) {
return ListTile(
selected: videoState.currentQuality == index,
title: Text(
videoState.availableQualities![index]['height'] == "Auto"
? videoState.availableQualities![index]['height']
: "${videoState.availableQualities![index]['height']} P",
style: TextStyle(
fontWeight: videoState.currentQuality == index
? FontWeight.bold
: null),
),
onTap: () {
flutterHLSVideoPlayerController
.changeQuality(index == 0 ? -1 : index);
Navigator.pop(context);
},
);
}),
)),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child: StreamBuilder<FlutterHLSVideoPlayerState>(
stream: flutterHLSVideoPlayerController.stateStream,
builder: (mContext, snapshot) {
bool isFullScreen =
(snapshot.data != null && snapshot.data!.fullScreen);
// Video Player
return Stack(
children: [
// Video Background UI For Portrate
if (isFullScreen == false)
Column(
children: [
AspectRatio(
aspectRatio: 16 / 9,
child: Container(
color: Colors.black,
),
),
// Body Content
Expanded(
child: ValueListenableBuilder<int>(
valueListenable: activeVideoIndexValueNotifier,
builder: (context, activeIndex, _) {
return ListView.builder(
itemCount: demoM3u8VideoUrls.length,
itemBuilder: (context, index) {
return ListTile(
onTap: () {
_playVideoFromList(index);
},
title: Text(
demoM3u8VideoUrls[index],
style: TextStyle(
color: activeIndex == index
? Theme.of(context)
.primaryColor
: Colors.white,
),
),
);
});
}))
],
),
FlutterHLSVideoPlayer(
controller: flutterHLSVideoPlayerController,
controls: FlutterHLSVideoPlayerControls(
hideBackArrowWidget: true,
onTapArrowBack: () {},
onTapSetting: () {
_showPopupMenu(mContext: context);
},
),
),
],
);
}),
),
);
}
@override
void dispose() {
flutterHLSVideoPlayerController.dispose();
super.dispose();
}
}
Add the following permissions in Info.plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>IOSWebViewOptions</key>
<dict>
<key>AllowsInlineMediaPlayback</key>
<true/>
<key>MediaTypesRequiringUserActionForPlayback</key>
<string>None</string>
</dict>
<key>NSAllowsArbitraryLoadsForMedia</key>
<true/>
Add the following permissions in AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
⚠ Supports only m3u8 URLs for HLS streaming. Other formats are not supported..
On iOS Simulators and Android Emulators, the player may not function correctly. Please use a physical device for accurate testing
Have suggestions or found a bug? Open an issue or submit a pull request on GitHub. Let's build a better player together!
This project is licensed under the MIT License.