Go + FFmpeg互動丨學習記錄

語言: CN / TW / HK

theme: cyanosis highlight: monokai


零、前言

注:本文未完待續

主要思路:

使用 Golang 和 FFmpeg 互動可以分為以下幾個步驟:

  1. 安裝 FFmpeg: 首先需要安裝 FFmpeg,可以在終端中輸入命令來安裝。
  2. 建立一個Golang專案,並在其中建立一個接收上傳視訊檔案的介面。
  3. 在介面中接收上傳的檔案,並使用Golang中的 exec 包來執行 FFmpeg 命令來轉碼視訊。
  4. 轉碼後的檔案可以儲存在本地或上傳到雲端儲存伺服器。
  5. 將視訊資訊儲存到 MySQL 資料庫中。
  6. 在Golang中使用GORM或其他ORM庫來連線資料庫並存儲資料。
  7. 在程式碼中使用 exec.Command 函式來執行 FFmpeg 命令。該函式需要 ffmpeg 的完整路徑和命令列引數,並返回一個 *exec.Cmd 型別的物件。
  8. 通過使用 .StdoutPipe() 和 .Start() 方法來執行 FFmpeg 命令並獲取命令輸出。
  9. 使用 io.Copy() 函式將轉碼後的視訊檔案寫入本地檔案或上傳到雲端儲存伺服器。
  10. 使用GORM將上傳視訊檔案的資訊儲存到資料庫中。

一、本地IO

以下是一個程式碼示例,實現從本地來,到本地去的功能,記得改路徑和名稱!

```Go package main

import ( "fmt" "os/exec" )

func main() { // 設定視訊原始檔路徑 inputFile := "input.mp4" // 設定轉碼後文件路徑 outputFile := "output.mp4"

// 設定 ffmpeg 命令列引數
args := []string{"-i", inputFile, "-c", "copy", outputFile}

// 建立 *exec.Cmd
cmd := exec.Command("ffmpeg", args...)

// 執行 ffmpeg 命令
if err := cmd.Run(); err != nil {
    fmt.Println(err)
    return
}

fmt.Println("轉碼成功")

} ```

如果你沒有報錯的話,可以看到,有輸出檔案,但是這一來一回有什麼用呢?

事實上目的就是讓這個轉碼後的視訊檔案是可以線上播放的。


二、儲存到資料庫

光從本地來到本地去總是不長久的,我們要開啟資料庫的大門;

首先需要準備好資料庫和表,這裡我們同樣使用Navicat來操作,具體操作步驟如下,不需要的可以跳過:

新建連線 -> MySQL -> 連線名隨便 -> 密碼隨便(強烈建議與資料庫密碼相同否則可能會產生一些錯誤) -> 雙擊左側開啟 -> 右鍵information_schema -> 新建資料庫 -> 名稱隨便 -> 字符集utf8mb4

然後執行如下程式碼即可,注意修改你的路徑、名稱、資料庫名稱等資訊

```Go package main

import ( "fmt" "os/exec"

"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"

)

// 定義 Video struct,用來儲存視訊資訊 type Video struct { gorm.Model Name string Path string }

func main() { // 連線資料庫 db, err := gorm.Open("mysql", "root:password@/database?charset=utf8&parseTime=True&loc=Local") if err != nil { panic("failed to connect to the database") } defer db.Close()

// 建立表
db.AutoMigrate(&Video{})

// FFmpeg命令轉換視訊
cmd := exec.Command("ffmpeg", "-i", "input.mp4", "-vcodec", "libx264", "-acodec", "aac", "-strict", "-2", "output.mp4")

err = cmd.Run()
if err != nil {
    fmt.Println(err)
}

// 在資料庫裡儲存視訊資訊
video := Video{Name: "output", Path: "output.mp4"}
db.Create(&video)

} ```

Navicat中效果如下:

avatar

幾點說明:

  • 這個 ffmpeg 示例中的命令是將視訊 "input.mp4" 轉換為新的視訊檔案 "output.mp4"。
  • 在這個命令中,我們使用了 "-i" 引數來指定輸入檔案,"-vcodec" 和 "-acodec" 引數來指定視訊和音訊編碼,"-strict" 和 "-2" 引數來指定編碼標準。
  • 其中 "-vcodec" 指定了視訊編碼為 libx264,"-acodec" 指定音訊編碼為 aac ,這兩個編碼是線上播放視訊常用的編碼方式,所以這個轉碼後的視訊檔案是可以線上播放的。
  • 如果你想要轉換成其它格式,可以查詢ffmpeg的文件和引數來實現。

