mirror of
https://github.com/asticode/go-astiav.git
synced 2025-10-05 08:06:59 +08:00
Added getters to FilterLink
This commit is contained in:
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -73,7 +73,7 @@ jobs:
|
||||
|
||||
- if: ${{ steps.load-ffmpeg-cache.outputs.cache-hit != 'true' }}
|
||||
name: Save ffmpeg cache
|
||||
uses: actions/cache/save@v3
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ${{ env.FFMPEG_CACHE_PATH }}
|
||||
key: ffmpeg-${{ env.FFMPEG_VERSION }}-${{ runner.os }}
|
||||
|
@@ -12,30 +12,127 @@ import (
|
||||
)
|
||||
|
||||
func TestFilterGraph(t *testing.T) {
|
||||
fg := AllocFilterGraph()
|
||||
defer fg.Free()
|
||||
cl := fg.Class()
|
||||
fg1 := AllocFilterGraph()
|
||||
require.NotNil(t, fg1)
|
||||
defer fg1.Free()
|
||||
cl := fg1.Class()
|
||||
require.NotNil(t, cl)
|
||||
require.Equal(t, "AVFilterGraph", cl.Name())
|
||||
fg.SetThreadCount(2)
|
||||
require.Equal(t, 2, fg.ThreadCount())
|
||||
fg.SetThreadType(ThreadTypeSlice)
|
||||
require.Equal(t, ThreadTypeSlice, fg.ThreadType())
|
||||
fg1.SetThreadCount(2)
|
||||
require.Equal(t, 2, fg1.ThreadCount())
|
||||
fg1.SetThreadType(ThreadTypeSlice)
|
||||
require.Equal(t, ThreadTypeSlice, fg1.ThreadType())
|
||||
|
||||
bufferSink := FindFilterByName("buffersink")
|
||||
require.NotNil(t, bufferSink)
|
||||
type command struct {
|
||||
args string
|
||||
cmd string
|
||||
flags FilterCommandFlags
|
||||
resp string
|
||||
target string
|
||||
withError bool
|
||||
}
|
||||
type link struct {
|
||||
channelLayout ChannelLayout
|
||||
frameRate Rational
|
||||
height int
|
||||
mediaType MediaType
|
||||
pixelFormat PixelFormat
|
||||
sampleAspectRatio Rational
|
||||
sampleFormat SampleFormat
|
||||
sampleRate int
|
||||
timeBase Rational
|
||||
width int
|
||||
}
|
||||
type graph struct {
|
||||
buffersinkExpectedInput link
|
||||
buffersinkName string
|
||||
buffersrcName string
|
||||
commands []command
|
||||
content string
|
||||
s string
|
||||
sources []FilterArgs
|
||||
}
|
||||
for _, v := range []graph{
|
||||
{
|
||||
buffersinkExpectedInput: link{
|
||||
frameRate: NewRational(4, 1),
|
||||
height: 4,
|
||||
mediaType: MediaTypeVideo,
|
||||
pixelFormat: PixelFormatRgba,
|
||||
sampleAspectRatio: NewRational(1, 4),
|
||||
timeBase: NewRational(1, 4),
|
||||
width: 2,
|
||||
},
|
||||
buffersinkName: "buffersink",
|
||||
buffersrcName: "buffer",
|
||||
commands: []command{
|
||||
{
|
||||
args: "a",
|
||||
cmd: "invalid",
|
||||
flags: NewFilterCommandFlags(),
|
||||
target: "scale",
|
||||
withError: true,
|
||||
},
|
||||
{
|
||||
args: "4",
|
||||
cmd: "width",
|
||||
flags: NewFilterCommandFlags().Add(FilterCommandFlagOne),
|
||||
target: "scale",
|
||||
},
|
||||
},
|
||||
content: "[input_1]scale=2x4,settb=1/4,fps=fps=4/1,format=pix_fmts=rgba,setsar=1/4",
|
||||
s: " +--------------+\nParsed_setsar_4:default--[2x4 1:4 rgba]--default| filter_out |\n | (buffersink) |\n +--------------+\n\n+-------------+\n| filter_in_1 |default--[1x2 1:2 yuv420p]--Parsed_scale_0:default\n| (buffer) |\n+-------------+\n\n +----------------+\nfilter_in_1:default--[1x2 1:2 yuv420p]--default| Parsed_scale_0 |default--[2x4 1:2 rgba]--Parsed_settb_1:default\n | (scale) |\n +----------------+\n\n +----------------+\nParsed_scale_0:default--[2x4 1:2 rgba]--default| Parsed_settb_1 |default--[2x4 1:2 rgba]--Parsed_fps_2:default\n | (settb) |\n +----------------+\n\n +--------------+\nParsed_settb_1:default--[2x4 1:2 rgba]--default| Parsed_fps_2 |default--[2x4 1:2 rgba]--Parsed_format_3:default\n | (fps) |\n +--------------+\n\n +-----------------+\nParsed_fps_2:default--[2x4 1:2 rgba]--default| Parsed_format_3 |default--[2x4 1:2 rgba]--Parsed_setsar_4:default\n | (format) |\n +-----------------+\n\n +-----------------+\nParsed_format_3:default--[2x4 1:2 rgba]--default| Parsed_setsar_4 |default--[2x4 1:4 rgba]--filter_out:default\n | (setsar) |\n +-----------------+\n\n",
|
||||
sources: []FilterArgs{
|
||||
{
|
||||
"height": "2",
|
||||
"pix_fmt": strconv.Itoa(int(PixelFormatYuv420P)),
|
||||
"sar": "1/2",
|
||||
"time_base": "1/2",
|
||||
"width": "1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
buffersinkExpectedInput: link{
|
||||
channelLayout: ChannelLayoutStereo,
|
||||
mediaType: MediaTypeAudio,
|
||||
sampleFormat: SampleFormatS16,
|
||||
sampleRate: 4,
|
||||
timeBase: NewRational(1, 4),
|
||||
},
|
||||
buffersinkName: "abuffersink",
|
||||
buffersrcName: "abuffer",
|
||||
content: "[input_1]aformat=sample_fmts=s16:channel_layouts=stereo:sample_rates=4,asettb=1/4",
|
||||
s: " +---------------+\nParsed_asettb_1:default--[4Hz s16:stereo]--default| filter_out |\n | (abuffersink) |\n +---------------+\n\n+-------------+\n| filter_in_1 |default--[2Hz fltp:mono]--auto_aresample_0:default\n| (abuffer) |\n+-------------+\n\n +------------------+\nauto_aresample_0:default--[4Hz s16:stereo]--default| Parsed_aformat_0 |default--[4Hz s16:stereo]--Parsed_asettb_1:default\n | (aformat) |\n +------------------+\n\n +-----------------+\nParsed_aformat_0:default--[4Hz s16:stereo]--default| Parsed_asettb_1 |default--[4Hz s16:stereo]--filter_out:default\n | (asettb) |\n +-----------------+\n\n +------------------+\nfilter_in_1:default--[2Hz fltp:mono]--default| auto_aresample_0 |default--[4Hz s16:stereo]--Parsed_aformat_0:default\n | (aresample) |\n +------------------+\n\n",
|
||||
sources: []FilterArgs{
|
||||
{
|
||||
"channel_layout": ChannelLayoutMono.String(),
|
||||
"sample_fmt": strconv.Itoa(int(SampleFormatFltp)),
|
||||
"sample_rate": "2",
|
||||
"time_base": "1/2",
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
fg := AllocFilterGraph()
|
||||
require.NotNil(t, fg)
|
||||
defer fg.Free()
|
||||
|
||||
fcOut, err := fg.NewFilterContext(bufferSink, "filter_out", nil)
|
||||
buffersrc := FindFilterByName(v.buffersrcName)
|
||||
require.NotNil(t, buffersrc)
|
||||
buffersink := FindFilterByName(v.buffersinkName)
|
||||
require.NotNil(t, buffersink)
|
||||
|
||||
buffersinkContext, err := fg.NewFilterContext(buffersink, "filter_out", nil)
|
||||
require.NoError(t, err)
|
||||
defer fcOut.Free()
|
||||
cl = fcOut.Class()
|
||||
cl = buffersinkContext.Class()
|
||||
require.NotNil(t, cl)
|
||||
require.Equal(t, "AVFilter", cl.Name())
|
||||
|
||||
inputs := AllocFilterInOut()
|
||||
defer inputs.Free()
|
||||
inputs.SetName("out")
|
||||
inputs.SetFilterContext(fcOut)
|
||||
inputs.SetFilterContext(buffersinkContext)
|
||||
inputs.SetPadIdx(0)
|
||||
inputs.SetNext(nil)
|
||||
|
||||
@@ -45,55 +142,64 @@ func TestFilterGraph(t *testing.T) {
|
||||
outputs.Free()
|
||||
}
|
||||
}()
|
||||
var fcIns []*FilterContext
|
||||
for i := 0; i < 2; i++ {
|
||||
bufferSrc := FindFilterByName("buffer")
|
||||
require.NotNil(t, bufferSrc)
|
||||
|
||||
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",
|
||||
})
|
||||
var buffersrcContexts []*FilterContext
|
||||
for idx, src := range v.sources {
|
||||
buffersrcContext, err := fg.NewFilterContext(buffersrc, fmt.Sprintf("filter_in_%d", idx+1), src)
|
||||
require.NoError(t, err)
|
||||
fcIns = append(fcIns, fcIn)
|
||||
defer fcIn.Free()
|
||||
buffersrcContexts = append(buffersrcContexts, buffersrcContext)
|
||||
|
||||
o := AllocFilterInOut()
|
||||
o.SetName(fmt.Sprintf("input_%d", i+1))
|
||||
o.SetFilterContext(fcIn)
|
||||
o.SetName(fmt.Sprintf("input_%d", idx+1))
|
||||
o.SetFilterContext(buffersrcContext)
|
||||
o.SetPadIdx(0)
|
||||
o.SetNext(outputs)
|
||||
|
||||
outputs = o
|
||||
}
|
||||
|
||||
err = fg.Parse("[input_1]scale=2x2[scaled_1];[input_2]scale=3x3[scaled_2];[scaled_1][scaled_2]overlay", inputs, outputs)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fg.Parse(v.content, inputs, outputs))
|
||||
require.NoError(t, fg.Configure())
|
||||
|
||||
err = fg.Configure()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, fcOut.NbInputs())
|
||||
require.Equal(t, 1, len(fcOut.Inputs()))
|
||||
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, NewRational(1, 1000), fc.Outputs()[0].TimeBase())
|
||||
require.Equal(t, 1, buffersinkContext.NbInputs())
|
||||
links := buffersinkContext.Inputs()
|
||||
require.Equal(t, 1, len(links))
|
||||
e, g := v.buffersinkExpectedInput, links[0]
|
||||
require.Equal(t, e.frameRate, g.FrameRate())
|
||||
require.Equal(t, e.mediaType, g.MediaType())
|
||||
require.Equal(t, e.timeBase, g.TimeBase())
|
||||
switch e.mediaType {
|
||||
case MediaTypeAudio:
|
||||
require.True(t, e.channelLayout.Equal(g.ChannelLayout()))
|
||||
require.Equal(t, e.sampleFormat, g.SampleFormat())
|
||||
require.Equal(t, e.sampleRate, g.SampleRate())
|
||||
default:
|
||||
require.Equal(t, e.height, g.Height())
|
||||
require.Equal(t, e.pixelFormat, g.PixelFormat())
|
||||
require.Equal(t, e.sampleAspectRatio, g.SampleAspectRatio())
|
||||
require.Equal(t, e.width, g.Width())
|
||||
}
|
||||
|
||||
resp, err := fg.SendCommand("scale", "invalid", "a", NewFilterCommandFlags())
|
||||
require.Error(t, err)
|
||||
require.Empty(t, resp)
|
||||
resp, err = fg.SendCommand("scale", "width", "4", NewFilterCommandFlags().Add(FilterCommandFlagOne))
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, resp)
|
||||
for _, buffersrcContext := range buffersrcContexts {
|
||||
require.Equal(t, 0, buffersrcContext.NbInputs())
|
||||
require.Equal(t, 1, buffersrcContext.NbOutputs())
|
||||
links := buffersrcContext.Outputs()
|
||||
require.Equal(t, 1, len(links))
|
||||
require.Equal(t, v.buffersinkExpectedInput.mediaType, links[0].MediaType())
|
||||
}
|
||||
|
||||
require.Equal(t, " +--------------+\nParsed_overlay_2:default--[2x2 1:1 yuv420p]--default| filter_out |\n | (buffersink) |\n +--------------+\n\n+-------------+\n| filter_in_1 |default--[1x1 1:1 yuv420p]--Parsed_scale_0:default\n| (buffer) |\n+-------------+\n\n+-------------+\n| filter_in_2 |default--[1x1 1:1 yuv420p]--Parsed_scale_1:default\n| (buffer) |\n+-------------+\n\n +----------------+\nfilter_in_1:default--[1x1 1:1 yuv420p]--default| Parsed_scale_0 |default--[4x2 1:2 yuv420p]--Parsed_overlay_2:main\n | (scale) |\n +----------------+\n\n +----------------+\nfilter_in_2:default--[1x1 1:1 yuv420p]--default| Parsed_scale_1 |default--[3x3 1:1 yuva420p]--Parsed_overlay_2:overlay\n | (scale) |\n +----------------+\n\n +------------------+\nParsed_scale_0:default--[4x2 1:2 yuv420p]------main| Parsed_overlay_2 |default--[2x2 1:1 yuv420p]--filter_out:default\nParsed_scale_1:default--[3x3 1:1 yuva420p]--overlay| (overlay) |\n +------------------+\n\n", fg.String())
|
||||
require.Equal(t, v.s, fg.String())
|
||||
|
||||
for _, command := range v.commands {
|
||||
resp, err := fg.SendCommand(command.target, command.cmd, command.args, command.flags)
|
||||
if command.withError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.Equal(t, command.resp, resp)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Test BuffersrcAddFrame
|
||||
// TODO Test BuffersinkGetFrame
|
||||
|
@@ -15,6 +15,43 @@ func newFilterLinkFromC(c *C.AVFilterLink) *FilterLink {
|
||||
return &FilterLink{c: c}
|
||||
}
|
||||
|
||||
func (l *FilterLink) ChannelLayout() ChannelLayout {
|
||||
v, _ := newChannelLayoutFromC(&l.c.ch_layout).clone()
|
||||
return v
|
||||
}
|
||||
|
||||
func (l *FilterLink) FrameRate() Rational {
|
||||
return newRationalFromC(l.c.frame_rate)
|
||||
}
|
||||
|
||||
func (l *FilterLink) Height() int {
|
||||
return int(l.c.h)
|
||||
}
|
||||
|
||||
func (l *FilterLink) MediaType() MediaType {
|
||||
return MediaType(l.c._type)
|
||||
}
|
||||
|
||||
func (l *FilterLink) PixelFormat() PixelFormat {
|
||||
return PixelFormat(l.c.format)
|
||||
}
|
||||
|
||||
func (l *FilterLink) SampleAspectRatio() Rational {
|
||||
return newRationalFromC(l.c.sample_aspect_ratio)
|
||||
}
|
||||
|
||||
func (l *FilterLink) SampleFormat() SampleFormat {
|
||||
return SampleFormat(l.c.format)
|
||||
}
|
||||
|
||||
func (l *FilterLink) SampleRate() int {
|
||||
return int(l.c.sample_rate)
|
||||
}
|
||||
|
||||
func (l *FilterLink) TimeBase() Rational {
|
||||
return newRationalFromC(l.c.time_base)
|
||||
}
|
||||
|
||||
func (l *FilterLink) Width() int {
|
||||
return int(l.c.w)
|
||||
}
|
||||
|
Reference in New Issue
Block a user