@@ -15,7 +15,7 @@ def _create_root_node(node_class, *args, **kwargs):
1515
1616
1717def _create_child_node (node_class , parent , * args , ** kwargs ):
18- child = node_class ([ parent ] , * args , ** kwargs )
18+ child = node_class (parent , * args , ** kwargs )
1919 child ._update_hash ()
2020 return child
2121
@@ -31,11 +31,7 @@ def _add_operator(cls, node_class):
3131 if not getattr (node_class , 'STATIC' , False ):
3232 def func (self , * args , ** kwargs ):
3333 return _create_child_node (node_class , self , * args , ** kwargs )
34- else :
35- @classmethod
36- def func (cls2 , * args , ** kwargs ):
37- return _create_root_node (node_class , * args , ** kwargs )
38- setattr (cls , node_class .NAME , func )
34+ setattr (cls , node_class .NAME , func )
3935
4036 @classmethod
4137 def _add_operators (cls , node_classes ):
@@ -75,18 +71,59 @@ def __init__(self, filename):
7571
7672
7773class _FilterNode (_Node ):
78- pass
74+ def _get_filter (self ):
75+ raise NotImplementedError ()
7976
8077
81- class _TrimFilterNode (_FilterNode ):
78+ class _TrimNode (_FilterNode ):
8279 NAME = 'trim'
8380
84- def __init__ (self , parents , start_frame , end_frame , setpts = 'PTS-STARTPTS' ):
85- super (_TrimFilterNode , self ).__init__ (parents )
81+ def __init__ (self , parent , start_frame , end_frame , setpts = 'PTS-STARTPTS' ):
82+ super (_TrimNode , self ).__init__ ([ parent ] )
8683 self .start_frame = start_frame
8784 self .end_frame = end_frame
8885 self .setpts = setpts
8986
87+ def _get_filter (self ):
88+ return 'trim=start_frame={}:end_frame={},setpts={}' .format (self .start_frame , self .end_frame , self .setpts )
89+
90+
91+ class _OverlayNode (_FilterNode ):
92+ NAME = 'overlay'
93+
94+ def __init__ (self , main_parent , overlay_parent , eof_action = 'repeat' ):
95+ super (_OverlayNode , self ).__init__ ([main_parent , overlay_parent ])
96+ self .eof_action = eof_action
97+
98+ def _get_filter (self ):
99+ return 'overlay=eof_action={}' .format (self .eof_action )
100+
101+
102+ class _HFlipNode (_FilterNode ):
103+ NAME = 'hflip'
104+
105+ def __init__ (self , parent ):
106+ super (_HFlipNode , self ).__init__ ([parent ])
107+
108+ def _get_filter (self ):
109+ return 'hflip'
110+
111+
112+ class _DrawBoxNode (_FilterNode ):
113+ NAME = 'drawbox'
114+
115+ def __init__ (self , parent , x , y , width , height , color , thickness = 1 ):
116+ super (_DrawBoxNode , self ).__init__ ([parent ])
117+ self .x = x
118+ self .y = y
119+ self .width = width
120+ self .height = height
121+ self .color = color
122+ self .thickness = thickness
123+
124+ def _get_filter (self ):
125+ return 'drawbox={}:{}:{}:{}:{}:t={}' .format (self .x , self .y , self .width , self .height , self .color , self .thickness )
126+
90127
91128class _ConcatNode (_Node ):
92129 NAME = 'concat'
@@ -95,6 +132,9 @@ class _ConcatNode(_Node):
95132 def __init__ (self , * parents ):
96133 super (_ConcatNode , self ).__init__ (parents )
97134
135+ def _get_filter (self ):
136+ return 'concat=n={}' .format (len (self .parents ))
137+
98138
99139class _OutputNode (_Node ):
100140 @classmethod
@@ -130,22 +170,12 @@ def visit(node, child):
130170 visit (unmarked_nodes .pop (), None )
131171 return sorted_nodes , child_map
132172
133- @classmethod
134- def _get_filter (cls , node ):
135- # TODO: find a better way to do this instead of ugly if/elifs.
136- if isinstance (node , _TrimFilterNode ):
137- return 'trim=start_frame={}:end_frame={},setpts={}' .format (node .start_frame , node .end_frame , node .setpts )
138- elif isinstance (node , _ConcatNode ):
139- return 'concat=n={}' .format (len (node .parents ))
140- else :
141- assert False , 'Unsupported filter node: {}' .format (node )
142-
143173 @classmethod
144174 def _get_filter_spec (cls , i , node , stream_name_map ):
145175 stream_name = cls ._get_stream_name ('v{}' .format (i ))
146176 stream_name_map [node ] = stream_name
147177 inputs = [stream_name_map [parent ] for parent in node .parents ]
148- filter_spec = '{}{}{}' .format ('' .join (inputs ), cls ._get_filter (node ), stream_name )
178+ filter_spec = '{}{}{}' .format ('' .join (inputs ), node ._get_filter (), stream_name )
149179 return filter_spec
150180
151181 @classmethod
@@ -197,19 +227,18 @@ def run(self):
197227
198228
199229class _GlobalNode (_OutputNode ):
200- def __init__ (self , parents ):
201- assert len (parents ) == 1
202- assert isinstance (parents [0 ], _OutputNode ), 'Global nodes can only be attached after output nodes'
203- super (_GlobalNode , self ).__init__ (parents )
230+ def __init__ (self , parent ):
231+ assert isinstance (parent , _OutputNode ), 'Global nodes can only be attached after output nodes'
232+ super (_GlobalNode , self ).__init__ ([parent ])
204233
205234
206235class _OverwriteOutputNode (_GlobalNode ):
207236 NAME = 'overwrite_output'
208237
209238
210-
211239class _MergeOutputsNode (_OutputNode ):
212240 NAME = 'merge_outputs'
241+ STATIC = True
213242
214243 def __init__ (self , * parents ):
215244 assert not any ([not isinstance (parent , _OutputNode ) for parent in parents ]), 'Can only merge output streams'
@@ -219,17 +248,20 @@ def __init__(self, *parents):
219248class _FileOutputNode (_OutputNode ):
220249 NAME = 'file_output'
221250
222- def __init__ (self , parents , filename ):
223- super (_FileOutputNode , self ).__init__ (parents )
251+ def __init__ (self , parent , filename ):
252+ super (_FileOutputNode , self ).__init__ ([ parent ] )
224253 self .filename = filename
225254
226255
227256NODE_CLASSES = [
257+ _HFlipNode ,
258+ _DrawBoxNode ,
228259 _ConcatNode ,
229260 _FileInputNode ,
230261 _FileOutputNode ,
262+ _OverlayNode ,
231263 _OverwriteOutputNode ,
232- _TrimFilterNode ,
264+ _TrimNode ,
233265]
234266
235267_Node ._add_operators (NODE_CLASSES )
0 commit comments