convert high quality GIF

convert high quality GIF
pull/166/head
xufulong 4 years ago
parent 99762f7dae
commit 5f75d3831c
  1. 4
      app/src/main/java/com/frank/ffmpeg/FFmpegCmd.java
  2. 54
      app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.java
  3. 1229
      app/src/main/java/com/frank/ffmpeg/gif/BeautyGifEncoder.java
  4. 105
      app/src/main/java/com/frank/ffmpeg/gif/HighQualityGif.java

@ -65,6 +65,10 @@ public class FFmpegCmd {
});
}
public static int executeSync(final String[] commands) {
return handle(commands);
}
/**
* Execute FFmpeg multi commands
* @param commands the String array of command

@ -15,6 +15,7 @@ import android.widget.TextView;
import com.frank.ffmpeg.FFmpegCmd;
import com.frank.ffmpeg.R;
import com.frank.ffmpeg.format.VideoLayout;
import com.frank.ffmpeg.gif.HighQualityGif;
import com.frank.ffmpeg.handler.FFmpegHandler;
import com.frank.ffmpeg.model.MediaBean;
import com.frank.ffmpeg.tool.JsonParseTool;
@ -57,6 +58,7 @@ public class VideoHandleActivity extends BaseActivity {
private String listPath = PATH + File.separator + "listFile.txt";
private boolean isJointing = false;
private final static boolean convertGifWithFFmpeg = false;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@ -80,7 +82,6 @@ public class VideoHandleActivity extends BaseActivity {
break;
case MSG_PROGRESS:
int progress = msg.arg1;
int duration = msg.arg2;
if (progress > 0) {
txtProgress.setVisibility(View.VISIBLE);
txtProgress.setText(String.format(Locale.getDefault(), "%d%%", progress));
@ -221,21 +222,26 @@ public class VideoHandleActivity extends BaseActivity {
}
break;
case R.id.btn_generate_gif://convert video into gif
String Video2Gif = PATH + File.separator + "Video2Gif.gif";
String video2Gif = PATH + File.separator + "video2Gif.gif";
int gifStart = 10;
int gifDuration = 6;
int gifDuration = 3;
int width = 320;
int frameRate = 10;
String palettePath = PATH + "/palette.png";
FileUtil.deleteFile(palettePath);
String[] paletteCmd = FFmpegUtil.generatePalette(srcFile, gifStart, gifDuration,
frameRate, width, palettePath);
String[] gifCmd = FFmpegUtil.generateGifByPalette(srcFile, palettePath, gifStart, gifDuration,
frameRate, width, Video2Gif);
List<String[]> cmdList = new ArrayList<>();
cmdList.add(paletteCmd);
cmdList.add(gifCmd);
ffmpegHandler.executeFFmpegCmds(cmdList);
if (convertGifWithFFmpeg) {
String palettePath = PATH + "/palette.png";
FileUtil.deleteFile(palettePath);
String[] paletteCmd = FFmpegUtil.generatePalette(srcFile, gifStart, gifDuration,
frameRate, width, palettePath);
String[] gifCmd = FFmpegUtil.generateGifByPalette(srcFile, palettePath, gifStart, gifDuration,
frameRate, width, video2Gif);
List<String[]> cmdList = new ArrayList<>();
cmdList.add(paletteCmd);
cmdList.add(gifCmd);
ffmpegHandler.executeFFmpegCmds(cmdList);
} else {
convertGifInHighQuality(video2Gif, srcFile, gifStart, gifDuration, frameRate);
}
break;
case R.id.btn_multi_video://combine video which layout could be horizontal of vertical
String input1 = PATH + File.separator + "input1.mp4";
@ -258,15 +264,14 @@ public class VideoHandleActivity extends BaseActivity {
String imagePath = PATH + File.separator + "Video2Image/";
File imageFile = new File(imagePath);
if (!imageFile.exists()) {
boolean result = imageFile.mkdir();
if (!result) {
if (!imageFile.mkdir()) {
return;
}
}
int mStartTime = 10;//start time
int mDuration = 5;//duration
int mFrameRate = 10;//frameRate
commandLine = FFmpegUtil.videoToImageWithScale(srcFile, mStartTime, mDuration, mFrameRate, 320, imagePath);
commandLine = FFmpegUtil.videoToImage(srcFile, mStartTime, mDuration, mFrameRate, imagePath);
break;
case R.id.btn_pip://combine into picture-in-picture video
String inputFile1 = PATH + File.separator + "beyond.mp4";
@ -358,11 +363,7 @@ public class VideoHandleActivity extends BaseActivity {
return;
}
String tempPath = PATH + "/temp/";
File tempFile = new File(tempPath);
if (tempFile.exists()) {
tempFile.delete();
}
tempFile.mkdirs();
FileUtil.deleteFolder(tempPath);
File photoFile = new File(picturePath);
File[] files = photoFile.listFiles();
List<String[]> cmdList = new ArrayList<>();
@ -383,6 +384,17 @@ public class VideoHandleActivity extends BaseActivity {
}
}
private void convertGifInHighQuality(String gifPath, String videoPath, int startTime, int duration, int frameRate) {
new Thread(() -> {
mHandler.sendEmptyMessage(MSG_BEGIN);
long start = System.currentTimeMillis();
HighQualityGif highQualityGif = new HighQualityGif();
boolean result = highQualityGif.convertGIF(gifPath, videoPath, startTime, duration, frameRate);
Log.e(TAG, "convert gif result=" + result + "--time=" + (System.currentTimeMillis()-start));
mHandler.sendEmptyMessage(MSG_FINISH);
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();

File diff suppressed because it is too large Load Diff

@ -0,0 +1,105 @@
package com.frank.ffmpeg.gif;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import com.frank.ffmpeg.FFmpegCmd;
import com.frank.ffmpeg.util.FFmpegUtil;
import com.frank.ffmpeg.util.FileUtil;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author frank
* @date 2020-09-25 20:11
* @desc Extract frames, and convert to GIF
*/
public class HighQualityGif {
private final static String TAG = HighQualityGif.class.getSimpleName();
private final static int TARGET_WIDTH = 320;
private final static int TARGET_HEIGHT = 180;
private byte[] generateGif(String filePath, int startTime, int duration, int frameRate) throws IllegalArgumentException {
if (TextUtils.isEmpty(filePath)) {
return null;
}
String folderPath = Environment.getExternalStorageDirectory() + "/gif_frames/";
FileUtil.deleteFolder(folderPath);
String[] commandLine = FFmpegUtil.videoToImageWithScale(filePath, startTime, duration, frameRate, TARGET_WIDTH, folderPath);
FFmpegCmd.executeSync(commandLine);
File fileFolder = new File(folderPath);
if (!fileFolder.exists() || fileFolder.listFiles() == null) {
return null;
}
File[] files = fileFolder.listFiles();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BeautyGifEncoder gifEncoder = new BeautyGifEncoder();
gifEncoder.setFrameRate(10);
gifEncoder.start(outputStream);
for (File file:files) {
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
if (bitmap != null) {
gifEncoder.addFrame(bitmap);
}
}
gifEncoder.finish();
return outputStream.toByteArray();
}
private boolean saveGif(byte[] data, String gifPath) {
if (data == null || data.length == 0 || TextUtils.isEmpty(gifPath)) {
return false;
}
boolean result = true;
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(gifPath);
outputStream.write(data);
outputStream.flush();
} catch (IOException e) {
result = false;
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
/**
* convert video into GIF
* @param gifPath gifPath
* @param filePath filePath
* @param startTime where starts from the video(Unit: second)
* @param duration how long you want to convert(Unit: second)
* @param frameRate how much frames you want in a second
* @return convert GIF success or not
*/
public boolean convertGIF(String gifPath, String filePath, int startTime, int duration, int frameRate) {
byte[] data;
try {
data = generateGif(filePath, startTime, duration, frameRate);
} catch (IllegalArgumentException | OutOfMemoryError e) {
Log.e(TAG, "generateGif error=" + e.toString());
return false;
}
return saveGif(data, gifPath);
}
}
Loading…
Cancel
Save