@@ -3,17 +3,17 @@ package main
33import (
44 "context"
55 "errors"
6- "fmt"
76 "log"
87 "os"
98 "path/filepath"
109 "runtime"
1110 "sync"
1211 "time"
12+ "unsafe"
1313
1414 // Packages
15- "github.com/mutablelogic/go-media"
16- "github.com/mutablelogic/go-media/pkg/ffmpeg"
15+ media "github.com/mutablelogic/go-media"
16+ ffmpeg "github.com/mutablelogic/go-media/pkg/ffmpeg"
1717 sdl "github.com/veandco/go-sdl2/sdl"
1818)
1919
@@ -41,12 +41,6 @@ func (s *Context) Close() error {
4141 return nil
4242}
4343
44- func (s * Context ) PushQuitEvent () {
45- sdl .PushEvent (& sdl.QuitEvent {
46- Type : sdl .QUIT ,
47- })
48- }
49-
5044func (s * Context ) NewWindow (title string , width , height int32 ) (* Window , error ) {
5145 window , err := sdl .CreateWindow (
5246 title ,
@@ -67,7 +61,6 @@ func (s *Context) NewWindow(title string, width, height int32) (*Window, error)
6761 window .Destroy ()
6862 return nil , err
6963 }
70-
7164 return & Window {window , renderer , texture }, nil
7265}
7366
@@ -82,6 +75,7 @@ func (w *Window) Close() error {
8275 if err := (* sdl .Window )(w .Window ).Destroy (); err != nil {
8376 result = errors .Join (result , err )
8477 }
78+ w .Texture = nil
8579 w .Renderer = nil
8680 w .Window = nil
8781
@@ -109,26 +103,63 @@ func (w *Window) RenderFrame(frame *ffmpeg.Frame) error {
109103 )
110104}
111105
112- func (s * Context ) RunLoop () {
106+ func (s * Context ) RunLoop (w * Window , evt uint32 ) {
113107 runtime .LockOSThread ()
114108 running := true
109+
110+ pts := ffmpeg .TS_UNDEFINED
115111 for running {
116112 for event := sdl .PollEvent (); event != nil ; event = sdl .PollEvent () {
117113 switch event .(type ) {
118114 case * sdl.QuitEvent :
119115 running = false
120116 break
117+ case * sdl.UserEvent :
118+ if event .(* sdl.UserEvent ).Type != evt {
119+ break
120+ }
121+
122+ // Get the video frame - if nil, then end of stream
123+ frame := (* ffmpeg .Frame )(event .(* sdl.UserEvent ).Data1 )
124+ if frame == nil {
125+ running = false
126+ break
127+ }
128+
129+ // Pause to present the frame at the correct PTS
130+ if pts != ffmpeg .TS_UNDEFINED && pts < frame .Ts () {
131+ pause := frame .Ts () - pts
132+ if pause > 0 {
133+ sdl .Delay (uint32 (pause * 1000 ))
134+ }
135+ }
136+
137+ // Set current timestamp
138+ pts = frame .Ts ()
139+
140+ // Render the frame, release the frame resources
141+ if err := w .RenderFrame (frame ); err != nil {
142+ log .Print (err )
143+ } else if err := w .Flush (); err != nil {
144+ log .Print (err )
145+ } else if err := frame .Close (); err != nil {
146+ log .Print (err )
147+ }
148+
121149 }
122150 }
123151 }
124152}
125153
126154func main () {
127- sdl , err := NewSDL ()
155+ ctx , err := NewSDL ()
128156 if err != nil {
129157 log .Fatal (err )
130158 }
131- defer sdl .Close ()
159+ defer ctx .Close ()
160+
161+ // Register an event for a new frame
162+ evt := sdl .RegisterEvents (1 )
132163
133164 // Open video
134165 input , err := ffmpeg .Open (os .Args [1 ])
@@ -151,24 +182,28 @@ func main() {
151182 return nil , nil
152183 }
153184
154- ch := make (chan * ffmpeg.Frame )
155-
156185 wg .Add (1 )
157186 go func () {
158187 defer wg .Done ()
159188 err := input .Decode (context .Background (), mapfn , func (stream int , frame * ffmpeg.Frame ) error {
160- ch <- frame
189+ copy , err := frame .Copy ()
190+ if err != nil {
191+ copy .Close ()
192+ return err
193+ }
194+ sdl .PushEvent (& sdl.UserEvent {
195+ Type : evt ,
196+ Data1 : unsafe .Pointer (copy ),
197+ })
161198 return nil
162199 })
163200 if err != nil {
164201 result = errors .Join (result , err )
165202 }
166-
167- // Close channel
168- close (ch )
169-
170203 // Quit event
171- sdl .PushQuitEvent ()
204+ sdl .PushEvent (& sdl.QuitEvent {
205+ Type : sdl .QUIT ,
206+ })
172207 }()
173208
174209 // HACK
@@ -183,27 +218,15 @@ func main() {
183218 title = meta [0 ].Value ()
184219 }
185220
186- window , err := sdl .NewWindow (title , w , h )
221+ // Create a new window
222+ window , err := ctx .NewWindow (title , w , h )
187223 if err != nil {
188224 log .Fatal (err )
189225 }
190226 defer window .Close ()
191227
192- wg .Add (1 )
193- go func () {
194- defer wg .Done ()
195- for frame := range ch {
196- if err := window .RenderFrame (frame ); err != nil {
197- fmt .Println ("Error rendering frame:" , err )
198- }
199- if err := window .Flush (); err != nil {
200- fmt .Println ("Error flushing frame:" , err )
201- }
202- }
203- }()
204-
205- // Run the SDL loop
206- sdl .RunLoop ()
228+ // Run the SDL loop until quit
229+ ctx .RunLoop (window , evt )
207230
208231 // Wait until all goroutines have finished
209232 wg .Wait ()
0 commit comments