Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I use image_picker record video, But I want to limit the time of the video

Tags:

flutter

I developed video recording using image_picker. We need to limit video recording time.

pubspec.yaml dependencies: 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;
    }
});

I want to set the recording time before I turn on the camera. What should I do?

like image 794
Coding24h Avatar asked Nov 01 '25 19:11

Coding24h


2 Answers

@Coding24h:

The following is the dart file that capture video and play video, explanation:

  1. The Import Self Darts:

dart files written by me:

(1) 'GlobalVariables.dart' - contains a class 'gv' with static variables that can be accessed by all 'Pages/Widgets'

(2) 'LangStrings.dart' - this app is multi-languages, this dart files contains Strings in different languages (English, Chinese ......)

(3) 'ScreenVariables.dart' - contains all screen related variables such as orientation, height, width, physical height, devicepixelratio ......

(4) 'Utilities.dart' - contains 'utilities functions' that can be used by all 'Pages', for example, display a toast message whenever and whereever you want.

  1. The InitState() Method: this is where the camera control is declared and initialized.

  2. The dispose() Method: The video recording will be stopped manually when: (1) The user click the 'Stop' buttun, or (2) The user leave this page. The video recording will also be stopped automatically when the user switch to another app or turn off the screen of the mobile phone. In either case, you should dispose the camera Control object inside dispose()

  3. didChangeAppLifecycleState() Method: Pause Video playing if the app goes background.

  4. funTimerVideo() Method: A timer that change the position of the 'Slider' per second. (You can create another timer to stop the video recording if that user has a recording limit)

  5. funSelectVideo() Method: Select videos from the gallery.

  6. funCameraStart() Method: Start capture a picture 'for future preview', then start capture video

  7. funCameraStop() Method: Stop capture video, you can call this method if: (1) The user press the 'Video Recording Stop' button, or (2) The 'another timer' I mentioned in 'funTimerVideo' calls this method when the recording limit exceeded.

Screen Capture (Video Player and Capture Screen):

enter image description here

Program Source Code (For the Video Player and Capture Page ONLY):

// 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();
    }
  }
}

like image 196
Kenneth Li Avatar answered Nov 04 '25 11:11

Kenneth Li


FYI: Today we have this feature implemented directly on image_picker package since version 0.6.5. You just need to set de property maxDuration with a Duration object.

final video = await ImagePicker().pickVideo(
      source: ImageSource.camera,
      maxDuration: Duration(seconds: 30),
      preferredCameraDevice: CameraDevice.front,
    );
like image 20
ricardogobbo Avatar answered Nov 04 '25 09:11

ricardogobbo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!