前言:
- 压缩时间较长, 10M压缩至1M大概需要2~3秒, 不怎么失帧;
- Demo中返回base64字符串, 可根据自己需求改返回值类型;
环境:
具体请看代码:
注意:?
- Window环境和Linux环境需要引用不同的包,建议都引用;?
- 如果是32位,请把64改为32;
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-core</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-win64</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-linux64</artifactId>
<version>2.7.3</version>
</dependency>
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
@RestController
public class DemoController {
/** 01_main方法测试 */
public static void main(String[] args) {
try {
File file = new File("C:/原视频.mp4");
String s = VideoUtil.compressVideoByFile(file);
System.out.println(s);
} catch (Exception ex) {
ex.printStackTrace();
}
}
/** 02_项目中测试 */
@PostMapping("/test/compressVideo")
public String getParams(MultipartFile file){
try {
String s = VideoUtil.compressVideoByMultipartFile(file);
System.out.println(s);
} catch (Exception ex) {
ex.printStackTrace();
}
return "成功";
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import ws.schild.jave.*;
import java.io.*;
import java.util.*;
/**
* 视频工具类
*/
@Slf4j
public class VideoUtil {
/**
* 压缩视频,返回base64;
* 接收MultipartFile格式文件;
* @param multipartFile
* @return
* @throws Exception
*/
public static String compressVideoByMultipartFile(MultipartFile multipartFile) throws Exception {
File sourceFile = MultipartFileToFile(multipartFile);
return compressVideoByFile(sourceFile);
}
/**
* 压缩视频,返回base64字符串
* sourceFile: 源文件;
*/
public static String compressVideoByFile(File sourceFile) throws Exception {
String fileName = sourceFile.getName();
File targetFile = new File(System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf(".")));
//参数:
int maxBitRate = 128000; //设置最大值:比特率越高,清晰度/音质越好
int maxSamplingRate = 44100; //设置编码时候的音量值,未设置为0,如果256,则音量值不会改变
int bitRate = 2000000; // 设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 800000 = 800kb)
int maxFrameRate = 20; // 视频帧率:15 f / s 帧率越低,效果越差
int maxWidth = 1920; //视频最大宽度(这里没使用)
try {
MultimediaObject object = new MultimediaObject(sourceFile);
// 视频属性设置
AudioInfo audioInfo = object.getInfo().getAudio();
AudioAttributes audio = new AudioAttributes();
// 设置通用编码格式
audio.setCodec("aac");
if (audioInfo.getBitRate() > maxBitRate) {
audio.setBitRate(new Integer(maxBitRate));
}
audio.setChannels(audioInfo.getChannels());
if (audioInfo.getSamplingRate() > maxSamplingRate) {
audio.setSamplingRate(maxSamplingRate);
}
// 视频编码属性配置
VideoInfo videoInfo = object.getInfo().getVideo();
VideoAttributes video = new VideoAttributes();
video.setCodec("h264");
if (videoInfo.getBitRate() > bitRate) {
video.setBitRate(bitRate);
}
if (videoInfo.getFrameRate() > maxFrameRate) {
video.setFrameRate(maxFrameRate);
}
// 限制视频宽高: 不推荐设置; 如果视频宽度大于maxWidth值,则压缩后的视频宽度会拉宽变形(亲身经历);
//int width = videoInfo.getSize().getWidth();
//int height = videoInfo.getSize().getHeight();
//if (width > maxWidth) {
// float rat = (float) width / maxWidth;
// video.setSize(new VideoSize(maxWidth, (int) (height / rat)));
//}
EncodingAttributes attr = new EncodingAttributes();
attr.setFormat("mp4");
attr.setAudioAttributes(audio);
attr.setVideoAttributes(video);
Encoder encoder = new Encoder();
encoder.encode(new MultimediaObject(sourceFile), targetFile, attr);
log.info("压缩后视频大小:[{}]",targetFile.length());
String base64FromFile = getBase64FromFile(targetFile);
//压缩后的base64转视频文件,可查看压缩后的视频:
getFileFromBase64(base64FromFile,null);
return base64FromFile;
} catch (Exception e) {
throw e;
} finally {
targetFile.delete();
}
}
/**
* 将文件转为base64
*/
public static String getBase64FromFile(File file) throws IOException {
FileInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(file);
out = new ByteArrayOutputStream();
int read = 0;
byte[] buffer = new byte[1024];
while ((read = in.read(buffer, 0, 1024)) != -1) {
out.write(buffer, 0, read);
}
return Base64.getEncoder().encodeToString(out.toByteArray());
} catch (IOException e) {
throw e;
} finally {
if (in != null) {
in.close();
}
if (out != null){
out.close();
}
}
}
/**
* 将MultipartFile转换为File
*/
public static File MultipartFileToFile(MultipartFile multiFile) throws IOException {
String fileName = multiFile.getOriginalFilename();
String prefix = fileName.substring(fileName.lastIndexOf("."));
InputStream in = null;
OutputStream out = null;
try {
File file = File.createTempFile(fileName, prefix);
out = new FileOutputStream(file);
in = multiFile.getInputStream();
int read = 0;
byte[] buffer = new byte[1024];
while ((read = in.read(buffer, 0, 1024)) != -1) {
out.write(buffer, 0, read);
}
return file;
} catch (Exception e) {
throw e;
}finally {
if (in != null){
in.close();
}
if (out != null){
out.close();
}
}
}
/**
* base64字符串转视频
* @param base64Pic
* @param filePath: 传空,则临时文件存放到项目更目录下;
* @return
* @throws Exception
*/
public static File getFileFromBase64(String base64Pic,String filePath) throws Exception {
File file = null;
if (base64Pic != null) {
try {
filePath = Optional.ofNullable(filePath).orElse("");
//文件目录
if (!"".equals(filePath)) {
File fileMk = new File(filePath);
if (!fileMk.exists() && !fileMk.isDirectory()) {
fileMk.mkdirs();
}
}
BASE64Decoder decoder = new BASE64Decoder();
//前台在用Ajax传base64值的时候会把base64中的+换成空格,所以需要替换回来。
String baseValue = base64Pic.replaceAll(" ", "+");
//去除base64中无用的部分
byte[] b = decoder.decodeBuffer(baseValue.replace("data:video/mp4;base64,", ""));
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
//存到临时文件中
file = new File(filePath + System.currentTimeMillis()+".mp4");
OutputStream out = new FileOutputStream(file.getPath());
out.write(b);
out.flush();
out.close();
} catch (Exception e) {
throw e;
}finally {
//删除filePath下的临时文件
if (file != null) {
file.delete();
}
}
}
return file;
}
}
|