saveTrimmedVideo method

Future<String> saveTrimmedVideo({
  1. required double startValue,
  2. required double endValue,
  3. bool applyVideoEncoding = false,
  4. FileFormat? outputFormat,
  5. String? ffmpegCommand,
  6. String? customVideoFormat,
  7. int? fpsGIF,
  8. int? scaleGIF,
  9. String? videoFolderName,
  10. String? videoFileName,
  11. StorageDir? storageDir,
})

Saves the trimmed video to file system.

Returns the output video path

The required parameters are startValue & endValue.

The optional parameters are videoFolderName, videoFileName, outputFormat, fpsGIF, scaleGIF, applyVideoEncoding.

The @required parameter startValue is for providing a starting point to the trimmed video. To be specified in milliseconds.

The @required parameter endValue is for providing an ending point to the trimmed video. To be specified in milliseconds.

The parameter videoFolderName is used to pass a folder name which will be used for creating a new folder in the selected directory. The default value for it is Trimmer.

The parameter videoFileName is used for giving a new name to the trimmed video file. By default the trimmed video is named as <original_file_name>_trimmed.mp4.

The parameter outputFormat is used for providing a file format to the trimmed video. This only accepts value of FileFormat type. By default it is set to FileFormat.mp4, which is for mp4 files.

The parameter storageDir can be used for providing a storage location option. It accepts only StorageDir values. By default it is set to applicationDocumentsDirectory. Some of the storage types are:

  • temporaryDirectory (Only accessible from inside the app, can be cleared at anytime)

  • applicationDocumentsDirectory (Only accessible from inside the app)

  • externalStorageDirectory (Supports only Android, accessible externally)

The parameters fpsGIF & scaleGIF are used only if the selected output format is FileFormat.gif.

  • fpsGIF for providing a FPS value (by default it is set to 10)

  • scaleGIF for proving a width to output GIF, the height is selected by maintaining the aspect ratio automatically (by default it is set to 480)

  • applyVideoEncoding for specifying whether to apply video encoding (by default it is set to false).

ADVANCED OPTION:

If you want to give custom FFmpeg command, then define ffmpegCommand & customVideoFormat strings. The input path, output path, start and end position is already define.

NOTE: The advanced option does not provide any safety check, so if wrong video format is passed in customVideoFormat, then the app may crash.

Implementation

Future<String> saveTrimmedVideo({
  required double startValue,
  required double endValue,
  bool applyVideoEncoding = false,
  FileFormat? outputFormat,
  String? ffmpegCommand,
  String? customVideoFormat,
  int? fpsGIF,
  int? scaleGIF,
  String? videoFolderName,
  String? videoFileName,
  StorageDir? storageDir,
}) async {
  final String _videoPath = currentVideoFile!.path;
  final String _videoName = basename(_videoPath).split('.')[0];

  String _command;

  // Formatting Date and Time
  String dateTime = DateFormat.yMMMd()
      .addPattern('-')
      .add_Hms()
      .format(DateTime.now())
      .toString();

  // String _resultString;
  String _outputPath;
  String? _outputFormatString;
  String formattedDateTime = dateTime.replaceAll(' ', '');

  debugPrint("DateTime: $dateTime");
  debugPrint("Formatted: $formattedDateTime");

  videoFolderName ??= "Trimmer";

  videoFileName ??= "${_videoName}_trimmed:$formattedDateTime";

  videoFileName = videoFileName.replaceAll(' ', '_');

  String path = await _createFolderInAppDocDir(
    videoFolderName,
    storageDir,
  ).whenComplete(
    () => debugPrint("Retrieved Trimmer folder"),
  );

  Duration startPoint = Duration(milliseconds: startValue.toInt());
  Duration endPoint = Duration(milliseconds: endValue.toInt());

  // Checking the start and end point strings
  debugPrint("Start: ${startPoint.toString()} & End: ${endPoint.toString()}");

  debugPrint(path);

  if (outputFormat == null) {
    outputFormat = FileFormat.mp4;
    _outputFormatString = outputFormat.toString();
    debugPrint('OUTPUT: $_outputFormatString');
  } else {
    _outputFormatString = outputFormat.toString();
  }

  String _trimLengthCommand =
      ' -ss $startPoint -i "$_videoPath" -t ${endPoint - startPoint} -avoid_negative_ts make_zero ';

  if (ffmpegCommand == null) {
    _command = '$_trimLengthCommand -c:a copy ';

    if (!applyVideoEncoding) {
      _command += '-c:v copy ';
    }

    if (outputFormat == FileFormat.gif) {
      fpsGIF ??= 10;
      scaleGIF ??= 480;
      _command =
          '$_trimLengthCommand -vf "fps=$fpsGIF,scale=$scaleGIF:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 ';
    }
  } else {
    _command = '$_trimLengthCommand $ffmpegCommand ';
    _outputFormatString = customVideoFormat;
  }

  _outputPath = '$path$videoFileName$_outputFormatString';

  _command += '"$_outputPath"';

  await _flutterFFmpeg.execute(_command).whenComplete(() {
    debugPrint('Got value');
    debugPrint('Video successfuly saved');
    // _resultString = 'Video successfuly saved';
  }).catchError((error) {
    debugPrint('Error');
    // _resultString = 'Couldn\'t save the video';
    debugPrint('Couldn\'t save the video');
  });

  return _outputPath;
}