优化下载

This commit is contained in:
zlzw 2024-11-26 17:47:27 +08:00
parent 44d23b6bac
commit d9919f4d26
10 changed files with 129 additions and 49 deletions

View File

@ -45,7 +45,7 @@ public class LiveRoomConfig {
public static LiveRoomConfig buildConfig(String roomId){ public static LiveRoomConfig buildConfig(String roomId){
BiliLiveConfigDatabase database = new BiliLiveConfigDatabase(); BiliLiveConfigDatabase database = new BiliLiveConfigDatabase();
LiveConfigDatabaseBean bean = database.getConfig(new String(roomId)); LiveConfigDatabaseBean bean = database.getConfig(new String(roomId));
database.close();
LiveRoomConfig config = new LiveRoomConfig(); LiveRoomConfig config = new LiveRoomConfig();
config.setLoginUid(bean.getRecordUid()); config.setLoginUid(bean.getRecordUid());
config.setRoomId(bean.getRoomId()); config.setRoomId(bean.getRoomId());

View File

@ -35,6 +35,6 @@ public class LoginCookieDatabaseBean extends AbsDatabasesBean {
} }
public String toCookieString() { public String toCookieString() {
return "SESSDATA=" + sessdta + "; Path=" + path + "; DedeUserID=" + dedeUserID + "; DedeUserID__ckMd5=" + dedeUserIDCkMd5 + "; bili_jct=" + biliJct + "; Expires=" + expires + "; Domain=" + domain + "; sid=" + sid + "; gourl=" + gourl; return "SESSDATA=" + sessdta + "; Path=" + path + "; DedeUserID=" + dedeUserID + "; DedeUserID__ckMd5=" + dedeUserIDCkMd5 + "; bili_jct=" + biliJct + "; Expires=" + expires + "; Domain=" + domain + "; sid=" + sid;
} }
} }

View File

@ -112,7 +112,7 @@ public class BiliLiveDatabase extends SQLiteManager {
} }
public void addSource(WSData bean) { public void addSource(WSData bean) {
Log.i("BiliLiveDatabase.addSource", config.getRoomId()); // Log.i("BiliLiveDatabase.addSource", config.getRoomId());
add(new LiveSourceDatabaseBean(bean)); add(new LiveSourceDatabaseBean(bean));
addData(bean); addData(bean);
} }

View File

