Skip to content

Instantly share code, notes, and snippets.

@wjkoh
Last active September 22, 2025 18:57
Show Gist options
  • Select an option

  • Save wjkoh/eb49409a2bce7ef117fec3ff4a3d24a0 to your computer and use it in GitHub Desktop.

Select an option

Save wjkoh/eb49409a2bce7ef117fec3ff4a3d24a0 to your computer and use it in GitHub Desktop.
Go: How to Cut or Chunk an Audio File using FFmpeg
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"os/exec"
"strings"
"time"
)
type audioCutter struct{}
func (s *audioCutter) Duration(ctx context.Context, filename string) (time.Duration, error) {
f, err := s.format(ctx, filename)
if err != nil {
return time.Duration(0), err
}
return time.ParseDuration(f.Duration + "s")
}
func (s *audioCutter) Cut(
ctx context.Context, w io.Writer, filename string, start time.Duration, end time.Duration,
) error {
f, err := s.format(ctx, filename)
if err != nil {
return err
}
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// -ss should be after -i. Check out https://trac.ffmpeg.org/wiki/Seeking#Cutting
cmd := exec.CommandContext(
ctx,
"ffmpeg",
"-f", f.FormatName,
"-i", filename,
"-ss", FormatHMS(start),
"-to", FormatHMS(end),
"-codec", "copy",
"-f", f.FormatName,
"-",
)
cmd.Stdout = w
var stderr strings.Builder
cmd.Stderr = &stderr
if err := cmd.Start(); err != nil {
slog.Debug("ffmpeg", "err", err, slog.String("stderr", stderr.String()))
return err
}
if err := cmd.Wait(); err != nil {
slog.Debug("ffmpeg", "err", err, slog.String("stderr", stderr.String()))
return err
}
return nil
}
type format struct {
FormatName string `json:"format_name"`
Duration string `json:"duration"`
}
func (s *audioCutter) format(ctx context.Context, filename string) (*format, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
cmd := exec.CommandContext(ctx, "ffprobe", "-i", filename, "-show_format", "-output_format", "json")
var stderr strings.Builder
cmd.Stderr = &stderr
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
slog.Debug("ffmpeg", "err", err, slog.String("stderr", stderr.String()))
return nil, err
}
var output struct {
Format format `json:"format"`
}
if err := json.NewDecoder(stdout).Decode(&output); err != nil {
return nil, err
}
if err := cmd.Wait(); err != nil {
slog.Debug("ffmpeg", "err", err, slog.String("stderr", stderr.String()))
return nil, err
}
return &output.Format, nil
}
func FormatHMS(d time.Duration) string {
m, s := (d%time.Hour)/time.Minute, d%time.Minute/time.Second
if hours := d / time.Hour; hours > 0 {
return fmt.Sprintf("%02d:%02d:%02d", hours, m, s)
}
return fmt.Sprintf("%02d:%02d", m, s)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment