apply fixes after testing

Signed-off-by: denis-tingaikin <denis.tingajkin@xored.com>
This commit is contained in:
denis-tingaikin
2025-02-21 05:03:15 +03:00
parent 77e4471ed3
commit ac22070f89
16 changed files with 625 additions and 518 deletions
+28 -83
View File
@@ -22,61 +22,29 @@ import (
"os"
"os/exec"
"path/filepath"
"sort"
"strconv"
"strings"
"github.com/pkg/errors"
"github.com/huly-stream/internal/pkg/log"
"github.com/huly-stream/internal/pkg/resconv"
"go.uber.org/zap"
)
// Options represents configuration for the ffmpeg command
type Options struct {
OuputDir string
Resolutions []string
Threads int
UploadID string
OuputDir string
ScalingLevels []string
Level string
Threads int
UploadID string
}
func measure(options *Options) int64 {
var res int64
for _, resolution := range options.Resolutions {
var w, h int
var parts = strings.Split(resolution, ":")
if len(parts) > 1 {
w, _ = strconv.Atoi(parts[0])
w = max(w, 320)
h, _ = strconv.Atoi(parts[1])
h = max(h, 240)
res += int64(w) * int64(h)
}
}
return max(res, 320*240)
}
func newFfmpegCommand(ctx context.Context, in io.Reader, options *Options) (*exec.Cmd, error) {
if options == nil {
return nil, errors.New("options should not be nil")
}
func newFfmpegCommand(ctx context.Context, in io.Reader, args []string) (*exec.Cmd, error) {
if ctx == nil {
return nil, errors.New("ctx should not be nil")
}
var logger = log.FromContext(ctx).With(zap.String("func", "NewFFMpegCommand"))
var args []string
if options.Resolutions == nil {
logger.Debug("resolutions were not provided, building audio command...")
args = BuildAudioCommand(options)
} else {
logger.Debug("building video command...")
args = BuildVideoCommand(options)
}
var logger = log.FromContext(ctx).With(zap.String("func", "newFFMpegCommand"))
logger.Debug("prepared command: ", zap.Strings("args", args))
@@ -90,6 +58,7 @@ func newFfmpegCommand(ctx context.Context, in io.Reader, options *Options) (*exe
func buildCommonComamnd(opts *Options) []string {
return []string{
"-nostdin",
"-threads", fmt.Sprint(opts.Threads),
"-i", "pipe:0",
}
@@ -105,25 +74,25 @@ func BuildAudioCommand(opts *Options) []string {
)
}
// BuildVideoCommand returns flags for ffmpeg for video transcoding
func BuildVideoCommand(opts *Options) []string {
// BuildRawVideoCommand returns an extremely lightweight ffmpeg command for converting raw video without extra cost.
func BuildRawVideoCommand(opts *Options) []string {
return append(buildCommonComamnd(opts),
"-c:v",
"copy",
"-fps_mode",
"vfr",
"-hls_time", "5",
"-hls_list_size", "0",
"-hls_segment_filename", filepath.Join(opts.OuputDir, opts.UploadID, fmt.Sprintf("%s_%s_%s.ts", opts.UploadID, "%03d", opts.Level)),
filepath.Join(opts.OuputDir, opts.UploadID, fmt.Sprintf("%s_%s_master.m3u8", opts.UploadID, opts.Level)))
}
// BuildScalingVideoCommand returns flags for ffmpeg for video scaling
func BuildScalingVideoCommand(opts *Options) []string {
var result = buildCommonComamnd(opts)
for _, res := range opts.Resolutions {
var prefix string
var w, h int
var parts = strings.Split(res, ":")
if len(parts) > 1 {
w, _ = strconv.Atoi(parts[0])
h, _ = strconv.Atoi(parts[1])
}
w = max(w, 640)
h = max(h, 480)
prefix = ResolutionFromPixels(w * h)
for _, level := range opts.ScalingLevels {
result = append(result,
"-vf", fmt.Sprintf("scale=%d:%d", w, h),
"-vf", "scale="+resconv.Resolution(level),
"-c:v",
"libx264",
"-preset", "veryfast",
@@ -131,33 +100,9 @@ func BuildVideoCommand(opts *Options) []string {
"-g", "60",
"-hls_time", "5",
"-hls_list_size", "0",
"-hls_segment_filename", filepath.Join(opts.OuputDir, fmt.Sprintf("%s_%s_%s.ts", opts.UploadID, "%03d", prefix)),
filepath.Join(opts.OuputDir, fmt.Sprintf("%s_%s_master.m3u8", opts.UploadID, prefix)))
"-hls_segment_filename", filepath.Join(opts.OuputDir, opts.UploadID, fmt.Sprintf("%s_%s_%s.ts", opts.UploadID, "%03d", level)),
filepath.Join(opts.OuputDir, opts.UploadID, fmt.Sprintf("%s_%s_master.m3u8", opts.UploadID, level)))
}
return result
}
var resolutions = []struct {
pixels int
label string
}{
{pixels: 640 * 480, label: "320p"},
{pixels: 1280 * 720, label: "480p"},
{pixels: 1920 * 1080, label: "720p"},
{pixels: 2560 * 1440, label: "1k"},
{pixels: 3840 * 2160, label: "2k"},
{pixels: 5120 * 2160, label: "4k"},
{pixels: 7680 * 4320, label: "5k"},
}
// ResolutionFromPixels converts pixel count to short string
func ResolutionFromPixels(pixels int) string {
idx := sort.Search(len(resolutions), func(i int) bool {
return pixels < resolutions[i].pixels
})
if idx == len(resolutions) {
return "8k"
}
return resolutions[idx].label
}