|
99 | 99 | from contextlib import contextmanager |
100 | 100 | from functools import partial, reduce |
101 | 101 | from copy import deepcopy |
| 102 | +import os |
102 | 103 | import re |
103 | 104 | from subprocess import PIPE |
104 | 105 | from tempfile import NamedTemporaryFile |
@@ -2340,43 +2341,71 @@ def rattach(self, left, right_on=None, left_on=None): |
2340 | 2341 |
|
2341 | 2342 | @contextmanager |
2342 | 2343 | def as_script_file(self): |
2343 | | - """return file-like object with filtergraph description |
| 2344 | + """return script file containing the filtergraph description |
2344 | 2345 |
|
2345 | | - :yield: temporary file with written filtergraph description |
2346 | | - :rtype: file-like object |
| 2346 | + :yield: path of a temporary text file with filtergraph description |
| 2347 | + :rtype: str |
2347 | 2348 |
|
2348 | | - The created file-like object can be used just like a normal file within |
2349 | | - a `with` statement. Use this function to pipe in a long filtergraph |
2350 | | - description with `filter_complex_script` or `filter_script` FFmpeg options. |
2351 | | - The option value shall be set to `'pipe:x'` where x is the pipe's descriptor. |
2352 | | - (`'pipe:0'` if using standard input). |
| 2349 | + This method is intended to work with the `filter_script` and |
| 2350 | + `filter_complex_script` FFmpeg options, by creating a temporary text file |
| 2351 | + containing the filtergraph description. |
2353 | 2352 |
|
2354 | 2353 | ..note:: |
2355 | 2354 | Only use this function when the filtergraph description is too long for |
2356 | | - OS to handle it as an command argument. Presenting the filtergraph with |
2357 | | - a `filter_complex` or `filter` option is a faster solution. |
| 2355 | + OS to handle it. Presenting the filtergraph with a `filter_complex` or |
| 2356 | + `filter` option to FFmpeg is always a faster solution. |
| 2357 | +
|
| 2358 | + Moreover, if `stdin` is available, i.e., not for a write or filter |
| 2359 | + operation, it is more performant to pass the long filtergraph object |
| 2360 | + to the subprocess' `input` argument instead of using this method. |
| 2361 | +
|
| 2362 | + Use this method with a `with` statement. How to incorporate its output |
| 2363 | + with `ffmpegprocess` depends on the `as_file_obj` argument. |
2358 | 2364 |
|
2359 | 2365 | ..example:: |
2360 | | - |
2361 | | - ..codeblock::python |
2362 | 2366 |
|
2363 | | - fg = ffmpegio.FilterGraph(...) # a very long filtergraph |
| 2367 | + The following example illustrates a usecase for a video SISO filtergraph: |
| 2368 | +
|
| 2369 | + ..codeblock::python |
| 2370 | +
|
| 2371 | + # assume `fg` is a SISO video filter Graph object |
| 2372 | +
|
| 2373 | + with fg.as_script_file() as script_path: |
| 2374 | + ffmpegio.ffmpegprocess.run( |
| 2375 | + { |
| 2376 | + 'inputs': [('input.mp4', None)] |
| 2377 | + 'outputs': [('output.mp4', {'filter_script:v': script_path})] |
| 2378 | + }) |
| 2379 | +
|
| 2380 | + As noted above, a performant alternative is to use an input pipe and |
| 2381 | + feed the filtergraph description directly: |
| 2382 | +
|
| 2383 | + ..codeblock::python |
2364 | 2384 |
|
2365 | | - with fg.as_script_file(self) as f: |
2366 | 2385 | ffmpegio.ffmpegprocess.run( |
2367 | 2386 | { |
2368 | 2387 | 'inputs': [('input.mp4', None)] |
2369 | | - 'outputs': [('output.mp4', {'filter_script:v': f})] |
2370 | | - }, stdin=f) |
| 2388 | + 'outputs': [('output.mp4', {'filter_script:v': 'pipe:0'})] |
| 2389 | + }, |
| 2390 | + input=str(fg)) |
| 2391 | +
|
| 2392 | + Note that `pipe:0` must be used and not the shorthand `'-'` unlike |
| 2393 | + the input url. |
| 2394 | +
|
2371 | 2395 | """ |
2372 | 2396 |
|
2373 | 2397 | # populate the file with filtergraph expression |
2374 | | - temp_file = NamedTemporaryFile("w+t", delete=False) |
| 2398 | + temp_file = NamedTemporaryFile("wt", delete=False) |
2375 | 2399 | temp_file.write(str(self)) |
2376 | | - temp_file.seek(0) |
| 2400 | + temp_file.close() |
| 2401 | + |
| 2402 | + try: |
| 2403 | + # present the file to the caller in the context |
| 2404 | + yield temp_file.name |
2377 | 2405 |
|
2378 | | - # present the file to the caller in the context |
2379 | | - yield temp_file |
| 2406 | + finally: |
| 2407 | + if temp_file: |
| 2408 | + os.remove(temp_file.name) |
2380 | 2409 |
|
2381 | 2410 |
|
2382 | 2411 | # dict: stores filter construction functions |
|
0 commit comments