154 lines
3.5 KiB
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()
|
|
}
|
|
}
|