diff --git a/examples/bit_stream_filtering/main.go b/examples/bit_stream_filtering/main.go index d29fd53..651a12f 100644 --- a/examples/bit_stream_filtering/main.go +++ b/examples/bit_stream_filtering/main.go @@ -42,11 +42,11 @@ func main() { return } - // Alloc packet + // Allocate packet pkt := astiav.AllocPacket() defer pkt.Free() - // Alloc input format context + // Allocate input format context inputFormatContext := astiav.AllocFormatContext() if inputFormatContext == nil { log.Fatal(errors.New("main: input format context is nil")) @@ -76,7 +76,7 @@ func main() { // Create stream s := &stream{} - // Alloc packet + // Allocate packet s.bitStreamPkt = astiav.AllocPacket() defer s.bitStreamPkt.Free() @@ -86,7 +86,7 @@ func main() { log.Fatal(errors.New("main: bit stream filter is nil")) } - // Alloc bit stream filter context + // Allocate bit stream filter context var err error if s.bitStreamFilterContext, err = astiav.AllocBitStreamFilterContext(bsf); err != nil { log.Fatal(fmt.Errorf("main: allocating bit stream filter context failed: %w", err)) @@ -112,23 +112,32 @@ func main() { // Loop through packets for { - // Read frame - if err := inputFormatContext.ReadFrame(pkt); err != nil { - if errors.Is(err, astiav.ErrEof) { - break + // We use a closure to ease unreferencing the packet + if stop := func() bool { + // Read frame + 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 - s, ok := streams[pkt.StreamIndex()] - if !ok { - continue - } + // Make sure to unreference the packet + defer pkt.Unref() - // Filter bit stream - if err := filterBitStream(pkt, s); err != nil { - log.Fatal(fmt.Errorf("main: filtering bit stream failed: %w", err)) + // Get stream + s, ok := streams[pkt.StreamIndex()] + 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 for { - // Receive packet - if err := s.bitStreamFilterContext.ReceivePacket(s.bitStreamPkt); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { - break + // We use a closure to ease unreferencing the packet + if stop, err := func() (bool, error) { + // Receive packet + 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 } diff --git a/examples/custom_io_demuxing/main.go b/examples/custom_io_demuxing/main.go index 825a41f..a1373d2 100644 --- a/examples/custom_io_demuxing/main.go +++ b/examples/custom_io_demuxing/main.go @@ -37,11 +37,11 @@ func main() { return } - // Alloc packet + // Allocate packet pkt := astiav.AllocPacket() defer pkt.Free() - // Alloc input format context + // Allocate input format context inputFormatContext := astiav.AllocFormatContext() if inputFormatContext == nil { log.Fatal(errors.New("main: input format context is nil")) @@ -55,7 +55,7 @@ func main() { } defer f.Close() - // Alloc io context + // Allocate io context ioContext, err := astiav.AllocIOContext( 4096, false, @@ -88,16 +88,25 @@ func main() { // Loop through packets for { - // Read frame - if err := inputFormatContext.ReadFrame(pkt); err != nil { - if errors.Is(err, astiav.ErrEof) { - break + // We use a closure to ease unreferencing the packet + if stop := func() bool { + // Read frame + 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 - log.Printf("new packet: stream %d - pts: %d", pkt.StreamIndex(), pkt.Pts()) + // Make sure to unreference the packet + 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 diff --git a/examples/demuxing_decoding/main.go b/examples/demuxing_decoding/main.go index 5fce9e0..f18e20f 100644 --- a/examples/demuxing_decoding/main.go +++ b/examples/demuxing_decoding/main.go @@ -42,15 +42,15 @@ func main() { return } - // Alloc packet + // Allocate packet pkt := astiav.AllocPacket() defer pkt.Free() - // Alloc frame + // Allocate frame f := astiav.AllocFrame() defer f.Free() - // Alloc input format context + // Allocate input format context inputFormatContext := astiav.AllocFormatContext() if inputFormatContext == 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")) } - // Alloc codec context + // Allocate codec context if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil { log.Fatal(errors.New("main: codec context is nil")) } @@ -105,39 +105,57 @@ func main() { streams[is.Index()] = s } - // Loop through packets + // Loop for { - // Read frame - if err := inputFormatContext.ReadFrame(pkt); err != nil { - if errors.Is(err, astiav.ErrEof) { - break + // We use a closure to ease unreferencing the packet + if stop := func() bool { + // Read frame + 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 - s, ok := streams[pkt.StreamIndex()] - if !ok { - continue - } + // Make sure to unreference the packet + defer pkt.Unref() - // Send packet - if err := s.decCodecContext.SendPacket(pkt); err != nil { - log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) - } + // Get stream + s, ok := streams[pkt.StreamIndex()] + if !ok { + return false + } - // Loop - for { - // Receive frame - if err := s.decCodecContext.ReceiveFrame(f); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { + // Send packet + if err := s.decCodecContext.SendPacket(pkt); err != nil { + log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) + } + + // 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 } - log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err)) } - - // Log - log.Printf("new %s frame: stream %d - pts: %d", s.inputStream.CodecParameters().MediaType(), pkt.StreamIndex(), f.Pts()) + return false + }(); stop { + break } } diff --git a/examples/filtering/main.go b/examples/filtering/main.go index 993bd7f..227ba1f 100644 --- a/examples/filtering/main.go +++ b/examples/filtering/main.go @@ -69,44 +69,62 @@ func main() { log.Fatal(fmt.Errorf("main: initializing filter failed: %w", err)) } - // Alloc packet + // Allocate packet pkt := astiav.AllocPacket() c.Add(pkt.Free) // Loop through packets for { - // Read frame - if err := inputFormatContext.ReadFrame(pkt); err != nil { - if errors.Is(err, astiav.ErrEof) { - break + // We use a closure to ease unreferencing the packet + if stop := func() bool { + // Read frame + 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 - if pkt.StreamIndex() != s.inputStream.Index() { - continue - } + // Make sure to unreference the packet + defer pkt.Unref() - // Send packet - if err := s.decCodecContext.SendPacket(pkt); err != nil { - log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) - } + // Invalid stream + if pkt.StreamIndex() != s.inputStream.Index() { + return false + } - // Loop - for { - // Receive frame - if err := s.decCodecContext.ReceiveFrame(s.decFrame); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { + // Send packet + if err := s.decCodecContext.SendPacket(pkt); err != nil { + log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) + } + + // 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 } - 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) { - // Alloc input format context + // Allocate input format context if inputFormatContext = astiav.AllocFormatContext(); inputFormatContext == nil { err = errors.New("main: input format context is nil") return @@ -159,7 +177,7 @@ func openInputFile() (err error) { return } - // Alloc codec context + // Allocate codec context if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil { err = errors.New("main: codec context is nil") return @@ -178,7 +196,7 @@ func openInputFile() (err error) { return } - // Alloc frame + // Allocate frame s.decFrame = astiav.AllocFrame() c.Add(s.decFrame.Free) @@ -194,14 +212,14 @@ func openInputFile() (err error) { } func initFilter() (err error) { - // Alloc graph + // Allocate graph if s.filterGraph = astiav.AllocFilterGraph(); s.filterGraph == nil { err = errors.New("main: graph is nil") return } c.Add(s.filterGraph.Free) - // Alloc outputs + // Allocate outputs outputs := astiav.AllocFilterInOut() if outputs == nil { err = errors.New("main: outputs is nil") @@ -209,7 +227,7 @@ func initFilter() (err error) { } c.Add(outputs.Free) - // Alloc inputs + // Allocate inputs inputs := astiav.AllocFilterInOut() if inputs == nil { err = errors.New("main: inputs is nil") @@ -270,7 +288,7 @@ func initFilter() (err error) { return } - // Alloc frame + // Allocate frame s.filterFrame = astiav.AllocFrame() c.Add(s.filterFrame.Free) return @@ -285,21 +303,28 @@ func filterFrame(f *astiav.Frame, s *stream) (err error) { // Loop for { - // Unref frame - s.filterFrame.Unref() - - // Get frame - if err = s.buffersinkContext.GetFrame(s.filterFrame, astiav.NewBuffersinkFlags()); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { - err = nil - break + // We use a closure to ease unreferencing the frame + if stop, err := func() (bool, error) { + // Get frame + if err := s.buffersinkContext.GetFrame(s.filterFrame, astiav.NewBuffersinkFlags()); err != nil { + if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { + return true, nil + } + 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 } diff --git a/examples/frame_data_manipulation/main.go b/examples/frame_data_manipulation/main.go index e3778c3..c09ebb0 100644 --- a/examples/frame_data_manipulation/main.go +++ b/examples/frame_data_manipulation/main.go @@ -28,7 +28,7 @@ func main() { */ - // Alloc frame + // Allocate frame audioFrame := astiav.AllocFrame() defer audioFrame.Free() @@ -38,13 +38,13 @@ func main() { audioFrame.SetSampleFormat(astiav.SampleFormatFlt) audioFrame.SetSampleRate(48000) - // Alloc buffer + // Allocate buffer align := 0 if err := audioFrame.AllocBuffer(align); err != nil { log.Fatal(fmt.Errorf("main: allocating buffer failed: %w", err)) } - // Alloc samples + // Allocate samples if err := audioFrame.AllocSamples(align); err != nil { log.Fatal(fmt.Errorf("main: allocating image failed: %w", err)) } @@ -71,7 +71,7 @@ func main() { */ - // Alloc frame + // Allocate frame videoFrame := astiav.AllocFrame() defer videoFrame.Free() @@ -80,13 +80,13 @@ func main() { videoFrame.SetPixelFormat(astiav.PixelFormatRgba) videoFrame.SetWidth(256) - // Alloc buffer + // Allocate buffer align = 1 if err := videoFrame.AllocBuffer(align); err != nil { log.Fatal(fmt.Errorf("main: allocating buffer failed: %w", err)) } - // Alloc image + // Allocate image if err := videoFrame.AllocImage(align); err != nil { log.Fatal(fmt.Errorf("main: allocating image failed: %w", err)) } diff --git a/examples/hardware_decoding/main.go b/examples/hardware_decoding/main.go index d41e184..fcaa76d 100644 --- a/examples/hardware_decoding/main.go +++ b/examples/hardware_decoding/main.go @@ -53,19 +53,19 @@ func main() { log.Fatal(errors.New("main: hardware device not found")) } - // Alloc packet + // Allocate packet pkt := astiav.AllocPacket() defer pkt.Free() - // Alloc hardware frame + // Allocate hardware frame hardwareFrame := astiav.AllocFrame() defer hardwareFrame.Free() - // Alloc software frame + // Allocate software frame softwareFrame := astiav.AllocFrame() defer softwareFrame.Free() - // Alloc input format context + // Allocate input format context inputFormatContext := astiav.AllocFormatContext() if inputFormatContext == 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")) } - // Alloc codec context + // Allocate codec context if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil { log.Fatal(errors.New("main: codec context is nil")) } @@ -160,55 +160,76 @@ func main() { // Loop through packets for { - // Read frame - if err := inputFormatContext.ReadFrame(pkt); err != nil { - if errors.Is(err, astiav.ErrEof) { - break + // We use a closure to ease unreferencing the packet + if stop := func() bool { + // Read frame + 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 - s, ok := streams[pkt.StreamIndex()] - if !ok { - continue - } + // Make sure to unreference the packet + defer pkt.Unref() - // Send packet - if err := s.decCodecContext.SendPacket(pkt); err != nil { - log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) - } + // Get stream + s, ok := streams[pkt.StreamIndex()] + if !ok { + return false + } - // Loop - for { - // Receive frame - if err := s.decCodecContext.ReceiveFrame(hardwareFrame); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { + // Send packet + if err := s.decCodecContext.SendPacket(pkt); err != nil { + log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) + } + + // 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 } - log.Fatal(fmt.Errorf("main: receiving frame failed: %w", err)) } - - // 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)) - } - - // 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 } } diff --git a/examples/hardware_encoding/main.go b/examples/hardware_encoding/main.go index 224acd6..2f12291 100644 --- a/examples/hardware_encoding/main.go +++ b/examples/hardware_encoding/main.go @@ -156,15 +156,24 @@ func main() { // Loop for { - // Receive packet - if err = encCodecContext.ReceivePacket(pkt); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { - break + // We use a closure to ease unreferencing the packet + if stop := func() bool { + // Receive packet + 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 - log.Println("new packet") + // Make sure to unreference packet + defer pkt.Unref() + + // Log + log.Println("new packet") + return false + }(); stop { + break + } } } diff --git a/examples/remuxing/main.go b/examples/remuxing/main.go index 3ca9272..9ea9713 100644 --- a/examples/remuxing/main.go +++ b/examples/remuxing/main.go @@ -37,11 +37,11 @@ func main() { return } - // Alloc packet + // Allocate packet pkt := astiav.AllocPacket() defer pkt.Free() - // Alloc input format context + // Allocate input format context inputFormatContext := astiav.AllocFormatContext() if inputFormatContext == 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)) } - // Alloc output format context + // Allocate output format context outputFormatContext, err := astiav.AllocOutputFormatContext(nil, "", *output) if err != nil { log.Fatal(fmt.Errorf("main: allocating output format context failed: %w", err)) @@ -120,36 +120,43 @@ func main() { // Loop through packets for { - // Read frame - if err = inputFormatContext.ReadFrame(pkt); err != nil { - if errors.Is(err, astiav.ErrEof) { - break + // We use a closure to ease unreferencing packet + if stop := func() bool { + // Read frame + 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 - inputStream, ok := inputStreams[pkt.StreamIndex()] - if !ok { - pkt.Unref() - continue - } + // Make sure to unreference packet + defer pkt.Unref() - // Get output stream - outputStream, ok := outputStreams[pkt.StreamIndex()] - if !ok { - pkt.Unref() - continue - } + // Get input stream + inputStream, ok := inputStreams[pkt.StreamIndex()] + if !ok { + return false + } - // Update packet - pkt.SetStreamIndex(outputStream.Index()) - pkt.RescaleTs(inputStream.TimeBase(), outputStream.TimeBase()) - pkt.SetPos(-1) + // Get output stream + outputStream, ok := outputStreams[pkt.StreamIndex()] + if !ok { + return false + } - // Write frame - if err = outputFormatContext.WriteInterleavedFrame(pkt); err != nil { - log.Fatal(fmt.Errorf("main: writing interleaved frame failed: %w", err)) + // Update packet + pkt.SetStreamIndex(outputStream.Index()) + 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 } } diff --git a/examples/transcoding/main.go b/examples/transcoding/main.go index f1024ba..4b35ba7 100644 --- a/examples/transcoding/main.go +++ b/examples/transcoding/main.go @@ -79,48 +79,66 @@ func main() { log.Fatal(fmt.Errorf("main: initializing filters failed: %w", err)) } - // Alloc packet + // Allocate packet pkt := astiav.AllocPacket() c.Add(pkt.Free) // Loop through packets for { - // Read frame - if err := inputFormatContext.ReadFrame(pkt); err != nil { - if errors.Is(err, astiav.ErrEof) { - break + // We use a closure to ease unreferencing the packet + if stop := func() bool { + // Read frame + 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 - s, ok := streams[pkt.StreamIndex()] - if !ok { - continue - } + // Make sure to unreference the packet + defer pkt.Unref() - // Update packet - pkt.RescaleTs(s.inputStream.TimeBase(), s.decCodecContext.TimeBase()) + // Get stream + s, ok := streams[pkt.StreamIndex()] + if !ok { + return false + } - // Send packet - if err := s.decCodecContext.SendPacket(pkt); err != nil { - log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) - } + // Update packet + pkt.RescaleTs(s.inputStream.TimeBase(), s.decCodecContext.TimeBase()) - // Loop - for { - // Receive frame - if err := s.decCodecContext.ReceiveFrame(s.decFrame); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { + // Send packet + if err := s.decCodecContext.SendPacket(pkt); err != nil { + log.Fatal(fmt.Errorf("main: sending packet failed: %w", err)) + } + + // 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 } - 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) { - // Alloc input format context + // Allocate input format context if inputFormatContext = astiav.AllocFormatContext(); inputFormatContext == nil { err = errors.New("main: input format context is nil") return @@ -184,7 +202,7 @@ func openInputFile() (err error) { return } - // Alloc codec context + // Allocate codec context if s.decCodecContext = astiav.AllocCodecContext(s.decCodec); s.decCodecContext == nil { err = errors.New("main: codec context is nil") return @@ -208,7 +226,7 @@ func openInputFile() (err error) { return } - // Alloc frame + // Allocate frame s.decFrame = astiav.AllocFrame() c.Add(s.decFrame.Free) @@ -219,7 +237,7 @@ func openInputFile() (err error) { } func openOutputFile() (err error) { - // Alloc output format context + // Allocate output format context if outputFormatContext, err = astiav.AllocOutputFormatContext(nil, "", *output); err != nil { err = fmt.Errorf("main: allocating output format context failed: %w", err) return @@ -255,7 +273,7 @@ func openOutputFile() (err error) { return } - // Alloc codec context + // Allocate codec context if s.encCodecContext = astiav.AllocCodecContext(s.encCodec); s.encCodecContext == nil { err = errors.New("main: codec context is nil") return @@ -334,14 +352,14 @@ func openOutputFile() (err error) { func initFilters() (err error) { // Loop through output streams for _, s := range streams { - // Alloc graph + // Allocate graph if s.filterGraph = astiav.AllocFilterGraph(); s.filterGraph == nil { err = errors.New("main: graph is nil") return } c.Add(s.filterGraph.Free) - // Alloc outputs + // Allocate outputs outputs := astiav.AllocFilterInOut() if outputs == nil { err = errors.New("main: outputs is nil") @@ -349,7 +367,7 @@ func initFilters() (err error) { } c.Add(outputs.Free) - // Alloc inputs + // Allocate inputs inputs := astiav.AllocFilterInOut() if inputs == nil { err = errors.New("main: inputs is nil") @@ -428,11 +446,11 @@ func initFilters() (err error) { return } - // Alloc frame + // Allocate frame s.filterFrame = astiav.AllocFrame() c.Add(s.filterFrame.Free) - // Alloc packet + // Allocate packet s.encPkt = astiav.AllocPacket() c.Add(s.encPkt.Free) } @@ -448,35 +466,37 @@ func filterEncodeWriteFrame(f *astiav.Frame, s *stream) (err error) { // Loop for { - // Unref frame - s.filterFrame.Unref() - - // Get frame - if err = s.buffersinkContext.GetFrame(s.filterFrame, astiav.NewBuffersinkFlags()); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { - err = nil - break + // We use a closure to unreference the frame + if stop, err := func() (bool, error) { + // Get frame + if err := s.buffersinkContext.GetFrame(s.filterFrame, astiav.NewBuffersinkFlags()); err != nil { + if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { + return true, nil + } + return false, fmt.Errorf("main: getting frame failed: %w", err) } - err = fmt.Errorf("main: getting frame failed: %w", err) - return - } - // Reset picture type - s.filterFrame.SetPictureType(astiav.PictureTypeNone) + // Make sure to unreference the frame + defer s.filterFrame.Unref() - // Encode and write frame - if err = encodeWriteFrame(s.filterFrame, s); err != nil { - err = fmt.Errorf("main: encoding and writing frame failed: %w", err) - return + // Reset picture type + s.filterFrame.SetPictureType(astiav.PictureTypeNone) + + // 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 } func encodeWriteFrame(f *astiav.Frame, s *stream) (err error) { - // Unref packet - s.encPkt.Unref() - // Send frame if err = s.encCodecContext.SendFrame(f); err != nil { err = fmt.Errorf("main: sending frame failed: %w", err) @@ -485,24 +505,32 @@ func encodeWriteFrame(f *astiav.Frame, s *stream) (err error) { // Loop for { - // Receive packet - if err = s.encCodecContext.ReceivePacket(s.encPkt); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { - err = nil - break + // We use a closure to ease unreferencing the packet + if stop, err := func() (bool, error) { + // Receive packet + if err := s.encCodecContext.ReceivePacket(s.encPkt); 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) } - err = fmt.Errorf("main: receiving packet failed: %w", err) - return - } - // Update pkt - s.encPkt.SetStreamIndex(s.outputStream.Index()) - s.encPkt.RescaleTs(s.encCodecContext.TimeBase(), s.outputStream.TimeBase()) + // Make sure to unreference packet + defer s.encPkt.Unref() - // Write frame - if err = outputFormatContext.WriteInterleavedFrame(s.encPkt); err != nil { - err = fmt.Errorf("main: writing frame failed: %w", err) - return + // Update pkt + s.encPkt.SetStreamIndex(s.outputStream.Index()) + s.encPkt.RescaleTs(s.encCodecContext.TimeBase(), s.outputStream.TimeBase()) + + // 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 diff --git a/io_context.go b/io_context.go index ccc11a0..710d932 100644 --- a/io_context.go +++ b/io_context.go @@ -42,7 +42,7 @@ func AllocIOContext(bufferSize int, writable bool, readFunc IOContextReadFunc, s return } - // Alloc buffer + // Allocate buffer buffer := C.av_malloc(C.size_t(bufferSize)) if buffer == nil { err = errors.New("astiav: allocating buffer failed") @@ -88,7 +88,7 @@ func AllocIOContext(bufferSize int, writable bool, readFunc IOContextReadFunc, s 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) if cic == nil { err = errors.New("astiav: allocating io context failed: %w") @@ -171,7 +171,7 @@ func (ic *IOContext) Read(b []byte) (n int, err error) { return } - // Alloc buffer + // Allocate buffer buf := C.av_malloc(C.size_t(len(b))) if buf == nil { err = errors.New("astiav: allocating buffer failed")