mirror of
https://github.com/asticode/go-astiav.git
synced 2025-09-26 20:21:15 +08:00
Added Classer + now logs returns a Classer + tests are now done in astiav package
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,3 @@
|
||||
.DS_STORE
|
||||
cover*
|
||||
coverage.out
|
||||
tmp
|
4
Makefile
4
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
|
||||
|
@@ -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()
|
||||
|
@@ -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
|
||||
|
@@ -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))
|
||||
}
|
||||
|
134
class.go
Normal file
134
class.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package astiav
|
||||
|
||||
//#cgo pkg-config: libavutil
|
||||
//#include <libavutil/log.h>
|
||||
//#include <stdint.h>
|
||||
/*
|
||||
|
||||
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
|
||||
}
|
30
class_category.go
Normal file
30
class_category.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package astiav
|
||||
|
||||
//#cgo pkg-config: libavutil
|
||||
//#include <libavutil/log.h>
|
||||
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)
|
||||
)
|
63
class_test.go
Normal file
63
class_test.go
Normal file
@@ -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))
|
||||
}
|
@@ -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)
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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())
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,9 @@
|
||||
package astiav_test
|
||||
package astiav
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/asticode/go-astiav"
|
||||
)
|
||||
|
||||
func TestDevice(t *testing.T) {
|
||||
astiav.RegisterAllDevices()
|
||||
RegisterAllDevices()
|
||||
}
|
||||
|
@@ -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))
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -6,18 +6,28 @@ package astiav
|
||||
//#include <libavfilter/buffersrc.h>
|
||||
//#include <libavutil/frame.h>
|
||||
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)
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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())
|
||||
|
195
flags_test.go
195
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)))
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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)
|
||||
|
2
frame.go
2
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
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -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()
|
||||
|
||||
|
@@ -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))
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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())
|
||||
|
@@ -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))
|
||||
}
|
||||
|
@@ -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 }}`
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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()
|
||||
|
60
log.go
60
log.go
@@ -5,19 +5,14 @@ package astiav
|
||||
//#include <stdio.h>
|
||||
//#include <stdlib.h>
|
||||
/*
|
||||
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)
|
||||
}
|
||||
|
54
log_test.go
54
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])
|
||||
}
|
||||
|
@@ -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))
|
||||
}
|
||||
|
@@ -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())
|
||||
}
|
||||
|
@@ -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{}
|
||||
|
@@ -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())
|
||||
}
|
||||
|
@@ -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())
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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())
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
@@ -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))
|
||||
|
||||
|
@@ -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())
|
||||
}
|
||||
|
@@ -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())
|
||||
}
|
||||
|
Reference in New Issue
Block a user