# 如何使用 FFmpeg 進行圖片壓縮與製作家庭影片

這應該是我媽第一次登上我的部落格，因為她很喜歡從電視看小孩的影片，我雖然照片很多，但要精修成影片每次都花上好多時間，藉由這幾天分享了 FFmpeg 工具，索性我就來寫個小工具，可以快速把我成千上萬永遠看不完的照片，整理成永遠看不完的影片，再搭配經典的台語老歌，讓媽媽開心！😍

![FFmpeg](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/9acadb91b77dbb7ecb77-194909644-1db91b46-3d6a-4777-9b7a-6735f5e0b708.png)

### 使用 `ffmpeg` 進行圖片格式轉換

其實 FFmpeg 有個功能，就是可以對圖片作格式轉換，同時還能做到圖片壓縮的效果，且執行速度還很快！👍

-   支援各種圖片格式轉換
    
    ```bash
    ffmpeg -v error -i SNAG-0047.png SNAG-0047.jpg
    ffmpeg -v error -i SNAG-0047.jpg SNAG-0047.gif
    ffmpeg -v error -i SNAG-0047.gif SNAG-0047.webp
    ```
    
-   重新編碼圖片 (具有壓縮圖片效果)
    
    ```bash
    ffmpeg -i SNAG-0045.jpg SNAG-0045-1.jpg
    ```
    

### 使用 `ffmpeg` 將連續圖片編碼成影片檔

照片轉成影片有兩種方法：

1.  先準備好一定命名規則的圖片，例如 `image-0001.jpg`, `image-0002.jpg`, ... 以此類推。
    
    假設你想要每 4 秒鐘播放 1 張圖片 (1/4 fps)，就可以用以下命令產生影片檔：
    
    ```bash
    ffmpeg -v error -framerate 1/4 -i 'image-%04d.jpg' out.mp4
    ```
    
    假設你想要每秒鐘播放 1 張圖片 (1 fps)，就可以用以下命令產生影片檔：
    
    ```bash
    ffmpeg -v error -framerate 1 -i 'image-%04d.jpg' out.mp4
    ```
    
    你可以指定影片顯示尺寸為 `1920x1080`
    
    ```bash
    # 可以用 -s WxH 指定圖片輸出的顯示尺寸
    ffmpeg -v error -framerate 1/4 -i 'image-%04d.jpg' -s 1920x1080 out.mp4
    
    # 也可以用 -vf scale=W:H 指定圖片輸出的顯示尺寸
    ffmpeg -v error -framerate 1/4 -i 'image-%04d.jpg' -vf scale=1920:1080 out.mp4
    ```
    
2.  直接用 `glob` 語法透過萬用字元語法將所有圖片加入影片
    
    ```bash
    ffmpeg -v error -framerate 1/4 -pattern_type glob -i "*.jpg" -s 1920x1080 out.mp4
    ```
    

不過，上述作法產生的影片都沒有聲音，看影片比較沒感覺！

### 將圖片輪撥配上一個聲音檔 (適合家庭照片轉換成影片給長輩看)

這種作法由於同時會有兩個來源(Source)，一個為圖片，一個為聲音，所以就有**影片長度**以誰為主的問題，因此使用上要稍微注意這點。

1.  一張圖片，配一首歌
    
    適合用來替**純音樂**或**語音**製作一個封面，就像[股癌的 YouTube 影片](https://www.youtube.com/watch?v=kYZuerhJ4mE&t=564s)一樣。
    
    ```bash
    ffmpeg -loop 1 -i image.jpg -i audio.wav -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuvj444p -s 1920x1080 -shortest out.mp4
    ```
    
    參數列中 `-i` 出現兩次，代表兩個來源。
    
    第一個 `-i image.jpg` 接在 `-loop 1` 後面，代表圖片會無限輪撥，時間為「無限大」。
    
    第二個 `-i audio.wav` 是另一個輸入源，這部分因為是音樂，所以肯定有個時間長度。
    
    最後的 `-shortest` 選項就是告訴 `ffmpeg` 要以「時間最短的那個來源」為基準，所以有人先結束，影片就會結束播放。
    
    `-c:v libx264` 是 Vidoe Codec 採用 [`libx264`](https://www.ffmpeg.org/ffmpeg-all.html#libx264_002c-libx264rgb) 為主，而 `-tune stillimage` 是 `libx264` 的參數，代表影片要對「靜態圖片」最佳化。
    
    `-c:a aac` 是 Audio Codec 採用 `aac` 為主，`-b:a 192k` 則是指定音頻的 bitrate 採用 `192k` 高品質。
    
    `-pix_fmt yuvj444p` 則是選用 `yuvj444p` 做為主要的 [pixel format](https://en.wikipedia.org/wiki/Pixel_Format) 像素格式，不同的像素格式會輸出不同的照片畫質。你可以透過 `ffmpeg -pix_fmts` 查出 FFmpeg 所有[支援的像素格式](https://gist.github.com/doggy8088/dd4ecf9256dbfd624770015c5fe117d6)。設定為 `gray` 的話，所有圖片就會變成灰階色。
    
    `-s 1920x1080` 則是指定影片的大小為 `1080p` (1920x1080)
    
2.  一堆圖片，配一首歌
    
    適合用來將家庭照片做成影片，可以讓長輩從電視回憶歡樂時光！
    
    > 影片的時間可能要自己計算一下，看是要以「照片」播放的時間為主，還是以「音樂」為主。
    
    ```bash
    # 不加上 `-loop 1` 的話，圖片撥完一遍影片就會結束
    ffmpeg -framerate 1/4 -pattern_type glob -i "*.jpg" -i audio.wav -c:v libx264 -crf 14 -r 60 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuvj444p -vf scale=w=1920:h=-1 -shortest out.mp4
    
    # 加上 -loop 1 的話，圖片會一直輪撥，直到音樂結束 (假設音樂播放的時間比較長)
    ffmpeg -framerate 1/4 -pattern_type glob -loop 1 -i "*.jpg" -i audio.wav -c:v libx264 -crf 14 -r 60 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuvj444p -vf scale=w=1920:h=-1 -shortest out.mp4
    ```
    

### 總結

以後想製作出帶有音樂的照片輪撥影片，就只要把照片準備好，再準備一個 MP3 或 WAV 音檔，全部放進資料夾，透過一個命令就可以自動產生影片了，真的相當省時省力。

雖然就只是簡單的照片輪撥，也沒有什麼轉場動畫特效，但其實老人家對 3C 的要求不多，有照片、有音樂，基本上就感覺很棒了。 👍

### 相關連結

-   [FFmpeg](https://www.ffmpeg.org/)
-   [ffmpeg Documentation](https://www.ffmpeg.org/ffmpeg.html)
-   [Slideshow - FFmpeg](https://trac.ffmpeg.org/wiki/Slideshow)
-   [bmp - How to specify size of output image in ffmpeg command? - Stack Overflow](https://stackoverflow.com/a/17659349/910074)
-   [Combine one image + one audio file to make one video using FFmpeg - Super User](https://superuser.com/a/1041820/95798)
-   [Merge and Concat Multiple Audio and Video files using FFMPEG - Stack Overflow](https://stackoverflow.com/a/53857401/910074)
