FFmpeg Video Editor

FFmpeg is a tool that can be used to edit or convert videos and audios.It includes libavcodec – the audio/video codec library.
Some of the uses of FFmpeg are:

  • Video Compress
  • Audio Compress
  • Video Cut
  • Video Rotate
  • Video Crop
  • Extract Picture from Video
  • Extract Sound from Video
  • Change Video Resolution
  • Adding filters to videos
  • Creating fast and slow motion video
  • Reverse Video
  • Creating video from images
  • Convert video from one format into another
  • Merge an audio and video

For integrating FFmpeg in android we can use precompiled libraries like ffmpeg-android.
ffmpeg-android is a library by WritingMinds that simplifies your task of using ffmpeg in Android project.
Below post covers integration of following features using FFmpeg-

  • Video Compress
  • Video Cut
  • Extract Picture from Video
  • Extract Audio from Video
  • Add Fade In Fade Out effect to Video
  • Creating Fast Motion Video
  • Creating Slow Motion Video
  • Reverse Video

Besides these following features have been discussed in comments section-

  • Merging audio and video overriding video’s audio if there
  • Adding audio as background music to video keeping video’s audio
  • Speed up video 3x, 4x times
  • Creating video from images
  • Segmenting video
  • Adding watermark
  • Concatenate audio with another audio
  • Concatenate video with another video
  • Adding two watermarks to a video at different times
  • Using URL as an input option

I have used RangeSeekBar to allow user to select the time range for cutting video from original video.

Complete code for the post is uploaded on github at below link-

https://github.com/bhuvnesh123/FFmpeg-Video-Editor-Android

and an extended app is published at following link-

https://apkfab.com/video-editor-using-ffmpeg/videoeditor.bhuvnesh.com.ffmpegvideoeditor

Integrating FFmpeg library
1.Add FFmpeg dependency in app module gradle file and sync project.

compile ‘com.writingminds:FFmpegAndroid:0.3.2’

2.Load FFMpeg using below code-

FFmpeg ffmpeg;
private void loadFFMpegBinary() {
try {
if (ffmpeg == null) {
Log.d(TAG, “ffmpeg : null”);
ffmpeg = FFmpeg.getInstance(this);
}
ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
@Override
public void onFailure() {
showUnsupportedExceptionDialog();
}
@Override
public void onSuccess() {
Log.d(TAG, “ffmpeg : correct Loaded”);
}
});
} catch (FFmpegNotSupportedException e) {
showUnsupportedExceptionDialog();
} catch (Exception e) {
Log.d(TAG, “EXception not supported : ” + e);
}
}

loadBinary copies the ffmpeg binary to device according to device’s architecture. You just need to put this once in your code, whenever you are starting the application or using FFmpeg for the first time.
3.Create a method which will take ffmpeg command as an argument and pass it to execute method of FFMpeg class.

