From 7dedb3f330512cbb6b9f248a15134525f114c413 Mon Sep 17 00:00:00 2001 From: Quentin Renard Date: Fri, 13 Dec 2024 11:23:45 +0100 Subject: [PATCH 1/4] IOInterrupted now has a pointer to the callback + added tests for dictionary and iointerrupter for openiocontext --- BREAKING_CHANGES.md | 4 ++++ format_context.go | 2 +- format_context_test.go | 2 ++ io_context.go | 11 ++++++----- io_context_test.go | 32 ++++++++++++++++++++++++-------- io_interrupter.c | 7 +++++-- io_interrupter.go | 8 +++++++- io_interrupter.h | 2 +- io_interrupter_test.go | 1 + 9 files changed, 51 insertions(+), 18 deletions(-) diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index e9df07d..fc796c2 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -1,3 +1,7 @@ +# v0.27.0 + +- make sure to call the `IOInterrupter`.`Free` method after using `NewIOInterrupter` + # v0.25.0 - `CodecParameters`.`CodecType` and `CodecParameters`.`SetCodecType` have been removed, use `CodecParameters`.`MediaType` and `CodecParameters`.`SetMediaType` instead diff --git a/format_context.go b/format_context.go index f128fa2..207dd3c 100644 --- a/format_context.go +++ b/format_context.go @@ -106,7 +106,7 @@ func (fc *FormatContext) SetIOInterrupter(i *IOInterrupter) { if i == nil { fc.c.interrupt_callback = C.AVIOInterruptCB{} } else { - fc.c.interrupt_callback = i.c + fc.c.interrupt_callback = *i.c } } diff --git a/format_context_test.go b/format_context_test.go index 445d742..5180e33 100644 --- a/format_context_test.go +++ b/format_context_test.go @@ -90,6 +90,7 @@ func TestFormatContext(t *testing.T) { require.NotNil(t, fc4) defer fc4.Free() ii1 := NewIOInterrupter() + defer ii1.Free() fc4.SetIOInterrupter(ii1) ii1.Interrupt() require.ErrorIs(t, fc4.OpenInput("testdata/video.mp4", nil, nil), ErrExit) @@ -98,6 +99,7 @@ func TestFormatContext(t *testing.T) { require.NotNil(t, fc9) defer fc9.Free() ii2 := NewIOInterrupter() + defer ii2.Free() fc9.SetIOInterrupter(ii2) fc9.SetIOInterrupter(nil) require.NoError(t, fc4.OpenInput("testdata/video.mp4", nil, nil)) diff --git a/io_context.go b/io_context.go index 063e95d..7b39494 100644 --- a/io_context.go +++ b/io_context.go @@ -118,7 +118,7 @@ func OpenIOContext(filename string, flags IOContextFlags, ii *IOInterrupter, d * } var cii *C.AVIOInterruptCB = nil if ii != nil { - cii = &ii.c + cii = ii.c } var c *C.AVIOContext if err := newError(C.avio_open2(&c, cfi, C.int(flags), cii, dc)); err != nil { @@ -137,14 +137,15 @@ func (ic *IOContext) Close() error { // Make sure to clone the classer before freeing the object since // the C free method may reset the pointer c := newClonedClasser(ic) - if err := newError(C.avio_closep(&ic.c)); err != nil { - return err - } + // Error is returned when closing the url but pointer has been freed at this point + // therefore we must make sure classers are cleaned up properly even on error + err := newError(C.avio_closep(&ic.c)) // Make sure to remove from classers after freeing the object since // the C free method may use methods needing the classer - if c != nil { + if c != nil && ic.c == nil { classers.del(c) } + return err } return nil } diff --git a/io_context_test.go b/io_context_test.go index 3a8b269..ee1caef 100644 --- a/io_context_test.go +++ b/io_context_test.go @@ -56,17 +56,33 @@ func TestIOContext(t *testing.T) { func TestOpenIOContext(t *testing.T) { path := filepath.Join(t.TempDir(), "iocontext.txt") - c, err := OpenIOContext(path, NewIOContextFlags(IOContextFlagWrite), nil, nil) + c1, err := OpenIOContext(path, NewIOContextFlags(IOContextFlagWrite), nil, nil) require.NoError(t, err) - cl := c.Class() + defer os.RemoveAll(path) + cl := c1.Class() require.NotNil(t, cl) require.Equal(t, "AVIOContext", cl.Name()) - c.Write(nil) - c.Write([]byte("test")) - require.NoError(t, c.Close()) - b, err := os.ReadFile(path) + c1.Write(nil) + c1.Write([]byte("test")) + require.NoError(t, c1.Close()) + b1, err := os.ReadFile(path) require.NoError(t, err) - require.Equal(t, "test", string(b)) - err = os.Remove(path) + require.Equal(t, "test", string(b1)) + + ii := NewIOInterrupter() + defer ii.Free() + c2, err := OpenIOContext(path, NewIOContextFlags(IOContextFlagRead), ii, nil) + require.NoError(t, err) + b2 := make([]byte, 10) + _, err = c2.Read(b2) require.NoError(t, err) + ii.Interrupt() + _, err = c2.Read(b2) + require.ErrorIs(t, err, ErrExit) + require.ErrorIs(t, c2.Close(), ErrExit) + + d := NewDictionary() + require.NoError(t, d.Set("protocol_whitelist", "rtp", NewDictionaryFlags())) + _, err = OpenIOContext(path, NewIOContextFlags(IOContextFlagWrite), nil, d) + require.Error(t, err) } diff --git a/io_interrupter.c b/io_interrupter.c index 6df0852..ebe1a78 100644 --- a/io_interrupter.c +++ b/io_interrupter.c @@ -1,12 +1,15 @@ #include +#include int astiavInterruptCallback(void *ret) { return *((int*)ret); } -AVIOInterruptCB astiavNewInterruptCallback(int *ret) +AVIOInterruptCB* astiavNewInterruptCallback(int *ret) { - AVIOInterruptCB c = { astiavInterruptCallback, ret }; + AVIOInterruptCB* c = malloc(sizeof(AVIOInterruptCB)); + c->callback = astiavInterruptCallback; + c->opaque = ret; return c; } \ No newline at end of file diff --git a/io_interrupter.go b/io_interrupter.go index 88a5206..2c90581 100644 --- a/io_interrupter.go +++ b/io_interrupter.go @@ -1,10 +1,12 @@ package astiav //#include "io_interrupter.h" +//#include import "C" +import "unsafe" type IOInterrupter struct { - c C.AVIOInterruptCB + c *C.AVIOInterruptCB i C.int } @@ -14,6 +16,10 @@ func NewIOInterrupter() *IOInterrupter { return i } +func (i *IOInterrupter) Free() { + C.free(unsafe.Pointer(i.c)) +} + func (i *IOInterrupter) Interrupt() { i.i = 1 } diff --git a/io_interrupter.h b/io_interrupter.h index eca2172..2361f3c 100644 --- a/io_interrupter.h +++ b/io_interrupter.h @@ -1,4 +1,4 @@ #include int astiavInterruptCallback(void *ret); -AVIOInterruptCB astiavNewInterruptCallback(int *ret); \ No newline at end of file +AVIOInterruptCB* astiavNewInterruptCallback(int *ret); \ No newline at end of file diff --git a/io_interrupter_test.go b/io_interrupter_test.go index 88f0bdd..9c2ecd8 100644 --- a/io_interrupter_test.go +++ b/io_interrupter_test.go @@ -8,6 +8,7 @@ import ( func TestIOInterrupter(t *testing.T) { ii := NewIOInterrupter() + defer ii.Free() require.False(t, ii.Interrupted()) ii.Interrupt() require.True(t, ii.Interrupted()) From e9341fd3e3cdce449396cb97e14d5e2b753f6206 Mon Sep 17 00:00:00 2001 From: oldma3095 <43288861+oldma3095@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:10:12 +0800 Subject: [PATCH 2/4] Program params and enum Discardxx (#119) * OpenIOContextWithDictionary * OpenIOContext * OpenIOContext * IOInterrupterCB * OpenIOContext(filename string, flags IOContextFlags, ii *IOInterrupter, d *Dictionary) * Program and Discard * Program and Discard * Program and Discard * Program and Discard * Program and Discard * Program and Discard * CodecContext MaxBFrames() SetMaxBFrames(n int) * another pr * delete Flags() * delete Flags() * delete Flags() * delete PmtVersion() * SetStreamIndex * SetStreamIndex --- .gitignore | 3 +- discard.go | 17 ++++++++++ program.go | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ program_test.go | 22 +++++++++++++ 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 discard.go diff --git a/.gitignore b/.gitignore index ee79665..5ac245f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_STORE -coverage.out \ No newline at end of file +coverage.out +.idea \ No newline at end of file diff --git a/discard.go b/discard.go new file mode 100644 index 0000000..e5b930a --- /dev/null +++ b/discard.go @@ -0,0 +1,17 @@ +package astiav + +//#include +import "C" + +// https://ffmpeg.org/doxygen/7.0/group__lavc__decoding.html#ga352363bce7d3ed82c101b3bc001d1c16 +type Discard C.enum_AVDiscard + +const ( + DiscardNone = Discard(C.AVDISCARD_NONE) + DiscardDefault = Discard(C.AVDISCARD_DEFAULT) + DiscardNonRef = Discard(C.AVDISCARD_NONREF) + DiscardBidirectional = Discard(C.AVDISCARD_BIDIR) + DiscardNonIntra = Discard(C.AVDISCARD_NONINTRA) + DiscardNonKey = Discard(C.AVDISCARD_NONKEY) + DiscardAll = Discard(C.AVDISCARD_ALL) +) diff --git a/program.go b/program.go index 76863bf..e8ff9c4 100644 --- a/program.go +++ b/program.go @@ -55,3 +55,89 @@ func (p *Program) Streams() (ss []*Stream) { } return } + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a9c7a07c08a1f960aaa49f3f47633af5c +func (p *Program) Discard() Discard { + return Discard(p.c.discard) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a9c7a07c08a1f960aaa49f3f47633af5c +func (p *Program) SetDiscard(d Discard) { + p.c.discard = int32(d) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a7967d41af4812ed61a28762e988c7a02 +func (p *Program) StreamIndex() *uint { + if p.c.stream_index == nil { + return nil + } + u := uint(C.uint(*p.c.stream_index)) + return &u +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a7967d41af4812ed61a28762e988c7a02 +func (p *Program) SetStreamIndex(n uint) { + if p.c.stream_index != nil { + *p.c.stream_index = C.uint(n) + } +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#ae9dab38d4694e3da9cba0f882f4e43d3 +func (p *Program) Metadata() *Dictionary { + return newDictionaryFromC(p.c.metadata) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#ae9dab38d4694e3da9cba0f882f4e43d3 +func (p *Program) SetMetadata(d *Dictionary) { + p.c.metadata = d.c +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a4c1539ea3c98da979b95a59a3ea163cb +func (p *Program) ProgramNumber() int { + return int(p.c.program_num) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a4c1539ea3c98da979b95a59a3ea163cb +func (p *Program) SetProgramNumber(n int) { + p.c.program_num = C.int(n) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a02011963a63c291c6dc6d4eefa56cd69 +func (p *Program) PmtPid() int { + return int(p.c.pmt_pid) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a02011963a63c291c6dc6d4eefa56cd69 +func (p *Program) SetPmtPid(n int) { + p.c.pmt_pid = C.int(n) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a7e026323df87e84a72ec5e5c8ce341a5 +func (p *Program) PcrPid() int { + return int(p.c.pcr_pid) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a7e026323df87e84a72ec5e5c8ce341a5 +func (p *Program) SetPcrPid(n int) { + p.c.pcr_pid = C.int(n) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a2276db4d51695120664d527f20b7c532 +func (p *Program) StartTime() int64 { + return int64(p.c.start_time) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a5a7795c918153d0f64d68a838e172db4 +func (p *Program) EndTime() int64 { + return int64(p.c.end_time) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a7e539e286876577e158039f6e7678452 +func (p *Program) PtsWrapReference() int64 { + return int64(p.c.pts_wrap_reference) +} + +// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#aa3f8af78093a910ff766ac5af381758b +func (p *Program) PtsWrapBehavior() int { + return int(p.c.pts_wrap_behavior) +} diff --git a/program_test.go b/program_test.go index 6c15724..db8ede3 100644 --- a/program_test.go +++ b/program_test.go @@ -14,11 +14,33 @@ func TestProgram(t *testing.T) { require.Equal(t, 1, p.ID()) p.SetID(2) require.Equal(t, 2, p.ID()) + p.SetDiscard(DiscardAll) + require.Equal(t, DiscardAll, p.Discard()) + d := NewDictionary() + require.NoError(t, d.Set("service_name", "test_service_name", 0)) + p.SetMetadata(d) + require.Equal(t, p.Metadata().Get("service_name", nil, 0).Value(), "test_service_name") + p.SetProgramNumber(101) + require.Equal(t, 101, p.ProgramNumber()) + p.SetPmtPid(201) + require.Equal(t, 201, p.PmtPid()) + p.SetPcrPid(301) + require.Equal(t, 301, p.PcrPid()) + require.Equal(t, p.StartTime(), NoPtsValue) + require.Equal(t, p.EndTime(), NoPtsValue) + require.Equal(t, p.PtsWrapReference(), NoPtsValue) + require.Equal(t, p.PtsWrapBehavior(), 0) s := fc.NewStream(nil) s.SetID(2) require.Equal(t, 0, p.NbStreams()) + require.Nil(t, p.StreamIndex(), nil) p.AddStream(s) require.Equal(t, 1, p.NbStreams()) + require.Equal(t, uint(0), *p.StreamIndex()) + var streamIndex uint = 1 + p.SetStreamIndex(streamIndex) + require.Equal(t, streamIndex, *p.StreamIndex()) + s.SetIndex(int(streamIndex)) ss := p.Streams() require.Equal(t, 1, len(ss)) require.Equal(t, s.ID(), ss[0].ID()) From b86c411567773711872e8d06da860d8ba13979fd Mon Sep 17 00:00:00 2001 From: Quentin Renard Date: Wed, 18 Dec 2024 09:14:50 +0100 Subject: [PATCH 3/4] Removed Program.StreamIndex --- program.go | 16 ---------------- program_test.go | 6 ------ 2 files changed, 22 deletions(-) diff --git a/program.go b/program.go index e8ff9c4..eb676f2 100644 --- a/program.go +++ b/program.go @@ -66,22 +66,6 @@ func (p *Program) SetDiscard(d Discard) { p.c.discard = int32(d) } -// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a7967d41af4812ed61a28762e988c7a02 -func (p *Program) StreamIndex() *uint { - if p.c.stream_index == nil { - return nil - } - u := uint(C.uint(*p.c.stream_index)) - return &u -} - -// https://ffmpeg.org/doxygen/7.0/structAVProgram.html#a7967d41af4812ed61a28762e988c7a02 -func (p *Program) SetStreamIndex(n uint) { - if p.c.stream_index != nil { - *p.c.stream_index = C.uint(n) - } -} - // https://ffmpeg.org/doxygen/7.0/structAVProgram.html#ae9dab38d4694e3da9cba0f882f4e43d3 func (p *Program) Metadata() *Dictionary { return newDictionaryFromC(p.c.metadata) diff --git a/program_test.go b/program_test.go index db8ede3..9445e7d 100644 --- a/program_test.go +++ b/program_test.go @@ -33,14 +33,8 @@ func TestProgram(t *testing.T) { s := fc.NewStream(nil) s.SetID(2) require.Equal(t, 0, p.NbStreams()) - require.Nil(t, p.StreamIndex(), nil) p.AddStream(s) require.Equal(t, 1, p.NbStreams()) - require.Equal(t, uint(0), *p.StreamIndex()) - var streamIndex uint = 1 - p.SetStreamIndex(streamIndex) - require.Equal(t, streamIndex, *p.StreamIndex()) - s.SetIndex(int(streamIndex)) ss := p.Streams() require.Equal(t, 1, len(ss)) require.Equal(t, s.ID(), ss[0].ID()) From ff05de2f4343c921e67c024b784ef4dc7e09edd7 Mon Sep 17 00:00:00 2001 From: Quentin Renard Date: Wed, 18 Dec 2024 09:29:54 +0100 Subject: [PATCH 4/4] Added libswresample in pkg config --- astiav.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astiav.go b/astiav.go index d780006..db0645d 100644 --- a/astiav.go +++ b/astiav.go @@ -1,4 +1,4 @@ package astiav -//#cgo pkg-config: libavcodec libavdevice libavfilter libavformat libswscale libavutil +//#cgo pkg-config: libavcodec libavdevice libavfilter libavformat libswresample libswscale libavutil import "C"