193 lines
3.7 KiB
Go
193 lines
3.7 KiB
Go
package frame
|
|
|
|
import (
|
|
"git.gammaspectra.live/S.O.N.G/Ignite/color"
|
|
"git.gammaspectra.live/S.O.N.G/Ignite/utilities"
|
|
"sync/atomic"
|
|
)
|
|
|
|
type Stream struct {
|
|
properties StreamProperties
|
|
channel chan Frame
|
|
lock atomic.Bool
|
|
}
|
|
|
|
func NewStream(properties StreamProperties) (*Stream, chan Frame) {
|
|
s := &Stream{
|
|
properties: properties,
|
|
channel: make(chan Frame),
|
|
}
|
|
return s, s.channel
|
|
}
|
|
|
|
type StreamProperties struct {
|
|
// Width could be not populated until the first frame is read. Frame can contain different settings.
|
|
Width int
|
|
// Height could be not populated until the first frame is read. Frame can contain different settings.
|
|
Height int
|
|
// PixelAspectRatio could be not populated until the first frame is read. Frame can contain different settings.
|
|
PixelAspectRatio utilities.Ratio
|
|
// ColorSpace could be not populated until the first frame is read. Frame can contain different settings.
|
|
ColorSpace color.Space
|
|
FrameRate utilities.Ratio
|
|
FullColorRange bool
|
|
}
|
|
|
|
func (p StreamProperties) FrameProperties() Properties {
|
|
return Properties{
|
|
Width: p.Width,
|
|
Height: p.Height,
|
|
PixelAspectRatio: p.PixelAspectRatio,
|
|
ColorSpace: p.ColorSpace,
|
|
FullColorRange: p.FullColorRange,
|
|
}
|
|
}
|
|
|
|
func (s *Stream) Properties() StreamProperties {
|
|
return s.properties
|
|
}
|
|
|
|
// Channel gets the Frame channel, and locks the input
|
|
func (s *Stream) Channel() chan Frame {
|
|
if s.Lock() {
|
|
return s.channel
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Lock locks the input, and returns success
|
|
func (s *Stream) Lock() bool {
|
|
return !s.lock.Swap(true)
|
|
}
|
|
|
|
// Unlock unlocks the input, and returns the old value
|
|
func (s *Stream) Unlock() bool {
|
|
return s.lock.Swap(false)
|
|
}
|
|
|
|
// Copy copies the stream n times
|
|
func (s *Stream) Copy(n int) []*Stream {
|
|
if !s.Lock() {
|
|
return nil
|
|
}
|
|
slice := make([]*Stream, n)
|
|
for i := range slice {
|
|
slice[i], _ = NewStream(s.Properties())
|
|
}
|
|
|
|
go func() {
|
|
defer func() {
|
|
for _, sliceItem := range slice {
|
|
close(sliceItem.channel)
|
|
}
|
|
}()
|
|
|
|
for f := range s.channel {
|
|
for _, sliceItem := range slice {
|
|
sliceItem.channel <- f
|
|
}
|
|
}
|
|
}()
|
|
|
|
return slice
|
|
}
|
|
|
|
// Slice produces a slice of the stream, and locks the input
|
|
func (s *Stream) Slice(start, end int) *Stream {
|
|
if end < start {
|
|
return nil
|
|
}
|
|
if !s.Lock() {
|
|
return nil
|
|
}
|
|
slice, channel := NewStream(s.Properties())
|
|
|
|
var index int
|
|
go func() {
|
|
defer func() {
|
|
//empty source channel
|
|
for range s.channel {
|
|
|
|
}
|
|
}()
|
|
defer close(channel)
|
|
for f := range s.channel {
|
|
if index >= end {
|
|
break
|
|
}
|
|
|
|
if index >= start {
|
|
channel <- f
|
|
}
|
|
index++
|
|
}
|
|
}()
|
|
|
|
return slice
|
|
}
|
|
|
|
// Split produces several Stream across each split point, and locks the input.
|
|
// For example, splits = [2, 5, 20] will produce 4 Stream, [0-1], [2-4], [5-19], [20-...]
|
|
func (s *Stream) Split(splits ...int) []*Stream {
|
|
if len(splits) == 0 {
|
|
return []*Stream{s}
|
|
} else if !s.Lock() {
|
|
return nil
|
|
}
|
|
slice := make([]*Stream, len(splits)+1)
|
|
for i := range slice {
|
|
slice[i], _ = NewStream(s.Properties())
|
|
}
|
|
|
|
var index int
|
|
go func() {
|
|
defer func() {
|
|
//empty source channel
|
|
for range s.channel {
|
|
|
|
}
|
|
}()
|
|
defer func() {
|
|
for _, sC := range slice {
|
|
close(sC.channel)
|
|
}
|
|
}()
|
|
|
|
for f := range s.channel {
|
|
for len(splits) > 0 && index >= splits[0] {
|
|
close(slice[0].channel)
|
|
splits = splits[1:]
|
|
slice = slice[1:]
|
|
}
|
|
|
|
slice[0].channel <- f
|
|
|
|
index++
|
|
}
|
|
}()
|
|
|
|
return slice
|
|
}
|
|
|
|
// Sample samples frames every each Frame, and locks the input
|
|
func (s *Stream) Sample(each int) *Stream {
|
|
if !s.Lock() {
|
|
return nil
|
|
}
|
|
slice, channel := NewStream(s.Properties())
|
|
|
|
var index int
|
|
go func() {
|
|
defer close(channel)
|
|
for f := range s.channel {
|
|
if index%each == 0 {
|
|
channel <- f
|
|
}
|
|
index++
|
|
}
|
|
}()
|
|
|
|
return slice
|
|
}
|