Files
llink/go/internal/media/helpers.go
T
Arjun Patel 563c91e7d5 infra: add logging wrapping
Resolves issues with gcp cloud logging quirks such as field names
2026-05-27 15:49:27 -07:00

105 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package media
import (
"bytes"
"context"
"errors"
"os"
"os/exec"
"strings"
"github.com/flowy-live/llink/internal/utils/flog"
)
func IsIOSPlayableMime(mime string) bool {
switch mime {
case "video/mp4", "video/quicktime", "audio/mp4", "audio/aac", "audio/x-m4a", "audio/mpeg":
return true
}
return false
}
func IsAudio(mime string) bool {
return strings.HasPrefix(mime, "audio/")
}
type TranscodeInput struct {
SourceURL string
MimeType string
}
type TranscodeOutput struct {
TempLocalFilePath string
OutputMimeType string
OutputExt string // e.g. ".m4a" or ".mp4"
}
var (
ErrInvalidInput error = errors.New("invalid input")
)
// TranscodeToMp4 writes the result to a temp file; caller is responsible
// for deleting TempLocalFilePath.
func TranscodeToMp4(ctx context.Context, input TranscodeInput) (*TranscodeOutput, error) {
if input.SourceURL == "" || input.MimeType == "" {
return nil, ErrInvalidInput
}
isAudio := IsAudio(input.MimeType)
var outputExt, outputMime string
if isAudio {
outputExt = ".m4a"
outputMime = "audio/mp4"
} else {
outputExt = ".mp4"
outputMime = "video/mp4"
}
tmp, err := os.CreateTemp("", "transcode-*"+outputExt)
if err != nil {
flog.Error("transcode: failed to create temp file", "error", err)
return nil, err
}
tmpPath := tmp.Name()
tmp.Close()
var args []string
if isAudio {
args = []string{
"-y", "-i", input.SourceURL,
"-vn",
"-c:a", "aac", "-b:a", "128k",
"-movflags", "+faststart",
tmpPath,
}
} else {
// 1440p4K screen recordings + libx264's lookahead buffers can OOM the
// worker. Bound parallelism/lookahead and downscale to 1080p; the
// original WebM stays in GCS untouched.
args = []string{
"-y", "-i", input.SourceURL,
"-vf", "scale='min(1920,iw)':-2:flags=lanczos",
"-c:v", "libx264", "-preset", "veryfast", "-crf", "23",
"-pix_fmt", "yuv420p", "-profile:v", "baseline", "-level", "3.1",
"-x264-params", "rc-lookahead=20:ref=2",
"-threads", "2", "-filter_threads", "2",
"-c:a", "aac", "-b:a", "128k",
"-movflags", "+faststart",
tmpPath,
}
}
cmd := exec.CommandContext(ctx, "ffmpeg", args...)
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return nil, errors.Join(err, errors.New(stderr.String()))
}
return &TranscodeOutput{
TempLocalFilePath: tmpPath,
OutputMimeType: outputMime,
OutputExt: outputExt,
}, nil
}