需求:將視頻文件壓入zip包,然后上傳服務器.服務器對zip解壓,使用bat/shell,使用ffmpeg對視頻進行封面截取.再使用OSS對視頻和封面進行批量上傳.最后將信息存入數據庫
遇到的問題
1.bat批量截取視頻封面
- 在之前的代碼中,遍歷視頻解壓后的目錄.通過ProcessBuilder調用bat/shell對某一個視頻進行封面截取.然后再上傳.這一次更改了方案,直接調用一次bat/shell文件對所有視頻截取封面.
- 很顯然想到了要在bat/shell中進行循環.在bat循環中要注意 bat for循環 變量賦值的問題.
bat for循環 變量賦值的問題
- 預處理機制:批處理讀取命令時是按行讀取的(另外例如 for 命令等,其后用一對圓括號閉合的所有語句也當作一行),在處理之前要完成必要的預處理工作,這其中就包括對該行命令中的變量賦值。在不啟用變量延遲,也不對變量動態捕獲其擴展變化時,變量在預處理階段不作改變
- setlocal enabledelayedexpansion ,就是啟用變量延遲,我們可以形象的認為是啟用了“對變量動態捕獲擴展變化”。而 ! 括起來的變量,就是要動態捕獲擴展的目標變量,如果不需要,可以繼續使用 % 括變量。
- 在調用該類型變量時也應注意,不是使用 %var% 而是使用 !var!
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
for /r D:\upload\zip\out\ %%i in (*.mp4) do (
set mp4=%%i
set res=!mp4:~0,-4!_pic.jpg
D:\ffmpeg\bin\ffmpeg.exe -i !mp4! -y -f image2 -t 0.001 !res!)
)
2.ffmpeg存在部分視頻截取不到封面問題
- 在使用ffmpeg的過程中發現存在部分視頻截取不到的情況,通過嘗試后發現是 -ss參數導致
原始代碼:
ffmpeg.exe -ss 3 -i a.mp4 -y -f image2 -t 0.001 -s 300*240 a_pic.jpg
ss參數表示截取第幾秒,存在截取不到的原因之一為視頻沒有那么長.估計還有其他原因,這里沒有深究
3.ffmpeg截取封面圖片尺寸大小問題
- 代碼如上. -s 參數后面可以指定所要截取出的圖片的大小.移動端使用后反饋圖片像素和視頻像素存在差別.[需要 封面圖片 和 視頻像素大小一致] 在嘗試后發現如果不加 -s 參數 那么默認生成的圖片和視頻像素一致.
4.使用ProcessBuilder調用bat/shell導致的進程掛起問題
- 在普通java程序中使用ProcessBuilder調用bat/shell去截取封面,沒有問題.但是在web工程中發現調用bat/shell 后,只會截取第一個視頻的封面,然后一直卡着.直到停止web工程.然后bat/shell程序才會繼續執行,生成所有的封面圖片.從現象可以看出,排除bat/shell腳本問題.一定是程序和bat/shell進行交互的地方卡住了.
- 問題解決參考博文:http://blog.csdn.net/sj13051180/article/details/47865803
使用Java代碼調用shell腳本,執行后會發現Java進程和Shell進程都會掛起,無法結束。
掛起原因
- 主進程中調用Runtime.exec會創建一個子進程,用於執行shell腳本。子進程創建后會和主進程分別獨立運行。
- 因為主進程需要等待腳本執行完成,然后對腳本返回值或輸出進行處理,所以這里主進程調用Process.waitfor等待子進程完成。
- 通過shell腳本可以看出:子進程執行過程就是不斷的打印信息。主進程中可以通過Process.getInputStream和Process.getErrorStream獲取並處理。
- 這時候子進程不斷向主進程發生數據,而主進程調用Process.waitfor后已掛起。當前子進程和主進程之間的緩沖區塞滿后,子進程不能繼續寫數據,然后也會掛起。
- 這樣子進程等待主進程讀取數據,主進程等待子進程結束,兩個進程相互等待,最終導致死鎖。
解決方法
- 基於上述分析,只要主進程在waitfor之前,能不斷處理緩沖區中的數據就可以。因為,我們可以再waitfor之前,單獨啟兩個額外的線程,分別用於處理InputStream和ErrorStream就可以。