parent
3dd8fc9920
commit
cd937493ad
@ -1,137 +0,0 @@ |
||||
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 int mWidth; |
||||
private int mHeight; |
||||
private int mRotateDegree; |
||||
|
||||
public HighQualityGif(int width, int height, int rotateDegree) { |
||||
mWidth = width; |
||||
mHeight = height; |
||||
mRotateDegree = rotateDegree; |
||||
} |
||||
|
||||
private int chooseWidth(int width, int height) { |
||||
if (width <= 0 || height <= 0) { |
||||
return TARGET_WIDTH; |
||||
} |
||||
int target; |
||||
if (mRotateDegree == 0 || mRotateDegree == 180) {//landscape
|
||||
if (width > TARGET_WIDTH) { |
||||
target = TARGET_WIDTH; |
||||
} else { |
||||
target = width; |
||||
} |
||||
} else {//portrait
|
||||
if (height > TARGET_HEIGHT) { |
||||
target = TARGET_HEIGHT; |
||||
} else { |
||||
target = height; |
||||
} |
||||
} |
||||
return target; |
||||
} |
||||
|
||||
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); |
||||
int targetWidth = chooseWidth(mWidth, mHeight); |
||||
String[] commandLine = FFmpegUtil.videoToImageWithScale(filePath, startTime, duration, frameRate, targetWidth, 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); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,138 @@ |
||||
package com.frank.ffmpeg.gif |
||||
|
||||
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-11-08 23:45 |
||||
* @desc Extract frames, and convert to GIF |
||||
*/ |
||||
class HighQualityGif(width: Int, height: Int, rotateDegree: Int) { |
||||
|
||||
companion object { |
||||
private val TAG = HighQualityGif::class.java.simpleName |
||||
|
||||
private const val TARGET_WIDTH = 320 |
||||
|
||||
private const val TARGET_HEIGHT = 180 |
||||
} |
||||
|
||||
private var mWidth: Int = 0 |
||||
private var mHeight: Int = 0 |
||||
private var mRotateDegree: Int = 0 |
||||
|
||||
init { |
||||
this.mWidth = width |
||||
this.mHeight = height |
||||
this.mRotateDegree = rotateDegree |
||||
} |
||||
|
||||
private fun chooseWidth(width: Int, height: Int): Int { |
||||
if (width <= 0 || height <= 0) { |
||||
return TARGET_WIDTH |
||||
} |
||||
return if (mRotateDegree == 0 || mRotateDegree == 180) {//landscape |
||||
if (width > TARGET_WIDTH) { |
||||
TARGET_WIDTH |
||||
} else { |
||||
width |
||||
} |
||||
} else {//portrait |
||||
if (height > TARGET_HEIGHT) { |
||||
TARGET_HEIGHT |
||||
} else { |
||||
height |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Throws(IllegalArgumentException::class) |
||||
private fun generateGif(filePath: String, startTime: Int, duration: Int, frameRate: Int): ByteArray? { |
||||
if (TextUtils.isEmpty(filePath)) { |
||||
return null |
||||
} |
||||
val folderPath = Environment.getExternalStorageDirectory().toString() + "/gif_frames/" |
||||
FileUtil.deleteFolder(folderPath) |
||||
val targetWidth = chooseWidth(mWidth, mHeight) |
||||
val commandLine = FFmpegUtil.videoToImageWithScale(filePath, startTime, duration, frameRate, targetWidth, folderPath) |
||||
FFmpegCmd.executeSync(commandLine) |
||||
val fileFolder = File(folderPath) |
||||
if (!fileFolder.exists() || fileFolder.listFiles() == null) { |
||||
return null |
||||
} |
||||
val files = fileFolder.listFiles() |
||||
|
||||
val outputStream = ByteArrayOutputStream() |
||||
val gifEncoder = BeautyGifEncoder() |
||||
gifEncoder.setFrameRate(10f) |
||||
gifEncoder.start(outputStream) |
||||
|
||||
for (file in files) { |
||||
val bitmap = BitmapFactory.decodeFile(file.absolutePath) |
||||
if (bitmap != null) { |
||||
gifEncoder.addFrame(bitmap) |
||||
} |
||||
} |
||||
gifEncoder.finish() |
||||
return outputStream.toByteArray() |
||||
} |
||||
|
||||
private fun saveGif(data: ByteArray?, gifPath: String): Boolean { |
||||
if (data == null || data.isEmpty() || TextUtils.isEmpty(gifPath)) { |
||||
return false |
||||
} |
||||
var result = true |
||||
var outputStream: FileOutputStream? = null |
||||
try { |
||||
outputStream = FileOutputStream(gifPath) |
||||
outputStream.write(data) |
||||
outputStream.flush() |
||||
} catch (e: IOException) { |
||||
result = false |
||||
} finally { |
||||
if (outputStream != null) { |
||||
try { |
||||
outputStream.close() |
||||
} catch (e: IOException) { |
||||
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 |
||||
*/ |
||||
fun convertGIF(gifPath: String, filePath: String, startTime: Int, duration: Int, frameRate: Int): Boolean { |
||||
val data: ByteArray? |
||||
try { |
||||
data = generateGif(filePath, startTime, duration, frameRate) |
||||
} catch (e: IllegalArgumentException) { |
||||
Log.e(TAG, "generateGif error=$e") |
||||
return false |
||||
} catch (e: OutOfMemoryError) { |
||||
Log.e(TAG, "generateGif error=$e") |
||||
return false |
||||
} |
||||
|
||||
return saveGif(data, gifPath) |
||||
} |
||||
} |
Loading…
Reference in new issue