@ -33,7 +33,7 @@ type HLSVariant struct {
@@ -33,7 +33,7 @@ type HLSVariant struct {
videoSize VideoSize // Resizes the video via scaling
framerate int // The output framerate
videoBitrate string // The output bitrate
videoBitrate int // The output bitrate
isVideoPassthrough bool // Override all settings and just copy the video stream
audioBitrate string // The audio bitrate
@ -164,11 +164,11 @@ func getVariantFromConfigQuality(quality config.StreamQuality, index int) HLSVar
@@ -164,11 +164,11 @@ func getVariantFromConfigQuality(quality config.StreamQuality, index int) HLSVar
variant . encoderPreset = "veryfast"
}
variant . SetVideoBitrate ( strconv . Itoa ( quality . VideoBitrate ) + "k" )
variant . SetVideoBitrate ( quality . VideoBitrate )
variant . SetAudioBitrate ( strconv . Itoa ( quality . AudioBitrate ) + "k" )
variant . SetVideoScalingWidth ( quality . ScaledWidth )
variant . SetVideoScalingHeight ( quality . ScaledHeight )
variant . SetVideoFramerate ( quality . Framerate )
variant . SetVideoFramerate ( quality . GetFramerate ( ) )
return variant
}
@ -196,13 +196,6 @@ func NewTranscoder() Transcoder {
@@ -196,13 +196,6 @@ func NewTranscoder() Transcoder {
transcoder . segmentLengthSeconds = config . Config . GetVideoSegmentSecondsLength ( )
qualities := config . Config . VideoSettings . StreamQualities
if len ( qualities ) == 0 {
defaultQuality := config . StreamQuality { }
defaultQuality . VideoBitrate = 1000
defaultQuality . EncoderPreset = "superfast"
qualities = append ( qualities , defaultQuality )
}
for index , quality := range qualities {
variant := getVariantFromConfigQuality ( quality , index )
transcoder . AddVariant ( variant )
@ -212,9 +205,9 @@ func NewTranscoder() Transcoder {
@@ -212,9 +205,9 @@ func NewTranscoder() Transcoder {
}
// Uses `map` https://www.ffmpeg.org/ffmpeg-all.html#Stream-specifiers-1 https://www.ffmpeg.org/ffmpeg-all.html#Advanced-options
func ( v * HLSVariant ) getVariantString ( ) string {
func ( v * HLSVariant ) getVariantString ( t * Transcoder ) string {
variantEncoderCommands := [ ] string {
v . getVideoQualityString ( ) ,
v . getVideoQualityString ( t ) ,
v . getAudioQualityString ( ) ,
}
@ -222,17 +215,7 @@ func (v *HLSVariant) getVariantString() string {
@@ -222,17 +215,7 @@ func (v *HLSVariant) getVariantString() string {
variantEncoderCommands = append ( variantEncoderCommands , v . getScalingString ( ) )
}
if v . framerate == 0 {
v . framerate = 30
}
if v . framerate != 0 {
variantEncoderCommands = append ( variantEncoderCommands , fmt . Sprintf ( "-r %d" , v . framerate ) )
// Insert a keyframe every 2 seconds.
// Multiply your output frame rate * 2. For example, if your input is -framerate 30, then use -g 60
variantEncoderCommands = append ( variantEncoderCommands , "-g " + strconv . Itoa ( v . framerate * 2 ) )
variantEncoderCommands = append ( variantEncoderCommands , "-keyint_min " + strconv . Itoa ( v . framerate * 2 ) )
}
variantEncoderCommands = append ( variantEncoderCommands , fmt . Sprintf ( "-r %d" , v . framerate ) )
if v . encoderPreset != "" {
variantEncoderCommands = append ( variantEncoderCommands , fmt . Sprintf ( "-preset %s" , v . encoderPreset ) )
@ -247,7 +230,7 @@ func (t *Transcoder) getVariantsString() string {
@@ -247,7 +230,7 @@ func (t *Transcoder) getVariantsString() string {
var variantsStreamMaps = " -var_stream_map \""
for _ , variant := range t . variants {
variantsCommandFlags = variantsCommandFlags + " " + variant . getVariantString ( )
variantsCommandFlags = variantsCommandFlags + " " + variant . getVariantString ( t )
variantsStreamMaps = variantsStreamMaps + fmt . Sprintf ( "v:%d,a:%d " , variant . index , variant . index )
}
variantsCommandFlags = variantsCommandFlags + " " + variantsStreamMaps + "\""
@ -278,17 +261,40 @@ func (v *HLSVariant) getScalingString() string {
@@ -278,17 +261,40 @@ func (v *HLSVariant) getScalingString() string {
// Video Quality
// SetVideoBitrate will set the output bitrate of this variant's video
func ( v * HLSVariant ) SetVideoBitrate ( bitrate string ) {
func ( v * HLSVariant ) SetVideoBitrate ( bitrate int ) {
v . videoBitrate = bitrate
}
func ( v * HLSVariant ) getVideoQualityString ( ) string {
func ( v * HLSVariant ) getVideoQualityString ( t * Transcoder ) string {
if v . isVideoPassthrough {
return fmt . Sprintf ( "-map v:0 -c:v:%d copy" , v . index )
}
encoderCodec := "libx264"
return fmt . Sprintf ( "-map v:0 -c:v:%d %s -b:v:%d %s" , v . index , encoderCodec , v . index , v . videoBitrate )
// -1 to work around segments being generated slightly larger than expected.
// https://trac.ffmpeg.org/ticket/6915?replyto=58#comment:57
gop := ( t . segmentLengthSeconds * v . framerate ) - 1
// For limiting the output bitrate
// https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate
// https://developer.apple.com/documentation/http_live_streaming/about_apple_s_http_live_streaming_tools
// Adjust the max & buffer size until the output bitrate doesn't exceed the ~+10% that Apple's media validator
// complains about.
maxBitrate := int ( float64 ( v . videoBitrate ) * 1.06 ) // Max is a ~+10% over specified bitrate.
bufferSize := int ( float64 ( v . videoBitrate ) * 1.2 ) // How often it checks the bitrate of encoded segments to see if it's too high/low.
cmd := [ ] string {
"-map v:0" ,
fmt . Sprintf ( "-c:v:%d %s" , v . index , encoderCodec ) , // Video codec used for this variant
fmt . Sprintf ( "-b:v:%d %dk" , v . index , v . videoBitrate ) , // The average bitrate for this variant
fmt . Sprintf ( "-maxrate:v:%d %dk" , v . index , maxBitrate ) , // The max bitrate allowed for this variant
fmt . Sprintf ( "-bufsize:v:%d %dk" , v . index , bufferSize ) , // How often the encoder checks the bitrate in order to meet average/max values
fmt . Sprintf ( "-g:v:%d %d" , v . index , gop ) , // How often i-frames are encoded into the segments
fmt . Sprintf ( "-x264-params:v:%d \"scenecut=0:open_gop=0:min-keyint=%d:keyint=%d\"" , v . index , gop , gop ) , // How often i-frames are encoded into the segments
}
return strings . Join ( cmd , " " )
}
// SetVideoFramerate will set the output framerate of this variant's video