saveTrimmedVideo method
- required double startValue,
- required double endValue,
- required dynamic onSave(
- String outputPath
- bool applyVideoEncoding = false,
- FileFormat? outputFormat,
- String? ffmpegCommand,
- String? customVideoFormat,
- int? fpsGIF,
- int? scaleGIF,
- String? videoFolderName,
- String? videoFileName,
- StorageDir? storageDir,
Saves the trimmed video to file system.
The required parameters are startValue
, endValue
& onSave
.
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 @required
parameter onSave
is a callback Function that helps to
retrieve the output path as the FFmpeg processing is complete. Returns a
String
.
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 onlyAndroid
, 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 to10
) -
scaleGIF
for proving a width to output GIF, the height is selected by maintaining the aspect ratio automatically (by default it is set to480
) -
applyVideoEncoding
for specifying whether to apply video encoding (by default it is set tofalse
).
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<void> saveTrimmedVideo({
required double startValue,
required double endValue,
required Function(String outputPath) onSave,
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(' ', '');
String formattedDateTime2 = formattedDateTime.replaceAll(',', '');
debugPrint("DateTime: $dateTime");
debugPrint("Formatted: $formattedDateTime");
videoFolderName ??= "Trimmer";
videoFileName ??= "${_videoName}_trimmed:$formattedDateTime2";
videoFileName = videoFileName.replaceAll(' ', '_');
String path = await _createFolderInAppDocDir(
videoFolderName,
storageDir,
).whenComplete(
() => debugPrint("Retrieved Trimmer folder"),
);
print("path hasil ==> ${path}");
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.toFormatString();
}
String _trimLengthCommand = ' -ss $startPoint -i "$_videoPath" -t ${endPoint - startPoint} -avoid_negative_ts make_zero -movflags faststart';
//-s 540x960
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"';
print("command ${_command}");
FFmpegKit.executeAsync(_command, (session) async {
final state =
FFmpegKitConfig.sessionStateToString(await session.getState());
final returnCode = await session.getReturnCode();
debugPrint("FFmpeg process exited with state $state and rc $returnCode");
if (ReturnCode.isSuccess(returnCode)) {
debugPrint("FFmpeg processing completed successfully.");
debugPrint('Video successfuly saved');
onSave(_outputPath);
} else {
debugPrint("FFmpeg processing failed.");
debugPrint('Couldn\'t save the video');
onSave("");
}
});
// return _outputPath;
}