Made all examples more consistent regarding unreferencing packets/frames

This commit is contained in:
Quentin Renard
2024-11-14 13:50:35 +01:00
parent b15d5d0e04
commit 6eb04b4fd9
10 changed files with 414 additions and 280 deletions

View File

@@ -42,11 +42,11 @@ func main() {
return return
} }
// Alloc packet // Allocate packet
pkt := astiav.AllocPacket() pkt := astiav.AllocPacket()
defer pkt.Free() defer pkt.Free()
// Alloc input format context // Allocate input format context
inputFormatContext := astiav.AllocFormatContext() inputFormatContext := astiav.AllocFormatContext()
if inputFormatContext == nil { if inputFormatContext == nil {
log.Fatal(errors.New("main: input format context is nil")) log.Fatal(errors.New("main: input format context is nil"))
@@ -76,7 +76,7 @@ func main() {
// Create stream // Create stream
s := &stream{} s := &stream{}
// Alloc packet // Allocate packet
s.bitStreamPkt = astiav.AllocPacket() s.bitStreamPkt = astiav.AllocPacket()
defer s.bitStreamPkt.Free() defer s.bitStreamPkt.Free()
@@ -86,7 +86,7 @@ func main() {
log.Fatal(errors.New("main: bit stream filter is nil")) log.Fatal(errors.New("main: bit stream filter is nil"))
} }
// Alloc bit stream filter context // Allocate bit stream filter context
var err error var err error
if s.bitStreamFilterContext, err = astiav.AllocBitStreamFilterContext(bsf); err != nil { if s.bitStreamFilterContext, err = astiav.AllocBitStreamFilterContext(bsf); err != nil {
log.Fatal(fmt.Errorf("main: allocating bit stream filter context failed: %w", err)) log.Fatal(fmt.Errorf("main: allocating bit stream filter context failed: %w", err))
@@ -112,23 +112,32 @@ func main() {
// Loop through packets // Loop through packets
for { for {
// Read frame // We use a closure to ease unreferencing the packet
if err := inputFormatContext.ReadFrame(pkt); err != nil { if stop := func() bool {
if errors.Is(err, astiav.ErrEof) { // Read frame
break if err := inputFormatContext.ReadFrame(pkt); err != nil {
if errors.Is(err, astiav.ErrEof) {
return true
}
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
} }
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
}
// Get stream // Make sure to unreference the packet
s, ok := streams[pkt.StreamIndex()] defer pkt.Unref()
if !ok {
continue
}
// Filter bit stream // Get stream
if err := filterBitStream(pkt, s); err != nil { s, ok := streams[pkt.StreamIndex()]
log.Fatal(fmt.Errorf("main: filtering bit stream failed: %w", err)) if !ok {
return false
}
// Filter bit stream
if err := filterBitStream(pkt, s); err != nil {
log.Fatal(fmt.Errorf("main: filtering bit stream failed: %w", err))
}
return false
}(); stop {
break
} }
} }
@@ -152,19 +161,27 @@ func filterBitStream(pkt *astiav.Packet, s *stream) error {
// Loop // Loop
for { for {
// Receive packet // We use a closure to ease unreferencing the packet
if err := s.bitStreamFilterContext.ReceivePacket(s.bitStreamPkt); err != nil { if stop, err := func() (bool, error) {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { // Receive packet
break if err := s.bitStreamFilterContext.ReceivePacket(s.bitStreamPkt); err != nil {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
return true, nil
}
return false, fmt.Errorf("main: receiving packet failed: %w", err)
} }
return fmt.Errorf("main: receiving packet failed: %w", err)
// Make sure to unreference the packet
defer s.bitStreamPkt.Unref()
// Do something with packet
log.Printf("new filtered packet: stream %d - pts: %d", s.bitStreamPkt.StreamIndex(), s.bitStreamPkt.Pts())
return false, nil
}(); err != nil {
return err
} else if stop {
break
} }
// Do something with packet
log.Printf("new filtered packet: stream %d - pts: %d", s.bitStreamPkt.StreamIndex(), s.bitStreamPkt.Pts())
// Unref packet
s.bitStreamPkt.Unref()
} }
return nil return nil
} }

View File

@@ -37,11 +37,11 @@ func main() {
return return
} }
// Alloc packet // Allocate packet
pkt := astiav.AllocPacket() pkt := astiav.AllocPacket()
defer pkt.Free() defer pkt.Free()
// Alloc input format context // Allocate input format context
inputFormatContext := astiav.AllocFormatContext() inputFormatContext := astiav.AllocFormatContext()
if inputFormatContext == nil { if inputFormatContext == nil {
log.Fatal(errors.New("main: input format context is nil")) log.Fatal(errors.New("main: input format context is nil"))
@@ -55,7 +55,7 @@ func main() {
} }
defer f.Close() defer f.Close()
// Alloc io context // Allocate io context
ioContext, err := astiav.AllocIOContext( ioContext, err := astiav.AllocIOContext(
4096, 4096,
false, false,
@@ -88,16 +88,25 @@ func main() {
// Loop through packets // Loop through packets
for { for {
// Read frame // We use a closure to ease unreferencing the packet
if err := inputFormatContext.ReadFrame(pkt); err != nil { if stop := func() bool {
if errors.Is(err, astiav.ErrEof) { // Read frame
break if err := inputFormatContext.ReadFrame(pkt); err != nil {
if errors.Is(err, astiav.ErrEof) {
return true
}
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
} }
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
}
// Do something with the packet // Make sure to unreference the packet
log.Printf("new packet: stream %d - pts: %d", pkt.StreamIndex(), pkt.Pts()) defer pkt.Unref()
// Do something with the packet
log.Printf("new packet: stream %d - pts: %d", pkt.StreamIndex(), pkt.Pts())
return false
}(); stop {
break
}
} }
// Success // Success

View File

@@ -42,15 +42,15 @@ func main() {
return return
} }
// Alloc packet // Allocate packet
pkt := astiav.AllocPacket() pkt := astiav.AllocPacket()
defer pkt.Free() defer pkt.Free()
// Alloc frame // Allocate frame
f := astiav.AllocFrame() f := astiav.AllocFrame()
defer f.Free() defer f.Free()
// Alloc input format context // Allocate input format context
inputFormatContext := astiav.AllocFormatContext() inputFormatContext := astiav.AllocFormatContext()
if inputFormatContext == nil { if inputFormatContext == nil {
log.Fatal(errors.New("main: input format context is nil")) log.Fatal(errors.New("main: input format context is nil"))
@@ -85,7 +85,7 @@ func main() {
log.Fatal(errors.New("main: codec is nil")) log.Fatal(errors.New("main: codec is nil"))
} }
// Alloc codec context // Allocate codec context
if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil { if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil {
log.Fatal(errors.New("main: codec context is nil")) log.Fatal(errors.New("main: codec context is nil"))
} }
@@ -105,39 +105,57 @@ func main() {
streams[is.Index()] = s streams[is.Index()] = s
} }
// Loop through packets // Loop
for { for {
// Read frame // We use a closure to ease unreferencing the packet
if err := inputFormatContext.ReadFrame(pkt); err != nil { if stop := func() bool {
if errors.Is(err, astiav.ErrEof) { // Read frame
break if err := inputFormatContext.ReadFrame(pkt); err != nil {
if errors.Is(err, astiav.ErrEof) {
return true
}
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
} }
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
}
// Get stream // Make sure to unreference the packet
s, ok := streams[pkt.StreamIndex()] defer pkt.Unref()
if !ok {
continue
}
// Send packet // Get stream
if err := s.decCodecContext.SendPacket(pkt); err != nil { s, ok := streams[pkt.StreamIndex()]
log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) if !ok {
} return false
}
// Loop // Send packet
for { if err := s.decCodecContext.SendPacket(pkt); err != nil {
// Receive frame log.Fatal(fmt.Errorf("main: sending packet failed: %w", err))
if err := s.decCodecContext.ReceiveFrame(f); err != nil { }
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
// Loop
for {
// We use a closure to ease unreferencing the frame
if stop := func() bool {
// Receive frame
if err := s.decCodecContext.ReceiveFrame(f); err != nil {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
return true
}
log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err))
}
// Make sure to unreference the frame
defer f.Unref()
// Log
log.Printf("new %s frame: stream %d - pts: %d", s.inputStream.CodecParameters().MediaType(), pkt.StreamIndex(), f.Pts())
return false
}(); stop {
break break
} }
log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err))
} }
return false
// Log }(); stop {
log.Printf("new %s frame: stream %d - pts: %d", s.inputStream.CodecParameters().MediaType(), pkt.StreamIndex(), f.Pts()) break
} }
} }

