diff --git a/.gitignore b/.gitignore index 465e2bd..b19b893 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .DS_STORE -cover* +coverage.out tmp \ No newline at end of file diff --git a/Makefile b/Makefile index de31643..6dfc51f 100644 --- a/Makefile +++ b/Makefile @@ -14,3 +14,7 @@ install-ffmpeg: cd $(srcPath) && ./configure --prefix=.. $(configure) cd $(srcPath) && make cd $(srcPath) && make install + +coverage: + go test -coverprofile=coverage.out + go tool cover -html=coverage.out diff --git a/astiav_test.go b/astiav_test.go index c0f11d9..d7673f3 100644 --- a/astiav_test.go +++ b/astiav_test.go @@ -1,4 +1,4 @@ -package astiav_test +package astiav import ( "errors" @@ -7,7 +7,6 @@ import ( "sync" "testing" - "github.com/asticode/go-astiav" "github.com/asticode/go-astikit" ) @@ -46,12 +45,12 @@ func (h *helper) close() { } type helperInput struct { - firstPkt *astiav.Packet - formatContext *astiav.FormatContext - lastFrame *astiav.Frame + firstPkt *Packet + formatContext *FormatContext + lastFrame *Frame } -func (h *helper) inputFormatContext(name string) (fc *astiav.FormatContext, err error) { +func (h *helper) inputFormatContext(name string) (fc *FormatContext, err error) { h.m.Lock() i, ok := h.inputs[name] if ok && i.formatContext != nil { @@ -60,7 +59,7 @@ func (h *helper) inputFormatContext(name string) (fc *astiav.FormatContext, err } h.m.Unlock() - if fc = astiav.AllocFormatContext(); fc == nil { + if fc = AllocFormatContext(); fc == nil { err = errors.New("astiav_test: allocated format context is nil") return } @@ -86,7 +85,7 @@ func (h *helper) inputFormatContext(name string) (fc *astiav.FormatContext, err return } -func (h *helper) inputFirstPacket(name string) (pkt *astiav.Packet, err error) { +func (h *helper) inputFirstPacket(name string) (pkt *Packet, err error) { h.m.Lock() i, ok := h.inputs[name] if ok && i.firstPkt != nil { @@ -95,13 +94,13 @@ func (h *helper) inputFirstPacket(name string) (pkt *astiav.Packet, err error) { } h.m.Unlock() - var fc *astiav.FormatContext + var fc *FormatContext if fc, err = h.inputFormatContext(name); err != nil { err = fmt.Errorf("astiav_test: getting input format context failed") return } - pkt = astiav.AllocPacket() + pkt = AllocPacket() if pkt == nil { err = errors.New("astiav_test: pkt is nil") return @@ -119,7 +118,7 @@ func (h *helper) inputFirstPacket(name string) (pkt *astiav.Packet, err error) { return } -func (h *helper) inputLastFrame(name string, mediaType astiav.MediaType) (f *astiav.Frame, err error) { +func (h *helper) inputLastFrame(name string, mediaType MediaType) (f *Frame, err error) { h.m.Lock() i, ok := h.inputs[name] if ok && i.lastFrame != nil { @@ -128,14 +127,14 @@ func (h *helper) inputLastFrame(name string, mediaType astiav.MediaType) (f *ast } h.m.Unlock() - var fc *astiav.FormatContext + var fc *FormatContext if fc, err = h.inputFormatContext(name); err != nil { err = fmt.Errorf("astiav_test: getting input format context failed: %w", err) return } - var cc *astiav.CodecContext - var cs *astiav.Stream + var cc *CodecContext + var cs *Stream for _, s := range fc.Streams() { if s.CodecParameters().MediaType() != mediaType { continue @@ -143,13 +142,13 @@ func (h *helper) inputLastFrame(name string, mediaType astiav.MediaType) (f *ast cs = s - c := astiav.FindDecoder(s.CodecParameters().CodecID()) + c := FindDecoder(s.CodecParameters().CodecID()) if c == nil { err = errors.New("astiav_test: no codec") return } - cc = astiav.AllocCodecContext(c) + cc = AllocCodecContext(c) if cc == nil { err = errors.New("astiav_test: no codec context") return @@ -173,25 +172,25 @@ func (h *helper) inputLastFrame(name string, mediaType astiav.MediaType) (f *ast return } - var pkt1 *astiav.Packet + var pkt1 *Packet if pkt1, err = h.inputFirstPacket(name); err != nil { err = fmt.Errorf("astiav_test: getting input first packet failed: %w", err) return } - pkt2 := astiav.AllocPacket() + pkt2 := AllocPacket() h.closer.Add(pkt2.Free) - f = astiav.AllocFrame() + f = AllocFrame() h.closer.Add(f.Free) - lastFrame := astiav.AllocFrame() + lastFrame := AllocFrame() h.closer.Add(lastFrame.Free) - pkts := []*astiav.Packet{pkt1} + pkts := []*Packet{pkt1} for { if err = fc.ReadFrame(pkt2); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { + if errors.Is(err, ErrEof) || errors.Is(err, ErrEagain) { if len(pkts) == 0 { if err = f.Ref(lastFrame); err != nil { err = fmt.Errorf("astiav_test: last refing frame failed: %w", err) @@ -220,7 +219,7 @@ func (h *helper) inputLastFrame(name string, mediaType astiav.MediaType) (f *ast for { if err = cc.ReceiveFrame(f); err != nil { - if errors.Is(err, astiav.ErrEof) || errors.Is(err, astiav.ErrEagain) { + if errors.Is(err, ErrEof) || errors.Is(err, ErrEagain) { err = nil break } @@ -235,7 +234,7 @@ func (h *helper) inputLastFrame(name string, mediaType astiav.MediaType) (f *ast } } - pkts = []*astiav.Packet{} + pkts = []*Packet{} } h.m.Lock() diff --git a/channel_layout.go b/channel_layout.go index 35420a1..b5371f9 100644 --- a/channel_layout.go +++ b/channel_layout.go @@ -122,8 +122,7 @@ func (l ChannelLayout) copy(dst *C.struct_AVChannelLayout) error { } func (l ChannelLayout) clone() (ChannelLayout, error) { - // TODO Should it be freed? - cl := C.struct_AVChannelLayout{} + var cl C.struct_AVChannelLayout err := l.copy(&cl) dst := newChannelLayoutFromC(&cl) return dst, err diff --git a/channel_layout_test.go b/channel_layout_test.go index 5121deb..1d907de 100644 --- a/channel_layout_test.go +++ b/channel_layout_test.go @@ -1,17 +1,16 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestChannelLayout(t *testing.T) { - cl := astiav.ChannelLayoutStereo + cl := ChannelLayoutStereo require.Equal(t, 2, cl.NbChannels()) require.Equal(t, "stereo", cl.String()) require.True(t, cl.Valid()) - require.True(t, cl.Equal(astiav.ChannelLayoutStereo)) - require.False(t, cl.Equal(astiav.ChannelLayoutMono)) + require.True(t, cl.Equal(ChannelLayoutStereo)) + require.False(t, cl.Equal(ChannelLayoutMono)) } diff --git a/class.go b/class.go new file mode 100644 index 0000000..36623a1 --- /dev/null +++ b/class.go @@ -0,0 +1,134 @@ +package astiav + +//#cgo pkg-config: libavutil +//#include +//#include +/* + +static inline char* astiavClassItemName(AVClass* c, void* ptr) { + return (char*)c->item_name(ptr); +} + +static inline AVClassCategory astiavClassCategory(AVClass* c, void* ptr) { + if (c->get_category) return c->get_category(ptr); + return c->category; +} + +static inline AVClass** astiavClassParent(AVClass* c, void* ptr) { + if (c->parent_log_context_offset) { + AVClass** parent = *(AVClass ***) (((uint8_t *) ptr) + c->parent_log_context_offset); + if (parent && *parent) { + return parent; + } + } + return NULL; +} + +*/ +import "C" +import ( + "fmt" + "sync" + "unsafe" +) + +// https://github.com/FFmpeg/FFmpeg/blob/n5.0/libavutil/log.h#L66 +type Class struct { + c *C.struct_AVClass + ptr unsafe.Pointer +} + +func newClassFromC(ptr unsafe.Pointer) *Class { + if ptr == nil { + return nil + } + c := (**C.struct_AVClass)(ptr) + if c == nil { + return nil + } + return &Class{ + c: *c, + ptr: ptr, + } +} + +func (c *Class) Category() ClassCategory { + return ClassCategory(C.astiavClassCategory(c.c, c.ptr)) +} + +func (c *Class) ItemName() string { + return C.GoString(C.astiavClassItemName(c.c, c.ptr)) +} + +func (c *Class) Name() string { + return C.GoString(c.c.class_name) +} + +func (c *Class) Parent() *Class { + return newClassFromC(unsafe.Pointer(C.astiavClassParent(c.c, c.ptr))) +} + +func (c *Class) String() string { + return fmt.Sprintf("%s [%s] @ %p", c.ItemName(), c.Name(), c.ptr) +} + +type Classer interface { + Class() *Class +} + +type UnknownClasser struct { + c *Class +} + +func newUnknownClasser(ptr unsafe.Pointer) *UnknownClasser { + return &UnknownClasser{c: newClassFromC(ptr)} +} + +func (c *UnknownClasser) Class() *Class { + return c.c +} + +var classers = newClasserPool() + +type classerPool struct { + m sync.Mutex + p map[unsafe.Pointer]Classer +} + +func newClasserPool() *classerPool { + return &classerPool{p: make(map[unsafe.Pointer]Classer)} +} + +func (p *classerPool) unsafePointer(c Classer) unsafe.Pointer { + if c == nil { + return nil + } + cl := c.Class() + if cl == nil { + return nil + } + return cl.ptr +} + +func (p *classerPool) set(c Classer) { + p.m.Lock() + defer p.m.Unlock() + if ptr := p.unsafePointer(c); ptr != nil { + p.p[ptr] = c + } +} + +func (p *classerPool) del(c Classer) { + p.m.Lock() + defer p.m.Unlock() + if ptr := p.unsafePointer(c); ptr != nil { + delete(p.p, ptr) + } +} + +func (p *classerPool) get(ptr unsafe.Pointer) (Classer, bool) { + p.m.Lock() + defer p.m.Unlock() + c, ok := p.p[ptr] + return c, ok +} diff --git a/class_category.go b/class_category.go new file mode 100644 index 0000000..70ae789 --- /dev/null +++ b/class_category.go @@ -0,0 +1,30 @@ +package astiav + +//#cgo pkg-config: libavutil +//#include +import "C" + +// https://github.com/FFmpeg/FFmpeg/blob/n5.0/libavutil/log.h#L28 +// TODO Find a way to use C.enum_AVClassCategory instead of uint +type ClassCategory uint + +const ( + ClassCategoryBitstreamFilter = ClassCategory(C.AV_CLASS_CATEGORY_BITSTREAM_FILTER) + ClassCategoryDecoder = ClassCategory(C.AV_CLASS_CATEGORY_DECODER) + ClassCategoryDemuxer = ClassCategory(C.AV_CLASS_CATEGORY_DEMUXER) + ClassCategoryDeviceAudioInput = ClassCategory(C.AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) + ClassCategoryDeviceAudioOutput = ClassCategory(C.AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) + ClassCategoryDeviceInput = ClassCategory(C.AV_CLASS_CATEGORY_DEVICE_INPUT) + ClassCategoryDeviceOutput = ClassCategory(C.AV_CLASS_CATEGORY_DEVICE_OUTPUT) + ClassCategoryDeviceVideoInput = ClassCategory(C.AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) + ClassCategoryDeviceVideoOutput = ClassCategory(C.AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) + ClassCategoryEncoder = ClassCategory(C.AV_CLASS_CATEGORY_ENCODER) + ClassCategoryFilter = ClassCategory(C.AV_CLASS_CATEGORY_FILTER) + ClassCategoryInput = ClassCategory(C.AV_CLASS_CATEGORY_INPUT) + ClassCategoryMuxer = ClassCategory(C.AV_CLASS_CATEGORY_MUXER) + ClassCategoryNa = ClassCategory(C.AV_CLASS_CATEGORY_NA) + ClassCategoryNb = ClassCategory(C.AV_CLASS_CATEGORY_NB) + ClassCategoryOutput = ClassCategory(C.AV_CLASS_CATEGORY_OUTPUT) + ClassCategorySwresampler = ClassCategory(C.AV_CLASS_CATEGORY_SWRESAMPLER) + ClassCategorySwscaler = ClassCategory(C.AV_CLASS_CATEGORY_SWSCALER) +) diff --git a/class_test.go b/class_test.go new file mode 100644 index 0000000..33ebc41 --- /dev/null +++ b/class_test.go @@ -0,0 +1,63 @@ +package astiav + +import ( + "fmt" + "os" + "path/filepath" + "testing" + "unsafe" + + "github.com/stretchr/testify/require" +) + +func TestClass(t *testing.T) { + c := FindDecoder(CodecIDMjpeg) + require.NotNil(t, c) + cc := AllocCodecContext(c) + require.NotNil(t, cc) + defer cc.Free() + + cl := cc.Class() + require.NotNil(t, cl) + require.Equal(t, ClassCategoryDecoder, cl.Category()) + require.Equal(t, "mjpeg", cl.ItemName()) + require.Equal(t, "AVCodecContext", cl.Name()) + require.Equal(t, fmt.Sprintf("mjpeg [AVCodecContext] @ %p", cc.c), cl.String()) + // TODO Test parent +} + +func TestClassers(t *testing.T) { + cl := len(classers.p) + f := AllocFilterGraph() + c := FindDecoder(CodecIDMjpeg) + require.NotNil(t, c) + cc := AllocCodecContext(c) + require.NotNil(t, cc) + bufferSink := FindFilterByName("buffersink") + require.NotNil(t, bufferSink) + fc, err := f.NewFilterContext(bufferSink, "filter_out", nil) + require.NoError(t, err) + fmc1 := AllocFormatContext() + fmc2 := AllocFormatContext() + require.NoError(t, fmc2.OpenInput("testdata/video.mp4", nil, nil)) + path := filepath.Join(t.TempDir(), "iocontext.txt") + ic, err := OpenIOContext(path, NewIOContextFlags(IOContextFlagWrite)) + require.NoError(t, err) + defer os.RemoveAll(path) + ssc, err := CreateSoftwareScaleContext(1, 1, PixelFormatRgba, 2, 2, PixelFormatRgba, NewSoftwareScaleContextFlags()) + require.NoError(t, err) + + require.Equal(t, cl+8, len(classers.p)) + v, ok := classers.get(unsafe.Pointer(f.c)) + require.True(t, ok) + require.Equal(t, f, v) + + cc.Free() + fc.Free() + f.Free() + fmc1.Free() + fmc2.CloseInput() + require.NoError(t, ic.Closep()) + ssc.Free() + require.Equal(t, cl, len(classers.p)) +} diff --git a/codec_context.go b/codec_context.go index 4bdb85e..556e82e 100644 --- a/codec_context.go +++ b/codec_context.go @@ -39,6 +39,17 @@ type CodecContext struct { hdc *HardwareDeviceContext } +func newCodecContextFromC(c *C.struct_AVCodecContext) *CodecContext { + if c == nil { + return nil + } + cc := &CodecContext{c: c} + classers.set(cc) + return cc +} + +var _ Classer = (*CodecContext)(nil) + func AllocCodecContext(c *Codec) *CodecContext { var cc *C.struct_AVCodec if c != nil { @@ -47,18 +58,12 @@ func AllocCodecContext(c *Codec) *CodecContext { return newCodecContextFromC(C.avcodec_alloc_context3(cc)) } -func newCodecContextFromC(c *C.struct_AVCodecContext) *CodecContext { - if c == nil { - return nil - } - return &CodecContext{c: c} -} - func (cc *CodecContext) Free() { if cc.hdc != nil { C.av_buffer_unref(&cc.hdc.c) cc.hdc = nil } + classers.del(cc) C.avcodec_free_context(&cc.c) } @@ -99,6 +104,10 @@ func (cc *CodecContext) ChromaLocation() ChromaLocation { return ChromaLocation(cc.c.chroma_sample_location) } +func (cc *CodecContext) Class() *Class { + return newClassFromC(unsafe.Pointer(cc.c)) +} + func (cc *CodecContext) CodecID() CodecID { return CodecID(cc.c.codec_id) } diff --git a/codec_context_test.go b/codec_context_test.go index 11fc336..b9badb0 100644 --- a/codec_context_test.go +++ b/codec_context_test.go @@ -1,9 +1,8 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) @@ -15,36 +14,39 @@ func TestCodecContext(t *testing.T) { s1 := ss[0] s2 := ss[1] - c1 := astiav.FindDecoder(s1.CodecParameters().CodecID()) + c1 := FindDecoder(s1.CodecParameters().CodecID()) require.NotNil(t, c1) - cc1 := astiav.AllocCodecContext(c1) + cc1 := AllocCodecContext(c1) require.NotNil(t, cc1) defer cc1.Free() err = s1.CodecParameters().ToCodecContext(cc1) require.NoError(t, err) require.Equal(t, "Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(progressive), 320x180 [SAR 1:1 DAR 16:9], 441 kb/s", cc1.String()) require.Equal(t, int64(441324), cc1.BitRate()) - require.Equal(t, astiav.ChromaLocationLeft, cc1.ChromaLocation()) - require.Equal(t, astiav.CodecIDH264, cc1.CodecID()) - require.Equal(t, astiav.ColorPrimariesUnspecified, cc1.ColorPrimaries()) - require.Equal(t, astiav.ColorRangeUnspecified, cc1.ColorRange()) - require.Equal(t, astiav.ColorSpaceUnspecified, cc1.ColorSpace()) - require.Equal(t, astiav.ColorTransferCharacteristicUnspecified, cc1.ColorTransferCharacteristic()) + require.Equal(t, ChromaLocationLeft, cc1.ChromaLocation()) + require.Equal(t, CodecIDH264, cc1.CodecID()) + require.Equal(t, ColorPrimariesUnspecified, cc1.ColorPrimaries()) + require.Equal(t, ColorRangeUnspecified, cc1.ColorRange()) + require.Equal(t, ColorSpaceUnspecified, cc1.ColorSpace()) + require.Equal(t, ColorTransferCharacteristicUnspecified, cc1.ColorTransferCharacteristic()) require.Equal(t, 12, cc1.GopSize()) require.Equal(t, 180, cc1.Height()) - require.Equal(t, astiav.Level(13), cc1.Level()) - require.Equal(t, astiav.MediaTypeVideo, cc1.MediaType()) - require.Equal(t, astiav.PixelFormatYuv420P, cc1.PixelFormat()) - require.Equal(t, astiav.ProfileH264ConstrainedBaseline, cc1.Profile()) - require.Equal(t, astiav.NewRational(1, 1), cc1.SampleAspectRatio()) - require.Equal(t, astiav.StrictStdComplianceNormal, cc1.StrictStdCompliance()) + require.Equal(t, Level(13), cc1.Level()) + require.Equal(t, MediaTypeVideo, cc1.MediaType()) + require.Equal(t, PixelFormatYuv420P, cc1.PixelFormat()) + require.Equal(t, ProfileH264ConstrainedBaseline, cc1.Profile()) + require.Equal(t, NewRational(1, 1), cc1.SampleAspectRatio()) + require.Equal(t, StrictStdComplianceNormal, cc1.StrictStdCompliance()) require.Equal(t, 1, cc1.ThreadCount()) - require.Equal(t, astiav.ThreadType(3), cc1.ThreadType()) + require.Equal(t, ThreadType(3), cc1.ThreadType()) require.Equal(t, 320, cc1.Width()) + cl := cc1.Class() + require.NotNil(t, cl) + require.Equal(t, "AVCodecContext", cl.Name()) - c2 := astiav.FindDecoder(s2.CodecParameters().CodecID()) + c2 := FindDecoder(s2.CodecParameters().CodecID()) require.NotNil(t, c2) - cc2 := astiav.AllocCodecContext(c2) + cc2 := AllocCodecContext(c2) require.NotNil(t, cc2) defer cc2.Free() err = s2.CodecParameters().ToCodecContext(cc2) @@ -52,66 +54,66 @@ func TestCodecContext(t *testing.T) { require.Equal(t, "Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 161 kb/s", cc2.String()) require.Equal(t, int64(161052), cc2.BitRate()) require.Equal(t, 2, cc2.Channels()) - require.True(t, cc2.ChannelLayout().Equal(astiav.ChannelLayoutStereo)) - require.Equal(t, astiav.CodecIDAac, cc2.CodecID()) + require.True(t, cc2.ChannelLayout().Equal(ChannelLayoutStereo)) + require.Equal(t, CodecIDAac, cc2.CodecID()) require.Equal(t, 1024, cc2.FrameSize()) - require.Equal(t, astiav.MediaTypeAudio, cc2.MediaType()) - require.Equal(t, astiav.SampleFormatFltp, cc2.SampleFormat()) + require.Equal(t, MediaTypeAudio, cc2.MediaType()) + require.Equal(t, SampleFormatFltp, cc2.SampleFormat()) require.Equal(t, 48000, cc2.SampleRate()) - require.Equal(t, astiav.StrictStdComplianceNormal, cc2.StrictStdCompliance()) + require.Equal(t, StrictStdComplianceNormal, cc2.StrictStdCompliance()) require.Equal(t, 1, cc2.ThreadCount()) - require.Equal(t, astiav.ThreadType(3), cc2.ThreadType()) + require.Equal(t, ThreadType(3), cc2.ThreadType()) - c3 := astiav.FindEncoder(astiav.CodecIDMjpeg) + c3 := FindEncoder(CodecIDMjpeg) require.NotNil(t, c3) - cc3 := astiav.AllocCodecContext(c3) + cc3 := AllocCodecContext(c3) require.NotNil(t, cc3) defer cc3.Free() cc3.SetHeight(2) - cc3.SetPixelFormat(astiav.PixelFormatYuvj420P) - cc3.SetTimeBase(astiav.NewRational(1, 1)) + cc3.SetPixelFormat(PixelFormatYuvj420P) + cc3.SetTimeBase(NewRational(1, 1)) cc3.SetWidth(3) err = cc3.Open(c3, nil) require.NoError(t, err) - cc4 := astiav.AllocCodecContext(nil) + cc4 := AllocCodecContext(nil) require.NotNil(t, cc4) defer cc4.Free() cc4.SetBitRate(1) - cc4.SetChannelLayout(astiav.ChannelLayout21) + cc4.SetChannelLayout(ChannelLayout21) cc4.SetChannels(3) - cc4.SetFlags(astiav.NewCodecContextFlags(4)) - cc4.SetFlags2(astiav.NewCodecContextFlags2(5)) - cc4.SetFramerate(astiav.NewRational(6, 1)) + cc4.SetFlags(NewCodecContextFlags(4)) + cc4.SetFlags2(NewCodecContextFlags2(5)) + cc4.SetFramerate(NewRational(6, 1)) cc4.SetGopSize(7) cc4.SetHeight(8) - cc4.SetPixelFormat(astiav.PixelFormat0Bgr) + cc4.SetPixelFormat(PixelFormat0Bgr) cc4.SetQmin(5) - cc4.SetSampleAspectRatio(astiav.NewRational(10, 1)) - cc4.SetSampleFormat(astiav.SampleFormatDbl) + cc4.SetSampleAspectRatio(NewRational(10, 1)) + cc4.SetSampleFormat(SampleFormatDbl) cc4.SetSampleRate(12) - cc4.SetStrictStdCompliance(astiav.StrictStdComplianceExperimental) + cc4.SetStrictStdCompliance(StrictStdComplianceExperimental) cc4.SetThreadCount(13) - cc4.SetThreadType(astiav.ThreadTypeSlice) - cc4.SetTimeBase(astiav.NewRational(15, 1)) + cc4.SetThreadType(ThreadTypeSlice) + cc4.SetTimeBase(NewRational(15, 1)) cc4.SetWidth(16) require.Equal(t, int64(1), cc4.BitRate()) - require.True(t, cc4.ChannelLayout().Equal(astiav.ChannelLayout21)) + require.True(t, cc4.ChannelLayout().Equal(ChannelLayout21)) require.Equal(t, 3, cc4.Channels()) - require.Equal(t, astiav.NewCodecContextFlags(4), cc4.Flags()) - require.Equal(t, astiav.NewCodecContextFlags2(5), cc4.Flags2()) - require.Equal(t, astiav.NewRational(6, 1), cc4.Framerate()) + require.Equal(t, NewCodecContextFlags(4), cc4.Flags()) + require.Equal(t, NewCodecContextFlags2(5), cc4.Flags2()) + require.Equal(t, NewRational(6, 1), cc4.Framerate()) require.Equal(t, 7, cc4.GopSize()) require.Equal(t, 8, cc4.Height()) - require.Equal(t, astiav.PixelFormat0Bgr, cc4.PixelFormat()) + require.Equal(t, PixelFormat0Bgr, cc4.PixelFormat()) require.Equal(t, 5, cc4.Qmin()) - require.Equal(t, astiav.NewRational(10, 1), cc4.SampleAspectRatio()) - require.Equal(t, astiav.SampleFormatDbl, cc4.SampleFormat()) + require.Equal(t, NewRational(10, 1), cc4.SampleAspectRatio()) + require.Equal(t, SampleFormatDbl, cc4.SampleFormat()) require.Equal(t, 12, cc4.SampleRate()) - require.Equal(t, astiav.StrictStdComplianceExperimental, cc4.StrictStdCompliance()) + require.Equal(t, StrictStdComplianceExperimental, cc4.StrictStdCompliance()) require.Equal(t, 13, cc4.ThreadCount()) - require.Equal(t, astiav.ThreadTypeSlice, cc4.ThreadType()) - require.Equal(t, astiav.NewRational(15, 1), cc4.TimeBase()) + require.Equal(t, ThreadTypeSlice, cc4.ThreadType()) + require.Equal(t, NewRational(15, 1), cc4.TimeBase()) require.Equal(t, 16, cc4.Width()) // TODO Test ReceivePacket diff --git a/codec_id_test.go b/codec_id_test.go index fb46dc0..9a5c941 100644 --- a/codec_id_test.go +++ b/codec_id_test.go @@ -1,14 +1,13 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestCodecID(t *testing.T) { - require.Equal(t, astiav.MediaTypeVideo, astiav.CodecIDH264.MediaType()) - require.Equal(t, "h264", astiav.CodecIDH264.Name()) - require.Equal(t, "h264", astiav.CodecIDH264.String()) + require.Equal(t, MediaTypeVideo, CodecIDH264.MediaType()) + require.Equal(t, "h264", CodecIDH264.Name()) + require.Equal(t, "h264", CodecIDH264.String()) } diff --git a/codec_parameters_test.go b/codec_parameters_test.go index 2d632be..9d40eb8 100644 --- a/codec_parameters_test.go +++ b/codec_parameters_test.go @@ -1,9 +1,8 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) @@ -17,75 +16,75 @@ func TestCodecParameters(t *testing.T) { cp1 := s1.CodecParameters() require.Equal(t, int64(441324), cp1.BitRate()) - require.Equal(t, astiav.ChromaLocationLeft, cp1.ChromaLocation()) - require.Equal(t, astiav.CodecIDH264, cp1.CodecID()) - require.Equal(t, astiav.CodecTag(0x31637661), cp1.CodecTag()) - require.Equal(t, astiav.ColorPrimariesUnspecified, cp1.ColorPrimaries()) - require.Equal(t, astiav.ColorRangeUnspecified, cp1.ColorRange()) - require.Equal(t, astiav.ColorSpaceUnspecified, cp1.ColorSpace()) - require.Equal(t, astiav.ColorTransferCharacteristicUnspecified, cp1.ColorTransferCharacteristic()) + require.Equal(t, ChromaLocationLeft, cp1.ChromaLocation()) + require.Equal(t, CodecIDH264, cp1.CodecID()) + require.Equal(t, CodecTag(0x31637661), cp1.CodecTag()) + require.Equal(t, ColorPrimariesUnspecified, cp1.ColorPrimaries()) + require.Equal(t, ColorRangeUnspecified, cp1.ColorRange()) + require.Equal(t, ColorSpaceUnspecified, cp1.ColorSpace()) + require.Equal(t, ColorTransferCharacteristicUnspecified, cp1.ColorTransferCharacteristic()) require.Equal(t, 180, cp1.Height()) - require.Equal(t, astiav.Level(13), cp1.Level()) - require.Equal(t, astiav.MediaTypeVideo, cp1.MediaType()) - require.Equal(t, astiav.PixelFormatYuv420P, cp1.PixelFormat()) - require.Equal(t, astiav.ProfileH264ConstrainedBaseline, cp1.Profile()) - require.Equal(t, astiav.NewRational(1, 1), cp1.SampleAspectRatio()) + require.Equal(t, Level(13), cp1.Level()) + require.Equal(t, MediaTypeVideo, cp1.MediaType()) + require.Equal(t, PixelFormatYuv420P, cp1.PixelFormat()) + require.Equal(t, ProfileH264ConstrainedBaseline, cp1.Profile()) + require.Equal(t, NewRational(1, 1), cp1.SampleAspectRatio()) require.Equal(t, 320, cp1.Width()) cp2 := s2.CodecParameters() require.Equal(t, int64(161052), cp2.BitRate()) require.Equal(t, 2, cp2.Channels()) - require.True(t, cp2.ChannelLayout().Equal(astiav.ChannelLayoutStereo)) - require.Equal(t, astiav.CodecIDAac, cp2.CodecID()) - require.Equal(t, astiav.CodecTag(0x6134706d), cp2.CodecTag()) + require.True(t, cp2.ChannelLayout().Equal(ChannelLayoutStereo)) + require.Equal(t, CodecIDAac, cp2.CodecID()) + require.Equal(t, CodecTag(0x6134706d), cp2.CodecTag()) require.Equal(t, 1024, cp2.FrameSize()) - require.Equal(t, astiav.MediaTypeAudio, cp2.MediaType()) - require.Equal(t, astiav.SampleFormatFltp, cp2.SampleFormat()) + require.Equal(t, MediaTypeAudio, cp2.MediaType()) + require.Equal(t, SampleFormatFltp, cp2.SampleFormat()) require.Equal(t, 48000, cp2.SampleRate()) - cp3 := astiav.AllocCodecParameters() + cp3 := AllocCodecParameters() require.NotNil(t, cp3) defer cp3.Free() err = cp2.Copy(cp3) require.NoError(t, err) require.Equal(t, 2, cp3.Channels()) - cc4 := astiav.AllocCodecContext(nil) + cc4 := AllocCodecContext(nil) require.NotNil(t, cc4) defer cc4.Free() err = cp2.ToCodecContext(cc4) require.NoError(t, err) require.Equal(t, 2, cc4.Channels()) - cp5 := astiav.AllocCodecParameters() + cp5 := AllocCodecParameters() require.NotNil(t, cp5) defer cp5.Free() err = cp5.FromCodecContext(cc4) require.NoError(t, err) require.Equal(t, 2, cp5.Channels()) - cp6 := astiav.AllocCodecParameters() + cp6 := AllocCodecParameters() require.NotNil(t, cp6) defer cp6.Free() - cp6.SetChannelLayout(astiav.ChannelLayout21) - require.True(t, cp6.ChannelLayout().Equal(astiav.ChannelLayout21)) + cp6.SetChannelLayout(ChannelLayout21) + require.True(t, cp6.ChannelLayout().Equal(ChannelLayout21)) defer cp6.Free() cp6.SetChannels(3) require.Equal(t, 3, cp6.Channels()) - cp6.SetCodecID(astiav.CodecIDRawvideo) - require.Equal(t, astiav.CodecIDRawvideo, cp6.CodecID()) - cp6.SetCodecTag(astiav.CodecTag(2)) - require.Equal(t, astiav.CodecTag(2), cp6.CodecTag()) - cp6.SetCodecType(astiav.MediaTypeAudio) - require.Equal(t, astiav.MediaTypeAudio, cp6.CodecType()) + cp6.SetCodecID(CodecIDRawvideo) + require.Equal(t, CodecIDRawvideo, cp6.CodecID()) + cp6.SetCodecTag(CodecTag(2)) + require.Equal(t, CodecTag(2), cp6.CodecTag()) + cp6.SetCodecType(MediaTypeAudio) + require.Equal(t, MediaTypeAudio, cp6.CodecType()) cp6.SetHeight(1) require.Equal(t, 1, cp6.Height()) - cp6.SetPixelFormat(astiav.PixelFormat0Bgr) - require.Equal(t, astiav.PixelFormat0Bgr, cp6.PixelFormat()) - cp6.SetSampleAspectRatio(astiav.NewRational(1, 2)) - require.Equal(t, astiav.NewRational(1, 2), cp6.SampleAspectRatio()) - cp6.SetSampleFormat(astiav.SampleFormatDbl) - require.Equal(t, astiav.SampleFormatDbl, cp6.SampleFormat()) + cp6.SetPixelFormat(PixelFormat0Bgr) + require.Equal(t, PixelFormat0Bgr, cp6.PixelFormat()) + cp6.SetSampleAspectRatio(NewRational(1, 2)) + require.Equal(t, NewRational(1, 2), cp6.SampleAspectRatio()) + cp6.SetSampleFormat(SampleFormatDbl) + require.Equal(t, SampleFormatDbl, cp6.SampleFormat()) cp6.SetSampleRate(4) require.Equal(t, 4, cp6.SampleRate()) cp6.SetWidth(2) diff --git a/codec_test.go b/codec_test.go index 8dc5ae5..8562123 100644 --- a/codec_test.go +++ b/codec_test.go @@ -1,34 +1,33 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestCodec(t *testing.T) { - c := astiav.FindDecoder(astiav.CodecIDMp3) + c := FindDecoder(CodecIDMp3) require.NotNil(t, c) - require.Equal(t, c.ID(), astiav.CodecIDMp3) + require.Equal(t, c.ID(), CodecIDMp3) require.Nil(t, c.ChannelLayouts()) require.True(t, c.IsDecoder()) require.False(t, c.IsEncoder()) require.Nil(t, c.PixelFormats()) - require.Equal(t, []astiav.SampleFormat{astiav.SampleFormatFltp, astiav.SampleFormatFlt}, c.SampleFormats()) + require.Equal(t, []SampleFormat{SampleFormatFltp, SampleFormatFlt}, c.SampleFormats()) require.Equal(t, "mp3float", c.Name()) require.Equal(t, "mp3float", c.String()) - c = astiav.FindDecoderByName("aac") + c = FindDecoderByName("aac") require.NotNil(t, c) - els := []astiav.ChannelLayout{ - astiav.ChannelLayoutMono, - astiav.ChannelLayoutStereo, - astiav.ChannelLayoutSurround, - astiav.ChannelLayout4Point0, - astiav.ChannelLayout5Point0Back, - astiav.ChannelLayout5Point1Back, - astiav.ChannelLayout7Point1WideBack, + els := []ChannelLayout{ + ChannelLayoutMono, + ChannelLayoutStereo, + ChannelLayoutSurround, + ChannelLayout4Point0, + ChannelLayout5Point0Back, + ChannelLayout5Point1Back, + ChannelLayout7Point1WideBack, } gls := c.ChannelLayouts() require.Len(t, gls, len(els)) @@ -37,40 +36,40 @@ func TestCodec(t *testing.T) { } require.True(t, c.IsDecoder()) require.False(t, c.IsEncoder()) - require.Equal(t, []astiav.SampleFormat{astiav.SampleFormatFltp}, c.SampleFormats()) + require.Equal(t, []SampleFormat{SampleFormatFltp}, c.SampleFormats()) require.Equal(t, "aac", c.Name()) require.Equal(t, "aac", c.String()) - c = astiav.FindEncoder(astiav.CodecIDMjpeg) + c = FindEncoder(CodecIDMjpeg) require.NotNil(t, c) require.False(t, c.IsDecoder()) require.True(t, c.IsEncoder()) - require.Contains(t, c.PixelFormats(), astiav.PixelFormatYuvj420P) + require.Contains(t, c.PixelFormats(), PixelFormatYuvj420P) require.Nil(t, c.SampleFormats()) require.Contains(t, c.Name(), "mjpeg") require.Contains(t, c.String(), "mjpeg") - c = astiav.FindEncoderByName("mjpeg") + c = FindEncoderByName("mjpeg") require.NotNil(t, c) require.False(t, c.IsDecoder()) require.True(t, c.IsEncoder()) - require.Equal(t, []astiav.PixelFormat{ - astiav.PixelFormatYuvj420P, - astiav.PixelFormatYuvj422P, - astiav.PixelFormatYuvj444P, - astiav.PixelFormatYuv420P, - astiav.PixelFormatYuv422P, - astiav.PixelFormatYuv444P, + require.Equal(t, []PixelFormat{ + PixelFormatYuvj420P, + PixelFormatYuvj422P, + PixelFormatYuvj444P, + PixelFormatYuv420P, + PixelFormatYuv422P, + PixelFormatYuv444P, }, c.PixelFormats()) require.Equal(t, "mjpeg", c.Name()) require.Equal(t, "mjpeg", c.String()) - c = astiav.FindDecoderByName("invalid") + c = FindDecoderByName("invalid") require.Nil(t, c) var found bool - for _, c := range astiav.Codecs() { - if c.ID() == astiav.CodecIDMjpeg { + for _, c := range Codecs() { + if c.ID() == CodecIDMjpeg { found = true } } diff --git a/device_test.go b/device_test.go index 9eff1b9..010fb1f 100644 --- a/device_test.go +++ b/device_test.go @@ -1,11 +1,9 @@ -package astiav_test +package astiav import ( "testing" - - "github.com/asticode/go-astiav" ) func TestDevice(t *testing.T) { - astiav.RegisterAllDevices() + RegisterAllDevices() } diff --git a/error_test.go b/error_test.go index 7f2adaa..97844f7 100644 --- a/error_test.go +++ b/error_test.go @@ -1,11 +1,10 @@ -package astiav_test +package astiav import ( "errors" "fmt" "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) @@ -14,10 +13,10 @@ type testError struct{} func (err testError) Error() string { return "" } func TestError(t *testing.T) { - require.Equal(t, "Decoder not found", astiav.ErrDecoderNotFound.Error()) - err1 := fmt.Errorf("test 1: %w", astiav.ErrDecoderNotFound) - require.True(t, errors.Is(err1, astiav.ErrDecoderNotFound)) + require.Equal(t, "Decoder not found", ErrDecoderNotFound.Error()) + err1 := fmt.Errorf("test 1: %w", ErrDecoderNotFound) + require.True(t, errors.Is(err1, ErrDecoderNotFound)) require.False(t, errors.Is(err1, testError{})) - err2 := fmt.Errorf("test 2: %w", astiav.ErrDemuxerNotFound) - require.False(t, errors.Is(err2, astiav.ErrDecoderNotFound)) + err2 := fmt.Errorf("test 2: %w", ErrDemuxerNotFound) + require.False(t, errors.Is(err2, ErrDecoderNotFound)) } diff --git a/examples/demuxing_decoding/main.go b/examples/demuxing_decoding/main.go index fdc8f0c..4b43bbe 100644 --- a/examples/demuxing_decoding/main.go +++ b/examples/demuxing_decoding/main.go @@ -23,8 +23,14 @@ type stream struct { func main() { // Handle ffmpeg logs astiav.SetLogLevel(astiav.LogLevelDebug) - astiav.SetLogCallback(func(l astiav.LogLevel, fmt, msg, parent string) { - log.Printf("ffmpeg log: %s (level: %d)\n", strings.TrimSpace(msg), l) + 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) }) // Parse flags diff --git a/examples/filtering/main.go b/examples/filtering/main.go index 0028114..9090fc0 100644 --- a/examples/filtering/main.go +++ b/examples/filtering/main.go @@ -37,8 +37,14 @@ type stream struct { func main() { // Handle ffmpeg logs astiav.SetLogLevel(astiav.LogLevelDebug) - astiav.SetLogCallback(func(l astiav.LogLevel, fmt, msg, parent string) { - log.Printf("ffmpeg log: %s (level: %d)\n", strings.TrimSpace(msg), l) + 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) }) // Parse flags diff --git a/examples/hardware_decoding/main.go b/examples/hardware_decoding/main.go index 0056570..5d15f93 100644 --- a/examples/hardware_decoding/main.go +++ b/examples/hardware_decoding/main.go @@ -28,8 +28,14 @@ type stream struct { func main() { // Handle ffmpeg logs astiav.SetLogLevel(astiav.LogLevelDebug) - astiav.SetLogCallback(func(l astiav.LogLevel, fmt, msg, parent string) { - log.Printf("ffmpeg log: %s (level: %d)\n", strings.TrimSpace(msg), l) + 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) }) // Parse flags diff --git a/examples/remuxing/main.go b/examples/remuxing/main.go index 65c7c47..8ef74e5 100644 --- a/examples/remuxing/main.go +++ b/examples/remuxing/main.go @@ -18,8 +18,14 @@ var ( func main() { // Handle ffmpeg logs astiav.SetLogLevel(astiav.LogLevelDebug) - astiav.SetLogCallback(func(l astiav.LogLevel, fmt, msg, parent string) { - log.Printf("ffmpeg log: %s (level: %d)\n", strings.TrimSpace(msg), l) + 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) }) // Parse flags @@ -96,11 +102,9 @@ func main() { // If this is a file, we need to use an io context if !outputFormatContext.OutputFormat().Flags().Has(astiav.IOFormatFlagNofile) { - // Create io context - ioContext := astiav.NewIOContext() - // Open io context - if err = ioContext.Open(*output, astiav.NewIOContextFlags(astiav.IOContextFlagWrite)); err != nil { + ioContext, err := astiav.OpenIOContext(*output, astiav.NewIOContextFlags(astiav.IOContextFlagWrite)) + if err != nil { log.Fatal(fmt.Errorf("main: opening io context failed: %w", err)) } defer ioContext.Closep() //nolint:errcheck diff --git a/examples/scaling/main.go b/examples/scaling/main.go index e8921ba..640c8a1 100644 --- a/examples/scaling/main.go +++ b/examples/scaling/main.go @@ -20,8 +20,14 @@ var ( func main() { // Handle ffmpeg logs astiav.SetLogLevel(astiav.LogLevelDebug) - astiav.SetLogCallback(func(l astiav.LogLevel, fmt, msg, parent string) { - log.Printf("ffmpeg log: %s (level: %d)\n", strings.TrimSpace(msg), l) + 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) }) // Parse flags diff --git a/examples/transcoding/main.go b/examples/transcoding/main.go index 5c629b8..6726856 100644 --- a/examples/transcoding/main.go +++ b/examples/transcoding/main.go @@ -42,8 +42,14 @@ type stream struct { func main() { // Handle ffmpeg logs astiav.SetLogLevel(astiav.LogLevelDebug) - astiav.SetLogCallback(func(l astiav.LogLevel, fmt, msg, parent string) { - log.Printf("ffmpeg log: %s (level: %d)\n", strings.TrimSpace(msg), l) + 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) }) // Parse flags @@ -306,11 +312,9 @@ func openOutputFile() (err error) { // If this is a file, we need to use an io context if !outputFormatContext.OutputFormat().Flags().Has(astiav.IOFormatFlagNofile) { - // Create io context - ioContext := astiav.NewIOContext() - // Open io context - if err = ioContext.Open(*output, astiav.NewIOContextFlags(astiav.IOContextFlagWrite)); err != nil { + var ioContext *astiav.IOContext + if ioContext, err = astiav.OpenIOContext(*output, astiav.NewIOContextFlags(astiav.IOContextFlagWrite)); err != nil { err = fmt.Errorf("main: opening io context failed: %w", err) return } diff --git a/filter_context.go b/filter_context.go index 90a2d31..94325ee 100644 --- a/filter_context.go +++ b/filter_context.go @@ -6,18 +6,28 @@ package astiav //#include //#include import "C" -import "unsafe" +import ( + "unsafe" +) // https://github.com/FFmpeg/FFmpeg/blob/n5.0/libavfilter/avfilter.h#L67 type FilterContext struct { c *C.struct_AVFilterContext } -func newFilterContext() *FilterContext { - return &FilterContext{} +func newFilterContext(c *C.struct_AVFilterContext) *FilterContext { + if c == nil { + return nil + } + fc := &FilterContext{c: c} + classers.set(fc) + return fc } +var _ Classer = (*FilterContext)(nil) + func (fc *FilterContext) Free() { + classers.del(fc) C.avfilter_free(fc.c) } @@ -37,6 +47,10 @@ func (fc *FilterContext) BuffersinkGetFrame(f *Frame, fs BuffersinkFlags) error return newError(C.av_buffersink_get_frame_flags(fc.c, cf, C.int(fs))) } +func (fc *FilterContext) Class() *Class { + return newClassFromC(unsafe.Pointer(fc.c)) +} + func (fc *FilterContext) NbInputs() int { return int(fc.c.nb_inputs) } diff --git a/filter_graph.go b/filter_graph.go index 1a7e482..2d8c783 100644 --- a/filter_graph.go +++ b/filter_graph.go @@ -17,21 +17,32 @@ func newFilterGraphFromC(c *C.struct_AVFilterGraph) *FilterGraph { if c == nil { return nil } - return &FilterGraph{c: c} + g := &FilterGraph{c: c} + classers.set(g) + return g } +var _ Classer = (*FilterGraph)(nil) + func AllocFilterGraph() *FilterGraph { return newFilterGraphFromC(C.avfilter_graph_alloc()) } func (g *FilterGraph) Free() { - C.avfilter_graph_free(&g.c) + classers.del(g) + if g.c != nil { + C.avfilter_graph_free(&g.c) + } } func (g *FilterGraph) String() string { return C.GoString(C.avfilter_graph_dump(g.c, nil)) } +func (g *FilterGraph) Class() *Class { + return newClassFromC(unsafe.Pointer(g.c)) +} + type FilterArgs map[string]string func (args FilterArgs) String() string { @@ -50,9 +61,11 @@ func (g *FilterGraph) NewFilterContext(f *Filter, name string, args FilterArgs) } cn := C.CString(name) defer C.free(unsafe.Pointer(cn)) - fc := newFilterContext() - err := newError(C.avfilter_graph_create_filter(&fc.c, f.c, cn, ca, nil, g.c)) - return fc, err + var c *C.struct_AVFilterContext + if err := newError(C.avfilter_graph_create_filter(&c, f.c, cn, ca, nil, g.c)); err != nil { + return nil, err + } + return newFilterContext(c), nil } func (g *FilterGraph) Parse(content string, inputs, outputs *FilterInOut) error { diff --git a/filter_graph_test.go b/filter_graph_test.go index 8509b11..46d750d 100644 --- a/filter_graph_test.go +++ b/filter_graph_test.go @@ -1,48 +1,53 @@ // TODO Fix https://github.com/asticode/go-astiav/actions/runs/5853322732/job/15867145888 //go:build !windows -package astiav_test +package astiav import ( "fmt" "strconv" "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestFilterGraph(t *testing.T) { - fg := astiav.AllocFilterGraph() + fg := AllocFilterGraph() defer fg.Free() + cl := fg.Class() + require.NotNil(t, cl) + require.Equal(t, "AVFilterGraph", cl.Name()) - bufferSink := astiav.FindFilterByName("buffersink") + bufferSink := FindFilterByName("buffersink") require.NotNil(t, bufferSink) fcOut, err := fg.NewFilterContext(bufferSink, "filter_out", nil) require.NoError(t, err) defer fcOut.Free() + cl = fcOut.Class() + require.NotNil(t, cl) + require.Equal(t, "AVFilter", cl.Name()) - inputs := astiav.AllocFilterInOut() + inputs := AllocFilterInOut() defer inputs.Free() inputs.SetName("out") inputs.SetFilterContext(fcOut) inputs.SetPadIdx(0) inputs.SetNext(nil) - var outputs *astiav.FilterInOut + var outputs *FilterInOut defer func() { if outputs != nil { outputs.Free() } }() - var fcIns []*astiav.FilterContext + var fcIns []*FilterContext for i := 0; i < 2; i++ { - bufferSrc := astiav.FindFilterByName("buffer") + bufferSrc := FindFilterByName("buffer") require.NotNil(t, bufferSrc) - fcIn, err := fg.NewFilterContext(bufferSrc, fmt.Sprintf("filter_in_%d", i+1), astiav.FilterArgs{ - "pix_fmt": strconv.Itoa(int(astiav.PixelFormatYuv420P)), + fcIn, err := fg.NewFilterContext(bufferSrc, fmt.Sprintf("filter_in_%d", i+1), FilterArgs{ + "pix_fmt": strconv.Itoa(int(PixelFormatYuv420P)), "pixel_aspect": "1/1", "time_base": "1/1000", "video_size": "1x1", @@ -51,7 +56,7 @@ func TestFilterGraph(t *testing.T) { fcIns = append(fcIns, fcIn) defer fcIn.Free() - o := astiav.AllocFilterInOut() + o := AllocFilterInOut() o.SetName(fmt.Sprintf("input_%d", i+1)) o.SetFilterContext(fcIn) o.SetPadIdx(0) @@ -68,19 +73,19 @@ func TestFilterGraph(t *testing.T) { require.Equal(t, 1, fcOut.NbInputs()) require.Equal(t, 1, len(fcOut.Inputs())) - require.Equal(t, astiav.NewRational(1, 1000), fcOut.Inputs()[0].TimeBase()) + require.Equal(t, NewRational(1, 1000), fcOut.Inputs()[0].TimeBase()) require.Equal(t, 0, fcOut.NbOutputs()) for _, fc := range fcIns { require.Equal(t, 0, fc.NbInputs()) require.Equal(t, 1, fc.NbOutputs()) require.Equal(t, 1, len(fc.Outputs())) - require.Equal(t, astiav.NewRational(1, 1000), fc.Outputs()[0].TimeBase()) + require.Equal(t, NewRational(1, 1000), fc.Outputs()[0].TimeBase()) } - resp, err := fg.SendCommand("scale", "invalid", "a", astiav.NewFilterCommandFlags()) + resp, err := fg.SendCommand("scale", "invalid", "a", NewFilterCommandFlags()) require.Error(t, err) require.Empty(t, resp) - resp, err = fg.SendCommand("scale", "width", "4", astiav.NewFilterCommandFlags().Add(astiav.FilterCommandFlagOne)) + resp, err = fg.SendCommand("scale", "width", "4", NewFilterCommandFlags().Add(FilterCommandFlagOne)) require.NoError(t, err) require.Empty(t, resp) diff --git a/filter_test.go b/filter_test.go index cb24286..82c7e50 100644 --- a/filter_test.go +++ b/filter_test.go @@ -1,14 +1,13 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestFilter(t *testing.T) { - f := astiav.FindFilterByName("format") + f := FindFilterByName("format") require.NotNil(t, f) require.Equal(t, "format", f.Name()) require.Equal(t, "format", f.String()) diff --git a/flags_test.go b/flags_test.go index d6189cf..cc7acfd 100644 --- a/flags_test.go +++ b/flags_test.go @@ -1,152 +1,151 @@ // Code generated by astiav. DO NOT EDIT. -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestBuffersinkFlags(t *testing.T) { - fs := astiav.NewBuffersinkFlags(astiav.BuffersinkFlag(1)) - require.True(t, fs.Has(astiav.BuffersinkFlag(1))) - fs = fs.Add(astiav.BuffersinkFlag(2)) - require.True(t, fs.Has(astiav.BuffersinkFlag(2))) - fs = fs.Del(astiav.BuffersinkFlag(2)) - require.False(t, fs.Has(astiav.BuffersinkFlag(2))) + fs := NewBuffersinkFlags(BuffersinkFlag(1)) + require.True(t, fs.Has(BuffersinkFlag(1))) + fs = fs.Add(BuffersinkFlag(2)) + require.True(t, fs.Has(BuffersinkFlag(2))) + fs = fs.Del(BuffersinkFlag(2)) + require.False(t, fs.Has(BuffersinkFlag(2))) } func TestBuffersrcFlags(t *testing.T) { - fs := astiav.NewBuffersrcFlags(astiav.BuffersrcFlag(1)) - require.True(t, fs.Has(astiav.BuffersrcFlag(1))) - fs = fs.Add(astiav.BuffersrcFlag(2)) - require.True(t, fs.Has(astiav.BuffersrcFlag(2))) - fs = fs.Del(astiav.BuffersrcFlag(2)) - require.False(t, fs.Has(astiav.BuffersrcFlag(2))) + fs := NewBuffersrcFlags(BuffersrcFlag(1)) + require.True(t, fs.Has(BuffersrcFlag(1))) + fs = fs.Add(BuffersrcFlag(2)) + require.True(t, fs.Has(BuffersrcFlag(2))) + fs = fs.Del(BuffersrcFlag(2)) + require.False(t, fs.Has(BuffersrcFlag(2))) } func TestCodecContextFlags(t *testing.T) { - fs := astiav.NewCodecContextFlags(astiav.CodecContextFlag(1)) - require.True(t, fs.Has(astiav.CodecContextFlag(1))) - fs = fs.Add(astiav.CodecContextFlag(2)) - require.True(t, fs.Has(astiav.CodecContextFlag(2))) - fs = fs.Del(astiav.CodecContextFlag(2)) - require.False(t, fs.Has(astiav.CodecContextFlag(2))) + fs := NewCodecContextFlags(CodecContextFlag(1)) + require.True(t, fs.Has(CodecContextFlag(1))) + fs = fs.Add(CodecContextFlag(2)) + require.True(t, fs.Has(CodecContextFlag(2))) + fs = fs.Del(CodecContextFlag(2)) + require.False(t, fs.Has(CodecContextFlag(2))) } func TestCodecContextFlags2(t *testing.T) { - fs := astiav.NewCodecContextFlags2(astiav.CodecContextFlag2(1)) - require.True(t, fs.Has(astiav.CodecContextFlag2(1))) - fs = fs.Add(astiav.CodecContextFlag2(2)) - require.True(t, fs.Has(astiav.CodecContextFlag2(2))) - fs = fs.Del(astiav.CodecContextFlag2(2)) - require.False(t, fs.Has(astiav.CodecContextFlag2(2))) + fs := NewCodecContextFlags2(CodecContextFlag2(1)) + require.True(t, fs.Has(CodecContextFlag2(1))) + fs = fs.Add(CodecContextFlag2(2)) + require.True(t, fs.Has(CodecContextFlag2(2))) + fs = fs.Del(CodecContextFlag2(2)) + require.False(t, fs.Has(CodecContextFlag2(2))) } func TestCodecHardwareConfigMethodFlags(t *testing.T) { - fs := astiav.NewCodecHardwareConfigMethodFlags(astiav.CodecHardwareConfigMethodFlag(1)) - require.True(t, fs.Has(astiav.CodecHardwareConfigMethodFlag(1))) - fs = fs.Add(astiav.CodecHardwareConfigMethodFlag(2)) - require.True(t, fs.Has(astiav.CodecHardwareConfigMethodFlag(2))) - fs = fs.Del(astiav.CodecHardwareConfigMethodFlag(2)) - require.False(t, fs.Has(astiav.CodecHardwareConfigMethodFlag(2))) + fs := NewCodecHardwareConfigMethodFlags(CodecHardwareConfigMethodFlag(1)) + require.True(t, fs.Has(CodecHardwareConfigMethodFlag(1))) + fs = fs.Add(CodecHardwareConfigMethodFlag(2)) + require.True(t, fs.Has(CodecHardwareConfigMethodFlag(2))) + fs = fs.Del(CodecHardwareConfigMethodFlag(2)) + require.False(t, fs.Has(CodecHardwareConfigMethodFlag(2))) } func TestDictionaryFlags(t *testing.T) { - fs := astiav.NewDictionaryFlags(astiav.DictionaryFlag(1)) - require.True(t, fs.Has(astiav.DictionaryFlag(1))) - fs = fs.Add(astiav.DictionaryFlag(2)) - require.True(t, fs.Has(astiav.DictionaryFlag(2))) - fs = fs.Del(astiav.DictionaryFlag(2)) - require.False(t, fs.Has(astiav.DictionaryFlag(2))) + fs := NewDictionaryFlags(DictionaryFlag(1)) + require.True(t, fs.Has(DictionaryFlag(1))) + fs = fs.Add(DictionaryFlag(2)) + require.True(t, fs.Has(DictionaryFlag(2))) + fs = fs.Del(DictionaryFlag(2)) + require.False(t, fs.Has(DictionaryFlag(2))) } func TestFilterCommandFlags(t *testing.T) { - fs := astiav.NewFilterCommandFlags(astiav.FilterCommandFlag(1)) - require.True(t, fs.Has(astiav.FilterCommandFlag(1))) - fs = fs.Add(astiav.FilterCommandFlag(2)) - require.True(t, fs.Has(astiav.FilterCommandFlag(2))) - fs = fs.Del(astiav.FilterCommandFlag(2)) - require.False(t, fs.Has(astiav.FilterCommandFlag(2))) + fs := NewFilterCommandFlags(FilterCommandFlag(1)) + require.True(t, fs.Has(FilterCommandFlag(1))) + fs = fs.Add(FilterCommandFlag(2)) + require.True(t, fs.Has(FilterCommandFlag(2))) + fs = fs.Del(FilterCommandFlag(2)) + require.False(t, fs.Has(FilterCommandFlag(2))) } func TestFormatContextFlags(t *testing.T) { - fs := astiav.NewFormatContextFlags(astiav.FormatContextFlag(1)) - require.True(t, fs.Has(astiav.FormatContextFlag(1))) - fs = fs.Add(astiav.FormatContextFlag(2)) - require.True(t, fs.Has(astiav.FormatContextFlag(2))) - fs = fs.Del(astiav.FormatContextFlag(2)) - require.False(t, fs.Has(astiav.FormatContextFlag(2))) + fs := NewFormatContextFlags(FormatContextFlag(1)) + require.True(t, fs.Has(FormatContextFlag(1))) + fs = fs.Add(FormatContextFlag(2)) + require.True(t, fs.Has(FormatContextFlag(2))) + fs = fs.Del(FormatContextFlag(2)) + require.False(t, fs.Has(FormatContextFlag(2))) } func TestFormatContextCtxFlags(t *testing.T) { - fs := astiav.NewFormatContextCtxFlags(astiav.FormatContextCtxFlag(1)) - require.True(t, fs.Has(astiav.FormatContextCtxFlag(1))) - fs = fs.Add(astiav.FormatContextCtxFlag(2)) - require.True(t, fs.Has(astiav.FormatContextCtxFlag(2))) - fs = fs.Del(astiav.FormatContextCtxFlag(2)) - require.False(t, fs.Has(astiav.FormatContextCtxFlag(2))) + fs := NewFormatContextCtxFlags(FormatContextCtxFlag(1)) + require.True(t, fs.Has(FormatContextCtxFlag(1))) + fs = fs.Add(FormatContextCtxFlag(2)) + require.True(t, fs.Has(FormatContextCtxFlag(2))) + fs = fs.Del(FormatContextCtxFlag(2)) + require.False(t, fs.Has(FormatContextCtxFlag(2))) } func TestFormatEventFlags(t *testing.T) { - fs := astiav.NewFormatEventFlags(astiav.FormatEventFlag(1)) - require.True(t, fs.Has(astiav.FormatEventFlag(1))) - fs = fs.Add(astiav.FormatEventFlag(2)) - require.True(t, fs.Has(astiav.FormatEventFlag(2))) - fs = fs.Del(astiav.FormatEventFlag(2)) - require.False(t, fs.Has(astiav.FormatEventFlag(2))) + fs := NewFormatEventFlags(FormatEventFlag(1)) + require.True(t, fs.Has(FormatEventFlag(1))) + fs = fs.Add(FormatEventFlag(2)) + require.True(t, fs.Has(FormatEventFlag(2))) + fs = fs.Del(FormatEventFlag(2)) + require.False(t, fs.Has(FormatEventFlag(2))) } func TestIOContextFlags(t *testing.T) { - fs := astiav.NewIOContextFlags(astiav.IOContextFlag(1)) - require.True(t, fs.Has(astiav.IOContextFlag(1))) - fs = fs.Add(astiav.IOContextFlag(2)) - require.True(t, fs.Has(astiav.IOContextFlag(2))) - fs = fs.Del(astiav.IOContextFlag(2)) - require.False(t, fs.Has(astiav.IOContextFlag(2))) + fs := NewIOContextFlags(IOContextFlag(1)) + require.True(t, fs.Has(IOContextFlag(1))) + fs = fs.Add(IOContextFlag(2)) + require.True(t, fs.Has(IOContextFlag(2))) + fs = fs.Del(IOContextFlag(2)) + require.False(t, fs.Has(IOContextFlag(2))) } func TestIOFormatFlags(t *testing.T) { - fs := astiav.NewIOFormatFlags(astiav.IOFormatFlag(1)) - require.True(t, fs.Has(astiav.IOFormatFlag(1))) - fs = fs.Add(astiav.IOFormatFlag(2)) - require.True(t, fs.Has(astiav.IOFormatFlag(2))) - fs = fs.Del(astiav.IOFormatFlag(2)) - require.False(t, fs.Has(astiav.IOFormatFlag(2))) + fs := NewIOFormatFlags(IOFormatFlag(1)) + require.True(t, fs.Has(IOFormatFlag(1))) + fs = fs.Add(IOFormatFlag(2)) + require.True(t, fs.Has(IOFormatFlag(2))) + fs = fs.Del(IOFormatFlag(2)) + require.False(t, fs.Has(IOFormatFlag(2))) } func TestPacketFlags(t *testing.T) { - fs := astiav.NewPacketFlags(astiav.PacketFlag(1)) - require.True(t, fs.Has(astiav.PacketFlag(1))) - fs = fs.Add(astiav.PacketFlag(2)) - require.True(t, fs.Has(astiav.PacketFlag(2))) - fs = fs.Del(astiav.PacketFlag(2)) - require.False(t, fs.Has(astiav.PacketFlag(2))) + fs := NewPacketFlags(PacketFlag(1)) + require.True(t, fs.Has(PacketFlag(1))) + fs = fs.Add(PacketFlag(2)) + require.True(t, fs.Has(PacketFlag(2))) + fs = fs.Del(PacketFlag(2)) + require.False(t, fs.Has(PacketFlag(2))) } func TestSeekFlags(t *testing.T) { - fs := astiav.NewSeekFlags(astiav.SeekFlag(1)) - require.True(t, fs.Has(astiav.SeekFlag(1))) - fs = fs.Add(astiav.SeekFlag(2)) - require.True(t, fs.Has(astiav.SeekFlag(2))) - fs = fs.Del(astiav.SeekFlag(2)) - require.False(t, fs.Has(astiav.SeekFlag(2))) + fs := NewSeekFlags(SeekFlag(1)) + require.True(t, fs.Has(SeekFlag(1))) + fs = fs.Add(SeekFlag(2)) + require.True(t, fs.Has(SeekFlag(2))) + fs = fs.Del(SeekFlag(2)) + require.False(t, fs.Has(SeekFlag(2))) } func TestSoftwareScaleContextFlags(t *testing.T) { - fs := astiav.NewSoftwareScaleContextFlags(astiav.SoftwareScaleContextFlag(1)) - require.True(t, fs.Has(astiav.SoftwareScaleContextFlag(1))) - fs = fs.Add(astiav.SoftwareScaleContextFlag(2)) - require.True(t, fs.Has(astiav.SoftwareScaleContextFlag(2))) - fs = fs.Del(astiav.SoftwareScaleContextFlag(2)) - require.False(t, fs.Has(astiav.SoftwareScaleContextFlag(2))) + fs := NewSoftwareScaleContextFlags(SoftwareScaleContextFlag(1)) + require.True(t, fs.Has(SoftwareScaleContextFlag(1))) + fs = fs.Add(SoftwareScaleContextFlag(2)) + require.True(t, fs.Has(SoftwareScaleContextFlag(2))) + fs = fs.Del(SoftwareScaleContextFlag(2)) + require.False(t, fs.Has(SoftwareScaleContextFlag(2))) } func TestStreamEventFlags(t *testing.T) { - fs := astiav.NewStreamEventFlags(astiav.StreamEventFlag(1)) - require.True(t, fs.Has(astiav.StreamEventFlag(1))) - fs = fs.Add(astiav.StreamEventFlag(2)) - require.True(t, fs.Has(astiav.StreamEventFlag(2))) - fs = fs.Del(astiav.StreamEventFlag(2)) - require.False(t, fs.Has(astiav.StreamEventFlag(2))) + fs := NewStreamEventFlags(StreamEventFlag(1)) + require.True(t, fs.Has(StreamEventFlag(1))) + fs = fs.Add(StreamEventFlag(2)) + require.True(t, fs.Has(StreamEventFlag(2))) + fs = fs.Del(StreamEventFlag(2)) + require.False(t, fs.Has(StreamEventFlag(2))) } diff --git a/format_context.go b/format_context.go index fbdc59b..acbe367 100644 --- a/format_context.go +++ b/format_context.go @@ -29,22 +29,22 @@ type FormatContext struct { c *C.struct_AVFormatContext } -func newFormatContext() *FormatContext { - return &FormatContext{} -} - func newFormatContextFromC(c *C.struct_AVFormatContext) *FormatContext { if c == nil { return nil } - return &FormatContext{c: c} + fc := &FormatContext{c: c} + classers.set(fc) + return fc } +var _ Classer = (*FormatContext)(nil) + func AllocFormatContext() *FormatContext { return newFormatContextFromC(C.avformat_alloc_context()) } -func AllocOutputFormatContext(o *OutputFormat, formatName, filename string) (*FormatContext, error) { +func AllocOutputFormatContext(of *OutputFormat, formatName, filename string) (*FormatContext, error) { fonc := (*C.char)(nil) if len(formatName) > 0 { fonc = C.CString(formatName) @@ -55,19 +55,30 @@ func AllocOutputFormatContext(o *OutputFormat, formatName, filename string) (*Fo finc = C.CString(filename) defer C.free(unsafe.Pointer(finc)) } - fc := newFormatContext() - var oc *C.struct_AVOutputFormat - if o != nil { - oc = o.c + var ofc *C.struct_AVOutputFormat + if of != nil { + ofc = of.c } - err := newError(C.avformat_alloc_output_context2(&fc.c, oc, fonc, finc)) - return fc, err + var fcc *C.struct_AVFormatContext + if err := newError(C.avformat_alloc_output_context2(&fcc, ofc, fonc, finc)); err != nil { + return nil, err + } + return newFormatContextFromC(fcc), nil +} + +func (fc *FormatContext) Free() { + classers.del(fc) + C.avformat_free_context(fc.c) } func (fc *FormatContext) BitRate() int64 { return int64(fc.c.bit_rate) } +func (fc *FormatContext) Class() *Class { + return newClassFromC(unsafe.Pointer(fc.c)) +} + func (fc *FormatContext) CtxFlags() FormatContextCtxFlags { return FormatContextCtxFlags(fc.c.ctx_flags) } @@ -115,6 +126,13 @@ func (fc *FormatContext) OutputFormat() *OutputFormat { } func (fc *FormatContext) Pb() *IOContext { + // If the io context has been created using the format context's OpenInput() method, we need to + // make sure to return the same go struct as the one stored in classers + if c, ok := classers.get(unsafe.Pointer(fc.c.pb)); ok { + if v, ok := c.(*IOContext); ok { + return v + } + } return newIOContextFromC(fc.c.pb) } @@ -153,15 +171,23 @@ func (fc *FormatContext) OpenInput(url string, fmt *InputFormat, d *Dictionary) if fmt != nil { fmtc = fmt.c } - return newError(C.avformat_open_input(&fc.c, urlc, fmtc, dc)) + if err := newError(C.avformat_open_input(&fc.c, urlc, fmtc, dc)); err != nil { + return err + } + if pb := fc.Pb(); pb != nil { + classers.set(pb) + } + return nil } func (fc *FormatContext) CloseInput() { - C.avformat_close_input(&fc.c) -} - -func (fc *FormatContext) Free() { - C.avformat_free_context(fc.c) + if pb := fc.Pb(); pb != nil { + classers.del(pb) + } + classers.del(fc) + if fc.c != nil { + C.avformat_close_input(&fc.c) + } } func (fc *FormatContext) NewStream(c *Codec) *Stream { diff --git a/format_context_test.go b/format_context_test.go index a7dd16c..7fe986a 100644 --- a/format_context_test.go +++ b/format_context_test.go @@ -1,9 +1,8 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) @@ -15,40 +14,42 @@ func TestFormatContext(t *testing.T) { s1 := ss[0] require.Equal(t, int64(607583), fc1.BitRate()) - require.Equal(t, astiav.NewFormatContextCtxFlags(0), fc1.CtxFlags()) + require.Equal(t, NewFormatContextCtxFlags(0), fc1.CtxFlags()) require.Equal(t, int64(5014000), fc1.Duration()) - require.True(t, fc1.EventFlags().Has(astiav.FormatEventFlagMetadataUpdated)) - require.True(t, fc1.Flags().Has(astiav.FormatContextFlagAutoBsf)) - require.Equal(t, astiav.NewRational(24, 1), fc1.GuessFrameRate(s1, nil)) - require.Equal(t, astiav.NewRational(1, 1), fc1.GuessSampleAspectRatio(s1, nil)) - require.True(t, fc1.InputFormat().Flags().Has(astiav.IOFormatFlagNoByteSeek)) - require.Equal(t, astiav.IOContextFlags(0), fc1.IOFlags()) + require.True(t, fc1.EventFlags().Has(FormatEventFlagMetadataUpdated)) + require.True(t, fc1.Flags().Has(FormatContextFlagAutoBsf)) + require.Equal(t, NewRational(24, 1), fc1.GuessFrameRate(s1, nil)) + require.Equal(t, NewRational(1, 1), fc1.GuessSampleAspectRatio(s1, nil)) + require.True(t, fc1.InputFormat().Flags().Has(IOFormatFlagNoByteSeek)) + require.Equal(t, IOContextFlags(0), fc1.IOFlags()) require.Equal(t, int64(0), fc1.MaxAnalyzeDuration()) - require.Equal(t, "isom", fc1.Metadata().Get("major_brand", nil, astiav.NewDictionaryFlags()).Value()) + require.Equal(t, "isom", fc1.Metadata().Get("major_brand", nil, NewDictionaryFlags()).Value()) require.Equal(t, int64(0), fc1.StartTime()) require.Equal(t, 2, fc1.NbStreams()) require.Len(t, fc1.Streams(), 2) + cl := fc1.Class() + require.NotNil(t, cl) + require.Equal(t, "AVFormatContext", cl.Name()) sdp, err := fc1.SDPCreate() require.NoError(t, err) require.Equal(t, "v=0\r\no=- 0 0 IN IP4 127.0.0.1\r\ns=Big Buck Bunny\r\nt=0 0\r\na=tool:libavformat LIBAVFORMAT_VERSION\r\nm=video 0 RTP/AVP 96\r\nb=AS:441\r\na=rtpmap:96 H264/90000\r\na=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z0LADasgKDPz4CIAAAMAAgAAAwBhHihUkA==,aM48gA==; profile-level-id=42C00D\r\na=control:streamid=0\r\nm=audio 0 RTP/AVP 97\r\nb=AS:161\r\na=rtpmap:97 MPEG4-GENERIC/48000/2\r\na=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=1190\r\na=control:streamid=1\r\n", sdp) - fc2, err := astiav.AllocOutputFormatContext(nil, "", "/tmp/test.mp4") + fc2, err := AllocOutputFormatContext(nil, "", "/tmp/test.mp4") require.NoError(t, err) defer fc2.Free() - require.True(t, fc2.OutputFormat().Flags().Has(astiav.IOFormatFlagGlobalheader)) + require.True(t, fc2.OutputFormat().Flags().Has(IOFormatFlagGlobalheader)) - fc3 := astiav.AllocFormatContext() + fc3 := AllocFormatContext() require.NotNil(t, fc3) defer fc3.Free() - c := astiav.NewIOContext() - err = c.Open("testdata/video.mp4", astiav.NewIOContextFlags(astiav.IOContextFlagRead)) + c, err := OpenIOContext("testdata/video.mp4", NewIOContextFlags(IOContextFlagRead)) require.NoError(t, err) defer c.Closep() //nolint:errcheck fc3.SetPb(c) - fc3.SetStrictStdCompliance(astiav.StrictStdComplianceExperimental) + fc3.SetStrictStdCompliance(StrictStdComplianceExperimental) require.NotNil(t, fc3.Pb()) - require.Equal(t, astiav.StrictStdComplianceExperimental, fc3.StrictStdCompliance()) + require.Equal(t, StrictStdComplianceExperimental, fc3.StrictStdCompliance()) s2 := fc3.NewStream(nil) require.NotNil(t, s2) s3 := fc3.NewStream(nil) diff --git a/frame.go b/frame.go index 289041c..17c6edb 100644 --- a/frame.go +++ b/frame.go @@ -214,6 +214,6 @@ func (f *Frame) MoveRef(src *Frame) { C.av_frame_move_ref(f.c, src.c) } -func (f *Frame) UnsafePointer() *C.struct_AVFrame { +func (f *Frame) UnsafeTypedPointer() *C.struct_AVFrame { return f.c } diff --git a/frame_data_internal_test.go b/frame_data_internal_test.go deleted file mode 100644 index 34c0264..0000000 --- a/frame_data_internal_test.go +++ /dev/null @@ -1,285 +0,0 @@ -package astiav - -import ( - "image" - "testing" - - "github.com/stretchr/testify/require" -) - -type mockedFrameDataFrame struct { - h int - imageBytes []byte - linesizes []int - pf PixelFormat - planesBytes [][]byte - w int -} - -var _ frameDataFramer = (*mockedFrameDataFrame)(nil) - -func (f *mockedFrameDataFrame) height() int { - return f.h -} - -func (f *mockedFrameDataFrame) imageBufferSize(align int) (int, error) { - return len(f.imageBytes), nil -} - -func (f *mockedFrameDataFrame) imageCopyToBuffer(b []byte, align int) (int, error) { - copy(b, f.imageBytes) - return len(f.imageBytes), nil -} - -func (f *mockedFrameDataFrame) linesize(i int) int { - return f.linesizes[i] -} - -func (f *mockedFrameDataFrame) pixelFormat() PixelFormat { - return f.pf -} - -func (f *mockedFrameDataFrame) planeBytes(i int) []byte { - return f.planesBytes[i] -} - -func (f *mockedFrameDataFrame) width() int { - return f.w -} - -func TestFrameDataInternal(t *testing.T) { - fdf := &mockedFrameDataFrame{} - fd := newFrameData(fdf) - - for _, v := range []struct { - err bool - i image.Image - pfs []PixelFormat - }{ - { - i: &image.Gray{}, - pfs: []PixelFormat{PixelFormatGray8}, - }, - { - i: &image.Gray16{}, - pfs: []PixelFormat{PixelFormatGray16Be}, - }, - { - i: &image.RGBA{}, - pfs: []PixelFormat{ - PixelFormatRgb0, - PixelFormat0Rgb, - PixelFormatRgb4, - PixelFormatRgb8, - }, - }, - { - i: &image.NRGBA{}, - pfs: []PixelFormat{PixelFormatRgba}, - }, - { - i: &image.NRGBA64{}, - pfs: []PixelFormat{PixelFormatRgba64Be}, - }, - { - i: &image.NYCbCrA{}, - pfs: []PixelFormat{ - PixelFormatYuva420P, - PixelFormatYuva422P, - PixelFormatYuva444P, - }, - }, - { - i: &image.YCbCr{}, - pfs: []PixelFormat{ - PixelFormatYuv410P, - PixelFormatYuv411P, - PixelFormatYuvj411P, - PixelFormatYuv420P, - PixelFormatYuvj420P, - PixelFormatYuv422P, - PixelFormatYuvj422P, - PixelFormatYuv440P, - PixelFormatYuvj440P, - PixelFormatYuv444P, - PixelFormatYuvj444P, - }, - }, - { - err: true, - pfs: []PixelFormat{PixelFormatAbgr}, - }, - } { - for _, pf := range v.pfs { - fdf.pf = pf - i, err := fd.GuessImageFormat() - if v.err { - require.Error(t, err) - } else { - require.IsType(t, v.i, i) - } - } - } - - fdf.imageBytes = []byte{0, 1, 2, 3} - _, err := fd.Bytes(0) - require.Error(t, err) - fdf.h = 1 - fdf.w = 2 - b, err := fd.Bytes(0) - require.NoError(t, err) - require.Equal(t, fdf.imageBytes, b) - - for _, v := range []struct { - e image.Image - err bool - i image.Image - linesizes []int - pixelFormat PixelFormat - planesBytes [][]byte - }{ - { - e: &image.Alpha{ - Pix: []byte{0, 1, 2, 3}, - Stride: 1, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.Alpha{}, - linesizes: []int{1}, - pixelFormat: PixelFormatRgba, - planesBytes: [][]byte{{0, 1, 2, 3}}, - }, - { - e: &image.Alpha16{ - Pix: []byte{0, 1, 2, 3}, - Stride: 1, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.Alpha16{}, - linesizes: []int{1}, - pixelFormat: PixelFormatRgba, - planesBytes: [][]byte{{0, 1, 2, 3}}, - }, - { - e: &image.CMYK{ - Pix: []byte{0, 1, 2, 3}, - Stride: 1, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.CMYK{}, - linesizes: []int{1}, - pixelFormat: PixelFormatRgba, - planesBytes: [][]byte{{0, 1, 2, 3}}, - }, - { - e: &image.Gray{ - Pix: []byte{0, 1, 2, 3}, - Stride: 1, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.Gray{}, - linesizes: []int{1}, - pixelFormat: PixelFormatRgba, - planesBytes: [][]byte{{0, 1, 2, 3}}, - }, - { - e: &image.Gray16{ - Pix: []byte{0, 1, 2, 3}, - Stride: 1, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.Gray16{}, - linesizes: []int{1}, - pixelFormat: PixelFormatRgba, - planesBytes: [][]byte{{0, 1, 2, 3}}, - }, - { - e: &image.NRGBA{ - Pix: []byte{0, 1, 2, 3}, - Stride: 1, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.NRGBA{}, - linesizes: []int{1}, - pixelFormat: PixelFormatRgba, - planesBytes: [][]byte{{0, 1, 2, 3}}, - }, - { - e: &image.NRGBA64{ - Pix: []byte{0, 1, 2, 3}, - Stride: 1, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.NRGBA64{}, - linesizes: []int{1}, - pixelFormat: PixelFormatRgba, - planesBytes: [][]byte{{0, 1, 2, 3}}, - }, - { - e: &image.NYCbCrA{ - A: []byte{6, 7}, - AStride: 4, - YCbCr: image.YCbCr{ - Y: []byte{0, 1}, - Cb: []byte{2, 3}, - Cr: []byte{4, 5}, - YStride: 1, - CStride: 2, - SubsampleRatio: image.YCbCrSubsampleRatio444, - Rect: image.Rect(0, 0, 2, 1), - }, - }, - i: &image.NYCbCrA{}, - linesizes: []int{1, 2, 3, 4}, - pixelFormat: PixelFormatYuv444P, - planesBytes: [][]byte{{0, 1}, {2, 3}, {4, 5}, {6, 7}}, - }, - { - e: &image.RGBA{ - Pix: []byte{0, 1, 2, 3}, - Stride: 1, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.RGBA{}, - linesizes: []int{1}, - pixelFormat: PixelFormatRgba, - planesBytes: [][]byte{{0, 1, 2, 3}}, - }, - { - e: &image.RGBA64{ - Pix: []byte{0, 1, 2, 3}, - Stride: 1, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.RGBA64{}, - linesizes: []int{1}, - pixelFormat: PixelFormatRgba, - planesBytes: [][]byte{{0, 1, 2, 3}}, - }, - { - e: &image.YCbCr{ - Y: []byte{0, 1}, - Cb: []byte{2, 3}, - Cr: []byte{4, 5}, - YStride: 1, - CStride: 2, - SubsampleRatio: image.YCbCrSubsampleRatio420, - Rect: image.Rect(0, 0, 2, 1), - }, - i: &image.YCbCr{}, - linesizes: []int{1, 2, 3}, - pixelFormat: PixelFormatYuv420P, - planesBytes: [][]byte{{0, 1}, {2, 3}, {4, 5}}, - }, - } { - fdf.linesizes = v.linesizes - fdf.pf = v.pixelFormat - fdf.planesBytes = v.planesBytes - err = fd.ToImage(v.i) - if v.err { - require.Error(t, err) - } else { - require.Equal(t, v.e, v.i) - } - } -} diff --git a/frame_data_test.go b/frame_data_test.go index fc9c12f..7621579 100644 --- a/frame_data_test.go +++ b/frame_data_test.go @@ -1,20 +1,297 @@ -package astiav_test +package astiav import ( + "image" "image/png" "os" "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) +type mockedFrameDataFrame struct { + h int + imageBytes []byte + linesizes []int + pf PixelFormat + planesBytes [][]byte + w int +} + +var _ frameDataFramer = (*mockedFrameDataFrame)(nil) + +func (f *mockedFrameDataFrame) height() int { + return f.h +} + +func (f *mockedFrameDataFrame) imageBufferSize(align int) (int, error) { + return len(f.imageBytes), nil +} + +func (f *mockedFrameDataFrame) imageCopyToBuffer(b []byte, align int) (int, error) { + copy(b, f.imageBytes) + return len(f.imageBytes), nil +} + +func (f *mockedFrameDataFrame) linesize(i int) int { + return f.linesizes[i] +} + +func (f *mockedFrameDataFrame) pixelFormat() PixelFormat { + return f.pf +} + +func (f *mockedFrameDataFrame) planeBytes(i int) []byte { + return f.planesBytes[i] +} + +func (f *mockedFrameDataFrame) width() int { + return f.w +} + +func TestFrameDataInternal(t *testing.T) { + fdf := &mockedFrameDataFrame{} + fd := newFrameData(fdf) + + for _, v := range []struct { + err bool + i image.Image + pfs []PixelFormat + }{ + { + i: &image.Gray{}, + pfs: []PixelFormat{PixelFormatGray8}, + }, + { + i: &image.Gray16{}, + pfs: []PixelFormat{PixelFormatGray16Be}, + }, + { + i: &image.RGBA{}, + pfs: []PixelFormat{ + PixelFormatRgb0, + PixelFormat0Rgb, + PixelFormatRgb4, + PixelFormatRgb8, + }, + }, + { + i: &image.NRGBA{}, + pfs: []PixelFormat{PixelFormatRgba}, + }, + { + i: &image.NRGBA64{}, + pfs: []PixelFormat{PixelFormatRgba64Be}, + }, + { + i: &image.NYCbCrA{}, + pfs: []PixelFormat{ + PixelFormatYuva420P, + PixelFormatYuva422P, + PixelFormatYuva444P, + }, + }, + { + i: &image.YCbCr{}, + pfs: []PixelFormat{ + PixelFormatYuv410P, + PixelFormatYuv411P, + PixelFormatYuvj411P, + PixelFormatYuv420P, + PixelFormatYuvj420P, + PixelFormatYuv422P, + PixelFormatYuvj422P, + PixelFormatYuv440P, + PixelFormatYuvj440P, + PixelFormatYuv444P, + PixelFormatYuvj444P, + }, + }, + { + err: true, + pfs: []PixelFormat{PixelFormatAbgr}, + }, + } { + for _, pf := range v.pfs { + fdf.pf = pf + i, err := fd.GuessImageFormat() + if v.err { + require.Error(t, err) + } else { + require.IsType(t, v.i, i) + } + } + } + + fdf.imageBytes = []byte{0, 1, 2, 3} + _, err := fd.Bytes(0) + require.Error(t, err) + fdf.h = 1 + fdf.w = 2 + b, err := fd.Bytes(0) + require.NoError(t, err) + require.Equal(t, fdf.imageBytes, b) + + for _, v := range []struct { + e image.Image + err bool + i image.Image + linesizes []int + pixelFormat PixelFormat + planesBytes [][]byte + }{ + { + e: &image.Alpha{ + Pix: []byte{0, 1, 2, 3}, + Stride: 1, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.Alpha{}, + linesizes: []int{1}, + pixelFormat: PixelFormatRgba, + planesBytes: [][]byte{{0, 1, 2, 3}}, + }, + { + e: &image.Alpha16{ + Pix: []byte{0, 1, 2, 3}, + Stride: 1, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.Alpha16{}, + linesizes: []int{1}, + pixelFormat: PixelFormatRgba, + planesBytes: [][]byte{{0, 1, 2, 3}}, + }, + { + e: &image.CMYK{ + Pix: []byte{0, 1, 2, 3}, + Stride: 1, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.CMYK{}, + linesizes: []int{1}, + pixelFormat: PixelFormatRgba, + planesBytes: [][]byte{{0, 1, 2, 3}}, + }, + { + e: &image.Gray{ + Pix: []byte{0, 1, 2, 3}, + Stride: 1, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.Gray{}, + linesizes: []int{1}, + pixelFormat: PixelFormatRgba, + planesBytes: [][]byte{{0, 1, 2, 3}}, + }, + { + e: &image.Gray16{ + Pix: []byte{0, 1, 2, 3}, + Stride: 1, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.Gray16{}, + linesizes: []int{1}, + pixelFormat: PixelFormatRgba, + planesBytes: [][]byte{{0, 1, 2, 3}}, + }, + { + e: &image.NRGBA{ + Pix: []byte{0, 1, 2, 3}, + Stride: 1, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.NRGBA{}, + linesizes: []int{1}, + pixelFormat: PixelFormatRgba, + planesBytes: [][]byte{{0, 1, 2, 3}}, + }, + { + e: &image.NRGBA64{ + Pix: []byte{0, 1, 2, 3}, + Stride: 1, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.NRGBA64{}, + linesizes: []int{1}, + pixelFormat: PixelFormatRgba, + planesBytes: [][]byte{{0, 1, 2, 3}}, + }, + { + e: &image.NYCbCrA{ + A: []byte{6, 7}, + AStride: 4, + YCbCr: image.YCbCr{ + Y: []byte{0, 1}, + Cb: []byte{2, 3}, + Cr: []byte{4, 5}, + YStride: 1, + CStride: 2, + SubsampleRatio: image.YCbCrSubsampleRatio444, + Rect: image.Rect(0, 0, 2, 1), + }, + }, + i: &image.NYCbCrA{}, + linesizes: []int{1, 2, 3, 4}, + pixelFormat: PixelFormatYuv444P, + planesBytes: [][]byte{{0, 1}, {2, 3}, {4, 5}, {6, 7}}, + }, + { + e: &image.RGBA{ + Pix: []byte{0, 1, 2, 3}, + Stride: 1, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.RGBA{}, + linesizes: []int{1}, + pixelFormat: PixelFormatRgba, + planesBytes: [][]byte{{0, 1, 2, 3}}, + }, + { + e: &image.RGBA64{ + Pix: []byte{0, 1, 2, 3}, + Stride: 1, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.RGBA64{}, + linesizes: []int{1}, + pixelFormat: PixelFormatRgba, + planesBytes: [][]byte{{0, 1, 2, 3}}, + }, + { + e: &image.YCbCr{ + Y: []byte{0, 1}, + Cb: []byte{2, 3}, + Cr: []byte{4, 5}, + YStride: 1, + CStride: 2, + SubsampleRatio: image.YCbCrSubsampleRatio420, + Rect: image.Rect(0, 0, 2, 1), + }, + i: &image.YCbCr{}, + linesizes: []int{1, 2, 3}, + pixelFormat: PixelFormatYuv420P, + planesBytes: [][]byte{{0, 1}, {2, 3}, {4, 5}}, + }, + } { + fdf.linesizes = v.linesizes + fdf.pf = v.pixelFormat + fdf.planesBytes = v.planesBytes + err = fd.ToImage(v.i) + if v.err { + require.Error(t, err) + } else { + require.Equal(t, v.e, v.i) + } + } +} + func TestFrameData(t *testing.T) { const ( name = "image-rgba" ext = "png" ) - f, err := globalHelper.inputLastFrame(name+"."+ext, astiav.MediaTypeVideo) + f, err := globalHelper.inputLastFrame(name+"."+ext, MediaTypeVideo) require.NoError(t, err) fd := f.Data() diff --git a/frame_test.go b/frame_test.go index a4f2fe9..98c175e 100644 --- a/frame_test.go +++ b/frame_test.go @@ -1,45 +1,44 @@ -package astiav_test +package astiav import ( "bytes" "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestFrame(t *testing.T) { - f1, err := globalHelper.inputLastFrame("video.mp4", astiav.MediaTypeVideo) + f1, err := globalHelper.inputLastFrame("video.mp4", MediaTypeVideo) require.NoError(t, err) require.Equal(t, [8]int{384, 192, 192, 0, 0, 0, 0, 0}, f1.Linesize()) require.Equal(t, int64(60928), f1.PktDts()) - require.NotNil(t, f1.UnsafePointer()) + require.Equal(t, f1.c, f1.UnsafeTypedPointer()) - f2 := astiav.AllocFrame() + f2 := AllocFrame() require.NotNil(t, f2) defer f2.Free() - f2.SetChannelLayout(astiav.ChannelLayout21) - f2.SetColorRange(astiav.ColorRangeJpeg) + f2.SetChannelLayout(ChannelLayout21) + f2.SetColorRange(ColorRangeJpeg) f2.SetHeight(2) f2.SetKeyFrame(true) f2.SetNbSamples(4) - f2.SetPictureType(astiav.PictureTypeB) - f2.SetPixelFormat(astiav.PixelFormat0Bgr) - require.Equal(t, astiav.PixelFormat0Bgr, f2.PixelFormat()) // Need to test it right away as sample format actually updates the same field + f2.SetPictureType(PictureTypeB) + f2.SetPixelFormat(PixelFormat0Bgr) + require.Equal(t, PixelFormat0Bgr, f2.PixelFormat()) // Need to test it right away as sample format actually updates the same field f2.SetPts(7) - f2.SetSampleAspectRatio(astiav.NewRational(10, 2)) - f2.SetSampleFormat(astiav.SampleFormatDbl) - require.Equal(t, astiav.SampleFormatDbl, f2.SampleFormat()) + f2.SetSampleAspectRatio(NewRational(10, 2)) + f2.SetSampleFormat(SampleFormatDbl) + require.Equal(t, SampleFormatDbl, f2.SampleFormat()) f2.SetSampleRate(9) f2.SetWidth(10) - require.True(t, f2.ChannelLayout().Equal(astiav.ChannelLayout21)) - require.Equal(t, astiav.ColorRangeJpeg, f2.ColorRange()) + require.True(t, f2.ChannelLayout().Equal(ChannelLayout21)) + require.Equal(t, ColorRangeJpeg, f2.ColorRange()) require.Equal(t, 2, f2.Height()) require.True(t, f2.KeyFrame()) require.Equal(t, 4, f2.NbSamples()) - require.Equal(t, astiav.PictureTypeB, f2.PictureType()) + require.Equal(t, PictureTypeB, f2.PictureType()) require.Equal(t, int64(7), f2.Pts()) - require.Equal(t, astiav.NewRational(10, 2), f2.SampleAspectRatio()) + require.Equal(t, NewRational(10, 2), f2.SampleAspectRatio()) require.Equal(t, 9, f2.SampleRate()) require.Equal(t, 10, f2.Width()) @@ -61,40 +60,40 @@ func TestFrame(t *testing.T) { f3.Unref() require.Equal(t, 0, f3.Height()) - f4 := astiav.AllocFrame() + f4 := AllocFrame() require.NotNil(t, f4) defer f4.Free() f4.SetNbSamples(960) - f4.SetChannelLayout(astiav.ChannelLayoutStereo) - f4.SetSampleFormat(astiav.SampleFormatS16) + f4.SetChannelLayout(ChannelLayoutStereo) + f4.SetSampleFormat(SampleFormatS16) f4.SetSampleRate(48000) err = f4.AllocBuffer(0) require.NoError(t, err) err = f4.AllocSamples(0) require.NoError(t, err) - f5 := astiav.AllocFrame() + f5 := AllocFrame() require.NotNil(t, f5) defer f5.Free() - sd := f5.NewSideData(astiav.FrameSideDataTypeAudioServiceType, 4) + sd := f5.NewSideData(FrameSideDataTypeAudioServiceType, 4) require.NotNil(t, sd) sd.SetData([]byte{1, 2, 3}) - sd = f5.SideData(astiav.FrameSideDataTypeAudioServiceType) + sd = f5.SideData(FrameSideDataTypeAudioServiceType) require.NotNil(t, sd) - require.Equal(t, astiav.FrameSideDataTypeAudioServiceType, sd.Type()) + require.Equal(t, FrameSideDataTypeAudioServiceType, sd.Type()) require.True(t, bytes.HasPrefix(sd.Data(), []byte{1, 2, 3})) require.Len(t, sd.Data(), 4) sd.SetData([]byte{1, 2, 3, 4, 5}) - sd = f5.SideData(astiav.FrameSideDataTypeAudioServiceType) + sd = f5.SideData(FrameSideDataTypeAudioServiceType) require.NotNil(t, sd) require.Equal(t, []byte{1, 2, 3, 4}, sd.Data()) - f6 := astiav.AllocFrame() + f6 := AllocFrame() require.NotNil(t, f6) defer f6.Free() - f6.SetColorRange(astiav.ColorRangeUnspecified) + f6.SetColorRange(ColorRangeUnspecified) f6.SetHeight(2) - f6.SetPixelFormat(astiav.PixelFormatYuv420P) + f6.SetPixelFormat(PixelFormatYuv420P) f6.SetWidth(4) const align = 1 require.NoError(t, f6.AllocBuffer(align)) diff --git a/hardware_device_type_test.go b/hardware_device_type_test.go index 06db25b..47913b1 100644 --- a/hardware_device_type_test.go +++ b/hardware_device_type_test.go @@ -1,13 +1,12 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestHardwareDeviceType(t *testing.T) { - require.Equal(t, "cuda", astiav.HardwareDeviceTypeCUDA.String()) - require.Equal(t, astiav.FindHardwareDeviceTypeByName("cuda"), astiav.HardwareDeviceTypeCUDA) + require.Equal(t, "cuda", HardwareDeviceTypeCUDA.String()) + require.Equal(t, FindHardwareDeviceTypeByName("cuda"), HardwareDeviceTypeCUDA) } diff --git a/input_format_test.go b/input_format_test.go index 4e1fdd4..42e94c2 100644 --- a/input_format_test.go +++ b/input_format_test.go @@ -1,15 +1,14 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestInputFormat(t *testing.T) { formatName := "rawvideo" - inputFormat := astiav.FindInputFormat(formatName) + inputFormat := FindInputFormat(formatName) require.NotNil(t, inputFormat) require.Equal(t, formatName, inputFormat.Name()) require.Equal(t, formatName, inputFormat.String()) diff --git a/int_read_write_test.go b/int_read_write_test.go index 714cb18..f7c82d6 100644 --- a/int_read_write_test.go +++ b/int_read_write_test.go @@ -1,16 +1,15 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestIntReadWrite(t *testing.T) { is := []uint8{1, 2, 3, 4, 5, 6, 7, 8} - require.Equal(t, uint32(0), astiav.RL32([]byte{})) - require.Equal(t, uint32(0x4030201), astiav.RL32(is)) - require.Equal(t, uint32(0), astiav.RL32WithOffset([]byte{}, 4)) - require.Equal(t, uint32(0x8070605), astiav.RL32WithOffset(is, 4)) + require.Equal(t, uint32(0), RL32([]byte{})) + require.Equal(t, uint32(0x4030201), RL32(is)) + require.Equal(t, uint32(0), RL32WithOffset([]byte{}, 4)) + require.Equal(t, uint32(0x8070605), RL32WithOffset(is, 4)) } diff --git a/internal/cmd/flags/main.go b/internal/cmd/flags/main.go index c5f05bf..4e968a3 100644 --- a/internal/cmd/flags/main.go +++ b/internal/cmd/flags/main.go @@ -61,21 +61,20 @@ func (fs {{ $val.Name }}Flags{{ $val.Suffix }}) Has(f {{ $val.Name }}Flag{{ $val {{ end }}` var tmplTest = `// Code generated by astiav. DO NOT EDIT. -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) {{ range $val := . }} func Test{{ $val.Name }}Flags{{ $val.Suffix }}(t *testing.T) { - fs := astiav.New{{ $val.Name }}Flags{{ $val.Suffix }}(astiav.{{ $val.Name }}Flag{{ $val.Suffix }}(1)) - require.True(t, fs.Has(astiav.{{ $val.Name }}Flag{{ $val.Suffix }}(1))) - fs = fs.Add(astiav.{{ $val.Name }}Flag{{ $val.Suffix }}(2)) - require.True(t, fs.Has(astiav.{{ $val.Name }}Flag{{ $val.Suffix }}(2))) - fs = fs.Del(astiav.{{ $val.Name }}Flag{{ $val.Suffix }}(2)) - require.False(t, fs.Has(astiav.{{ $val.Name }}Flag{{ $val.Suffix }}(2))) + fs := New{{ $val.Name }}Flags{{ $val.Suffix }}({{ $val.Name }}Flag{{ $val.Suffix }}(1)) + require.True(t, fs.Has({{ $val.Name }}Flag{{ $val.Suffix }}(1))) + fs = fs.Add({{ $val.Name }}Flag{{ $val.Suffix }}(2)) + require.True(t, fs.Has({{ $val.Name }}Flag{{ $val.Suffix }}(2))) + fs = fs.Del({{ $val.Name }}Flag{{ $val.Suffix }}(2)) + require.False(t, fs.Has({{ $val.Name }}Flag{{ $val.Suffix }}(2))) } {{ end }}` diff --git a/io_context.go b/io_context.go index d03eeb9..eef486a 100644 --- a/io_context.go +++ b/io_context.go @@ -10,25 +10,37 @@ type IOContext struct { c *C.struct_AVIOContext } -func NewIOContext() *IOContext { - return &IOContext{} -} - func newIOContextFromC(c *C.struct_AVIOContext) *IOContext { if c == nil { return nil } - return &IOContext{c: c} + ic := &IOContext{c: c} + classers.set(ic) + return ic +} + +var _ Classer = (*IOContext)(nil) + +func OpenIOContext(filename string, flags IOContextFlags) (*IOContext, error) { + cfi := C.CString(filename) + defer C.free(unsafe.Pointer(cfi)) + var c *C.struct_AVIOContext + if err := newError(C.avio_open(&c, cfi, C.int(flags))); err != nil { + return nil, err + } + return newIOContextFromC(c), nil +} + +func (ic *IOContext) Class() *Class { + return newClassFromC(unsafe.Pointer(ic.c)) } func (ic *IOContext) Closep() error { - return newError(C.avio_closep(&ic.c)) -} - -func (ic *IOContext) Open(filename string, flags IOContextFlags) error { - cfi := C.CString(filename) - defer C.free(unsafe.Pointer(cfi)) - return newError(C.avio_open(&ic.c, cfi, C.int(flags))) + classers.del(ic) + if ic.c != nil { + return newError(C.avio_closep(&ic.c)) + } + return nil } func (ic *IOContext) Write(b []byte) { diff --git a/io_context_test.go b/io_context_test.go index 3ddf63a..fe4c7f0 100644 --- a/io_context_test.go +++ b/io_context_test.go @@ -1,19 +1,20 @@ -package astiav_test +package astiav import ( "os" "path/filepath" "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestIOContext(t *testing.T) { - c := astiav.NewIOContext() path := filepath.Join(t.TempDir(), "iocontext.txt") - err := c.Open(path, astiav.NewIOContextFlags(astiav.IOContextFlagWrite)) + c, err := OpenIOContext(path, NewIOContextFlags(IOContextFlagWrite)) require.NoError(t, err) + cl := c.Class() + require.NotNil(t, cl) + require.Equal(t, "AVIOContext", cl.Name()) c.Write(nil) c.Write([]byte("test")) err = c.Closep() diff --git a/log.go b/log.go index 481f7ed..9441788 100644 --- a/log.go +++ b/log.go @@ -5,19 +5,14 @@ package astiav //#include //#include /* -extern void goAstiavLogCallback(int level, char* fmt, char* msg, char* parent); +extern void goAstiavLogCallback(void* ptr, int level, char* fmt, char* msg); -static inline void astiavLogCallback(void *avcl, int level, const char *fmt, va_list vl) +static inline void astiavLogCallback(void *ptr, int level, const char *fmt, va_list vl) { if (level > av_log_get_level()) return; - AVClass* avc = avcl ? *(AVClass **) avcl : NULL; - char parent[1024]; - if (avc) { - sprintf(parent, "%p", avcl); - } char msg[1024]; vsprintf(msg, fmt, vl); - goAstiavLogCallback(level, (char*)(fmt), msg, parent); + goAstiavLogCallback(ptr, level, (char*)(fmt), msg); } static inline void astiavSetLogCallback() { @@ -27,13 +22,15 @@ static inline void astiavResetLogCallback() { av_log_set_callback(av_log_default_callback); } -static inline void astiavLog(int level, const char *fmt) +static inline void astiavLog(void* ptr, int level, const char *fmt, char* arg) { - av_log(NULL, level, fmt, NULL); + av_log(ptr, level, fmt, arg); } */ import "C" -import "unsafe" +import ( + "unsafe" +) type LogLevel int @@ -53,7 +50,11 @@ func SetLogLevel(l LogLevel) { C.av_log_set_level(C.int(l)) } -type LogCallback func(l LogLevel, fmt, msg, parent string) +func GetLogLevel() LogLevel { + return LogLevel(C.av_log_get_level()) +} + +type LogCallback func(c Classer, l LogLevel, fmt, msg string) var logCallback LogCallback @@ -63,19 +64,42 @@ func SetLogCallback(c LogCallback) { } //export goAstiavLogCallback -func goAstiavLogCallback(level C.int, fmt, msg, parent *C.char) { +func goAstiavLogCallback(ptr unsafe.Pointer, level C.int, fmt, msg *C.char) { + // No callback if logCallback == nil { return } - logCallback(LogLevel(level), C.GoString(fmt), C.GoString(msg), C.GoString(parent)) + + // Get classer + var c Classer + if ptr != nil { + var ok bool + if c, ok = classers.get(ptr); !ok { + c = newUnknownClasser(ptr) + } + } + + // Callback + logCallback(c, LogLevel(level), C.GoString(fmt), C.GoString(msg)) } func ResetLogCallback() { C.astiavResetLogCallback() } -func Log(l LogLevel, msg string) { - msgc := C.CString(msg) - defer C.free(unsafe.Pointer(msgc)) - C.astiavLog(C.int(l), msgc) +func Log(c Classer, l LogLevel, fmt string, args ...string) { + fmtc := C.CString(fmt) + defer C.free(unsafe.Pointer(fmtc)) + argc := (*C.char)(nil) + if len(args) > 0 { + argc = C.CString(args[0]) + defer C.free(unsafe.Pointer(argc)) + } + var ptr unsafe.Pointer + if c != nil { + if cl := c.Class(); cl != nil { + ptr = cl.ptr + } + } + C.astiavLog(ptr, C.int(l), fmtc, argc) } diff --git a/log_test.go b/log_test.go index 6651246..37fd302 100644 --- a/log_test.go +++ b/log_test.go @@ -1,51 +1,73 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) type logItem struct { + c Classer fmt string - l astiav.LogLevel + l LogLevel msg string } func TestLog(t *testing.T) { var lis []logItem - astiav.SetLogCallback(func(l astiav.LogLevel, fmt, msg, parent string) { + + SetLogLevel(LogLevelWarning) + require.Equal(t, LogLevelWarning, GetLogLevel()) + + SetLogCallback(func(c Classer, l LogLevel, fmt, msg string) { lis = append(lis, logItem{ + c: c, fmt: fmt, l: l, msg: msg, }) }) - astiav.SetLogLevel(astiav.LogLevelWarning) - astiav.Log(astiav.LogLevelInfo, "info") - astiav.Log(astiav.LogLevelWarning, "warning") - astiav.Log(astiav.LogLevelError, "error") - astiav.Log(astiav.LogLevelFatal, "fatal") + f := AllocFilterGraph() + defer f.Free() + Log(f, LogLevelInfo, "info") + Log(f, LogLevelWarning, "warning %s", "arg") + Log(f, LogLevelError, "error") + Log(f, LogLevelFatal, "fatal") require.Equal(t, []logItem{ { - fmt: "warning", - l: astiav.LogLevelWarning, - msg: "warning", + c: f, + fmt: "warning %s", + l: LogLevelWarning, + msg: "warning arg", }, { + c: f, fmt: "error", - l: astiav.LogLevelError, + l: LogLevelError, msg: "error", }, { + c: f, fmt: "fatal", - l: astiav.LogLevelFatal, + l: LogLevelFatal, msg: "fatal", }, }, lis) - astiav.ResetLogCallback() + + ResetLogCallback() lis = []logItem{} - astiav.Log(astiav.LogLevelError, "test error log\n") + Log(nil, LogLevelError, "test error log\n") require.Equal(t, []logItem{}, lis) + + lcs := []Classer{} + SetLogCallback(func(c Classer, l LogLevel, fmt, msg string) { + if c != nil { + lcs = append(lcs, c) + } + }) + classers.del(f) + lcs = []Classer{} + Log(f, LogLevelWarning, "") + require.Len(t, lcs, 1) + require.IsType(t, &UnknownClasser{}, lcs[0]) } diff --git a/mathematics_test.go b/mathematics_test.go index 2fe9834..5e909f8 100644 --- a/mathematics_test.go +++ b/mathematics_test.go @@ -1,14 +1,13 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestMathematics(t *testing.T) { - require.Equal(t, int64(1000), astiav.RescaleQ(100, astiav.NewRational(1, 100), astiav.NewRational(1, 1000))) - require.Equal(t, int64(0), astiav.RescaleQRnd(1, astiav.NewRational(1, 100), astiav.NewRational(1, 10), astiav.RoundingDown)) - require.Equal(t, int64(1), astiav.RescaleQRnd(1, astiav.NewRational(1, 100), astiav.NewRational(1, 10), astiav.RoundingUp)) + require.Equal(t, int64(1000), RescaleQ(100, NewRational(1, 100), NewRational(1, 1000))) + require.Equal(t, int64(0), RescaleQRnd(1, NewRational(1, 100), NewRational(1, 10), RoundingDown)) + require.Equal(t, int64(1), RescaleQRnd(1, NewRational(1, 100), NewRational(1, 10), RoundingUp)) } diff --git a/media_type_test.go b/media_type_test.go index 5d478ff..190edee 100644 --- a/media_type_test.go +++ b/media_type_test.go @@ -1,12 +1,11 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestMediaType(t *testing.T) { - require.Equal(t, "video", astiav.MediaTypeVideo.String()) + require.Equal(t, "video", MediaTypeVideo.String()) } diff --git a/packet_test.go b/packet_test.go index 3ed6657..9a335f4 100644 --- a/packet_test.go +++ b/packet_test.go @@ -1,9 +1,8 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) @@ -13,13 +12,13 @@ func TestPacket(t *testing.T) { require.Equal(t, []byte{0x0, 0x0, 0x0, 0xd1, 0x65, 0x88, 0x82, 0x0, 0x1f, 0x5f, 0xff, 0xf8, 0x22, 0x8a, 0x0, 0x2, 0x2d, 0xbe, 0x38, 0xc7, 0x19, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xba, 0xeb, 0xae, 0xb9, 0xb8, 0xe6, 0x39, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xc0}, pkt1.Data()) require.Equal(t, int64(0), pkt1.Dts()) require.Equal(t, int64(512), pkt1.Duration()) - require.True(t, pkt1.Flags().Has(astiav.PacketFlagKey)) + require.True(t, pkt1.Flags().Has(PacketFlagKey)) require.Equal(t, int64(48), pkt1.Pos()) require.Equal(t, int64(0), pkt1.Pts()) require.Equal(t, 213, pkt1.Size()) require.Equal(t, 0, pkt1.StreamIndex()) - pkt2 := astiav.AllocPacket() + pkt2 := AllocPacket() require.NotNil(t, pkt2) defer pkt2.Free() require.Nil(t, pkt2.Data()) @@ -28,14 +27,14 @@ func TestPacket(t *testing.T) { require.Len(t, pkt2.Data(), 5) pkt2.SetDts(1) pkt2.SetDuration(2) - pkt2.SetFlags(astiav.NewPacketFlags(3)) + pkt2.SetFlags(NewPacketFlags(3)) pkt2.SetPos(4) pkt2.SetPts(5) pkt2.SetSize(6) pkt2.SetStreamIndex(7) require.Equal(t, int64(1), pkt2.Dts()) require.Equal(t, int64(2), pkt2.Duration()) - require.Equal(t, astiav.NewPacketFlags(3), pkt2.Flags()) + require.Equal(t, NewPacketFlags(3), pkt2.Flags()) require.Equal(t, int64(4), pkt2.Pos()) require.Equal(t, int64(5), pkt2.Pts()) require.Equal(t, 6, pkt2.Size()) @@ -60,26 +59,26 @@ func TestPacket(t *testing.T) { pkt3.SetDts(10) pkt3.SetDuration(20) pkt3.SetPts(30) - pkt3.RescaleTs(astiav.NewRational(1, 10), astiav.NewRational(1, 1)) + pkt3.RescaleTs(NewRational(1, 10), NewRational(1, 1)) require.Equal(t, int64(1), pkt3.Dts()) require.Equal(t, int64(2), pkt3.Duration()) require.Equal(t, int64(3), pkt3.Pts()) - pkt4 := astiav.AllocPacket() + pkt4 := AllocPacket() require.NotNil(t, pkt4) defer pkt4.Free() b := []byte("test") require.NoError(t, pkt4.FromData(b)) require.Equal(t, b, pkt4.Data()) - pkt5 := astiav.AllocPacket() + pkt5 := AllocPacket() require.NotNil(t, pkt5) defer pkt5.Free() b = []byte{1, 2, 3, 4} - require.NoError(t, pkt5.AddSideData(astiav.PacketSideDataTypeAudioServiceType, b)) - require.Equal(t, b, pkt5.SideData(astiav.PacketSideDataTypeAudioServiceType)) + require.NoError(t, pkt5.AddSideData(PacketSideDataTypeAudioServiceType, b)) + require.Equal(t, b, pkt5.SideData(PacketSideDataTypeAudioServiceType)) - pkt6 := astiav.AllocPacket() + pkt6 := AllocPacket() require.NotNil(t, pkt6) defer pkt6.Free() b = []byte{} diff --git a/picture_type_test.go b/picture_type_test.go index e0f0e69..d92cdcd 100644 --- a/picture_type_test.go +++ b/picture_type_test.go @@ -1,12 +1,11 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestPictureType(t *testing.T) { - require.Equal(t, "I", astiav.PictureTypeI.String()) + require.Equal(t, "I", PictureTypeI.String()) } diff --git a/pixel_format_test.go b/pixel_format_test.go index 0c2a6eb..9ce4c2a 100644 --- a/pixel_format_test.go +++ b/pixel_format_test.go @@ -1,14 +1,13 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestPixelFormat(t *testing.T) { - p := astiav.FindPixelFormatByName("yuv420p") - require.Equal(t, astiav.PixelFormatYuv420P, p) + p := FindPixelFormatByName("yuv420p") + require.Equal(t, PixelFormatYuv420P, p) require.Equal(t, "yuv420p", p.String()) } diff --git a/rational_test.go b/rational_test.go index 79fc2b5..c34eb14 100644 --- a/rational_test.go +++ b/rational_test.go @@ -1,14 +1,13 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestRational(t *testing.T) { - r := astiav.NewRational(2, 1) + r := NewRational(2, 1) require.Equal(t, 2, r.Num()) require.Equal(t, 1, r.Den()) r.SetNum(1) diff --git a/sample_format_test.go b/sample_format_test.go index fe6a426..ffaea35 100644 --- a/sample_format_test.go +++ b/sample_format_test.go @@ -1,12 +1,11 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestSampleFormat(t *testing.T) { - require.Equal(t, "s16", astiav.SampleFormatS16.String()) + require.Equal(t, "s16", SampleFormatS16.String()) } diff --git a/software_scale_context.go b/software_scale_context.go index c1df881..a40cffb 100644 --- a/software_scale_context.go +++ b/software_scale_context.go @@ -5,6 +5,7 @@ package astiav import "C" import ( "errors" + "unsafe" ) // https://github.com/FFmpeg/FFmpeg/blob/n5.0/libswscale/swscale_internal.h#L300 @@ -31,7 +32,7 @@ type softwareScaleContextUpdate struct { } func CreateSoftwareScaleContext(srcW, srcH int, srcFormat PixelFormat, dstW, dstH int, dstFormat PixelFormat, flags SoftwareScaleContextFlags) (*SoftwareScaleContext, error) { - ssc := SoftwareScaleContext{ + ssc := &SoftwareScaleContext{ dstFormat: C.enum_AVPixelFormat(dstFormat), dstH: C.int(dstH), dstW: C.int(dstW), @@ -54,7 +55,20 @@ func CreateSoftwareScaleContext(srcW, srcH int, srcFormat PixelFormat, dstW, dst if ssc.c == nil { return nil, errors.New("astiav: empty new context") } - return &ssc, nil + + classers.set(ssc) + return ssc, nil +} + +func (ssc *SoftwareScaleContext) Free() { + classers.del(ssc) + C.sws_freeContext(ssc.c) +} + +var _ Classer = (*SoftwareScaleContext)(nil) + +func (ssc *SoftwareScaleContext) Class() *Class { + return newClassFromC(unsafe.Pointer(ssc.c)) } func (ssc *SoftwareScaleContext) ScaleFrame(src, dst *Frame) error { @@ -195,9 +209,3 @@ func (ssc *SoftwareScaleContext) SourceResolution() (int, int) { func (ssc *SoftwareScaleContext) SetSourceResolution(w int, h int) error { return ssc.update(softwareScaleContextUpdate{srcW: &w, srcH: &h}) } - -func (ssc *SoftwareScaleContext) Free() { - if ssc.c != nil { - C.sws_freeContext(ssc.c) - } -} diff --git a/software_scale_context_test.go b/software_scale_context_test.go index e5cf7fa..99b524e 100644 --- a/software_scale_context_test.go +++ b/software_scale_context_test.go @@ -1,40 +1,39 @@ -package astiav_test +package astiav import ( "os" "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestSoftwareScaleContext(t *testing.T) { - f1 := astiav.AllocFrame() + f1 := AllocFrame() require.NotNil(t, f1) defer f1.Free() - f2 := astiav.AllocFrame() + f2 := AllocFrame() require.NotNil(t, f2) defer f2.Free() - f3 := astiav.AllocFrame() + f3 := AllocFrame() require.NotNil(t, f3) defer f3.Free() srcW := 4 srcH := 2 - srcPixelFormat := astiav.PixelFormatYuv420P + srcPixelFormat := PixelFormatYuv420P dstW := 8 dstH := 4 - dstPixelFormat := astiav.PixelFormatRgba - swscf1 := astiav.SoftwareScaleContextFlags(astiav.SoftwareScaleContextFlagBilinear) + dstPixelFormat := PixelFormatRgba + swscf1 := SoftwareScaleContextFlags(SoftwareScaleContextFlagBilinear) f1.SetHeight(srcH) f1.SetWidth(srcW) f1.SetPixelFormat(srcPixelFormat) require.NoError(t, f1.AllocBuffer(1)) - swsc1, err := astiav.CreateSoftwareScaleContext(srcW, srcH, srcPixelFormat, dstW, dstH, dstPixelFormat, swscf1) + swsc1, err := CreateSoftwareScaleContext(srcW, srcH, srcPixelFormat, dstW, dstH, dstPixelFormat, swscf1) require.NoError(t, err) defer swsc1.Free() require.Equal(t, dstH, swsc1.DestinationHeight()) @@ -50,6 +49,9 @@ func TestSoftwareScaleContext(t *testing.T) { require.Equal(t, w, srcW) require.Equal(t, h, srcH) require.Equal(t, srcW, swsc1.SourceWidth()) + cl := swsc1.Class() + require.NotNil(t, cl) + require.Equal(t, "SWScaler", cl.Name()) require.NoError(t, swsc1.ScaleFrame(f1, f2)) require.Equal(t, dstH, f2.Height()) @@ -58,11 +60,11 @@ func TestSoftwareScaleContext(t *testing.T) { dstW = 4 dstH = 3 - dstPixelFormat = astiav.PixelFormatYuv420P - swscf2 := astiav.SoftwareScaleContextFlags(astiav.SoftwareScaleContextFlagPoint) + dstPixelFormat = PixelFormatYuv420P + swscf2 := SoftwareScaleContextFlags(SoftwareScaleContextFlagPoint) srcW = 2 srcH = 1 - srcPixelFormat = astiav.PixelFormatRgba + srcPixelFormat = PixelFormatRgba require.NoError(t, swsc1.SetDestinationHeight(dstH)) require.Equal(t, dstH, swsc1.DestinationHeight()) @@ -91,14 +93,14 @@ func TestSoftwareScaleContext(t *testing.T) { require.Equal(t, w, srcW) require.Equal(t, h, srcH) - f4, err := globalHelper.inputLastFrame("image-rgba.png", astiav.MediaTypeVideo) + f4, err := globalHelper.inputLastFrame("image-rgba.png", MediaTypeVideo) require.NoError(t, err) - f5 := astiav.AllocFrame() + f5 := AllocFrame() require.NotNil(t, f5) defer f5.Free() - swsc2, err := astiav.CreateSoftwareScaleContext(f4.Width(), f4.Height(), f4.PixelFormat(), 512, 512, f4.PixelFormat(), astiav.NewSoftwareScaleContextFlags(astiav.SoftwareScaleContextFlagBilinear)) + swsc2, err := CreateSoftwareScaleContext(f4.Width(), f4.Height(), f4.PixelFormat(), 512, 512, f4.PixelFormat(), NewSoftwareScaleContextFlags(SoftwareScaleContextFlagBilinear)) require.NoError(t, err) require.NoError(t, swsc2.ScaleFrame(f4, f5)) diff --git a/stream_test.go b/stream_test.go index 78d5750..12db4d3 100644 --- a/stream_test.go +++ b/stream_test.go @@ -1,9 +1,8 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) @@ -16,25 +15,25 @@ func TestStream(t *testing.T) { s2 := ss[1] require.Equal(t, 0, s1.Index()) - require.Equal(t, astiav.NewRational(24, 1), s1.AvgFrameRate()) + require.Equal(t, NewRational(24, 1), s1.AvgFrameRate()) require.Equal(t, int64(61440), s1.Duration()) - require.True(t, s1.EventFlags().Has(astiav.StreamEventFlag(2))) + require.True(t, s1.EventFlags().Has(StreamEventFlag(2))) require.Equal(t, 1, s1.ID()) - require.Equal(t, "und", s1.Metadata().Get("language", nil, astiav.NewDictionaryFlags()).Value()) + require.Equal(t, "und", s1.Metadata().Get("language", nil, NewDictionaryFlags()).Value()) require.Equal(t, int64(120), s1.NbFrames()) - require.Equal(t, astiav.NewRational(24, 1), s1.RFrameRate()) - require.Equal(t, astiav.NewRational(1, 1), s1.SampleAspectRatio()) - require.Equal(t, []byte{}, s1.SideData(astiav.PacketSideDataTypeNb)) + require.Equal(t, NewRational(24, 1), s1.RFrameRate()) + require.Equal(t, NewRational(1, 1), s1.SampleAspectRatio()) + require.Equal(t, []byte{}, s1.SideData(PacketSideDataTypeNb)) require.Equal(t, int64(0), s1.StartTime()) - require.Equal(t, astiav.NewRational(1, 12288), s1.TimeBase()) + require.Equal(t, NewRational(1, 12288), s1.TimeBase()) require.Equal(t, 1, s2.Index()) require.Equal(t, int64(240640), s2.Duration()) require.Equal(t, 2, s2.ID()) require.Equal(t, int64(235), s2.NbFrames()) require.Equal(t, int64(0), s2.StartTime()) - require.Equal(t, astiav.NewRational(1, 48000), s2.TimeBase()) + require.Equal(t, NewRational(1, 48000), s2.TimeBase()) - s1.SetTimeBase(astiav.NewRational(1, 1)) - require.Equal(t, astiav.NewRational(1, 1), s1.TimeBase()) + s1.SetTimeBase(NewRational(1, 1)) + require.Equal(t, NewRational(1, 1), s1.TimeBase()) } diff --git a/time_test.go b/time_test.go index f31b4e9..912c3f4 100644 --- a/time_test.go +++ b/time_test.go @@ -1,12 +1,11 @@ -package astiav_test +package astiav import ( "testing" - "github.com/asticode/go-astiav" "github.com/stretchr/testify/require" ) func TestTime(t *testing.T) { - require.NotEqual(t, 0, astiav.RelativeTime()) + require.NotEqual(t, 0, RelativeTime()) }