This commit is contained in:
zlzw 2024-10-29 18:29:43 +08:00
parent e6568480b7
commit 129e407646
11 changed files with 132 additions and 113 deletions

View File

@ -1,6 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="zh-CN">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
@ -9,51 +8,31 @@
</head> </head>
<body> <body>
<div class="layui-layout layui-layout-admin">
<div id="header"></div> <div id="header"></div>
<div class="layui-body" style="left: 0px;"> <button id="btn" type="button" class="layui-btn" onclick="onButton()">默认按钮</button>
<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>
<script src="/layui/layui.js"></script> <script src="/layui/layui.js"></script>
<script src="/js/jquery-3.2.1.js"></script> <script src="/js/jquery-3.2.1.js"></script>
<script src="/js/CommonConfig.js"></script>
<script src="/js/httpUtils.js"></script>
<script> <script>
layui.use(['layer', 'form', 'element'], function () { headerModel=0;
var layer = layui.layer
, form = layui.form;
});
$('#header').load("/html/header.html"); $('#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>
<script>
function onButton(){
getLiveVideoList({
success:function(json){
console.log(json)
},
error:function(error){
</body>
<style>
.layui-body {
position: relative;
z-index: 0;
background-color: #F2F2F2;
} }
})
}
</script>
<style>
</style> </style>
</html> </html>

View File

@ -3,10 +3,13 @@ package com.yutou.bilibili.Controllers;
import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.yutou.biliapi.bean.live.database.LiveConfigDatabaseBean; 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.ResultData;
import com.yutou.bilibili.datas.ReturnCode; import com.yutou.bilibili.datas.ReturnCode;
import com.yutou.bilibili.services.LiveConfigService; import com.yutou.bilibili.services.LiveConfigService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -60,7 +63,7 @@ public class LiveConfigController {
public JSONObject getAllConfig() { public JSONObject getAllConfig() {
List<LiveConfigDatabaseBean> config = configService.getAllConfig(); List<LiveConfigDatabaseBean> config = configService.getAllConfig();
if (config != null) { if (config != null) {
return ResultData.success(JSONArray.parseArray(JSONArray.toJSONString(config))); return ResultData.success(config);
} }
return ResultData.fail(ReturnCode.RC999); return ResultData.fail(ReturnCode.RC999);
} }
@ -77,4 +80,9 @@ public class LiveConfigController {
} }
return ResultData.fail(ReturnCode.RC999); return ResultData.fail(ReturnCode.RC999);
} }
@RequestMapping(value = "face", method = RequestMethod.GET)
public ResponseEntity<FileSystemResource> getFace(String roomId) {
return Tools.getFile(configService.getFace(roomId));
}
} }

View File

@ -7,16 +7,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
@Controller @Controller
public class TestControllers { public class TestControllers {
@RequestMapping("/root/test") @RequestMapping("/root/all")
@ResponseBody @ResponseBody
public String test(){ public String test(){
FFmpegUtils.killAll();
return "hello world"; return "hello world";
} }
@RequestMapping("/root/kill")
@ResponseBody
public String kill(String roomId){
FFmpegUtils.kill(roomId);
return FFmpegUtils.check(roomId)+"";
}
} }

View File

@ -1,5 +1,6 @@
package com.yutou.bilibili.Tools; package com.yutou.bilibili.Tools;
import com.yutou.bilibili.services.LiveVideoService;
import com.yutou.bilibili.services.SystemService; import com.yutou.bilibili.services.SystemService;
import com.yutou.common.utils.FFmpegUtils; import com.yutou.common.utils.FFmpegUtils;
import com.yutou.common.utils.Log; import com.yutou.common.utils.Log;
@ -7,15 +8,18 @@ import jakarta.annotation.Resource;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Component @Component
public class ApplicationClose implements ApplicationListener<ContextClosedEvent> { public class ApplicationClose implements ApplicationListener<ContextClosedEvent> {
@Resource @Resource
SystemService systemConfigService; SystemService systemConfigService;
@Resource
LiveVideoService videoService;
@Override @Override
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) { public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
Log.i("服务结束"); Log.i("服务结束");
systemConfigService.stop(); systemConfigService.stop();
FFmpegUtils.killAll(); videoService.stopAll();
} }
} }

View File

@ -42,15 +42,15 @@ public class FFmpegUtils {
file.getAbsolutePath(), file.getAbsolutePath(),
out.getAbsolutePath() + File.separator + file.getName()); out.getAbsolutePath() + File.separator + file.getName());
Log.i(exec); 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(); InputStream inputStream = process.getErrorStream();
byte[] bytes = new byte[1024]; byte[] bytes = new byte[1024];
while (inputStream.read(bytes) > -1) { while (inputStream.read(bytes) > -1) {
} }
inputStream.close(); 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(); file.delete();
new File(out.getAbsolutePath()+File.separator+file.getName()).delete(); new File(out.getAbsolutePath() + File.separator + file.getName()).delete();
} catch (Exception e) { } catch (Exception e) {
Log.e(e); Log.e(e);
} }

