Skip to content

Commit

Permalink
Added filter ParseSegment()
Browse files Browse the repository at this point in the history
  • Loading branch information
asticode committed Sep 17, 2024
1 parent fba33b1 commit 00de6ca
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 4 deletions.
26 changes: 25 additions & 1 deletion filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package astiav

//#include <libavfilter/avfilter.h>
import "C"
import "unsafe"
import (
"unsafe"
)

// https://github.com/FFmpeg/FFmpeg/blob/n5.0/libavfilter/avfilter.h#L165
type Filter struct {
Expand All @@ -29,3 +31,25 @@ func (f *Filter) Name() string {
func (f *Filter) String() string {
return f.Name()
}

func (f *Filter) NbInputs() int {
return int(f.c.nb_inputs)
}

func (f *Filter) NbOutputs() int {
return int(f.c.nb_outputs)
}

func (f *Filter) Inputs() (ps []*FilterPad) {
for idx := 0; idx < f.NbInputs(); idx++ {
ps = append(ps, newFilterPad(MediaType(C.avfilter_pad_get_type(f.c.inputs, C.int(idx)))))
}
return
}

func (f *Filter) Outputs() (ps []*FilterPad) {
for idx := 0; idx < f.NbOutputs(); idx++ {
ps = append(ps, newFilterPad(MediaType(C.avfilter_pad_get_type(f.c.outputs, C.int(idx)))))
}
return
}
32 changes: 32 additions & 0 deletions filter_chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package astiav

//#include <libavfilter/avfilter.h>
import "C"
import (
"math"
"unsafe"
)

// https://github.com/FFmpeg/FFmpeg/blob/n7.0/libavfilter/avfilter.h#L1142
type FilterChain struct {
c *C.AVFilterChain
}

func newFilterChainFromC(c *C.AVFilterChain) *FilterChain {
if c == nil {
return nil
}
return &FilterChain{c: c}
}

func (fc *FilterChain) Filters() (fs []*FilterParams) {
fcs := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.AVFilterParams)(nil))](*C.AVFilterParams))(unsafe.Pointer(fc.c.filters))
for i := 0; i < fc.NbFilters(); i++ {
fs = append(fs, newFilterParamsFromC(fcs[i]))
}
return
}

func (fc *FilterChain) NbFilters() int {
return int(fc.c.nb_filters)
}
10 changes: 10 additions & 0 deletions filter_graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ func (g *FilterGraph) Parse(content string, inputs, outputs *FilterInOut) error
return newError(C.avfilter_graph_parse_ptr(g.c, cc, ic, oc, nil))
}

func (g *FilterGraph) ParseSegment(content string) (*FilterGraphSegment, error) {
cc := C.CString(content)
defer C.free(unsafe.Pointer(cc))
var cs *C.AVFilterGraphSegment
if err := newError(C.avfilter_graph_segment_parse(g.c, cc, 0, &cs)); err != nil {
return nil, err
}
return newFilterGraphSegmentFromC(cs), nil
}

func (g *FilterGraph) Configure() error {
return newError(C.avfilter_graph_config(g.c, nil))
}
Expand Down
36 changes: 36 additions & 0 deletions filter_graph_segment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package astiav

//#include <libavfilter/avfilter.h>
import "C"
import (
"math"
"unsafe"
)

// https://github.com/FFmpeg/FFmpeg/blob/n7.0/libavfilter/avfilter.h#L1156
type FilterGraphSegment struct {
c *C.AVFilterGraphSegment
}

func newFilterGraphSegmentFromC(c *C.AVFilterGraphSegment) *FilterGraphSegment {
if c == nil {
return nil
}
return &FilterGraphSegment{c: c}
}

func (fgs *FilterGraphSegment) Free() {
C.avfilter_graph_segment_free(&fgs.c)
}

func (fgs *FilterGraphSegment) Chains() (cs []*FilterChain) {
ccs := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.AVFilterChain)(nil))](*C.AVFilterChain))(unsafe.Pointer(fgs.c.chains))
for i := 0; i < fgs.NbChains(); i++ {
cs = append(cs, newFilterChainFromC(ccs[i]))
}
return
}

func (fgs *FilterGraphSegment) NbChains() int {
return int(fgs.c.nb_chains)
}
26 changes: 23 additions & 3 deletions filter_graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ func TestFilterGraph(t *testing.T) {
channelLayout: ChannelLayoutStereo,
mediaType: MediaTypeAudio,
sampleFormat: SampleFormatS16,
sampleRate: 4,
sampleRate: 3,
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",
content: "[input_1]aformat=sample_fmts=s16:channel_layouts=stereo:sample_rates=3,asettb=1/4",
s: " +---------------+\nParsed_asettb_1:default--[3Hz 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--[3Hz s16:stereo]--default| Parsed_aformat_0 |default--[3Hz s16:stereo]--Parsed_asettb_1:default\n | (aformat) |\n +------------------+\n\n +-----------------+\nParsed_aformat_0:default--[3Hz s16:stereo]--default| Parsed_asettb_1 |default--[3Hz s16:stereo]--filter_out:default\n | (asettb) |\n +-----------------+\n\n +------------------+\nfilter_in_1:default--[2Hz fltp:mono]--default| auto_aresample_0 |default--[3Hz s16:stereo]--Parsed_aformat_0:default\n | (aresample) |\n +------------------+\n\n",
sources: []FilterArgs{
{
"channel_layout": ChannelLayoutMono.String(),
Expand Down Expand Up @@ -201,6 +201,26 @@ func TestFilterGraph(t *testing.T) {
}
}

fg2 := AllocFilterGraph()
require.NotNil(t, fg2)
defer fg2.Free()
fgs, err := fg2.ParseSegment("anullsrc")
require.NoError(t, err)
defer fgs.Free()
require.Equal(t, 1, fgs.NbChains())
cs := fgs.Chains()
require.Equal(t, 1, len(cs))
require.Equal(t, 1, cs[0].NbFilters())
fs := cs[0].Filters()
require.Equal(t, 1, len(fs))
f := FindFilterByName(fs[0].FilterName())
require.NotNil(t, f)
require.Equal(t, 0, f.NbInputs())
require.Equal(t, 1, f.NbOutputs())
os := f.Outputs()
require.Equal(t, 1, len(os))
require.Equal(t, MediaTypeAudio, os[0].MediaType())

// TODO Test BuffersrcAddFrame
// TODO Test BuffersinkGetFrame
}
14 changes: 14 additions & 0 deletions filter_pad.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package astiav

// Struct attributes are internal but there are C functions to get some of them
type FilterPad struct {
mediaType MediaType
}

func newFilterPad(mediaType MediaType) *FilterPad {
return &FilterPad{mediaType: mediaType}
}

func (fp *FilterPad) MediaType() MediaType {
return fp.mediaType
}
20 changes: 20 additions & 0 deletions filter_params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package astiav

//#include <libavfilter/avfilter.h>
import "C"

// https://github.com/FFmpeg/FFmpeg/blob/n7.0/libavfilter/avfilter.h#L1075
type FilterParams struct {
c *C.AVFilterParams
}

func newFilterParamsFromC(c *C.AVFilterParams) *FilterParams {
if c == nil {
return nil
}
return &FilterParams{c: c}
}

func (fp *FilterParams) FilterName() string {
return C.GoString(fp.c.filter_name)
}

0 comments on commit 00de6ca

Please sign in to comment.