Skip to content

Commit

Permalink
lottie: improve interface
Browse files Browse the repository at this point in the history
  • Loading branch information
tulir committed Sep 25, 2024
1 parent 1ba4f62 commit 1734c3c
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 34 deletions.
22 changes: 17 additions & 5 deletions ffmpeg/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func SetPath(path string) {
ffmpegPath = path
}

// ConvertPath converts a media file on the disk using ffmpeg.
// ConvertPath converts a media file on the disk using ffmpeg and auto-generates the output file name.
//
// Args:
// * inputFile: The full path to the file.
Expand All @@ -53,6 +53,18 @@ func SetPath(path string) {
// Returns: the path to the converted file.
func ConvertPath(ctx context.Context, inputFile string, outputExtension string, inputArgs []string, outputArgs []string, removeInput bool) (string, error) {
outputFilename := strings.TrimSuffix(strings.TrimSuffix(inputFile, filepath.Ext(inputFile)), "*") + outputExtension
return outputFilename, ConvertPathWithDestination(ctx, inputFile, outputFilename, inputArgs, outputArgs, removeInput)
}

// ConvertPathWithDestination converts a media file on the disk using ffmpeg and saves the result to the provided file name.
//
// Args:
// * inputFile: The full path to the file.
// * outputFile: The full path to the output file. Must include the appropriate extension so ffmpeg knows what to convert to.
// * 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.
func ConvertPathWithDestination(ctx context.Context, inputFile string, outputFile string, inputArgs []string, outputArgs []string, removeInput bool) error {
if removeInput {
defer func() {
_ = os.Remove(inputFile)
Expand All @@ -64,7 +76,7 @@ func ConvertPath(ctx context.Context, inputFile string, outputExtension string,
args = append(args, inputArgs...)
args = append(args, "-i", inputFile)
args = append(args, outputArgs...)
args = append(args, outputFilename)
args = append(args, outputFile)

cmd := exec.CommandContext(ctx, ffmpegPath, args...)
ctxLog := zerolog.Ctx(ctx).With().Str("command", "ffmpeg").Logger()
Expand All @@ -73,11 +85,11 @@ func ConvertPath(ctx context.Context, inputFile string, outputExtension string,
cmd.Stderr = logWriter
err := cmd.Run()
if err != nil {
_ = os.Remove(outputFilename)
return "", fmt.Errorf("ffmpeg error: %w", err)
_ = os.Remove(outputFile)
return fmt.Errorf("ffmpeg error: %w", err)
}

return outputFilename, nil
return nil
}

// ConvertBytes converts media data using ffmpeg.
Expand Down
46 changes: 17 additions & 29 deletions lottie/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
package lottie

import (
"bytes"
"context"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strconv"

"github.com/rs/zerolog"
Expand Down Expand Up @@ -83,42 +83,40 @@ func Convert(ctx context.Context, input io.Reader, outputFilename string, output
return nil
}

// FfmpegConvert converts lottie data to a video or image using ffmpeg.
// FFmpegConvert converts lottie data to a video or image using ffmpeg.
//
// This function should only be called if [ffmpeg.Supported] returns true.
//
// Args:
// - input: an io.Reader containing the lottie data to convert.
// - target: the output format. Can be one of: webm, webp.
// - outputFile: the filename to write the output to. Must have .webp or .webm extension.
// - width: the width of the output video or image.
// - height: the height of the output video or image.
// - fps: the framerate of the output video.
//
// Returns: the converted data as a *bytes.Buffer, the mimetype of the output,
// and the thumbnail data as a PNG.
func FfmpegConvert(ctx context.Context, input io.Reader, target string, width, height, fps int) (*bytes.Buffer, string, []byte, error) {
func FFmpegConvert(ctx context.Context, input io.Reader, outputFile string, width, height, fps int) (thumbnailData []byte, err error) {
if !ffmpeg.Supported() {
panic("ffmpeg is not available")
return nil, fmt.Errorf("ffmpeg is not available")
}

var tmpDir string
tmpDir, err := os.MkdirTemp("", "lottieconvert")
if err != nil {
return nil, "", nil, err
return
}
defer os.RemoveAll(tmpDir)

err = Convert(ctx, input, tmpDir+"/out_", nil, "pngs", width, height, strconv.Itoa(fps))
if err != nil {
return nil, "", nil, err
return
}

files, err := os.ReadDir(tmpDir)
if err != nil {
return nil, "", nil, err
return
}

var thumbnailData []byte
var firstFrameName string
for _, file := range files {
if firstFrameName == "" || file.Name() < firstFrameName {
Expand All @@ -127,36 +125,26 @@ func FfmpegConvert(ctx context.Context, input io.Reader, target string, width, h
}
thumbnailData, err = os.ReadFile(fmt.Sprintf("%s/%s", tmpDir, firstFrameName))
if err != nil {
return nil, "", nil, err
return
}

var mimeType string
var outputArgs []string
switch target {
case "webm":
mimeType = "video/webm"
switch filepath.Ext(outputFile) {
case ".webm":
outputArgs = []string{"-c:v", "libvpx-vp9", "-pix_fmt", "yuva420p", "-f", "webm"}
case "webp":
mimeType = "image/webp"
case ".webp":
outputArgs = []string{"-c:v", "libwebp_anim", "-pix_fmt", "yuva420p", "-f", "webp"}
default:
panic(fmt.Sprintf("unsupported target %s", target))
err = fmt.Errorf("unsupported extension %s", filepath.Ext(outputFile))
return
}
convertedFilename, err := ffmpeg.ConvertPath(
err = ffmpeg.ConvertPathWithDestination(
ctx,
tmpDir+"/out_*.png",
"",
outputFile,
[]string{"-framerate", strconv.Itoa(fps), "-pattern_type", "glob"},
outputArgs,
false,
)
if err != nil {
return nil, "", nil, err
} else if file, err := os.Open(convertedFilename); err != nil {
return nil, "", nil, err
} else {
var buf bytes.Buffer
_, err = io.Copy(&buf, file)
return &buf, mimeType, thumbnailData, err
}
return
}

0 comments on commit 1734c3c

Please sign in to comment.