@@ -159,11 +159,19 @@ def finalize_input(key, val):
159159 return key , val
160160
161161 def opts2args (opts , finalize ):
162- args = []
162+ # FFmpeg applies the last of the repeated options regardless of overall/per-stream
163+ # need to parse per-stream options and group repeated options together and
164+ # apply the overall option first
165+
166+ opts_parsed = {}
163167 for itm in opts .items ():
164- key , val = finalize (* itm )
168+ k , v = finalize (* itm )
169+ oname , * sspec = k .split (":" , 1 )
170+ if oname not in opts_parsed :
171+ opts_parsed [oname ] = o = {}
172+ o [sspec [0 ] if len (sspec ) else None ] = v
165173
166- karg = f"- { key } "
174+ def set_arg ( karg , val ):
167175 if not isinstance (val , (str , Graph , Chain , Filter )) and isinstance (
168176 val , abc .Sequence
169177 ):
@@ -173,12 +181,21 @@ def opts2args(opts, finalize):
173181 args .append (karg )
174182 if val is not FLAG :
175183 args .append (str (val ))
184+
185+ args = []
186+ for key , vals in opts_parsed .items ():
187+ kbase = f"-{ key } "
188+ if None in vals :
189+ val = val = vals .pop (None )
190+ set_arg (kbase , val )
191+ for st , val in vals .items ():
192+ set_arg (f"{ kbase } :{ st } " , val )
193+
176194 return args
177195
178196 def inputs2args (inputs ):
179197 args = []
180198 for url , opts in inputs :
181-
182199 # resolve url enumeration if it's a device
183200 url , opts = devices .resolve_source (url , opts )
184201
@@ -195,7 +212,6 @@ def inputs2args(inputs):
195212 def outputs2args (outputs ):
196213 args = []
197214 for url , opts in outputs :
198-
199215 # resolve url enumeration if it's a device
200216 url , opts = devices .resolve_sink (url , opts )
201217
0 commit comments