Add migrating to ffmpeg 6

This commit is contained in:
Ingo Oppermann
2024-02-09 17:15:41 +01:00
parent 5a4d00f969
commit 00c5ad3883

View File

@@ -4,6 +4,9 @@ import (
"fmt" "fmt"
"os" "os"
"regexp" "regexp"
"strconv"
"strings"
"time"
cfgstore "github.com/datarhei/core/v16/config/store" cfgstore "github.com/datarhei/core/v16/config/store"
cfgvars "github.com/datarhei/core/v16/config/vars" cfgvars "github.com/datarhei/core/v16/config/vars"
@@ -11,6 +14,7 @@ import (
"github.com/datarhei/core/v16/io/file" "github.com/datarhei/core/v16/io/file"
"github.com/datarhei/core/v16/io/fs" "github.com/datarhei/core/v16/io/fs"
"github.com/datarhei/core/v16/log" "github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/restream/app"
"github.com/datarhei/core/v16/restream/store" "github.com/datarhei/core/v16/restream/store"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
@@ -18,10 +22,7 @@ import (
) )
func main() { func main() {
logger := log.New("Migration").WithOutput(log.NewConsoleWriter(os.Stderr, log.Linfo, true)).WithFields(log.Fields{ logger := log.New("Migration").WithOutput(log.NewConsoleWriter(os.Stderr, log.Linfo, true))
"from": "ffmpeg4",
"to": "ffmpeg5",
})
configfile := cfgstore.Location(os.Getenv("CORE_CONFIGFILE")) configfile := cfgstore.Location(os.Getenv("CORE_CONFIGFILE"))
@@ -34,6 +35,7 @@ func main() {
} }
if err := doMigration(logger, configstore); err != nil { if err := doMigration(logger, configstore); err != nil {
logger.Error().WithError(err).Log("Migration failed")
os.Exit(1) os.Exit(1)
} }
} }
@@ -82,17 +84,6 @@ func doMigration(logger log.Logger, configstore cfgstore.Store) error {
return fmt.Errorf("parsing FFmpeg version failed: %w", err) return fmt.Errorf("parsing FFmpeg version failed: %w", err)
} }
// The current FFmpeg version is 4. Nothing to do.
if version.Major() == 4 {
return nil
}
if version.Major() != 5 {
err := fmt.Errorf("unknown FFmpeg version found: %d", version.Major())
logger.Error().WithError(err).Log("Unsupported FFmpeg version found")
return fmt.Errorf("unsupported FFmpeg version found: %w", err)
}
// Check if there's a DB file // Check if there's a DB file
dbFilepath := cfg.DB.Dir + "/db.json" dbFilepath := cfg.DB.Dir + "/db.json"
@@ -102,29 +93,20 @@ func doMigration(logger log.Logger, configstore cfgstore.Store) error {
return nil return nil
} }
// Check if we already have a backup
backupFilepath := cfg.DB.Dir + "/db_ff4.json"
if _, err = os.Stat(backupFilepath); err == nil {
// Yes, we have a backup. The migration already happened
logger.Info().WithField("backup", backupFilepath).Log("Migration already done")
return nil
}
// Create a backup
if err := file.Copy(dbFilepath, backupFilepath); err != nil {
logger.Error().WithError(err).Log("Creating backup file failed")
return fmt.Errorf("creating backup file failed: %w", err)
}
logger.Info().WithField("backup", backupFilepath).Log("Backup created")
// Load the existing DB // Load the existing DB
diskfs, err := fs.NewDiskFilesystem(fs.DiskConfig{})
if err != nil {
logger.Error().WithError(err).Log("Accessing disk filesystem failed")
return fmt.Errorf("accessing disk filesystem failed: %w", err)
}
datastore, err := store.NewJSON(store.JSONConfig{ datastore, err := store.NewJSON(store.JSONConfig{
Filepath: cfg.DB.Dir + "/db.json", Filesystem: diskfs,
Filepath: cfg.DB.Dir + "/db.json",
}) })
if err != nil { if err != nil {
return err logger.Error().WithField("db", dbFilepath).WithError(err).Log("Creating JSON store failed")
return fmt.Errorf("creating JSON store failed: %w", err)
} }
data, err := datastore.Load() data, err := datastore.Load()
@@ -133,17 +115,102 @@ func doMigration(logger log.Logger, configstore cfgstore.Store) error {
return fmt.Errorf("loading database failed: %w", err) return fmt.Errorf("loading database failed: %w", err)
} }
// Migrate processes
logger.Info().Log("Migrating processes ...") logger.Info().Log("Migrating processes ...")
// Migrate the processes to version 5 migrated := false
// Only this happens:
// - for RTSP inputs, replace -stimeout with -timeout
reRTSP := regexp.MustCompile(`^rtsps?://`)
for id, p := range data.Process { for id, p := range data.Process {
logger.Info().WithField("processid", p.ID).Log("") ok, err := migrateProcessConfig(logger.WithField("processid", p.ID), p.Config, version.String())
if err != nil {
logger.Info().WithField("processid", p.ID).WithError(err).Log("Migrating process failed")
return fmt.Errorf("migrating process failed: %w", err)
}
for index, input := range p.Config.Input { data.Process[id] = p
if ok {
migrated = true
}
}
logger.Info().Log("Migrating processes done")
if migrated {
// Create backup if something has been changed.
backupFilepath := cfg.DB.Dir + "/db." + strconv.FormatInt(time.Now().UnixMilli(), 10) + ".json"
if _, err = os.Stat(backupFilepath); err == nil {
// Yes, we have a backup. The migration already happened
logger.Info().WithField("backup", backupFilepath).Log("Migration already done")
return nil
}
// Create a backup
if err := file.Copy(dbFilepath, backupFilepath); err != nil {
logger.Error().WithError(err).Log("Creating backup file failed")
return fmt.Errorf("creating backup file failed: %w", err)
}
logger.Info().WithField("backup", backupFilepath).Log("Backup created")
// Store the modified DB
if err := datastore.Store(data); err != nil {
logger.Error().WithError(err).Log("Storing database failed")
return fmt.Errorf("storing database failed: %w", err)
}
}
logger.Info().Log("Completed")
return nil
}
func migrateProcessConfig(logger log.Logger, config *app.Config, version string) (bool, error) {
migrated := false
vtarget, err := semver.NewVersion(version)
if err != nil {
logger.Error().WithError(err).Log("Parsing target FFmpeg version failed")
return false, fmt.Errorf("parsing target FFmpeg version failed: %w", err)
}
targetmajor := vtarget.Major()
currentmajor := uint64(4)
if len(config.FFVersion) != 0 {
vcurrent, err := semver.NewVersion(strings.TrimPrefix(config.FFVersion, "^"))
if err != nil {
logger.Error().WithError(err).Log("Parsing current FFmpeg version failed")
return false, fmt.Errorf("parsing current FFmpeg version failed: %w", err)
}
currentmajor = vcurrent.Major()
}
if currentmajor < 4 {
err := fmt.Errorf("unknown FFmpeg version found: %d", currentmajor)
logger.Error().WithError(err).Log("Unsupported FFmpeg version")
return false, fmt.Errorf("unsupported FFmpeg version: %w", err)
}
if targetmajor > 6 {
err := fmt.Errorf("unknown FFmpeg version found: %d", targetmajor)
logger.Error().WithError(err).Log("Unsupported FFmpeg version")
return false, fmt.Errorf("unsupported FFmpeg version: %w", err)
}
if currentmajor != targetmajor {
migrated = true
}
if currentmajor == 4 && targetmajor > 4 {
// Migration from version 4 to version 5
// Only this happens:
// - for RTSP inputs, replace -stimeout with -timeout
reRTSP := regexp.MustCompile(`^rtsps?://`)
for index, input := range config.Input {
if !reRTSP.MatchString(input.Address) { if !reRTSP.MatchString(input.Address) {
continue continue
} }
@@ -156,21 +223,27 @@ func doMigration(logger log.Logger, configstore cfgstore.Store) error {
input.Options[i] = "-timeout" input.Options[i] = "-timeout"
} }
p.Config.Input[index] = input config.Input[index] = input
} }
p.Config.FFVersion = version.String()
data.Process[id] = p currentmajor = 5
} }
logger.Info().Log("Migrating processes done") if currentmajor == 5 && targetmajor > 5 {
// Migration from version 5 to version 6
// Nothing happens
// Store the modified DB currentmajor = 6
if err := datastore.Store(data); err != nil {
logger.Error().WithError(err).Log("Storing database failed")
return fmt.Errorf("storing database failed: %w", err)
} }
logger.Info().Log("Completed") if migrated {
logger.Info().WithFields(log.Fields{
"from": config.FFVersion,
"to": "^" + version,
}).Log("Migrated")
}
return nil config.FFVersion = "^" + version
return migrated, nil
} }