I am using Flutter-FFMPEG a Flutter library based on Mobile FFMPEG. I am creating a video from a list of .bmp images. The video works plays normally in devices media player on android or desktop.
But when I tried to share that video on social media like say Instagram it says file format not supported.
It didn't use to work on WhatsApp but after some googling, I made some changes and it works on WhatsApp and Youtube now but not on Instagram, Linkedin, etc.
void _runFFmpeg() async {
print('Run FFMPEG');
var dir = await getApplicationDocumentsDirectory();
var output = await getExternalStorageDirectory();
String videoSize = '$ImageWidth:$ImageSize';
print("${ImageWidth}x$ImageSize");
var arguments = [
"-y", // replace output file if it already exists
"-i", "${output.path}/frame_%d.bmp",
"-s", '${ImageWidth}x$ImageSize',
"-framerate", "30", // framrate
"-c:v", "libvpx",
'-ab', '128k',
'-ar', '44100',
'-strict', 'experimental',
"-vcodec", "libx264",
"-pixel_format", "yuv420p",
"-preset", "ultrafast",
"-tune", "animation",
"${output.path}/test.mp4"
];
await _flutterFFmpeg.executeWithArguments(arguments).then((rc) {
print('Process done with $rc');
});
The plugin I am using (Flutter-FFMPEG) didn't support libx264
I tried using '-profile:v' to baseline but that gives an error, saying Error setting profile to baseline.
Also, I tried to first make a .webm file and then convert that to mp4. I was also able to use '-profile:v' when converting .webm to mp4 and gave no error but the output video didn't work on Social Media platforms.
fixFFMPEG(int imageWidth, int imageSize) async {
print('Fix FFMPEG');
var output = await getExternalStorageDirectory();
var arguments2 = [
'-y',
// "-s",
// '${imageWidth}:$imageSize',
'-i',
'${output.path}/testNew.mp4',
"-framerate", "30", // framrate
"-vcodec", "h264",
"-c:v", "libx264rgb",
"-c:a", 'acc',
'-ab', '128k',
'-ar', '44100',
'-strict', 'experimental',
// '-c',
// 'copy',
// '-strict',
// '-2',
"-vprofile",
"baseline",
"-level",
"3.0",
"-an",
"-pixel_format", "yuv420p",
// '-vtag',
// 'avc1',
// "-vprofile",
// "baseline",
// "-level",
// "3.0",
// "-brand", "mp42",
'${output.path}/fixedvideo1.mp4'
];
// await _flutterFFmpeg
// .executeWithArguments(arguments2)
// .then((rc) => print("FFmpeg process2 exited with rc $rc"));
}
Related
I'm trying to connect an audio file to a static image and render it as video containing only the static image and the audio playback, I looked into several pub libraries like this
but haven't found any documentation on how to implement when I'm looking for, is there a simple way to do this? and if not is it possible to accomplish using dart without writing platform specific stuff?
This is what I ended up doing, I hope it helped someone,
in my case I needed to connect an image to an audio file to create a video that can be shared with the share_plus plugin
You don't really have an alternative to ffmpeg, but you can set it up so it isn't so bad to use:
add this to your pubspec.yaml dependencies
ffmpeg_kit_flutter_min_gpl: ^4.5.0-LTS
import those in the files you want to render the video:
import 'package:ffmpeg_kit_flutter_min_gpl/return_code.dart';
import 'package:ffmpeg_kit_flutter_min_gpl/ffmpeg_kit.dart';
and then the render itself:
await FFmpegKit.executeAsync(
'-y -i $screenshotPath -i $filePath -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p ${applicationDocumentDirectory.path}/new.mp4',
(session) async {
final state = await session.getState();
final returnCode = await session.getReturnCode();
String output = await session.getOutput();
print(output);
if (ReturnCode.isSuccess(returnCode)) {
// SUCCESS
await Share.shareFiles(
['${applicationDocumentDirectory.path}/new.mp4'],
);
} else if (ReturnCode.isCancel(returnCode)) {
// CANCEL
} else {
// ERROR
}
});
It's been 3 days that I try to fix an issue with the download of audio files with my Flutter application. When I try to download audio files, the request keep the "pending" status and finish with no error.
I have research a lot and find something about the contentLength of the client who is always at 0 but it doesn't help.
Now I have tried to make a get request to a website with sample audio files and it doesn't work too. I have tested via Postman and it always work.
My function:
Future<void> _download(String url, String filepath) async {
final response = await this.get("https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3");// await this.get("$baseURL$url");
log("Try to get audio files: ${response.isOk}");
if (response.isOk) {
File file = File(filepath);
final raf = file.openSync(mode: FileMode.write);
response.bodyBytes.listen((value) {
raf.writeFromSync(value);
}, onDone: () {
log("closed $filepath");
raf.closeSync();
});
}
}
The response.isOk is always false.
I used GetConnect from GetX package who used httpClient.
Via Dart devtools I obtain this from the request:
https://prnt.sc/1q3w33z
https://prnt.sc/1q3x9ot
So I used another package: Dio and now it works.
I am trying to make a simple app in Flutter. A user can either take or pick a video and then upload it. However, I wanted to compress the video for storage purposes on firebase storage, and also trim it to only get the first 30 seconds.
I am facing a very puzzling problem. I am able to compress the video, but with the resultant file, FFmpeg fails to trim it and I get endless logs which result in me having to stop the app and re-run. Alternatively, I am able to trim the video, but with the resultant file, I am unable to compress it getting the error: Failed to open file '/data/user/0/live.roots.roots/app_flutter/TRIMMED.mp4'. (No such file or directory) PlatformException(error, java.io.IOException: Failed to instantiate extractor., null, java.lang.RuntimeException: java.io.IOException: Failed to instantiate extractor.
This is my code below:
//! function that controls file compression and trimming
static Future<File> compressFile(File file) async {
print('[COMPRESSING FILE]');
String mimeStr = lookupMimeType(file.path);
var fileType = mimeStr.split('/');
if (fileType.contains("image")) {
print('[COMPRESSING FILE] - file is image');
String tempPath = (await getTemporaryDirectory()).path;
String targetPath = '$tempPath/${DateTime.now().toIso8601String()}.jpg';
return await compressImageAndGetFile(file, targetPath);
} else {
print('[COMPRESSING FILE] - file is video');
final compressedVideoFile = await compressVideoAndGetFile(file);
print('[VIDEO FILE COMPRESSED]');
return await trimVideoGetFile(compressedVideoFile);
}
}
//! function to compress video
static Future<File> compressVideoAndGetFile(File file) async {
print('[COMPRESSING VIDEO]');
var result = await VideoCompress.compressVideo(
file.absolute.path,
quality: VideoQuality.DefaultQuality,
deleteOrigin: true,
);
print('[COMPRESSED VIDEO TO]: ${result.file.path}');
return result.file;
}
//! function to trim video
static Future<File> trimVideoGetFile(File file) async {
print('[TRIMMING VIDEO]');
Directory appDocumentDir = await getApplicationDocumentsDirectory();
String rawDocumentPath = appDocumentDir.path;
String outputPath = rawDocumentPath + "/TRIMMED.mp4";
final newFile = File(outputPath);
if (await newFile.exists()) {
await newFile.delete();
}
_flutterFFmpeg
.execute(
"-ss 00:00:00 -i ${file.path} -to 00:00:30 -c copy $outputPath")
.then((rt) async {
print('[TRIMMED VIDEO RESULT] : $rt');
if (rt == -1) {
throw Exception("Something went wrong when trimming the video");
}
});
return File(outputPath);
}
Thank you in advance
Video_compress package allows you to trim the duration without the need to FFmpeg.
var result = await VideoCompress.compressVideo(
file.absolute.path,
quality: VideoQuality.DefaultQuality,
deleteOrigin: true,
startTime: 0, // customize start time
duration: 30, // customize the length
);
I'm using this to return the video file but I got .jpg
Future<File> getVideo() async {
var video = await ImagePicker.pickVideo(
source: ImageSource.gallery);
return video;
}
I want to ImagePicker.pickVideo() return video file instead of .jpg file so I can upload this file to firebase, how can I achieve that?
I'm assuming that you're using the package:
https://pub.dev/packages/image_picker
pickVideo() method has been decrecated, and you will need to replace these apis with getVideo()
As explained the repositories' documentation:
https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker
Write this:
final _picker = ImagePicker();
PickedFile video = await _picker.getVideo(...)
However I would suggest to use this package as an alternative:
https://pub.dev/packages/flutter_document_picker
This package will allow you to select all videos on the device, including those taken from a users' Google Drive or iCloud providers. In this case write this:
FlutterDocumentPickerParams params = FlutterDocumentPickerParams(
allowedUtiTypes: [
'public.video',
'public.mpeg',
'public.mpeg-4-audio',
'com.apple.protected-​mpeg-4-audio'
],
allowedMimeTypes: [
'video/mpeg',
'video/x-flv',
'video/mp4',
'application/x-mpegURL',
'video/quicktime',
'video/x-msvideo',
'video/x-ms-wmv',
'video/ogg',
'video/mp2t',
'video/3gpp'
],
invalidFileNameSymbols: ['/'],
);
return await FlutterDocumentPicker.openDocument(params: params);
You will need to make sure that the Mimes and Uti types for videos on iOS & Android are set correctly.
I have this page where the camera is initialized and ready with a button that will record and stop the video, so I tried this :
FlatButton(
onPressed: () => {
!isRecording
? {
setState(() {
isRecording = true;
}),
cameraController.prepareForVideoRecording(),
cameraController.startVideoRecording('assets/Videos/test.mp4')
}
: cameraController.stopVideoRecording(),
},
............
but throws this error : nhandled Exception: CameraException(videoRecordingFailed, assets/Videos/test.mp4: open failed: ENOENT (No such file or directory)).
I don't understand, I don't want to open this file I want to save it there, Is there sth wrong with my code ?
In the new version, static method startRecordingVideo doesn't take any string parameter.
When you want to start the recording just see whether a video is already getting recorded, if not start
if (!_controller.value.isRecordingVideo) {
_controller.startVideoRecording();
}
and when you want to finish the recording you can call the static method stopVideoRecording() and it will give you a object of the class XFile, it will have the path to your video.
if (_controller.value.isRecordingVideo) {
XFile videoFile = await _controller.stopVideoRecording();
print(videoFile.path);//and there is more in this XFile object
}
This thing has worked for me. I am new to flutter please improve my answer if you know more.
You are trying to save a video in your assets folder which is not possible ,
What you need to do is to save to device locally either common folders like downloads or app directory.
Here is an example of how to go about it
dependencies:
path_provider:
Flutter plugin for getting commonly used locations on host platform
file systems, such as the temp and app data directories.
We will be saving the video to app directory.
We need to get the path to the directory where the file is or will be. Usually a file is put in the application's document directory, in the application's cache directory, or in the external storage directory. To get the path easily and reduce the chance of type, we can use PathProvider
Future<String> _startVideoRecording() async {
if (!controller.value.isInitialized) {
return null;
}
// Do nothing if a recording is on progress
if (controller.value.isRecordingVideo) {
return null;
}
//get storage path
final Directory appDirectory = await getApplicationDocumentsDirectory();
final String videoDirectory = '${appDirectory.path}/Videos';
await Directory(videoDirectory).create(recursive: true);
final String currentTime = DateTime.now().millisecondsSinceEpoch.toString();
final String filePath = '$videoDirectory/${currentTime}.mp4';
try {
await controller.startVideoRecording(filePath);
videoPath = filePath;
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
//gives you path of where the video was stored
return filePath;
}