Add: support customized ffmpeg container format

This commit is contained in:
2022-04-18 01:00:02 +08:00
parent e4c59fd539
commit 61d85bba97
7 changed files with 106 additions and 104 deletions

View File

@@ -6,16 +6,42 @@
"token": "!! config your very strong token here !!",
"ffmpeg_threads": 1,
"ffmpeg_config_list": [
{ "name": "OPUS 128k", "args": "-c:a libopus -ab 128k -vn" },
{ "name": "OPUS 96k", "args": "-c:a libopus -ab 96k -vn" },
{ "name": "OPUS 256k", "args": "-c:a libopus -ab 256k -vn" },
{ "name": "OPUS 320k", "args": "-c:a libopus -ab 320k -vn" },
{ "name": "OPUS 512k", "args": "-c:a libopus -ab 512k -vn" },
{ "name": "AAC 128k", "args": "-c:a aac -ab 128k -vn" },
{ "name": "AAC 256k", "args": "-c:a aac -ab 256k -vn" },
{
"name": "WEBM OPUS 128k",
"args": "-c:a libopus -ab 128k -vn",
"format": "webm"
},
{
"name": "WEBM OPUS 96k",
"args": "-c:a libopus -ab 96k -vn",
"format": "webm"
},
{
"name": "WEBM OPUS 256k",
"args": "-c:a libopus -ab 256k -vn",
"format": "webm"
},
{
"name": "WEBM OPUS 512k",
"args": "-c:a libopus -ab 512k -vn",
"format": "webm"
},
{
"name": "AAC 128k",
"args": "-c:a aac -ab 128k -vn",
"format": "adts"
},
{
"name": "AAC 256k",
"args": "-c:a aac -ab 256k -vn",
"format": "adts"
},
{ "name": "MP3 128k", "args": "-c:a mp3 -ab 128k -vn", "format": "mp3" },
{ "name": "MP3 320k", "args": "-c:a mp3 -ab 320k -vn", "format": "mp3" },
{ "name": "全损音质 32k", "args": "-c:a libopus -ab 32k -vn" },
{
"name": "video test",
"format": "webm",
"args": "-c:a libopus -ab 128k -filter:v scale='min(640,iw)':min'(360,ih)':force_original_aspect_ratio=decrease -c:v libvpx -r 5"
}
]

View File