View File

@@ -69,44 +69,62 @@ func main() {
log.Fatal(fmt.Errorf("main: initializing filter failed: %w", err)) log.Fatal(fmt.Errorf("main: initializing filter failed: %w", err))
} }
// Alloc packet // Allocate packet
pkt := astiav.AllocPacket() pkt := astiav.AllocPacket()
c.Add(pkt.Free) c.Add(pkt.Free)
// Loop through packets // Loop through packets
for { for {
// Read frame // We use a closure to ease unreferencing the packet
if err := inputFormatContext.ReadFrame(pkt); err != nil { if stop := func() bool {
if errors.Is(err, astiav.ErrEof) { // Read frame
break if err := inputFormatContext.ReadFrame(pkt); err != nil {
if errors.Is(err, astiav.ErrEof) {
return true
}
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
} }
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
}
// Invalid stream // Make sure to unreference the packet
if pkt.StreamIndex() != s.inputStream.Index() { defer pkt.Unref()
continue
}
// Send packet // Invalid stream
if err := s.decCodecContext.SendPacket(pkt); err != nil { if pkt.StreamIndex() != s.inputStream.Index() {
log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) return false
} }
// Loop // Send packet
for { if err := s.decCodecContext.SendPacket(pkt); err != nil {
// Receive frame log.Fatal(fmt.Errorf("main: sending packet failed: %w", err))
if err := s.decCodecContext.ReceiveFrame(s.decFrame); err != nil { }
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
// Loop
for {
// We use a closure to ease unreferencing the frame
if stop := func() bool {
// Receive frame
if err := s.decCodecContext.ReceiveFrame(s.decFrame); err != nil {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
return true
}
log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err))
}
// Make sure to unreference the frame
defer s.decFrame.Unref()
// Filter frame
if err := filterFrame(s.decFrame, s); err != nil {
log.Fatal(fmt.Errorf("main: filtering frame failed: %w", err))
}
return false
}(); stop {
break break
} }
log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err))
}
// Filter frame
if err := filterFrame(s.decFrame, s); err != nil {
log.Fatal(fmt.Errorf("main: filtering frame failed: %w", err))
} }
return false
}(); stop {
break
} }
} }
@@ -120,7 +138,7 @@ func main() {
} }
func openInputFile() (err error) { func openInputFile() (err error) {
// Alloc input format context // Allocate input format context
if inputFormatContext = astiav.AllocFormatContext(); inputFormatContext == nil { if inputFormatContext = astiav.AllocFormatContext(); inputFormatContext == nil {
err = errors.New("main: input format context is nil") err = errors.New("main: input format context is nil")
return return
@@ -159,7 +177,7 @@ func openInputFile() (err error) {
return return
} }
// Alloc codec context // Allocate codec context
if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil { if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil {
err = errors.New("main: codec context is nil") err = errors.New("main: codec context is nil")
return return
@@ -178,7 +196,7 @@ func openInputFile() (err error) {
return return
} }
// Alloc frame // Allocate frame
s.decFrame = astiav.AllocFrame() s.decFrame = astiav.AllocFrame()
c.Add(s.decFrame.Free) c.Add(s.decFrame.Free)
@@ -194,14 +212,14 @@ func openInputFile() (err error) {
} }
func initFilter() (err error) { func initFilter() (err error) {
// Alloc graph // Allocate graph
if s.filterGraph = astiav.AllocFilterGraph(); s.filterGraph == nil { if s.filterGraph = astiav.AllocFilterGraph(); s.filterGraph == nil {
err = errors.New("main: graph is nil") err = errors.New("main: graph is nil")
return return
} }
c.Add(s.filterGraph.Free) c.Add(s.filterGraph.Free)
// Alloc outputs // Allocate outputs
outputs := astiav.AllocFilterInOut() outputs := astiav.AllocFilterInOut()
if outputs == nil { if outputs == nil {
err = errors.New("main: outputs is nil") err = errors.New("main: outputs is nil")
@@ -209,7 +227,7 @@ func initFilter() (err error) {
} }
c.Add(outputs.Free) c.Add(outputs.Free)
// Alloc inputs // Allocate inputs
inputs := astiav.AllocFilterInOut() inputs := astiav.AllocFilterInOut()
if inputs == nil { if inputs == nil {
err = errors.New("main: inputs is nil") err = errors.New("main: inputs is nil")
@@ -270,7 +288,7 @@ func initFilter() (err error) {
return return
} }
// Alloc frame // Allocate frame
s.filterFrame = astiav.AllocFrame() s.filterFrame = astiav.AllocFrame()
c.Add(s.filterFrame.Free) c.Add(s.filterFrame.Free)
return return
@@ -285,21 +303,28 @@ func filterFrame(f *astiav.Frame, s *stream) (err error) {
// Loop // Loop
for { for {
// Unref frame // We use a closure to ease unreferencing the frame
s.filterFrame.Unref() if stop, err := func() (bool, error) {
// Get frame
// Get frame if err := s.buffersinkContext.GetFrame(s.filterFrame, astiav.NewBuffersinkFlags()); err != nil {
if err = s.buffersinkContext.GetFrame(s.filterFrame, astiav.NewBuffersinkFlags()); err != nil { if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { return true, nil
err = nil }
break return false, fmt.Errorf("main: getting frame failed: %w", err)
} }
err = fmt.Errorf("main: getting frame failed: %w", err)
return // Make sure to unrefernce the frame
defer s.filterFrame.Unref()
// Do something with filtered frame
log.Printf("new filtered frame: %dx%d\n", s.filterFrame.Width(), s.filterFrame.Height())
return false, nil
}(); err != nil {
return err
} else if stop {
break
} }
// Do something with filtered frame
log.Printf("new filtered frame: %dx%d\n", s.filterFrame.Width(), s.filterFrame.Height())
} }
return return
} }

View File

@@ -28,7 +28,7 @@ func main() {
*/ */
// Alloc frame // Allocate frame
audioFrame := astiav.AllocFrame() audioFrame := astiav.AllocFrame()
defer audioFrame.Free() defer audioFrame.Free()
@@ -38,13 +38,13 @@ func main() {
audioFrame.SetSampleFormat(astiav.SampleFormatFlt) audioFrame.SetSampleFormat(astiav.SampleFormatFlt)
audioFrame.SetSampleRate(48000) audioFrame.SetSampleRate(48000)
// Alloc buffer // Allocate buffer
align := 0 align := 0
if err := audioFrame.AllocBuffer(align); err != nil { if err := audioFrame.AllocBuffer(align); err != nil {
log.Fatal(fmt.Errorf("main: allocating buffer failed: %w", err)) log.Fatal(fmt.Errorf("main: allocating buffer failed: %w", err))
} }
// Alloc samples // Allocate samples
if err := audioFrame.AllocSamples(align); err != nil { if err := audioFrame.AllocSamples(align); err != nil {
log.Fatal(fmt.Errorf("main: allocating image failed: %w", err)) log.Fatal(fmt.Errorf("main: allocating image failed: %w", err))
} }
@@ -71,7 +71,7 @@ func main() {
*/ */
// Alloc frame // Allocate frame
videoFrame := astiav.AllocFrame() videoFrame := astiav.AllocFrame()
defer videoFrame.Free() defer videoFrame.Free()
@@ -80,13 +80,13 @@ func main() {
videoFrame.SetPixelFormat(astiav.PixelFormatRgba) videoFrame.SetPixelFormat(astiav.PixelFormatRgba)
videoFrame.SetWidth(256) videoFrame.SetWidth(256)
// Alloc buffer // Allocate buffer
align = 1 align = 1
if err := videoFrame.AllocBuffer(align); err != nil { if err := videoFrame.AllocBuffer(align); err != nil {
log.Fatal(fmt.Errorf("main: allocating buffer failed: %w", err)) log.Fatal(fmt.Errorf("main: allocating buffer failed: %w", err))
} }
// Alloc image // Allocate image
if err := videoFrame.AllocImage(align); err != nil { if err := videoFrame.AllocImage(align); err != nil {
log.Fatal(fmt.Errorf("main: allocating image failed: %w", err)) log.Fatal(fmt.Errorf("main: allocating image failed: %w", err))
} }

View File

@@ -53,19 +53,19 @@ func main() {
log.Fatal(errors.New("main: hardware device not found")) log.Fatal(errors.New("main: hardware device not found"))
} }
// Alloc packet // Allocate packet
pkt := astiav.AllocPacket() pkt := astiav.AllocPacket()
defer pkt.Free() defer pkt.Free()
// Alloc hardware frame // Allocate hardware frame
hardwareFrame := astiav.AllocFrame() hardwareFrame := astiav.AllocFrame()
defer hardwareFrame.Free() defer hardwareFrame.Free()
// Alloc software frame // Allocate software frame
softwareFrame := astiav.AllocFrame() softwareFrame := astiav.AllocFrame()
defer softwareFrame.Free() defer softwareFrame.Free()
// Alloc input format context // Allocate input format context
inputFormatContext := astiav.AllocFormatContext() inputFormatContext := astiav.AllocFormatContext()
if inputFormatContext == nil { if inputFormatContext == nil {
log.Fatal(errors.New("main: input format context is nil")) log.Fatal(errors.New("main: input format context is nil"))
@@ -106,7 +106,7 @@ func main() {
log.Fatal(errors.New("main: codec is nil")) log.Fatal(errors.New("main: codec is nil"))
} }
// Alloc codec context // Allocate codec context
if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil { if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil {
log.Fatal(errors.New("main: codec context is nil")) log.Fatal(errors.New("main: codec context is nil"))
} }
@@ -160,55 +160,76 @@ func main() {
// Loop through packets // Loop through packets
for { for {
// Read frame // We use a closure to ease unreferencing the packet
if err := inputFormatContext.ReadFrame(pkt); err != nil { if stop := func() bool {
if errors.Is(err, astiav.ErrEof) { // Read frame
break if err := inputFormatContext.ReadFrame(pkt); err != nil {
if errors.Is(err, astiav.ErrEof) {
return true
}
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
} }
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
}
// Get stream // Make sure to unreference the packet
s, ok := streams[pkt.StreamIndex()] defer pkt.Unref()
if !ok {
continue
}
// Send packet // Get stream
if err := s.decCodecContext.SendPacket(pkt); err != nil { s, ok := streams[pkt.StreamIndex()]
log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) if !ok {
} return false
}
// Loop // Send packet
for { if err := s.decCodecContext.SendPacket(pkt); err != nil {
// Receive frame log.Fatal(fmt.Errorf("main: sending packet failed: %w", err))
if err := s.decCodecContext.ReceiveFrame(hardwareFrame); err != nil { }
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
// Loop
for {
// We use a closure to ease unreferencing frames
if stop := func() bool {
// Receive frame
if err := s.decCodecContext.ReceiveFrame(hardwareFrame); err != nil {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
return true
}
log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err))
}
// Make sure to unreference hardware frame
defer hardwareFrame.Unref()
// Get final frame
var finalFrame *astiav.Frame
if hardwareFrame.PixelFormat() == s.hardwarePixelFormat {
// Transfer hardware data
if err := hardwareFrame.TransferHardwareData(softwareFrame); err != nil {
log.Fatal(fmt.Errorf("main: transferring hardware data failed: %w", err))
}
// Make sure to unreference software frame
defer softwareFrame.Unref()
// Update pts
softwareFrame.SetPts(hardwareFrame.Pts())
// Update final frame
finalFrame = softwareFrame
} else {
// Update final frame
finalFrame = hardwareFrame
}
// Do something with decoded frame
log.Printf("new frame: stream %d - pts: %d - transferred: %v", pkt.StreamIndex(), finalFrame.Pts(), hardwareFrame.PixelFormat() == s.hardwarePixelFormat)
return false
}(); stop {
break break
} }
log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err))
} }
return false
// Get final frame }(); stop {
var finalFrame *astiav.Frame break
if hardwareFrame.PixelFormat() == s.hardwarePixelFormat {
// Transfer hardware data
if err := hardwareFrame.TransferHardwareData(softwareFrame); err != nil {
log.Fatal(fmt.Errorf("main: transferring hardware data failed: %w", err))
}
// Update pts
softwareFrame.SetPts(hardwareFrame.Pts())
// Update final frame
finalFrame = softwareFrame
} else {
// Update final frame
finalFrame = hardwareFrame
}
// Do something with decoded frame
log.Printf("new frame: stream %d - pts: %d - transferred: %v", pkt.StreamIndex(), finalFrame.Pts(), hardwareFrame.PixelFormat() == s.hardwarePixelFormat)
} }
} }

View File

@@ -156,15 +156,24 @@ func main() {
// Loop // Loop
for { for {
// Receive packet // We use a closure to ease unreferencing the packet
if err = encCodecContext.ReceivePacket(pkt); err != nil { if stop := func() bool {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { // Receive packet
break if err = encCodecContext.ReceivePacket(pkt); err != nil {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
return true
}
log.Fatal(fmt.Errorf("main: receiving packet failed: %w", err))
} }
log.Fatal(fmt.Errorf("main: receiving packet failed: %w", err))
}
// Log // Make sure to unreference packet
log.Println("new packet") defer pkt.Unref()
// Log
log.Println("new packet")
return false
}(); stop {
break
}
} }
} }

