Ignite/utilities/frameserver/frameserver.go

154 lines
3.5 KiB
Go

package frameserver
import (
"git.gammaspectra.live/S.O.N.G/Ignite/decoder/y4m"
"git.gammaspectra.live/S.O.N.G/Ignite/frame"
"io"
"sync"
)
type FrameServer struct {
readerLock sync.Mutex
decoder *y4m.Decoder
}
func New(reader io.ReadSeeker, cachedFrameSeekTable []int64) *FrameServer {
s := &FrameServer{}
var err error
settings := make(map[string]any)
settings["seek_table"] = cachedFrameSeekTable
if s.decoder, err = y4m.NewDecoder(reader, settings); err != nil {
return nil
}
return s
}
func NewXZCompressed(reader io.ReadSeeker, cachedFrameSeekTable []int64) *FrameServer {
s := &FrameServer{}
var err error
settings := make(map[string]any)
settings["seek_table"] = cachedFrameSeekTable
if s.decoder, err = y4m.NewXZCompressedDecoder(reader, settings); err != nil {
return nil
}
return s
}
func (s *FrameServer) GetFrameSeekTable() []int64 {
s.readerLock.Lock()
defer s.readerLock.Unlock()
return s.decoder.GetFrameSeekTable()
}
// GetAllFrames gets all frames from start to end. Locks on every iteration. See GetAllFramesLock
func (s *FrameServer) GetAllFrames() *frame.Stream {
frameNumber := 0
stream, channel := frame.NewStream(s.decoder.Properties())
go func() {
defer close(channel)
for {
if f, err := s.GetFrame(frameNumber); err != nil {
return
} else {
channel <- f
}
frameNumber++
}
}()
return stream
}
// GetAllFramesLock gets all frames from start to end. Locks on every iteration. See GetAllFramesLock
func (s *FrameServer) GetAllFramesLock() *frame.Stream {
s.readerLock.Lock()
defer s.readerLock.Unlock()
frameNumber := 0
if err := s.decoder.SeekToFrame(frameNumber); err != nil {
return nil
} else {
stream, channel := frame.NewStream(s.decoder.Properties())
go func() {
defer close(channel)
for {
if f, err := s.decoder.Decode(); err != nil {
return
} else {
channel <- f
}
frameNumber++
}
}()
return stream
}
}
// GetFrames gets a range of frames, like a slice [0, 1] will return just one frame.Frame. Locks on every iteration. See GetFramesLock
func (s *FrameServer) GetFrames(startFrameNumber, endFrameNumber int) *frame.Stream {
if endFrameNumber < startFrameNumber {
return nil
}
frameNumber := startFrameNumber
stream, channel := frame.NewStream(s.decoder.Properties())
go func() {
defer close(channel)
for frameNumber < endFrameNumber {
if f, err := s.GetFrame(frameNumber); err != nil {
return
} else {
channel <- f
}
frameNumber++
}
}()
return stream
}
// GetFramesLock gets a range of frames, but locks during all of them. See GetFrames
func (s *FrameServer) GetFramesLock(startFrameNumber, endFrameNumber int) *frame.Stream {
if endFrameNumber < startFrameNumber {
return nil
}
s.readerLock.Lock()
defer s.readerLock.Unlock()
frameNumber := startFrameNumber
//todo: spawn new frame.Stream or just use GetFrame()?
if err := s.decoder.SeekToFrame(frameNumber); err != nil {
return nil
} else {
stream, channel := frame.NewStream(s.decoder.Properties())
go func() {
defer close(channel)
for frameNumber < endFrameNumber {
if f, err := s.decoder.Decode(); err != nil {
return
} else {
channel <- f
}
frameNumber++
}
}()
return stream
}
}
func (s *FrameServer) GetFrame(frameNumber int) (f frame.Frame, err error) {
s.readerLock.Lock()
defer s.readerLock.Unlock()
if err = s.decoder.SeekToFrame(frameNumber); err != nil {
return nil, err
} else {
return s.decoder.Decode()
}
}