2013年10月13日星期日

FFmpeg 輔助指令

FFmpeg 雖然是一種功能強大、跨平台、擴展性高的程式
但由於 FFmpeg 主要由指令組成,對於現今 GUI 當道的作業系統, FFmpeg 便顯示非常難操作
而且部分選項並不人性化,操作上便更加困難

FFmpeg 可以在轉換前,先利用 -i 選項觀察媒體檔案的資訊
ffmpeg -i video
使用者有時會嘗試將媒體檔案的資訊先輸出成文字檔案進行分析
但 FFmpeg 的資訊輸出是以 standard error 輸出,因此以
ffmpeg -i video >video.info
不能將資訊輸出成檔案
需要使用
ffmpeg -i video 2>video.info
「2>」是將 standard error 以 standard out 的方式輸出至檔案
若果不想將輸出至檔案,可以使用
ffmpeg -i video 2>&1
便會以 standard out 輸出至 terminal 上
當正常輸出後便可以將資訊利用不同的指令或程式分析

例如媒體檔案播放時間長度
FFmpeg 會以 Duration: HH:MM:SS.ss 的方式顯示,例如
 Duration: 01:23:45.67, start: 0.000000, bitrate: 1200 kb/s
可以配合 pipe, grep, awk, tr 截取播放時間長度,例如
ffmpeg -i video 2>&1 | grep -e 'Duration' | awk '{print $2}' | tr -d ','
ffmpeg -i video 2>&1 將資訊輸出至 terminal
| grep -e 'Duration' 利用 pipe 將 standard out 給予 grep 並只接收資訊中包含 Duration 字串的行(理論上只有1行)
| awk '{print $2}' 利用 pipe 將 standard out 給予 awk 以空白作為分隔器,並截取第2組字串(不包含空字串),即 01:23:45.67,
| tr -d ',' 利用 pipe 將 standard out 給予 tr 將截取到的字串的 , (逗號) 移除,便可以完整地只輸出播放時間長度

FFmpeg 只能使用 -t 或 -vframe 截取長度選項,沒有截取結束時間的選項
若需要截取影片 00:01:00.00 至 00:05:00.00 的範圍,便需要計算 00:05:00.00 減 00:01:00.00 的長度
00:05:00.00 減 00:01:00.00 是 00:04:00.00 當然易計,但時間長度並不一定如此簡單計算
雖然 Shell Script 有運算能力,但時間格式不能相減,因此要先將時間格式轉換成普通整數值
eraseZeros(){
    echo "${1}" | sed 's/^0*//'
}

timeToInt(){
    time="${1}"
    HH="${time:0:2}"
    HH=`eraseZeros $HH`
    MM="${time:3:2}"
    MM=`eraseZeros $MM`
    SS="${time:6:2}"
    SS=`eraseZeros $SS`
    ss="${time:9:2}"
    ss=`eraseZeros $ss`
    echo $(((HH*3600+MM*60+SS)*100+ss))
}
將 HH:MM:SS.ss 的時間格式轉換成獨立的時、分、秒及百分秒,但由於 Shell Script 會將前置 0 的整數以 八進制 運算
因此要將 前置 0 刪除,以確保數值以正常既 十進制 運算,如 01:23:45.67 會轉換成 502567 便可以進行運算
例如要截取 01:23:45.67 至 02:34:56.78 之間的影片,可以
start=`timeToInt 01:23:45.67`
end=`timeToInt 02:34:56.78`
hectoSecond=$((end-start))
得到 hectoSecond (百分秒) 但由於 -t 必須接收時間格式,而 -vframe 只接收秒格並非百分秒,因此將百分秒轉成時間格式會較簡單
padZero(){
    printf "%02d" $1
}

intToTime()
    ss="${1}"
    HH=$((ss/360000))
    HH=`padZero $HH`
    ss=$((ss%360000))
    MM=$((ss/6000))
    MM=`padZero $MM`
    ss=$((ss%6000))
    SS=$((ss/100))
    SS=`padZero $SS`
    ss=$((ss%100))
    ss=`padZero $ss`
    echo "${HH}:${MM}:${SS}.${ss}"
}
將百分秒數值轉換成時間格式
duration=`intToTime $hectoSecond`
準備好這些功能後便可以根據結束時間以 FFmpeg 截取影片
start_time=<start_time>
end_time=<end_time>
start_int=`timeToInt $start_time`
end_int=`timeToInt $end_time`
duration_int=$((end_int-start_int))
duration_time=`intToTime $duration_int`
ffmpeg -i video -ss $start_time -t $duration_time [other options] output.avi

沒有留言 :

發佈留言