Major improvements to UnifiedPlayer: 1. GetFrameImage() now works when paused for responsive UI updates 2. Play() method properly starts FFmpeg process 3. Frame display loop runs continuously for smooth video display 4. Disabled audio temporarily to fix video playback fundamentals 5. Simplified FFmpeg command to focus on video stream only Player now: - Generates video frames correctly - Shows video when paused - Has responsive progress tracking - Starts playback properly Next steps: Re-enable audio playback once video is stable
201 lines
5.1 KiB
Go
201 lines
5.1 KiB
Go
package canvas
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
"image/draw"
|
|
|
|
"fyne.io/fyne/v2"
|
|
)
|
|
|
|
// Declare conformity with CanvasObject interface
|
|
var _ fyne.CanvasObject = (*Raster)(nil)
|
|
|
|
// Raster describes a raster image area that can render in a Fyne canvas
|
|
type Raster struct {
|
|
baseObject
|
|
|
|
// Render the raster image from code
|
|
Generator func(w, h int) image.Image
|
|
|
|
// Set a translucency value > 0.0 to fade the raster
|
|
Translucency float64
|
|
// Specify the type of scaling interpolation applied to the raster if it is not full-size
|
|
// Since: 1.4.1
|
|
ScaleMode ImageScale
|
|
}
|
|
|
|
// Alpha is a convenience function that returns the alpha value for a raster
|
|
// based on its Translucency value. The result is 1.0 - Translucency.
|
|
func (r *Raster) Alpha() float64 {
|
|
return 1.0 - r.Translucency
|
|
}
|
|
|
|
// Hide will set this raster to not be visible
|
|
func (r *Raster) Hide() {
|
|
r.baseObject.Hide()
|
|
|
|
repaint(r)
|
|
}
|
|
|
|
// Move the raster to a new position, relative to its parent / canvas
|
|
func (r *Raster) Move(pos fyne.Position) {
|
|
if r.Position() == pos {
|
|
return
|
|
}
|
|
|
|
r.baseObject.Move(pos)
|
|
|
|
repaint(r)
|
|
}
|
|
|
|
// Resize on a raster image causes the new size to be set and then calls Refresh.
|
|
// This causes the underlying data to be recalculated and a new output to be drawn.
|
|
func (r *Raster) Resize(s fyne.Size) {
|
|
if s == r.Size() {
|
|
return
|
|
}
|
|
|
|
r.baseObject.Resize(s)
|
|
Refresh(r)
|
|
}
|
|
|
|
// Refresh causes this raster to be redrawn with its configured state.
|
|
func (r *Raster) Refresh() {
|
|
Refresh(r)
|
|
}
|
|
|
|
// NewRaster returns a new Image instance that is rendered dynamically using
|
|
// the specified generate function.
|
|
// Images returned from this method should draw dynamically to fill the width
|
|
// and height parameters passed to pixelColor.
|
|
func NewRaster(generate func(w, h int) image.Image) *Raster {
|
|
return &Raster{Generator: generate}
|
|
}
|
|
|
|
type pixelRaster struct {
|
|
r *Raster
|
|
|
|
img draw.Image
|
|
}
|
|
|
|
// NewRasterWithPixels returns a new Image instance that is rendered dynamically
|
|
// by iterating over the specified pixelColor function for each x, y pixel.
|
|
// Images returned from this method should draw dynamically to fill the width
|
|
// and height parameters passed to pixelColor.
|
|
func NewRasterWithPixels(pixelColor func(x, y, w, h int) color.Color) *Raster {
|
|
pix := &pixelRaster{}
|
|
pix.r = &Raster{
|
|
Generator: func(w, h int) image.Image {
|
|
if pix.img == nil || pix.img.Bounds().Size().X != w || pix.img.Bounds().Size().Y != h {
|
|
// raster first pixel, figure out color type
|
|
var dst draw.Image
|
|
rect := image.Rect(0, 0, w, h)
|
|
switch pixelColor(0, 0, w, h).(type) {
|
|
case color.Alpha:
|
|
dst = image.NewAlpha(rect)
|
|
case color.Alpha16:
|
|
dst = image.NewAlpha16(rect)
|
|
case color.CMYK:
|
|
dst = image.NewCMYK(rect)
|
|
case color.Gray:
|
|
dst = image.NewGray(rect)
|
|
case color.Gray16:
|
|
dst = image.NewGray16(rect)
|
|
case color.NRGBA:
|
|
dst = image.NewNRGBA(rect)
|
|
case color.NRGBA64:
|
|
dst = image.NewNRGBA64(rect)
|
|
case color.RGBA:
|
|
dst = image.NewRGBA(rect)
|
|
case color.RGBA64:
|
|
dst = image.NewRGBA64(rect)
|
|
default:
|
|
dst = image.NewRGBA(rect)
|
|
}
|
|
pix.img = dst
|
|
}
|
|
|
|
for y := 0; y < h; y++ {
|
|
for x := 0; x < w; x++ {
|
|
pix.img.Set(x, y, pixelColor(x, y, w, h))
|
|
}
|
|
}
|
|
|
|
return pix.img
|
|
},
|
|
}
|
|
return pix.r
|
|
}
|
|
|
|
type subImg interface {
|
|
SubImage(r image.Rectangle) image.Image
|
|
}
|
|
|
|
// NewRasterFromImage returns a new Raster instance that is rendered from the Go
|
|
// image.Image passed in.
|
|
// Rasters returned from this method will map pixel for pixel to the screen
|
|
// starting img.Bounds().Min pixels from the top left of the canvas object.
|
|
// Truncates rather than scales the image.
|
|
// If smaller than the target space, the image will be padded with zero-pixels to the target size.
|
|
func NewRasterFromImage(img image.Image) *Raster {
|
|
return &Raster{
|
|
Generator: func(w int, h int) image.Image {
|
|
bounds := img.Bounds()
|
|
|
|
rect := image.Rect(0, 0, w, h)
|
|
|
|
switch {
|
|
case w == bounds.Max.X && h == bounds.Max.Y:
|
|
return img
|
|
case w >= bounds.Max.X && h >= bounds.Max.Y:
|
|
// try quickly truncating
|
|
if sub, ok := img.(subImg); ok {
|
|
return sub.SubImage(image.Rectangle{
|
|
Min: bounds.Min,
|
|
Max: image.Point{
|
|
X: bounds.Min.X + w,
|
|
Y: bounds.Min.Y + h,
|
|
},
|
|
})
|
|
}
|
|
default:
|
|
if !rect.Overlaps(bounds) {
|
|
return image.NewUniform(color.RGBA{})
|
|
}
|
|
bounds = bounds.Intersect(rect)
|
|
}
|
|
|
|
// respect the user's pixel format (if possible)
|
|
var dst draw.Image
|
|
switch i := img.(type) {
|
|
case *image.Alpha:
|
|
dst = image.NewAlpha(rect)
|
|
case *image.Alpha16:
|
|
dst = image.NewAlpha16(rect)
|
|
case *image.CMYK:
|
|
dst = image.NewCMYK(rect)
|
|
case *image.Gray:
|
|
dst = image.NewGray(rect)
|
|
case *image.Gray16:
|
|
dst = image.NewGray16(rect)
|
|
case *image.NRGBA:
|
|
dst = image.NewNRGBA(rect)
|
|
case *image.NRGBA64:
|
|
dst = image.NewNRGBA64(rect)
|
|
case *image.Paletted:
|
|
dst = image.NewPaletted(rect, i.Palette)
|
|
case *image.RGBA:
|
|
dst = image.NewRGBA(rect)
|
|
case *image.RGBA64:
|
|
dst = image.NewRGBA64(rect)
|
|
default:
|
|
dst = image.NewRGBA(rect)
|
|
}
|
|
|
|
draw.Draw(dst, bounds, img, bounds.Min, draw.Over)
|
|
return dst
|
|
},
|
|
}
|
|
}
|