stage borrowed video frames on render thread
This commit is contained in:
+56
-21
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"mxl-player/internal/imgui"
|
||||
"mxl-player/internal/playback"
|
||||
"mxl-player/internal/renderer"
|
||||
"mxl-player/internal/sdl"
|
||||
"mxl-player/internal/source"
|
||||
@@ -359,7 +360,7 @@ func main() {
|
||||
}
|
||||
// One control channel: grant (empty params) or reconnect (with params).
|
||||
control := make(chan reconnectParams, 1)
|
||||
staged := make(chan uint64)
|
||||
videoBridge := playback.NewVideoBridge()
|
||||
|
||||
reopen := func(params reconnectParams) error {
|
||||
// Close current sources
|
||||
@@ -529,9 +530,7 @@ func main() {
|
||||
continue
|
||||
}
|
||||
|
||||
var payload []byte
|
||||
var grainIdx uint64
|
||||
|
||||
var videoFrame playback.VideoFrame
|
||||
if syncSrc != nil {
|
||||
vFrame, aFrame, err := syncSrc.NextSync(ctx, audioBatch, 200*time.Millisecond)
|
||||
if err != nil {
|
||||
@@ -551,8 +550,15 @@ func main() {
|
||||
}
|
||||
continue
|
||||
}
|
||||
payload = vFrame.Payload
|
||||
grainIdx = vFrame.Index
|
||||
videoFrame = playback.VideoFrame{
|
||||
Index: vFrame.Index,
|
||||
Width: vFrame.Width,
|
||||
Height: vFrame.Height,
|
||||
Stride: vFrame.Stride,
|
||||
Size: vFrame.Size,
|
||||
Invalid: vFrame.Invalid,
|
||||
Payload: vFrame.Payload,
|
||||
}
|
||||
if aFrame.Samples != nil && audioStream != 0 {
|
||||
sdl.PutAudioStreamData(audioStream, interleaveAudio(aFrame.Samples))
|
||||
}
|
||||
@@ -575,16 +581,22 @@ func main() {
|
||||
}
|
||||
continue
|
||||
}
|
||||
payload = f.Payload
|
||||
grainIdx = f.Index
|
||||
videoFrame = playback.VideoFrame{
|
||||
Index: f.Index,
|
||||
Width: f.Width,
|
||||
Height: f.Height,
|
||||
Stride: f.Stride,
|
||||
Size: f.Size,
|
||||
Invalid: f.Invalid,
|
||||
Payload: f.Payload,
|
||||
}
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
vk.CopyToMapped(r.StagingMapped(), payload)
|
||||
}
|
||||
select {
|
||||
case staged <- grainIdx:
|
||||
case <-ctx.Done():
|
||||
if err := videoBridge.ConsumeVideo(ctx, videoFrame); err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
log.Printf("video output: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -661,15 +673,38 @@ func main() {
|
||||
}
|
||||
var shownIndex uint64
|
||||
hasFrame := false
|
||||
select {
|
||||
case shownIndex = <-staged:
|
||||
|
||||
frameCtx, frameCancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||
pendingFrame, frameErr := videoBridge.Next(frameCtx)
|
||||
frameCancel()
|
||||
|
||||
if pendingFrame != nil {
|
||||
var stageErr error
|
||||
if r != nil {
|
||||
stageErr = r.StageFrame(
|
||||
pendingFrame.Frame.Payload,
|
||||
pendingFrame.Frame.Width,
|
||||
pendingFrame.Frame.Height,
|
||||
pendingFrame.Frame.Stride,
|
||||
)
|
||||
}
|
||||
|
||||
// Release the borrowed payload before reacting to a staging error
|
||||
pendingFrame.Complete(stageErr)
|
||||
|
||||
if stageErr != nil {
|
||||
panic(stageErr)
|
||||
}
|
||||
|
||||
shownIndex = pendingFrame.Frame.Index
|
||||
granted = false
|
||||
hasFrame = true
|
||||
case <-ctx.Done():
|
||||
running = false
|
||||
continue
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
// No frame staged. Reset granted so we re-grant on next iteration.
|
||||
} else if frameErr != nil &&
|
||||
!errors.Is(frameErr, context.DeadlineExceeded) &&
|
||||
!errors.Is(frameErr, context.Canceled) {
|
||||
panic(frameErr)
|
||||
} else {
|
||||
// No frame arrived before the deadline.
|
||||
granted = false
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user