74 lines
2.1 KiB
Go
74 lines
2.1 KiB
Go
package generator
|
|
|
|
import "fmt"
|
|
|
|
// V210AGenerator combines a v210 fill generator with a packed 10-bit alpha
|
|
// plane. It owns the fill generator and closes it from Close.
|
|
type V210AGenerator struct {
|
|
fill FrameGenerator
|
|
width int
|
|
height int
|
|
fillSize int
|
|
fillBase []byte
|
|
alphaBase []byte
|
|
}
|
|
|
|
var _ FrameGenerator = (*V210AGenerator)(nil)
|
|
|
|
func NewV210AGenerator(
|
|
fill FrameGenerator,
|
|
width, height uint,
|
|
fillDynamic bool,
|
|
) (*V210AGenerator, error) {
|
|
if fill == nil {
|
|
return nil, fmt.Errorf("v210a: fill generator is nil")
|
|
}
|
|
if width == 0 || height == 0 {
|
|
return nil, fmt.Errorf("v210a: width and height must be greater than zero, got %dx%d", width, height)
|
|
}
|
|
if width%2 != 0 {
|
|
return nil, fmt.Errorf("v210a: width must be even for 4:2:2 video, got %d", width)
|
|
}
|
|
|
|
g := &V210AGenerator{
|
|
fill: fill,
|
|
width: int(width),
|
|
height: int(height),
|
|
fillSize: V210FrameSize(int(width), int(height)),
|
|
alphaBase: make([]byte, AlphaFrameSize(int(width), int(height))),
|
|
}
|
|
if err := fillAlphaPlane(g.alphaBase, g.width, g.height, alphaOpaque); err != nil {
|
|
return nil, fmt.Errorf("v210a: initialize alpha plane: %w", err)
|
|
}
|
|
if !fillDynamic {
|
|
g.fillBase = make([]byte, g.fillSize)
|
|
if err := fill.GenerateFrame(g.fillBase, 0); err != nil {
|
|
return nil, fmt.Errorf("v210a: initialize static fill: %w", err)
|
|
}
|
|
}
|
|
return g, nil
|
|
}
|
|
|
|
func (g *V210AGenerator) GenerateFrame(dst []byte, frameIndex int) error {
|
|
need := V210AFrameSize(g.width, g.height)
|
|
if len(dst) < need {
|
|
return fmt.Errorf("v210a: destination is too small: got %d bytes, need %d", len(dst), need)
|
|
}
|
|
|
|
if g.fillBase != nil {
|
|
copy(dst[:g.fillSize], g.fillBase)
|
|
} else if err := g.fill.GenerateFrame(dst[:g.fillSize], frameIndex); err != nil {
|
|
return fmt.Errorf("v210a: generate dynamic fill frame %d: %w", frameIndex, err)
|
|
}
|
|
alpha := dst[g.fillSize:need]
|
|
copy(alpha, g.alphaBase)
|
|
if err := patchAlphaMovingSquare(alpha, g.width, g.height, frameIndex); err != nil {
|
|
return fmt.Errorf("v210a: patch alpha frame %d: %w", frameIndex, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *V210AGenerator) Close() error {
|
|
return g.fill.Close()
|
|
}
|