1. 任務描述:由給定圖像序列合成 24fps 視頻
方案一
直接對圖像進行操作,適用於圖像名比較規范且默認順序即為所需順序的情景
ffmpeg -f image2 -i ./images_crop_%d.png -pix_fmt yuv420p -vcodec libx264 -r 24 -y output.mp4
方案二
將圖像順序寫入一個文件列表,讓 ffmpeg 從列表讀入並合成視頻,適用於自定義圖像順序的情景
ffmpeg -f concat -safe 0 -i input.txt -pix_fmt yuv420p -vcodec libx264 -r 24 -y -an output.mp4
其中列表格式如下

file '/Users/cv/playground/data/cam_1_frame_00.png' duration 0.5 file '/Users/cv/playground/data/cam_2_frame_01.png' duration 0.5 ……
file 設置當前幀圖像路徑,使用絕對路徑防止出錯。
duration 設置當前幀與下一幀的時間間隔,單位是秒(s)。
可能出現的錯誤及解決方法
錯誤提示:如果圖像的寬或高不是偶數,在轉換過程中會出現下面的問題

[libx264 @ 0x7fec87003c00] height not divisible by 2 (2000x1125) Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height Conversion failed!
解決方案:在轉換過程中對寬和高重新調整
ffmpeg -f concat -safe 0 -i input.txt -pix_fmt yuv420p -vcodec libx264 -r 24 -y -an -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" output.mp4
2. 任務描述:將視頻拆分成圖像序列
直接輸入需要分解的視頻名,並指定輸出圖像的格式即可
ffmpeg -i video.mpg image%d.jpg
ffmpeg -i scene2frame1.mov frame%d.png
ffmpeg -i src.mp4 -vframes 200 bmp_images/camera_01/%04d.bmp ffmpeg -i src.mp4 -vf scale=1920:1080 -vframes 200 bmp_resize/camera_01/%04d.bmp
vframes 用於設置提取的幀數。
vf scale 用於設置提取幀之后輸出的分辨率,可用於對提取幀進行 resize 處理。
3. 任務描述:將 YUV420P10LE 格式的圖片/視頻轉換成 YUV420P 格式
先查看原圖格式
cv:~ cv$ ffprobe -hide_banner -show_format cam-1-frame-1_yuv420ple.png Input #0, png_pipe, from 'cam-1-frame-1_yuv420ple.png': Duration: N/A, bitrate: N/A Stream #0:0: Video: png, rgb48be(pc), 3840x2160 [SAR 1:1 DAR 16:9], 25 tbr, 25 tbn, 25 tbc [FORMAT] filename=cam-1-frame-1_yuv420ple.png nb_streams=1 nb_programs=0 format_name=png_pipe format_long_name=piped png sequence start_time=N/A duration=N/A size=35370650 bit_rate=N/A probe_score=99 [/FORMAT]
然后使用 ffmpeg 轉換格式
cv:~ cv$ ffmpeg -pix_fmt yuv420p10le -i cam-1-frame-1.png -pix_fmt yuv420p cam-1-frame-1_yuv420p.png
然后查看轉換后的圖像的格式
cv:~ cv$ ffprobe -hide_banner -show_format cam-1-frame-1.png Input #0, png_pipe, from 'cam-1-frame-1.png': Duration: N/A, bitrate: N/A Stream #0:0: Video: png, rgb24(pc), 3840x2160 [SAR 1:1 DAR 16:9], 25 tbr, 25 tbn, 25 tbc [FORMAT] filename=cam-1-frame-1.png nb_streams=1 nb_programs=0 format_name=png_pipe format_long_name=piped png sequence start_time=N/A duration=N/A size=11496668 bit_rate=N/A probe_score=99 [/FORMAT]
4. 任務描述:兩路/多路視頻拼接,同時播放
ffmpeg -i test_1.mp4 -i test_2.mp4 -filter_complex "[0:v]pad=iw*2:ih[a];[a][1:v]overlay=w:0" -pix_fmt yuv420p -y output_result.mp4
從前往后參數的含義分別是:
-i test_1.mp4 指定輸入文件的名字,即打算放在左側播放的視頻1
-i test_2.mp4 指定輸入文件的名字,及打算放在右側播放的視頻2
-filter_complex "[0:v]pad=iw*2:ih[a];[a][1:v]overlay=w:0"
指的是復雜濾波器的設置。
其中[0:v] [1:v]表示輸入的第一個和第二個編號。
pad 用於邊界擴充,iw/ih分別是輸入視頻的寬度和高度。
[0:v]pad=iw*2:ih[a] 表示將第一個輸入視頻邊界擴充,並將擴充好的命名為 [a],方便后續操作。
[a][1:v]overlay=w*1 中的 [a][1:v] 表示將 [1:v] 疊加到 [a] 上去,並且位置從 w 開始,默認是 width=w 處,h 未寫表示 0。
同理可得三個視頻水平並列放置的命令
ffmpeg -i test_1.mp4 -i test_2.mp4 -i test_3.mp4 -filter_complex "[0:v]pad=iw*3:ih[a];[a][1:v]overlay=w[b];[b][2:v]overlay=w*2:0" -pix_fmt yuv420p -y output_result.mp4
還有一種方法,使用 hstack/vstack 進行組合,實現類似上面的結果
ffmpeg -i /home/cv/Downloads/cam_test_01.mp4 -i /home/cv/Downloads/cam_test_02.mp4 -i /home/cv/Downloads/cam_test_03.mp4 -i /home/cv/Downloads/cam_test_04.mp4 -filter_complex hstack=inputs=4 -shortest -y test_hstack.mp4
其中 -i 用於指示輸入數據路徑和格式
-filter_complex 用於選擇使用的視頻濾波器,本例使用水平方向的拼接,filter 的參數 hstac=inputs=4 用於顯式指示輸入通道數量
-shortest 的選項表示結果的時長與輸入數據中時間最短的數據相同
這樣得到的結果就是四個輸入視頻俺從左到右的順序水平放置。
對輸入視頻流的旋轉可以使用視頻濾鏡中的 transpose 來實現,不同的值產生不同得結果
- 0:逆時針旋轉90度並垂直翻轉
- 1:順時針旋轉90度
- 2:逆時針旋轉90度
- 3:順時針旋轉90度后並垂直翻轉
結合上面的 overlay 可以實現旋轉后組合放置的效果,比如下面這種對四個輸入流先逆時針旋轉90度然后按左上0-左下1-右下2-右上3的順序放置的示例。
ffmpeg -hide_banner \ -re -thread_queue_size 32 -i /dev/video0 \ -re -thread_queue_size 32 -i /dev/video1 \ -re -thread_queue_size 32 -i /dev/video2 \ -re -thread_queue_size 32 -i /dev/video3 \ -filter_complex "[0:v]transpose=2[va];[1:v]transpose=2[vb];[2:v]transpose=2[vc];[3:v]transpose=2[vd]; \ [va]pad=iw*2:ih*2[a];[a][vb]overlay=0:h[b];[b][vc]overlay=w:h[c];[c][vd]overlay=w:0" \ -pix_fmt yuv420p -vcodec libx264 -preset ultrafast -tune zerolatency \ -g 50 -sc_threshold 0 -x264-params keyint=25 -vb 50M -vframes 1000 -y overlay_out.mp4
5. 任務描述:對給定視頻在指定位置添加文字水印
ffmpeg -i ctest.mp4 -vf "drawtext=fontfile=simhei.ttf: text='Original':x=620:y=1920:fontsize=72:fontcolor=yellow:shadowy=2" -y test_dst.mp4
其中:
fontfile 表示字體類型,要確保存在對應的字體庫
text 表示要添加的字符串形式的文字內容
fontsize 用來設置字體大小,默認大小為 16
fontcolor 用來設置字體顏色,默認為 Black
x=620:y=1920 表示文字水印放置的位置
如果有多個水印需要放置,中間用逗號隔開即可。
ffmpeg -i test.mp4 -vf "drawtext=fontfile=simhei.ttf: text='Original':x=520:y=1950:fontsize=72:fontcolor=yellow:shadowy=2,drawtext=fontfile=simhei.ttf: text='DaVinci Resolve':x=1770:y=1950:fontsize=72:fontcolor=yellow:shadowy=2, drawtext=fontfile=simhei.ttf: text='Ours':x=3320:y=1950:fontsize=72:fontcolor=yellow:shadowy=2" -y test_dst.mp4
6. 任務描述:從輸入視頻中裁剪一部分作為輸出
利用 ffmpeg 中的 video filter功能,設置指定的裁剪開始位置和裁剪的寬度和高度即可
ffmpeg -i ffmpeg_test.mp4 -vf "crop=w:h:x:y" -y ffmpeg_test_out.mp4
其中 -i 指定輸入視頻數據
-vf 是 -filter:v 的縮略形式告訴 ffmpeg 使用視頻濾波器進行次操作
crop=w:h:x:y 中 w 是輸出視頻的寬,h 是輸出視頻的高,x 和 y 是裁剪開始的坐標值,以左上為坐標原點,向右為 x 方向,向下為 y 方向
例如 ffmpeg -i ffmpeg_test.mp4 -vf "crop=960:720:1920:480" -y ffmpeg_test_out.mp4 表示從給定視頻中 (1920, 480) 的位置出開始裁剪,
目標視頻分辨率為 960x720,所指示的方向坐標和起始點坐標方向相同。
A. 其它常用功能
A.1 獲取視頻格式信息
ffmpeg -i video.avi
會顯示 視頻時長、比特率、編碼方式、像素格式、分辨率 等信息。

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf57.71.100 Duration: 00:00:36.00, start: 0.000000, bitrate: 2781 kb/s Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x2160, 2776 kb/s, 50 fps, 50 tbr, 10000k tbn, 100.01 tbc (default) Metadata: handler_name : VideoHandler
查看某個視頻的總幀數
cv@cv:~/datasets$ ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 -i 1.mp4
等解碼完成后會輸出信息,比如我的輸入視頻只有 299 幀,輸出結果如下
299
其中
-v error 用於隱藏“info”輸出(版本信息等),使輸出更簡潔。
-count_frames 計算每個流的幀數,並在相應的流部分中報告。
-select_streams v:0 用於選擇感興趣的視頻流。
-show_entries stream=nb_read_frames 設置只顯示讀取的幀數。
-of default=nokey=1:noprint_wrappers=1 將輸出格式(也稱為“writer”)設置為默認值,不打印每個字段的鍵(nokey=1),不打印節頭和頁腳(noprint_wrappers=1)。
A.2 把視頻的前30幀轉換成一個Animated Gif
ffmpeg -i test.asf -vframes 30 -y -f gif a.gif
A.3 將 YUV420P 格式的圖像保存成二進制形式的 rawdata ,用ffmpeg轉化成正常的 yuv420p 並顯示
ffmpeg -f rawvideo -s 7680x3840 -pix_fmt yuv420p -i eqr_000010.bin -y a.bmp
open a.bmp
A.4 yuvj420p vs yuv420p
yuvj420p 格式和 yuv420p 格式之間唯一的區別在於:
yuvj420p 使用的是 0-255 的顏色值范圍(也就是常見的 PC、JPEG 等標准使用的顏色值范圍),
而yuv420p 使用的是 16-240 的顏色值范圍(也就是常見的 TV、MPEG 等標准使用的顏色值范圍)。
A.5 刪除視頻中相鄰的重復幀
使用視頻濾波器對相鄰重復的幀進行刪除,保證每一幀不會連續出現幾次
ffmpeg -i test_in.mp4 -vf mpdecimate,setpts=N/FRAME_RATE/TB -y test_out.mp4
參考資料
[1] 每天學習一個命令:ffprobe 查看多媒體信息 http://einverne.github.io/post/2015/02/ffprobe-show-media-info.html
[2] ffprobe,ffplay ffmpeg常用的命令行命令 https://juejin.im/post/5a59993cf265da3e4f0a1e4b
[3] ffmpeg 10bit 8bit yuv格式轉換 https://blog.csdn.net/baoyongshuai1509/article/details/83927538
[4] YUV420P格式分析 https://blog.csdn.net/yhc166188/article/details/81016916
[5] FFmpeg命令行實現兩路/多路視頻拼接 合並 合成 同時播放 https://blog.csdn.net/a386115360/article/details/89465633