mirror of
https://mau.dev/mautrix/go.git
synced 2026-03-14 14:25:53 +01:00
Merge pull request #58 from mautrix/ffmpeg-utils
util: add ffmpeg utils for converting bytes and files
This commit is contained in:
commit
d2f80cb1e4
2 changed files with 144 additions and 0 deletions
95
util/ffmpeg/convert.go
Normal file
95
util/ffmpeg/convert.go
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) 2022 Sumner Evans
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package ffmpeg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
"maunium.net/go/mautrix/util"
|
||||
)
|
||||
|
||||
var ffmpegDefaultParams = []string{"-hide_banner", "-loglevel", "warning"}
|
||||
|
||||
// Convert a media file on the disk using ffmpeg.
|
||||
//
|
||||
// Args:
|
||||
// * inputFile: The full path to the file.
|
||||
// * outputExtension: The extension that the output file should be.
|
||||
// * inputArgs: Arguments to tell ffmpeg how to parse the input file.
|
||||
// * outputArgs: Arguments to tell ffmpeg how to convert the file to reach the wanted output.
|
||||
// * removeInput: Whether the input file should be removed after converting.
|
||||
//
|
||||
// Returns: the path to the converted file.
|
||||
func ConvertPath(inputFile string, outputExtension string, inputArgs []string, outputArgs []string, removeInput bool) (string, error) {
|
||||
outputFilename := strings.TrimSuffix(inputFile, filepath.Ext(inputFile)) + "." + outputExtension
|
||||
|
||||
args := []string{}
|
||||
args = append(args, ffmpegDefaultParams...)
|
||||
args = append(args, inputArgs...)
|
||||
args = append(args, "-i", inputFile)
|
||||
args = append(args, outputArgs...)
|
||||
args = append(args, outputFilename)
|
||||
|
||||
log.Info(args)
|
||||
|
||||
cmd := exec.Command("ffmpeg", args...)
|
||||
vcLog := log.Sub("ffmpeg").Writer(log.LevelWarn)
|
||||
cmd.Stdout = vcLog
|
||||
cmd.Stderr = vcLog
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ffmpeg error: %+v", err)
|
||||
}
|
||||
|
||||
if removeInput {
|
||||
os.Remove(inputFile)
|
||||
}
|
||||
|
||||
return outputFilename, nil
|
||||
}
|
||||
|
||||
// Convert media data using ffmpeg.
|
||||
//
|
||||
// Args:
|
||||
// * data: The media data to convert
|
||||
// * outputExtension: The extension that the output file should be.
|
||||
// * inputArgs: Arguments to tell ffmpeg how to parse the input file.
|
||||
// * outputArgs: Arguments to tell ffmpeg how to convert the file to reach the wanted output.
|
||||
// * inputMime: The mimetype of the input data.
|
||||
//
|
||||
// Returns: the converted data
|
||||
func ConvertBytes(data []byte, outputExtension string, inputArgs []string, outputArgs []string, inputMime string) ([]byte, error) {
|
||||
tempdir, err := ioutil.TempDir("", "mautrix_ffmpeg_*")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(tempdir)
|
||||
inputFileName := fmt.Sprintf("%s/input.%s", tempdir, util.ExtensionFromMimetype(inputMime))
|
||||
|
||||
inputFile, err := os.OpenFile(inputFileName, os.O_EXCL|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open input file: %w", err)
|
||||
}
|
||||
_, err = inputFile.Write(data)
|
||||
if err != nil {
|
||||
inputFile.Close()
|
||||
return nil, fmt.Errorf("failed to write data to input file: %w", err)
|
||||
}
|
||||
inputFile.Close()
|
||||
|
||||
outputPath, err := ConvertPath(inputFileName, outputExtension, inputArgs, outputArgs, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.ReadFile(outputPath)
|
||||
}
|
||||
49
util/mimetypes.go
Normal file
49
util/mimetypes.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) 2022 Sumner Evans
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MimeExtensionSanityOverrides includes extensions for various common mimetypes.
|
||||
//
|
||||
// This is necessary because sometimes the OS mimetype database and Go interact in weird ways,
|
||||
// which causes very obscure extensions to be first in the array for common mimetypes
|
||||
// (e.g. image/jpeg -> .jpe, text/plain -> ,v).
|
||||
var MimeExtensionSanityOverrides = map[string]string{
|
||||
"image/png": ".png",
|
||||
"image/webp": ".webp",
|
||||
"image/jpeg": ".jpg",
|
||||
"image/tiff": ".tiff",
|
||||
"image/heif": ".heic",
|
||||
"image/heic": ".heic",
|
||||
|
||||
"audio/mpeg": ".mp3",
|
||||
"audio/ogg": ".ogg",
|
||||
"audio/webm": ".webm",
|
||||
"video/mp4": ".mp4",
|
||||
"video/mpeg": ".mpeg",
|
||||
"video/webm": ".webm",
|
||||
|
||||
"text/plain": ".txt",
|
||||
"text/html": ".html",
|
||||
|
||||
"application/xml": ".xml",
|
||||
}
|
||||
|
||||
func ExtensionFromMimetype(mimetype string) string {
|
||||
ext, ok := MimeExtensionSanityOverrides[strings.Split(mimetype, ";")[0]]
|
||||
if !ok {
|
||||
exts, _ := mime.ExtensionsByType(mimetype)
|
||||
if len(exts) > 0 {
|
||||
ext = exts[0]
|
||||
}
|
||||
}
|
||||
return ext
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue