diff --git a/config.go b/config.go index 7ee61c42b..d4c5cffbf 100644 --- a/config.go +++ b/config.go @@ -25,6 +25,7 @@ type VideoSettings struct { StreamingKey string `yaml:"streamingKey"` EncoderPreset string `yaml:"encoderPreset"` StreamQualities []StreamQuality `yaml:"streamQualities"` + EnablePassthrough bool `yaml:"passthrough"` } type StreamQuality struct { @@ -106,7 +107,4 @@ func checkConfig(config Config) { panic("A video encoder preset is required to be set in the config file.") } - if len(config.VideoSettings.StreamQualities) < 1 { - panic("At least one stream quality must be set in the config file.") - } } diff --git a/config/config-example.yaml b/config/config-example.yaml index 1a5bd1e2a..ea44e5bfd 100644 --- a/config/config-example.yaml +++ b/config/config-example.yaml @@ -7,6 +7,7 @@ videoSettings: chunkLengthInSeconds: 4 streamingKey: abc123 encoderPreset: superfast # https://trac.ffmpeg.org/wiki/Encode/H.264 + passthrough: true # Enabling this will ignore the below stream qualities and pass through the same quality that you're sending it streamQualities: - bitrate: 6000k diff --git a/ffmpeg.go b/ffmpeg.go index c51347de8..797f9b128 100644 --- a/ffmpeg.go +++ b/ffmpeg.go @@ -33,21 +33,33 @@ func startFfmpeg(configuration Config) { 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") + 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)) + streamMaps = append(streamMaps, fmt.Sprintf("v:%d,a:%d", index, index)) + videoMapsString = strings.Join(videoMaps, " ") + audioMaps = append(audioMaps, "-map a:0") + audioMapsString = strings.Join(audioMaps, " ") + " -c:a copy" // Pass through audio for all the variants, don't reencode + } } + streamMappingString = "-var_stream_map \"" + strings.Join(streamMaps, " ") + "\"" ffmpegFlags := []string{ "-hide_banner", "-re", "-i pipe:", // "-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 - 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 + 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", @@ -66,8 +78,7 @@ func startFfmpeg(configuration Config) { "-segment_wrap 100", "-tune zerolatency", - // "-master_m3u8_publish_rate 5", - "-var_stream_map \"" + strings.Join(streamMaps, " ") + "\"", + streamMappingString, variantPlaylistName, } diff --git a/playlistMonitor.go b/playlistMonitor.go index 783080e73..7936bd7c0 100644 --- a/playlistMonitor.go +++ b/playlistMonitor.go @@ -53,13 +53,16 @@ func getVariantIndexFromPath(fullDiskPath string) int { var variants []Variant func monitorVideoContent(pathToMonitor string, configuration Config, storage ChunkStorage) { - // Create structures to store the segments for the different stream variants + // Create at least one structure to store the segments for the different stream variants variants = make([]Variant, len(configuration.VideoSettings.StreamQualities)) - for index := range variants { - variants[index] = Variant{index, make([]Segment, 0)} + if len(configuration.VideoSettings.StreamQualities) > 0 && !configuration.VideoSettings.EnablePassthrough { + for index := range variants { + variants[index] = Variant{index, make([]Segment, 0)} + } + } else { + variants[0] = Variant{0, make([]Segment, 0)} } - - log.Printf("Using %s for storing files with %d variants...\n", pathToMonitor, len(variants)) + log.Printf("Using directory %s for storing files with %d variants...\n", pathToMonitor, len(variants)) w := watcher.New() diff --git a/utils.go b/utils.go index 4d0f161a0..cfd6654b6 100644 --- a/utils.go +++ b/utils.go @@ -57,13 +57,19 @@ func copy(src, dst string) { func resetDirectories(configuration Config) { // Wipe the public, web-accessible hls data directory os.RemoveAll(configuration.PublicHLSPath) + os.RemoveAll(configuration.PrivateHLSPath) os.MkdirAll(configuration.PublicHLSPath, 0777) + os.MkdirAll(configuration.PrivateHLSPath, 0777) // Create private hls data dirs - os.RemoveAll(configuration.PrivateHLSPath) - for index := range configuration.VideoSettings.StreamQualities { - os.MkdirAll(path.Join(configuration.PrivateHLSPath, strconv.Itoa(index)), 0777) - os.MkdirAll(path.Join(configuration.PublicHLSPath, strconv.Itoa(index)), 0777) + if !configuration.VideoSettings.EnablePassthrough || len(configuration.VideoSettings.StreamQualities) == 0 { + for index := range configuration.VideoSettings.StreamQualities { + os.MkdirAll(path.Join(configuration.PrivateHLSPath, strconv.Itoa(index)), 0777) + os.MkdirAll(path.Join(configuration.PublicHLSPath, strconv.Itoa(index)), 0777) + } + } else { + os.MkdirAll(path.Join(configuration.PrivateHLSPath, strconv.Itoa(0)), 0777) + os.MkdirAll(path.Join(configuration.PublicHLSPath, strconv.Itoa(0)), 0777) } }