package main import ( "fmt" "image" "log" "strings" "github.com/asticode/go-astiav" ) func main() { // Handle ffmpeg logs astiav.SetLogLevel(astiav.LogLevelDebug) astiav.SetLogCallback(func(c astiav.Classer, l astiav.LogLevel, fmt, msg string) { var cs string if c != nil { if cl := c.Class(); cl != nil { cs = " - class: " + cl.String() } } log.Printf("ffmpeg log: %s%s - level: %d\n", strings.TrimSpace(msg), cs, l) }) /* In this first part we're going to manipulate an audio frame */ // Allocate frame audioFrame := astiav.AllocFrame() defer audioFrame.Free() // To write data manually into a frame, proper attributes need to be set and allocated audioFrame.SetChannelLayout(astiav.ChannelLayoutStereo) audioFrame.SetNbSamples(960) audioFrame.SetSampleFormat(astiav.SampleFormatFlt) audioFrame.SetSampleRate(48000) // Allocate buffer align := 0 if err := audioFrame.AllocBuffer(align); err != nil { log.Fatal(fmt.Errorf("main: allocating buffer failed: %w", err)) } // When writing data manually into a frame, you need to make sure the frame is writable if err := audioFrame.MakeWritable(); err != nil { log.Fatal(fmt.Errorf("main: making frame writable failed: %w", err)) } // Let's say b1 contains an actual audio buffer, we can update the audio frame's data based on the buffer var b1 []byte if err := audioFrame.Data().SetBytes(b1, align); err != nil { log.Fatal(fmt.Errorf("main: setting frame's data based from bytes failed: %w", err)) } // We can also retrieve the audio frame's data as buffer if _, err := audioFrame.Data().Bytes(align); err != nil { log.Fatal(fmt.Errorf("main: getting frame's data as bytes failed: %w", err)) } /* In this second part we're going to manipulate a video frame */ // Allocate frame videoFrame := astiav.AllocFrame() defer videoFrame.Free() // To write data manually into a frame, proper attributes need to be set and allocated videoFrame.SetHeight(256) videoFrame.SetPixelFormat(astiav.PixelFormatRgba) videoFrame.SetWidth(256) // Allocate buffer align = 1 if err := videoFrame.AllocBuffer(align); err != nil { log.Fatal(fmt.Errorf("main: allocating buffer failed: %w", err)) } // When writing data manually into a frame, you need to make sure the frame is writable if err := videoFrame.MakeWritable(); err != nil { log.Fatal(fmt.Errorf("main: making frame writable failed: %w", err)) } // Let's say b2 contains an actual video buffer, we can update the video frame's data based on the buffer var b2 []byte if err := videoFrame.Data().SetBytes(b2, align); err != nil { log.Fatal(fmt.Errorf("main: setting frame's data based from bytes failed: %w", err)) } // We can also retrieve the video frame's data as buffer if _, err := videoFrame.Data().Bytes(align); err != nil { log.Fatal(fmt.Errorf("main: getting frame's data as bytes failed: %w", err)) } // Let's say i1 is an actual Go image.Image, we can update the video frame's data based on the image var i1 image.Image if err := videoFrame.Data().FromImage(i1); err != nil { log.Fatal(fmt.Errorf("main: setting frame's data based on Go image failed: %w", err)) } // We can also retrieve the video frame's data as a Go image // For that we first need to guess the Go image format based on the frame's attributes before providing // it to .ToImage(). You may not need this and can provide your own image.Image to .ToImage() i2, err := videoFrame.Data().GuessImageFormat() if err != nil { log.Fatal(fmt.Errorf("main: guessing image format failed: %w", err)) } if err := videoFrame.Data().ToImage(i2); err != nil { log.Fatal(fmt.Errorf("main: getting frame's data as Go image failed: %w", err)) } // Success log.Println("success") }