﻿# 介紹好用工具：FFmpeg (強大的錄影、轉檔、串流工具與函式庫)

我在直播完後通常會錄製出 `*.mkv` 這種影片格式的檔案，但是我無法透過 Camtasia Studio 對該 MKV 的檔案進行後製 (不支援)，一定要先將影片轉換為 `*.mp4` 或其他支援的格式才能編輯。但是上網查找轉換格式的工具，大多都是需要付費的，很多人不知道的是，其實大部分的轉換工作都可以透過 [FFmpeg](https://ffmpeg.org/) 命令列工具來完成。今天這篇文章我就來介紹一下這套強大的轉檔工具，順便分享幾個我常用的命令與參數。

![FFmpeg](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/02c43b7386216877fc82-194717684-9919353b-8d51-4920-9980-3193fd895390.png)

### 簡介 FFmpeg

[FFmpeg](https://ffmpeg.org/) 是一個開放原始碼的自由軟體，它包含了**音訊**和**視訊**多種格式的錄影、轉檔、串流功能，同時也是一個音訊與視訊格式轉換**函式庫**(Library)，許多開源的工具都是基於 [FFmpeg](https://ffmpeg.org/) 打造的。

> `FFmpeg` 這個單詞中的 `FF` 指的是 `Fast Forward` (快轉) 的意思。

`FFmpeg` 主要由以下幾個元件組成：

-   命令列應用程式 (CLI)
    
    -   `ffmpeg`：用於對視訊檔案或音訊檔案轉換格式
    -   `ffplay`：一個簡單的播放器，基於 [SDL](https://zh.wikipedia.org/wiki/SDL) 與 `FFmpeg` 函式庫
    -   `ffprobe`：用於顯示媒體檔案的資訊，見 [MediaInfo](https://zh.wikipedia.org/wiki/MediaInfo)
-   函式庫 (Libraries)
    
    -   `libavcodec`：包含全部 `FFmpeg` 音訊/視訊**編解碼函式庫**(Codec)
    -   `libavformat`：包含 `demuxers` 和 `muxer` 函式庫
    -   `libavutil`：包含一些工具函式庫
    -   `libpostproc`：對於**視訊**做**前處理**的函式庫
    -   `libswscale`：對於**影像**作**縮放**的函式庫
    -   `libavfilter`
    -   `libswresample`
    -   `libavresample`

我之前一直都覺得，為什麼這個世界已經有 `FFmpeg` 這樣強大的工具，還會有這麼多付費的**影音轉檔**工具存在呢？其實是**影音轉檔**牽涉的知識實在是太太太太廣了，如果真的研究下去，你會發現這門技術跟無底洞沒甚麼兩樣，太複雜了，永遠學不完的感覺。不信嗎？你可以看看以下三個命令的說明就知道了！😅

1.  `ffmpeg`
    
    完整文件請看 [ffmpeg](https://www.ffmpeg.org/ffmpeg.html) 與 [ffmpeg-all](https://www.ffmpeg.org/ffmpeg-all.html)
    
    ```bash
    ffmpeg -help
    ```
    
    > [ffmpeg -help 輸出結果](https://gist.github.com/doggy8088/85c6a8b3924e208b9f1b156a1ca01d1a)
    
2.  `ffprobe`
    
    完整文件請看 [ffprobe](https://www.ffmpeg.org/ffprobe.html) 與 [ffprobe-all](https://www.ffmpeg.org/ffprobe-all.html)
    
    ```bash
    ffprobe -help
    ```
    
3.  `ffplay`
    
    完整文件請看 [ffplay](https://www.ffmpeg.org/ffplay.html) 與 [ffplay-all](https://www.ffmpeg.org/ffplay-all.html)
    
    ```bash
    ffplay -help
    ```
    
    > [ffplay -help 輸出結果](https://gist.github.com/doggy8088/76bd84519240d9c1d1735d37b310dfe2)
    
    > [ffprobe -help 輸出結果](https://gist.github.com/doggy8088/d6a81377156e2ff71434cf7aec065f2b)
    

### 安裝 FFmpeg 工具

使用 [Chocolatey](https://chocolatey.org/install) 來安裝 [ffmpeg](https://community.chocolatey.org/packages/ffmpeg) 套件應該是最簡單的了：

```bash
choco install ffmpeg -y
```

查看版本資訊：

1.  `ffmpeg`
    
    ```bash
    ffmpeg -version
    ```
    
    ```
    ffmpeg version 5.0.1-essentials_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers
    built with gcc 11.2.0 (Rev7, Built by MSYS2 project)
    configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
    libavutil      57. 17.100 / 57. 17.100
    libavcodec     59. 18.100 / 59. 18.100
    libavformat    59. 16.100 / 59. 16.100
    libavdevice    59.  4.100 / 59.  4.100
    libavfilter     8. 24.100 /  8. 24.100
    libswscale      6.  4.100 /  6.  4.100
    libswresample   4.  3.100 /  4.  3.100
    libpostproc    56.  3.100 / 56.  3.100
    ```
    
2.  `ffplay`
    
    ```bash
    ffplay -version
    ```
    
    ```
    ffplay version 5.0.1-essentials_build-www.gyan.dev Copyright (c) 2003-2022 the FFmpeg developers
    ```
    
3.  `ffprobe`
    
    ```bash
    ffprobe -version
    ```
    
    ```
    ffprobe version 5.0.1-essentials_build-www.gyan.dev Copyright (c) 2007-2022 the FFmpeg developers
    ```
    

### 使用 `ffmpeg` 進行影音格式轉檔

-   將 MKV (視訊) 轉 MP4 (視訊) 格式
    
    ```powershell
    ffmpeg -i 'test.mkv' -c copy 'test.mp4'
    ```
    
    如果上述命令有問題，才改用以下命令執行：
    
    ```powershell
    ffmpeg -i 'test.mkv' 'test.mp4'
    ```
    
    > 事實上 FFmpeg 支援超多種格式，任何格式你都可以試著轉轉看，我很少遇到無法轉換的格式。
    
-   將 MP4 (視訊) 轉 MP3 (音訊) 格式
    
    ```powershell
    ffmpeg -i 'test.mp4' 'test.mp3'
    ```
    
    > 事實上 FFmpeg 支援超多種「音訊」格式，任何影音檔都可以試著轉轉看，我很少遇到無法轉換的格式。
    

### 使用 `ffmpeg` 進行影片裁切 (剪片)

使用 FFmpeg 剪片時，可以大致分成兩種剪法：

1.  使用 `codec copy` 快速剪片
    
    使用 FFmpeg 剪片時，在不需要進行影音格式轉換的前提下，可以使用 `codec copy` 的方式來剪片，剪輯速度非常快，我有個影片長達兩個多小時(`02:18:57`)，使用 `ffmpeg` 命令搭配 `-c copy` 參數做影片裁切，只需要執行 `3.4` 秒就可以剪片完畢，是不是超快！👍
    
    不過，速度快縱然是他的優點，但缺點是影片可能會在**開頭**或**結尾**會呈現幾秒鐘的**黑畫面**或**停格畫面** (看你用什麼**影音播放器**而定)，這是因為如果你切割的**時間點**沒有 keyframe 關鍵影格，剪出來的影片會比原本想剪輯的片段還長一些，會有一點怪怪的！
    
    > 開頭第一幀(first frame)如果不是 Keyframe 的話，在 Windows Media Player 播放影片會很怪，一開始就只有聲音，影片是停格的畫面(停在第一幀 Keyframe 的畫面)。但是在 [PotPlayer](https://potplayer.tv/) 就看不到這個問題，應該是有些影音播放器會自動修正這種詭異的影片格式。相關資訊：[https://trac.ffmpeg.org/wiki/Seeking](https://trac.ffmpeg.org/wiki/Seeking)
    
2.  使用 `re-encode` 精準剪片
    
    你只要在使用 `ffmpeg` 命令剪片時，不要使用 `-c copy` 參數做影片裁切，預設就會對整部影片全部重新解碼再編碼，然後「精準」的剪出你要的影片長度。
    
    不過，剪出來的影片品質最沒問題，但缺點是剪片的時間就會長很多很多了！
    

以下我說明剪片時重要的幾個參數：

-   使用 `-ss` 指定開始時間 (時間單位格式：`HH:MM:SS.MICROSECONDS`)
    
-   使用 `-to` 指定結束時間 (時間單位格式：`HH:MM:SS.MICROSECONDS`)
    
-   使用 `-t` 指定影片剪接的時間長度 (單位: 秒)
    
-   使用 `-i` 指定影片檔名
    
-   使用 `-c` 指定 Codec 名稱
    
    若 Codec 指定為 `copy` 的話，則代表 [Stream copy](https://ffmpeg.org/ffmpeg.html#Stream-copy) 或 `codec copy` 的意思，從 `copy` 的名字也可以看的出來，這種 Codec 就是不做**編碼**與**解碼**，直接**複製**的意思，所以剪片的速度非常快。這種用法特別適用於不需要轉換影片格式的情境。
    
    你可以透過以下命令查詢 FFmpeg 支援的 Codec 有哪些，真的相當多！
    
    ```bash
    ffmpeg -codecs
    ```
    
    因為 Codec 還有區分多種類型，所以 `ffmpeg -codecs` 命令會顯示以下提示，讓你知道不同 Codec 可以用在哪邊：
    
    ```
    Codecs:
     D..... = Decoding supported
     .E.... = Encoding supported
     ..V... = Video codec
     ..A... = Audio codec
     ..S... = Subtitle codec
     ...I.. = Intra frame-only codec
     ....L. = Lossy compression
     .....S = Lossless compression
    -------
    D.VI.S 012v                 Uncompressed 4:2:2 10-bit
    D.V.L. 4xm                  4X Movie
    D.VI.S 8bps                 QuickTime 8BPS video
    D.V..S aasc                 Autodesk RLE
    D.V.L. agm                  Amuse Graphics Movie
    D.VIL. aic                  Apple Intermediate Codec
    DEVI.S alias_pix            Alias/Wavefront PIX image
    DEVIL. amv                  AMV Video
    ...
    ...
    ```
    
    > 注意: 你只要不加上 `-c` 參數，就可以做到剪片的同時直接轉檔(換影片檔格式)！🔥
    

以下是使用範例：

-   剪掉**特定時間點之前**的片段
    
    使用 `-c copy` 參數指定 Codec (編解碼函式庫) 為 `copy`，就可以做到快速剪片，把指定時間點前的片段裁掉，並產生新的影片檔。
    
    ```bash
    ffmpeg -ss '00:28:16' -i 'test.mp4' -c copy 'test_new.mp4'
    ```
    
    如果要明確指定 Video (`-vcodec`) 與 Audio (`-acodec`) 的 Codec，也可這樣執行：
    
    ```bash
    # 完整的命令
    ffmpeg -ss '00:28:16' -i 'test.mp4' -vcodec copy -acodec copy 'test_new.mp4'
    # 簡寫的命令
    ffmpeg -ss '00:28:16' -i 'test.mp4' -c:v copy -c:a copy 'test_new.mp4'
    ```
    
    > 請記得: 不加上 codec 參數時，剪輯出來的影片比較沒問題，但執行時間較長。
    
-   剪掉**特定時間點之後**的片段
    
    ```bash
    ffmpeg -to '00:51:38' -i 'test.mp4' -c copy 'test_new.mp4'
    ```
    
-   剪掉**特定時間點之前**與**特定時間點之後**的片段
    
    ```bash
    ffmpeg -ss '00:28:16' -to '00:51:38' -i 'test.mp4' -c copy 'test_new.mp4'
    ```
    
-   取得**特定時間點之後**的**一段時間**的片段
    
    使用 `-t` 可以指定一個時間長度(duration)，單位為「秒數」。例如以下命令可以剪出從 `00:28:16` 開始後 5 分鐘的影片！
    
    ```bash
    ffmpeg -ss '00:28:16' -t '300' -i 'test.mp4' -c copy 'test_new.mp4'
    ```
    

### 使用 `ffmpeg` 進行影片截圖

透過 `ffmpeg` 截圖有許多方式：

1.  Input seeking
    
    先決定要截圖的時間位置，直接讀取 `test.mp4` 的該時間點位置的畫面：
    
    ```bash
    ffmpeg -ss '01:20:29' -i test.mp4 -frames:v 1 out1.jpg
    ```
    
    > 這種截圖方式非常快，幾乎都可以在**一秒內**完成截圖，而且從 FFmpeg 2.1 開始，截圖已經非常精準，應該不需要第二種 Output seeking 的方法！🔥
    
2.  Output seeking
    
    先對 `test.mp4` 進行影片解碼，再依據要截圖的時間位置，讀取該時間點位置的畫面：
    
    ```bash
    ffmpeg -i test.mp4 -ss '01:20:29' -frames:v 1 out2.jpg
    ```
    
    > 這種截圖方式非常非常慢，但優點一樣是「精準」截圖，因為他要一幀一幀的解開畫面，到指定位置才能進行截圖！
    
3.  直接將影片中所有影格(Frame)都擷取成 PNG 圖片
    
    ```bash
    ffmpeg -i test.mp4 'test-screenshot-%04d.png'
    ```
    
4.  直接將影片中每一秒的畫面擷取成 PNG 圖片
    
    ```bash
    ffmpeg -i test.mp4 -vf fps=1 'test-screenshot-%04d.png'
    ```
    
5.  直接將影片中每 5 秒的畫面擷取成 PNG 圖片
    
    ```bash
    ffmpeg -i test.mp4 -vf fps=1/5 'test-screenshot-%04d.png'
    ```
    
6.  直接將影片中每 5 秒的畫面擷取成 PNG 圖片
    
    ```bash
    ffmpeg -ss '00:28:16' -to '00:51:38' -i test.mp4 -vf fps=1/5 'test-screenshot-%04d.png'
    ```
    
    > 請記得不要將 `-i` 參數放在 `-ss` 參數之前，否則截圖速度會超級慢！🔥
    

### 使用 `ffprobe` 分析影片內容

-   分析一個影片檔的摘要資訊
    
    ```bash
    ffprobe 'test.mp4' 2>&1
    ```
    
    > 預設該命令會輸出**版本與檔案資訊**在 `STDERR` 的管道，你可以用 `2>&1` 改輸出到 `STDOUT`！
    
    該影片總長度為 `02:18:57.33`，每秒偵率為 496 kb/s，有兩個 Stream 頻道，一個為 Video (`h264`)，一個為 Audio (`aac`)
    
    ```
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf59.16.100
      Duration: 02:18:57.33, start: 0.000000, bitrate: 496 kb/s
      Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 358 kb/s, 30 fps, 30     tbr, 15360 tbn (default)
        Metadata:
          handler_name    : VideoHandler
          vendor_id       : [0][0][0][0]
      Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 126 kb/s (default)
        Metadata:
          handler_name    : SoundHandler
          vendor_id       : [0][0][0][0]
    ```
    
-   分析一個影片檔的格式資訊
    
    ```bash
    ffprobe -v error -show_format 'test.mkv'
    ```
    
    > 這裡的 `-v error` 主要用來隱藏**版本與檔案資訊**，也就是隱藏 `STDERR` 管道輸出的意思。
    
    ```ini
    [FORMAT]
    filename=test.mkv
    nb_streams=2
    nb_programs=0
    format_name=matroska,webm
    format_long_name=Matroska / WebM
    start_time=0.000000
    duration=8337.333000
    size=2743626385
    bit_rate=2632617
    probe_score=100
    TAG:ENCODER=Lavf58.76.100
    [/FORMAT]
    ```
    
    > 這裡的 `nb_streams` 是 `number of streams` 的意思。
    
-   分析一個影片檔的音軌、影像軌資訊
    
    顯示所有 Streams 資訊
    
    ```bash
    ffprobe -v error -show_streams 'test.mkv'
    ```
    
    ```ini
    [STREAM]
    index=0
    codec_name=h264
    codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
    profile=High
    codec_type=video
    codec_tag_string=[0][0][0][0]
    codec_tag=0x0000
    width=1920
    height=1080
    coded_width=1920
    coded_height=1080
    closed_captions=0
    film_grain=0
    has_b_frames=1
    sample_aspect_ratio=1:1
    display_aspect_ratio=16:9
    pix_fmt=yuv420p
    level=40
    color_range=tv
    color_space=bt709
    color_transfer=bt709
    color_primaries=bt709
    chroma_location=left
    field_order=progressive
    refs=1
    is_avc=true
    nal_length_size=4
    id=N/A
    r_frame_rate=30/1
    avg_frame_rate=30/1
    time_base=1/1000
    start_pts=0
    start_time=0.000000
    duration_ts=N/A
    duration=N/A
    bit_rate=N/A
    max_bit_rate=N/A
    bits_per_raw_sample=8
    nb_frames=N/A
    nb_read_frames=N/A
    nb_read_packets=N/A
    extradata_size=57
    DISPOSITION:default=1
    DISPOSITION:dub=0
    DISPOSITION:original=0
    DISPOSITION:comment=0
    DISPOSITION:lyrics=0
    DISPOSITION:karaoke=0
    DISPOSITION:forced=0
    DISPOSITION:hearing_impaired=0
    DISPOSITION:visual_impaired=0
    DISPOSITION:clean_effects=0
    DISPOSITION:attached_pic=0
    DISPOSITION:timed_thumbnails=0
    DISPOSITION:captions=0
    DISPOSITION:descriptions=0
    DISPOSITION:metadata=0
    DISPOSITION:dependent=0
    DISPOSITION:still_image=0
    TAG:DURATION=02:18:57.333000000
    [/STREAM]
    [STREAM]
    index=1
    codec_name=aac
    codec_long_name=AAC (Advanced Audio Coding)
    profile=LC
    codec_type=audio
    codec_tag_string=[0][0][0][0]
    codec_tag=0x0000
    sample_fmt=fltp
    sample_rate=48000
    channels=2
    channel_layout=stereo
    bits_per_sample=0
    id=N/A
    r_frame_rate=0/0
    avg_frame_rate=0/0
    time_base=1/1000
    start_pts=0
    start_time=0.000000
    duration_ts=N/A
    duration=N/A
    bit_rate=N/A
    max_bit_rate=N/A
    bits_per_raw_sample=N/A
    nb_frames=N/A
    nb_read_frames=N/A
    nb_read_packets=N/A
    extradata_size=2
    DISPOSITION:default=1
    DISPOSITION:dub=0
    DISPOSITION:original=0
    DISPOSITION:comment=0
    DISPOSITION:lyrics=0
    DISPOSITION:karaoke=0
    DISPOSITION:forced=0
    DISPOSITION:hearing_impaired=0
    DISPOSITION:visual_impaired=0
    DISPOSITION:clean_effects=0
    DISPOSITION:attached_pic=0
    DISPOSITION:timed_thumbnails=0
    DISPOSITION:captions=0
    DISPOSITION:descriptions=0
    DISPOSITION:metadata=0
    DISPOSITION:dependent=0
    DISPOSITION:still_image=0
    TAG:title=simple_aac
    TAG:DURATION=02:18:57.216000000
    [/STREAM]
    ```
    
    你也可以透過以下參數選擇你想顯示的 Streams 資訊：
    
    ```bash
    # 顯示所有影像軌資訊
    ffprobe -v error -show_streams -select_streams v   'test.mkv'
    # 顯示第0個影像軌資訊
    ffprobe -v error -show_streams -select_streams v:0 'test.mkv'
    # 顯示所有音軌資訊
    ffprobe -v error -show_streams -select_streams a   'test.mkv'
    # 顯示第0個音軌資訊
    ffprobe -v error -show_streams -select_streams a:0 'test.mkv'
    ```
    
-   顯示每個封包(Packet)的詳細資訊
    
    顯示總共的封包(Packet)統計
    
    ```bash
    ffprobe -v error -show_streams -select_streams v:0 -count_packets 'test.mkv'
    ```
    
    > 其中 `nb_frames` 代表影片的總封包數，而 `nb_read_packets` 代表已讀取到的總封包數。
    
    顯示每一個封包的詳細資訊
    
    ```bash
    ffprobe -v error -show_streams -select_streams v:0 -show_packets 'test.mkv'
    ```
    
-   顯示每個影格(Frame)的資訊
    
    顯示總共的影格(Frame)統計
    
    ```bash
    ffprobe -v error -show_streams -select_streams v:0 -count_frames 'test.mkv'
    ```
    
    > 其中 `nb_frames` 代表影片的總影格數，而 `nb_read_frames` 代表已讀取到的總影格數。
    
    顯示每一個影格(Frame)的詳細資訊
    
    ```bash
    ffprobe -v error -show_streams -select_streams v:0 -show_frames 'test.mkv'
    ```
    
    其中一個 FRAME 的資訊如下：
    
    ```ini
    [FRAME]
    media_type=video
    stream_index=0
    key_frame=0
    pts=6144
    pts_time=0.400000
    pkt_dts=6144
    pkt_dts_time=0.400000
    best_effort_timestamp=6144
    best_effort_timestamp_time=0.400000
    pkt_duration=512
    pkt_duration_time=0.033333
    pkt_pos=325207
    pkt_size=160
    width=1920
    height=1080
    pix_fmt=yuv420p
    sample_aspect_ratio=1:1
    pict_type=B
    coded_picture_number=136
    display_picture_number=0
    interlaced_frame=0
    top_field_first=0
    repeat_pict=0
    color_range=tv
    color_space=bt709
    color_primaries=bt709
    color_transfer=bt709
    chroma_location=left
    [/FRAME]
    ```
    
-   取得一個影片中**所有關鍵影格**的位置 (時間)
    
    我用 `-show_entries 'frame=pts_time'` 參數來選取 Frame 中的 `pts_time` 欄位資訊，也就是該影格屬於影片中的時間點：
    
    ```bash
    ffprobe -v error -select_streams 'v:0' -show_entries 'frame=pts_time,format=size' -of 'csv=p=0' -sexagesimal -skip_frame nokey 'test.mp4'
    ```
    
    > 其中 `-sexagesimal` 是為了顯示 `HH:MM:SS.MICROSECONDS` 這種格式，若不加上就是 `SS.MICROSECONDS` 格式(以秒數為主)。
    
    > 其中 `-of 'csv=p=0'` 是為了輸出 CSV 格式，而 `p=0` 代表的意思是「輸出時不顯示欄位名稱，僅輸出 frame 的時間值」。
    
    > 其中 `-skip_frame nokey` 是為了排除「非關鍵影格」的 Frame！
    
-   找出**特定時間點附近**的**關鍵影格**位置 (時間)
    
    如果我們想剪出 `00:28:16` 到 `00:51:38` 這個時間點為例，可以透過以下命令找出這兩個時間點最接近的關鍵影格位置：
    
    ```bash
    ffprobe -v error -select_streams 'v:0' -show_entries 'frame=pts_time' -of 'csv=p=0' -sexagesimal -read_intervals '00:28:16%+#1' 'test.mp4'
    # 0:28:11.900000
    
    ffprobe -v error -select_streams 'v:0' -show_entries 'frame=pts_time' -of 'csv=p=0' -sexagesimal -read_intervals '00:51:38%+#1' 'test.mp4'
    # 0:51:36.366667
    ```
    
    > 這裡的 `-read_intervals` 的 `%+#1` 代表從**時間點**開始往後讀取一個 packet，但是 `ffmpeg` 在跳轉的時候，只能從「關鍵影格」(Keyframe)開始讀，因此回傳的時間將會從**最近的**(早一點的時間)一個關鍵影格時間點。所以你想從 `00:28:16` 開始擷取影片，但事實上你只能從 `0:28:11.900000` 開始擷取， 由於該參數很多變化，建議看[官網文件](https://ffmpeg.org/ffprobe.html#:~:text=corresponding%20stream%20section.-,%2Dread_intervals,-read_intervals)。
    
    然後再改用以下命令裁剪影片，就可以剪出精準的影片長度了，這個新影片檔的第一個 frame (`0:00:00.000000`) 就一定是 keyframe：
    
    ```bash
    ffmpeg -ss '0:28:11.900000' -to '0:51:36.366667' -i 'test.mp4' -c copy 'test2.mp4'
    ```
    
-   取得音量增益資訊 ([dB gain](https://en.wikipedia.org/wiki/Gain_\(electronics\)))
    
    顯示所有 **Audio** 相關的 Metadata，這可以看出你有多少資訊/欄位/TAG可以用
    
    ```bash
    ffprobe -v error -f lavfi -i 'amovie=test_new.mp4,astats=metadata=1:reset=1' -show_frames
    ```
    
    以下可以從 `test.mp4` 擷取出所有聲音的 Profile 並輸出到 `test_AudioProbe.csv` 檔案中：
    
    ```bash
    # 輸出成 CSV 格式
    ffprobe -v error -f lavfi -i 'amovie=test_new.mp4,astats=metadata=1:reset=1' -show_entries 'frame=pts_time:frame_tags=lavfi.astats.Overall.RMS_level,lavfi.astats.1.RMS_level,lavfi.astats.2.RMS_level' -of 'csv=p=0' > test_AudioProbe.csv
    ```
    
    輸出檔案內容為 CSV 格式，欄位內容如下：
    
    1.  聲音出現的秒數 (audio frame time in seconds)
    2.  整體音量的 dB 數 (overall RMS dB volume for that frame)
    3.  第一聲道的 dB 數 (the 3rd column RMS volume for the first channel)
    4.  第二聲道的 dB 數 (the last column the RMS volume for the 2nd channel) (如果有的話)
    
    你也可以輸出成 JSON 格式，方便程式分析
    
    ```bash
    # 輸出成 JSON 格式
    ffprobe -v error -f lavfi -i 'amovie=test_new.mp4,astats=metadata=1:reset=1' -show_entries 'frame=pts_time:frame_tags=lavfi.astats.Overall.RMS_level,lavfi.astats.1.RMS_level,lavfi.astats.2.RMS_level' -of 'json' > test_AudioProbe.json
    ```
    
-   取得影片的時間長度 (Stream duration)
    
    ```bash
    ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 test.mp4
    # 輸出: 253.600000
    
    ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 -sexagesimal test.mp4
    # 輸出: 0:04:13.600000
    ```
    
    > 其中 `-sexagesimal` 是為了顯示 `HH:MM:SS.MICROSECONDS` 這種格式，若不加上就是 `SS.MICROSECONDS` 格式(以秒數為主)。
    
-   取得影片的解析度 (Resolution)
    
    ```bash
    ffprobe -v error -select_streams v:0 -show_entries stream=height,width -of csv=s=x:p=0 test.mp4
    # 輸出: 1920x1080
    ```
    
-   取得影片的 Frame Rate
    
    ```bash
    ffprobe -v error -select_streams v:0 -show_entries stream=avg_frame_rate -of default=noprint_wrappers=1:nokey=1 test.mp4
    # 輸出: 2517000/41951
    ```
    
    > 注意: Frame Rate 有可能是變動的，而且一個影片檔可能會有多個 Video Streams
    

### 使用 `ffplay` 播放影音內容

-   直接播放影片
    
    ```bash
    ffplay test.mp4
    ```
    
    > 開啟的視窗沒有任何工具列，但有滿滿的快速鍵可以按，詳細清單請見 [ffplay Documentation - 3.6 While playing](https://ffmpeg.org/ffplay.html#While-playing)
    
-   在不顯示 GUI 介面的情況下播放音樂
    
    ```bash
    # 直接播放聲音檔
    ffplay -nodisp -f lavfi "amovie=audio.wav"
    
    # 直接播放影音檔中的聲音部分
    ffplay -nodisp -f lavfi "amovie=out.mp4"
    ```
    

### 總結

[FFmpeg](https://www.ffmpeg.org) 這水真的很深，我研究出本文的各種用法，是我曾經用過的，其實就已經可以衍生出數十種不同的影音應用，但本文的介紹可能講不到 FFmpeg 的 10% 吧，像是字幕的 Codec 就沒有講到，他可以把字幕寫入到影片中，但因為我還沒有這種需求，所以就沒特別去研究這部分的用法！

### 相關連結

-   [FFmpeg](https://www.ffmpeg.org/)
-   [ffmpeg Documentation](https://www.ffmpeg.org/ffmpeg.html)
-   [FFmpeg - 維基百科，自由的百科全書](https://zh.wikipedia.org/wiki/FFmpeg)
-   [使用 ffprobe 取得 mp4 資訊](https://cmdps.blogspot.com/2020/10/ffprobemp4.html)
-   [選擇 mp4 裡的幾段時間範圍，另存成一個 mp4](https://cmdps.blogspot.com/2019/12/mp4mp4.html)
-   [Fastest way to extract frames using ffmpeg? - Stack Overflow](https://stackoverflow.com/a/64260611/910074)
-   [ffmpeg txt from audio levels - Stack Overflow](https://stackoverflow.com/a/38060849/910074)
-   [FFprobeTips - FFmpeg](https://trac.ffmpeg.org/wiki/FFprobeTips)
-   [Converting Audio into Different Formats / Sample Rates](https://gist.github.com/protrolium/e0dbd4bb0f1a396fcb55)
-   [FFmpeg Commander](https://alfg.dev/ffmpeg-commander/)
-   [Newest 'ffmpeg' Questions - Video Production Stack Exchange](https://video.stackexchange.com/questions/tagged/ffmpeg?newreg=35b9478f714545ec8b641809adf52f15) (這是詢問 ffmpeg 相關問題最好的地方)
