As I have understood, the only way to change FFmpeg volume is to do it throught a command line.
This is what should change the volume of the audio :
ffmpeg -i input.wav -filter:a "volume=1.5" output.wav
Now I have used FFmpeg with command line before and it looked like this and gave me no errors:
String[] cmd = { "-i" , pcmtowavTempFile.toString(), "-i", mp3towavTempFile.toString(), "-filter_complex", "amix=inputs=2:duration=first:dropout_transition=3", combinedwavTempFile.toString()};
ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
super.onSuccess(message);
encodeWavToAAC();
}
#Override
public void onFailure(String message) {
super.onFailure(message);
onError(message);
}
});
But If I try to do it with audio volume in the same method, it just ignores it :
String[] cmd = { "-i" , pcmtowavTempFile.toString(), "-filter:a", "volume=1.3", pcmtowavTempFile.toString()};
ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
#Override
public void onSuccess(String message) {
super.onSuccess(message);
}
#Override
public void onFailure(String message) {
super.onFailure(message);
}
});
I get neither, no success or error message with the last volume change method.
Since the volume is there between " ", I tried adding this :
String[] cmd = { "-i" , pcmtowavTempFile.toString(), "-filter:a", "\"volume=1.3\"", pcmtowavTempFile.toString()};
But the app started crashing after adding this line.
Please try using this library instead with the same command. It uses the latest FFmpeg.
https://github.com/bravobit/FFmpeg-Android
FFmpeg ffmpeg = FFmpeg.getInstance(context);
if (ffmpeg.isSupported()) {
// to execute "ffmpeg -version" command you just need to pass "-version"
String[] cmd= {"-i", pcmtowavTempFile.toString(), "-af", "volume=1.3", pcmtowavTempFile.toString()};
ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {}
#Override
public void onProgress(String message) {}
#Override
public void onFailure(String message) {}
#Override
public void onSuccess(String message) {}
#Override
public void onFinish() {}
});
} else {
// ffmpeg is not supported
}
The error here was that FFmpeg does NOT perform in-place editing which means that I can not overwrite the same File. I tried overwriting by adding command "-y" but that did not also work because of that same rule.
So the solution was to create a new File as output File.
Related
I have been compressing Images without any problems. Recently my app required video compress functionality to be added. Again, Silicompressor does the job but for some reason there is no audio in output file.
I am using code inside Runnable
String videoUriStr; // Passed as a variable
String folderPath = activity.getExternalFilesDir("/").getAbsolutePath() + "/My Folder";
String videoPath = SiliCompressor.with(context).compressVideo(videoUriStr, folderPath);
I am able to play compressed video without sound (though on uploading to firebase storage, url shows black screen but right length of video. But I will figure that out). My main concern is the sound.
I have googled a lot and found 2 solutions out of which second seems to be promising but looking way to implement it.
First is to downgrade implementation 'com.googlecode.mp4parser:isoparser:1.1.22' to implementation 'com.googlecode.mp4parser:isoparser:1.0.6', which doesn't work.
Second, which I found here, says "issue seems to be with audio encoder, I changed audio encoder to HE_AAC it works now". Can please anyone help me with this?
So answering my own question. Didn't get much of help on this, hence decided to switch library to FFmpeg.
Gradle
implementation 'com.writingminds:FFmpegAndroid:0.3.2'
Load Library:
FFmpeg fFmpeg;
private void LoadFfmpegLibrary(){
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy_hh-mm", Locale.CANADA);
Date now = new Date();
String videoFileName = "Video-" + formatter.format(now) + ".mp4";
if(fFmpeg == null){
fFmpeg = FFmpeg.getInstance(context);
try {
fFmpeg.loadBinary(new LoadBinaryResponseHandler() {
#Override
public void onStart() {
}
#Override
public void onFailure() {
}
#Override
public void onSuccess() {
}
#Override
public void onFinish() {
Compress(videoFileName);
}
});
} catch (FFmpegNotSupportedException e) {
e.printStackTrace();
}
} else {
Compress(videoFileName);
}
}
Then Compress videos
private void Compress(String fileName){
String outputPath = getExternalFilesDir("/").getAbsolutePath() + "/My Folder/" + fileName;
String[] commandArray;
commandArray = new String[]{"-y", "-i", originalFileUriStr, "-s", "720x480", "-r", "25", "-vcodec", "mpeg4", "-b:v", "300k", "-b:a", "48000", "-ac", "2", "-ar", "22050", outputPath};
final ProgressDialog dialog = new ProgressDialog(activity);
try {
fFmpeg.execute(commandArray, new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {
dialog.setMessage("Compressing... please wait");
}
#Override
public void onProgress(String message) {
Log.e("FFmpeg onProgress? ", message);
}
#Override
public void onFailure(String message) {
Log.e("FFmpeg onFailure? ", message);
}
#Override
public void onSuccess(String message) {
Log.e("FFmpeg onSuccess? ", message);
}
#Override
public void onFinish() {
Uri compressedOutputUri = Uri.fromFile(new File(outputPath));
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
e.printStackTrace();
}
}
And now sound works perfect.
i am using ffmpeg to create video from images and i have 2 image store in my sd card but when i am runing code it takes too long to execute or sometimes its shows only executing..my question is how to increase speed and check if there is anything wrong in my command
String cmd[]={ "-r" ,"1/5", "-i", inputputimg, "-strict",
"experimental", "-vcodec" ,"libx264" ,"-preset" ,"ultrafast" ,"-crf"
,"30",output};
String
inputputimg="/storage/emulated/0/FestiveApp/temp/img%02d.jpeg";
public void ImageCommand(String command[])
{
ffmpeg = FFmpeg.getInstance(MainActivity2.this);
try {
// to execute "ffmpeg -version" command you just need to pass "-version"
ffmpeg.execute(command, new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {
Log.e("ffmpeg","Exaction Start");
}
#Override
public void onProgress(String message) {
}
#Override
public void onFailure(String message) {
imageprogressDialog.dismiss();
Log.e("ok",message);
}
#Override
public void onSuccess(String message) {
imageprogressDialog.dismiss();
Toast.makeText(MainActivity2.this,"success",Toast.LENGTH_SHORT).show();
}
#Override
public void onFinish() {
imageprogressDialog.dismiss();
Log.e("ffmpeg","Exaction Start");
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
imageprogressDialog.dismiss();
Log.e("ffmpeg",e.toString());
}
}
i want video should takes some sec to edit and also i trying to merge to video but it also takes same things
i am trying add image over a video using ffmpeg lib. it show
[NULL # 0xb6dab000] Unable to find a suitable output format for
'ffmpeg '
ffmpeg : Invalid argument
String addimg[]={"ffmpeg", "-i", inputpath,"-i", imagepath ,"\"" +"-filter_complex", "[0:v][1:v] overlay=25:25:enable='between(t,0,10)'" ,"\"" +"-pix_fmt yuv420p", "-c:a copy","\"" +output};
LoadFFmpegLibrary
public void LoadFFmpegLibrary()
{
if(ffmpeg==null)
{
ffmpeg = FFmpeg.getInstance(MainActivity.this);
try {
ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
#Override
public void onStart() {
Log.e("ffmpef","Start to load");
}
#Override
public void onFailure() {
Log.e("ffmpef","failed to load");
}
#Override
public void onSuccess() {
Log.e("ffmpef","load Successfully");
ExcuteFfmpefLibrabry(addimg);
}
#Override
public void onFinish() {}
});
} catch (FFmpegNotSupportedException e) {
// Handle if FFmpeg is not supported by device
Log.e("ffmpef",e.toString());
}
}
}
public void ExcuteFfmpefLibrabry(String command[])
{
ffmpeg = FFmpeg.getInstance(MainActivity.this);
try {
// to execute "ffmpeg -version" command you just need to pass "-version"
ffmpeg.execute(command, new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {
Log.e("ffmpef","Exaction Start");
}
#Override
public void onProgress(String message) {}
#Override
public void onFailure(String message) {
Log.e("ffmpef","failed to Excute Command");
Log.e("ok",message);
}
#Override
public void onSuccess(String message) {
Log.e("ffmpef","Video Edited Successfully");
Log.e("ok",message);
}
#Override
public void onFinish() {
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
Log.e("ffmpef",e.toString());
}
}
I Have seen your Code and get to know that you are using Writing minds For FFMPEG in Android Right?
and i your erro also indicate that ffmpeg is invalid argumnet means ffmpeg is not found in FFMPEG
when you pass commands to writing mind build
for example :
you pass command like : String command[]={"ffmpeg","-i",inputpath,outputpath};
then ffmpeg execute below code::-- ffmpeg ffmpeg -i inputpath outputpath
so ffmpef cant find argument named ffmpeg in thier build
so change you command
from
String addimg[]={"ffmpeg", "-i", inputpath,"-i", imagepath ,"\"" +"-filter_complex", "[0:v][1:v] overlay=25:25:enable='between(t,0,10)'" ,"\"" +"-pix_fmt yuv420p", "-c:a copy","\"" +output};
to
String addimg[]={"-i", inputpath,"-i", imagepath ,"-filter_complex", "[0:v][1:v] overlay=25:25:enable='between(t,0,10)'" ,"-pix_fmt yuv420p", "-c:a copy",output};
I am processing video in android using FFMPEG android java library to change play back of speed. for 6 sec video to make it play back slow by 0.5 setpts , its taking more than 1 min.
Here is my code
public class TestFFMpegActivity {
private static String cmd,
private static FFmpeg ffmpeg;
private static Context mContext;
public static String getInternalDirectoryPath() {
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
public static void initiateFFmpeg(Context context, String path) {
mContext = context;
ffmpeg = FFmpeg.getInstance(context);
VideoIn = getInternalDirectoryPath() + "/Download/input.mp4";
VideoOut = getInternalDirectoryPath() + "/Download/output.mp4";
cmd = "-i "+VideoIn+" -vf setpts=2*PTS -strict -2 "+VideoOut;
try {
ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
#Override
public void onStart() {
}
#Override
public void onFailure() {
}
#Override
public void onSuccess() {
}
#Override
public void onFinish() {
processVideo();
}
});
} catch (FFmpegNotSupportedException e) {
// Handle if FFmpeg is not supported by device
}
}
private static void processVideo(){
try {
ffmpeg.execute(cmd ,
new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {
//for logcat
Log.w(null,"processing started");
}
#Override
public void onProgress(String message) {
//for logcat
Log.w(null, "onProgress");
}
#Override
public void onFailure(String message) {
Log.w(null, message.toString());
}
#Override
public void onSuccess(String message) {
Log.w(null, message.toString());
}
#Override
public void onFinish() {
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
Toast.makeText(mContext, "Video processing failed due to exception", Toast.LENGTH_LONG).show();
// Handle if FFmpeg is already running
e.printStackTrace();
Log.w(null, e.toString());
}
}
}
This is the gradle build path for using above library
compile 'com.github.hiteshsondhi88.libffmpeg:FFmpegAndroid:0.2.5'
For changing playback command add in it parameter "-ultrafast".
Now cmd will be like
cmd= "-i " + VideoIn+ " -vf setpts=2*PTS -c:v libx264 -c:a aac -strict experimental -vcodec libx264 -preset ultrafast -b:a 128k " + VideoOut;
this parameter has magical effect on processing. The video processing time decreases from 1 min 6 sec to 13 secs with same environment.
On windows I could cut a video with below code with ffmpeg.exe
Can't use ffmpeg in android.
I used gradle to grab ffmpeg in my app.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.github.hiteshsondhi88.libffmpeg:FFmpegAndroid:0.2.5'
}
I have these lines in my method
VideoIn = getInternalDirectoryPath() + "/Download/Ab.mp4";
VideoOut = getInternalDirectoryPath() + "/Download/Ab1.mp4";
try {
ffmpeg.execute("ffmpeg -i " + VideoIn + " -ss 00:00:03 -c:v libx264 -crf 17 -t 00:00:5 " + VideoOut + " -y",null);
}
catch (FFmpegCommandAlreadyRunningException e) {
e.printStackTrace();
}
Shows this error: Error running exec(). Command: [/data/data/com.videoeditor.myname.myapp/files/ffmpeg, ffmpeg, -i, /storage/emulated/0/Download/Ab.mp4, -ss, 00:00:03, -c:v, libx264, -crf, 17, -t, 00:00:5, /storage/emulated/0/Download/Ab1.mp4, -y] Working Directory: null Environment: null
What's wrong with this method? Thanks for your help
Ok I found the answer:
There is no need for "ffmpeg" in cmd with this method of using ffmpeg
Simple video cut example:
/**
* Returns the path to internal storage ex:- /storage/emulated/0
*
* #return
*/
private String getInternalDirectoryPath() {
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
VideoIn = getInternalDirectoryPath() + "/Download/Ab.mp4";
VideoOut = getInternalDirectoryPath() + "/Download/Ab1.mp4";
private void CutVideo(){
try {
ffmpeg.execute("-i "+VideoIn+" -ss 00:01:00 -to 00:02:00 -c copy "+VideoOut ,
new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {
//for logcat
Log.w(null,"Cut started");
}
#Override
public void onProgress(String message) {
//for logcat
Log.w(null,message.toString());
}
#Override
public void onFailure(String message) {
Log.w(null,message.toString());
}
#Override
public void onSuccess(String message) {
Log.w(null,message.toString());
}
#Override
public void onFinish() {
Log.w(null,"Cutting video finished");
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
// Handle if FFmpeg is already running
e.printStackTrace();
Log.w(null,e.toString());
}
}
Ok. Your problem is that you aren't loading the ffmpeg binary. You have to load it before executing the command. Try something like this:
private FFmpeg ffmpeg;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FFmpeg ffmpeg = FFmpeg.getInstance(this);
try {
//Load the binary
ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
#Override
public void onStart() {}
#Override
public void onFailure() {}
#Override
public void onSuccess() {}
#Override
public void onFinish() {}
});
} catch (FFmpegNotSupportedException e) {
// Handle if FFmpeg is not supported by device
}
try {
// to execute "ffmpeg -version" command you just need to pass "-version"
// Now, you can execute your command here
ffmpeg.execute("ffmpeg -version", new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {}
#Override
public void onProgress(String message) {}
#Override
public void onFailure(String message) {}
#Override
public void onSuccess(String message) {
Log.i("SUCCESS", message);
}
#Override
public void onFinish() {}
});
} catch (FFmpegCommandAlreadyRunningException e) {
// Handle if FFmpeg is already running
}
}
More info on http://hiteshsondhi88.github.io/ffmpeg-android-java/
Friends, just to mention that if your sdk version is equal or higher than 23 (Marshmelow), don't forget to check runtime permission for
android.permission.WRITE_EXTERNAL_STORAGE
that was my problem. everything was fine but logs didn't show onSuccess result.
android doc for runtime permission
You need to read process's error stream to figure out what is wrong:
InputStreamReader errReader = new InputStreamReader(process.getErrorStream());
BufferedReader bufReader = new BufferedReader(errReader);
while ((String line = bufReader.readLine()) != null) {
Log.d("MyApp", line);
}
But I suppose problem is in wrong argument for exec method, if you need to run both chmod and ffmpeg, you should probably use exec(String[] progArray, String[] envp)