对于视频上传与图片上传没有多大区别,主要在我们对视频的处理,如截取某一帧作为封面图,获取视频时长等。
//视频上传
//对登录用户上传视频进行处理
if(_file.isEmpty()) {
return APIResultJson.getFailInstance("视频不能为空!");
} else {
//获取当前上传文件的文件名称
String originalFileName = _file.getOriginalFilename();
//获取文件后缀名
String fileSuffix = getExtName(originalFileName, '.');
//文件新名称
String newFileName = getUUIDFileName(originalFileName);
//获取文件上传hash算法路径
String fileSaveAllPath = makePath(newFileName);
//绝对路径
String absolutePath = fileSaveRootPath + fileSaveAllPath;
//封装上传文件位置的全路径
File uploadPath = new File(absolutePath, newFileName);
//把本地文件上传到封装上传文件位置的全路径
try {
_file.transferTo(uploadPath);
} catch (IOException e) {
APIResultJson.getFailInstance("视频发布失败,请稍后尝试!");
e.printStackTrace();
}
//获取用户上传视频路径,fileSaveAllPath + "\" + newFileName
//获取视频秒数
Long videoTimes = VideoUtils.getVideoTime(uploadPath);
//截取视频中某一针,将其保存为视频封面图
BufferedImage bi = VideoUtils.interceptPictureByVideo(uploadPath);
//重绘图片时先将案例图保存到视频目录下
String picName = newFileName.substring(0, newFileName.lastIndexOf('.')) + ".jpg";
String interceptPicturePath = absolutePath + "\\" + picName;
try {
ImageIO.write(bi, "jpg", new File(interceptPicturePath));
} catch (IOException e) {
APIResultJson.getFailInstance("视频截取图片失败,请重写上传!");
}
//保存视频信息到数据库
VInfo vi = new VInfo();
vi.setsName(_name);//视频名称
vi.setsPath(fileSaveAllPath + "\\" + newFileName);//视频存储路径
vi.setnSeconds(videoTimes);//视频秒数
vi.setcDesc(_desc);//视频描述
vi.setsCoverPath(fileSaveAllPath + "\\" + picName);//视频封面图存储路径
vi.settPubdate(new Date());//发布时间
vi.setiWcs(Long.valueOf(_wcs));//谁可见
vi.setcComment(_comment);//是否允许评论
vi.setcStatus("1");//视频状态
vi.setiUid(cui.getId());
vi.settEdit(new Date());
int result = vis.insertSelective(vi);
if(result <= 0) {
return APIResultJson.getFailInstance("视频发布失败!");
}
}
对视频处理我们使用到了
JavaCV
1. pom.xml
引入Jar
包
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv-platform</artifactId>
<version>3.4.1-1.4.1</version>
</dependency>
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>3.4.2-1.4.1</version>
</dependency>
2.获取指定帧截取为图片
/**
* 获取指定视频的帧截取为图片
* @param file 源视频文件
* @return
*/
public static BufferedImage interceptPictureByVideo(File file) {
//FFmpegFrameGrabber可以理解为解码器,也可以理解为帧收集器
FFmpegFrameGrabber ffg = new FFmpegFrameGrabber(file);
try {
//启动
ffg.start();
//获取视频帧长度
int videoLength = ffg.getLengthInFrames();
int i = 0;
Frame frame = null;
while (i < videoLength) {
//过滤前5帧,避免出现全黑的图片
frame = ffg.grabFrame();
if((i > 5) && (frame.image != null)) {
break;
}
i++;
}
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage srcBi = converter.getBufferedImage(frame);
int owidth = srcBi.getWidth();
int oheight = srcBi.getHeight();
//对截取的帧进行等比例缩放
int width = 800;
int height = (int) ((double)(width / owidth) * oheight);
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
bi.getGraphics().drawImage(srcBi.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
ffg.stop();
return bi;
} catch (FrameGrabber.Exception e) {
e.printStackTrace();
return null;
}
}
3. 获取视频时长
/**
* 获取视频时长,单位为秒
* @param file
* @return
*/
public static Long getVideoTime(File file) {
Long times = 0L;
FFmpegFrameGrabber ffg = new FFmpegFrameGrabber(file);
try {
ffg.start();
times = ffg.getLengthInTime() / (1000 * 1000);
ffg.stop();
} catch (FrameGrabber.Exception e) {
e.printStackTrace();
return times;
}
return times;
}
对文件名进行处理,使用hash算法打散存储防止目录下出现太多文件
/**
* 上传文件到服务器时,为防止一个目录下出现太多文件,使用hash算法打散存储
* @param fileName 文件名称
* @return
*/
public String makePath(String fileName) {
//得到文件名的hashCode的值,得到的就是fileName这个字符串对象在内存中的地址
int hashCode = fileName.hashCode();
int dirOPath = hashCode & 0xf;//0--15
int dirTPath = (hashCode & 0xf0) >> 4;//0-15
String path = dirOPath + "\\" + dirTPath;
//构造新的保存目录
String newPath = fileSaveRootPath + path;
//File即可代表文件也可以代表目录
File file = new File(newPath);
//如果目录不存在,则创建
if(!file.exists()) {
file.mkdirs();
}
return path;
}
使用UUID对文件名做处理,防止重复
/**
* 将文件名转换成uuid表示,防止文件名上传重复
* @param fileName
* @return
*/
private String getUUIDFileName(String fileName) {
UUID uuid = UUID.randomUUID();
StringBuilder sb = new StringBuilder(100);
sb.append(uuid.toString()).append(".").append(this.getExtName(fileName, '.'));
return sb.toString();
}
获取文件后缀
/**
* 获取文件后缀名
* @param s
* @param split
* @return
*/
private String getExtName(String s, char split) {
int i = s.lastIndexOf(split);
int leg = s.length();
return i > 0 ? (i + 1) == leg ? " " : s.substring(i + 1, s.length()) : " ";
}
网友评论