private void execFFmpegBinary(final String[] command) {
try {
ffmpeg.execute(command, new ExecuteBinaryResponseHandler() {
@Override
public void onFailure(String s) {
Log.d(TAG, “FAILED with output : ” + s);
}
@Override
public void onSuccess(String s) {
Log.d(TAG, “SUCCESS with output : ” + s);
//Perform action on success
}
}
@Override
public void onProgress(String s) {
Log.d(TAG, “progress : ” + s);
}
@Override
public void onStart() {
Log.d(TAG, “Started command : ffmpeg ” + command);
}
@Override
public void onFinish() {
Log.d(TAG, “Finished command : ffmpeg ” + command);
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
}
}

execute() method of FFmpeg class takes command as parameter and executes it.It has a ResponseHandler which return event on start,progress,finish,success and failure.
Now we will go through the various FFmpeg commands that we can use to perform different operations-
Compress a video

To compress a video we can use below command-

String[] command = {"-y", "-i", inputFileAbsolutePath, "-s", "160x120", "-r", "25", "-vcodec", "mpeg4", "-b:v", "150k", "-b:a", "48000", "-ac", "2", "-ar", "22050", outputFileAbsolutePath};

Here,

-y

Overwrite output files without asking.

-i

ffmpeg reads from an arbitrary number of input “files” specified by the -i option

-s

video output size

-r

Set frame rate

-vcodec

Set the video codec.

-b:v

Set the video bitrate

-b:a

Set the audio bitrate
-ac

Set the number of audio channels.

-ar

sets the sampling rate for audio streams if encoded
Cut a video

To cut a video with re-encoding ,we can use below command-

String[] complexCommand = {"-ss", "" + startMs / 1000, "-y", "-i", inputFileAbsolutePath, "-t", "" + (endMs - startMs) / 1000, "-s", "320x240", "-r", "15", "-vcodec", "mpeg4", "-b:v", "2097152", "-b:a", "48000", "-ac", "2", "-ar", "22050", outputFileAbsolutePath};

Here,

-ss
seeks to position(time from where we want to start cutting video)
-t
limit the duration of data read from the input file(duration from cutting start position time upto which we want to cut video)

Other options already defined in previous command

Remove -s 320×240 if you want to keep the resolution of original video.

To cut a video without re-encoding ,we can use below command-

String[] complexCommand = { "-y", "-i", inputFileAbsolutePath,"-ss", "" + startMs / 1000, "-t", "" + (endMs - startMs) / 1000, "-c","copy", outputFileAbsolutePath};

Here,

-c copy
copies the video, audio and bit stream from the input to the output file without re-encoding them.
Extract images from video

To extract images from a video we can use below command

String[] complexCommand = {"-y", "-i", inputFileAbsolutePath, "-an", "-r", "1/2", "-ss", "" + startMs / 1000, "-t", "" + (endMs - startMs) / 1000, outputFileAbsolutePath};

Here,

-an
Disable audio recording.

-r 1/2 will extract one image frame from every 2 second of video.Similarly,-r 1/4 will extract one image frame from every 4 seconds of video and -r 1 will extract one image frame from every second of video.

Remove -r option(-r 1/2 in above command) if you want to extract all video frames as images from the specified time duration.

Other options already defined in previous commands
Extract audio from video

To extract audio from a video we can use below command

String[] complexCommand = {"-y", "-i", inputFileAbsolutePath, "-vn", "-ar", "44100", "-ac", "2", "-b:a", "256k", "-f", "mp3", outputFileAbsolutePath};

-vn

Disable video recording

-f

format

Other options already defined in previous commands
Add Fade In Fade Out effect at start and end of video

To add Fade In and Fade Out effect to start and end of video respectively we can use below command

String[] complexCommand = {"-y", "-i", inputFileAbsolutePath, "-acodec", "copy", "-vf", "fade=t=in:st=0:d=5,fade=t=out:st=" + String.valueOf(duration - 5) + ":d=5", outputFileAbsolutePath};

Here,

-acodec

Set the audio codec

vf filtergraph (output)

Create the filtergraph specified by filtergraph and use it to filter the stream.

fade=t=in:st=0:d=5

Fade in first 5 seconds of video
fade=t=out:st=”+String.valueOf(duration-5)+”:d=5″

Fade out last 5 seconds of video

Other options already defined in previous commands
Fast Motion Video

To create fast motion video we can use below command-

String[] complexCommand = {"-y", "-i", inputFileAbsolutePath, "-filter_complex", "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputFileAbsolutePath};

-filter_complex filtergraph (global)

Define a complex filtergraph, i.e. one with arbitrary number of inputs and/or outputs.

[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]

The filter works by changing the presentation timestamp (PTS) of each video frame. For example, if there are two succesive frames shown at timestamps 1 and 2, and you want to speed up the video, those timestamps need to become 0.5 and 1, respectively. Thus, we have to multiply them by 0.5.

You can speed up or slow down audio with the atemto audio filter.The atempo filter is limited to using values between 0.5 and 2.0 (so it can slow it down to no less than half the original speed, and speed up to no more than double the input).To speed up the audio to double of its speed we have to use atempo value 2.0 .

-map

-map option is a way to tell FFmpeg which streams do you want to select/copy from input to an output.When you want to control which streams are included then you will need/want to specify the “-map” command manually, and change these parameters.

-map [v] -map [a] – Select the streams labeled v and a
-map 0 -Select all streams from input 0.

Check out this for detailed explanation on map option

Other options already defined in previous commands
Slow Motion Video

To create a slow motion video we can use the below command-

String[] complexCommand = {"-y", "-i", inputFileAbsolutePath, "-filter_complex", "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputFileAbsolutePath};

The filter works by changing the presentation timestamp (PTS) of each video frame.To slow down your video, you have to use a multiplier greater than 1. For example, if there are two succesive frames shown at timestamps 1 and 2, and you want to slow down the video, those timestamps need to become 2 and 4, respectively.Thus, we have to multiply them by 2.0.

You can speed up or slow down audio with the atemto audio filter.The atempo filter is limited to using values between 0.5 and 2.0 (so it can slow it down to no less than half the original speed, and speed up to no more than double the input).To slow down the audio to half of its speed we have to use atempo value 0.5 .

Other options already defined in previous commands.
Reverse Video

For reversing video,first we need to divide video into segments with duration of 10 seconds or less because reverse video command for ffmpeg will not work for long duration videos unless your device has 32 GB of RAM.

Hence,to reverse a video-

1.Divide video into segments with duration of 10 seconds or less.
2.Reverse the segmented videos
3.Concatenate reversed segmented videos in reverse order.

For dividing video into segments with duration of 6 seconds we can use the below command-

String[] complexCommand = {"-i", inputFileAbsolutePath, "-c:v", "libx264", "-crf", "22", "-map", "0", "-segment_time", "6", "-g", "9", "-sc_threshold", "0", "-force_key_frames", "expr:gte(t,n_forced*6)", "-f", "segment", outputFileAbsolutePath};

-c:v libx264

encodes all video streams with libx264

-crf

Set the quality for constant quality mode.

-segment_time

time for each segment of video

-g

GOP size

-sc_threshold

set scene change threshold.

-force_key_frames expr:gte(t,n_forced*n)

Forcing a keyframe every n seconds

After segmenting video,we need to reverse the segmented videos.For that we need to run a loop where each segmented video file will be reversed.

To reverse a video with audio(without removing its audio) we can use the below command-

String command[] = {"-i", inputFileAbsolutePath, "-vf", "reverse", "-af", "areverse", outputFileAbsolutePath};

To reverse a video with audio removing its audio we can use the below command-

String command[] = {"-i", inputFileAbsolutePath, "-an", "-vf", "reverse", outputFileAbsolutePath};

To reverse a video without audio we can use the below command-

String command[] = {"-i",inputFileAbsolutePath, "-vf", "reverse", outputFileAbsolutePath};

After reversing segmented videos,we need to concatenate reversed segmented videos in reverse order.For that we sort videos on the basis of last modified file using Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE).

Then, to concatenate reversed segmented videos(with audio) we can use the below command-

String command[] = {"-i",inputFile1AbsolutePath,"-i",inputFile2AbsolutePath .....,"-i",inputFileNAbsolutePath,"-filter_complex","[0:v0] [0:a0] [1:v1] [1:a1]...[N:vN] concat=n=N:v=1:a=1 [v] [a],"-map","[v]","-map","[a]", outputFileAbsolutePath};

To concatenate reversed segmented videos(without audio) we can use the below command-

String command[] = {"-i",inputFile1AbsolutePath,"-i",inputFile2AbsolutePath .....,"-i",inputFileNAbsolutePath,"-filter_complex","[0:0] [1:0] [2:0]...[N:0] concat=n=N:v=1:a=0",outputFileAbsolutePath};

-filter_complex [0:v0] [0:a0] [1:v1] [1:a1]…[N:vN] tells ffmpeg what streams to send to the concat filter.In the above case, video stream 0 [0:v0] and audio stream 0 [0:a0] from input 0,video stream 1 [1:v1] and audio stream 1 [1:v1] from input 1 and so on.

concat filter is used to concatenate audio and video streams, joining them together one after the other.The filter accepts the following options:

n

Set the number of segments. Default is 2.
v

Set the number of output video streams, that is also the number of video streams in each segment. Default is 1.
a

Set the number of output audio streams, that is also the number of audio streams in each segment. Default is 0.
Adding presets

FFmpeg provides certain presets which are collection of options that provide certain speed to the process. Presets in descending order of speed are: ultrafast,superfast, veryfast, faster, fast, medium, slow, slower, veryslow. The default preset is medium.Utrafast preset is specially useful where command is taking too much time to execute and you want to speed up the process.Example while compressing,fading or reversing large size videos.To use preset just add “-preset”, “ultrafast” to the command.
Example-
String command[] = {“-i”, inputFileAbsolutePath,”-preset”, “ultrafast”, “-vf”, “reverse”, “-af”, “areverse”, outputFileAbsolutePath};

The general guideline is to use the slowest preset that you have patience for.
Please check out here for detailed explanation on choosing a preset.

If you like my post please rate it as it will mean a lot to me!

174 thoughts on “FFmpeg Video Editor

  1. Hi.
    I’m using following command to convert array of images to video..it’ working fine..
    But when any image size is more than 2 MB then it can’t make video. kindly help me with this..
    Do we have to take car of size of image and it’s width and height?

    Like

    • String commandNew[] = {“-analyzeduration”, “1M”, “-probesize”, “1M”, “-y”, “-f”, “concat”, “-safe”, “0”, “-i”, textFile.getAbsolutePath(), “-framerate”, “1/” + duration, “-acodec”, “copy”, “-vsync”, “vfr”, “-c:v”, “libx264”, “-vf”, “scale=2*trunc(iw/2):-2”, “-pix_fmt”, “yuv420p”, “-crf”, “18”, “-strict”, “experimental”, “-preset”, “medium”, videoFile.getAbsolutePath(), “-hide_banner”};

      Like

  2. Hi,
    as you explained in “reversing the video” section how you first cut the video into segments and then concate them in reverse order. My problem is, i want to cut my video into segments. But in the command you have given only ONE output file path. Where will be the other segments saved ?

    Like

  3. Hi there, thanks for this this awesome work. I just need to know about slow motion. Is there any way to make rangeseekbar effective for slow motion effect. Suppose I imported a video 40 seconds of length, and I want slow motion effect from 20 to 30 second, not full video. but when video will save it will save 40 second video. 1 to 20 second regular speed, 20 to 30 slow mo and 30 to 40 will be again regular speed.
    Is there any way to do this. again thank you. 🙂

    Like

    • FFmpeg provides certain presets which are collection of options that provide certain speed to the process. Presets in descending order of speed are: ultrafast,superfast, veryfast, faster, fast, medium, slow, slower, veryslow. The default preset is medium.Utrafast preset is specially useful where command is taking too much time to execute and you want to speed up the process.To use preset just add “-preset”, “ultrafast” to the command.

      Like

  4. Hello Bhuvnesh sir i have download app from play store and i see u have split video in different segments so how could possible to video split in different segment ….

    Like

  5. Can you create an ffmpeg livestreaming app,unlike other apps on playstore it needs access to your youtube account .but it delivers poor quality but for ffmpeg only the rtmp key needed .no youtube account needed without lossless quality .so its easy to use it .no one have published the app on playstore .i dont how to create an app.but i have the ffmpeg code directly stream video file or record the screen directly to youtube without loss quality.It will get huge succes of that app believe me.
    I have asked so many developers but they have no experience in that iam asking you can you develop an app i will partnership with you?
    Mail me through given mail..

    Like

  6. Hey there,
    I’m not able to compress the video according to your instructions mentioned above…
    Could you help me to implement this ffmpeg library properly on android studio and compress video..

    Like

  7. Hi, I am trying to extract all frames from video, I have already removed “-r”, “1”, and the first frames I am getting a good resolution, but after 20 frames the quality is dropping. I also tried to removed the limited duration of data read from the input file, but still is I am getting low resolution images.
    Is there any parameter that increase the quality ? even if it takes more time that is fine for me.

    Thank you!

    Like

Leave a comment