package media import ( "bytes" "context" "fmt" "io" "os/exec" ) type ffmpegReader struct { io.ReadCloser cmd *exec.Cmd stdErrBuf *bytes.Buffer } func newFfmpegReader(ctx context.Context, input io.Reader, arg ...string) (*ffmpegReader, error) { var stdErr bytes.Buffer cmd := exec.CommandContext(ctx, "ffmpeg", arg...) cmd.Stdin = input cmd.Stderr = &stdErr r, err := cmd.StdoutPipe() if err != nil { return nil, fmt.Errorf("error creating pipe: %v", err) } if err := cmd.Start(); err != nil { return nil, fmt.Errorf("error starting ffmpeg: %v, output: %s", err, stdErr.String()) } return &ffmpegReader{ReadCloser: r, cmd: cmd, stdErrBuf: &stdErr}, nil } func (r *ffmpegReader) Cancel() error { if err := r.cmd.Process.Kill(); err != nil { return fmt.Errorf("error killing ffmpeg process: %v", err) } return nil } func (r *ffmpegReader) Close() error { state, err := r.cmd.Process.Wait() if err != nil { return fmt.Errorf("error returned from ffmpeg process: %v", err) } if state.ExitCode() != 0 { return fmt.Errorf("non-zero status %d returned from ffmpeg process, output: %s", state.ExitCode(), r.stdErrBuf.String()) } return nil }