@@ -5,6 +5,7 @@ import (
"flag"
"log"
"msw-open-music/pkg/api"
"msw-open-music/pkg/commonconfig"
"os"
)
@@ -14,12 +15,11 @@ func init() {
flag.StringVar(&ConfigFilePath, "config", "config.json", "backend config file path")
}
func main() {
var err error
flag.Parse()
config := api.Config{}
config := commonconfig.Config{}
configFile, err := os.Open(ConfigFilePath)
if err != nil {
log.Fatal(err)

View File

@@ -3,6 +3,7 @@ package api
import (
"github.com/gorilla/sessions"
"msw-open-music/pkg/database"
"msw-open-music/pkg/commonconfig"
"msw-open-music/pkg/tmpfs"
"net/http"
"os"
@@ -12,32 +13,13 @@ type API struct {
Db *database.Database
Server http.Server
token string
APIConfig APIConfig
APIConfig commonconfig.APIConfig
Tmpfs *tmpfs.Tmpfs
store *sessions.CookieStore
defaultSessionName string
}
func NewAPIConfig() APIConfig {
apiConfig := APIConfig{}
return apiConfig
}
type APIConfig struct {
DatabaseName string `json:"database_name"`
SingleThread bool `json:"single_thread,default=true"`
Addr string `json:"addr"`
Token string `json:"token"`
FfmpegThreads int64 `json:"ffmpeg_threads"`
FfmpegConfigList []FfmpegConfig `json:"ffmpeg_config_list"`
}
type Config struct {
APIConfig APIConfig `json:"api"`
TmpfsConfig tmpfs.TmpfsConfig `json:"tmpfs"`
}
func NewAPI(config Config) (*API, error) {
func NewAPI(config commonconfig.Config) (*API, error) {
var err error
apiConfig := config.APIConfig
@@ -117,7 +99,6 @@ func NewAPI(config Config) (*API, error) {
// below needs token
apiMux.HandleFunc("/walk", api.HandleWalk)
apiMux.HandleFunc("/reset", api.HandleReset)
apiMux.HandleFunc("/add_ffmpeg_config", api.HandleAddFfmpegConfig)
mux.Handle("/api/v1/", http.StripPrefix("/api/v1", apiMux))
mux.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("web/build"))))

View File

@@ -3,20 +3,12 @@ package api
import (
"encoding/json"
"log"
"msw-open-music/pkg/commonconfig"
"net/http"
)
type FfmpegConfig struct {
Name string `json:"name"`
Args string `json:"args"`
}
type FfmpegConfigList struct {
FfmpegConfigList []FfmpegConfig `json:"ffmpeg_config_list"`
}
func (api *API) GetFfmpegConfig(configName string) (FfmpegConfig, bool) {
ffmpegConfig := FfmpegConfig{}
func (api *API) GetFfmpegConfig(configName string) (commonconfig.FfmpegConfig, bool) {
ffmpegConfig := commonconfig.FfmpegConfig{}
for _, f := range api.APIConfig.FfmpegConfigList {
if f.Name == configName {
ffmpegConfig = f
@@ -30,45 +22,8 @@ func (api *API) GetFfmpegConfig(configName string) (FfmpegConfig, bool) {
func (api *API) HandleGetFfmpegConfigs(w http.ResponseWriter, r *http.Request) {
log.Println("[api] Get ffmpeg config list")
ffmpegConfigList := &FfmpegConfigList{
ffmpegConfigList := &commonconfig.FfmpegConfigList{
FfmpegConfigList: api.APIConfig.FfmpegConfigList,
}
json.NewEncoder(w).Encode(&ffmpegConfigList)
}
type AddFfmpegConfigRequest struct {
Token string `json:"token"`
Name string `json:"name"`
FfmpegConfig FfmpegConfig `json:"ffmpeg_config"`
}
func (api *API) HandleAddFfmpegConfig(w http.ResponseWriter, r *http.Request) {
addFfmpegConfigRequest := AddFfmpegConfigRequest{}
err := json.NewDecoder(r.Body).Decode(&addFfmpegConfigRequest)
if err != nil {
api.HandleError(w, r, err)
return
}
// check token
err = api.CheckToken(w, r, addFfmpegConfigRequest.Token)
if err != nil {
return
}
// check name and args not null
if addFfmpegConfigRequest.Name == "" {
api.HandleErrorString(w, r, `"ffmpeg_config.name" can't be empty`)
return
}
if addFfmpegConfigRequest.FfmpegConfig.Args == "" {
api.HandleErrorString(w, r, `"ffmpeg_config.args" can't be empty`)
return
}
log.Println("[api] Add ffmpeg config")
api.APIConfig.FfmpegConfigList = append(api.APIConfig.FfmpegConfigList, addFfmpegConfigRequest.FfmpegConfig)
api.HandleOK(w, r)
}

View File

@@ -68,11 +68,12 @@ func (api *API) HandleGetFileStream(w http.ResponseWriter, r *http.Request) {
}
args := strings.Split(ffmpegConfig.Args, " ")
startArgs := []string{"-threads", strconv.FormatInt(api.APIConfig.FfmpegThreads, 10), "-i", path}
endArgs := []string{"-f", "webm", "-"}
endArgs := []string{"-f", ffmpegConfig.Format, "-"}
ffmpegArgs := append(startArgs, args...)
ffmpegArgs = append(ffmpegArgs, endArgs...)
cmd := exec.Command("ffmpeg", ffmpegArgs...)
cmd.Stdout = w
// cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
api.HandleError(w, r, err)
@@ -127,7 +128,7 @@ func (api *API) HandlePrepareFileStreamDirect(w http.ResponseWriter, r *http.Req
api.HandleErrorStringCode(w, r, `ffmpeg config not found`, 404)
return
}
objPath := api.Tmpfs.GetObjFilePath(prepareFileStreamDirectRequst.ID, prepareFileStreamDirectRequst.ConfigName)
objPath := api.Tmpfs.GetObjFilePath(prepareFileStreamDirectRequst.ID, ffmpegConfig)
// check obj file exists
exists := api.Tmpfs.Exits(objPath)
@@ -179,7 +180,13 @@ func (api *API) HandleGetFileStreamDirect(w http.ResponseWriter, r *http.Request
configs := q["config"]
configName := configs[0]
path := api.Tmpfs.GetObjFilePath(int64(id), configName)
ffmpegConfig, ok := api.GetFfmpegConfig(configName)
if !ok {
api.HandleErrorStringCode(w, r, `ffmpeg config not found`, 404)
return
}
path := api.Tmpfs.GetObjFilePath(int64(id), ffmpegConfig)
if api.Tmpfs.Exits(path) {
api.Tmpfs.Record(path)
}

View File

@@ -0,0 +1,43 @@
package commonconfig
type Config struct {
APIConfig APIConfig `json:"api"`
TmpfsConfig TmpfsConfig `json:"tmpfs"`
}
type APIConfig struct {
DatabaseName string `json:"database_name"`
SingleThread bool `json:"single_thread,default=true"`
Addr string `json:"addr"`
Token string `json:"token"`
FfmpegThreads int64 `json:"ffmpeg_threads"`
FfmpegConfigList []FfmpegConfig `json:"ffmpeg_config_list"`
}
type FfmpegConfigList struct {
FfmpegConfigList []FfmpegConfig `json:"ffmpeg_config_list"`
}
type FfmpegConfig struct {
Name string `json:"name"`
Args string `json:"args"`
Format string `json:"format"`
}
type TmpfsConfig struct {
FileLifeTime int64 `json:"file_life_time"`
CleanerInternal int64 `json:"cleaner_internal"`
Root string `json:"root"`
}
// Constructors for Config
func NewAPIConfig() APIConfig {
apiConfig := APIConfig{}
return apiConfig
}
func NewTmpfsConfig() *TmpfsConfig {
config := &TmpfsConfig{}
return config
}

View File

@@ -2,6 +2,7 @@ package tmpfs
import (
"log"
"msw-open-music/pkg/commonconfig"
"os"
"path/filepath"
"strconv"
@@ -10,14 +11,14 @@ import (
)
type Tmpfs struct {
record map[string]int64
Config TmpfsConfig
wg sync.WaitGroup
record map[string]int64
Config commonconfig.TmpfsConfig
wg sync.WaitGroup
recordLocks map[string]*sync.Mutex
}
func (tmpfs *Tmpfs) GetObjFilePath(id int64, configName string) (string) {
return filepath.Join(tmpfs.Config.Root, strconv.FormatInt(id, 10) + "." + configName + ".webm")
func (tmpfs *Tmpfs) GetObjFilePath(id int64, ffmpegConfig commonconfig.FfmpegConfig) string {
return filepath.Join(tmpfs.Config.Root, strconv.FormatInt(id, 10)+"."+ffmpegConfig.Name+"."+ffmpegConfig.Format)
}
func (tmpfs *Tmpfs) GetLock(filename string) *sync.Mutex {
@@ -35,21 +36,10 @@ func (tmpfs *Tmpfs) Unlock(filename string) {
tmpfs.GetLock(filename).Unlock()
}
type TmpfsConfig struct {
FileLifeTime int64 `json:"file_life_time"`
CleanerInternal int64 `json:"cleaner_internal"`
Root string `json:"root"`
}
func NewTmpfsConfig() (*TmpfsConfig) {
config := &TmpfsConfig{}
return config
}
func NewTmpfs(config TmpfsConfig) *Tmpfs {
func NewTmpfs(config commonconfig.TmpfsConfig) *Tmpfs {
tmpfs := &Tmpfs{
record: make(map[string]int64),
Config: config,
record: make(map[string]int64),
Config: config,
recordLocks: make(map[string]*sync.Mutex),
}
tmpfs.wg.Add(1)
@@ -61,7 +51,7 @@ func (tmpfs *Tmpfs) Record(filename string) {
tmpfs.record[filename] = time.Now().Unix()
}
func (tmpfs *Tmpfs) Exits(filename string) (bool) {
func (tmpfs *Tmpfs) Exits(filename string) bool {
_, ok := tmpfs.record[filename]
return ok
}
@@ -77,7 +67,7 @@ func (tmpfs *Tmpfs) Cleaner() {
lock.Unlock()
continue
}
if now - recordTime > tmpfs.Config.FileLifeTime {
if now-recordTime > tmpfs.Config.FileLifeTime {
err = os.Remove(path)
if err != nil {
log.Println("[tmpfs] Failed to remove file", err)