0
# Execution and Control
1
2
Functions for executing FFmpeg commands synchronously or asynchronously, building command-line arguments, and handling process control with comprehensive error management.
3
4
## Capabilities
5
6
### Synchronous Execution
7
8
Execute FFmpeg commands and wait for completion with comprehensive output capture and error handling.
9
10
```python { .api }
11
def run(stream_spec, cmd: str = 'ffmpeg', capture_stdout: bool = False, capture_stderr: bool = False, input=None, quiet: bool = False, overwrite_output: bool = False) -> tuple:
12
"""
13
Invoke FFmpeg for the supplied node graph and wait for completion.
14
15
Parameters:
16
- stream_spec: Stream or stream specification to execute
17
- cmd: str, FFmpeg command path (default: 'ffmpeg')
18
- capture_stdout: bool, capture stdout for pipe: outputs
19
- capture_stderr: bool, capture stderr for debugging
20
- input: bytes, data to send to stdin for pipe: inputs
21
- quiet: bool, suppress output (sets capture_stdout and capture_stderr)
22
- overwrite_output: bool, add -y flag to overwrite existing files
23
24
Returns:
25
tuple: (stdout_data, stderr_data) as bytes objects
26
27
Raises:
28
ffmpeg.Error: if FFmpeg returns non-zero exit code
29
"""
30
```
31
32
**Usage Example:**
33
```python
34
import ffmpeg
35
36
# Simple execution
37
stream = ffmpeg.input('input.mp4').hflip().output('output.mp4')
38
ffmpeg.run(stream)
39
40
# Execution with output capture
41
try:
42
stdout, stderr = ffmpeg.run(
43
stream,
44
capture_stdout=True,
45
capture_stderr=True
46
)
47
print("Command succeeded")
48
except ffmpeg.Error as e:
49
print(f"Command failed: {e}")
50
print(f"stderr: {e.stderr.decode()}")
51
52
# Quiet execution (suppress all output)
53
ffmpeg.run(stream, quiet=True, overwrite_output=True)
54
```
55
56
### Asynchronous Execution
57
58
Start FFmpeg processes without waiting for completion, enabling real-time processing and pipeline control.
59
60
```python { .api }
61
def run_async(stream_spec, cmd: str = 'ffmpeg', pipe_stdin: bool = False, pipe_stdout: bool = False, pipe_stderr: bool = False, quiet: bool = False, overwrite_output: bool = False):
62
"""
63
Asynchronously invoke FFmpeg for the supplied node graph.
64
65
Parameters:
66
- stream_spec: Stream or stream specification to execute
67
- cmd: str, FFmpeg command path (default: 'ffmpeg')
68
- pipe_stdin: bool, connect pipe to subprocess stdin
69
- pipe_stdout: bool, connect pipe to subprocess stdout
70
- pipe_stderr: bool, connect pipe to subprocess stderr
71
- quiet: bool, shorthand for pipe_stdout and pipe_stderr
72
- overwrite_output: bool, add -y flag to overwrite existing files
73
74
Returns:
75
subprocess.Popen: Process object for the running FFmpeg command
76
"""
77
```
78
79
**Usage Example:**
80
```python
81
import subprocess
82
83
# Basic async execution
84
stream = ffmpeg.input('input.mp4').output('output.mp4')
85
process = ffmpeg.run_async(stream)
86
process.wait() # Wait for completion
87
88
# Streaming input and output
89
input_stream = ffmpeg.input('pipe:', format='rawvideo', pix_fmt='rgb24', s='640x480')
90
output_stream = ffmpeg.output(input_stream, 'pipe:', format='rawvideo', pix_fmt='yuv420p')
91
92
process = ffmpeg.run_async(
93
output_stream,
94
pipe_stdin=True,
95
pipe_stdout=True
96
)
97
98
# Send data and receive results
99
stdout, stderr = process.communicate(input=raw_video_data)
100
101
# Real-time processing example
102
process1 = ffmpeg.run_async(
103
ffmpeg.input('input.mp4').output('pipe:', format='rawvideo'),
104
pipe_stdout=True
105
)
106
107
process2 = ffmpeg.run_async(
108
ffmpeg.input('pipe:', format='rawvideo', s='1920x1080').output('processed.mp4'),
109
pipe_stdin=True
110
)
111
112
# Stream data between processes
113
while True:
114
chunk = process1.stdout.read(1920 * 1080 * 3) # One frame
115
if not chunk:
116
break
117
process2.stdin.write(chunk)
118
119
process2.stdin.close()
120
process1.wait()
121
process2.wait()
122
```
123
124
### Command Building
125
126
Generate FFmpeg command-line arguments for debugging or manual execution.
127
128
```python { .api }
129
def get_args(stream_spec, overwrite_output: bool = False) -> list:
130
"""
131
Build command-line arguments for FFmpeg execution.
132
133
Parameters:
134
- stream_spec: Stream or stream specification
135
- overwrite_output: bool, add -y flag to overwrite files
136
137
Returns:
138
list: Command-line arguments (without 'ffmpeg' command)
139
"""
140
141
def compile(stream_spec, cmd: str = 'ffmpeg', overwrite_output: bool = False) -> list:
142
"""
143
Build complete command line for invoking FFmpeg.
144
145
Parameters:
146
- stream_spec: Stream or stream specification
147
- cmd: str/list, FFmpeg command (default: 'ffmpeg')
148
- overwrite_output: bool, add -y flag to overwrite files
149
150
Returns:
151
list: Complete command including FFmpeg executable
152
"""
153
```
154
155
**Usage Example:**
156
```python
157
# Build arguments for debugging
158
stream = ffmpeg.input('input.mp4').hflip().output('output.mp4')
159
args = ffmpeg.get_args(stream)
160
print(' '.join(args))
161
# Output: -i input.mp4 -filter_complex [0]hflip[s0] -map [s0] output.mp4
162
163
# Build complete command
164
cmd = ffmpeg.compile(stream, overwrite_output=True)
165
print(' '.join(cmd))
166
# Output: ffmpeg -i input.mp4 -filter_complex [0]hflip[s0] -map [s0] -y output.mp4
167
168
# Use custom FFmpeg path
169
custom_cmd = ffmpeg.compile(stream, cmd='/usr/local/bin/ffmpeg')
170
171
# Execute manually with subprocess
172
import subprocess
173
result = subprocess.run(custom_cmd, capture_output=True)
174
```
175
176
## Error Handling
177
178
```python { .api }
179
class Error(Exception):
180
"""
181
Exception raised when FFmpeg returns non-zero exit code.
182
183
Attributes:
184
- stdout: bytes, captured stdout data
185
- stderr: bytes, captured stderr data
186
"""
187
188
def __init__(self, cmd: str, stdout: bytes, stderr: bytes):
189
"""
190
Initialize error with command information.
191
192
Parameters:
193
- cmd: str, command that failed
194
- stdout: bytes, stdout data
195
- stderr: bytes, stderr data
196
"""
197
```
198
199
**Error Handling Patterns:**
200
```python
201
try:
202
ffmpeg.run(stream)
203
except ffmpeg.Error as e:
204
print(f"FFmpeg failed with error: {e}")
205
206
# Decode error messages
207
if e.stderr:
208
error_msg = e.stderr.decode('utf-8')
209
print(f"Error details: {error_msg}")
210
211
# Check for specific error conditions
212
if b'No such file or directory' in e.stderr:
213
print("Input file not found")
214
elif b'Invalid data found' in e.stderr:
215
print("Corrupt or invalid input file")
216
elif b'Permission denied' in e.stderr:
217
print("Insufficient permissions")
218
```
219
220
## Advanced Execution Patterns
221
222
### Progress Monitoring
223
224
```python
225
# Monitor progress with global args
226
stream = (
227
ffmpeg
228
.input('large_video.mp4')
229
.output('compressed.mp4', vcodec='libx264')
230
.global_args('-progress', 'progress.txt', '-nostats')
231
)
232
233
process = ffmpeg.run_async(stream)
234
235
# Read progress in real-time
236
import time
237
while process.poll() is None:
238
try:
239
with open('progress.txt', 'r') as f:
240
progress_data = f.read()
241
print(f"Progress: {progress_data}")
242
except FileNotFoundError:
243
pass
244
time.sleep(1)
245
```
246
247
### Resource Management
248
249
```python
250
import contextlib
251
252
@contextlib.contextmanager
253
def ffmpeg_process(stream_spec, **kwargs):
254
"""Context manager for FFmpeg processes."""
255
process = ffmpeg.run_async(stream_spec, **kwargs)
256
try:
257
yield process
258
finally:
259
if process.poll() is None: # Still running
260
process.terminate()
261
process.wait()
262
263
# Usage
264
with ffmpeg_process(stream, pipe_stdout=True) as process:
265
output_data = process.stdout.read()
266
# Process automatically terminated if exception occurs
267
```
268
269
### Batch Processing
270
271
```python
272
def process_videos(input_files, output_dir):
273
"""Process multiple videos in parallel."""
274
processes = []
275
276
for input_file in input_files:
277
output_file = f"{output_dir}/{input_file.stem}_processed.mp4"
278
stream = ffmpeg.input(str(input_file)).hflip().output(str(output_file))
279
process = ffmpeg.run_async(stream)
280
processes.append((process, input_file))
281
282
# Wait for all to complete
283
for process, input_file in processes:
284
try:
285
process.wait()
286
print(f"Completed: {input_file}")
287
except Exception as e:
288
print(f"Failed: {input_file} - {e}")
289
```