如何根據 CSV 的時間戳記使用 FFmpeg 加速影片?

如何根據 CSV 的時間戳記使用 FFmpeg 加速影片?

已經存在關於使用 FFmpeg 加速視訊的問題,例如這個

我的問題是:是否還有一種方法可以指定多個部分,這些部分應透過外部 CSV 加速。

我的 CSV 看起來像這樣:

start, end
00:00:03.296, 00:00:14.372,
00:00:16.388, 00:00:33.635,
00:00:33.693, 00:00:39.428,
00:00:39.460, 00:00:50.355,
00:00:50.355, 00:01:17.892,
00:01:17.892, 00:01:19.845,
00:01:19.845, 00:01:47.616,

這些是精確的部分(每行一個部分,定義每個部分的開始和結束的兩個時間戳記),應將速度提高 10 倍。其餘保持原播放速度。

有什麼辦法可以做到這一點嗎?

答案1

我們可以設定每個視訊畫面所需的 PTS 時間戳,使用設定點使用精心設計的嵌套if表達式進行過濾。

以下答案只是一個“概念證明”,假設您擁有以程式設計方式創建所需的更複雜表達式的知識。此解決方案假設輸入影片具有固定的幀速率,並且從輸入幀數計算輸入時間戳很簡單。

注意:
透過設定時間戳來加速部分視頻會創建可變幀率 (VFR) 視頻,該視頻可能無法在所有視頻播放器中正常播放。
最好透過將所有視頻加速 10 倍來創建固定幀速率視頻,並在原始速率的部分中將每個幀複製 10 次。
請注意,使用使用 OpenCV 讀取幀並使用 OpenCV(或更好的 FFmpeg 管道)寫入的 Python 腳本,複製幀相對簡單。


假設我們有以下輸入檔(40 幀,1fps):

ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=40 -c:v libx264 -g 1 input.mp4

輸入影片的時間戳為:

 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,

假設我們想要在 [0, 19] 和 [30, 39] 範圍內加速,並且得到以下輸出時間戳記:

 0,    1,    2,    3,    4,    5,    6,    7,    8,    9,
10, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9,
11,   12,   13,   14,   15,   16,   17,   18,   19,   20,
21, 21.1, 21.2, 21.3, 21.4, 21.5, 21.6, 21.7, 21.8, 21.9,

我們可以使用以下 FFmpeg 指令:

ffmpeg -y -r 100 -i input.mp4 -fps_mode:v passthrough -vf "setpts='(if(lt(N,10), N, if(lt(N,20), ((N-10)/10)+10, if(lt(N,30), 11+(N-20), 21+(N-30)/10))))/TB'" -c:v libx264 -g 1 output.mp4

  • -r 100用於將資料包持續時間設定為 10 毫秒(短資料包持續時間允許更高解析度的時間戳記)。
  • -fps_mode:v passthrough- 將每個輸入幀從輸入傳遞到輸出(由於 100 fps 速率而不會重複幀)。
  • -vf "setpts='(if(lt(N,10), N, if(lt(N,20), ((N-10)/10)+10, if(lt(N,30), 11+(N-20), 21+(N-30)/10))))/TB'"- 使用if表達式和一些數學來調整時間戳記。
    if表達式適用 if(條件,如果為真則為值,如果為假則為值)。
    N為輸入幀號,從零開始計數。將前 10 幀的
    if(lt(N,10), N, ...PTS 設定為...除以以秒為單位的時間除以時基。N
    /TB
  • -g 1- 將 GOP 大小設為 1 進行測試(將其刪除)。使用 FFprobe 時它會保持 PTS 排序。

使用 FFprobe 驗證輸出時間戳記:
ffprobe -select_streams v:0 -of default=noprint_wrappers=1 -show_entries packet=pts_time output.mp4

輸出如預期:

pts_time=0.000000
pts_time=1.000000
pts_time=2.000000
pts_time=3.000000
pts_time=4.000000
pts_time=5.000000
pts_time=6.000000
pts_time=7.000000
pts_time=8.000000
pts_time=9.000000
pts_time=10.000000
pts_time=10.100000
pts_time=10.190000
pts_time=10.300000
pts_time=10.400000
pts_time=10.500000
pts_time=10.600000
pts_time=10.700000
pts_time=10.800000
pts_time=10.900000
pts_time=11.000000
pts_time=12.000000
pts_time=13.000000
pts_time=14.000000
pts_time=15.000000
pts_time=16.000000
pts_time=17.000000
pts_time=18.000000
pts_time=19.000000
pts_time=20.000000
pts_time=21.000000
pts_time=21.100000
pts_time=21.200000
pts_time=21.300000
pts_time=21.400000
pts_time=21.500000
pts_time=21.600000
pts_time=21.700000
pts_time=21.800000
pts_time=21.900000

示範輸出的動畫 GIF:
在此輸入影像描述
(使用創建ffmpeg -y -i output.mp4 -filter_complex "[0:v]split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -r 1 output.gif

相關內容