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服務器了。

這個時候我們再運行思路二中的示例代碼,記得寫好要傳輸的文件,運行即可實現文件互傳,非常方便。