update
This commit is contained in:
parent
e6568480b7
commit
129e407646
@ -1,6 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
@ -9,51 +8,31 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="layui-layout layui-layout-admin">
|
||||
<div id="header"></div>
|
||||
<div class="layui-body" style="left: 0px;">
|
||||
<div style="width: 50%;margin-left: 25%; margin-top: 2%;" >
|
||||
<blockquote class="layui-elem-quote" style="background-color: #FFFFFF">
|
||||
本站点采用限时注册模式,仅登陆用户可使用。当前注册状态: <span style="color: #FD482C" id="model">关闭</span>
|
||||
</blockquote>
|
||||
<div align="center">
|
||||
|
||||
<img src="https://s1.hdslb.com/bfs/static/jinkela/international-home/assets/bgm-nodata.png" style="float: contour">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="footer"></div>
|
||||
</div>
|
||||
<button id="btn" type="button" class="layui-btn" onclick="onButton()">默认按钮</button>
|
||||
|
||||
<script src="/layui/layui.js"></script>
|
||||
<script src="/js/jquery-3.2.1.js"></script>
|
||||
<script src="/js/CommonConfig.js"></script>
|
||||
<script src="/js/httpUtils.js"></script>
|
||||
<script>
|
||||
layui.use(['layer', 'form', 'element'], function () {
|
||||
var layer = layui.layer
|
||||
, form = layui.form;
|
||||
|
||||
});
|
||||
headerModel=0;
|
||||
$('#header').load("/html/header.html");
|
||||
$('#footer').load("/html/footer.html");
|
||||
$.post("/system/public/reg.do",function (json) {
|
||||
if(json.data.userReg){
|
||||
$('#model').css('color','#499C54')
|
||||
$('#model').text('开启')
|
||||
}else{
|
||||
$('#model').css('color','#FD482C')
|
||||
$('#model').text('关闭')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<script>
|
||||
function onButton(){
|
||||
getLiveVideoList({
|
||||
success:function(json){
|
||||
console.log(json)
|
||||
},
|
||||
error:function(error){
|
||||
|
||||
</body>
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.layui-body {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
background-color: #F2F2F2;
|
||||
}
|
||||
|
||||
</style>
|
||||
</html>
|
@ -3,10 +3,13 @@ package com.yutou.bilibili.Controllers;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.yutou.biliapi.bean.live.database.LiveConfigDatabaseBean;
|
||||
import com.yutou.bilibili.Tools.Tools;
|
||||
import com.yutou.bilibili.datas.ResultData;
|
||||
import com.yutou.bilibili.datas.ReturnCode;
|
||||
import com.yutou.bilibili.services.LiveConfigService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -60,7 +63,7 @@ public class LiveConfigController {
|
||||
public JSONObject getAllConfig() {
|
||||
List<LiveConfigDatabaseBean> config = configService.getAllConfig();
|
||||
if (config != null) {
|
||||
return ResultData.success(JSONArray.parseArray(JSONArray.toJSONString(config)));
|
||||
return ResultData.success(config);
|
||||
}
|
||||
return ResultData.fail(ReturnCode.RC999);
|
||||
}
|
||||
@ -77,4 +80,9 @@ public class LiveConfigController {
|
||||
}
|
||||
return ResultData.fail(ReturnCode.RC999);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "face", method = RequestMethod.GET)
|
||||
public ResponseEntity<FileSystemResource> getFace(String roomId) {
|
||||
return Tools.getFile(configService.getFace(roomId));
|
||||
}
|
||||
}
|
||||
|
@ -7,16 +7,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class TestControllers {
|
||||
@RequestMapping("/root/test")
|
||||
@RequestMapping("/root/all")
|
||||
@ResponseBody
|
||||
public String test(){
|
||||
FFmpegUtils.killAll();
|
||||
return "hello world";
|
||||
}
|
||||
@RequestMapping("/root/kill")
|
||||
@ResponseBody
|
||||
public String kill(String roomId){
|
||||
FFmpegUtils.kill(roomId);
|
||||
return FFmpegUtils.check(roomId)+"";
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.yutou.bilibili.Tools;
|
||||
|
||||
import com.yutou.bilibili.services.LiveVideoService;
|
||||
import com.yutou.bilibili.services.SystemService;
|
||||
import com.yutou.common.utils.FFmpegUtils;
|
||||
import com.yutou.common.utils.Log;
|
||||
@ -7,15 +8,18 @@ import jakarta.annotation.Resource;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Component
|
||||
public class ApplicationClose implements ApplicationListener<ContextClosedEvent> {
|
||||
@Resource
|
||||
SystemService systemConfigService;
|
||||
@Resource
|
||||
LiveVideoService videoService;
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
|
||||
Log.i("服务结束");
|
||||
systemConfigService.stop();
|
||||
FFmpegUtils.killAll();
|
||||
videoService.stopAll();
|
||||
}
|
||||
}
|
||||
|
@ -42,15 +42,15 @@ public class FFmpegUtils {
|
||||
file.getAbsolutePath(),
|
||||
out.getAbsolutePath() + File.separator + file.getName());
|
||||
Log.i(exec);
|
||||
Process process= ProcessUtils.exec(exec);
|
||||
Process process = ProcessUtils.exec(ffmpeg, "-i", file.getAbsolutePath(), "-c:v", "copy", "-y", out.getAbsolutePath() + File.separator + file.getName());
|
||||
InputStream inputStream = process.getErrorStream();
|
||||
byte[] bytes = new byte[1024];
|
||||
while (inputStream.read(bytes) > -1) {
|
||||
}
|
||||
inputStream.close();
|
||||
AppTools.copyFileToName(out.getAbsolutePath()+File.separator+file.getName(), file.getParent() + File.separator, file.getName().replace(".mp4", "_ffmpeg.mp4"), true);
|
||||
AppTools.copyFileToName(out.getAbsolutePath() + File.separator + file.getName(), file.getParent() + File.separator, file.getName().replace(".mp4", "_ffmpeg.mp4"), true);
|
||||
file.delete();
|
||||
new File(out.getAbsolutePath()+File.separator+file.getName()).delete();
|
||||
new File(out.getAbsolutePath() + File.separator + file.getName()).delete();
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
}
|
||||
|
@ -7,11 +7,12 @@ import java.io.InputStreamReader;
|
||||
|
||||
|
||||
public class ProcessUtils {
|
||||
public static boolean isRuntimeSystemOfWindow(){
|
||||
return System.getProperty ("os.name").contains("Windows");
|
||||
public static boolean isRuntimeSystemOfWindow() {
|
||||
return System.getProperty("os.name").contains("Windows");
|
||||
}
|
||||
|
||||
public static void killProcess(Long pid) throws Exception {
|
||||
if(pid==null) {
|
||||
if (pid == null) {
|
||||
return;
|
||||
}
|
||||
if (isRuntimeSystemOfWindow()) {
|
||||
@ -25,8 +26,9 @@ public class ProcessUtils {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean isProcessRunning(Long pid) throws Exception {
|
||||
if(pid==null) {
|
||||
if (pid == null) {
|
||||
return false;
|
||||
}
|
||||
String command;
|
||||
@ -48,24 +50,19 @@ public class ProcessUtils {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static Process exec(String exec)throws Exception{
|
||||
if(isRuntimeSystemOfWindow()) {
|
||||
return Runtime.getRuntime().exec(new String[]{
|
||||
"cmd",
|
||||
"/c",
|
||||
exec
|
||||
}
|
||||
);
|
||||
public static Process exec(String exec) throws Exception {
|
||||
if(isRuntimeSystemOfWindow()){
|
||||
return exec("cmd.exe","/c",exec);
|
||||
}else{
|
||||
return Runtime.getRuntime().exec(new String[]{
|
||||
"sh",
|
||||
"-c",
|
||||
exec
|
||||
}
|
||||
);
|
||||
return exec("sh","-c",exec);
|
||||
}
|
||||
}
|
||||
public static Process exec(String... command) throws Exception {
|
||||
ProcessBuilder pb;
|
||||
pb = new ProcessBuilder(command);
|
||||
return pb.start();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,19 @@
|
||||
package com.yutou.bilibili.datas;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ResultData<T> {
|
||||
private int status;
|
||||
private String message;
|
||||
private T data;
|
||||
private long timestamp ;
|
||||
private int count;
|
||||
private long timestamp;
|
||||
|
||||
public ResultData() {
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
@ -20,6 +25,9 @@ public class ResultData<T> {
|
||||
resultData.setStatus(ReturnCode.RC100.getCode());
|
||||
resultData.setMessage(ReturnCode.RC100.getMessage());
|
||||
resultData.setData(data);
|
||||
if (data instanceof Collection<?>) {
|
||||
resultData.count = ((Collection<?>) data).size();
|
||||
}
|
||||
return JSONObject.parseObject(JSONObject.toJSONString(resultData));
|
||||
}
|
||||
|
||||
@ -29,9 +37,11 @@ public class ResultData<T> {
|
||||
resultData.setMessage(message);
|
||||
return JSONObject.parseObject(JSONObject.toJSONString(resultData));
|
||||
}
|
||||
|
||||
public static JSONObject success(ReturnCode code) {
|
||||
return fail(code);
|
||||
}
|
||||
|
||||
public static <T> JSONObject fail(ReturnCode code) {
|
||||
ResultData<T> resultData = new ResultData<>();
|
||||
resultData.setStatus(code.getCode());
|
||||
|
@ -5,10 +5,12 @@ import com.yutou.biliapi.bean.live.MasterInfoBean;
|
||||
import com.yutou.biliapi.bean.live.database.LiveConfigDatabaseBean;
|
||||
import com.yutou.biliapi.databases.BiliLiveConfigDatabase;
|
||||
import com.yutou.biliapi.net.BiliLiveNetApiManager;
|
||||
import com.yutou.common.okhttp.HttpDownloadUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
@ -34,6 +36,7 @@ public class LiveConfigService {
|
||||
bean.setAnchorFace(infoBean.getInfo().getFace());
|
||||
bean.setAnchorName(infoBean.getInfo().getUname());
|
||||
database.setConfig(bean);
|
||||
downloadFace(bean);
|
||||
return bean;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@ -48,6 +51,7 @@ public class LiveConfigService {
|
||||
bean.setRoomId(roomId);
|
||||
bean.setSql_time(config.getSql_time());
|
||||
database.setConfig(bean);
|
||||
downloadFace(bean);
|
||||
return bean;
|
||||
}
|
||||
|
||||
@ -67,4 +71,22 @@ public class LiveConfigService {
|
||||
public LiveConfigDatabaseBean getConfig(BigInteger roomId) {
|
||||
return database.getConfig(roomId);
|
||||
}
|
||||
|
||||
public File getFace(String roomId){
|
||||
LiveConfigDatabaseBean config = database.getConfig(new BigInteger(roomId));
|
||||
if (config == null) {
|
||||
return null;
|
||||
}
|
||||
return new File(config.getRecordPath() + File.separator + config.getAnchorName() + File.separator + config.getAnchorFace());
|
||||
}
|
||||
|
||||
private void downloadFace(LiveConfigDatabaseBean bean) {
|
||||
HttpDownloadUtils.download(
|
||||
new HttpDownloadUtils.Builder()
|
||||
.setPath(bean.getRecordPath() + File.separator + bean.getAnchorName())
|
||||
.setUrl(bean.getAnchorFace())
|
||||
.setFileName("face.jpg")
|
||||
);
|
||||
bean.setAnchorFace(bean.getRecordPath() + File.separator + bean.getAnchorName() + File.separator + "face.jpg");
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import com.yutou.bilibili.datas.VideoFilePath;
|
||||
import com.yutou.bilibili.interfaces.DownloadInterface;
|
||||
import com.yutou.common.okhttp.HttpCallback;
|
||||
import com.yutou.common.okhttp.HttpDownloadUtils;
|
||||
import com.yutou.common.record.AbsVideoRecord;
|
||||
import com.yutou.common.utils.ConfigTools;
|
||||
import com.yutou.common.utils.FFmpegUtils;
|
||||
import com.yutou.common.utils.Log;
|
||||
@ -47,12 +48,12 @@ import static com.alibaba.fastjson2.util.DateUtils.DateTimeFormatPattern.DATE_FO
|
||||
@Service
|
||||
public class LiveVideoService {
|
||||
ThreadPoolExecutor executor;
|
||||
private final Map<LiveConfigDatabaseBean, VideoTask> liveVideoMap = new HashMap<>();
|
||||
private final List<String> userStopList = new ArrayList<>();//手动停止列表
|
||||
|
||||
AbsVideoRecord videoRecord;
|
||||
|
||||
public LiveVideoService() {
|
||||
Log.i("初始化下载服务");
|
||||
videoRecord=new FFmpegUtils();
|
||||
executor = new ThreadPoolExecutor(2, 4, Long.MAX_VALUE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
|
||||
}
|
||||
|
||||
@ -63,27 +64,22 @@ public class LiveVideoService {
|
||||
if (isUser) {
|
||||
userStopList.remove(bean.getRoomId().toString());
|
||||
}
|
||||
if (liveVideoMap.containsKey(bean)) {
|
||||
if (videoRecord.check(bean.getRoomId().toString())) {
|
||||
return;
|
||||
}
|
||||
Log.i("添加下载任务:" + liveVideoMap.keySet().size());
|
||||
liveVideoMap.put(bean, null);
|
||||
BiliLiveNetApiManager.getInstance().getApi(bean.getRecordUid()).getRoomInfo(bean.getRoomId().toString()).enqueue(new HttpCallback<LiveRoomInfo>() {
|
||||
@Override
|
||||
public void onResponse(Headers headers, int code, String status, LiveRoomInfo response, String rawResponse) {
|
||||
if (response.getLiveStatus() == 1) {
|
||||
VideoTask task = new VideoTask(bean, response);
|
||||
executor.execute(task);
|
||||
liveVideoMap.put(bean, task);
|
||||
} else {
|
||||
liveVideoMap.remove(bean);
|
||||
Log.i("移除下载");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
liveVideoMap.remove(bean);
|
||||
Log.i("移除下载");
|
||||
}
|
||||
});
|
||||
@ -95,36 +91,18 @@ public class LiveVideoService {
|
||||
if (isUser) {
|
||||
userStopList.add(roomId);
|
||||
}
|
||||
for (Map.Entry<LiveConfigDatabaseBean, VideoTask> entry : liveVideoMap.entrySet()) {
|
||||
if (entry.getKey().getRoomId().toString().equals(roomId)) {
|
||||
entry.getValue().isDownload = false;
|
||||
liveVideoMap.remove(entry.getKey());
|
||||
Log.i("移除下载");
|
||||
break;
|
||||
}
|
||||
}
|
||||
videoRecord.kill(roomId);
|
||||
}
|
||||
|
||||
public boolean check(String roomId) {
|
||||
for (LiveConfigDatabaseBean bean : liveVideoMap.keySet()) {
|
||||
if (bean.getRoomId().toString().equals(roomId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public JSONArray getDownloadTasks() {
|
||||
JSONArray array = new JSONArray();
|
||||
array.addAll(liveVideoMap.keySet());
|
||||
array.addAll(videoRecord.getRoomIds());
|
||||
return array;
|
||||
}
|
||||
|
||||
public void stopAll() {
|
||||
for (VideoTask task : liveVideoMap.values()) {
|
||||
task.isDownload = false;
|
||||
}
|
||||
liveVideoMap.clear();
|
||||
videoRecord.killAll();
|
||||
}
|
||||
|
||||
private class VideoTask implements Runnable {
|
||||
@ -163,7 +141,7 @@ public class LiveVideoService {
|
||||
}
|
||||
|
||||
private void stop() {
|
||||
liveVideoMap.remove(bean);
|
||||
videoRecord.kill(bean.getRoomId().toString());
|
||||
api.getRoomInfo(config.getRoomId().toString()).enqueue(new HttpCallback<LiveRoomInfo>() {
|
||||
@Override
|
||||
public void onResponse(Headers headers, int code, String status, LiveRoomInfo response, String rawResponse) {
|
||||
@ -196,7 +174,7 @@ public class LiveVideoService {
|
||||
HttpDownloadUtils.download(new HttpDownloadUtils.Builder().setUrl(roomInfo.getKeyframe())
|
||||
.setPath(rootPath.getAbsolutePath())
|
||||
.setFileName("poster.jpg"));
|
||||
LiveInfoNfoTools.saveLiveInfoNfo(roomInfo,rootPath.getAbsolutePath(),new File(savePath).getName().replace(".flv",".nfo"));
|
||||
LiveInfoNfoTools.saveLiveInfoNfo(roomInfo, rootPath.getAbsolutePath(), new File(savePath).getName().replace(".flv", ".nfo"));
|
||||
saveLiveInfo(roomInfo);
|
||||
api.getLiveRoomPlayInfo(
|
||||
bean.getRoomId().toString(),
|
||||
@ -270,7 +248,7 @@ public class LiveVideoService {
|
||||
.withNotSymbolParam("-threads", "8")
|
||||
.withNotSymbolParam("-c:v", "copy")
|
||||
.withNotSymbolParam("-y", "")
|
||||
.build(config.getRoomId().toString(),ffmpegPath, url, savePath);
|
||||
.build(config.getRoomId().toString(), ffmpegPath, url, savePath);
|
||||
Log.i(command.getCommand());
|
||||
try {
|
||||
command.start(new DownloadInterface() {
|
||||
|
14
src/main/java/com/yutou/common/record/AbsVideoRecord.java
Normal file
14
src/main/java/com/yutou/common/record/AbsVideoRecord.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.yutou.common.record;
|
||||
|
||||
import com.yutou.bilibili.interfaces.DownloadInterface;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbsVideoRecord {
|
||||
public abstract List<String> getRoomIds();
|
||||
public abstract boolean check(String roomId);
|
||||
public abstract void kill(String roomId);
|
||||
public abstract void killAll();
|
||||
public abstract void start(DownloadInterface downloadInterface);
|
||||
public abstract void stop();
|
||||
}
|
@ -2,13 +2,14 @@ package com.yutou.common.utils;
|
||||
|
||||
import com.yutou.bilibili.Tools.ProcessUtils;
|
||||
import com.yutou.bilibili.interfaces.DownloadInterface;
|
||||
import com.yutou.common.record.AbsVideoRecord;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class FFmpegUtils {
|
||||
public class FFmpegUtils extends AbsVideoRecord {
|
||||
private static final Map<String, Long> pidMap = new HashMap<>();
|
||||
@Getter
|
||||
private String command;
|
||||
@ -16,28 +17,38 @@ public class FFmpegUtils {
|
||||
InputStream inputStream;
|
||||
OutputStream outputStream;
|
||||
|
||||
private FFmpegUtils() {
|
||||
public FFmpegUtils() {
|
||||
}
|
||||
|
||||
public static boolean check(String anchorUid) {
|
||||
@Override
|
||||
public List<String> getRoomIds() {
|
||||
pidMap.keySet().removeIf(key -> !check(key));
|
||||
return pidMap.keySet().stream().toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(String roomId) {
|
||||
try {
|
||||
return ProcessUtils.isProcessRunning(pidMap.get(anchorUid));
|
||||
return ProcessUtils.isProcessRunning(pidMap.get(roomId));
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void kill(String anchorUid) {
|
||||
@Override
|
||||
public void kill(String roomId) {
|
||||
try {
|
||||
ProcessUtils.killProcess(pidMap.get(anchorUid));
|
||||
ProcessUtils.killProcess(pidMap.get(roomId));
|
||||
pidMap.remove(roomId);
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void killAll() {
|
||||
@Override
|
||||
public void killAll() {
|
||||
for (Long pid : pidMap.values()) {
|
||||
try {
|
||||
ProcessUtils.killProcess(pid);
|
||||
@ -45,6 +56,7 @@ public class FFmpegUtils {
|
||||
Log.e(e);
|
||||
}
|
||||
}
|
||||
pidMap.clear();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
@ -96,15 +108,16 @@ public class FFmpegUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(DownloadInterface downloadInterface) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
if (check(uid)) {
|
||||
kill(uid);
|
||||
}
|
||||
Process process = ProcessUtils.exec(command);
|
||||
Process process = ProcessUtils.exec(command.split(" "));
|
||||
long pid = process.toHandle().pid();
|
||||
Log.i("进程id "+pid);
|
||||
Log.i("进程id " + pid);
|
||||
inputStream = process.getErrorStream();
|
||||
outputStream = process.getOutputStream();
|
||||
byte[] bytes = new byte[2048];
|
||||
@ -130,6 +143,7 @@ public class FFmpegUtils {
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
try {
|
||||
outputStream.write("q".getBytes());
|
||||
|
Loading…
Reference in New Issue
Block a user