三、前端實現與使用者互動

思路一:Nginx

Nginx 的作用是作為一個反向代理伺服器,用於將使用者的請求轉發到後端伺服器進行處理。

反向代理伺服器可以幫助實現負載均衡、安全性、快取等功能。

如果想使用 Nginx 作為 Web 伺服器來處理使用者的請求並將其轉發到後端伺服器,可以這樣做:

  1. 首先,需要在自己的伺服器上安裝 Nginx。
  2. 然後,需要編寫 Nginx 的配置檔案來處理使用者的請求。舉個例子,如果想將所有的 /upload 請求轉發到後端伺服器的 /upload 介面,可以在 Nginx 的配置檔案中新增如下程式碼:

location /upload { proxy_pass http://backend_server:8000/upload; }

  1. 在後端伺服器上實現對 /upload 介面的處理,如接收視訊檔案並進行轉碼。可以使用 Gin 或其他框架來實現這個功能,並將轉碼後的檔案儲存到資料庫中。
  2. 完成以上步驟後,當用戶在前端網頁上上傳視訊檔案時,這個檔案會被髮送到 Nginx,然後 Nginx 會將請求轉發到後端伺服器進行處理。後端伺服器接收到請求後會呼叫 ffmpeg 將視訊轉碼並存儲在資料庫中。

如果是在web端指定本地要作為輸入的視訊路徑,這部分需要在前端進行實現,可以在前端頁面上使用 HTML input 標籤來實現檔案選擇功能,並在選擇檔案後使用 JavaScript 來獲取檔案路徑併發送到後端伺服器。

例如,在 HTML 中使用 input 標籤來實現檔案選擇功能:

HTML <input type="file" id="input-file">

使用 JavaScript 程式碼來獲取檔案路徑併發送到後端伺服器:

```javascript

```


思路二:GoFTP

使用 GoFTP 來上傳和下載視訊,可以在 Go 中使用第三方庫:https://github.com/jlaffaye/ftp ;

使用這個庫可以在 Go 中實現 FTP 協議的上傳和下載功能,並可以輕鬆地將視訊檔案上傳到伺服器並在伺服器上進行轉碼。如此,可以將檔案上傳和轉碼的功能放在同一個伺服器上,而不需要使用反向代理伺服器來轉發請求。

使用 GoFTP 來上傳和下載視訊檔案的話不需要使用 HTML 和 JavaScript 。可以使用 Go 程式來直接與 FTP 伺服器進行互動。可以使用 GoFTP 庫,在 Go 中編寫程式來連線到 FTP 伺服器實現:連線到FTP伺服器,登入,上傳檔案,下載檔案等操作。

當然,如果需要在web上獲取使用者選擇的視訊檔案路徑,可以使用HTML和JavaScript來實現這部分功能,但是FTP上傳和下載操作可以直接在Go程式中實現。

以下是一個示例程式碼

```Go package main

import ( "fmt" "os"

"github.com/jlaffaye/ftp"

)

func main() { // 連線到 FTP 伺服器 conn, err := ftp.Connect("ftp.example.com:21") // ftp.example.com:21是一個模擬的FTP伺服器地址,實際使用中需要替換成真正的FTP伺服器的地址。 if err != nil { fmt.Println("Error connecting to FTP server:", err) return } defer conn.Quit()

// 登入到 FTP 伺服器
// 需要提前設定好username and password
if err := conn.Login("username", "password"); err != nil {
    fmt.Println("Error logging in to FTP server:", err)
    return
}

// 開啟本地檔案
file, err := os.Open("example.txt")
if err != nil {
    fmt.Println("Error opening local file:", err)
    return
}
defer file.Close()

// 上傳檔案到 FTP 伺服器
if err := conn.Stor("example.txt", file); err != nil {
    fmt.Println("Error uploading file:", err)
    return
}

fmt.Println("File uploaded successfully!!!")

} ```

一個新的問題出現了,如何搭建一個本地測試用的伺服器呢?好問題,如下:

在本地搭建一個測試用的FTP伺服器可以使用一些常用的FTP伺服器軟體來實現,如FileZilla Server, ProFTPD等。

  • 對於windows系統,可以使用FileZilla Server,下載地址:https://filezilla-project.org/download.php?type=server 下載完成後安裝,配置好FTP使用者名稱和密碼,設定好訪問許可權,就可以在本地測試使用了。
  • 對於Linux系統,可以使用ProFTPD, 安裝方法可以使用apt-get,yum等安裝工具,配置好FTP使用者名稱和密碼,設定好訪問許可權,就可以在本地測試使用了。

三個注意

  • 首席需要注意的是,在安裝和配置FTP伺服器的過程中,需要遵循安全原則,如設定強密碼,限制訪問許可權等,以防止未經授權的訪問。
  • 其次還需要注意的是,在使用FTP伺服器時需要注意防火牆設定,確保FTP伺服器能夠正常訪問。
  • 最後需要注意的是,如果您使用的是公網IP地址,需要注意安全性,因為您的FTP伺服器可能會被惡意攻擊。

兩種方法的對比:

使用 Nginx 作為反向代理伺服器和使用 GoFTP 上傳和下載視訊檔案,兩種方法有一些不同的優缺點。

使用 Nginx 作為反向代理伺服器的優點:

  • 可以提高系統的安全性,因為 Nginx 可以對使用者的請求進行驗證和過濾。
  • 可以實現負載均衡,可以提高系統的可用性和穩定性。
  • 可以實現快取功能,可以提高系統的效能。

使用 Nginx 作為反向代理伺服器的缺點:

  • 可能會增加系統的複雜度。
  • 可能會增加系統的運維成本。

使用 GoFTP 上傳和下載視訊檔案的優點:

  • 不需要使用額外的伺服器或框架,可以簡化系統的架構。
  • 可以直接在 Go 程式中實現檔案上傳和下載功能。

使用 GoFTP 上傳和下載視訊檔案的缺點:

  • 可能沒有Nginx那麼高的安全性,負載均衡和快取功能。
  • 可能需要自己手動實現檔案上傳和下載的功能,運維成本可能更高。

總結來說,對於需要高安全性,高併發,高可用性的系統,使用 Nginx 作為反向代理伺服器可能會更好。但是如果你的系統不需要如此高階的功能,並且希望簡化系統架構,減少運維成本,使用 GoFTP 來上傳和下載視訊檔案可能是一個更好的選擇。


兩種方法的結合:

當然,這兩種方法是可以結合起來使用的。

  • 使用 Nginx 作為反向代理伺服器,來過濾和驗證使用者的請求,並將請求轉發到 Go 程式中進行處理。

  • 在 Go 程式中可以使用 GoFTP 上傳和下載視訊檔案,並在檔案上傳完成後使用 ffmpeg 進行轉碼,將轉碼後的檔案儲存到資料庫。

這樣做的好處是,Nginx 可以提供高安全性、高併發、高可用性等功能,而 GoFTP 可以提供簡化系統架構、減少運維成本等功能,壞處很顯然,就是實現麻煩。


四、FileZillaServer + X-Plore

這裡介紹一種基於上文思路二,使用FileZillaServer + X-Plore實現的區域網下不同裝置之間的檔案互傳方法;

FileZillaServer

是什麼

是能在本地搭建一個測試用的FTP伺服器的軟體。

怎麼下載怎麼用

下載地址:FileZilla中文網 - 免費開源的FTP解決方案

前面的安裝以及初始化步驟可以參考:

FileZilla搭建FTP伺服器圖解教程 - 知乎 (zhihu.com)

記得第一個要設定為根目錄;

完成設定之後在本地的資源管理器中(以前是可以用瀏覽器的)輸入ftp://127.0.0.1進入即可。

然後就可以看到該使用者可以看到的檔案列表了。

這個時候可以為該使用者新增新的可見的非根目錄的資料夾,並且需要人為地指定它在伺服器端的路徑,例如/myAdditional,隨後確定後重新整理頁面,就可以發現多了一個資料夾,這樣就可以做到本地的檔案結構和伺服器端的不一樣。

有趣的是,這一操作可以讓我們重新組織本地檔案系統下的各個路徑。

還有我們可以使用一個比較方便的視覺化的客戶端來操作:FileZilla-Client;

由於操作比較簡單這裡就不給出介紹了,下載地址同上。


Android訪問FTP伺服器

可供使用的APP有:

  • AndFTP
  • 螞蟻科技
  • Turbo FTP 客戶端
  • ES 檔案資源管理器
  • 簡易 FTP 客戶端
  • 管理員之手應用程式
  • Termius - SSH / SFTP
  • FTP 伺服器
  • X-Plore

筆者的選擇是X-Plore,非常好用;

下載之後點選FTP,然後輸入剛才在PC端設定的IP(就是cmd中ipconfig的ipv4那個)以及賬戶+密碼,就可以連線到FTP伺服器了。

這個時候我們再執行思路二中的示例程式碼,記得寫好要傳輸的檔案,執行即可實現檔案互傳,非常方便。