mirror of
https://github.com/openlibrecommunity/olcrtc.git
synced 2026-05-26 07:08:11 +00:00
feat(ffmpeg): Add -ffmpeg flag for custom path
- Add -ffmpeg flag for custom path - Allow FFMPEG_BIN env var to set path - Update ffmpeg
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/openlibrecommunity/olcrtc/internal/app/session"
|
||||
"github.com/openlibrecommunity/olcrtc/internal/logger"
|
||||
"github.com/openlibrecommunity/olcrtc/internal/names"
|
||||
"github.com/openlibrecommunity/olcrtc/internal/transport/videochannel"
|
||||
)
|
||||
|
||||
const modeGen = "gen"
|
||||
@@ -25,8 +26,10 @@ const modeGen = "gen"
|
||||
// ErrDataDirRequired is returned when no data directory is specified.
|
||||
var ErrDataDirRequired = errors.New("data directory required (use -data data)")
|
||||
|
||||
//nolint:gochecknoglobals // Tests replace the long-running session runner with a bounded function.
|
||||
var runSession = session.Run
|
||||
|
||||
//nolint:gochecknoglobals // Tests replace gen runner with a stub.
|
||||
var runGen = execGen
|
||||
|
||||
type config struct {
|
||||
@@ -63,6 +66,7 @@ type config struct {
|
||||
seiFragmentSize int
|
||||
seiAckTimeoutMS int
|
||||
amount int
|
||||
ffmpegPath string
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -89,6 +93,10 @@ func runWithArgs(args []string) error {
|
||||
func runWithConfig(cfg config) error {
|
||||
configureLogging(cfg.debug)
|
||||
|
||||
if cfg.ffmpegPath != "ffmpeg" && cfg.ffmpegPath != "" {
|
||||
videochannel.FFmpegPath = cfg.ffmpegPath
|
||||
}
|
||||
|
||||
if cfg.mode == modeGen {
|
||||
return runGen(cfg)
|
||||
}
|
||||
@@ -200,6 +208,7 @@ func parseFlagsFrom(args []string, errorHandling flag.ErrorHandling) (config, er
|
||||
fs.IntVar(&cfg.seiFragmentSize, "frag", 0, "Fragment size in bytes for fragmented transports (seichannel)")
|
||||
fs.IntVar(&cfg.seiAckTimeoutMS, "ack-ms", 0, "ACK timeout in milliseconds for reliable visual transports (seichannel)")
|
||||
fs.IntVar(&cfg.amount, "amount", 0, "Number of rooms to generate (gen mode only)")
|
||||
fs.StringVar(&cfg.ffmpegPath, "ffmpeg", "ffmpeg", "Path to ffmpeg executable")
|
||||
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return cfg, fmt.Errorf("parse flags: %w", err)
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
| `-video-qr-size` | Размер фрагмента QR в байтах, `0` = авто | `0` |
|
||||
| `-video-tile-module` | Размер тайла в пикселях 1..270 (только `tile`) | `4` |
|
||||
| `-video-tile-rs` | Reed-Solomon паритет % 0..200 (только `tile`) | `20` |
|
||||
| `-ffmpeg` | Путь к исполняемому файлу ffmpeg | `ffmpeg` |
|
||||
|
||||
Для codec `tile` нужно точно `1080x1080`.
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -42,6 +43,9 @@ var (
|
||||
ErrUnexpectedFrameSize = errors.New("unexpected encoder frame size")
|
||||
)
|
||||
|
||||
// FFmpegPath defines the path to the ffmpeg executable.
|
||||
var FFmpegPath = "ffmpeg"
|
||||
|
||||
type codecSpec struct {
|
||||
mimeType string
|
||||
fourCC string
|
||||
@@ -195,14 +199,25 @@ func newFFmpegEncoder(
|
||||
width, height, fps int,
|
||||
bitrate, hw string,
|
||||
) (*ffmpegEncoder, error) {
|
||||
ffmpegBin := FFmpegPath
|
||||
if envBin := os.Getenv("FFMPEG_BIN"); envBin != "" {
|
||||
ffmpegBin = envBin
|
||||
}
|
||||
|
||||
if ffmpegBin == "ffmpeg" {
|
||||
if _, err := exec.LookPath("ffmpeg"); err != nil {
|
||||
return nil, ErrFFmpegUnavailable
|
||||
}
|
||||
} else {
|
||||
if _, err := os.Stat(ffmpegBin); err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrFFmpegUnavailable, err)
|
||||
}
|
||||
}
|
||||
|
||||
vcodec := resolveEncoderCodec(spec, hw)
|
||||
args := buildEncoderArgs(spec, vcodec, width, height, fps, bitrate)
|
||||
|
||||
cmd := exec.CommandContext(ctx, "ffmpeg", args...)
|
||||
cmd := exec.CommandContext(ctx, ffmpegBin, args...) //nolint:gosec
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encoder stdin: %w", err)
|
||||
@@ -397,14 +412,25 @@ func newFFmpegDecoder(
|
||||
width, height, fps int,
|
||||
hw string,
|
||||
) (*ffmpegDecoder, error) {
|
||||
ffmpegBin := FFmpegPath
|
||||
if envBin := os.Getenv("FFMPEG_BIN"); envBin != "" {
|
||||
ffmpegBin = envBin
|
||||
}
|
||||
|
||||
if ffmpegBin == "ffmpeg" {
|
||||
if _, err := exec.LookPath("ffmpeg"); err != nil {
|
||||
return nil, ErrFFmpegUnavailable
|
||||
}
|
||||
} else {
|
||||
if _, err := os.Stat(ffmpegBin); err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrFFmpegUnavailable, err)
|
||||
}
|
||||
}
|
||||
|
||||
decoderName := resolveDecoderName(spec, hw)
|
||||
args := buildDecoderArgs(spec, decoderName, width, height, "gray")
|
||||
|
||||
cmd := exec.CommandContext(ctx, "ffmpeg", args...)
|
||||
cmd := exec.CommandContext(ctx, ffmpegBin, args...) //nolint:gosec
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoder stdin: %w", err)
|
||||
@@ -539,9 +565,9 @@ func writeIVFHeader(w io.Writer, fourCC string, width, height, frameRate int) er
|
||||
binary.LittleEndian.PutUint16(header[4:6], 0)
|
||||
binary.LittleEndian.PutUint16(header[6:8], 32)
|
||||
copy(header[8:12], []byte(fourCC))
|
||||
binary.LittleEndian.PutUint16(header[12:14], uint16(width))
|
||||
binary.LittleEndian.PutUint16(header[14:16], uint16(height))
|
||||
binary.LittleEndian.PutUint32(header[16:20], uint32(frameRate))
|
||||
binary.LittleEndian.PutUint16(header[12:14], uint16(width)) //nolint:gosec
|
||||
binary.LittleEndian.PutUint16(header[14:16], uint16(height)) //nolint:gosec
|
||||
binary.LittleEndian.PutUint32(header[16:20], uint32(frameRate)) //nolint:gosec
|
||||
binary.LittleEndian.PutUint32(header[20:24], 1)
|
||||
binary.LittleEndian.PutUint32(header[24:28], 0)
|
||||
binary.LittleEndian.PutUint32(header[28:32], 0)
|
||||
@@ -550,7 +576,7 @@ func writeIVFHeader(w io.Writer, fourCC string, width, height, frameRate int) er
|
||||
|
||||
func writeIVFFrame(w io.Writer, pts uint64, frame []byte) error {
|
||||
header := make([]byte, 12)
|
||||
binary.LittleEndian.PutUint32(header[0:4], uint32(len(frame)))
|
||||
binary.LittleEndian.PutUint32(header[0:4], uint32(len(frame))) //nolint:gosec
|
||||
binary.LittleEndian.PutUint64(header[4:12], pts)
|
||||
if err := writeAll(w, header); err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user