2018-03-25 13:26:51 +08:00
|
|
|
|
package cn.keking.service.impl;
|
|
|
|
|
|
|
2021-04-18 12:40:59 +08:00
|
|
|
|
import cn.keking.config.ConfigConstants;
|
2019-05-16 17:46:08 +08:00
|
|
|
|
import cn.keking.model.FileAttribute;
|
2021-04-18 12:40:59 +08:00
|
|
|
|
import cn.keking.model.FileType;
|
2020-05-19 11:04:53 +08:00
|
|
|
|
import cn.keking.model.ReturnResponse;
|
2018-03-25 13:26:51 +08:00
|
|
|
|
import cn.keking.service.FilePreview;
|
2020-05-19 11:04:53 +08:00
|
|
|
|
import cn.keking.utils.DownloadUtils;
|
2020-12-26 19:13:50 +08:00
|
|
|
|
import cn.keking.service.FileHandlerService;
|
2020-05-19 11:04:53 +08:00
|
|
|
|
import cn.keking.web.filter.BaseUrlFilter;
|
2021-04-18 12:40:59 +08:00
|
|
|
|
import org.artofsolving.jodconverter.util.ConfigUtils;
|
|
|
|
|
|
import org.bytedeco.ffmpeg.global.avcodec;
|
|
|
|
|
|
import org.bytedeco.javacv.FFmpegFrameGrabber;
|
|
|
|
|
|
import org.bytedeco.javacv.FFmpegFrameRecorder;
|
|
|
|
|
|
import org.bytedeco.javacv.Frame;
|
2018-03-25 13:26:51 +08:00
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import org.springframework.ui.Model;
|
2021-04-18 12:40:59 +08:00
|
|
|
|
import java.io.File;
|
2020-12-27 14:06:06 +08:00
|
|
|
|
|
2018-03-25 13:26:51 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @author : kl
|
|
|
|
|
|
* @authorboke : kailing.pub
|
|
|
|
|
|
* @create : 2018-03-25 上午11:58
|
|
|
|
|
|
* @description:
|
|
|
|
|
|
**/
|
|
|
|
|
|
@Service
|
|
|
|
|
|
public class MediaFilePreviewImpl implements FilePreview {
|
|
|
|
|
|
|
2020-12-26 19:13:50 +08:00
|
|
|
|
private final FileHandlerService fileHandlerService;
|
2020-12-27 14:47:28 +08:00
|
|
|
|
private final OtherFilePreviewImpl otherFilePreview;
|
2020-05-19 11:04:53 +08:00
|
|
|
|
|
2021-04-18 12:40:59 +08:00
|
|
|
|
private static Object LOCK=new Object();
|
|
|
|
|
|
|
2020-12-27 14:47:28 +08:00
|
|
|
|
public MediaFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
2020-12-26 19:13:50 +08:00
|
|
|
|
this.fileHandlerService = fileHandlerService;
|
2020-12-27 14:47:28 +08:00
|
|
|
|
this.otherFilePreview = otherFilePreview;
|
2020-05-19 11:04:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-03-25 13:26:51 +08:00
|
|
|
|
@Override
|
2019-06-17 14:21:16 +08:00
|
|
|
|
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
2020-05-19 11:04:53 +08:00
|
|
|
|
// 不是http开头,浏览器不能直接访问,需下载到本地
|
|
|
|
|
|
if (url != null && !url.toLowerCase().startsWith("http")) {
|
2020-12-27 01:43:50 +08:00
|
|
|
|
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileAttribute.getName());
|
2020-12-27 14:47:28 +08:00
|
|
|
|
if (response.isFailure()) {
|
|
|
|
|
|
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
2020-05-19 11:04:53 +08:00
|
|
|
|
} else {
|
2021-04-18 12:40:59 +08:00
|
|
|
|
url=BaseUrlFilter.getBaseUrl() + fileHandlerService.getRelativePath(response.getContent());
|
|
|
|
|
|
fileAttribute.setUrl(url);
|
2020-05-19 11:04:53 +08:00
|
|
|
|
}
|
2021-04-18 12:40:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(checkNeedConvert(fileAttribute.getSuffix())){
|
|
|
|
|
|
url=convertUrl(fileAttribute);
|
|
|
|
|
|
}else{
|
|
|
|
|
|
//正常media类型
|
|
|
|
|
|
String[] medias = ConfigConstants.getMedia();
|
|
|
|
|
|
for(String media:medias){
|
|
|
|
|
|
if(media.equals(fileAttribute.getSuffix())){
|
|
|
|
|
|
model.addAttribute("mediaUrl", url);
|
|
|
|
|
|
return MEDIA_FILE_PREVIEW_PAGE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return otherFilePreview.notSupportedFile(model, fileAttribute, "暂不支持");
|
2020-05-19 11:04:53 +08:00
|
|
|
|
}
|
2018-03-25 13:26:51 +08:00
|
|
|
|
model.addAttribute("mediaUrl", url);
|
2020-12-27 15:14:32 +08:00
|
|
|
|
return MEDIA_FILE_PREVIEW_PAGE;
|
2018-03-25 13:26:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-18 12:40:59 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 检查视频文件处理逻辑
|
|
|
|
|
|
* 返回处理过后的url
|
|
|
|
|
|
* @return url
|
|
|
|
|
|
*/
|
|
|
|
|
|
private String convertUrl(FileAttribute fileAttribute) {
|
|
|
|
|
|
String url = fileAttribute.getUrl();
|
|
|
|
|
|
if(fileHandlerService.listConvertedMedias().containsKey(url)){
|
|
|
|
|
|
url= fileHandlerService.getConvertedMedias(url);
|
|
|
|
|
|
}else{
|
|
|
|
|
|
if(!fileHandlerService.listConvertedMedias().containsKey(url)){
|
|
|
|
|
|
synchronized(LOCK){
|
|
|
|
|
|
if(!fileHandlerService.listConvertedMedias().containsKey(url)){
|
|
|
|
|
|
String convertedUrl=convertToMp4(fileAttribute);
|
|
|
|
|
|
//加入缓存
|
|
|
|
|
|
fileHandlerService.addConvertedMedias(url,convertedUrl);
|
|
|
|
|
|
url=convertedUrl;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return url;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 检查视频文件转换是否已开启,以及当前文件是否需要转换
|
|
|
|
|
|
* @return
|
|
|
|
|
|
*/
|
|
|
|
|
|
private boolean checkNeedConvert(String suffix) {
|
|
|
|
|
|
//1.检查开关是否开启
|
|
|
|
|
|
if("false".equals(ConfigConstants.getMediaConvertDisable())){
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
//2.检查当前文件是否需要转换
|
|
|
|
|
|
String[] mediaTypesConvert = FileType.MEDIA_TYPES_CONVERT;
|
|
|
|
|
|
String type = suffix;
|
|
|
|
|
|
for(String temp : mediaTypesConvert){
|
|
|
|
|
|
if(type.equals(temp)){
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 将浏览器不兼容视频格式转换成MP4
|
|
|
|
|
|
* @param fileAttribute
|
|
|
|
|
|
* @return
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static String convertToMp4(FileAttribute fileAttribute) {
|
|
|
|
|
|
|
|
|
|
|
|
//说明:这里做临时处理,取上传文件的目录
|
|
|
|
|
|
String homePath = ConfigUtils.getHomePath();
|
|
|
|
|
|
String filePath = homePath+File.separator+"file"+File.separator+"demo"+File.separator+fileAttribute.getName();
|
|
|
|
|
|
String convertFileName=fileAttribute.getUrl().replace(fileAttribute.getSuffix(),"mp4");
|
|
|
|
|
|
|
|
|
|
|
|
File file=new File(filePath);
|
|
|
|
|
|
FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(file);
|
|
|
|
|
|
String fileName = null;
|
|
|
|
|
|
Frame captured_frame = null;
|
|
|
|
|
|
FFmpegFrameRecorder recorder = null;
|
|
|
|
|
|
try {
|
|
|
|
|
|
fileName = file.getAbsolutePath().replace(fileAttribute.getSuffix(),"mp4");
|
|
|
|
|
|
File desFile=new File(fileName);
|
|
|
|
|
|
//判断一下防止穿透缓存
|
|
|
|
|
|
if(desFile.exists()){
|
|
|
|
|
|
return fileName;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
frameGrabber.start();
|
|
|
|
|
|
recorder = new FFmpegFrameRecorder(fileName, frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());
|
|
|
|
|
|
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); //avcodec.AV_CODEC_ID_H264 //AV_CODEC_ID_MPEG4
|
|
|
|
|
|
recorder.setFormat("mp4");
|
|
|
|
|
|
recorder.setFrameRate(frameGrabber.getFrameRate());
|
|
|
|
|
|
//recorder.setSampleFormat(frameGrabber.getSampleFormat()); //
|
|
|
|
|
|
recorder.setSampleRate(frameGrabber.getSampleRate());
|
2018-03-25 13:26:51 +08:00
|
|
|
|
|
2021-04-18 12:40:59 +08:00
|
|
|
|
recorder.setAudioChannels(frameGrabber.getAudioChannels());
|
|
|
|
|
|
recorder.setFrameRate(frameGrabber.getFrameRate());
|
|
|
|
|
|
recorder.start();
|
|
|
|
|
|
while ((captured_frame = frameGrabber.grabFrame()) != null) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
recorder.setTimestamp(frameGrabber.getTimestamp());
|
|
|
|
|
|
recorder.record(captured_frame);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
recorder.stop();
|
|
|
|
|
|
recorder.release();
|
|
|
|
|
|
frameGrabber.stop();
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
}
|
|
|
|
|
|
//是否删除源文件
|
|
|
|
|
|
//file.delete();
|
|
|
|
|
|
return convertFileName;
|
|
|
|
|
|
}
|
2018-03-25 13:26:51 +08:00
|
|
|
|
}
|