直接上代碼:

public abstract class FFmpegUtils { FFmpegUtils ffmpegUtils; int timeLengthSec = 1; String timeLength = ""; Pattern pattern = Pattern.compile("Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s"); String frameRegexDuration = "size=([\\s\\S]*) time=(.*?) bitrate=([\\s\\S]*) speed=(.*?)x"; String videoframeRegexDuration = "frame=([\\s,\\d]*) fps=(.*?) q=(.*?) size=([\\s\\S]*) time=(.*?) bitrate=([\\s\\S]*) speed=(.*?)x"; Pattern framePattern = Pattern.compile(frameRegexDuration); public static void main(String[] args){ String target = ""; /* try { target = extractAsyn("D:\\ffmpeg4.2\\bin\\ffmpeg.exe", "-y -f image2 -ss 1 -t 0.001 -s 640x480", "E:\\迅雷下載\\電影\\test.avi", "E:\\迅雷下載\\電影\\test.avi.jpg"); System.out.println(target); } catch (Throwable e) { System.err.println(e.getMessage()); } */ try { new FFmpegUtils() { @Override public void dealLine(String line) { System.out.println(line); if(timeLength == null || timeLength.equals("")) { Matcher m = pattern.matcher(line.trim()); if (m.find()) { timeLength = m.group(1); if(timeLength!=null){ timeLengthSec = FFVideoUtil.getTimelen(timeLength); } System.out.println(timeLength+"||"+timeLengthSec); } } //獲取視頻信息 Matcher matcher = framePattern.matcher(line); if(matcher.find()){ try { String execTimeStr = matcher.group(2); int execTimeInt = FFVideoUtil.getTimelen(execTimeStr); double devnum = FFBigDecimalUtil.div(execTimeInt,timeLengthSec,5); double progressDouble = FFBigDecimalUtil.mul(devnum,100); System.out.println("execTimeInt:"+execTimeInt+"&,devnum:"+devnum+"&,progressDouble:"+progressDouble); } catch (IllegalAccessException e) { System.err.println("獲取輸出流異常:"+e.getMessage()); } } } @Override public void dealStream(Process process) { if (process == null) { return; } // 處理InputStream的線程 new Thread() { @Override public void run() { BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = null; try { while ((line = in.readLine()) != null) { //logger.info("output: " + line); dealLine(line); } } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }.start(); // 處理ErrorStream的線程 new Thread() { @Override public void run() { BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream())); String line = null; try { while ((line = err.readLine()) != null) { dealLine(line); } } catch (IOException e) { e.printStackTrace(); } finally { try { err.close(); } catch (IOException e) { e.printStackTrace(); } } } }.start(); } }.processVideoSync("D:\\ffmpeg4.2\\bin\\ffmpeg.exe", " -f|mp3", "E:\\迅雷下載\\電影\\test.avi", "E:\\迅雷下載\\電影\\test.avi.mp3"); System.out.println(target); } catch (Throwable e) { System.err.println(e.getMessage()); } } //異步 適合抽幀等快速的操作 public static String extractAsyn( String ffmpegPath,String cmdParam, String sourceFile,String targetFile) throws Throwable { Runtime runtime = Runtime.getRuntime(); Process proce = null; // 視頻截圖命令,封面圖。 8是代表第8秒的時候截圖 String cmd = ""; String cut = ffmpegPath +" -i "+ sourceFile +" "+ cmdParam +" "+ targetFile; String cutCmd = cmd + cut; proce = runtime.exec(cutCmd); proce.getOutputStream(); System.out.println("抽幀命令是:"+cut); return targetFile; } public static boolean checkfile(String path) { File file = new File(path); if (!file.isFile()) { return false; } return true; } //異步處理 public boolean processVideoSync(String ffmpegPath,String cmdParam, String sourceFile,String targetFile) { // 文件命名 List<String> commond = new ArrayList<String>(); commond.add(ffmpegPath); commond.add("-i"); commond.add(sourceFile); commond.addAll(Arrays.asList(cmdParam.trim().split("\\|"))); commond.add(targetFile); if(new File(targetFile).exists()) { new File(targetFile).delete(); } String cmds = ""; for (String cmd : commond) { cmds = cmds + " " + cmd; } System.out.println("執行命令參數為:" + cmds); try { // 調用線程命令進行轉碼 Process videoProcess = new ProcessBuilder(commond).redirectErrorStream(true).start(); //new PrintStream(videoProcess.getInputStream()).start(); //videoProcess.waitFor(); /*new InputStreamReader(videoProcess.getErrorStream()); BufferedReader stdout = new BufferedReader(new InputStreamReader(videoProcess.getInputStream())); String line; while ((line = stdout.readLine()) != null) { dealLine(line); }*/ dealStream(videoProcess); videoProcess.waitFor(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } //處理輸出流 public abstract void dealLine(String line); public abstract void dealStream(Process process ); }
@Component public class ProgressService extends FFmpegUtils{ public static Logger logger = LoggerFactory.getLogger(ProgressService.class); /** * 進度正則查詢 */ private String frameRegexDuration = "frame=([\\s,\\d]*) fps=(.*?) q=(.*?) size=([\\s\\S]*) time=(.*?) bitrate=([\\s\\S]*) speed=(.*?)x"; /** * 正則模式 */ private Pattern framePattern = Pattern.compile(frameRegexDuration); /** * 秒數 */ private Integer timeLengthSec; /** * 時長 */ private String timeLength; /** * 開始時間 */ private String startTime; /** * 比特率 */ private String bitrate; /** * 時長 正則 */ private String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s"; /** * 正則模式 */ private Pattern pattern = Pattern.compile(regexDuration); public String getStartTime() { return startTime; } public void setStartTime(String startTime) { this.startTime = startTime; } public String getBitrate() { return bitrate; } public void setBitrate(String bitrate) { this.bitrate = bitrate; } private TranscodeTask task; public TranscodeTask getTask() { return task; } public void setTask(TranscodeTask task) { this.task = task; } @Autowired private TaskReposity _taskRep; @Override public void dealLine(String line) { logger.debug("{}輸出信息:{}",task.getName(),line); //獲取視頻長度信息 if(timeLength == null || "".equals(timeLength)) { Matcher m = pattern.matcher(line.trim()); if (m.find()) { timeLength = m.group(1); if(timeLength!=null){ timeLengthSec = FFVideoUtil.getTimelen(timeLength); } startTime = m.group(2); bitrate = m.group(3); logger.debug("timeLength:{}, startTime:{},bitrate:{}",timeLength,startTime,bitrate); } } //獲取視頻信息 Matcher matcher = framePattern.matcher(line); if(matcher.find()){ try { String execTimeStr = matcher.group(5); int execTimeInt = FFVideoUtil.getTimelen(execTimeStr); double devnum = FFBigDecimalUtil.div(execTimeInt,timeLengthSec,5); double progressDouble = FFBigDecimalUtil.mul(devnum,100); logger.debug("execTimeInt:{},devnum:{},progressDouble:{}",execTimeInt,devnum,progressDouble); task.setProgress((float)progressDouble); _taskRep.saveAndFlush(this.task); } catch (IllegalAccessException e) { logger.error("獲取輸出流異常:{}",e.getMessage()); } } } /** * 處理process輸出流和錯誤流,防止進程阻塞 * 在process.waitFor();前調用 * @param process */ @Override public void dealStream(Process process) { if (process == null) { return; } // 處理InputStream的線程 new Thread() { @Override public void run() { BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = null; try { while ((line = in.readLine()) != null) { //logger.info("output: " + line); dealLine(line); } } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }.start(); // 處理ErrorStream的線程 new Thread() { @Override public void run() { BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream())); String line = null; try { while ((line = err.readLine()) != null) { logger.info("err: " + line); } } catch (IOException e) { e.printStackTrace(); } finally { try { err.close(); } catch (IOException e) { e.printStackTrace(); } } } }.start(); } }

@Component public class FileService { public static Logger logger = LoggerFactory.getLogger(FileService.class); // 下載小文件 public File downloadFile(String formUrl, String fileName) throws Throwable { File desc = null; CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet(formUrl); httpget.setConfig(RequestConfig.custom() // .setConnectionRequestTimeout(5000) // .setConnectTimeout(5000) // .setSocketTimeout(5000) // .build()); logger.debug("正在從{}下載文件到{}",formUrl,fileName); try (CloseableHttpResponse response = httpclient.execute(httpget)) { org.apache.http.HttpEntity entity = response.getEntity(); desc = new File(fileName); try (InputStream is = entity.getContent(); // OutputStream os = new FileOutputStream(desc)) { StreamUtils.copy(is, os); logger.debug("成功從{}下載文件到{}",formUrl,fileName); } } return desc; } public void downloadLittleFileToPath(String url, String target) { Instant now = Instant.now(); RestTemplate template = new RestTemplate(); ClientHttpRequestFactory clientFactory = new HttpComponentsClientHttpRequestFactory(); template.setRequestFactory(clientFactory); HttpHeaders header = new HttpHeaders(); List<MediaType> list = new ArrayList<MediaType>(); // 指定下載文件類型 list.add(MediaType.APPLICATION_OCTET_STREAM); header.setAccept(list); HttpEntity<byte[]> request = new HttpEntity<byte[]>(header); ResponseEntity<byte[]> rsp = template.exchange(url, HttpMethod.GET, request, byte[].class); logger.info("[下載文件] [狀態碼] code:{}", rsp.getStatusCode()); try { if(Paths.get(target).toFile().exists()) { Paths.get(target).toFile().delete(); } Files.write(Paths.get(target), Objects.requireNonNull(rsp.getBody(), "未獲取到下載文件")); } catch (IOException e) { logger.error("[下載文件] 寫入失敗:", e); } logger.info("[下載文件] 完成,耗時:{}", ChronoUnit.MILLIS.between(now, Instant.now())); } public void downloadBigFileToPath(String url, String target) { Instant now = Instant.now(); try { RestTemplate template = new RestTemplate(); ClientHttpRequestFactory clientFactory = new HttpComponentsClientHttpRequestFactory(); template.setRequestFactory(clientFactory); //定義請求頭的接收類型 RequestCallback requestCallback = request -> request.getHeaders() .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL)); // getForObject會將所有返回直接放到內存中,使用流來替代這個操作 ResponseExtractor<Void> responseExtractor = response -> { // Here I write the response to a file but do what you like if(Files.exists(Paths.get(target), LinkOption.NOFOLLOW_LINKS)) { Files.delete(Paths.get(target)); } Files.copy(response.getBody(), Paths.get(target)); return null; }; template.execute(url, HttpMethod.GET, requestCallback, responseExtractor); } catch (Throwable e) { logger.error("[下載文件] 寫入失敗:", e); } logger.info("[下載文件] 完成,耗時:{}", ChronoUnit.MILLIS.between(now, Instant.now())); } }
有個問題需要注意:
轉碼目標文件必須不存在才行,如果存在 先刪除,不然就卡死。