我使用image_picker开发了视频录制。我们需要限制视频录制时间。
pubspec.yaml依赖项:image_picker:^ 0.4.10
[flutter] flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel beta, v1.0.1-pre.2, on Mac OS X 10.14.2 18C54, locale zh-Hans-CN) [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) [✓] iOS toolchain - develop for iOS devices (Xcode 10.1) [✓] Android Studio (version 3.0) [✓] IntelliJ IDEA Ultimate Edition (version 2018.1.7) [✓] VS Code (version 1.31.1) [✓] Connected device (2 available) • No issues found! exit code 0 // Open the camera for recording Code ImagePicker.pickVideo(source: ImageSource.camera).then((File file) { if (file != null && mounted) { var tempFile = file; } });
我想在打开相机之前设置录制时间。我 该怎么办?
@ Coding24h:
以下是捕获视频并播放视频的dart文件,说明:
导入自我飞镖: 我写的dart文件:
(1)’GlobalVariables.dart’-包含带有静态变量的类’gv’, 所有“页面/小部件”均可访问
(2)’LangStrings.dart’-此应用程序是多国语言,此dart文件包含 不同语言的字符串(英语,中文......)
(3)’ScreenVariables.dart’-包含所有与屏幕相关的变量,例如 方向,高度,宽度,物理高度,devicepixelratio ......
(4)“ Utilities.dart”-包含可被所有 “页面” 使用的“实用程序功能”,例如,在任何时候,任何地方显示一条祝酒消息。
InitState()方法:在此声明并初始化相机控件。
dispose()方法:在以下情况下,视频录制将手动停止:(1)用户单击“停止”按钮,或者(2)用户离开此页面。当用户切换到另一个应用程序或关闭手机屏幕时,视频录制也会自动停止。无论哪种情况,都应将相机控制对象放置在dispose()中
didChangeAppLifecycleState()方法:如果应用程序进入后台,则暂停视频播放。
funTimerVideo()方法:一个计时器,每秒更改“滑块”的位置。(如果该用户有录制限制,则可以创建另一个计时器来停止视频录制)
funSelectVideo()方法:从图库中选择视频。
funCameraStart()方法:开始捕获图片以备将来预览,然后开始捕获视频
funCameraStop()方法:停止捕获视频,如果出现以下情况,则可以调用此方法:(1)用户按下“视频录制停止”按钮,或者(2)当“ funTimerVideo”中提到的“另一个计时器”调用此方法时,超出记录限制。
程序源代码(仅适用于视频播放器和捕获页面):
// Import Flutter Darts import 'dart:io'; import 'package:camera/camera.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:intl/intl.dart'; import "package:threading/threading.dart"; import 'package:video_player/video_player.dart'; // Import Self Darts import 'GlobalVariables.dart'; import 'LangStrings.dart'; import 'ScreenVariables.dart'; import 'Utilities.dart'; // Import Pages import 'BottomBar.dart'; // Home Page class ClsHome extends StatefulWidget { @override _ClsHomeState createState() => _ClsHomeState(); } class _ClsHomeState extends State<ClsHome> with WidgetsBindingObserver { AppLifecycleState _lastLifecycleState; // Declare Camera CameraController ctlCamera; // Var for Video bool bolVideoPaused = true; @override void initState() { super.initState(); print("Init State Started"); if (gv.bolHomeFirstInit) { // This page is called by navigator.push twice, do nothing on the first call gv.bolHomeFirstInit = false; } else { // Not the first time call of Init, do Init WidgetsBinding.instance.addObserver(this); try { // Try to dispose old Camera Control ctlCamera.dispose(); print("Camera Disposed 1"); } catch (err) { print("Camera Dispose Error: " + err.toString()); } try { // Declare New Camera Control ctlCamera = CameraController(gv.cameras[1], ResolutionPreset.high); ctlCamera.initialize().then((_) { if (!mounted) { ut.showToast('1:' + ls.gs('SystemErrorOpenAgain'), true); return; } setState(() {}); print('Controller Inited'); }); } catch (err) { ut.showToast('2:' + ls.gs('SystemErrorOpenAgain'), true); print("Camera Init Error: " + err.toString()); } try { gv.threadHomeVideo = new Thread(funTimerVideo); gv.threadHomeVideo.start(); print('New Video Timer Started'); } catch (err) { ut.showToast('3:' + ls.gs('SystemErrorOpenAgain'), true); print('New Video Timer Error: ' + err.toString()); } } print("Init State Ended"); } @override void dispose() async { super.dispose(); print("Dispose Started"); if (gv.bolHomeFirstDispose) { gv.bolHomeFirstDispose = false; } else { WidgetsBinding.instance.removeObserver(this); try { await funCameraStop(); ctlCamera?.dispose(); print("Camera Disposed"); } catch (err) { // print("Play Video Dispose Error 1: " + err.toString()); } try { // gv.ctlVideo?.dispose(); gv.ctlVideo.pause(); // gv.threadPageHomeVideo.abort(); // print('Thread Video Aborted'); } catch (err) { // print("Play Video Dispose Error 2: " + err.toString()); } // print('Controller dispose'); } print("Dispose Ended"); } @override void didChangeAppLifecycleState(AppLifecycleState state) { _lastLifecycleState = state; print('***** Life Cycle State: ' + _lastLifecycleState.toString() + ' *****'); if (_lastLifecycleState.toString() == 'AppLifecycleState.paused') { try { if (gv.ctlVideo.value.isPlaying) { bolVideoPaused = true; gv.ctlVideo.pause(); } setState(() {}); } catch (err) { // } } else if (_lastLifecycleState.toString() == 'AppLifecycleState.resumed') { } } // Timer to setState Video Play Position void funTimerVideo() async { while (true) { await Thread.sleep(1000); try { if (gv.ctlVideo.value.isPlaying) { gv.dblHomeVDSliderValueMS = gv.ctlVideo.value.position.inMilliseconds.toDouble(); setState(() {}); } } catch (err) { // Video Not Yet Ready, Do Nothing } } } // Select Video from External Storage funSelectVideo() async { print('Select Video Started'); String filePath = ''; filePath = await FilePicker.getFilePath(type: FileType.VIDEO); if (filePath != '') { try { // Declare Video if a video file is selected gv.ctlVideo = VideoPlayerController.file(File(filePath)) ..initialize().then((_) { // Set Video Looping gv.ctlVideo.setLooping(true); // Get Video Duration in Milliseconds gv.intHomeVDMS = gv.ctlVideo.value.duration.inMilliseconds; setState(() {}); print('Video Inited'); }); } catch (err) { print('Video Init Error: ' + err.toString()); gv.intHomeVDMS = 0; ut.showToast(ls.gs('VideoErrorUnsupport'), true); } } else { print('No Video Selected'); setState(() {}); } print('Select Video Ended'); } // The Widget that show the Video Player Widget ctnVideoPlayer() { try { double dblHeight = sv.dblBodyHeight / 1.8; print('Before Check Video Init'); if (gv.ctlVideo.value.initialized) { print('Before Check Video AspectRatio'); if (gv.ctlVideo.value.aspectRatio < 1) { dblHeight = sv.dblBodyHeight / 1.25; } print('Before Return ctnVideoPlayer'); return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Container( padding: EdgeInsets.fromLTRB(0, 10, 0, 10), height: dblHeight, width: sv.dblScreenWidth, child: Center( child: AspectRatio( aspectRatio: gv.ctlVideo.value.aspectRatio, child: VideoPlayer(gv.ctlVideo), ), ), ), objVideoSlider(), ], ); print('After Return ctnVideoPlayer'); } else { print('Before Return EMPTY ctnVideoPlayer'); return Container( // color: Colors.white, height: dblHeight, width: sv.dblScreenWidth, child: Center( child: Text(ls.gs('SelectVideo')), ), ); print('After Return EMPTY ctnVideoPlayer'); } } catch (err) { print('Page Home ctnVideoPlayer() : ' + err.toString()); return Container( // color: Colors.white, height: sv.dblBodyHeight / 1.8, width: sv.dblScreenWidth, child: Center( child: Text(ls.gs('SelectVideo')), ), ); } } // function when Play or Pause clicked funPlayVideo() async { try { if (gv.ctlVideo.value.initialized) { if (gv.ctlVideo.value.isPlaying) { bolVideoPaused = true; gv.ctlVideo.pause(); // Stop Camera Recording funCameraStop(); } else { bolVideoPaused = false; gv.ctlVideo.play(); // Start Camera Recording funCameraStart(); } setState(() {}); } else { // Do Nothing } } catch (err) { // Do Nothing } } // function when Forward 15 seconds clicked funForwardVideo() async { try { if (gv.ctlVideo.value.initialized) { gv.ctlVideo.seekTo(gv.ctlVideo.value.position + Duration(seconds: 15)); setState(() {}); } else { // Do Nothing } } catch (err) { // Do Nothing } } // function when Backward 15 seconds clicked funBackwardVideo() async { try { if (gv.ctlVideo.value.initialized) { gv.ctlVideo.seekTo(gv.ctlVideo.value.position - Duration(seconds: 15)); setState(() {}); } else { // Do Nothing } } catch (err) { // Do Nothing } } // Widget to show the Slider of the playing position of Video Widget objVideoSlider() { try { if (gv.ctlVideo.value.initialized) { return Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Text(' '), Text(gv.ctlVideo.value.position.inHours.toString() + ":" + (gv.ctlVideo.value.position.inMinutes % 60) .toString() .padLeft(2, '0') + ":" + (gv.ctlVideo.value.position.inSeconds % 60) .toString() .padLeft(2, '0')), Expanded( child: CupertinoSlider( min: 0.0, max: gv.intHomeVDMS.toDouble(), divisions: (gv.intHomeVDMS / 1000).toInt(), value: gv.dblHomeVDSliderValueMS, onChanged: (double dblNewValue) { objVideoSliderChanged(dblNewValue); }, ), ), Text(gv.ctlVideo.value.duration.inHours.toString() + ":" + (gv.ctlVideo.value.duration.inMinutes % 60) .toString() .padLeft(2, '0') + ":" + (gv.ctlVideo.value.duration.inSeconds % 60) .toString() .padLeft(2, '0')), Text(' '), ], ); } else { return Container(); } } catch (err) { return Container(); } } // Function when Slider Changed Manually objVideoSliderChanged(dblNewValue) { gv.dblHomeVDSliderValueMS = dblNewValue; gv.ctlVideo .seekTo(Duration(milliseconds: gv.dblHomeVDSliderValueMS.toInt())); setState(() {}); } // Function Start Camera void funCameraStart() async{ // Declare File Name DateTime dtTimeStamp() => DateTime.now(); String strTimeStamp = DateFormat('yyyyMMdd_kkmmss').format(dtTimeStamp()); String strMovieFile = gv.strMoviePath + '/' + strTimeStamp + '.mp4'; gv.strImageFile = gv.strImagePath + '/' + strTimeStamp; print('File Path: ' + strMovieFile); try { await ctlCamera.takePicture(gv.strImageFile + '_01.jpg'); await ctlCamera.startVideoRecording(strMovieFile); } catch(err) { ut.showToast('4:' + ls.gs('SystemErrorOpenAgain'), true); } } // Function Stop Camera void funCameraStop() async{ try { await ctlCamera.stopVideoRecording(); } catch(err) { // ut.showToast('5:' + ls.gs('SystemErrorOpenAgain'), true); } try { await ctlCamera.takePicture(gv.strImageFile + '_02.jpg'); } catch(err) { // ut.showToast('5:' + ls.gs('SystemErrorOpenAgain'), true); } } // Main Widget @override Widget build(BuildContext context) { try { if (ctlCamera != null) { if (!ctlCamera.value.isInitialized) { print('return Container'); return Container(); } print('Before Return'); return Scaffold( appBar: PreferredSize( child: AppBar( title: Text( ls.gs('Player'), style: TextStyle(fontSize: sv.dblDefaultFontSize), ), ), preferredSize: new Size.fromHeight(sv.dblTopHeight), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ ctnVideoPlayer(), Stack(children: <Widget>[ Container( // color: Colors.white, height: sv.dblBodyHeight / 25, width: sv.dblScreenWidth, child: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Text(' '), AspectRatio( aspectRatio: ctlCamera.value.aspectRatio, child: CameraPreview(ctlCamera), ), ]), ), ), Container( // color: Colors.white, height: sv.dblBodyHeight / 25, width: sv.dblScreenWidth, child: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ RaisedButton( onPressed: () => funSelectVideo(), child: Icon(Icons.folder_open), ), Text(' '), RaisedButton( onPressed: () => funBackwardVideo(), child: Icon(FontAwesomeIcons.angleDoubleLeft), ), Text(' '), RaisedButton( onPressed: () => funPlayVideo(), child: bolVideoPaused ? Icon(Icons.play_arrow) : Icon(Icons.pause), ), Text(' '), RaisedButton( onPressed: () => funForwardVideo(), child: Icon(FontAwesomeIcons.angleDoubleRight), ), ], ), ), ), ]) ]), bottomNavigationBar: ClsBottom(), ); } else { return Container(); } } catch (err) { print('PageHome Error build: ' + err.toString()); return Container(); } } }