Merged move to fMP4 segments with associated fixes.
This commit is contained in:
+41
-10
@@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -98,23 +99,53 @@ func createInitialOfflineState() error {
|
||||
// offline video stream state only. No live stream HLS segments will continue to be
|
||||
// referenced.
|
||||
func transitionToOfflineVideoStreamContent() {
|
||||
log.Traceln("Firing transcoder with offline stream state")
|
||||
log.Traceln("Placing offline fMP4 content into HLS directories")
|
||||
|
||||
_transcoder := transcoder.NewTranscoder()
|
||||
_transcoder.SetIdentifier("offline")
|
||||
_transcoder.SetLatencyLevel(models.GetLatencyLevel(4))
|
||||
_transcoder.SetIsEvent(true)
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
offlineFilePath, err := saveOfflineClipToDisk("offline-v2.ts")
|
||||
offlineInitPath, offlineSegmentPath, err := saveOfflineFMP4ToDisk()
|
||||
if err != nil {
|
||||
log.Fatalln("unable to save offline clip:", err)
|
||||
log.Fatalln("unable to save offline fMP4 files:", err)
|
||||
}
|
||||
|
||||
_transcoder.SetInput(offlineFilePath)
|
||||
go _transcoder.Start(false)
|
||||
variants := configRepository.GetStreamOutputVariants()
|
||||
if len(variants) == 0 {
|
||||
// Ensure at least one variant directory exists.
|
||||
variants = make([]models.StreamOutputVariant, 1)
|
||||
}
|
||||
|
||||
for index := range variants {
|
||||
variantDir := filepath.Join(config.HLSStoragePath, fmt.Sprintf("%d", index))
|
||||
if err := os.MkdirAll(variantDir, 0o750); err != nil {
|
||||
log.Errorln("unable to create variant directory:", err)
|
||||
continue
|
||||
}
|
||||
makeVariantIndexOffline(index, offlineInitPath, offlineSegmentPath)
|
||||
}
|
||||
|
||||
// Write the master playlist that points to each variant's playlist.
|
||||
masterPlaylistPath := filepath.Join(config.HLSStoragePath, "stream.m3u8")
|
||||
masterFile, err := os.Create(masterPlaylistPath) //nolint:gosec
|
||||
if err != nil {
|
||||
log.Errorln("unable to create master playlist:", err)
|
||||
} else {
|
||||
_, _ = masterFile.WriteString("#EXTM3U\n")
|
||||
_, _ = masterFile.WriteString("#EXT-X-VERSION:7\n")
|
||||
_, _ = masterFile.WriteString("#EXT-X-INDEPENDENT-SEGMENTS\n")
|
||||
for index := range variants {
|
||||
_, _ = fmt.Fprintf(masterFile, "#EXT-X-STREAM-INF:BANDWIDTH=0\n")
|
||||
_, _ = fmt.Fprintf(masterFile, "%d/stream.m3u8\n", index)
|
||||
}
|
||||
if err := masterFile.Close(); err != nil {
|
||||
log.Errorln("unable to close master playlist:", err)
|
||||
}
|
||||
|
||||
// Notify the storage provider so it can rewrite variant URLs
|
||||
// to absolute paths for S3 or remote serving endpoints.
|
||||
_storage.MasterPlaylistWritten(masterPlaylistPath)
|
||||
}
|
||||
|
||||
// Copy the logo to be the thumbnail
|
||||
configRepository := configrepository.Get()
|
||||
logo := configRepository.GetLogoPath()
|
||||
dst := filepath.Join(config.TempDir, "thumbnail.jpg")
|
||||
if err = utils.Copy(filepath.Join("data", logo), dst); err != nil {
|
||||
|
||||
+61
-33
@@ -5,14 +5,13 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafov/m3u8"
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/static"
|
||||
"github.com/owncast/owncast/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func appendOfflineToVariantPlaylist(index int, playlistFilePath string) {
|
||||
func appendOfflineToVariantPlaylist(index int, playlistFilePath string, initFilename string, segmentFilename string) {
|
||||
existingPlaylistContents, err := os.ReadFile(playlistFilePath) // nolint: gosec
|
||||
if err != nil {
|
||||
log.Debugln("unable to read existing playlist file", err)
|
||||
@@ -34,9 +33,10 @@ func appendOfflineToVariantPlaylist(index int, playlistFilePath string) {
|
||||
|
||||
// Manually append the offline clip to the end of the media playlist.
|
||||
_, _ = atomicWriteTmpPlaylistFile.WriteString("#EXT-X-DISCONTINUITY\n")
|
||||
_, _ = fmt.Fprintf(atomicWriteTmpPlaylistFile, "#EXT-X-MAP:URI=\"%s\"\n", initFilename)
|
||||
// If "offline" content gets changed then change the duration below
|
||||
_, _ = atomicWriteTmpPlaylistFile.WriteString("#EXTINF:8.000000,\n")
|
||||
_, _ = atomicWriteTmpPlaylistFile.WriteString("offline-v2.ts\n")
|
||||
_, _ = fmt.Fprintf(atomicWriteTmpPlaylistFile, "%s\n", segmentFilename)
|
||||
_, _ = atomicWriteTmpPlaylistFile.WriteString("#EXT-X-ENDLIST\n")
|
||||
|
||||
if err := atomicWriteTmpPlaylistFile.Close(); err != nil {
|
||||
@@ -48,61 +48,89 @@ func appendOfflineToVariantPlaylist(index int, playlistFilePath string) {
|
||||
}
|
||||
}
|
||||
|
||||
func makeVariantIndexOffline(index int, offlineFilePath string, offlineFilename string) {
|
||||
playlistFilePath := fmt.Sprintf(filepath.Join(config.HLSStoragePath, "%d/stream.m3u8"), index)
|
||||
segmentFilePath := fmt.Sprintf(filepath.Join(config.HLSStoragePath, "%d/%s"), index, offlineFilename)
|
||||
func makeVariantIndexOffline(index int, offlineInitPath string, offlineSegmentPath string) {
|
||||
variantDir := filepath.Join(config.HLSStoragePath, fmt.Sprintf("%d", index))
|
||||
playlistFilePath := filepath.Join(variantDir, "stream.m3u8")
|
||||
|
||||
if err := utils.Copy(offlineFilePath, segmentFilePath); err != nil {
|
||||
initDest := filepath.Join(variantDir, "offline-init.mp4")
|
||||
segmentDest := filepath.Join(variantDir, "offline-v2.m4s")
|
||||
|
||||
if err := utils.Copy(offlineInitPath, initDest); err != nil {
|
||||
log.Warnln(err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := _storage.Save(initDest, 0); err != nil {
|
||||
log.Warnln(err)
|
||||
}
|
||||
|
||||
if _, err := _storage.Save(segmentFilePath, 0); err != nil {
|
||||
if err := utils.Copy(offlineSegmentPath, segmentDest); err != nil {
|
||||
log.Warnln(err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := _storage.Save(segmentDest, 0); err != nil {
|
||||
log.Warnln(err)
|
||||
}
|
||||
|
||||
if utils.DoesFileExists(playlistFilePath) {
|
||||
appendOfflineToVariantPlaylist(index, playlistFilePath)
|
||||
appendOfflineToVariantPlaylist(index, playlistFilePath, "offline-init.mp4", "offline-v2.m4s")
|
||||
} else {
|
||||
createEmptyOfflinePlaylist(playlistFilePath, offlineFilename)
|
||||
createEmptyOfflinePlaylist(playlistFilePath, "offline-init.mp4", "offline-v2.m4s")
|
||||
}
|
||||
if _, err := _storage.Save(playlistFilePath, 0); err != nil {
|
||||
log.Warnln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func createEmptyOfflinePlaylist(playlistFilePath string, offlineFilename string) {
|
||||
p, err := m3u8.NewMediaPlaylist(1, 1)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
// If "offline" content gets changed then change the duration below
|
||||
if err := p.Append(offlineFilename, 8.0, ""); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
p.Close()
|
||||
func createEmptyOfflinePlaylist(playlistFilePath string, initFilename string, segmentFilename string) {
|
||||
f, err := os.Create(playlistFilePath) //nolint:gosec
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := f.Write(p.Encode().Bytes()); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
_, _ = f.WriteString("#EXTM3U\n")
|
||||
_, _ = f.WriteString("#EXT-X-VERSION:7\n")
|
||||
_, _ = f.WriteString("#EXT-X-TARGETDURATION:8\n")
|
||||
_, _ = fmt.Fprintf(f, "#EXT-X-MAP:URI=\"%s\"\n", initFilename)
|
||||
// If "offline" content gets changed then change the duration below
|
||||
_, _ = f.WriteString("#EXTINF:8.000000,\n")
|
||||
_, _ = fmt.Fprintf(f, "%s\n", segmentFilename)
|
||||
_, _ = f.WriteString("#EXT-X-ENDLIST\n")
|
||||
}
|
||||
|
||||
func saveOfflineClipToDisk(offlineFilename string) (string, error) {
|
||||
offlineFileData := static.GetOfflineSegment()
|
||||
offlineTmpFile, err := os.CreateTemp(config.TempDir, offlineFilename)
|
||||
func saveOfflineFMP4ToDisk() (initPath string, segmentPath string, err error) {
|
||||
initData := static.GetOfflineInitSegment()
|
||||
initTmp, err := os.CreateTemp(config.TempDir, "offline-init-*.mp4")
|
||||
if err != nil {
|
||||
log.Errorln("unable to create temp file for offline video segment", err)
|
||||
return "", "", fmt.Errorf("unable to create temp file for offline init segment: %s", err)
|
||||
}
|
||||
|
||||
if _, err = offlineTmpFile.Write(offlineFileData); err != nil {
|
||||
return "", fmt.Errorf("unable to write offline segment to disk: %s", err)
|
||||
if _, err = initTmp.Write(initData); err != nil {
|
||||
return "", "", fmt.Errorf("unable to write offline init segment to disk: %s", err)
|
||||
}
|
||||
|
||||
offlineFilePath := offlineTmpFile.Name()
|
||||
return filepath.Abs(offlineFilePath)
|
||||
if err := initTmp.Close(); err != nil {
|
||||
return "", "", fmt.Errorf("unable to close offline init segment: %s", err)
|
||||
}
|
||||
initPath, _ = filepath.Abs(initTmp.Name())
|
||||
|
||||
segData := static.GetOfflineMediaSegment()
|
||||
segTmp, err := os.CreateTemp(config.TempDir, "offline-v2-*.m4s")
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("unable to create temp file for offline media segment: %s", err)
|
||||
}
|
||||
|
||||
if _, err = segTmp.Write(segData); err != nil {
|
||||
return "", "", fmt.Errorf("unable to write offline media segment to disk: %s", err)
|
||||
}
|
||||
|
||||
if err := segTmp.Close(); err != nil {
|
||||
return "", "", fmt.Errorf("unable to close offline media segment: %s", err)
|
||||
}
|
||||
segmentPath, _ = filepath.Abs(segTmp.Name())
|
||||
|
||||
return initPath, segmentPath, nil
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ func getAllFilesRecursive(baseDirectory string) (map[string][]os.FileInfo, error
|
||||
directory = info.Name()
|
||||
}
|
||||
|
||||
if filepath.Ext(info.Name()) == ".ts" {
|
||||
if filepath.Ext(info.Name()) == ".m4s" {
|
||||
files[directory] = append(files[directory], info)
|
||||
}
|
||||
|
||||
|
||||
@@ -317,7 +317,7 @@ func (s *S3Storage) retrieveAllVideoSegments() ([]s3object, error) {
|
||||
err := s.s3Client.ListObjectsPages(allObjectsListRequest,
|
||||
func(page *s3.ListObjectsOutput, lastPage bool) bool {
|
||||
for _, item := range page.Contents {
|
||||
if strings.HasSuffix(*item.Key, ".ts") {
|
||||
if strings.HasSuffix(*item.Key, ".m4s") {
|
||||
allObjects = append(allObjects, s3object{
|
||||
key: *item.Key,
|
||||
lastModified: *item.LastModified,
|
||||
|
||||
+2
-4
@@ -96,9 +96,7 @@ func SetStreamAsDisconnected() {
|
||||
_stats.LastConnectTime = nil
|
||||
_broadcaster = nil
|
||||
|
||||
offlineFilename := "offline-v2.ts"
|
||||
|
||||
offlineFilePath, err := saveOfflineClipToDisk(offlineFilename)
|
||||
offlineInitPath, offlineSegmentPath, err := saveOfflineFMP4ToDisk()
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
return
|
||||
@@ -122,7 +120,7 @@ func SetStreamAsDisconnected() {
|
||||
}
|
||||
|
||||
for index := range _currentBroadcast.OutputSettings {
|
||||
makeVariantIndexOffline(index, offlineFilePath, offlineFilename)
|
||||
makeVariantIndexOffline(index, offlineInitPath, offlineSegmentPath)
|
||||
}
|
||||
|
||||
StartOfflineCleanupTimer()
|
||||
|
||||
@@ -18,6 +18,7 @@ type FileWriterReceiverServiceCallback interface {
|
||||
SegmentWritten(localFilePath string)
|
||||
VariantPlaylistWritten(localFilePath string)
|
||||
MasterPlaylistWritten(localFilePath string)
|
||||
InitSegmentWritten(localFilePath string)
|
||||
}
|
||||
|
||||
// FileWriterReceiverService accepts transcoder responses via HTTP and fires the callbacks.
|
||||
@@ -81,8 +82,10 @@ func (s *FileWriterReceiverService) uploadHandler(w http.ResponseWriter, r *http
|
||||
func (s *FileWriterReceiverService) fileWritten(path string) {
|
||||
if utils.GetRelativePathFromAbsolutePath(path) == "hls/stream.m3u8" {
|
||||
s.callbacks.MasterPlaylistWritten(path)
|
||||
} else if strings.HasSuffix(path, ".ts") {
|
||||
} else if strings.HasSuffix(path, ".m4s") {
|
||||
s.callbacks.SegmentWritten(path)
|
||||
} else if strings.HasSuffix(path, "init.mp4") {
|
||||
s.callbacks.InitSegmentWritten(path)
|
||||
} else if strings.HasSuffix(path, ".m3u8") {
|
||||
s.callbacks.VariantPlaylistWritten(path)
|
||||
}
|
||||
|
||||
@@ -23,3 +23,8 @@ func (h *HLSHandler) VariantPlaylistWritten(localFilePath string) {
|
||||
func (h *HLSHandler) MasterPlaylistWritten(localFilePath string) {
|
||||
h.Storage.MasterPlaylistWritten(localFilePath)
|
||||
}
|
||||
|
||||
// InitSegmentWritten is fired when an fMP4 init segment is written to disk.
|
||||
func (h *HLSHandler) InitSegmentWritten(localFilePath string) {
|
||||
h.Storage.SegmentWritten(localFilePath)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package transcoder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@@ -64,7 +65,7 @@ func fireThumbnailGenerator(segmentPath string, variantIndex int) error {
|
||||
var modTime time.Time
|
||||
var names []string
|
||||
for _, f := range files {
|
||||
if path.Ext(f.Name()) != ".ts" {
|
||||
if path.Ext(f.Name()) != ".m4s" {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -88,7 +89,21 @@ func fireThumbnailGenerator(segmentPath string, variantIndex int) error {
|
||||
return nil
|
||||
}
|
||||
configRepository := configrepository.Get()
|
||||
// With multiple variants ffmpeg names init segments init_0.mp4, init_1.mp4, etc.
|
||||
// With a single variant it uses init.mp4.
|
||||
initSegment := path.Join(framePath, fmt.Sprintf("init_%d.mp4", variantIndex))
|
||||
if !utils.DoesFileExists(initSegment) {
|
||||
initSegment = path.Join(framePath, "init.mp4")
|
||||
}
|
||||
mostRecentFile := path.Join(framePath, names[0])
|
||||
|
||||
// The segment may have been cleaned up between ReadDir and now.
|
||||
if !utils.DoesFileExists(mostRecentFile) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// fMP4 segments require the init segment to be readable by ffmpeg
|
||||
inputArg := fmt.Sprintf("concat:%s|%s", initSegment, mostRecentFile)
|
||||
ffmpegPath := utils.ValidatedFfmpegPath(configRepository.GetFfMpegPath())
|
||||
outputFileTemp := path.Join(config.TempDir, "tempthumbnail.jpg")
|
||||
|
||||
@@ -96,7 +111,7 @@ func fireThumbnailGenerator(segmentPath string, variantIndex int) error {
|
||||
"-y", // Overwrite file
|
||||
"-threads", "1", // Low priority processing
|
||||
"-t", "1", // Pull from frame 1
|
||||
"-i", mostRecentFile, // Input
|
||||
"-i", inputArg, // Input (init segment + media segment)
|
||||
"-f", "image2", // format
|
||||
"-vframes", "1", // Single frame
|
||||
outputFileTemp,
|
||||
@@ -111,7 +126,7 @@ func fireThumbnailGenerator(segmentPath string, variantIndex int) error {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
makeAnimatedGifPreview(mostRecentFile, previewGifFile)
|
||||
makeAnimatedGifPreview(inputArg, previewGifFile)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -245,7 +245,9 @@ func (t *Transcoder) getFlags() *execInfo {
|
||||
ffmpegFlags = append(ffmpegFlags, hlsOptionsString...)
|
||||
ffmpegFlags = append(ffmpegFlags, hlsEventString...)
|
||||
ffmpegFlags = append(ffmpegFlags, []string{
|
||||
"-segment_format_options", "mpegts_flags=mpegts_copyts=1",
|
||||
"-hls_segment_type", "fmp4",
|
||||
"-hls_fmp4_init_filename", "init.mp4",
|
||||
"-bsf:a", "aac_adtstoasc", // Convert AAC ADTS headers to ASC for fMP4 container compatibility
|
||||
}...)
|
||||
ffmpegFlags = append(ffmpegFlags, t.codec.ExtraArguments()...)
|
||||
|
||||
@@ -257,7 +259,7 @@ func (t *Transcoder) getFlags() *execInfo {
|
||||
// Filenames
|
||||
"-master_pl_name", "stream.m3u8",
|
||||
|
||||
"-hls_segment_filename", localListenerAddress + "/%v/stream-" + t.segmentIdentifier + "-%d.ts", // Send HLS segments back to us over HTTP
|
||||
"-hls_segment_filename", localListenerAddress + "/%v/stream-" + t.segmentIdentifier + "-%d.m4s", // Send HLS segments back to us over HTTP
|
||||
"-max_muxing_queue_size", "400", // Workaround for Too many packets error: https://trac.ffmpeg.org/ticket/6375?cversion=0
|
||||
|
||||
"-method", "PUT", // HLS results sent back to us will be over PUTs
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestFFmpegNvencCommand(t *testing.T) {
|
||||
cmd := transcoder.GetString()
|
||||
|
||||
expectedLogPath := "data/logs/transcoder.log"
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -hwaccel cuda -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_nvenc -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -tune:v:0 ll -map a:0? -c:a:0 copy -preset p3 -map v:0 -c:v:1 h264_nvenc -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -tune:v:1 ll -map a:0? -c:a:1 copy -preset p5 -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset p1 -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -segment_format_options mpegts_flags=mpegts_copyts=1 -pix_fmt yuv420p -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdoieGg-%d.ts -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -hwaccel cuda -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_nvenc -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -tune:v:0 ll -map a:0? -c:a:0 copy -preset p3 -map v:0 -c:v:1 h264_nvenc -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -tune:v:1 ll -map a:0? -c:a:1 copy -preset p5 -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset p1 -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -hls_segment_type fmp4 -hls_fmp4_init_filename init.mp4 -bsf:a aac_adtstoasc -pix_fmt yuv420p -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdoieGg-%d.m4s -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
|
||||
if cmd != expected {
|
||||
t.Errorf("ffmpeg command does not match expected.\nGot %s\n, want: %s", cmd, expected)
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestFFmpegOmxCommand(t *testing.T) {
|
||||
cmd := transcoder.GetString()
|
||||
|
||||
expectedLogPath := "data/logs/transcoder.log"
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_omx -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -map a:0? -c:a:0 copy -preset veryfast -map v:0 -c:v:1 h264_omx -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -map a:0? -c:a:1 copy -preset fast -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset ultrafast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -segment_format_options mpegts_flags=mpegts_copyts=1 -tune zerolatency -pix_fmt yuv420p -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdFsdfzGg-%d.ts -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_omx -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -map a:0? -c:a:0 copy -preset veryfast -map v:0 -c:v:1 h264_omx -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -map a:0? -c:a:1 copy -preset fast -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset ultrafast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -hls_segment_type fmp4 -hls_fmp4_init_filename init.mp4 -bsf:a aac_adtstoasc -tune zerolatency -pix_fmt yuv420p -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdFsdfzGg-%d.m4s -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
|
||||
if cmd != expected {
|
||||
t.Errorf("ffmpeg command does not match expected.\nGot %s\n, want: %s", cmd, expected)
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestFFmpegQuicksyncCommand(t *testing.T) {
|
||||
cmd := transcoder.GetString()
|
||||
|
||||
expectedLogPath := "data/logs/transcoder.log"
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -init_hw_device qsv=hw -filter_hw_device hw -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_qsv -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -map a:0? -c:a:0 copy -filter:v:0 hwupload=extra_hw_frames=64,format=qsv -preset medium -map v:0 -c:v:1 h264_qsv -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -map a:0? -c:a:1 copy -filter:v:1 hwupload=extra_hw_frames=64,format=qsv -preset veryslow -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset veryfast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -segment_format_options mpegts_flags=mpegts_copyts=1 -pix_fmt qsv -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdofFGg-%d.ts -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -init_hw_device qsv=hw -filter_hw_device hw -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_qsv -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -map a:0? -c:a:0 copy -filter:v:0 hwupload=extra_hw_frames=64,format=qsv -preset medium -map v:0 -c:v:1 h264_qsv -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -map a:0? -c:a:1 copy -filter:v:1 hwupload=extra_hw_frames=64,format=qsv -preset veryslow -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset veryfast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -hls_segment_type fmp4 -hls_fmp4_init_filename init.mp4 -bsf:a aac_adtstoasc -pix_fmt qsv -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdofFGg-%d.m4s -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
|
||||
if cmd != expected {
|
||||
t.Errorf("ffmpeg command does not match expected.\nGot %s\n, want: %s", cmd, expected)
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestFFmpegVaapiCommand(t *testing.T) {
|
||||
cmd := transcoder.GetString()
|
||||
|
||||
expectedLogPath := "data/logs/transcoder.log"
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device /dev/dri/renderD128 -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_vaapi -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -map a:0? -c:a:0 copy -filter:v:0 hwupload=extra_hw_frames=64,format=vaapi -preset veryfast -map v:0 -c:v:1 h264_vaapi -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -map a:0? -c:a:1 copy -filter:v:1 hwupload=extra_hw_frames=64,format=vaapi -preset fast -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset ultrafast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -segment_format_options mpegts_flags=mpegts_copyts=1 -pix_fmt vaapi -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdofFGg-%d.ts -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device /dev/dri/renderD128 -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_vaapi -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -map a:0? -c:a:0 copy -filter:v:0 hwupload=extra_hw_frames=64,format=vaapi -preset veryfast -map v:0 -c:v:1 h264_vaapi -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -map a:0? -c:a:1 copy -filter:v:1 hwupload=extra_hw_frames=64,format=vaapi -preset fast -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset ultrafast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -hls_segment_type fmp4 -hls_fmp4_init_filename init.mp4 -bsf:a aac_adtstoasc -pix_fmt vaapi -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdofFGg-%d.m4s -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
|
||||
if cmd != expected {
|
||||
t.Errorf("ffmpeg command does not match expected.\nGot %s\n, want: %s", cmd, expected)
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestFFmpegVideoToolboxCommand(t *testing.T) {
|
||||
cmd := transcoder.GetString()
|
||||
|
||||
expectedLogPath := "data/logs/transcoder.log"
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_videotoolbox -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -realtime true -map a:0? -c:a:0 copy -preset veryfast -map v:0 -c:v:1 h264_videotoolbox -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -map a:0? -c:a:1 copy -preset fast -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset ultrafast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -segment_format_options mpegts_flags=mpegts_copyts=1 -pix_fmt nv12 -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdFsdfzGg-%d.ts -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 h264_videotoolbox -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -realtime true -map a:0? -c:a:0 copy -preset veryfast -map v:0 -c:v:1 h264_videotoolbox -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -map a:0? -c:a:1 copy -preset fast -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset ultrafast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -hls_segment_type fmp4 -hls_fmp4_init_filename init.mp4 -bsf:a aac_adtstoasc -pix_fmt nv12 -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdFsdfzGg-%d.m4s -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
|
||||
if cmd != expected {
|
||||
t.Errorf("ffmpeg command does not match expected.\nGot %s\n, want: %s", cmd, expected)
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestFFmpegx264Command(t *testing.T) {
|
||||
cmd := transcoder.GetString()
|
||||
|
||||
expectedLogPath := "data/logs/transcoder.log"
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 libx264 -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -x264-params:v:0 scenecut=0:open_gop=0 -bufsize:v:0 1088k -profile:v:0 high -map a:0? -c:a:0 copy -preset veryfast -map v:0 -c:v:1 libx264 -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -x264-params:v:1 scenecut=0:open_gop=0 -bufsize:v:1 3572k -profile:v:1 high -map a:0? -c:a:1 copy -preset fast -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset ultrafast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -segment_format_options mpegts_flags=mpegts_copyts=1 -tune zerolatency -pix_fmt yuv420p -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdofFGg-%d.ts -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
expected := `FFREPORT=file=` + expectedLogPath + `:level=32 ` + transcoder.ffmpegPath + ` -hide_banner -loglevel warning -fflags +genpts -flags +cgop -i fakecontent.flv -map v:0 -c:v:0 libx264 -b:v:0 1008k -maxrate:v:0 1088k -g:v:0 90 -keyint_min:v:0 90 -r:v:0 30 -x264-params:v:0 scenecut=0:open_gop=0 -bufsize:v:0 1088k -profile:v:0 high -map a:0? -c:a:0 copy -preset veryfast -map v:0 -c:v:1 libx264 -b:v:1 3308k -maxrate:v:1 3572k -g:v:1 72 -keyint_min:v:1 72 -r:v:1 24 -x264-params:v:1 scenecut=0:open_gop=0 -bufsize:v:1 3572k -profile:v:1 high -map a:0? -c:a:1 copy -preset fast -map v:0 -c:v:2 copy -map a:0? -c:a:2 copy -preset ultrafast -var_stream_map v:0,a:0 v:1,a:1 v:2,a:2 -f hls -hls_time 3 -hls_list_size 10 -hls_flags program_date_time+independent_segments+omit_endlist -hls_segment_type fmp4 -hls_fmp4_init_filename init.mp4 -bsf:a aac_adtstoasc -tune zerolatency -pix_fmt yuv420p -sc_threshold 0 -master_pl_name stream.m3u8 -hls_segment_filename http://127.0.0.1:8123/%v/stream-jdofFGg-%d.m4s -max_muxing_queue_size 400 -method PUT http://127.0.0.1:8123/%v/stream.m3u8`
|
||||
|
||||
if cmd != expected {
|
||||
t.Errorf("ffmpeg command does not match expected.\nGot %s\n, want: %s", cmd, expected)
|
||||
|
||||
Reference in New Issue
Block a user