FFmpeg是一款多媒体视频处理工具,有非常强大的功能包括:视频采集、视频推流、视频格式转换、视频抓图、给视频加水印等功能。FFmpeg本身是一个命令行程序
目录
1.继承FileAlterationListenerAdaptor 重写方法
1.继承FileAlterationListenerAdaptor 重写方法
package com.example.fruit.listener;
import com.example.fruit.pojo.Table_File;
import com.example.fruit.service.Table_FileMapperService;
import com.example.fruit.utils.ToolUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import net.bramp.ffmpeg.FFmpeg;
import net.bramp.ffmpeg.FFmpegExecutor;
import net.bramp.ffmpeg.FFprobe;
import net.bramp.ffmpeg.builder.FFmpegBuilder;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.channels.FileChannel;
import java.util.*;
import java.util.regex.Pattern;
import static org.bouncycastle.crypto.tls.ConnectionEnd.server;
/*
*
* 本地某个文件夹下的监听
*
* */
@Data
@Component
public class FileListener extends FileAlterationListenerAdaptor {
// 监听的目录
private String monitorDir;
//存放完整的文件路径(视频) 添加数据进入数据库
//private String keepPath = "D:/BL1-BJ1/test1";
//最终工具转换的视频路径
private String updateVideo = "D:/BL1-BJ1/videoNew/";
//ip地址的获取
private static String ip4address = "/192.168.1.";
/*
* 服务器路径:D:/java/java/ffmpeg-6.1.1-essentials_build/ffmpeg-6.1.1-essentials_build/bin/
* 本地路径: D:/BL1-BJ1/ffmpeg-6.1.1-essentials_build/ffmpeg-6.1.1-essentials_build/bin/
* */
//转换工具文件路径
private String fileGovern = "D:/java/java/ffmpeg-6.1.1-essentials_build/ffmpeg-6.1.1-essentials_build/bin/ffmpeg.exe";
//转换工具文件路径
private String fileFfmpeg = "D:/java/java/ffmpeg-6.1.1-essentials_build/ffmpeg-6.1.1-essentials_build/bin/ffprobe.exe";
private static int port = 8888;
/*
*
* init方法原因:如下
* 在SpringMVC框架中,我们经常要使用@Autowired注解注入Service或者Mapper接口,我们也知道,
* 在controller层中注入service接口,在service层中注入其它的service接口或者mapper接口都是可以的,
* 但是如果我们要在我们自己封装的Utils工具类中或者非controller普通类中使用@Autowired注解注入Service
* 或者Mapper接口,直接注入是不可能的,因为Utils使用了静态的方法,我们是无法直接使用非静态接口的,
* 当我们遇到这样的问题,我们就要想办法解决了。
*
* */
public static FileListener fileListener;
@Autowired
Table_FileMapperService table_FileMapperService;
@PostConstruct
public void init() {
fileListener = this;
}
/**
* @param
* @return
* @description 启动监听
* @version 2.0, 2019/1/24 15:08
* @author <a href="Tastill@**.cn">Tastill</a>
*/
@Override
public void onStart(FileAlterationObserver observer) {
// System.out.println("启动监听器:");
}
@Override
public void onDirectoryCreate(File directory) {
System.out.println("有新文件夹生成:" + directory.getName());
}
@Override
public void onDirectoryChange(File directory) {
System.out.println("有文件夹内容发生变化:" + directory.getName());
}
@Override
public void onDirectoryDelete(File directory) {
System.out.println("有文件夹被删除:" + directory.getName());
}
/**
* @param
* @return
* @description 文件创建
* @version 2.0, 2019/1/24 14:59
* @author <a href="Tastill@**.cn">Tastill</a>
*/
@Override
public void onFileCreate(File file) {
/*
* 只要是Test下视频的文件最后将会被转换到
* videoFFmpeg 方法中的指定路径
* D:/Test/新建文件夹 (2)/
* */
System.out.println("有新文件生成:" + file.getName());
Table_File tableFile = new Table_File();
tableFile.setFileId(ToolUtils.getUUIDTOLong());
tableFile.setFileName(file.getName());
String filePath = file.getPath();
String ok = file.getPath().replaceAll("\\\\", "/");
System.out.println(ok);
try {
//路径不包含已经编译完成的路径 路径的后缀不包含图片jpg
//!ok.contains(keepPath) &&
if (!ok.contains(".jpg")) {
videoFFmpeg(ok, file.getName());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
String substring = filePath.substring(2, filePath.length());
String s = substring.replaceAll("\\\\", "/");
//System.out.println("替换的值:::" + s);
System.out.println(file.getName());
//由于检测的是D:/BL1-BJ1 所以必须把视频存在在扫描文件夹下面
if (!s.contains(".jpg")) {
Set<String> localIp4Address = getLocalIp4Address();
for (String ip4Address : localIp4Address) {
//tableFile.setFilePath("http://" + ip4Address + ":" + port + "/BL1-BJ1/videoNew/" + file.getName());
tableFile.setFilePath("http://" + ip4Address + ":" + port + s);
}
//截取_之前字符串
int index = ok.indexOf("/");//获取第一个_索引
index = ok.indexOf("/", index + 1);//获取第二个_索引
String str1 = ok.substring(0, index);
//System.out.println("截取第二个_之前字符串:" + str1);
tableFile.setFileLocalHostPath(str1);
tableFile.setFileType(file.getName().substring(file.getName().lastIndexOf(".")));
int i = fileListener.table_FileMapperService.insertFile(tableFile);
}
}
/**
* @param
* @return
* @description 文件内容发生变化
* @version 2.0, 2019/1/24 15:05
* @author <a href="Tastill@**.cn">Tastill</a>
*/
@Override
public void onFileChange(File file) {
System.out.println("有文件被修改:" + file.getName());
}
/**
* @param
* @return
* @description 文件被删除
* @version 2.0, 2019/1/24 16:13
* @author <a href="Tastill@**.cn">Tastill</a>
*/
@Override
public void onFileDelete(File file) {
System.out.println("文件被删除" + file.getName());
}
/**
* @param
* @return
* @description 监听停止
* @version 2.0, 2019/1/24 15:07
* @author <a href="Tastill@**.cn">Tastill</a>
*/
@Override
public void onStop(FileAlterationObserver observer) {
// System.out.println("监听停止");
}
}
2.编写监控文件夹的类
package com.example.fruit.core;
import com.example.fruit.listener.FileListener;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
/*
*
* 文件夹执行的方法
*
*
* */
@Component
public class FileMonitor {
//String rootDir="D:/BL1-BJ1";
String filePath="BL1-BJ1,BL1-JJ1,BL1-JJ2,BL2-BJ1";
@PostConstruct
public void initFile() {
// 根目录
String rootPath = "D:/";
// 根目录中需要监控的目录列表
String[] monitorDirList = filePath.split(",");
// 观察者(Observer)列表
FileAlterationObserver[] observers = new FileAlterationObserver[monitorDirList.length];
FileListener fileListener = new FileListener();
for (int i = 0; i < monitorDirList.length; i++) {
String monitorPath = rootPath + monitorDirList[i];
// 创建“文件变更观察者”,每一个需要监控的目录,都对应一个观察者(Observer)
FileAlterationObserver observer = new FileAlterationObserver(monitorPath);
fileListener.setMonitorDir(monitorPath);
observer.addListener(fileListener);
observers[i] = observer;
}
// 创建文件变化监听器,构造函数中支持传入多个观察者Observer
long interval = TimeUnit.MILLISECONDS.toMillis(1000L); // 轮询间隔1秒
FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observers);
try {
// 开启监控,会另起线程,且会一直运行
monitor.start();
} catch (Exception e) {
System.out.println("目录监听启动异常");
e.printStackTrace();
}
}
}
3.视频转码的方法
public void videoFFmpeg(String path, String fileName) throws IOException {
//将下载后并解压的 "ffmpeg.exe,ffprobe.exe" 执行文件路径填写进去
FFmpeg ffmpeg = new FFmpeg(fileGovern);
FFprobe ffprobe = new FFprobe(fileFfmpeg);
FFmpegBuilder builder = new FFmpegBuilder()
// 源视频文件
.setInput(path)
// 目标视频文件 "D:/Test/新建文件夹 (2)/"+fileName
.addOutput(updateVideo + fileName)
.done();
try {
FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe);
executor.createJob(builder).run();
} catch (Exception e) {
e.printStackTrace();
}
//复制文件到指定路径
copyFileUsingFileChannels(new File(updateVideo + fileName), new File(path));
//删除转换好的文件
deleteFiles(updateVideo + fileName);
System.err.println("---------执行完毕----------------");
}
/*将文件复制到指定的目录*/
private static void copyFileUsingFileChannels(File source, File dest) throws IOException {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
inputChannel = new FileInputStream(source).getChannel();
outputChannel = new FileOutputStream(dest).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} finally {
inputChannel.close();
outputChannel.close();
}
}
/*返回所检测道德ip地址集合*/
public static Set<String> getLocalIp4Address() {
Set<String> result = new HashSet<>();
List<Inet4Address> list = null;
try {
list = getLocalIp4AddressFromNetworkInterface();
list.forEach(d -> {
result.add(d.toString().replaceAll("/", ""));
});
} catch (Exception e) {
//LoggerManager.systemLogger.error("getLocalIp4Address Exception", e);
}
return result;
}
/*
* 获取本机所有网卡信息 得到所有IPv4信息
* @return Inet4Address>
*/
public static List<Inet4Address> getLocalIp4AddressFromNetworkInterface() throws SocketException {
List<Inet4Address> addresses = new ArrayList<>(8);
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
if (networkInterfaces == null) {
return addresses;
}
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
while (inetAddresses.hasMoreElements()) {
InetAddress inetAddress = inetAddresses.nextElement();
if (inetAddress.toString().contains(ip4address)) {
addresses.add((Inet4Address) inetAddress);
}
/*
获取本机所有的ip地址
if (inetAddress instanceof Inet4Address) {
addresses.add((Inet4Address) inetAddress);
}
*/
}
}
return addresses;
}
/**
* 删除单个文件
*
* @param pathName 删除文件路径名
* @return
*/
public boolean deleteFiles(String pathName) {
boolean flag = false;
//根据路径创建文件对象
File file = new File(pathName);
//路径是个文件且不为空时删除文件
if (file.isFile() && file.exists()) {
flag = file.delete();
}
//删除失败时,返回false
return flag;
}