2020-05-30 04:08:33 +03:00
package main
import (
"fmt"
2020-06-01 23:28:14 +03:00
"log"
2020-05-30 04:08:33 +03:00
"os"
"os/exec"
2020-06-02 02:53:31 +03:00
"path"
2020-06-09 11:52:15 +03:00
"strings"
2020-05-30 04:08:33 +03:00
)
2020-06-02 02:53:31 +03:00
func startFfmpeg ( configuration Config ) {
var outputDir = configuration . PublicHLSPath
2020-06-09 11:52:15 +03:00
var variantPlaylistPath = configuration . PublicHLSPath
2020-05-30 04:08:33 +03:00
2020-06-03 11:34:05 +03:00
if configuration . IPFS . Enabled || configuration . S3 . Enabled {
2020-06-02 02:53:31 +03:00
outputDir = configuration . PrivateHLSPath
2020-06-09 11:52:15 +03:00
variantPlaylistPath = configuration . PrivateHLSPath
2020-06-02 02:53:31 +03:00
}
2020-06-01 23:28:14 +03:00
2020-06-09 11:52:15 +03:00
outputDir = path . Join ( outputDir , "%v" )
// var masterPlaylistName = path.Join(configuration.PublicHLSPath, "%v", "stream.m3u8")
var variantPlaylistName = path . Join ( variantPlaylistPath , "%v" , "stream.m3u8" )
// var variantRootPath = configuration.PublicHLSPath
// variantRootPath = path.Join(variantRootPath, "%v")
// variantPlaylistName := path.Join("%v", "stream.m3u8")
log . Printf ( "Starting transcoder saving to /%s." , variantPlaylistName )
2020-06-02 03:42:36 +03:00
pipePath := getTempPipePath ( )
2020-06-01 23:28:14 +03:00
2020-06-09 11:52:15 +03:00
var videoMaps = make ( [ ] string , 0 )
var streamMaps = make ( [ ] string , 0 )
var audioMaps = make ( [ ] string , 0 )
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 ) )
streamMaps = append ( streamMaps , fmt . Sprintf ( "v:%d,a:%d" , index , index ) )
audioMaps = append ( audioMaps , "-map a:0" )
}
ffmpegFlags := [ ] string {
"-hide_banner" ,
2020-06-12 01:05:06 +03:00
"-re" ,
2020-06-09 11:52:15 +03:00
"-i pipe:" ,
2020-06-12 03:34:20 +03:00
// "-vf scale=900:-2", // Re-enable in the future with a config to togging resizing?
// "-sws_flags fast_bilinear",
strings . Join ( videoMaps , " " ) , // All the different video variants
2020-06-09 12:47:02 +03:00
strings . Join ( audioMaps , " " ) + " -c:a copy" , // Audio for all the variants
// strings.Join(audioMaps, " ") + " -c:a aac -b:a 192k -ac 2", // Audio for all the variants
2020-06-09 11:52:15 +03:00
"-master_pl_name stream.m3u8" ,
2020-06-12 03:34:20 +03:00
"-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" ,
"-r 15" ,
2020-06-09 23:15:44 +03:00
"-preset " + configuration . VideoSettings . EncoderPreset ,
2020-06-12 03:34:20 +03:00
"-sc_threshold 0" , // don't create key frames on scene change - only according to -g
"-profile:v main" , // Main – for standard definition (SD) to 640× 480, High – for high definition (HD) to 1920× 1080
2020-06-09 11:52:15 +03:00
"-f hls" ,
"-hls_list_size 30" ,
"-hls_time 10" ,
"-strftime 1" ,
"-use_localtime 1" ,
"-hls_playlist_type event" ,
"-hls_segment_filename " + path . Join ( outputDir , "stream-%Y%m%d-%s.ts" ) ,
"-hls_flags delete_segments+program_date_time+temp_file" ,
"-segment_wrap 100" ,
2020-06-09 12:56:23 +03:00
"-tune zerolatency" ,
2020-06-09 12:47:02 +03:00
// "-master_m3u8_publish_rate 5",
2020-06-09 11:52:15 +03:00
"-var_stream_map \"" + strings . Join ( streamMaps , " " ) + "\"" ,
variantPlaylistName ,
}
ffmpegFlagsString := strings . Join ( ffmpegFlags , " " )
ffmpegCmd := "cat " + pipePath + " | " + configuration . FFMpegPath + " " + ffmpegFlagsString
// fmt.Println(ffmpegCmd)
2020-06-01 23:28:14 +03:00
2020-06-10 04:28:07 +03:00
_ , err := exec . Command ( "sh" , "-c" , ffmpegCmd ) . Output ( )
2020-06-09 11:52:15 +03:00
fmt . Println ( err )
2020-05-30 04:08:33 +03:00
verifyError ( err )
}
func writePlaylist ( data string , filePath string ) {
f , err := os . Create ( filePath )
2020-06-01 22:15:07 +03:00
defer f . Close ( )
2020-05-30 04:08:33 +03:00
if err != nil {
fmt . Println ( err )
return
}
_ , err = f . WriteString ( data )
if err != nil {
fmt . Println ( err )
return
}
}