@@ -9,10 +9,10 @@ import (
99 "log/slog"
1010 "net/url"
1111 "os"
12+ "os/exec"
1213 "path"
1314 "strings"
14-
15- log "github.com/sirupsen/logrus"
15+ "time"
1616
1717 "github.com/tum-dev/gocast/runner/config"
1818 "github.com/tum-dev/gocast/runner/pkg/metrics"
@@ -21,7 +21,7 @@ import (
2121
2222// MkVOD takes a stream that was streamed and moves the hls stream to long term storage.
2323// Additionally, the playlist type is transformed from event to VOD.
24- func MkVOD (_ context.Context , _ * slog.Logger , notify chan * protobuf.Notification , d map [string ]any , metrics * metrics.Broker ) error {
24+ func MkVOD (ctx context.Context , logger * slog.Logger , notify chan * protobuf.Notification , d map [string ]any , metrics * metrics.Broker ) error {
2525 streamID , ok := d ["streamID" ].(uint64 )
2626 if ! ok {
2727 return AbortingError (fmt .Errorf ("no stream id in context" ))
@@ -35,6 +35,11 @@ func MkVOD(_ context.Context, _ *slog.Logger, notify chan *protobuf.Notification
3535 return AbortingError (fmt .Errorf ("no recordingDir in context" ))
3636 }
3737
38+ metrics .ConvertingProgresses .With (metrics .With ().Stream (streamID ).L ()).Inc ()
39+ defer func () {
40+ metrics .ConvertingProgresses .With (metrics .With ().Stream (streamID ).L ()).Dec ()
41+ }()
42+
3843 vodDir := path .Join (config .Config .StoragePath , fmt .Sprintf ("%d" , streamID ), streamVersion )
3944 err := os .MkdirAll (vodDir , os .ModePerm )
4045 if err != nil {
@@ -48,27 +53,13 @@ func MkVOD(_ context.Context, _ *slog.Logger, notify chan *protobuf.Notification
4853
4954 for _ , entry := range recordingContent {
5055 if entry .IsDir () {
51- log .Warn ("found dir in recordingDir, skipping" , "name" , entry .Name ())
56+ logger .Warn ("found dir in recordingDir, skipping" , "name" , entry .Name ())
5257 continue
5358 }
5459 if entry .Name () == "playlist.m3u8" {
55- srcPlst , err := os .Open (path .Join (recordingDir , entry .Name ()))
56- if err != nil {
57- return AbortingError (fmt .Errorf ("open recording playlist: %w" , err ))
58- }
59- dstPlstS := vodFromEventPlst (srcPlst )
60- dstPlst , err := os .Create (path .Join (vodDir , entry .Name ()))
61- if err != nil {
62- return AbortingError (fmt .Errorf ("create vod playlist: %w" , err ))
63- }
64- _ , err = io .WriteString (dstPlst , dstPlstS )
65- if err != nil {
66- return fmt .Errorf ("write vod to playlist: %w" , err )
67- }
68- _ = dstPlst .Close ()
60+ err = convertStream (ctx , logger , streamID , path .Join (recordingDir , entry .Name ()), vodDir , entry .Name ())
6961 continue
7062 }
71- err = copyFile (path .Join (recordingDir , entry .Name ()), path .Join (vodDir , entry .Name ()))
7263 }
7364
7465 vodUrl , err := url .JoinPath (config .Config .EdgeServer , fmt .Sprintf ("%d" , streamID ), streamVersion , "playlist.m3u8" )
@@ -87,24 +78,36 @@ func MkVOD(_ context.Context, _ *slog.Logger, notify chan *protobuf.Notification
8778 return nil
8879}
8980
90- func copyFile (sourcePath , destPath string ) error {
91- inputFile , err := os .Open (sourcePath )
81+ func convertStream (ctx context.Context , logger * slog.Logger , streamID uint64 , streamPath , vodDir string , playlistName string ) error {
82+ input := "-i " + streamPath
83+ options := "-c copy -f hls -hls_time 240 -hls_playlist_type event -hls_flags append_list -hls_segment_filename " + path .Join (vodDir , "%05d.ts" ) + " " + path .Join (vodDir , playlistName )
84+
85+ args := strings .Split (input , " " )
86+ args = append (args , strings .Split (options , " " )... )
87+ command := exec .CommandContext (ctx , "ffmpeg" , args ... )
88+
89+ // give ffmpeg 10 seconds on sigterm (context cancellation) to shut down before sending sigkill.
90+ command .WaitDelay = 10 * time .Second
91+
92+ logger .Info ("starting ffmpeg" , "command" , command .String ())
93+ stderr , err := command .StderrPipe ()
9294 if err != nil {
93- return fmt . Errorf ( "open source file: %w" , err )
95+ return err
9496 }
95- defer inputFile . Close ( )
97+ go logCmdPipe ( logger , stderr , [] any { "stream" , streamID , "logStream" , "stderr" } )
9698
97- outputFile , err := os . Create ( destPath )
99+ stdo , err := command . StdoutPipe ( )
98100 if err != nil {
99- return fmt . Errorf ( "open dest file: %w" , err )
101+ return err
100102 }
101- defer outputFile .Close ()
102-
103- _ , err = io .Copy (outputFile , inputFile )
103+ go logCmdPipe (logger , stdo , []any {"stream" , streamID , "logStream" , "stdout" })
104+ err = command .Run ()
104105 if err != nil {
105- return fmt .Errorf ("copy to dest from source: %w" , err )
106+ logger .Error ("ffmpeg command failed" , "error" , err )
107+ } else {
108+ logger .Info ("ffmpeg converting completed successfully" , "stream_id" , streamID )
106109 }
107- return nil
110+ return err
108111}
109112
110113// vodFromEventPlst modifies an HLS playlist from EVENT to VOD
0 commit comments