|
1 |
| -// Copyright 2013 The Flutter Authors. All rights reserved. |
2 |
| -// Use of this source code is governed by a BSD-style license that can be |
3 |
| -// found in the LICENSE file. |
4 |
| - |
5 |
| -// ignore_for_file: public_member_api_docs |
6 |
| - |
7 | 1 | import 'package:flutter/material.dart';
|
8 |
| - |
| 2 | +import 'package:video_player_avfoundation/video_player_avfoundation.dart'; |
| 3 | +import 'dart:async'; |
| 4 | +import 'dart:io'; |
| 5 | +import 'package:flutter/material.dart'; |
| 6 | +import 'package:flutter/services.dart'; |
| 7 | +import 'package:video_player_platform_interface/video_player_platform_interface.dart'; |
9 | 8 | import 'mini_controller.dart';
|
10 | 9 |
|
11 | 10 | void main() {
|
12 | 11 | runApp(
|
13 |
| - MaterialApp( |
14 |
| - home: _App(), |
| 12 | + const MaterialApp( |
| 13 | + home: MyVideo(), |
15 | 14 | ),
|
16 | 15 | );
|
17 | 16 | }
|
18 | 17 |
|
19 |
| -class _App extends StatelessWidget { |
20 |
| - @override |
21 |
| - Widget build(BuildContext context) { |
22 |
| - return DefaultTabController( |
23 |
| - length: 2, |
24 |
| - child: Scaffold( |
25 |
| - key: const ValueKey<String>('home_page'), |
26 |
| - appBar: AppBar( |
27 |
| - title: const Text('Video player example'), |
28 |
| - bottom: const TabBar( |
29 |
| - isScrollable: true, |
30 |
| - tabs: <Widget>[ |
31 |
| - Tab( |
32 |
| - icon: Icon(Icons.cloud), |
33 |
| - text: 'Remote', |
34 |
| - ), |
35 |
| - Tab(icon: Icon(Icons.insert_drive_file), text: 'Asset'), |
36 |
| - ], |
37 |
| - ), |
38 |
| - ), |
39 |
| - body: TabBarView( |
40 |
| - children: <Widget>[ |
41 |
| - _BumbleBeeRemoteVideo(), |
42 |
| - _ButterFlyAssetVideo(), |
43 |
| - ], |
44 |
| - ), |
45 |
| - ), |
46 |
| - ); |
47 |
| - } |
48 |
| -} |
| 18 | +class MyVideo extends StatefulWidget { |
| 19 | + const MyVideo({Key? key}) : super(key: key); |
49 | 20 |
|
50 |
| -class _ButterFlyAssetVideo extends StatefulWidget { |
51 | 21 | @override
|
52 |
| - _ButterFlyAssetVideoState createState() => _ButterFlyAssetVideoState(); |
| 22 | + _MyVideoState createState() => _MyVideoState(); |
53 | 23 | }
|
54 | 24 |
|
55 |
| -class _ButterFlyAssetVideoState extends State<_ButterFlyAssetVideo> { |
56 |
| - late MiniController _controller; |
| 25 | +class _MyVideoState extends State<MyVideo> { |
| 26 | + MiniController? _controller; |
57 | 27 |
|
58 | 28 | @override
|
59 | 29 | void initState() {
|
60 | 30 | super.initState();
|
61 |
| - _controller = MiniController.asset('assets/Butterfly-209.mp4'); |
62 |
| - |
63 |
| - _controller.addListener(() { |
64 |
| - setState(() {}); |
65 |
| - }); |
66 |
| - _controller.initialize().then((_) => setState(() {})); |
67 |
| - _controller.play(); |
| 31 | + init(); |
68 | 32 | }
|
69 | 33 |
|
70 | 34 | @override
|
71 | 35 | void dispose() {
|
72 |
| - _controller.dispose(); |
| 36 | + _controller?.dispose(); |
73 | 37 | super.dispose();
|
74 | 38 | }
|
75 | 39 |
|
76 | 40 | @override
|
77 | 41 | Widget build(BuildContext context) {
|
78 |
| - return SingleChildScrollView( |
79 |
| - child: Column( |
80 |
| - children: <Widget>[ |
81 |
| - Container( |
82 |
| - padding: const EdgeInsets.only(top: 20.0), |
83 |
| - ), |
84 |
| - const Text('With assets mp4'), |
85 |
| - Container( |
86 |
| - padding: const EdgeInsets.all(20), |
87 |
| - child: AspectRatio( |
88 |
| - aspectRatio: _controller.value.aspectRatio, |
89 |
| - child: Stack( |
90 |
| - alignment: Alignment.bottomCenter, |
91 |
| - children: <Widget>[ |
92 |
| - VideoPlayer(_controller), |
93 |
| - _ControlsOverlay(controller: _controller), |
94 |
| - VideoProgressIndicator(_controller), |
95 |
| - ], |
| 42 | + return Scaffold( |
| 43 | + appBar: AppBar( |
| 44 | + title: const Text("My Video"), |
| 45 | + ), |
| 46 | + body: Center( |
| 47 | + child: _controller!.value.isInitialized |
| 48 | + ? AspectRatio( |
| 49 | + aspectRatio: _controller!.value.aspectRatio, |
| 50 | + child: VideoPlayer(_controller!), |
| 51 | + ) |
| 52 | + : Container( |
| 53 | + child: const Text('loading...'), |
96 | 54 | ),
|
97 |
| - ), |
98 |
| - ), |
99 |
| - ], |
100 | 55 | ),
|
101 | 56 | );
|
102 | 57 | }
|
103 |
| -} |
104 | 58 |
|
105 |
| -class _BumbleBeeRemoteVideo extends StatefulWidget { |
106 |
| - @override |
107 |
| - _BumbleBeeRemoteVideoState createState() => _BumbleBeeRemoteVideoState(); |
108 |
| -} |
109 |
| - |
110 |
| -class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> { |
111 |
| - late MiniController _controller; |
112 |
| - |
113 |
| - @override |
114 |
| - void initState() { |
115 |
| - super.initState(); |
| 59 | + Future<void> init() async { |
116 | 60 | _controller = MiniController.network(
|
117 |
| - 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4', |
| 61 | + // 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4', |
| 62 | + 'https://service.beta.sanjieke.cn/video/media/11244355/608p.m3u8?user_id=18942194&class_id=33254014&time=1663055202&nonce=868849&token=73daa6bce6e2643a3a9d2f28f3385ce86fa5ec82', |
118 | 63 | );
|
119 | 64 |
|
120 |
| - _controller.addListener(() { |
| 65 | + _controller?.addListener(() { |
121 | 66 | setState(() {});
|
122 | 67 | });
|
123 |
| - _controller.initialize(); |
124 |
| - } |
125 | 68 |
|
126 |
| - @override |
127 |
| - void dispose() { |
128 |
| - _controller.dispose(); |
129 |
| - super.dispose(); |
130 |
| - } |
| 69 | + await _controller?.initialize(); |
131 | 70 |
|
132 |
| - @override |
133 |
| - Widget build(BuildContext context) { |
134 |
| - return SingleChildScrollView( |
135 |
| - child: Column( |
136 |
| - children: <Widget>[ |
137 |
| - Container(padding: const EdgeInsets.only(top: 20.0)), |
138 |
| - const Text('With remote mp4'), |
139 |
| - Container( |
140 |
| - padding: const EdgeInsets.all(20), |
141 |
| - child: AspectRatio( |
142 |
| - aspectRatio: _controller.value.aspectRatio, |
143 |
| - child: Stack( |
144 |
| - alignment: Alignment.bottomCenter, |
145 |
| - children: <Widget>[ |
146 |
| - VideoPlayer(_controller), |
147 |
| - _ControlsOverlay(controller: _controller), |
148 |
| - VideoProgressIndicator(_controller), |
149 |
| - ], |
150 |
| - ), |
151 |
| - ), |
152 |
| - ), |
153 |
| - ], |
154 |
| - ), |
155 |
| - ); |
156 |
| - } |
157 |
| -} |
158 |
| - |
159 |
| -class _ControlsOverlay extends StatelessWidget { |
160 |
| - const _ControlsOverlay({Key? key, required this.controller}) |
161 |
| - : super(key: key); |
162 |
| - |
163 |
| - static const List<double> _examplePlaybackRates = <double>[ |
164 |
| - 0.25, |
165 |
| - 0.5, |
166 |
| - 1.0, |
167 |
| - 1.5, |
168 |
| - 2.0, |
169 |
| - 3.0, |
170 |
| - 5.0, |
171 |
| - 10.0, |
172 |
| - ]; |
173 |
| - |
174 |
| - final MiniController controller; |
175 |
| - |
176 |
| - @override |
177 |
| - Widget build(BuildContext context) { |
178 |
| - return Stack( |
179 |
| - children: <Widget>[ |
180 |
| - AnimatedSwitcher( |
181 |
| - duration: const Duration(milliseconds: 50), |
182 |
| - reverseDuration: const Duration(milliseconds: 200), |
183 |
| - child: controller.value.isPlaying |
184 |
| - ? const SizedBox.shrink() |
185 |
| - : Container( |
186 |
| - color: Colors.black26, |
187 |
| - child: const Center( |
188 |
| - child: Icon( |
189 |
| - Icons.play_arrow, |
190 |
| - color: Colors.white, |
191 |
| - size: 100.0, |
192 |
| - semanticLabel: 'Play', |
193 |
| - ), |
194 |
| - ), |
195 |
| - ), |
196 |
| - ), |
197 |
| - GestureDetector( |
198 |
| - onTap: () { |
199 |
| - controller.value.isPlaying ? controller.pause() : controller.play(); |
200 |
| - }, |
201 |
| - ), |
202 |
| - Align( |
203 |
| - alignment: Alignment.topRight, |
204 |
| - child: PopupMenuButton<double>( |
205 |
| - initialValue: controller.value.playbackSpeed, |
206 |
| - tooltip: 'Playback speed', |
207 |
| - onSelected: (double speed) { |
208 |
| - controller.setPlaybackSpeed(speed); |
209 |
| - }, |
210 |
| - itemBuilder: (BuildContext context) { |
211 |
| - return <PopupMenuItem<double>>[ |
212 |
| - for (final double speed in _examplePlaybackRates) |
213 |
| - PopupMenuItem<double>( |
214 |
| - value: speed, |
215 |
| - child: Text('${speed}x'), |
216 |
| - ) |
217 |
| - ]; |
218 |
| - }, |
219 |
| - child: Padding( |
220 |
| - padding: const EdgeInsets.symmetric( |
221 |
| - // Using less vertical padding as the text is also longer |
222 |
| - // horizontally, so it feels like it would need more spacing |
223 |
| - // horizontally (matching the aspect ratio of the video). |
224 |
| - vertical: 12, |
225 |
| - horizontal: 16, |
226 |
| - ), |
227 |
| - child: Text('${controller.value.playbackSpeed}x'), |
228 |
| - ), |
229 |
| - ), |
230 |
| - ), |
231 |
| - ], |
232 |
| - ); |
| 71 | + _controller?.play(); |
233 | 72 | }
|
234 | 73 | }
|
0 commit comments