Changes to support updating the ffmpeg path from the settings tab
This commit is contained in:
@@ -252,11 +252,11 @@ func serveContent(w http.ResponseWriter, r *http.Request, tv *soapcalls.TVPayloa
|
||||
|
||||
switch f := mf.(type) {
|
||||
case osFileType:
|
||||
serveContentCustomType(w, r, mediaType, transcode, seek, f, ff)
|
||||
serveContentCustomType(w, r, tv, mediaType, transcode, seek, f, ff)
|
||||
case []byte:
|
||||
serveContentBytes(w, r, mediaType, f)
|
||||
case io.ReadCloser:
|
||||
serveContentReadClose(w, r, mediaType, transcode, f, ff)
|
||||
serveContentReadClose(w, r, tv, mediaType, transcode, f, ff)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
@@ -279,7 +279,7 @@ func serveContentBytes(w http.ResponseWriter, r *http.Request, mediaType string,
|
||||
http.ServeContent(w, r, name, time.Now(), bReader)
|
||||
}
|
||||
|
||||
func serveContentReadClose(w http.ResponseWriter, r *http.Request, mediaType string, transcode bool, f io.ReadCloser, ff *exec.Cmd) {
|
||||
func serveContentReadClose(w http.ResponseWriter, r *http.Request, tv *soapcalls.TVPayload, mediaType string, transcode bool, f io.ReadCloser, ff *exec.Cmd) {
|
||||
if r.Header.Get("getcontentFeatures.dlna.org") == "1" {
|
||||
contentFeatures, err := utils.BuildContentFeatures(mediaType, "00", transcode)
|
||||
if err != nil {
|
||||
@@ -293,7 +293,7 @@ func serveContentReadClose(w http.ResponseWriter, r *http.Request, mediaType str
|
||||
// Since we're dealing with an io.Reader we can't
|
||||
// allow any HEAD requests that some DMRs trigger.
|
||||
if transcode && r.Method == http.MethodGet && strings.Contains(mediaType, "video") {
|
||||
_ = utils.ServeTranscodedStream(w, f, ff)
|
||||
_ = utils.ServeTranscodedStream(w, f, ff, tv.FFmpegPath)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ func serveContentReadClose(w http.ResponseWriter, r *http.Request, mediaType str
|
||||
}
|
||||
}
|
||||
|
||||
func serveContentCustomType(w http.ResponseWriter, r *http.Request, mediaType string, transcode, seek bool, f osFileType, ff *exec.Cmd) {
|
||||
func serveContentCustomType(w http.ResponseWriter, r *http.Request, tv *soapcalls.TVPayload, mediaType string, transcode, seek bool, f osFileType, ff *exec.Cmd) {
|
||||
if r.Header.Get("getcontentFeatures.dlna.org") == "1" {
|
||||
seekflag := "00"
|
||||
if seek {
|
||||
@@ -330,7 +330,7 @@ func serveContentCustomType(w http.ResponseWriter, r *http.Request, mediaType st
|
||||
if f.path != "" {
|
||||
input = f.path
|
||||
}
|
||||
_ = utils.ServeTranscodedStream(w, input, ff)
|
||||
_ = utils.ServeTranscodedStream(w, input, ff, tv.FFmpegPath)
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -100,8 +100,7 @@ func selectMediaFile(screen *NewScreen, f fyne.URI) {
|
||||
|
||||
screen.MediaText.Refresh()
|
||||
|
||||
subs, err := utils.GetSubs(absMediaFile)
|
||||
check(screen, err)
|
||||
subs, err := utils.GetSubs(screen.ffmpegPath, absMediaFile)
|
||||
if err != nil {
|
||||
screen.SelectInternalSubs.Options = []string{}
|
||||
screen.SelectInternalSubs.PlaceHolder = "No Embedded Subs"
|
||||
@@ -344,7 +343,7 @@ func playAction(screen *NewScreen) {
|
||||
if opt == screen.SelectInternalSubs.Selected {
|
||||
screen.PlayPause.Text = "Extracting Subtitles"
|
||||
screen.PlayPause.Refresh()
|
||||
tempSubsPath, err := utils.ExtractSub(n, screen.mediafile)
|
||||
tempSubsPath, err := utils.ExtractSub(screen.ffmpegPath, n, screen.mediafile)
|
||||
screen.PlayPause.Text = "Play"
|
||||
screen.PlayPause.Refresh()
|
||||
if err != nil {
|
||||
@@ -373,6 +372,7 @@ func playAction(screen *NewScreen) {
|
||||
Transcode: screen.Transcode,
|
||||
Seekable: isSeek,
|
||||
LogOutput: screen.Debug,
|
||||
FFmpegPath: screen.ffmpegPath,
|
||||
}
|
||||
|
||||
screen.httpserver = httphandlers.NewServer(whereToListen)
|
||||
|
@@ -21,6 +21,7 @@ import (
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/alexballas/go2tv/httphandlers"
|
||||
"github.com/alexballas/go2tv/soapcalls"
|
||||
"github.com/alexballas/go2tv/soapcalls/utils"
|
||||
)
|
||||
|
||||
// NewScreen .
|
||||
@@ -41,6 +42,7 @@ type NewScreen struct {
|
||||
SubsText *widget.Entry
|
||||
CustomSubsCheck *widget.Check
|
||||
NextMediaCheck *widget.Check
|
||||
TranscodeCheckBox *widget.Check
|
||||
Stop *widget.Button
|
||||
DeviceList *deviceList
|
||||
httpserver *httphandlers.HTTPserver
|
||||
@@ -60,6 +62,7 @@ type NewScreen struct {
|
||||
renderingControlURL string
|
||||
connectionManagerURL string
|
||||
currentmfolder string
|
||||
ffmpegPath string
|
||||
mediaFormats []string
|
||||
muError sync.RWMutex
|
||||
mu sync.RWMutex
|
||||
@@ -113,6 +116,11 @@ func Start(ctx context.Context, s *NewScreen) {
|
||||
|
||||
s.Hotkeys = true
|
||||
tabs.OnSelected = func(t *container.TabItem) {
|
||||
s.TranscodeCheckBox.Enable()
|
||||
if err := utils.CheckFFmpeg(s.ffmpegPath); err != nil {
|
||||
s.TranscodeCheckBox.Disable()
|
||||
}
|
||||
|
||||
if t.Text == "Go2TV" {
|
||||
s.Hotkeys = true
|
||||
return
|
||||
@@ -120,6 +128,10 @@ func Start(ctx context.Context, s *NewScreen) {
|
||||
s.Hotkeys = false
|
||||
}
|
||||
|
||||
if err := utils.CheckFFmpeg(s.ffmpegPath); err != nil {
|
||||
s.TranscodeCheckBox.Disable()
|
||||
}
|
||||
|
||||
s.tabs = tabs
|
||||
|
||||
w.SetContent(tabs)
|
||||
|
@@ -8,7 +8,6 @@ import (
|
||||
"errors"
|
||||
"math"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -325,11 +324,6 @@ func mainWindow(s *NewScreen) fyne.CanvasObject {
|
||||
nextmedia := widget.NewCheck("Auto-Play Next File", func(b bool) {})
|
||||
transcode := widget.NewCheck("Transcode", func(b bool) {})
|
||||
|
||||
_, err := exec.LookPath("ffmpeg")
|
||||
if err != nil {
|
||||
transcode.Disable()
|
||||
}
|
||||
|
||||
mediafilelabel := canvas.NewText("File:", nil)
|
||||
subsfilelabel := canvas.NewText("Subtitles:", nil)
|
||||
devicelabel := canvas.NewText("Select Device:", nil)
|
||||
@@ -367,6 +361,7 @@ func mainWindow(s *NewScreen) fyne.CanvasObject {
|
||||
s.CurrentPos = curPos
|
||||
s.EndPos = endPos
|
||||
s.SelectInternalSubs = selectInternalSubs
|
||||
s.TranscodeCheckBox = transcode
|
||||
|
||||
curPos.Set("00:00:00")
|
||||
endPos.Set("00:00:00")
|
||||
@@ -476,7 +471,7 @@ func mainWindow(s *NewScreen) fyne.CanvasObject {
|
||||
s.MediaText.Disable()
|
||||
|
||||
if mediafileOld != "" {
|
||||
subs, err := utils.GetSubs(mediafileOld)
|
||||
subs, err := utils.GetSubs(s.ffmpegPath, mediafileOld)
|
||||
if err != nil {
|
||||
s.SelectInternalSubs.Options = []string{}
|
||||
s.SelectInternalSubs.PlaceHolder = "No Embedded Subs"
|
||||
@@ -531,7 +526,7 @@ func mainWindow(s *NewScreen) fyne.CanvasObject {
|
||||
}
|
||||
|
||||
if s.tvdata != nil && s.tvdata.CallbackURL != "" {
|
||||
_, err = queueNext(s, true)
|
||||
_, err := queueNext(s, true)
|
||||
if err != nil {
|
||||
stopAction(s)
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
package gui
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
@@ -43,6 +44,35 @@ func settingsWindow(s *NewScreen) fyne.CanvasObject {
|
||||
}
|
||||
}
|
||||
|
||||
ffmpegText := widget.NewLabel("ffmpeg Path")
|
||||
ffmpegTextEntry := widget.NewEntry()
|
||||
|
||||
ffmpegTextEntry.Text = func() string {
|
||||
if fyne.CurrentApp().Preferences().String("ffmpeg") != "" {
|
||||
return fyne.CurrentApp().Preferences().String("ffmpeg")
|
||||
}
|
||||
|
||||
os := runtime.GOOS
|
||||
switch os {
|
||||
case "windows":
|
||||
return "ffmpeg"
|
||||
case "linux":
|
||||
return "ffmpeg"
|
||||
case "darwin":
|
||||
return "/opt/homebrew/bin/ffmpeg"
|
||||
default:
|
||||
return "ffmpeg"
|
||||
}
|
||||
|
||||
}()
|
||||
ffmpegTextEntry.Refresh()
|
||||
s.ffmpegPath = ffmpegTextEntry.Text
|
||||
|
||||
ffmpegTextEntry.OnChanged = func(update string) {
|
||||
s.ffmpegPath = update
|
||||
fyne.CurrentApp().Preferences().SetString("ffmpeg", update)
|
||||
}
|
||||
|
||||
debugText := widget.NewLabel("Debug")
|
||||
debugExport := widget.NewButton("Export Debug Logs", func() {
|
||||
var itemInRing bool
|
||||
@@ -107,7 +137,7 @@ If 'Auto-Play Next File' is not working correctly, please disable it.`, w)
|
||||
|
||||
dropdown.Refresh()
|
||||
|
||||
return container.New(layout.NewFormLayout(), themeText, dropdown, gaplessText, gaplessdropdown, debugText, debugExport)
|
||||
return container.New(layout.NewFormLayout(), themeText, dropdown, gaplessText, gaplessdropdown, ffmpegText, ffmpegTextEntry, debugText, debugExport)
|
||||
}
|
||||
|
||||
func saveDebugLogs(f fyne.URIWriteCloser, s *NewScreen) {
|
||||
|
@@ -369,7 +369,7 @@ func setAVTransportSoapBuild(tvdata *TVPayload) ([]byte, error) {
|
||||
|
||||
var didl didLLiteItem
|
||||
resNodeData := []resNode{}
|
||||
duration, _ := utils.DurationForMedia(tvdata.MediaPath)
|
||||
duration, _ := utils.DurationForMedia(tvdata.FFmpegPath, tvdata.MediaPath)
|
||||
|
||||
switch duration {
|
||||
case "":
|
||||
@@ -512,7 +512,7 @@ func setNextAVTransportSoapBuild(tvdata *TVPayload, clear bool) ([]byte, error)
|
||||
|
||||
var didl didLLiteItem
|
||||
resNodeData := []resNode{}
|
||||
duration, _ := utils.DurationForMedia(tvdata.MediaPath)
|
||||
duration, _ := utils.DurationForMedia(tvdata.FFmpegPath, tvdata.MediaPath)
|
||||
|
||||
switch duration {
|
||||
case "":
|
||||
|
@@ -40,6 +40,7 @@ type TVPayload struct {
|
||||
CurrentTimers map[string]*time.Timer
|
||||
InitialMediaRenderersStates map[string]bool
|
||||
MediaRenderersStates map[string]*States
|
||||
FFmpegPath string
|
||||
EventURL string
|
||||
ControlURL string
|
||||
MediaURL string
|
||||
|
15
soapcalls/utils/checkffmpeg.go
Normal file
15
soapcalls/utils/checkffmpeg.go
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package utils
|
||||
|
||||
import "os/exec"
|
||||
|
||||
func CheckFFmpeg(ffmpeg string) error {
|
||||
checkffmpeg := exec.Command(ffmpeg, "-h")
|
||||
_, err := checkffmpeg.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
17
soapcalls/utils/checkffmpeg_windows.go
Normal file
17
soapcalls/utils/checkffmpeg_windows.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func CheckFFmpeg(ffmpeg string) error {
|
||||
checkffmpeg := exec.Command(ffmpeg, "-h")
|
||||
checkffmpeg.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000}
|
||||
|
||||
_, err := checkffmpeg.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
@@ -18,14 +19,18 @@ type ffprobeInfo struct {
|
||||
} `json:"format"`
|
||||
}
|
||||
|
||||
func DurationForMedia(f string) (string, error) {
|
||||
func DurationForMedia(ffmpeg string, f string) (string, error) {
|
||||
_, err := os.Stat(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := CheckFFmpeg(ffmpeg); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"ffprobe",
|
||||
filepath.Join(filepath.Dir(ffmpeg), "ffprobe"),
|
||||
"-loglevel", "error",
|
||||
"-show_format",
|
||||
"-of", "json",
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -16,14 +17,18 @@ type ffprobeInfo struct {
|
||||
} `json:"format"`
|
||||
}
|
||||
|
||||
func DurationForMedia(f string) (string, error) {
|
||||
func DurationForMedia(ffmpeg string, f string) (string, error) {
|
||||
_, err := os.Stat(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := CheckFFmpeg(ffmpeg); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"ffprobe",
|
||||
filepath.Join(filepath.Dir(ffmpeg), "ffprobe"),
|
||||
"-loglevel", "error",
|
||||
"-show_format",
|
||||
"-of", "json",
|
||||
|
@@ -1,11 +1,14 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
@@ -28,15 +31,20 @@ type tags struct {
|
||||
|
||||
var ErrNoSubs = errors.New("no subs")
|
||||
|
||||
func GetSubs(f string) ([]string, error) {
|
||||
func GetSubs(ffmpeg string, f string) ([]string, error) {
|
||||
_, err := os.Stat(f)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We assume the ffprobe path based on the ffmpeg one.
|
||||
// So we need to ensure that the ffmpeg one exists.
|
||||
if err := CheckFFmpeg(ffmpeg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"ffprobe",
|
||||
filepath.Join(filepath.Dir(ffmpeg), "ffprobe"),
|
||||
"-loglevel", "error",
|
||||
"-show_streams",
|
||||
"-of", "json",
|
||||
@@ -45,14 +53,12 @@ func GetSubs(f string) ([]string, error) {
|
||||
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var info ffprobeInfoforSubs
|
||||
|
||||
if err := json.Unmarshal(output, &info); err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -64,7 +70,6 @@ func GetSubs(f string) ([]string, error) {
|
||||
subcounter++
|
||||
tag := &tags{}
|
||||
if err := mapstructure.Decode(s.Tags, tag); err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -82,14 +87,13 @@ func GetSubs(f string) ([]string, error) {
|
||||
}
|
||||
|
||||
if len(out) == 0 {
|
||||
fmt.Println(ErrNoSubs)
|
||||
return nil, ErrNoSubs
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func ExtractSub(n int, f string) (string, error) {
|
||||
func ExtractSub(ffmpeg string, n int, f string) (string, error) {
|
||||
_, err := os.Stat(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -101,7 +105,7 @@ func ExtractSub(n int, f string) (string, error) {
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"ffmpeg",
|
||||
ffmpeg,
|
||||
"-y",
|
||||
"-i", f,
|
||||
"-map", "0:s:"+strconv.Itoa(n),
|
||||
|
119
soapcalls/utils/substools_windows.go
Normal file
119
soapcalls/utils/substools_windows.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
type ffprobeInfoforSubs struct {
|
||||
Streams []streams `json:"streams"`
|
||||
}
|
||||
|
||||
type streams struct {
|
||||
Tags any `json:"tags,omitempty"`
|
||||
CodecType string `json:"codec_type"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
type tags struct {
|
||||
Title string `mapstructure:"title"`
|
||||
Language string `mapstructure:"language"`
|
||||
}
|
||||
|
||||
var ErrNoSubs = errors.New("no subs")
|
||||
|
||||
func GetSubs(ffmpeg string, f string) ([]string, error) {
|
||||
_, err := os.Stat(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := CheckFFmpeg(ffmpeg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
filepath.Join(filepath.Dir(ffmpeg), "ffprobe"),
|
||||
"-loglevel", "error",
|
||||
"-show_streams",
|
||||
"-of", "json",
|
||||
f,
|
||||
)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000}
|
||||
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var info ffprobeInfoforSubs
|
||||
|
||||
if err := json.Unmarshal(output, &info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make([]string, 0)
|
||||
|
||||
var subcounter int
|
||||
for _, s := range info.Streams {
|
||||
if s.CodecType == "subtitle" {
|
||||
subcounter++
|
||||
tag := &tags{}
|
||||
if err := mapstructure.Decode(s.Tags, tag); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subName := tag.Title
|
||||
if tag.Title == "" {
|
||||
subName = tag.Language
|
||||
}
|
||||
|
||||
if subName == "" {
|
||||
subName = strconv.Itoa(subcounter)
|
||||
}
|
||||
|
||||
out = append(out, subName)
|
||||
}
|
||||
}
|
||||
|
||||
if len(out) == 0 {
|
||||
return nil, ErrNoSubs
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func ExtractSub(ffmpeg string, n int, f string) (string, error) {
|
||||
_, err := os.Stat(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tempSub, err := os.CreateTemp(os.TempDir(), "go2tv-sub-*.srt")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
ffmpeg,
|
||||
"-y",
|
||||
"-i", f,
|
||||
"-map", "0:s:"+strconv.Itoa(n),
|
||||
tempSub.Name(),
|
||||
)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000}
|
||||
|
||||
_, err = cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tempSub.Name(), nil
|
||||
}
|
@@ -15,7 +15,7 @@ var (
|
||||
|
||||
// ServeTranscodedStream passes an input file or io.Reader to ffmpeg and writes the output directly
|
||||
// to our io.Writer.
|
||||
func ServeTranscodedStream(w io.Writer, input interface{}, ff *exec.Cmd) error {
|
||||
func ServeTranscodedStream(w io.Writer, input interface{}, ff *exec.Cmd, ffmpeg string) error {
|
||||
// Pipe streaming is not great as explained here
|
||||
// https://video.stackexchange.com/questions/34087/ffmpeg-fails-on-pipe-to-pipe-video-decoding.
|
||||
// That's why if we have the option to pass the file directly to ffmpeg, we should.
|
||||
@@ -34,7 +34,7 @@ func ServeTranscodedStream(w io.Writer, input interface{}, ff *exec.Cmd) error {
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"ffmpeg",
|
||||
ffmpeg,
|
||||
"-re",
|
||||
"-i", in,
|
||||
"-vcodec", "h264",
|
||||
|
@@ -13,7 +13,7 @@ var (
|
||||
|
||||
// ServeTranscodedStream passes an input file or io.Reader to ffmpeg and writes the output directly
|
||||
// to our io.Writer.
|
||||
func ServeTranscodedStream(w io.Writer, input interface{}, ff *exec.Cmd) error {
|
||||
func ServeTranscodedStream(w io.Writer, input interface{}, ff *exec.Cmd, ffmpeg string) error {
|
||||
// Pipe streaming is not great as explained here
|
||||
// https://video.stackexchange.com/questions/34087/ffmpeg-fails-on-pipe-to-pipe-video-decoding.
|
||||
// That's why if we have the option to pass the file directly to ffmpeg, we should.
|
||||
@@ -32,7 +32,7 @@ func ServeTranscodedStream(w io.Writer, input interface{}, ff *exec.Cmd) error {
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"ffmpeg",
|
||||
ffmpeg,
|
||||
"-re",
|
||||
"-i", in,
|
||||
"-vcodec", "h264",
|
||||
|
Reference in New Issue
Block a user