@ -174,7 +174,7 @@ public class WebSocketManager {
heartbeatTask.setSocket(this); heartbeatTask.setSocket(this);
heartbeatTask.sendInitAuthData(); heartbeatTask.sendInitAuthData();
new Timer().schedule(heartbeatTask, 1000, 30000); new Timer().schedule(heartbeatTask, 1000, 30000);
Log.i("WebSocketClientTh.onOpen", roomConfig); Log.i("WebSocketClientTh.onOpen", roomConfig.getRoomId());
} }
@Override @Override
@ -296,7 +296,7 @@ public class WebSocketManager {
json.put("key", roomConfig.getLiveInfo().getToken()); json.put("key", roomConfig.getLiveInfo().getToken());
byte[] bytes = {0, 16, 0, 1, 0, 0, 0, 7, 0, 0, 0, 1}; byte[] bytes = {0, 16, 0, 1, 0, 0, 0, 7, 0, 0, 0, 1};
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Log.i("bytes.length = " + bytes.length); // Log.i("bytes.length = " + bytes.length);
Log.i(json); Log.i(json);
outputStream.write(BytesUtils.toLH(json.toString().length() + 16)); outputStream.write(BytesUtils.toLH(json.toString().length() + 16));
outputStream.write(bytes); outputStream.write(bytes);

View File

@ -36,6 +36,7 @@ public class LiveVideoController {
public JSONObject startDownload(String roomId) { public JSONObject startDownload(String roomId) {
BiliLiveConfigDatabase liveConfigDatabase = new BiliLiveConfigDatabase(); BiliLiveConfigDatabase liveConfigDatabase = new BiliLiveConfigDatabase();
List<LiveConfigDatabaseBean> list = liveConfigDatabase.getAllConfig(); List<LiveConfigDatabaseBean> list = liveConfigDatabase.getAllConfig();
liveConfigDatabase.close();
for (LiveConfigDatabaseBean bean : list) { for (LiveConfigDatabaseBean bean : list) {
if (bean.getRoomId().toString().equals(roomId)) { if (bean.getRoomId().toString().equals(roomId)) {
videoService.start(bean, true); videoService.start(bean, true);

View File

@ -62,6 +62,9 @@ public class DateFormatUtils {
public Date parse(String date, String format) { public Date parse(String date, String format) {
try { try {
if(date.startsWith("1")){
return new Date(Long.parseLong(date));
}
return getFormat(format).parse(date); return getFormat(format).parse(date);
} catch (ParseException e) { } catch (ParseException e) {
System.err.println("Error parsing date: " + e.getMessage()); System.err.println("Error parsing date: " + e.getMessage());

View File

@ -1,9 +1,15 @@
package com.yutou.bilibili.Tools; package com.yutou.bilibili.Tools;
import com.yutou.common.utils.AppTools; import com.yutou.common.utils.AppTools;
import com.yutou.common.utils.Base64Tools;
import com.yutou.common.utils.Log;
import org.apache.commons.io.IOUtils;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
public class ProcessUtils { public class ProcessUtils {
@ -31,35 +37,46 @@ public class ProcessUtils {
if (pid == null) { if (pid == null) {
return false; return false;
} }
String command; String[] command;
if (isRuntimeSystemOfWindow()) { if (isRuntimeSystemOfWindow()) {
// Windows 操作系统 // Windows 操作系统
command = "tasklist /FI \"PID eq " + pid + "\""; command = new String[]{"cmd.exe", "/c", "tasklist /FI \"PID eq " + pid + "\""};
} else { } else {
// Unix/Linux 操作系统 // Unix/Linux 操作系统
command = "ps -p " + pid; command = new String[]{"sh", "-c", "ps -p " + pid};
} }
Process process = exec(command); Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); boolean isRunning = false;
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
if (line.contains(Long.toString(pid))) { if (line.contains(String.valueOf(pid))) {
return true; isRunning = true;
} }
} }
return false; reader.close();
process.destroy();
} catch (Exception e) {
Log.e(e);
} }
return isRunning;
}
public static Process exec(String exec) throws Exception { public static Process exec(String exec) throws Exception {
if(isRuntimeSystemOfWindow()){ if (isRuntimeSystemOfWindow()) {
return exec("cmd.exe","/c",exec); return exec("cmd.exe", "/c", exec);
}else{ } else {
return exec("sh","-c",exec); return exec("sh", "-c", exec);
} }
} }
public static Process exec(String... command) throws Exception { public static Process exec(String... command) throws Exception {
ProcessBuilder pb; ProcessBuilder pb;
pb = new ProcessBuilder(command); List<String> list = Arrays.stream(command).map(Base64Tools::decode).toList();
pb = new ProcessBuilder(list);
return pb.start(); return pb.start();
} }

View File

@ -18,9 +18,11 @@ import com.yutou.biliapi.enums.LiveVideoCodec;
import com.yutou.biliapi.enums.LiveVideoDefinition; import com.yutou.biliapi.enums.LiveVideoDefinition;
import com.yutou.biliapi.enums.LiveVideoFormat; import com.yutou.biliapi.enums.LiveVideoFormat;
import com.yutou.biliapi.net.BiliLiveNetApiManager; import com.yutou.biliapi.net.BiliLiveNetApiManager;
import com.yutou.biliapi.net.WebSignManager;
import com.yutou.bilibili.Tools.DateFormatUtils; import com.yutou.bilibili.Tools.DateFormatUtils;
import com.yutou.bilibili.Tools.FileServerUtils; import com.yutou.bilibili.Tools.FileServerUtils;
import com.yutou.bilibili.Tools.LiveInfoNfoTools; import com.yutou.bilibili.Tools.LiveInfoNfoTools;
import com.yutou.bilibili.Tools.ProcessUtils;
import com.yutou.bilibili.datas.VideoFilePath; 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;
@ -36,6 +38,7 @@ import org.springframework.util.StringUtils;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -78,13 +81,13 @@ public class LiveVideoDownloadService {
VideoTask task = new VideoTask(bean, response); VideoTask task = new VideoTask(bean, response);
executor.execute(task); executor.execute(task);
} else { } else {
Log.i("移除下载"); Log.i(bean.getRoomId(), "没有开播");
} }
} }
@Override @Override
public void onFailure(Throwable throwable) { public void onFailure(Throwable throwable) {
Log.i("移除下载"); Log.e(throwable, "移除下载");
} }
}); });
@ -195,8 +198,29 @@ public class LiveVideoDownloadService {
LiveVideoDefinition.ORIGINAL.getValue()).enqueue(new HttpCallback<LiveRoomPlayInfo>() { LiveVideoDefinition.ORIGINAL.getValue()).enqueue(new HttpCallback<LiveRoomPlayInfo>() {
@Override @Override
public void onResponse(Headers headers, int code, String status, LiveRoomPlayInfo response, String rawResponse) { public void onResponse(Headers headers, int code, String status, LiveRoomPlayInfo response, String rawResponse) {
LiveRoomPlayInfo.Codec codec = response.getPlayurlInfo().getPlayurl().getStream().get(0).getFormat().get(0).getCodec().get(0); Random random = new Random();
String url = codec.getUrlInfo().get(0).getHost() + codec.getBaseUrl() + codec.getUrlInfo().get(0).getExtra(); List<LiveRoomPlayInfo.Stream> streams = response.getPlayurlInfo().getPlayurl().getStream();
List<LiveRoomPlayInfo.Stream> streamList = streams.stream()
.filter(it -> "http_stream".equals(it.getProtocolName()))
.toList();
LiveRoomPlayInfo.Stream stream = streamList.get(random.nextInt(streamList.size()));
if (stream == null) {
return;
}
List<LiveRoomPlayInfo.Format> formats = stream.getFormat().stream().filter(it -> "flv".equals(it.getFormatName())).toList();
LiveRoomPlayInfo.Format format = formats.get(random.nextInt(formats.size()));
List<LiveRoomPlayInfo.Codec> codecs = format.getCodec().stream().filter(item -> "avc".equals(item.getCodecName())).toList();
LiveRoomPlayInfo.Codec codec = codecs.get(random.nextInt(codecs.size()));
int urlIndex = random.nextInt(codec.getUrlInfo().size());
LiveRoomPlayInfo.UrlInfo urlInfo = codec.getUrlInfo().get(urlIndex);
String url = urlInfo.getHost() + codec.getBaseUrl() + urlInfo.getExtra();
Log.i("下载直播",rawResponse,codec.toString(),urlInfo.toString(),"URL:"+url);
if (bean.getRecordLiveModel() == 1) { if (bean.getRecordLiveModel() == 1) {
javaRecord(url, response); javaRecord(url, response);
@ -253,32 +277,46 @@ public class LiveVideoDownloadService {
FFmpegUtils.Builder builder = new FFmpegUtils.Builder() FFmpegUtils.Builder builder = new FFmpegUtils.Builder()
.withParam("-user_agent", ConfigTools.getUserAgent()) .withParam("-user_agent", ConfigTools.getUserAgent())
.withParam("-headers", "Referer: https://live.bilibili.com") .withParam("-headers", "Referer: https://live.bilibili.com/" + playInfo.getRoomId())
// .withNotSymbolParam("-reconnect", "1")
// .withNotSymbolParam("-reconnect_at_eof", "1")
// .withNotSymbolParam("-reconnect_streamed", "1")
// .withNotSymbolParam("-reconnect_delay_max", "2")
// .withNotSymbolParam("-loglevel", "error")
// .withNotSymbolParam("-progress", "-") // .withNotSymbolParam("-progress", "-")
// .withNotSymbolParam("-fflags", "+genpts")
.withNotSymbolParam("-threads", "8") .withNotSymbolParam("-threads", "8")
.withNotSymbolParam("-c:v", "copy") .withNotSymbolParam("-bufsize", "10M")
.withNotSymbolParam("-fflags", "+genpts") .withNotSymbolParam("-c", "copy")
.withNotSymbolParam("-bsf:a", "aac_adtstoasc")
// .withNotSymbolParam("-loglevel", "debug")
.withNotSymbolParam("-y", "") .withNotSymbolParam("-y", "")
//-reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 2 //-reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 2
.withNotSymbolParam("-reconnect", "1")
.withNotSymbolParam("-reconnect_at_eof", "1")
.withNotSymbolParam("-reconnect_streamed", "1")
.withNotSymbolParam("-reconnect_delay_max", "2")
.withNotSymbolParam("-loglevel", "error")
// .withNotSymbolParam("-progress",new File("cache",config.getRoomId()+".txt").getAbsolutePath()); //输出进度日志,暂时没啥用 // .withNotSymbolParam("-progress",new File("cache",config.getRoomId()+".txt").getAbsolutePath()); //输出进度日志,暂时没啥用
; ;
if (ck != null) { if (ck != null) {
builder = builder.withParam("-cookies", cookie); // builder = builder.withParam("-cookies", cookie);
} }
FFmpegUtils command = builder.build(config.getRoomId(), ffmpegPath, url, savePath); FFmpegUtils command = builder.build(config.getRoomId(), ffmpegPath, url, savePath);
Log.i(command.getCommand()); Log.i(command.getCommandDecode());
try { try {
command.start(new DownloadInterface() { command.start(new DownloadInterface() {
TimerTask task = null;
@Override @Override
public void onDownloadStart() { public void onDownloadStart() {
super.onDownloadStart(); super.onDownloadStart();
task = new TimerTask() {
@Override
public void run() {
VideoTask.this.onStart(); VideoTask.this.onStart();
Log.i("启动录制:" + playInfo.getRoomId()); Log.i("启动录制:" + playInfo.getRoomId());
task = null;
cancel();
}
};
new Timer().schedule(task, 5 * 1000);
} }
@Override @Override
@ -289,6 +327,10 @@ public class LiveVideoDownloadService {
@Override @Override
public void onDownload(File file) { public void onDownload(File file) {
super.onDownload(file); super.onDownload(file);
if (task != null) {
task.cancel();
task = null;
}
} }
}); });
@ -386,7 +428,7 @@ public class LiveVideoDownloadService {
videoFile = new File(videoInfo.getPath()); videoFile = new File(videoInfo.getPath());
} }
FFmpegUtils ffmpeg = FFmpegUtils.segment(videoId, ffmpegPath, videoFile, ConfigTools.load(ConfigTools.CONFIG, "outVideoPath", String.class)); FFmpegUtils ffmpeg = FFmpegUtils.segment(videoId, ffmpegPath, videoFile, ConfigTools.load(ConfigTools.CONFIG, "outVideoPath", String.class));
System.out.println(ffmpeg.getCommand()); System.out.println(ffmpeg.getCommandDecode());
ffmpeg.start(new DownloadInterface() { ffmpeg.start(new DownloadInterface() {
@Override @Override
public void onDownload(File file) { public void onDownload(File file) {

View File

@ -13,7 +13,11 @@ public class Base64Tools {
} }
public static String decode(String str) { public static String decode(String str) {
try {
return new String(Base64.getDecoder().decode(str)); return new String(Base64.getDecoder().decode(str));
} catch (Exception e) {
return str;
}
} }
public static String encode(byte[] bytes) { public static String encode(byte[] bytes) {
@ -31,5 +35,6 @@ public class Base64Tools {
} }
public static void main(String[] args) { public static void main(String[] args) {
System.out.println(decode("aHR0cHM6Ly9jbi16ampoLWN0LTA0LTA2LmJpbGl2aWRlby5jb20vbGl2ZS1idmMvMzE1MDQ2L2xpdmVfMjY5NDE1MzU3Xzk4Mjc2ODIuZmx2P2V4cGlyZXM9MTczMjYwNDIyOCZwdD13ZWImZGVhZGxpbmU9MTczMjYwNDIyOCZsZW49MCZvaT0yOTM2NjQ2MjYwJnBsYXRmb3JtPXdlYiZxbj0xMDAwMCZ0cmlkPTEwMDAwZTUzYTY2ZjBiNWFjMDgwNGMwMDBhZGI5MTY3NDU2MyZ1aXBrPTEwMCZ1aXB2PTEwMCZuYnM9MSZ1cGFyYW1zPWNkbixkZWFkbGluZSxsZW4sb2kscGxhdGZvcm0scW4sdHJpZCx1aXBrLHVpcHYsbmJzJmNkbj1jbi1nb3RjaGEwMSZ1cHNpZz1iOGZhNjQyNGYxM2E1MDUwZThkNGRkZDc1NDcyOGYwYiZzaXRlPWRhYTczMDFjYmM5YzgwMjA1MTk4MDZmYmM4YzA4MmI2JmZyZWVfdHlwZT0wJm1pZD05NjMwMCZzY2hlPWJhbiZzaWQ9Y24tempqaC1jdC0wNC0wNiZjaGFzaD0xJmJtdD0xJnNnPWxyJnRyYWNlPTE3JmlzcD1jdCZyZz1DZW50cmFsJnB2PUh1bmFuJnNsPTImcHA9cnRtcCZwMnBfdHlwZT0xJmRlcGxveV9lbnY9cHJvZCZzdWZmaXg9b3JpZ2luJm9yaWdpbl9iaXRyYXRlPTc2OTczNiZzb3VyY2U9cHV2M19vbmV0aWVyJnNrPTQ5Yzc3YTNjMDBlY2M0NzI2ZjdlMGU1YTEzZjM5ZjYzJnNjb3JlPTUyJmhvdF9jZG49NTczNTMmdmQ9bmMmem9uZWlkX2w9MTUxMzg4MTYxJnNpZF9sPWxpdmVfMjY5NDE1MzU3Xzk4Mjc2ODImc3JjPXB1djMmb3JkZXI9MQ=="));
} }
} }

View File

@ -10,14 +10,18 @@ import org.springframework.util.StringUtils;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
public class FFmpegUtils extends AbsVideoRecord { public class FFmpegUtils extends AbsVideoRecord {
private static final Map<String, Task> pidMap = new HashMap<>(); private static final Map<String, Task> pidMap = new HashMap<>();
@Getter
private String command; private String command;
@Getter @Getter
private String outputFilePath; private String outputFilePath;
private String uid; private String uid;
@Getter
private String commandDecode;
@Getter
private Long pid;
public FFmpegUtils() { public FFmpegUtils() {
} }
@ -88,6 +92,7 @@ public class FFmpegUtils extends AbsVideoRecord {
.withParam("-y", outputPath + File.separator + "course-%04d.ts") .withParam("-y", outputPath + File.separator + "course-%04d.ts")
.getCommand(ffmpegPath, video.getAbsolutePath(), null); .getCommand(ffmpegPath, video.getAbsolutePath(), null);
ffmpeg.outputFilePath = "video.m3u8"; ffmpeg.outputFilePath = "video.m3u8";
ffmpeg.commandDecode= Arrays.stream(ffmpeg.command.split(" ")).map(Base64Tools::decode).collect(Collectors.joining(" "));
return ffmpeg; return ffmpeg;
} }
// ffmpeg 切片 // ffmpeg 切片
@ -111,20 +116,20 @@ public class FFmpegUtils extends AbsVideoRecord {
} }
private String getCommand(String ffmpegPath, String inputUrl, String outputPath) { private String getCommand(String ffmpegPath, String inputUrl, String outputPath) {
StringBuilder command = new StringBuilder(ffmpegPath); StringBuilder command = new StringBuilder(Base64Tools.encode(ffmpegPath));
command.append(" -i ").append("\"").append(inputUrl).append("\""); command.append(" ").append(Base64Tools.encode("-re")).append(" ").append(Base64Tools.encode("-i")).append(" ").append(Base64Tools.encode("\""+inputUrl+"\""));
for (Map.Entry<String, String> entry : params.entrySet()) { for (Map.Entry<String, String> entry : params.entrySet()) {
if (StringUtils.hasText(entry.getKey())) { if (StringUtils.hasText(entry.getKey())) {
command.append(" "); command.append(" ");
command.append(entry.getKey()); command.append(Base64Tools.encode(entry.getKey()));
} }
if (entry.getValue() != null && !entry.getValue().isEmpty()) { if (entry.getValue() != null && !entry.getValue().isEmpty()) {
command.append(" ").append(entry.getValue()); command.append(" ").append(Base64Tools.encode(entry.getValue()));
} }
} }
if (outputPath != null) { if (outputPath != null) {
command.append(" ").append("\"").append(outputPath).append("\""); command.append(" ").append(Base64Tools.encode("\""+outputPath+"\""));
} }
return command.toString(); return command.toString();
@ -133,6 +138,7 @@ public class FFmpegUtils extends AbsVideoRecord {
public FFmpegUtils build(String uid, String ffmpegPath, String inputUrl, String outputPath) { public FFmpegUtils build(String uid, String ffmpegPath, String inputUrl, String outputPath) {
FFmpegUtils ffmpeg = new FFmpegUtils(); FFmpegUtils ffmpeg = new FFmpegUtils();
ffmpeg.command = getCommand(ffmpegPath, inputUrl, outputPath); ffmpeg.command = getCommand(ffmpegPath, inputUrl, outputPath);
ffmpeg.commandDecode= Arrays.stream(ffmpeg.command.split(" ")).map(Base64Tools::decode).collect(Collectors.joining(" "));
ffmpeg.outputFilePath = outputPath; ffmpeg.outputFilePath = outputPath;
ffmpeg.uid = uid; ffmpeg.uid = uid;
return ffmpeg; return ffmpeg;
@ -141,7 +147,9 @@ public class FFmpegUtils extends AbsVideoRecord {
@Override @Override
public void start(DownloadInterface downloadInterface) { public void start(DownloadInterface downloadInterface) {
new Task(downloadInterface).start(); Task task = new Task(downloadInterface);
task.start();
pid= task.pid;
} }
@Override @Override
@ -194,7 +202,7 @@ public class FFmpegUtils extends AbsVideoRecord {
super.run(); super.run();
try { try {
if (check(uid)) { if (check(uid)) {
kill(); return;
} }
Process process = ProcessUtils.exec(command.split(" ")); Process process = ProcessUtils.exec(command.split(" "));
pid = process.toHandle().pid(); pid = process.toHandle().pid();
@ -207,7 +215,10 @@ public class FFmpegUtils extends AbsVideoRecord {
} }
pidMap.put(uid, this); pidMap.put(uid, this);
long startTimer = System.currentTimeMillis(); long startTimer = System.currentTimeMillis();
while (inputStream.read(bytes) > -1) { ByteArrayOutputStream os=new ByteArrayOutputStream();
int len;
while ((len=inputStream.read(bytes)) > -1) {
os.write(bytes, 0, len);
if (downloadInterface != null) { if (downloadInterface != null) {
downloadInterface.onDownloading(System.currentTimeMillis() - startTimer, 0); downloadInterface.onDownloading(System.currentTimeMillis() - startTimer, 0);
} }
@ -216,11 +227,12 @@ public class FFmpegUtils extends AbsVideoRecord {
//获取视频时长ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4 //获取视频时长ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
//获取到结果:5372.432000 //获取到结果:5372.432000
if (downloadInterface != null) { if (downloadInterface != null) {
Log.i("触发下载完成", command); //Log.i("触发下载完成", command);
Log.i("触发下载完成", new String(os.toByteArray()));
downloadInterface.onDownload(null); downloadInterface.onDownload(null);
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); Log.e(e);
} }
} }