Now removing from classers after the free method

This commit is contained in:
Quentin Renard
2024-10-04 10:45:40 +02:00
parent ff9ebd25ed
commit 680b5f933c
9 changed files with 92 additions and 18 deletions

View File

@@ -60,8 +60,15 @@ func (bsfc *BitStreamFilterContext) ReceivePacket(p *Packet) error {
} }
func (bsfc *BitStreamFilterContext) Free() { func (bsfc *BitStreamFilterContext) Free() {
classers.del(bsfc) if bsfc.c != nil {
C.av_bsf_free(&bsfc.c) // Make sure to clone the classer before freeing the object since
// the C free method resets the pointer
c := newClonedClasser(bsfc)
C.av_bsf_free(&bsfc.c)
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
classers.del(c)
}
} }
func (bsfc *BitStreamFilterContext) InputTimeBase() Rational { func (bsfc *BitStreamFilterContext) InputTimeBase() Rational {

View File

@@ -52,6 +52,8 @@ type Classer interface {
Class() *Class Class() *Class
} }
var _ Classer = (*UnknownClasser)(nil)
type UnknownClasser struct { type UnknownClasser struct {
c *Class c *Class
} }
@@ -64,6 +66,24 @@ func (c *UnknownClasser) Class() *Class {
return c.c return c.c
} }
var _ Classer = (*ClonedClasser)(nil)
type ClonedClasser struct {
c *Class
}
func newClonedClasser(c Classer) *ClonedClasser {
cl := c.Class()
if cl == nil {
return nil
}
return &ClonedClasser{c: newClassFromC(cl.ptr)}
}
func (c *ClonedClasser) Class() *Class {
return c.c
}
var classers = newClasserPool() var classers = newClasserPool()
type classerPool struct { type classerPool struct {

View File

@@ -31,6 +31,10 @@ func TestClassers(t *testing.T) {
f := AllocFilterGraph() f := AllocFilterGraph()
c := FindDecoder(CodecIDMjpeg) c := FindDecoder(CodecIDMjpeg)
require.NotNil(t, c) require.NotNil(t, c)
bf := FindBitStreamFilterByName("null")
require.NotNil(t, bf)
bfc, err := AllocBitStreamFilterContext(bf)
require.NoError(t, err)
cc := AllocCodecContext(c) cc := AllocCodecContext(c)
require.NotNil(t, cc) require.NotNil(t, cc)
bufferSink := FindFilterByName("buffersink") bufferSink := FindFilterByName("buffersink")
@@ -41,23 +45,27 @@ func TestClassers(t *testing.T) {
fmc2 := AllocFormatContext() fmc2 := AllocFormatContext()
require.NoError(t, fmc2.OpenInput("testdata/video.mp4", nil, nil)) require.NoError(t, fmc2.OpenInput("testdata/video.mp4", nil, nil))
path := filepath.Join(t.TempDir(), "iocontext.txt") path := filepath.Join(t.TempDir(), "iocontext.txt")
ic, err := OpenIOContext(path, NewIOContextFlags(IOContextFlagWrite)) ic1, err := OpenIOContext(path, NewIOContextFlags(IOContextFlagWrite))
require.NoError(t, err) require.NoError(t, err)
defer os.RemoveAll(path) defer os.RemoveAll(path)
ic2, err := AllocIOContext(1, true, nil, nil, nil)
require.NoError(t, err)
ssc, err := CreateSoftwareScaleContext(1, 1, PixelFormatRgba, 2, 2, PixelFormatRgba, NewSoftwareScaleContextFlags()) ssc, err := CreateSoftwareScaleContext(1, 1, PixelFormatRgba, 2, 2, PixelFormatRgba, NewSoftwareScaleContextFlags())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, cl+8, len(classers.p)) require.Equal(t, cl+10, len(classers.p))
v, ok := classers.get(unsafe.Pointer(f.c)) v, ok := classers.get(unsafe.Pointer(f.c))
require.True(t, ok) require.True(t, ok)
require.Equal(t, f, v) require.Equal(t, f, v)
bfc.Free()
cc.Free() cc.Free()
fc.Free() fc.Free()
f.Free() f.Free()
fmc1.Free() fmc1.Free()
fmc2.CloseInput() fmc2.CloseInput()
require.NoError(t, ic.Close()) require.NoError(t, ic1.Close())
ic2.Free()
ssc.Free() ssc.Free()
require.Equal(t, cl, len(classers.p)) require.Equal(t, cl, len(classers.p))
} }

View File

@@ -38,8 +38,15 @@ func (cc *CodecContext) Free() {
C.av_buffer_unref(&cc.hdc.c) C.av_buffer_unref(&cc.hdc.c)
cc.hdc = nil cc.hdc = nil
} }
classers.del(cc) if cc.c != nil {
C.avcodec_free_context(&cc.c) // Make sure to clone the classer before freeing the object since
// the C free method resets the pointer
c := newClonedClasser(cc)
C.avcodec_free_context(&cc.c)
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
classers.del(c)
}
} }
func (cc *CodecContext) String() string { func (cc *CodecContext) String() string {

View File

@@ -27,8 +27,10 @@ func newFilterContext(c *C.AVFilterContext) *FilterContext {
var _ Classer = (*FilterContext)(nil) var _ Classer = (*FilterContext)(nil)
func (fc *FilterContext) Free() { func (fc *FilterContext) Free() {
classers.del(fc)
C.avfilter_free(fc.c) C.avfilter_free(fc.c)
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
classers.del(fc)
} }
func (fc *FilterContext) BuffersrcAddFrame(f *Frame, fs BuffersrcFlags) error { func (fc *FilterContext) BuffersrcAddFrame(f *Frame, fs BuffersrcFlags) error {

View File

@@ -28,9 +28,14 @@ func AllocFilterGraph() *FilterGraph {
} }
func (g *FilterGraph) Free() { func (g *FilterGraph) Free() {
classers.del(g)
if g.c != nil { if g.c != nil {
// Make sure to clone the classer before freeing the object since
// the C free method resets the pointer
c := newClonedClasser(g)
C.avfilter_graph_free(&g.c) C.avfilter_graph_free(&g.c)
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
classers.del(c)
} }
} }

View File

@@ -51,8 +51,10 @@ func AllocOutputFormatContext(of *OutputFormat, formatName, filename string) (*F
} }
func (fc *FormatContext) Free() { func (fc *FormatContext) Free() {
classers.del(fc)
C.avformat_free_context(fc.c) C.avformat_free_context(fc.c)
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
classers.del(fc)
} }
func (fc *FormatContext) BitRate() int64 { func (fc *FormatContext) BitRate() int64 {
@@ -192,12 +194,18 @@ func (fc *FormatContext) OpenInput(url string, fmt *InputFormat, d *Dictionary)
} }
func (fc *FormatContext) CloseInput() { func (fc *FormatContext) CloseInput() {
if pb := fc.Pb(); pb != nil { pb := fc.Pb()
classers.del(pb)
}
classers.del(fc)
if fc.c != nil { if fc.c != nil {
// Make sure to clone the classer before freeing the object since
// the C free method resets the pointer
c := newClonedClasser(fc)
C.avformat_close_input(&fc.c) C.avformat_close_input(&fc.c)
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
if pb != nil {
classers.del(pb)
}
classers.del(c)
} }
} }

View File

@@ -122,15 +122,21 @@ func (ic *IOContext) Class() *Class {
} }
func (ic *IOContext) Close() error { func (ic *IOContext) Close() error {
classers.del(ic)
if ic.c != nil { if ic.c != nil {
return newError(C.avio_closep(&ic.c)) // Make sure to clone the classer before freeing the object since
// the C free method resets the pointer
c := newClonedClasser(ic)
if err := newError(C.avio_closep(&ic.c)); err != nil {
return err
}
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
classers.del(c)
} }
return nil return nil
} }
func (ic *IOContext) Free() { func (ic *IOContext) Free() {
classers.del(ic)
if ic.c != nil { if ic.c != nil {
if ic.c.buffer != nil { if ic.c.buffer != nil {
C.av_freep(unsafe.Pointer(&ic.c.buffer)) C.av_freep(unsafe.Pointer(&ic.c.buffer))
@@ -139,7 +145,13 @@ func (ic *IOContext) Free() {
C.free(ic.handlerID) C.free(ic.handlerID)
ic.handlerID = nil ic.handlerID = nil
} }
// Make sure to clone the classer before freeing the object since
// the C free method resets the pointer
c := newClonedClasser(ic)
C.avio_context_free(&ic.c) C.avio_context_free(&ic.c)
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
classers.del(c)
} }
return return
} }

View File

@@ -60,8 +60,13 @@ func CreateSoftwareScaleContext(srcW, srcH int, srcFormat PixelFormat, dstW, dst
} }
func (ssc *SoftwareScaleContext) Free() { func (ssc *SoftwareScaleContext) Free() {
classers.del(ssc) // Make sure to clone the classer before freeing the object since
// the C free method may reset the pointer
c := newClonedClasser(ssc)
C.sws_freeContext(ssc.c) C.sws_freeContext(ssc.c)
// Make sure to remove from classers after freeing the object since
// the C free method may use methods needing the classer
classers.del(c)
} }
var _ Classer = (*SoftwareScaleContext)(nil) var _ Classer = (*SoftwareScaleContext)(nil)