92 lines
1.6 KiB
Go
92 lines
1.6 KiB
Go
|
package ffmpeg
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"log"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"strconv"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"dndmusicbot/ytdl"
|
||
|
)
|
||
|
|
||
|
type FFmpeg struct {
|
||
|
Out *bytes.Buffer
|
||
|
Cmd *exec.Cmd
|
||
|
Started bool
|
||
|
Cancel context.CancelFunc
|
||
|
Len time.Duration
|
||
|
Title string
|
||
|
Channel string
|
||
|
PMutex *sync.RWMutex
|
||
|
ProcessState *os.ProcessState
|
||
|
err chan error
|
||
|
}
|
||
|
|
||
|
func NewFFmpeg(uri string, sampleRate int, channels int) (ff *FFmpeg, err error) {
|
||
|
var yt *ytdl.YTdl
|
||
|
for {
|
||
|
yt, err = ytdl.NewYTdl(uri)
|
||
|
if err != nil {
|
||
|
log.Println("Something went wrong, trying again.", err)
|
||
|
continue
|
||
|
}
|
||
|
if yt.Url != "" {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
log.Println("Something went wrong, trying again.")
|
||
|
time.Sleep(500 * time.Millisecond)
|
||
|
}
|
||
|
|
||
|
ff = new(FFmpeg)
|
||
|
ff.PMutex = &sync.RWMutex{}
|
||
|
ff.Len = yt.Len
|
||
|
ff.Title = yt.Title
|
||
|
ff.Channel = yt.Channel
|
||
|
ctx, cancel := context.WithCancel(context.Background())
|
||
|
ff.Cancel = cancel
|
||
|
|
||
|
ff.Cmd = exec.CommandContext(
|
||
|
ctx,
|
||
|
"ffmpeg",
|
||
|
"-i", yt.Url,
|
||
|
"-f", "s16le",
|
||
|
"-v", "error",
|
||
|
// "-stats",
|
||
|
//"-progress", "pipe:2",
|
||
|
"-ar", strconv.Itoa(sampleRate),
|
||
|
"-ac", strconv.Itoa(channels),
|
||
|
"-af", "loudnorm=I=-16:LRA=11:TP=-1.5",
|
||
|
"pipe:1",
|
||
|
)
|
||
|
|
||
|
ff.Cmd.Stderr = os.Stdin
|
||
|
|
||
|
// FFmpeg requires a certain buffer size to start writing. This seems to be enough?
|
||
|
// This will grow big enough to fit the whole song.
|
||
|
ff.Out = bytes.NewBuffer(make([]byte, 43920))
|
||
|
ff.Cmd.Stdout = ff.Out
|
||
|
|
||
|
ff.Start()
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (ff *FFmpeg) Start() {
|
||
|
go func() {
|
||
|
ff.Cmd.Start()
|
||
|
ff.err <- ff.Cmd.Wait()
|
||
|
}()
|
||
|
|
||
|
ff.Started = true
|
||
|
}
|
||
|
|
||
|
func (ff *FFmpeg) Close() error {
|
||
|
ff.Cancel()
|
||
|
return nil
|
||
|
}
|