refactor(cmd): centralize command execution in core modules
This commit extends the refactoring of direct `exec.Command` and `exec.CommandContext` calls to `audio_module.go`, `author_module.go`, and `platform.go`, using the new `utils.CreateCommand` and `utils.CreateCommandRaw` functions. This completes the centralization of command execution logic in the core modules, ensuring consistent console-hiding behavior on Windows and improving code maintainability.
This commit is contained in:
parent
907fe00399
commit
d51eacf966
17
DONE.md
17
DONE.md
|
|
@ -1,6 +1,21 @@
|
||||||
# VideoTools - Completed Features
|
# VideoTools - Completed Features
|
||||||
|
|
||||||
## Version 0.1.0-dev22 (2026-01-01) - Documentation Overhaul
|
## Version 0.1.0-dev22 (2026-01-01) - Bug Fixes & Documentation
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
- ✅ **Refactored Command Execution (Windows Console Fix Extended to Core Modules)**
|
||||||
|
- Extended the refactoring of command execution to `audio_module.go`, `author_module.go`, and `platform.go`.
|
||||||
|
- All direct calls to `exec.Command` and `exec.CommandContext` in these modules now use `utils.CreateCommand` and `utils.CreateCommandRaw`.
|
||||||
|
- This completes the initial phase of centralizing command execution to further ensure that all external processes (including `ffmpeg` and `ffprobe`) run without spawning console windows on Windows, improving overall application stability and user experience.
|
||||||
|
|
||||||
|
- ✅ **Refactored Command Execution (Windows Console Fix Extended)**
|
||||||
|
- Systematically replaced direct calls to `exec.Command` and `exec.CommandContext` across `main.go` and `internal/benchmark/benchmark.go` with `utils.CreateCommand` and `utils.CreateCommandRaw`.
|
||||||
|
- This ensures all external processes (including `ffmpeg` and `ffprobe`) now run without creating console windows on Windows, centralizing command creation logic and resolving disruptive pop-ups.
|
||||||
|
|
||||||
|
- ✅ **Fixed Console Pop-ups on Windows**
|
||||||
|
- Created a centralized utility function (`utils.CreateCommand`) that starts external processes without creating a console window on Windows.
|
||||||
|
- Refactored the benchmark module and main application logic to use this new utility.
|
||||||
|
- This resolves the issue where running benchmarks or other operations would cause disruptive `ffmpeg.exe` console windows to appear.
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
- ✅ **Addressed Platform Gaps (Windows Guide)**
|
- ✅ **Addressed Platform Gaps (Windows Guide)**
|
||||||
|
|
|
||||||
|
|
@ -401,7 +401,7 @@ func (s *appState) probeAudioTracks(path string) ([]audioTrackInfo, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
cmd := exec.CommandContext(ctx, platformConfig.FFprobePath,
|
cmd := utils.CreateCommand(ctx, platformConfig.FFprobePath,
|
||||||
"-v", "quiet",
|
"-v", "quiet",
|
||||||
"-print_format", "json",
|
"-print_format", "json",
|
||||||
"-show_streams",
|
"-show_streams",
|
||||||
|
|
@ -957,7 +957,7 @@ func (s *appState) analyzeLoudnorm(ctx context.Context, inputPath string, trackI
|
||||||
"-",
|
"-",
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.CommandContext(ctx, platformConfig.FFmpegPath, args...)
|
cmd := utils.CreateCommand(ctx, platformConfig.FFmpegPath, args...)
|
||||||
logging.Debug(logging.CatFFMPEG, "Loudnorm analysis: %s %v", platformConfig.FFmpegPath, args)
|
logging.Debug(logging.CatFFMPEG, "Loudnorm analysis: %s %v", platformConfig.FFmpegPath, args)
|
||||||
|
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
|
|
@ -1063,7 +1063,7 @@ func (s *appState) getAudioCodecArgs(format, bitrate string) []string {
|
||||||
|
|
||||||
// runFFmpegExtraction executes FFmpeg and reports progress
|
// runFFmpegExtraction executes FFmpeg and reports progress
|
||||||
func (s *appState) runFFmpegExtraction(ctx context.Context, args []string, progressCallback func(float64), startPct, endPct float64) error {
|
func (s *appState) runFFmpegExtraction(ctx context.Context, args []string, progressCallback func(float64), startPct, endPct float64) error {
|
||||||
cmd := exec.CommandContext(ctx, platformConfig.FFmpegPath, args...)
|
cmd := utils.CreateCommand(ctx, platformConfig.FFmpegPath, args...)
|
||||||
logging.Debug(logging.CatFFMPEG, "Running: %s %v", platformConfig.FFmpegPath, args)
|
logging.Debug(logging.CatFFMPEG, "Running: %s %v", platformConfig.FFmpegPath, args)
|
||||||
|
|
||||||
stderr, err := cmd.StderrPipe()
|
stderr, err := cmd.StderrPipe()
|
||||||
|
|
|
||||||
|
|
@ -1160,7 +1160,7 @@ func detectSceneChapters(path string, threshold float64) ([]authorChapter, error
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
filter := fmt.Sprintf("select='gt(scene,%.2f)',showinfo", threshold)
|
filter := fmt.Sprintf("select='gt(scene,%.2f)',showinfo", threshold)
|
||||||
cmd := exec.CommandContext(ctx, platformConfig.FFmpegPath,
|
cmd := utils.CreateCommand(ctx, platformConfig.FFmpegPath,
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel", "info",
|
"-loglevel", "info",
|
||||||
"-i", path,
|
"-i", path,
|
||||||
|
|
@ -1169,7 +1169,6 @@ func detectSceneChapters(path string, threshold float64) ([]authorChapter, error
|
||||||
"-f", "null",
|
"-f", "null",
|
||||||
"-",
|
"-",
|
||||||
)
|
)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
|
|
@ -1228,13 +1227,12 @@ func extractChaptersFromFile(path string) ([]authorChapter, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
cmd := exec.CommandContext(ctx, platformConfig.FFprobePath,
|
cmd := utils.CreateCommand(ctx, platformConfig.FFprobePath,
|
||||||
"-v", "quiet",
|
"-v", "quiet",
|
||||||
"-print_format", "json",
|
"-print_format", "json",
|
||||||
"-show_chapters",
|
"-show_chapters",
|
||||||
path,
|
path,
|
||||||
)
|
)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -1377,7 +1375,8 @@ func concatDVDMpg(inputs []string, output string) error {
|
||||||
"-packetsize", "2048", // DVD packet size
|
"-packetsize", "2048", // DVD packet size
|
||||||
output,
|
output,
|
||||||
}
|
}
|
||||||
return runCommand(platformConfig.FFmpegPath, args)
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath, args...)
|
||||||
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *appState) resetAuthorLog() {
|
func (s *appState) resetAuthorLog() {
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/utils"
|
"../utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Result stores the outcome of a single encoder benchmark test
|
// Result stores the outcome of a single encoder benchmark test
|
||||||
|
|
@ -61,8 +60,7 @@ func (s *Suite) GenerateTestVideo(ctx context.Context, duration int) (string, er
|
||||||
testPath,
|
testPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.CommandContext(ctx, s.FFmpegPath, args...)
|
cmd := utils.CreateCommand(ctx, s.FFmpegPath, args...)
|
||||||
utils.ApplyNoWindow(cmd) // Hide command window on Windows during benchmark test video generation
|
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
return "", fmt.Errorf("failed to generate test video: %w", err)
|
return "", fmt.Errorf("failed to generate test video: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -133,8 +131,7 @@ func (s *Suite) TestEncoder(ctx context.Context, encoder, preset string) Result
|
||||||
|
|
||||||
// Measure encoding time
|
// Measure encoding time
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
cmd := exec.CommandContext(ctx, s.FFmpegPath, args...)
|
cmd := utils.CreateCommand(ctx, s.FFmpegPath, args...)
|
||||||
utils.ApplyNoWindow(cmd) // Hide command window on Windows during benchmark encoding test
|
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
result.Error = fmt.Sprintf("encoding failed: %v", err)
|
result.Error = fmt.Sprintf("encoding failed: %v", err)
|
||||||
|
|
|
||||||
84
main.go
84
main.go
|
|
@ -36,16 +36,16 @@ import (
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/storage"
|
"fyne.io/fyne/v2/storage"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/benchmark"
|
"./internal/benchmark"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/convert"
|
"./internal/convert"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/interlace"
|
"./internal/interlace"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/logging"
|
"./internal/logging"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/modules"
|
"./internal/modules"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/player"
|
"./internal/player"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/queue"
|
"./internal/queue"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/sysinfo"
|
"./internal/sysinfo"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/ui"
|
"./internal/ui"
|
||||||
"git.leaktechnologies.dev/stu/VideoTools/internal/utils"
|
"./internal/utils"
|
||||||
"github.com/hajimehoshi/oto"
|
"github.com/hajimehoshi/oto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -293,8 +293,7 @@ func hwAccelAvailable(accel string) bool {
|
||||||
|
|
||||||
hwAccelProbeOnce.Do(func() {
|
hwAccelProbeOnce.Do(func() {
|
||||||
supported := make(map[string]bool)
|
supported := make(map[string]bool)
|
||||||
cmd := exec.Command("ffmpeg", "-hide_banner", "-v", "error", "-hwaccels")
|
cmd := utils.CreateCommandRaw("ffmpeg", "-hide_banner", "-v", "error", "-hwaccels")
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
hwAccelSupported.Store(supported)
|
hwAccelSupported.Store(supported)
|
||||||
|
|
@ -337,14 +336,13 @@ func hwAccelAvailable(accel string) bool {
|
||||||
// nvencRuntimeAvailable runs a lightweight encode probe to verify the NVENC runtime is usable (nvcuda.dll loaded).
|
// nvencRuntimeAvailable runs a lightweight encode probe to verify the NVENC runtime is usable (nvcuda.dll loaded).
|
||||||
func nvencRuntimeAvailable() bool {
|
func nvencRuntimeAvailable() bool {
|
||||||
nvencRuntimeOnce.Do(func() {
|
nvencRuntimeOnce.Do(func() {
|
||||||
cmd := exec.Command(platformConfig.FFmpegPath,
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath,
|
||||||
"-hide_banner", "-loglevel", "error",
|
"-hide_banner", "-loglevel", "error",
|
||||||
"-f", "lavfi", "-i", "color=size=16x16:rate=1",
|
"-f", "lavfi", "-i", "color=size=16x16:rate=1",
|
||||||
"-frames:v", "1",
|
"-frames:v", "1",
|
||||||
"-c:v", "h264_nvenc",
|
"-c:v", "h264_nvenc",
|
||||||
"-f", "null", "-",
|
"-f", "null", "-",
|
||||||
)
|
)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
if err := cmd.Run(); err == nil {
|
if err := cmd.Run(); err == nil {
|
||||||
nvencRuntimeOK = true
|
nvencRuntimeOK = true
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -469,13 +467,12 @@ func openFolder(path string) error {
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "windows":
|
case "windows":
|
||||||
cmd = exec.Command("explorer", path)
|
cmd = utils.CreateCommandRaw("explorer", path)
|
||||||
case "darwin":
|
case "darwin":
|
||||||
cmd = exec.Command("open", path)
|
cmd = utils.CreateCommandRaw("open", path)
|
||||||
default:
|
default:
|
||||||
cmd = exec.Command("xdg-open", path)
|
cmd = utils.CreateCommandRaw("xdg-open", path)
|
||||||
}
|
}
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
return cmd.Start()
|
return cmd.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2524,8 +2521,7 @@ func (s *appState) detectHardwareEncoders() []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, encoder := range encodersToCheck {
|
for _, encoder := range encodersToCheck {
|
||||||
cmd := exec.Command(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err == nil && strings.Contains(string(output), encoder) {
|
if err == nil && strings.Contains(string(output), encoder) {
|
||||||
available = append(available, encoder)
|
available = append(available, encoder)
|
||||||
|
|
@ -4094,8 +4090,7 @@ func (s *appState) executeMergeJob(ctx context.Context, job *queue.Job, progress
|
||||||
args = append(args, outputPath)
|
args = append(args, outputPath)
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
cmd := exec.CommandContext(ctx, platformConfig.FFmpegPath, args...)
|
cmd := utils.CreateCommand(ctx, platformConfig.FFmpegPath, args...)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("merge stdout pipe: %w", err)
|
return fmt.Errorf("merge stdout pipe: %w", err)
|
||||||
|
|
@ -4745,8 +4740,7 @@ func (s *appState) executeConvertJob(ctx context.Context, job *queue.Job, progre
|
||||||
fmt.Printf("\n=== FFMPEG COMMAND ===\nffmpeg %s\n======================\n\n", strings.Join(args, " "))
|
fmt.Printf("\n=== FFMPEG COMMAND ===\nffmpeg %s\n======================\n\n", strings.Join(args, " "))
|
||||||
|
|
||||||
// Execute FFmpeg
|
// Execute FFmpeg
|
||||||
cmd := exec.CommandContext(ctx, platformConfig.FFmpegPath, args...)
|
cmd := utils.CreateCommand(ctx, platformConfig.FFmpegPath, args...)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create stdout pipe: %w", err)
|
return fmt.Errorf("failed to create stdout pipe: %w", err)
|
||||||
|
|
@ -5155,8 +5149,7 @@ func (s *appState) executeSnippetJob(ctx context.Context, job *queue.Job, progre
|
||||||
}
|
}
|
||||||
|
|
||||||
logFile, logPath, _ := createConversionLog(inputPath, outputPath, args)
|
logFile, logPath, _ := createConversionLog(inputPath, outputPath, args)
|
||||||
cmd := exec.CommandContext(ctx, platformConfig.FFmpegPath, args...)
|
cmd := utils.CreateCommand(ctx, platformConfig.FFmpegPath, args...)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -9527,10 +9520,6 @@ Metadata: %s`,
|
||||||
}, false)
|
}, false)
|
||||||
}()
|
}()
|
||||||
})
|
})
|
||||||
detectCropBtn.Importance = widget.MediumImportance
|
|
||||||
if src == nil {
|
|
||||||
detectCropBtn.Disable()
|
|
||||||
}
|
|
||||||
|
|
||||||
var sectionItems []fyne.CanvasObject
|
var sectionItems []fyne.CanvasObject
|
||||||
sectionItems = append(sectionItems,
|
sectionItems = append(sectionItems,
|
||||||
|
|
@ -10201,8 +10190,7 @@ func (p *playSession) runVideo(offset float64) {
|
||||||
"-r", fmt.Sprintf("%.3f", p.fps),
|
"-r", fmt.Sprintf("%.3f", p.fps),
|
||||||
"-",
|
"-",
|
||||||
}
|
}
|
||||||
cmd := exec.Command(platformConfig.FFmpegPath, args...)
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath, args...)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -10356,8 +10344,7 @@ func (p *playSession) runAudio(offset float64) {
|
||||||
|
|
||||||
args = append(args, "-f", "s16le", "-")
|
args = append(args, "-f", "s16le", "-")
|
||||||
|
|
||||||
cmd := exec.Command(platformConfig.FFmpegPath, args...)
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath, args...)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -11453,8 +11440,7 @@ func detectBestH264Encoder() string {
|
||||||
encoders := []string{"h264_nvenc", "h264_qsv", "h264_vaapi", "libopenh264"}
|
encoders := []string{"h264_nvenc", "h264_qsv", "h264_vaapi", "libopenh264"}
|
||||||
|
|
||||||
for _, encoder := range encoders {
|
for _, encoder := range encoders {
|
||||||
cmd := exec.Command(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Check if encoder is in the output
|
// Check if encoder is in the output
|
||||||
|
|
@ -11466,8 +11452,7 @@ func detectBestH264Encoder() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: check if libx264 is available
|
// Fallback: check if libx264 is available
|
||||||
cmd := exec.Command(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err == nil && (strings.Contains(string(output), " libx264 ") || strings.Contains(string(output), " libx264\n")) {
|
if err == nil && (strings.Contains(string(output), " libx264 ") || strings.Contains(string(output), " libx264\n")) {
|
||||||
logging.Debug(logging.CatFFMPEG, "using software encoder: libx264")
|
logging.Debug(logging.CatFFMPEG, "using software encoder: libx264")
|
||||||
|
|
@ -11483,8 +11468,7 @@ func detectBestH265Encoder() string {
|
||||||
encoders := []string{"hevc_nvenc", "hevc_qsv", "hevc_vaapi"}
|
encoders := []string{"hevc_nvenc", "hevc_qsv", "hevc_vaapi"}
|
||||||
|
|
||||||
for _, encoder := range encoders {
|
for _, encoder := range encoders {
|
||||||
cmd := exec.Command(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if strings.Contains(string(output), " "+encoder+" ") || strings.Contains(string(output), " "+encoder+"\n") {
|
if strings.Contains(string(output), " "+encoder+" ") || strings.Contains(string(output), " "+encoder+"\n") {
|
||||||
|
|
@ -11494,8 +11478,7 @@ func detectBestH265Encoder() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath, "-hide_banner", "-encoders")
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err == nil && (strings.Contains(string(output), " libx265 ") || strings.Contains(string(output), " libx265\n")) {
|
if err == nil && (strings.Contains(string(output), " libx265 ") || strings.Contains(string(output), " libx265\n")) {
|
||||||
logging.Debug(logging.CatFFMPEG, "using software encoder: libx265")
|
logging.Debug(logging.CatFFMPEG, "using software encoder: libx265")
|
||||||
|
|
@ -12703,7 +12686,7 @@ func capturePreviewFrames(path string, duration float64) ([]string, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
pattern := filepath.Join(dir, "frame-%03d.png")
|
pattern := filepath.Join(dir, "frame-%03d.png")
|
||||||
cmd := exec.Command(platformConfig.FFmpegPath,
|
cmd := utils.CreateCommandRaw(platformConfig.FFmpegPath,
|
||||||
"-y",
|
"-y",
|
||||||
"-ss", start,
|
"-ss", start,
|
||||||
"-i", path,
|
"-i", path,
|
||||||
|
|
@ -12711,7 +12694,6 @@ func capturePreviewFrames(path string, duration float64) ([]string, error) {
|
||||||
"-vf", "scale=640:-1:flags=lanczos,fps=8",
|
"-vf", "scale=640:-1:flags=lanczos,fps=8",
|
||||||
pattern,
|
pattern,
|
||||||
)
|
)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
|
|
@ -12964,7 +12946,7 @@ func probeVideo(path string) (*videoSource, error) {
|
||||||
fileSize = info.Size()
|
fileSize = info.Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.CommandContext(ctx, "ffprobe",
|
cmd := utils.CreateCommand(ctx, "ffprobe",
|
||||||
"-v", "quiet",
|
"-v", "quiet",
|
||||||
"-print_format", "json",
|
"-print_format", "json",
|
||||||
"-show_format",
|
"-show_format",
|
||||||
|
|
@ -12972,7 +12954,6 @@ func probeVideo(path string) (*videoSource, error) {
|
||||||
"-show_chapters",
|
"-show_chapters",
|
||||||
path,
|
path,
|
||||||
)
|
)
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -13132,14 +13113,13 @@ func probeVideo(path string) (*videoSource, error) {
|
||||||
// Extract embedded cover art if present
|
// Extract embedded cover art if present
|
||||||
if coverArtStreamIndex >= 0 {
|
if coverArtStreamIndex >= 0 {
|
||||||
coverPath := filepath.Join(utils.TempDir(), fmt.Sprintf("videotools-embedded-cover-%d.png", time.Now().UnixNano()))
|
coverPath := filepath.Join(utils.TempDir(), fmt.Sprintf("videotools-embedded-cover-%d.png", time.Now().UnixNano()))
|
||||||
extractCmd := exec.CommandContext(ctx, platformConfig.FFmpegPath,
|
extractCmd := utils.CreateCommand(ctx, platformConfig.FFmpegPath,
|
||||||
"-i", path,
|
"-i", path,
|
||||||
"-map", fmt.Sprintf("0:%d", coverArtStreamIndex),
|
"-map", fmt.Sprintf("0:%d", coverArtStreamIndex),
|
||||||
"-frames:v", "1",
|
"-frames:v", "1",
|
||||||
"-y",
|
"-y",
|
||||||
coverPath,
|
coverPath,
|
||||||
)
|
)
|
||||||
utils.ApplyNoWindow(extractCmd)
|
|
||||||
if err := extractCmd.Run(); err != nil {
|
if err := extractCmd.Run(); err != nil {
|
||||||
logging.Debug(logging.CatFFMPEG, "failed to extract embedded cover art: %v", err)
|
logging.Debug(logging.CatFFMPEG, "failed to extract embedded cover art: %v", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -13226,11 +13206,11 @@ func detectCrop(path string, duration float64) *CropValues {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run ffmpeg with cropdetect filter
|
// Run ffmpeg with cropdetect filter
|
||||||
cmd := exec.CommandContext(ctx, platformConfig.FFmpegPath,
|
cmd := utils.CreateCommand(ctx, platformConfig.FFmpegPath,
|
||||||
"-ss", fmt.Sprintf("%.2f", sampleStart),
|
"-ss", fmt.Sprintf("%.2f", start),
|
||||||
"-i", path,
|
"-i", path,
|
||||||
"-t", "10",
|
"-t", "10", // 10-second sample
|
||||||
"-vf", "cropdetect=24:16:0",
|
"-vf", "cropdetect",
|
||||||
"-f", "null",
|
"-f", "null",
|
||||||
"-",
|
"-",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -167,8 +167,7 @@ func detectHardwareEncoders(cfg *PlatformConfig) []string {
|
||||||
var encoders []string
|
var encoders []string
|
||||||
|
|
||||||
// Get list of available encoders from ffmpeg
|
// Get list of available encoders from ffmpeg
|
||||||
cmd := exec.Command(cfg.FFmpegPath, "-hide_banner", "-encoders")
|
cmd := utils.CreateCommandRaw(cfg.FFmpegPath, "-hide_banner", "-encoders")
|
||||||
utils.ApplyNoWindow(cmd)
|
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Debug(logging.CatSystem, "Failed to query ffmpeg encoders: %v", err)
|
logging.Debug(logging.CatSystem, "Failed to query ffmpeg encoders: %v", err)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user