diff --git a/config.go b/config.go index 465e0b911..0f0369900 100644 --- a/config.go +++ b/config.go @@ -29,7 +29,7 @@ type VideoSettings struct { } type StreamQuality struct { - Bitrate string `yaml:"bitrate"` + Bitrate int `yaml:"bitrate"` } // MaxNumberOnDisk must be at least as large as MaxNumberInPlaylist diff --git a/config/config-example.yaml b/config/config-example.yaml index b4292b098..76849c3e6 100644 --- a/config/config-example.yaml +++ b/config/config-example.yaml @@ -10,7 +10,7 @@ videoSettings: passthrough: true # Enabling this will ignore the below stream qualities and pass through the same quality that you're sending it streamQualities: - - bitrate: 6000k + - bitrate: 1000 # in k files: maxNumberInPlaylist: 30 diff --git a/ffmpeg.go b/ffmpeg.go index 7863025b8..4f30ae324 100644 --- a/ffmpeg.go +++ b/ffmpeg.go @@ -3,6 +3,7 @@ package main import ( "fmt" "log" + "math" "os" "os/exec" "path" @@ -37,14 +38,15 @@ func startFfmpeg(configuration Config) { var videoMapsString = "" var audioMapsString = "" var streamMappingString = "" - if configuration.VideoSettings.EnablePassthrough || len(configuration.VideoSettings.StreamQualities) == 0 { fmt.Println("Enabling passthrough video") // videoMaps = append(videoMaps, fmt.Sprintf("-map 0:v -c:v copy")) streamMaps = append(streamMaps, fmt.Sprintf("v:%d,a:%d", 0, 0)) } else { for index, quality := range configuration.VideoSettings.StreamQualities { - videoMaps = append(videoMaps, fmt.Sprintf("-map v:0 -c:v:%d libx264 -b:v:%d %s", index, index, quality.Bitrate)) + // minRate := math.Floor(float64(quality.Bitrate) / 2) + maxRate := math.Floor(float64(quality.Bitrate) * 0.8) + videoMaps = append(videoMaps, fmt.Sprintf("-map v:0 -c:v:%d libx264 -b:v:%d %dk -maxrate %dk -bufsize %dk", index, index, int(quality.Bitrate), int(maxRate), int(maxRate))) streamMaps = append(streamMaps, fmt.Sprintf("v:%d,a:%d", index, index)) videoMapsString = strings.Join(videoMaps, " ") audioMaps = append(audioMaps, "-map a:0") @@ -52,6 +54,8 @@ func startFfmpeg(configuration Config) { } } + framerate := 30 + streamMappingString = "-var_stream_map \"" + strings.Join(streamMaps, " ") + "\"" ffmpegFlags := []string{ "-hide_banner", @@ -62,15 +66,14 @@ func startFfmpeg(configuration Config) { videoMapsString, // All the different video variants audioMapsString, "-master_pl_name stream.m3u8", - "-g 60", "-keyint_min 60", // create key frame (I-frame) every 48 frames (~2 seconds) - will later affect correct slicing of segments and alignment of renditions - // "-framerate 30", + "-framerate " + strconv.Itoa(framerate), + "-g " + strconv.Itoa(framerate*2), " -keyint_min " + strconv.Itoa(framerate*2), // multiply your output frame rate * 2. For example, if your input is -framerate 30, then use -g 60 // "-r 25", "-preset " + configuration.VideoSettings.EncoderPreset, "-sc_threshold 0", // don't create key frames on scene change - only according to -g "-profile:v high", // Main – for standard definition (SD) to 640×480, High – for high definition (HD) to 1920×1080 "-movflags +faststart", "-pix_fmt yuv420p", - "-maxrate 2048k -bufsize 2048k", "-f hls", "-hls_list_size " + strconv.Itoa(configuration.Files.MaxNumberInPlaylist), "-hls_time " + strconv.Itoa(configuration.VideoSettings.ChunkLengthInSeconds), @@ -89,7 +92,7 @@ func startFfmpeg(configuration Config) { ffmpegCmd := "cat " + pipePath + " | " + configuration.FFMpegPath + " " + ffmpegFlagsString - // fmt.Println(ffmpegCmd) + fmt.Println(ffmpegCmd) _, err := exec.Command("sh", "-c", ffmpegCmd).Output() fmt.Println(err)