调整代码
This commit is contained in:
parent
0a05388483
commit
65c596c808
@ -4,6 +4,7 @@ import ink.wgink.module.file.media.manager.domain.ImageMetaInfo;
|
||||
import ink.wgink.module.file.media.manager.domain.MusicMetaInfo;
|
||||
import ink.wgink.module.file.media.manager.domain.VideoMetaInfo;
|
||||
import ink.wgink.module.file.media.manager.domain.gif.AnimatedGifEncoder;
|
||||
import ink.wgink.module.file.media.manager.process.IMediaStream;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -98,7 +99,8 @@ public class MediaManager {
|
||||
musicStreamPattern = Pattern.compile(musicStreamRegex);
|
||||
}
|
||||
|
||||
private MediaManager() {}
|
||||
private MediaManager() {
|
||||
}
|
||||
|
||||
public static MediaManager getInstance() {
|
||||
return MEDIA_MANAGER;
|
||||
@ -156,7 +158,6 @@ public class MediaManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 执行FFmpeg命令
|
||||
*
|
||||
@ -212,21 +213,69 @@ public class MediaManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令
|
||||
*
|
||||
* @param commonds
|
||||
* @param mediaStream
|
||||
* @return
|
||||
*/
|
||||
public void executeCommand(List<String> commonds, IMediaStream mediaStream) {
|
||||
if (CollectionUtils.isEmpty(commonds)) {
|
||||
LOG.error("--- 指令执行失败,因为要执行的FFmpeg指令为空! ---");
|
||||
return;
|
||||
}
|
||||
LinkedList<String> ffmpegCmds = new LinkedList<>(commonds);
|
||||
ffmpegCmds.addFirst(FFMPEG_PATH);
|
||||
LOG.info("--- 待执行的FFmpeg指令为:---" + ffmpegCmds);
|
||||
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
Process ffmpeg = null;
|
||||
try {
|
||||
// 执行ffmpeg指令
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
builder.command(ffmpegCmds);
|
||||
ffmpeg = builder.start();
|
||||
LOG.info("--- 开始执行FFmpeg指令:--- 执行线程名:" + builder.toString());
|
||||
|
||||
// 取出输出流和错误流的信息
|
||||
// 注意:必须要取出ffmpeg在执行命令过程中产生的输出信息,如果不取的话当输出流信息填满jvm存储输出留信息的缓冲区时,线程就回阻塞住
|
||||
mediaStream.error(ffmpeg.getErrorStream());
|
||||
mediaStream.input(ffmpeg.getInputStream());
|
||||
} catch (Exception e) {
|
||||
LOG.error("--- FFmpeg命令执行出错! --- 出错信息: " + e.getMessage());
|
||||
} finally {
|
||||
if (null != ffmpeg) {
|
||||
ProcessKiller ffmpegKiller = new ProcessKiller(ffmpeg);
|
||||
// JVM退出时,先通过钩子关闭FFmepg进程
|
||||
runtime.addShutdownHook(ffmpegKiller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频转换
|
||||
* <p>
|
||||
* 注意指定视频分辨率时,宽度和高度必须同时有值;
|
||||
*
|
||||
* @param fileInput 源视频路径
|
||||
* @param fileOutPut 转换后的视频输出路径
|
||||
* @param withAudio 是否保留音频;true-保留,false-不保留
|
||||
* @param crf 指定视频的质量系数(值越小,视频质量越高,体积越大;该系数取值为0-51,直接影响视频码率大小),取值参考:CrfValueEnum.code
|
||||
* @param preset 指定视频的编码速率(速率越快压缩率越低),取值参考:PresetVauleEnum.presetValue
|
||||
* @param width 视频宽度;为空则保持源视频宽度
|
||||
* @param height 视频高度;为空则保持源视频高度
|
||||
* @param fileInput 源视频路径
|
||||
* @param fileOutPut 转换后的视频输出路径
|
||||
* @param withAudio 是否保留音频;true-保留,false-不保留
|
||||
* @param crf 指定视频的质量系数(值越小,视频质量越高,体积越大;该系数取值为0-51,直接影响视频码率大小),取值参考:CrfValueEnum.code
|
||||
* @param preset 指定视频的编码速率(速率越快压缩率越低),取值参考:PresetVauleEnum.presetValue
|
||||
* @param width 视频宽度;为空则保持源视频宽度
|
||||
* @param height 视频高度;为空则保持源视频高度
|
||||
* @param mediaStream 媒体流,处理转码的过程中产生的流信息
|
||||
* @return 转换结果
|
||||
*/
|
||||
public void convertVideo(File fileInput, File fileOutPut, boolean withAudio, Integer crf, String preset, Integer width, Integer height) {
|
||||
public void convertVideo(File fileInput,
|
||||
File fileOutPut,
|
||||
boolean withAudio,
|
||||
Integer crf,
|
||||
String preset,
|
||||
Integer width,
|
||||
Integer height,
|
||||
IMediaStream mediaStream) {
|
||||
if (null == fileInput || !fileInput.exists()) {
|
||||
throw new RuntimeException("源视频文件不存在,请检查源视频路径");
|
||||
}
|
||||
@ -268,10 +317,13 @@ public class MediaManager {
|
||||
commond.add("-y"); // 当已存在输出文件时,不提示是否覆盖
|
||||
commond.add(fileOutPut.getAbsolutePath());
|
||||
|
||||
executeCommand(commond);
|
||||
if (mediaStream == null) {
|
||||
executeCommand(commond);
|
||||
return;
|
||||
}
|
||||
executeCommand(commond, mediaStream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 视频帧抽取
|
||||
* 默认抽取第10秒的帧画面
|
||||
@ -932,7 +984,7 @@ public class MediaManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MediaManagerBuilder {
|
||||
private static class MediaManagerBuilder {
|
||||
static MediaManager mediaManager = new MediaManager();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
package ink.wgink.module.file.media.manager.process;
|
||||
|
||||
import ink.wgink.module.file.media.manager.MediaManager;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: MediaProcess
|
||||
* @Description: 媒体流
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/6/10 10:52 上午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public interface IMediaStream {
|
||||
|
||||
void input(InputStream inputStream) throws Exception;
|
||||
|
||||
void error(InputStream errorStream) throws Exception;
|
||||
|
||||
}
|
@ -58,17 +58,17 @@ public class VideoServiceImpl extends DefaultBaseService implements IVideoServic
|
||||
long fileSize = video.getSize();
|
||||
String fileType = mediaService.getFileType(fileName);
|
||||
String fileMd5 = mediaService.upload(video, filePath, fileName);
|
||||
String fileFullPath = filePath + File.separator + fileName;
|
||||
String fileFullPath = filePath;
|
||||
// 构建视频内容
|
||||
VideoVO videoVO = new VideoVO();
|
||||
videoVO.setFileName(fileName);
|
||||
videoVO.setFileFullPath(fileFullPath);
|
||||
videoVO.setFilePath(VIDEO_PATH + File.separator + fileName);
|
||||
videoVO.setFilePath(VIDEO_PATH);
|
||||
videoVO.setFileSize(fileSize);
|
||||
videoVO.setFileType(fileType);
|
||||
videoVO.setFileMd5(fileMd5);
|
||||
|
||||
File uploadFile = new File(fileFullPath);
|
||||
File uploadFile = new File(fileFullPath + File.separator + fileName);
|
||||
VideoMetaInfo videoMetaInfo = MediaManager.getInstance().getVideoMetaInfo(uploadFile);
|
||||
if (videoMetaInfo == null) {
|
||||
throw new FileException("上传失败");
|
||||
@ -86,8 +86,9 @@ public class VideoServiceImpl extends DefaultBaseService implements IVideoServic
|
||||
videoVO.setAudioBitRate(musicMetaInfo.getBitRate());
|
||||
videoVO.setAudioSampleRate(musicMetaInfo.getSampleRate());
|
||||
}
|
||||
|
||||
return save(token, videoVO);
|
||||
String fileId = save(token, videoVO);
|
||||
// 转码
|
||||
return fileId;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package ink.wgink.module.file.media.task.transcoding;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: VideoTransCodingManager
|
||||
* @Description: 视频转码
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/6/10 9:46 上午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class VideoTransCodingManager {
|
||||
|
||||
private static VideoTransCodingManager VIDEO_TRANS_CODING_MANAGER = VideoTransCodingManagerBuilder.videoTransCodingManager;
|
||||
private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 10, 30L, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
|
||||
|
||||
private VideoTransCodingManager() {}
|
||||
|
||||
|
||||
|
||||
private static class VideoTransCodingManagerBuilder {
|
||||
public static VideoTransCodingManager videoTransCodingManager = new VideoTransCodingManager();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package ink.wgink.module.file.media.task.transcoding.runnable;
|
||||
|
||||
import ink.wgink.module.file.media.manager.MediaManager;
|
||||
import ink.wgink.module.file.media.manager.domain.enums.CrfValueEnum;
|
||||
import ink.wgink.module.file.media.manager.domain.enums.PresetVauleEnum;
|
||||
import ink.wgink.module.file.media.manager.process.IMediaStream;
|
||||
import ink.wgink.module.file.media.service.video.IVideoService;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: VideoTransCodingRunnable
|
||||
* @Description: 视频转码
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/6/10 10:04 上午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class VideoTransCodingRunnable implements Runnable {
|
||||
|
||||
private String sourcePath;
|
||||
private String sourceName;
|
||||
private IVideoService videoService;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
File sourceFile = new File(sourcePath + File.separator + sourceName);
|
||||
File outFile = new File(sourcePath + File.separator + sourceName + ".mp4");
|
||||
MediaManager.getInstance().convertVideo(sourceFile, outFile, true, CrfValueEnum.HIGH_QUALITY.getCode(), PresetVauleEnum.MAX_FAST_ZIP_SPEED.getPresetValue(), null, null, new IMediaStream() {
|
||||
@Override
|
||||
public void input(InputStream inputStream) throws Exception {
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
||||
System.out.println("input-" + line);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(InputStream errorStream) throws Exception {
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(errorStream));
|
||||
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
||||
System.out.println("error-" + line);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,16 @@
|
||||
import ink.wgink.module.file.media.manager.MediaManager;
|
||||
import ink.wgink.module.file.media.manager.domain.VideoMetaInfo;
|
||||
import ink.wgink.module.file.media.manager.domain.enums.CrfValueEnum;
|
||||
import ink.wgink.module.file.media.manager.domain.enums.PresetVauleEnum;
|
||||
import ink.wgink.module.file.media.manager.process.IMediaStream;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
@ -44,5 +50,49 @@ public class MediaTest {
|
||||
process.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t3() {
|
||||
MediaManager.getInstance().setFFmpegPath("/Users/wanggeng/ffmpeg/ffmpeg");
|
||||
String sourcePath = "/Users/wanggeng/Desktop/UploadFiles/videos/20210119";
|
||||
String sourceName = "85355a761e3442cda765c3bc6f5bd526.mp4";
|
||||
File sourceFile = new File(sourcePath + File.separator + sourceName);
|
||||
File outFile = new File(sourcePath + File.separator + sourceName + ".mp4");
|
||||
MediaManager.getInstance().convertVideo(sourceFile, outFile, true, CrfValueEnum.LOW_QUALITY.getCode(), PresetVauleEnum.MAX_FAST_ZIP_SPEED.getPresetValue(), null, null, new IMediaStream() {
|
||||
@Override
|
||||
public void input(InputStream inputStream) throws Exception {
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
||||
System.out.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(InputStream errorStream) throws Exception {
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(errorStream));
|
||||
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
||||
System.out.println(line);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t4() {
|
||||
String line = " Duration: 00:14:05.11, start: 0.000000, bitrate: 1022 kb/s";
|
||||
String line2 = "frame= 1 fps=0.0 q=0.0 size= 0kB time=00:00:00.13 bitrate= 2.8kbits/s speed=3.58x ";
|
||||
Pattern durationPattern = Pattern.compile("Duration: \\d{2}:\\d{2}:\\d{2}\\.\\d{2}");
|
||||
Pattern timePattern = Pattern.compile("time=\\d{2}:\\d{2}:\\d{2}\\.\\d{2}");
|
||||
Matcher durationMatcher = durationPattern.matcher(line);
|
||||
Matcher timeMatcher = timePattern.matcher(line2);
|
||||
while(durationMatcher.find()) {
|
||||
String count = durationMatcher.group();
|
||||
System.out.println(count);
|
||||
}
|
||||
while (timeMatcher.find()) {
|
||||
String count = timeMatcher.group();
|
||||
System.out.println(count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user