@@ -15,7 +15,7 @@ def _create_root_node(node_class, *args, **kwargs):
15
15
16
16
17
17
def _create_child_node (node_class , parent , * args , ** kwargs ):
18
- child = node_class ([ parent ] , * args , ** kwargs )
18
+ child = node_class (parent , * args , ** kwargs )
19
19
child ._update_hash ()
20
20
return child
21
21
@@ -31,11 +31,7 @@ def _add_operator(cls, node_class):
31
31
if not getattr (node_class , 'STATIC' , False ):
32
32
def func (self , * args , ** kwargs ):
33
33
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 )
39
35
40
36
@classmethod
41
37
def _add_operators (cls , node_classes ):
@@ -75,18 +71,59 @@ def __init__(self, filename):
75
71
76
72
77
73
class _FilterNode (_Node ):
78
- pass
74
+ def _get_filter (self ):
75
+ raise NotImplementedError ()
79
76
80
77
81
- class _TrimFilterNode (_FilterNode ):
78
+ class _TrimNode (_FilterNode ):
82
79
NAME = 'trim'
83
80
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 ] )
86
83
self .start_frame = start_frame
87
84
self .end_frame = end_frame
88
85
self .setpts = setpts
89
86
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
+
90
127
91
128
class _ConcatNode (_Node ):
92
129
NAME = 'concat'
@@ -95,6 +132,9 @@ class _ConcatNode(_Node):
95
132
def __init__ (self , * parents ):
96
133
super (_ConcatNode , self ).__init__ (parents )
97
134
135
+ def _get_filter (self ):
136
+ return 'concat=n={}' .format (len (self .parents ))
137
+
98
138
99
139
class _OutputNode (_Node ):
100
140
@classmethod
@@ -130,22 +170,12 @@ def visit(node, child):
130
170
visit (unmarked_nodes .pop (), None )
131
171
return sorted_nodes , child_map
132
172
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
-
143
173
@classmethod
144
174
def _get_filter_spec (cls , i , node , stream_name_map ):
145
175
stream_name = cls ._get_stream_name ('v{}' .format (i ))
146
176
stream_name_map [node ] = stream_name
147
177
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 )
149
179
return filter_spec
150
180
151
181
@classmethod
@@ -197,19 +227,18 @@ def run(self):
197
227
198
228
199
229
class _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 ])
204
233
205
234
206
235
class _OverwriteOutputNode (_GlobalNode ):
207
236
NAME = 'overwrite_output'
208
237
209
238
210
-
211
239
class _MergeOutputsNode (_OutputNode ):
F987
td>212
240
NAME = 'merge_outputs'
241
+ STATIC = True
213
242
214
243
def __init__ (self , * parents ):
215
244
assert not any ([not isinstance (parent , _OutputNode ) for parent in parents ]), 'Can only merge output streams'
@@ -219,17 +248,20 @@ def __init__(self, *parents):
219
248
class _FileOutputNode (_OutputNode ):
220
249
NAME = 'file_output'
221
250
222
- def __init__ (self , parents , filename ):
223
- super (_FileOutputNode , self ).__init__ (parents )
251
+ def __init__ (self , parent , filename ):
252
+ super (_FileOutputNode , self ).__init__ ([ parent ] )
224
253
self .filename = filename
225
254
226
255
227
256
NODE_CLASSES = [
257
+ _HFlipNode ,
258
+ _DrawBoxNode ,
228
259
_ConcatNode ,
229
260
_FileInputNode ,
230
261
_FileOutputNode ,
262
+ _OverlayNode ,
231
263
_OverwriteOutputNode ,
232
- _TrimFilterNode ,
264
+ _TrimNode ,
233
265
]
234
266
235
267
_Node ._add_operators (NODE_CLASSES )
0 commit comments