View File

@@ -37,11 +37,11 @@ func main() {
return return
} }
// Alloc packet // Allocate packet
pkt := astiav.AllocPacket() pkt := astiav.AllocPacket()
defer pkt.Free() defer pkt.Free()
// Alloc input format context // Allocate input format context
inputFormatContext := astiav.AllocFormatContext() inputFormatContext := astiav.AllocFormatContext()
if inputFormatContext == nil { if inputFormatContext == nil {
log.Fatal(errors.New("main: input format context is nil")) log.Fatal(errors.New("main: input format context is nil"))
@@ -59,7 +59,7 @@ func main() {
log.Fatal(fmt.Errorf("main: finding stream info failed: %w", err)) log.Fatal(fmt.Errorf("main: finding stream info failed: %w", err))
} }
// Alloc output format context // Allocate output format context
outputFormatContext, err := astiav.AllocOutputFormatContext(nil, "", *output) outputFormatContext, err := astiav.AllocOutputFormatContext(nil, "", *output)
if err != nil { if err != nil {
log.Fatal(fmt.Errorf("main: allocating output format context failed: %w", err)) log.Fatal(fmt.Errorf("main: allocating output format context failed: %w", err))
@@ -120,36 +120,43 @@ func main() {
// Loop through packets // Loop through packets
for { for {
// Read frame // We use a closure to ease unreferencing packet
if err = inputFormatContext.ReadFrame(pkt); err != nil { if stop := func() bool {
if errors.Is(err, astiav.ErrEof) { // Read frame
break if err = inputFormatContext.ReadFrame(pkt); err != nil {
if errors.Is(err, astiav.ErrEof) {
return true
}
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
} }
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
}
// Get input stream // Make sure to unreference packet
inputStream, ok := inputStreams[pkt.StreamIndex()] defer pkt.Unref()
if !ok {
pkt.Unref()
continue
}
// Get output stream // Get input stream
outputStream, ok := outputStreams[pkt.StreamIndex()] inputStream, ok := inputStreams[pkt.StreamIndex()]
if !ok { if !ok {
pkt.Unref() return false
continue }
}
// Update packet // Get output stream
pkt.SetStreamIndex(outputStream.Index()) outputStream, ok := outputStreams[pkt.StreamIndex()]
pkt.RescaleTs(inputStream.TimeBase(), outputStream.TimeBase()) if !ok {
pkt.SetPos(-1) return false
}
// Write frame // Update packet
if err = outputFormatContext.WriteInterleavedFrame(pkt); err != nil { pkt.SetStreamIndex(outputStream.Index())
log.Fatal(fmt.Errorf("main: writing interleaved frame failed: %w", err)) pkt.RescaleTs(inputStream.TimeBase(), outputStream.TimeBase())
pkt.SetPos(-1)
// Write frame
if err = outputFormatContext.WriteInterleavedFrame(pkt); err != nil {
log.Fatal(fmt.Errorf("main: writing interleaved frame failed: %w", err))
}
return false
}(); stop {
break
} }
} }

View File

@@ -79,48 +79,66 @@ func main() {
log.Fatal(fmt.Errorf("main: initializing filters failed: %w", err)) log.Fatal(fmt.Errorf("main: initializing filters failed: %w", err))
} }
// Alloc packet // Allocate packet
pkt := astiav.AllocPacket() pkt := astiav.AllocPacket()
c.Add(pkt.Free) c.Add(pkt.Free)
// Loop through packets // Loop through packets
for { for {
// Read frame // We use a closure to ease unreferencing the packet
if err := inputFormatContext.ReadFrame(pkt); err != nil { if stop := func() bool {
if errors.Is(err, astiav.ErrEof) { // Read frame
break if err := inputFormatContext.ReadFrame(pkt); err != nil {
if errors.Is(err, astiav.ErrEof) {
return true
}
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
} }
log.Fatal(fmt.Errorf("main: reading frame failed: %w", err))
}
// Get stream // Make sure to unreference the packet
s, ok := streams[pkt.StreamIndex()] defer pkt.Unref()
if !ok {
continue
}
// Update packet // Get stream
pkt.RescaleTs(s.inputStream.TimeBase(), s.decCodecContext.TimeBase()) s, ok := streams[pkt.StreamIndex()]
if !ok {
return false
}
// Send packet // Update packet
if err := s.decCodecContext.SendPacket(pkt); err != nil { pkt.RescaleTs(s.inputStream.TimeBase(), s.decCodecContext.TimeBase())
log.Fatal(fmt.Errorf("main: sending packet failed: %w", err))
}
// Loop // Send packet
for { if err := s.decCodecContext.SendPacket(pkt); err != nil {
// Receive frame log.Fatal(fmt.Errorf("main: sending packet failed: %w", err))
if err := s.decCodecContext.ReceiveFrame(s.decFrame); err != nil { }
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
// Loop
for {
// We use a closure to ease unreferencing the frame
if stop := func() bool {
// Receive frame
if err := s.decCodecContext.ReceiveFrame(s.decFrame); err != nil {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
return true
}
log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err))
}
// Make sure to unreference the frame
defer s.decFrame.Unref()
// Filter, encode and write frame
if err := filterEncodeWriteFrame(s.decFrame, s); err != nil {
log.Fatal(fmt.Errorf("main: filtering, encoding and writing frame failed: %w", err))
}
return false
}(); stop {
break break
} }
log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err))
}
// Filter, encode and write frame
if err := filterEncodeWriteFrame(s.decFrame, s); err != nil {
log.Fatal(fmt.Errorf("main: filtering, encoding and writing frame failed: %w", err))
} }
return false
}(); stop {
break
} }
} }
@@ -147,7 +165,7 @@ func main() {
} }
func openInputFile() (err error) { func openInputFile() (err error) {
// Alloc input format context // Allocate input format context
if inputFormatContext = astiav.AllocFormatContext(); inputFormatContext == nil { if inputFormatContext = astiav.AllocFormatContext(); inputFormatContext == nil {
err = errors.New("main: input format context is nil") err = errors.New("main: input format context is nil")
return return
@@ -184,7 +202,7 @@ func openInputFile() (err error) {
return return
} }
// Alloc codec context // Allocate codec context
if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil { if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil {
err = errors.New("main: codec context is nil") err = errors.New("main: codec context is nil")
return return
@@ -208,7 +226,7 @@ func openInputFile() (err error) {
return return
} }
// Alloc frame // Allocate frame
s.decFrame = astiav.AllocFrame() s.decFrame = astiav.AllocFrame()
c.Add(s.decFrame.Free) c.Add(s.decFrame.Free)
@@ -219,7 +237,7 @@ func openInputFile() (err error) {
} }
func openOutputFile() (err error) { func openOutputFile() (err error) {
// Alloc output format context // Allocate output format context
if outputFormatContext, err = astiav.AllocOutputFormatContext(nil, "", *output); err != nil { if outputFormatContext, err = astiav.AllocOutputFormatContext(nil, "", *output); err != nil {
err = fmt.Errorf("main: allocating output format context failed: %w", err) err = fmt.Errorf("main: allocating output format context failed: %w", err)
return return
@@ -255,7 +273,7 @@ func openOutputFile() (err error) {
return return
} }
// Alloc codec context // Allocate codec context
if s.encCodecContext = astiav.AllocCodecContext(s.encCodec); s.encCodecContext == nil { if s.encCodecContext = astiav.AllocCodecContext(s.encCodec); s.encCodecContext == nil {
err = errors.New("main: codec context is nil") err = errors.New("main: codec context is nil")
return return
@@ -334,14 +352,14 @@ func openOutputFile() (err error) {
func initFilters() (err error) { func initFilters() (err error) {
// Loop through output streams // Loop through output streams
for _, s := range streams { for _, s := range streams {
// Alloc graph // Allocate graph
if s.filterGraph = astiav.AllocFilterGraph(); s.filterGraph == nil { if s.filterGraph = astiav.AllocFilterGraph(); s.filterGraph == nil {
err = errors.New("main: graph is nil") err = errors.New("main: graph is nil")
return return
} }
c.Add(s.filterGraph.Free) c.Add(s.filterGraph.Free)
// Alloc outputs // Allocate outputs
outputs := astiav.AllocFilterInOut() outputs := astiav.AllocFilterInOut()
if outputs == nil { if outputs == nil {
err = errors.New("main: outputs is nil") err = errors.New("main: outputs is nil")
@@ -349,7 +367,7 @@ func initFilters() (err error) {
} }
c.Add(outputs.Free) c.Add(outputs.Free)
// Alloc inputs // Allocate inputs
inputs := astiav.AllocFilterInOut() inputs := astiav.AllocFilterInOut()
if inputs == nil { if inputs == nil {
err = errors.New("main: inputs is nil") err = errors.New("main: inputs is nil")
@@ -428,11 +446,11 @@ func initFilters() (err error) {
return return
} }
// Alloc frame // Allocate frame
s.filterFrame = astiav.AllocFrame() s.filterFrame = astiav.AllocFrame()
c.Add(s.filterFrame.Free) c.Add(s.filterFrame.Free)
// Alloc packet // Allocate packet
s.encPkt = astiav.AllocPacket() s.encPkt = astiav.AllocPacket()
c.Add(s.encPkt.Free) c.Add(s.encPkt.Free)
} }
@@ -448,35 +466,37 @@ func filterEncodeWriteFrame(f *astiav.Frame, s *stream) (err error) {
// Loop // Loop
for { for {
// Unref frame // We use a closure to unreference the frame
s.filterFrame.Unref() if stop, err := func() (bool, error) {
// Get frame
// Get frame if err := s.buffersinkContext.GetFrame(s.filterFrame, astiav.NewBuffersinkFlags()); err != nil {
if err = s.buffersinkContext.GetFrame(s.filterFrame, astiav.NewBuffersinkFlags()); err != nil { if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { return true, nil
err = nil }
break return false, fmt.Errorf("main: getting frame failed: %w", err)
} }
err = fmt.Errorf("main: getting frame failed: %w", err)
return
}
// Reset picture type // Make sure to unreference the frame
s.filterFrame.SetPictureType(astiav.PictureTypeNone) defer s.filterFrame.Unref()
// Encode and write frame // Reset picture type
if err = encodeWriteFrame(s.filterFrame, s); err != nil { s.filterFrame.SetPictureType(astiav.PictureTypeNone)
err = fmt.Errorf("main: encoding and writing frame failed: %w", err)
return // Encode and write frame
if err := encodeWriteFrame(s.filterFrame, s); err != nil {
return false, fmt.Errorf("main: encoding and writing frame failed: %w", err)
}
return false, nil
}(); err != nil {
return err
} else if stop {
break
} }
} }
return return
} }
func encodeWriteFrame(f *astiav.Frame, s *stream) (err error) { func encodeWriteFrame(f *astiav.Frame, s *stream) (err error) {
// Unref packet
s.encPkt.Unref()
// Send frame // Send frame
if err = s.encCodecContext.SendFrame(f); err != nil { if err = s.encCodecContext.SendFrame(f); err != nil {
err = fmt.Errorf("main: sending frame failed: %w", err) err = fmt.Errorf("main: sending frame failed: %w", err)
@@ -485,24 +505,32 @@ func encodeWriteFrame(f *astiav.Frame, s *stream) (err error) {
// Loop // Loop
for { for {
// Receive packet // We use a closure to ease unreferencing the packet
if err = s.encCodecContext.ReceivePacket(s.encPkt); err != nil { if stop, err := func() (bool, error) {
if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { // Receive packet
err = nil if err := s.encCodecContext.ReceivePacket(s.encPkt); err != nil {
break if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) {
return true, nil
}
return false, fmt.Errorf("main: receiving packet failed: %w", err)
} }
err = fmt.Errorf("main: receiving packet failed: %w", err)
return
}
// Update pkt // Make sure to unreference packet
s.encPkt.SetStreamIndex(s.outputStream.Index()) defer s.encPkt.Unref()
s.encPkt.RescaleTs(s.encCodecContext.TimeBase(), s.outputStream.TimeBase())
// Write frame // Update pkt
if err = outputFormatContext.WriteInterleavedFrame(s.encPkt); err != nil { s.encPkt.SetStreamIndex(s.outputStream.Index())
err = fmt.Errorf("main: writing frame failed: %w", err) s.encPkt.RescaleTs(s.encCodecContext.TimeBase(), s.outputStream.TimeBase())
return
// Write frame
if err := outputFormatContext.WriteInterleavedFrame(s.encPkt); err != nil {
return false, fmt.Errorf("main: writing frame failed: %w", err)
}
return false, nil
}(); err != nil {
return err
} else if stop {
break
} }
} }
return return

View File

@@ -42,7 +42,7 @@ func AllocIOContext(bufferSize int, writable bool, readFunc IOContextReadFunc, s
return return
} }
// Alloc buffer // Allocate buffer
buffer := C.av_malloc(C.size_t(bufferSize)) buffer := C.av_malloc(C.size_t(bufferSize))
if buffer == nil { if buffer == nil {
err = errors.New("astiav: allocating buffer failed") err = errors.New("astiav: allocating buffer failed")
@@ -88,7 +88,7 @@ func AllocIOContext(bufferSize int, writable bool, readFunc IOContextReadFunc, s
wf = C.int(1) wf = C.int(1)
} }
// Alloc io context // Allocate io context
cic := C.avio_alloc_context((*C.uchar)(buffer), C.int(bufferSize), wf, handlerID, cReadFunc, cWriteFunc, cSeekFunc) cic := C.avio_alloc_context((*C.uchar)(buffer), C.int(bufferSize), wf, handlerID, cReadFunc, cWriteFunc, cSeekFunc)
if cic == nil { if cic == nil {
err = errors.New("astiav: allocating io context failed: %w") err = errors.New("astiav: allocating io context failed: %w")
@@ -171,7 +171,7 @@ func (ic *IOContext) Read(b []byte) (n int, err error) {
return return
} }
// Alloc buffer // Allocate buffer
buf := C.av_malloc(C.size_t(len(b))) buf := C.av_malloc(C.size_t(len(b)))
if buf == nil { if buf == nil {
err = errors.New("astiav: allocating buffer failed") err = errors.New("astiav: allocating buffer failed")