View File

@ -7,11 +7,12 @@ import java.io.InputStreamReader;
public class ProcessUtils { public class ProcessUtils {
public static boolean isRuntimeSystemOfWindow(){ public static boolean isRuntimeSystemOfWindow() {
return System.getProperty ("os.name").contains("Windows"); return System.getProperty("os.name").contains("Windows");
} }
public static void killProcess(Long pid) throws Exception { public static void killProcess(Long pid) throws Exception {
if(pid==null) { if (pid == null) {
return; return;
} }
if (isRuntimeSystemOfWindow()) { if (isRuntimeSystemOfWindow()) {
@ -25,8 +26,9 @@ public class ProcessUtils {
} }
} }
public static boolean isProcessRunning(Long pid) throws Exception { public static boolean isProcessRunning(Long pid) throws Exception {
if(pid==null) { if (pid == null) {
return false; return false;
} }
String command; String command;
@ -48,22 +50,17 @@ public class ProcessUtils {
} }
return false; return false;
} }
public static Process exec(String exec)throws Exception{ public static Process exec(String exec) throws Exception {
if(isRuntimeSystemOfWindow()) { if(isRuntimeSystemOfWindow()){
return Runtime.getRuntime().exec(new String[]{ return exec("cmd.exe","/c",exec);
"cmd",
"/c",
exec
}
);
}else{ }else{
return Runtime.getRuntime().exec(new String[]{ return exec("sh","-c",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 { public static void main(String[] args) throws Exception {

View File

@ -1,14 +1,19 @@
package com.yutou.bilibili.datas; package com.yutou.bilibili.datas;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import lombok.Data; import lombok.Data;
import java.util.Collection;
import java.util.List;
@Data @Data
public class ResultData<T> { public class ResultData<T> {
private int status; private int status;
private String message; private String message;
private T data; private T data;
private long timestamp ; private int count;
private long timestamp;
public ResultData() { public ResultData() {
this.timestamp = System.currentTimeMillis(); this.timestamp = System.currentTimeMillis();
@ -20,6 +25,9 @@ public class ResultData<T> {
resultData.setStatus(ReturnCode.RC100.getCode()); resultData.setStatus(ReturnCode.RC100.getCode());
resultData.setMessage(ReturnCode.RC100.getMessage()); resultData.setMessage(ReturnCode.RC100.getMessage());
resultData.setData(data); resultData.setData(data);
if (data instanceof Collection<?>) {
resultData.count = ((Collection<?>) data).size();
}
return JSONObject.parseObject(JSONObject.toJSONString(resultData)); return JSONObject.parseObject(JSONObject.toJSONString(resultData));
} }
@ -29,9 +37,11 @@ public class ResultData<T> {
resultData.setMessage(message); resultData.setMessage(message);
return JSONObject.parseObject(JSONObject.toJSONString(resultData)); return JSONObject.parseObject(JSONObject.toJSONString(resultData));
} }
public static JSONObject success(ReturnCode code) { public static JSONObject success(ReturnCode code) {
return fail(code); return fail(code);
} }
public static <T> JSONObject fail(ReturnCode code) { public static <T> JSONObject fail(ReturnCode code) {
ResultData<T> resultData = new ResultData<>(); ResultData<T> resultData = new ResultData<>();
resultData.setStatus(code.getCode()); resultData.setStatus(code.getCode());

View File

@ -5,10 +5,12 @@ import com.yutou.biliapi.bean.live.MasterInfoBean;
import com.yutou.biliapi.bean.live.database.LiveConfigDatabaseBean; import com.yutou.biliapi.bean.live.database.LiveConfigDatabaseBean;
import com.yutou.biliapi.databases.BiliLiveConfigDatabase; import com.yutou.biliapi.databases.BiliLiveConfigDatabase;
import com.yutou.biliapi.net.BiliLiveNetApiManager; import com.yutou.biliapi.net.BiliLiveNetApiManager;
import com.yutou.common.okhttp.HttpDownloadUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.List; import java.util.List;
@ -34,6 +36,7 @@ public class LiveConfigService {
bean.setAnchorFace(infoBean.getInfo().getFace()); bean.setAnchorFace(infoBean.getInfo().getFace());
bean.setAnchorName(infoBean.getInfo().getUname()); bean.setAnchorName(infoBean.getInfo().getUname());
database.setConfig(bean); database.setConfig(bean);
downloadFace(bean);
return bean; return bean;
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -48,6 +51,7 @@ public class LiveConfigService {
bean.setRoomId(roomId); bean.setRoomId(roomId);
bean.setSql_time(config.getSql_time()); bean.setSql_time(config.getSql_time());
database.setConfig(bean); database.setConfig(bean);
downloadFace(bean);
return bean; return bean;
} }
@ -67,4 +71,22 @@ public class LiveConfigService {
public LiveConfigDatabaseBean getConfig(BigInteger roomId) { public LiveConfigDatabaseBean getConfig(BigInteger roomId) {
return database.getConfig(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");
}
} }

View File

@ -27,6 +27,7 @@ import com.yutou.bilibili.datas.VideoFilePath;
import com.yutou.bilibili.interfaces.DownloadInterface; import com.yutou.bilibili.interfaces.DownloadInterface;
import com.yutou.common.okhttp.HttpCallback; import com.yutou.common.okhttp.HttpCallback;
import com.yutou.common.okhttp.HttpDownloadUtils; import com.yutou.common.okhttp.HttpDownloadUtils;
import com.yutou.common.record.AbsVideoRecord;
import com.yutou.common.utils.ConfigTools; import com.yutou.common.utils.ConfigTools;
import com.yutou.common.utils.FFmpegUtils; import com.yutou.common.utils.FFmpegUtils;
import com.yutou.common.utils.Log; import com.yutou.common.utils.Log;
@ -47,12 +48,12 @@ import static com.alibaba.fastjson2.util.DateUtils.DateTimeFormatPattern.DATE_FO
@Service @Service
public class LiveVideoService { public class LiveVideoService {
ThreadPoolExecutor executor; ThreadPoolExecutor executor;
private final Map<LiveConfigDatabaseBean, VideoTask> liveVideoMap = new HashMap<>();
private final List<String> userStopList = new ArrayList<>();//手动停止列表 private final List<String> userStopList = new ArrayList<>();//手动停止列表
AbsVideoRecord videoRecord;
public LiveVideoService() { public LiveVideoService() {
Log.i("初始化下载服务"); Log.i("初始化下载服务");
videoRecord=new FFmpegUtils();
executor = new ThreadPoolExecutor(2, 4, Long.MAX_VALUE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100)); executor = new ThreadPoolExecutor(2, 4, Long.MAX_VALUE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
} }
@ -63,27 +64,22 @@ public class LiveVideoService {
if (isUser) { if (isUser) {
userStopList.remove(bean.getRoomId().toString()); userStopList.remove(bean.getRoomId().toString());
} }
if (liveVideoMap.containsKey(bean)) { if (videoRecord.check(bean.getRoomId().toString())) {
return; return;
} }
Log.i("添加下载任务:" + liveVideoMap.keySet().size());
liveVideoMap.put(bean, null);
BiliLiveNetApiManager.getInstance().getApi(bean.getRecordUid()).getRoomInfo(bean.getRoomId().toString()).enqueue(new HttpCallback<LiveRoomInfo>() { BiliLiveNetApiManager.getInstance().getApi(bean.getRecordUid()).getRoomInfo(bean.getRoomId().toString()).enqueue(new HttpCallback<LiveRoomInfo>() {
@Override @Override
public void onResponse(Headers headers, int code, String status, LiveRoomInfo response, String rawResponse) { public void onResponse(Headers headers, int code, String status, LiveRoomInfo response, String rawResponse) {
if (response.getLiveStatus() == 1) { if (response.getLiveStatus() == 1) {
VideoTask task = new VideoTask(bean, response); VideoTask task = new VideoTask(bean, response);
executor.execute(task); executor.execute(task);
liveVideoMap.put(bean, task);
} else { } else {
liveVideoMap.remove(bean);
Log.i("移除下载"); Log.i("移除下载");
} }
} }
@Override @Override
public void onFailure(Throwable throwable) { public void onFailure(Throwable throwable) {
liveVideoMap.remove(bean);
Log.i("移除下载"); Log.i("移除下载");
} }
}); });
@ -95,36 +91,18 @@ public class LiveVideoService {
if (isUser) { if (isUser) {
userStopList.add(roomId); userStopList.add(roomId);
} }
for (Map.Entry<LiveConfigDatabaseBean, VideoTask> entry : liveVideoMap.entrySet()) { videoRecord.kill(roomId);
if (entry.getKey().getRoomId().toString().equals(roomId)) {
entry.getValue().isDownload = false;
liveVideoMap.remove(entry.getKey());
Log.i("移除下载");
break;
}
}
} }
public boolean check(String roomId) {
for (LiveConfigDatabaseBean bean : liveVideoMap.keySet()) {
if (bean.getRoomId().toString().equals(roomId)) {
return true;
}
}
return false;
}
public JSONArray getDownloadTasks() { public JSONArray getDownloadTasks() {
JSONArray array = new JSONArray(); JSONArray array = new JSONArray();
array.addAll(liveVideoMap.keySet()); array.addAll(videoRecord.getRoomIds());
return array; return array;
} }
public void stopAll() { public void stopAll() {
for (VideoTask task : liveVideoMap.values()) { videoRecord.killAll();
task.isDownload = false;
}
liveVideoMap.clear();
} }
private class VideoTask implements Runnable { private class VideoTask implements Runnable {
@ -163,7 +141,7 @@ public class LiveVideoService {
} }
private void stop() { private void stop() {
liveVideoMap.remove(bean); videoRecord.kill(bean.getRoomId().toString());
api.getRoomInfo(config.getRoomId().toString()).enqueue(new HttpCallback<LiveRoomInfo>() { api.getRoomInfo(config.getRoomId().toString()).enqueue(new HttpCallback<LiveRoomInfo>() {
@Override @Override
public void onResponse(Headers headers, int code, String status, LiveRoomInfo response, String rawResponse) { 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()) HttpDownloadUtils.download(new HttpDownloadUtils.Builder().setUrl(roomInfo.getKeyframe())
.setPath(rootPath.getAbsolutePath()) .setPath(rootPath.getAbsolutePath())
.setFileName("poster.jpg")); .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); saveLiveInfo(roomInfo);
api.getLiveRoomPlayInfo( api.getLiveRoomPlayInfo(
bean.getRoomId().toString(), bean.getRoomId().toString(),
@ -270,7 +248,7 @@ public class LiveVideoService {
.withNotSymbolParam("-threads", "8") .withNotSymbolParam("-threads", "8")
.withNotSymbolParam("-c:v", "copy") .withNotSymbolParam("-c:v", "copy")
.withNotSymbolParam("-y", "") .withNotSymbolParam("-y", "")
.build(config.getRoomId().toString(),ffmpegPath, url, savePath); .build(config.getRoomId().toString(), ffmpegPath, url, savePath);
Log.i(command.getCommand()); Log.i(command.getCommand());
try { try {
command.start(new DownloadInterface() { command.start(new DownloadInterface() {

View 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();
}

View File

@ -2,13 +2,14 @@ package com.yutou.common.utils;
import com.yutou.bilibili.Tools.ProcessUtils; import com.yutou.bilibili.Tools.ProcessUtils;
import com.yutou.bilibili.interfaces.DownloadInterface; import com.yutou.bilibili.interfaces.DownloadInterface;
import com.yutou.common.record.AbsVideoRecord;
import lombok.Getter; import lombok.Getter;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
public class FFmpegUtils { public class FFmpegUtils extends AbsVideoRecord {
private static final Map<String, Long> pidMap = new HashMap<>(); private static final Map<String, Long> pidMap = new HashMap<>();
@Getter @Getter
private String command; private String command;
@ -16,28 +17,38 @@ public class FFmpegUtils {
InputStream inputStream; InputStream inputStream;
OutputStream outputStream; 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 { try {
return ProcessUtils.isProcessRunning(pidMap.get(anchorUid)); return ProcessUtils.isProcessRunning(pidMap.get(roomId));
} catch (Exception e) { } catch (Exception e) {
Log.e(e); Log.e(e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static void kill(String anchorUid) { @Override
public void kill(String roomId) {
try { try {
ProcessUtils.killProcess(pidMap.get(anchorUid)); ProcessUtils.killProcess(pidMap.get(roomId));
pidMap.remove(roomId);
} catch (Exception e) { } catch (Exception e) {
Log.e(e); Log.e(e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static void killAll() { @Override
public void killAll() {
for (Long pid : pidMap.values()) { for (Long pid : pidMap.values()) {
try { try {
ProcessUtils.killProcess(pid); ProcessUtils.killProcess(pid);
@ -45,6 +56,7 @@ public class FFmpegUtils {
Log.e(e); Log.e(e);
} }
} }
pidMap.clear();
} }
public static class Builder { public static class Builder {
@ -96,15 +108,16 @@ public class FFmpegUtils {
} }
} }
@Override
public void start(DownloadInterface downloadInterface) { public void start(DownloadInterface downloadInterface) {
new Thread(() -> { new Thread(() -> {
try { try {
if (check(uid)) { if (check(uid)) {
kill(uid); kill(uid);
} }
Process process = ProcessUtils.exec(command); Process process = ProcessUtils.exec(command.split(" "));
long pid = process.toHandle().pid(); long pid = process.toHandle().pid();
Log.i("进程id "+pid); Log.i("进程id " + pid);
inputStream = process.getErrorStream(); inputStream = process.getErrorStream();
outputStream = process.getOutputStream(); outputStream = process.getOutputStream();
byte[] bytes = new byte[2048]; byte[] bytes = new byte[2048];
@ -130,6 +143,7 @@ public class FFmpegUtils {
}).start(); }).start();
} }
@Override
public void stop() { public void stop() {
try { try {
outputStream.write("q".getBytes()); outputStream.write("q".getBytes());