: 三方摄像头厂商云视频只会短时间保留,如需长时间保留则需转储至自己的资源服务器。应用场景
: 保存海康的视频成MP4格式的视频,最后无法在网页上播放,或者干脆本地无法打开。解决案例
引入pom依赖
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.7</version>
</dependency>
视频转码核心代码,转码成功后会在同级目录下生成转码后的视频
/**
* 将视频文件转码为视频编码为H264并且音频编码为ACC的视频
* @param absolutePath 视频文件路径
* @param format 转码后的封装格式
* @return
* @throws Exception
*/
public String convert(String absolutePath, String format) throws Exception {
String path = absolutePath;
FFmpegFrameGrabber frameGrabber = FFmpegFrameGrabber.createDefault(path);
String fileName = null;
Frame capturedFrame = null;
FFmpegFrameRecorder recorder = null;
try {
int index = path.lastIndexOf(".");
if (index < 0) {
index += path.length();
}
fileName = path.replace(path.substring(index), "_recode." + format);
frameGrabber.start();
recorder = new FFmpegFrameRecorder(fileName, frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
recorder.setFormat(format);
recorder.setFrameRate(frameGrabber.getFrameRate());
recorder.setVideoBitrate(frameGrabber.getVideoBitrate());
recorder.setAspectRatio(frameGrabber.getAspectRatio());
recorder.setAudioBitrate(frameGrabber.getAudioBitrate());
recorder.setAudioOptions(frameGrabber.getAudioOptions());
recorder.setSampleRate(frameGrabber.getSampleRate());
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
recorder.start();
while (true) {
capturedFrame = frameGrabber.grabFrame();
if (capturedFrame == null) {
log.info(fileName + "转码完成");
break;
}
recorder.record(capturedFrame);
}
} finally {
if (recorder != null) {
try {
recorder.close();
} catch (Exception e) {
log.warn("recorder.close异常", e);
}
}
try {
frameGrabber.close();
} catch (org.bytedeco.javacv.FrameGrabber.Exception e) {
log.warn("frameGrabber.close异常", e);
}
}
return fileName;
}
处理视频转码,转码后上传资源服务器,删除中转资源
public void upload(String url) {
// url = "https://open.ys7.com/api/lapp/mq/downloadurl?appKey=14356cdcd2da4703b2db05ae56e7420f&fileKey=ISAPI_FILES/K27765188_1/20221209113342970-K27765188-1-10000-2$encrypt=2,2022-12-09T11:33:46,434e6d9f142facfc6b678c1b21430be5";
try {
MultipartFile multipartFile = getFile(url, "test.mp4");
// 获取文件的名称
String originalFilename = multipartFile.getOriginalFilename();
// 文件后缀 例如:.png
String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf("."));
// uuid 生成文件名
String uuid = String.valueOf(UUID.randomUUID());
// 根路径,在 resources/static/upload
String basePath = ResourceUtils.getURL("classpath:").getPath() + "upload/";
// 新的文件名,使用uuid生成文件名
String fileName = uuid + fileSuffix;
// 创建新的文件
File fileExist = new File(basePath);
// 文件夹不存在,则新建
if (!fileExist.exists()) {
fileExist.mkdirs();
}
// 获取文件对象
File file = new File(basePath, fileName);
// 完成文件的上传
multipartFile.transferTo(file);
String substring = basePath.substring(basePath.indexOf("/") + 1);
log.info("basePath:{}", substring + fileName);
String mp4 = convert(substring + fileName, "mp4");
// 上传转码后的mp4文件
InputStream inStream = Files.newInputStream(Paths.get(mp4));
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while ((rc = inStream.read(buff, 0, 100)) > 0) {
swapStream.write(buff, 0, rc);
}
byte[] in2b = swapStream.toByteArray();
BytesToMultipartFile toMultipartFile = new BytesToMultipartFile(in2b, "file", fileName, MediaType.MULTIPART_FORM_DATA);
R<BladeFile> picFileR = ossClient.feignPutFileAttach(toMultipartFile, InvoiceConstant.ATTACH_TYPE, InvoiceConstant.FILE_PIC_URL + fileName, IdWorker.getId());
System.out.println("picFileR:"+picFileR.getData().getLink());
// 处理完毕删除文件
deleteFolders(substring);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
删除文件下所有文件,为避免并发操作,此处可以优化为删除指定文件
public void deleteFolders(String filePath) {
Path path = Paths.get(filePath);
try {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException {
Files.delete(file);
log.info("删除文件: {}", file);
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
e.printStackTrace();
}
}