JAVA使用ffmepg处理视频的方法(压缩,分片,合并)

网友投稿 281 2023-01-15

JAVA使用ffmepg处理视频的方法(压缩,分片,合并)

FFmepg安装

路径:

然后在使用的类中生命一个全局变量就好

private static String ffmpegPath = "C:\\hk\\ffmpeg\\bin\\ffmpeg.exe"; //ffmepg的绝对路径

视频压缩

注意:此压缩视频涉及转码,对cpu的占用比较大(能不压缩尽量不压缩)

/**

* 压缩视频

* @param convertFile 待转换的文件

* @param targetFile 转换后的目标文件

*/

public static void toCompressFile(String convertFile,String targetFile) throws IOException {

List command = new ArrayList();

/**将视频压缩为 每秒15帧 平均码率600k 画面的宽与高 为1280*720*/

command.add(ffmpegPath);

command.add("-i");

command.add(convertFile);

command.add("-r");

command.add("15");

command.add("-b:v");

command.add("600k");

command.add("-s");

command.add("1280x720");

command.add(targetFile);

ProcessBuilder builder = new ProcessBuilder(command);

Process process = null;

try {

process = builder.start();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

// 使用这种方式会在瞬间大量消耗CPU和内存等系统资源,所以这里我们需要对流进行处理

InputStream errorStream = process.getErrorStream();

InputStreamReader inputStreamReader = new InputStreamReader(errorStream);

BufferedReader br = new BufferedReader(inputStreamReader);

String line = "";

while ((line = br.readLine()) != null) {

}

if (br != null) {

br.close();

}

if (inputStreamReader != null) {

inputStreamReader.close();

}

if (errorStream != null) {

errorStream.close();

}

logger.info("-------------------压缩完成---转存文件--"+targetFile+"-------------");

}

获取视频合并

/**

* ffmpeg合并多个视频文件

*

* @param list 需要合并的多视频url地址以List存放

* @param outputDir 此处是ffmpeg 配置地址,可写死如“E:/ffmpeg/bin/ffmpeg.exe”

* @param outputFile 合并后的视频存放地址,如:E:/mergevideo.mp4

* @date: 2021/4/17 9:31

* @return: void

*/

public static String mergeVideo(List list, String outputDir, String outputFile) {

try {

String format1 = "%s -i %s -c copy -bsf:v h264_mp4toannexb -f mpegts %s";

List commandList = new ArrayList<>(6);

List inputList = new ArrayList<>(6);

for (int i = 0; i < list.size(); i++) {

String input = String.format("input%d.ts", i + 1);

String command = String.format(format1, ffmpegPath, list.get(i), outputDir + input);

commandList.add(command);

inputList.add(input);

}

String command = getCommand(outputDir,outputFile, inputList);

commandList.add(command);

Boolean falg = Boolean.FALSE;

for (int i = 0; i < commandList.size(); i++) {

if (execCommand(commandList.get(i)) > 0) falg = true;

}

if (falg) {

for (int i = 0; i < inputList.size(); i++) {

if (i != commandList.size() - 1) {

File file = new File(outputDir + inputList.get(i));

file.delete();

}

}

// //删除压缩的文件

// for (String s:list

// ) {

// new File(s).delete();

// }

return outputFile;

} else {

return "fail";

}

} catch (Exception e) {

e.printStackTrace();

logger.error("-----合并失败!!!!!!" + outputFile);

return "fail";

}

}

private static Integer execCommand(String command) {

logger.info("execCommand.exec command={}",command);

try {

Process process = Runtime.getRuntime().exec(command);

//获取进程的标准输入流

final InputStream is1 = process.getInputStream();

//获取进城的错误流

final InputStream is2 = process.getErrorStream();

//启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流

readInputStream(is1);

readInputStream(is2);

process.waitFor();

process.destroy();

logger.info("-----操作成功" + command + " " + sdf.format(new Date()));

return 1;

} catch (Exception e) {

e.printStackTrace();

System.out.println("-----操作失败" + command);

return -1;

}

}

private static void readInputStream(InputStream inputStream) {

new Thread(() -> {

BufferedReader br1 = new BufferedReader(new InputStreamReader(inputStream));

try {

String line1;

while ((line1 = br1.readLine()) != null) {

if (line1 != null) {

}

}

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

inputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}).start();

}

视频分片(分割)

/**

* 将视频分割为小段

*

* @param fileName 源文件名字(带路径)

* @param outputPath 输出文件路径,会在该路径下根据系统时间创建目录,并在此目录下输出段视频

* @param videoTime 总时间,单位 分钟

* @param periodTime 小段视频时长 单位 分钟

* @param merge true合并,false单独分割 说明:是否将整个视频结尾部分不足一次分割时间的部分,合并到最后一次分割的视频中,即false会比true多生成一段视频

*/

public static List> splitVideoFile(String fileName, String outputPath, float videoTime, int periodTime, boolean merge) {

final String TAG = "----------------------------";

// 在outputPath路径下根据系统时间创建目录

File file = createFileBySysTime(outputPath);

if (file == null) {

System.out.println("分割视频失败,创建目录失败");

return null;

}

outputPath = file.getPath() + File.separator; // 更新视频输出目录

// 计算视频分割的个数

int count;// 分割为几段

float remain = 0; // 不足一次剪辑的剩余时间

if (merge) {

count = (int) (videoTime / periodTime);

remain = videoTime % periodTime; // 不足一次剪辑的剩余时间

} else {

count = (int) (videoTime / periodTime) + 1;

}

System.out.println("将视频分割为" + count + "段,每段约" + periodTime + "分钟");

String indexName; // 第 i 个视频,打印日志用

final String FFMPEG = ffmpegPath;

String startTime; // 每段视频的开始时间

String periodVideoName; // 每段视频的名字,名字规则:视频i_时间段xx_yy

float duration; // 每次分割的时长

String command;// 执行的命令

// 得到视频后缀 如.mp4

String videoSuffix = fileName.substring(fileName.lastIndexOf("."));//得到点后面的后缀,包括点

Runtime runtime = Runtime.getRuntime(); // 执行命令者

List> list =new ArrayList<>();

// 将视频分割为count段

for (int i = 0; i < count; i++) {

Map map =new HashMap<>();

indexName = "第" + (i+1) + "个视频";

// 决定是否将整个视频结尾部分不足一次的时间,合并到最后一次分割的视频中

if (merge) {

if (i == count - 1) {

duration = periodTime * 60 + remain * 60;// 将整个视频不足一次剪辑的时间,拼接在最后一次剪裁中

if(periodTime * i /60 >= 1){

startTime = "0"+periodTime * i /60+ ":00:00";

}else{

startTime = periodTime * i + ":00";

}

periodVideoName = "video" + (i+1) + "_" + periodTime * i + "_end" + videoSuffix;

} else {

duration = periodTime * 60;

if(periodTime * i /60 >= 1){

startTime = "0"+periodTime * i /60+ ":00:00";

}else{

startTime = periodTime * i + ":00";

}

periodVideoName = "video" +(i+1) + "_" + periodTime * i + "_" + periodTime * (i + 1) + videoSuffix;

}

} else {

duration = periodTime * 60;

if(periodTime * i /60 >= 1){

startTime = "0"+periodTime * i /60+ ":00:00";

}else{

startTime = periodTime * i + ":00";

}

periodVideoName = "video" + (i+1) + "_" + periodTime * i + "_" + periodTime * (i + 1) + videoSuffix;

}

// 执行分割命令

try {

// 创建命令

command = FFMPEG + " -ss " + startTime +" -accurate_seek "+ " -i " + fileName + " -c copy -t " + duration + " " + outputPath + periodVideoName;

System.out.println(TAG);

System.out.println(indexName);

System.out.println("执行命令:" + command);

runtime.exec(command);

System.out.println(indexName + "分割成功");

map.put("videoPath",(outputPath + periodVideoName).replace("\\","/"));

map.put("count",i);

list.add(map);

} catch (Exception e) {

e.printStackTrace();

System.out.println(indexName + "分割失败!!!!!!");

}

}

//删除原来的大视频

new File(fileName).delete();

return list;

}

/**

* 在指定目录下根据系统时间创建文件夹

* 文件名字eg:2019-07-02-23-56-31

*

* @param path 路径:eg: "/Users/amarao/业余/剪辑/output/";

* 结果:创建成功/Users/amarao/业余/剪辑/output/2019-07-03-10-28-05

*

* 步骤:

* 1. 读取系统时间

* 2. 格式化系统时间

* 3. 创建文件夹

*

* 参考:http://bubuko.com/infodetail-1685972.html

*/

public static File createFileBySysTime(String path) {

// 1. 读取系统时间

Calendar calendar = Calendar.getInstance();

Date time = calendar.getTime();

// 2. 格式化系统时间

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");

String fileName = format.format(time); //获取系统当前时间并将其转换为string类型,fileName即文件名

// 3. 创建文件夹

String newPath = path + fileName;

File file = new File(newPath);

//如果文件目录不存在则创建目录

if (!file.exists()) {

if (!file.mkdir()) {

System.out.println("当前路径不存在,创建失败");

return null;

}

}

System.out.println("创建成功" + newPath);

return file;

}

获取视频的时长

/**

* 获取视频时长 单位/秒

* @param video

* @return

*/

public static long getVideoDuration(File video) {

long duration = 0L;

FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video);

try {

ff.start();

duration = ff.getLengthInTime() / (1000 * 1000 * 60);

ff.stop();

} catch (FrameGrabber.Exception e) {

e.printStackTrace();

}

return duration;

}

视频剪切

/**

*

*剪切视频

videoInputPath 需要处理的视频路径

startTime: 截取的开始时间 格式为 00:00:00(时分秒)

endTime: 截取的结束时间 格式为00:03:00(时分秒)

devIp: 通道号 业务存在 ,可自行删除

* */

public static String videoClip(String videoInputPhttp://ath,String startTime,String endTime,String devIp) throws IOException {

SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd");

SimpleDateFormat dtf=new SimpleDateFormat("yyyyMMddHHmmss");

//判断转码文件是否存在

if(!new File(videoInputPath).exists()){

System.out.println("需要处理的视频不存在");

return null;

}

StringBuffer videoOutPath = new StringBuffer();

videoOutPath.append("C:/video/playBack/"+devIp+"/"+sdf1.format(new Date())+"/clip/");

File file = new File(videoOutPath.toString());

if (!file.exists()){

file.mkdirs();

}

videoOutPath.append(dtf.format(new Date())+".mp4");

List command = new ArrayList();

command.add(ffmpegPath);

command.add("-ss");

command.add(startTime);

command.add("-t");

command.add(endTime);

command.add("-i");

command.add(videoInputPath);

command.add("-c");

command.add("copy");

command.add(videoOutPath.toString());

command.add("-y");

ProcessBuilder builder = new ProcessBuilder(command);

Process process = null;

try {

process = builder.start();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

InputStream errorStream = process.getErrorStream();

InputStreamReader inputStreamReader = new InputStreamReader(errorStream);

BufferedReaderhttp:// br = new BufferedReader(inputStreamReader);

String line = "";

while ((line = br.readLine()) != null) {

}

if (br != null) {

br.close();

}

if (inputStreamReader != null) {

inputStreamReader.close();

}

if (errorStream != null) {

errorStream.close();

}

return videoOutPath.toString();

}

视频转GIF(MP4)

/*

* 视频转gif

*inputVideoPath 需要转换的视频

* createGif gif保存的位置

* */

public static String mp4ToGif(String inputVideoPath,String createGif) {

String name = UUID.randomUUID().toString().replaceAll("-", "");

String paletteFile = createGif +name + ".png";

String gifFile = createGif+name + ".gif";

boolean isComplete = false;

//操作ffmpeg生成gif图片

for (int i = 0; i < 5; i++) {

try {

//生成调色板

Process p = new ProcessBuilder()

.command(ffmpegPath,

"-v", "warning",

"-ss", "2",

"-t", "10",

"-i", inputVideoPath,

"-vf", "fps=5,scale=400:-1:flags=lanczos,palettegen",

"-y", paletteFile, "-vn")

.redirectError(new File("stderr.txt"))

.start();

isComplete = p.waitFor(10, TimeUnit.SECONDS);

if (!isComplete) {

System.out.println("生成调色板出错");

} else {

List command = new ArrayList();

/**将视频压缩为 每秒15帧 平均码率600k 画面的宽与高 为1280*720*/

command.add(ffmpegPath);

command.add("-v");

command.add("warning");

command.add("-ss");

http:// command.add("2");

command.add("-t");

command.add("10");

command.add("-i");

command.add(inputVideoPath);

command.add("-i");

command.add(paletteFile);

command.add("-lavfi");

command.add("fps=5,scale=400:-1:flags=lanczos [x]; [x][1:v] paletteuse");

command.add("-y");

command.add(gifFile);

command.add("-vn");

ProcessBuilder builder = new ProcessBuilder(command);

Process process = null;

try {

process = builder.start();

isComplete = process.waitFor(10, TimeUnit.SECONDS);

if (isComplete) {

new File(paletteFile).delete();

System.out.println("生成gif成功");

break;

} else {

System.out.println("生成gif出错");

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

// process = new ProcessBuilder()

// .command(ffmpegPath,

// "-v", "warning",

// "-ss", "2",

// "-t", "10",

// "-i", "E:\\Video_2021-05-14_113013.mp4",

// "-i", paletteFile,

// "-lavfi", "fps=5,scale=400:-1:flags=lanczos [x]; [x][1:v] paletteuse",

// "-y", gifFile, "-vn")

// .redirectError(new File("stderr.txt"))

// .start();

// isComplete = process.waitFor(10, TimeUnit.SECONDS);

// if (isComplete) {

// System.out.println("生成gif成功");

// break;

// } else {

// System.out.println("生成gif出错");

// }

}

} catch (Exception e) {

System.out.println("生成gif出错");

}

}

return gifFile;

}

以上就是java使用ffmepg处理视频的方法(压缩,分片,合并)的详细内容,更多关于java ffmepg处理视频的资料请关注我们其它相关文章!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:同花顺免费api(同花顺免费版和同花顺新一代)
下一篇:中通快递物流查询(中通快递物流查询跟踪查询系统)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~