ffmpeg-python-helper 0.1.0__tar.gz → 3.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ffmpeg_python_helper-3.0.0/PKG-INFO +358 -0
- ffmpeg_python_helper-3.0.0/README.md +349 -0
- {ffmpeg_python_helper-0.1.0 → ffmpeg_python_helper-3.0.0}/pyproject.toml +2 -2
- {ffmpeg_python_helper-0.1.0 → ffmpeg_python_helper-3.0.0}/pyproject.toml.orig +2 -2
- ffmpeg_python_helper-3.0.0/src/ffmpeg_python_helper/__init__.py +67 -0
- ffmpeg_python_helper-3.0.0/src/ffmpeg_python_helper/ffmpeg_api.py +526 -0
- ffmpeg_python_helper-3.0.0/src/ffmpeg_python_helper/pipe_helper.py +114 -0
- ffmpeg_python_helper-0.1.0/PKG-INFO +0 -9
- ffmpeg_python_helper-0.1.0/README.md +0 -0
- ffmpeg_python_helper-0.1.0/src/ffmpeg_python_helper/__init__.py +0 -9
- ffmpeg_python_helper-0.1.0/src/ffmpeg_python_helper/_bundled/ffmpeg.exe +0 -4
- ffmpeg_python_helper-0.1.0/src/ffmpeg_python_helper/ffmpeg_api.py +0 -121
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: ffmpeg-python-helper
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: A Python wrapper for FFMPEG that provides a simple, intuitive API for common video processing tasks including format conversion, GIF creation, and video trimming.
|
|
5
|
+
Author: marjon
|
|
6
|
+
Author-email: marjon <marjongodito@gmanmi.com>
|
|
7
|
+
Requires-Python: >=3.14
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# FFMPEG Python Helper
|
|
11
|
+
|
|
12
|
+
A Python wrapper for FFMPEG that provides a simple, intuitive API for common video processing tasks.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- 🔧 **Easy FFMPEG Integration** - Automatically detects FFMPEG installation
|
|
17
|
+
- 🎥 **Video Processing** - Reformat videos between formats
|
|
18
|
+
- 🎞️ **GIF Creation** - Convert videos to optimized GIFs with customizable settings
|
|
19
|
+
- 🎵 **Audio Extraction** - Extract audio tracks from videos without re-encoding
|
|
20
|
+
- 🧠 **In-Memory Processing** - Process video/audio data directly from bytes without temporary files
|
|
21
|
+
- ✂️ **Video Trimming** - Trim videos with precise start time and duration control
|
|
22
|
+
- 🐍 **Pythonic API** - Clean, object-oriented interface with proper error handling
|
|
23
|
+
- 📁 **File Validation** - Automatic input file existence checking
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
### Prerequisites
|
|
28
|
+
- Python 3.14 or higher
|
|
29
|
+
- FFMPEG installed and available in your system PATH
|
|
30
|
+
|
|
31
|
+
### Install FFMPEG Python Helper
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install ffmpeg-python-helper
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or install from source:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/yourusername/ffmpeg-python-helper.git
|
|
41
|
+
cd ffmpeg-python-helper
|
|
42
|
+
pip install -e .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from ffmpeg_python_helper import FFMPEG
|
|
49
|
+
|
|
50
|
+
# Initialize the FFMPEG wrapper
|
|
51
|
+
ffmpeg = FFMPEG()
|
|
52
|
+
|
|
53
|
+
# Check if FFMPEG is available
|
|
54
|
+
print(f"FFMPEG executable found at: {ffmpeg.executable}")
|
|
55
|
+
|
|
56
|
+
# Convert a video file
|
|
57
|
+
output = ffmpeg.reformat("input.mp4", "output.avi")
|
|
58
|
+
print(output.decode())
|
|
59
|
+
|
|
60
|
+
# Create a GIF from video
|
|
61
|
+
ffmpeg.gif("video.mp4", "animation.gif", fps=15, scale=480)
|
|
62
|
+
|
|
63
|
+
# Trim a video
|
|
64
|
+
ffmpeg.trim("video.mp4", "short_clip.mp4", start=10.5, duration=5.0)
|
|
65
|
+
|
|
66
|
+
# Extract audio from video
|
|
67
|
+
ffmpeg.extract_audio("video.mp4", "audio.m4a")
|
|
68
|
+
|
|
69
|
+
# Create GIF from in-memory video data
|
|
70
|
+
with open("video.mp4", "rb") as f:
|
|
71
|
+
video_data = f.read()
|
|
72
|
+
gif_data = ffmpeg.gifs(video_data, fps=15, scale=480)
|
|
73
|
+
with open("memory.gif", "wb") as f:
|
|
74
|
+
f.write(gif_data)
|
|
75
|
+
|
|
76
|
+
# Trim video in memory
|
|
77
|
+
trimmed_data = ffmpeg.trims(video_data, start=0, duration=30)
|
|
78
|
+
with open("trimmed.mp4", "wb") as f:
|
|
79
|
+
f.write(trimmed_data)
|
|
80
|
+
|
|
81
|
+
# Extract audio in memory
|
|
82
|
+
audio_data = ffmpeg.extract_audios(video_data, output_format="m4a")
|
|
83
|
+
with open("audio.m4a", "wb") as f:
|
|
84
|
+
f.write(audio_data)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## API Reference
|
|
88
|
+
|
|
89
|
+
### `FFMPEG` Class
|
|
90
|
+
|
|
91
|
+
The main class that wraps FFMPEG functionality.
|
|
92
|
+
|
|
93
|
+
#### Constructor
|
|
94
|
+
```python
|
|
95
|
+
FFMPEG()
|
|
96
|
+
```
|
|
97
|
+
Creates a new FFMPEG instance. Automatically searches for FFMPEG in the system PATH.
|
|
98
|
+
- **Raises**: `FileNotFoundError` if FFMPEG is not found in PATH
|
|
99
|
+
|
|
100
|
+
#### Properties
|
|
101
|
+
- `executable` (str): The path to the FFMPEG executable found in the system
|
|
102
|
+
|
|
103
|
+
#### Class Methods
|
|
104
|
+
```python
|
|
105
|
+
@classmethod
|
|
106
|
+
def api(cls) -> "FFMPEG"
|
|
107
|
+
```
|
|
108
|
+
Factory method that returns a new FFMPEG instance.
|
|
109
|
+
- **Returns**: `FFMPEG` instance
|
|
110
|
+
|
|
111
|
+
#### Instance Methods
|
|
112
|
+
|
|
113
|
+
##### `execute(*args: str, input_data: bytes | None = None) -> tuple[bytes, bytes]`
|
|
114
|
+
Execute raw FFMPEG commands with the given arguments.
|
|
115
|
+
|
|
116
|
+
**Parameters:**
|
|
117
|
+
- `*args` (str): FFMPEG command-line arguments
|
|
118
|
+
- `input_data` (bytes | None, optional): Optional bytes to send to FFMPEG's stdin
|
|
119
|
+
|
|
120
|
+
**Returns:**
|
|
121
|
+
- `tuple[bytes, bytes]`: A tuple containing (stdout, stderr) as bytes
|
|
122
|
+
|
|
123
|
+
**Raises:**
|
|
124
|
+
- `FileNotFoundError`: If FFMPEG executable is not found
|
|
125
|
+
- `RuntimeError`: If FFMPEG command returns a non-zero exit code
|
|
126
|
+
|
|
127
|
+
**Example:**
|
|
128
|
+
```python
|
|
129
|
+
stdout, stderr = ffmpeg.execute("-version")
|
|
130
|
+
print(stdout.decode())
|
|
131
|
+
|
|
132
|
+
# Process data from memory
|
|
133
|
+
video_data = b"...video bytes..."
|
|
134
|
+
stdout, stderr = ffmpeg.execute("-i", "pipe:0", "-f", "null", "-", input_data=video_data)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
##### `reformat(input_file: str, output_file: str) -> bytes`
|
|
138
|
+
Convert a video file from one format to another.
|
|
139
|
+
|
|
140
|
+
**Parameters:**
|
|
141
|
+
- `input_file` (str): Path to the input video file
|
|
142
|
+
- `output_file` (str): Path for the output video file
|
|
143
|
+
|
|
144
|
+
**Returns:**
|
|
145
|
+
- `bytes`: FFMPEG output (stdout or stderr) as bytes
|
|
146
|
+
|
|
147
|
+
**Raises:**
|
|
148
|
+
- `FileNotFoundError`: If input file doesn't exist
|
|
149
|
+
|
|
150
|
+
**Example:**
|
|
151
|
+
```python
|
|
152
|
+
output = ffmpeg.reformat("input.mov", "output.mp4")
|
|
153
|
+
print(output.decode())
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
##### `gif(input_file: str, output_file: str, fps: int = 10, scale: int = 320) -> bytes`
|
|
157
|
+
Convert a video file to an optimized GIF.
|
|
158
|
+
|
|
159
|
+
**Parameters:**
|
|
160
|
+
- `input_file` (str): Path to the input video file
|
|
161
|
+
- `output_file` (str): Path for the output GIF file
|
|
162
|
+
- `fps` (int, optional): Frames per second for the GIF (default: 10)
|
|
163
|
+
- `scale` (int, optional): Width of the GIF in pixels, height is auto-scaled (default: 320)
|
|
164
|
+
|
|
165
|
+
**Returns:**
|
|
166
|
+
- `bytes`: FFMPEG output (stdout or stderr) as bytes
|
|
167
|
+
|
|
168
|
+
**Raises:**
|
|
169
|
+
- `FileNotFoundError`: If input file doesn't exist
|
|
170
|
+
- `RuntimeError`: If GIF file was not created successfully
|
|
171
|
+
|
|
172
|
+
**Example:**
|
|
173
|
+
```python
|
|
174
|
+
output = ffmpeg.gif("video.mp4", "output.gif", fps=15, scale=640)
|
|
175
|
+
print(output.decode())
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
##### `gifs(input_byte: bytes, fps: int = 10, scale: int = 320) -> bytes`
|
|
179
|
+
Convert video data from bytes to an optimized GIF (in-memory processing).
|
|
180
|
+
|
|
181
|
+
**Parameters:**
|
|
182
|
+
- `input_byte` (bytes): Video data as bytes to convert to GIF
|
|
183
|
+
- `fps` (int, optional): Frames per second for the GIF (default: 10)
|
|
184
|
+
- `scale` (int, optional): Width of the GIF in pixels, height is auto-scaled (default: 320)
|
|
185
|
+
|
|
186
|
+
**Returns:**
|
|
187
|
+
- `bytes`: The generated GIF data as bytes
|
|
188
|
+
|
|
189
|
+
**Raises:**
|
|
190
|
+
- `RuntimeError`: If GIF conversion fails
|
|
191
|
+
|
|
192
|
+
**Example:**
|
|
193
|
+
```python
|
|
194
|
+
# Read video data from a file
|
|
195
|
+
with open("video.mp4", "rb") as f:
|
|
196
|
+
video_data = f.read()
|
|
197
|
+
|
|
198
|
+
# Convert to GIF in memory
|
|
199
|
+
gif_data = ffmpeg.gifs(video_data, fps=15, scale=480)
|
|
200
|
+
|
|
201
|
+
# Save the GIF
|
|
202
|
+
with open("output.gif", "wb") as f:
|
|
203
|
+
f.write(gif_data)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
##### `trim(input_file: str, output_file: str, start: float = 0, duration: float | None = None) -> bytes`
|
|
207
|
+
Trim a video file.
|
|
208
|
+
|
|
209
|
+
**Parameters:**
|
|
210
|
+
- `input_file` (str): Path to the input video file
|
|
211
|
+
- `output_file` (str): Path for the output trimmed video
|
|
212
|
+
- `start` (float, optional): Start time in seconds (default: 0)
|
|
213
|
+
- `duration` (float | None, optional): Duration in seconds, or None for remaining video (default: None)
|
|
214
|
+
|
|
215
|
+
**Returns:**
|
|
216
|
+
- `bytes`: FFMPEG output (stdout or stderr) as bytes
|
|
217
|
+
|
|
218
|
+
**Raises:**
|
|
219
|
+
- `FileNotFoundError`: If input file doesn't exist
|
|
220
|
+
- `ValueError`: If start is negative or duration is non-positive
|
|
221
|
+
- `RuntimeError`: If trimmed video was not created successfully
|
|
222
|
+
|
|
223
|
+
**Example:**
|
|
224
|
+
```python
|
|
225
|
+
# Trim from 5 seconds to 10 seconds (5-second clip)
|
|
226
|
+
output = ffmpeg.trim("video.mp4", "clip.mp4", start=5, duration=5)
|
|
227
|
+
print(output.decode())
|
|
228
|
+
|
|
229
|
+
# Trim from 10 seconds to the end of video
|
|
230
|
+
output = ffmpeg.trim("video.mp4", "ending.mp4", start=10)
|
|
231
|
+
print(output.decode())
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Advanced Usage
|
|
235
|
+
|
|
236
|
+
### Custom FFMPEG Commands
|
|
237
|
+
For operations not covered by the built-in methods, use the `execute` method:
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
# Extract audio from video
|
|
241
|
+
ffmpeg.execute("-i", "video.mp4", "-q:a", "0", "-map", "a", "audio.mp3")
|
|
242
|
+
|
|
243
|
+
# Add watermark to video
|
|
244
|
+
ffmpeg.execute("-i", "video.mp4", "-i", "watermark.png",
|
|
245
|
+
"-filter_complex", "overlay=10:10", "output.mp4")
|
|
246
|
+
|
|
247
|
+
# Change video bitrate
|
|
248
|
+
ffmpeg.execute("-i", "input.mp4", "-b:v", "1M", "output.mp4")
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Error Handling
|
|
252
|
+
```python
|
|
253
|
+
from ffmpeg_python_helper import FFMPEG
|
|
254
|
+
import sys
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
ffmpeg = FFMPEG()
|
|
258
|
+
ffmpeg.gif("video.mp4", "output.gif")
|
|
259
|
+
except FileNotFoundError as e:
|
|
260
|
+
print(f"FFMPEG not found: {e}", file=sys.stderr)
|
|
261
|
+
sys.exit(1)
|
|
262
|
+
except RuntimeError as e:
|
|
263
|
+
print(f"Processing failed: {e}", file=sys.stderr)
|
|
264
|
+
sys.exit(1)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Common Use Cases
|
|
268
|
+
|
|
269
|
+
### Batch Processing
|
|
270
|
+
```python
|
|
271
|
+
import os
|
|
272
|
+
from ffmpeg_python_helper import FFMPEG
|
|
273
|
+
|
|
274
|
+
ffmpeg = FFMPEG()
|
|
275
|
+
videos = ["video1.mp4", "video2.mp4", "video3.mp4"]
|
|
276
|
+
|
|
277
|
+
for video in videos:
|
|
278
|
+
if os.path.exists(video):
|
|
279
|
+
base_name = os.path.splitext(video)[0]
|
|
280
|
+
ffmpeg.gif(video, f"{base_name}.gif", fps=12, scale=400)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Video Compilation
|
|
284
|
+
```python
|
|
285
|
+
from ffmpeg_python_helper import FFMPEG
|
|
286
|
+
|
|
287
|
+
ffmpeg = FFMPEG()
|
|
288
|
+
|
|
289
|
+
# Trim interesting parts
|
|
290
|
+
ffmpeg.trim("concert.mp4", "intro.mp4", start=0, duration=30)
|
|
291
|
+
ffmpeg.trim("concert.mp4", "chorus.mp4", start=120, duration=45)
|
|
292
|
+
ffmpeg.trim("concert.mp4", "finale.mp4", start=300, duration=60)
|
|
293
|
+
|
|
294
|
+
# Later, use FFMPEG to concatenate trimmed parts
|
|
295
|
+
ffmpeg.execute("-f", "concat", "-safe", "0", "-i", "parts.txt", "highlight_reel.mp4")
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Troubleshooting
|
|
299
|
+
|
|
300
|
+
### FFMPEG Not Found
|
|
301
|
+
If you get `FileNotFoundError` when creating an FFMPEG instance:
|
|
302
|
+
|
|
303
|
+
1. **Install FFMPEG**:
|
|
304
|
+
- **Windows**: Download from [ffmpeg.org](https://ffmpeg.org/download.html)
|
|
305
|
+
- **macOS**: `brew install ffmpeg`
|
|
306
|
+
- **Linux**: `sudo apt install ffmpeg` (Ubuntu/Debian) or `sudo yum install ffmpeg` (Fedora/RHEL)
|
|
307
|
+
|
|
308
|
+
2. **Add to PATH**:
|
|
309
|
+
- Ensure FFMPEG is in your system PATH
|
|
310
|
+
- Test with `ffmpeg -version` in your terminal
|
|
311
|
+
|
|
312
|
+
### File Not Found Errors
|
|
313
|
+
- Ensure input file paths are correct and files exist
|
|
314
|
+
- Use absolute paths if working with files in different directories
|
|
315
|
+
- Check file permissions
|
|
316
|
+
|
|
317
|
+
### GIF Creation Issues
|
|
318
|
+
- Lower FPS or scale if GIF file is too large
|
|
319
|
+
- Ensure input video has sufficient quality
|
|
320
|
+
- Check available disk space
|
|
321
|
+
|
|
322
|
+
## Development
|
|
323
|
+
|
|
324
|
+
### Running Tests
|
|
325
|
+
```bash
|
|
326
|
+
python -m pytest tests/
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Building Documentation
|
|
330
|
+
```bash
|
|
331
|
+
# Install documentation dependencies
|
|
332
|
+
pip install pdoc3
|
|
333
|
+
|
|
334
|
+
# Generate API documentation
|
|
335
|
+
pdoc --html ffmpeg_python_helper --output-dir docs
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Contributing
|
|
339
|
+
1. Fork the repository
|
|
340
|
+
2. Create a feature branch
|
|
341
|
+
3. Add tests for your changes
|
|
342
|
+
4. Ensure all tests pass
|
|
343
|
+
5. Submit a pull request
|
|
344
|
+
|
|
345
|
+
## License
|
|
346
|
+
|
|
347
|
+
MIT License - see LICENSE file for details
|
|
348
|
+
|
|
349
|
+
## Support
|
|
350
|
+
|
|
351
|
+
- **Issues**: [GitHub Issues](https://github.com/yourusername/ffmpeg-python-helper/issues)
|
|
352
|
+
- **Documentation**: [ReadTheDocs](https://ffmpeg-python-helper.readthedocs.io)
|
|
353
|
+
- **Email**: marjongodito@gmanmi.com
|
|
354
|
+
|
|
355
|
+
## Acknowledgments
|
|
356
|
+
|
|
357
|
+
- FFMPEG team for the amazing multimedia framework
|
|
358
|
+
- Python community for excellent tooling and libraries
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# FFMPEG Python Helper
|
|
2
|
+
|
|
3
|
+
A Python wrapper for FFMPEG that provides a simple, intuitive API for common video processing tasks.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔧 **Easy FFMPEG Integration** - Automatically detects FFMPEG installation
|
|
8
|
+
- 🎥 **Video Processing** - Reformat videos between formats
|
|
9
|
+
- 🎞️ **GIF Creation** - Convert videos to optimized GIFs with customizable settings
|
|
10
|
+
- 🎵 **Audio Extraction** - Extract audio tracks from videos without re-encoding
|
|
11
|
+
- 🧠 **In-Memory Processing** - Process video/audio data directly from bytes without temporary files
|
|
12
|
+
- ✂️ **Video Trimming** - Trim videos with precise start time and duration control
|
|
13
|
+
- 🐍 **Pythonic API** - Clean, object-oriented interface with proper error handling
|
|
14
|
+
- 📁 **File Validation** - Automatic input file existence checking
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### Prerequisites
|
|
19
|
+
- Python 3.14 or higher
|
|
20
|
+
- FFMPEG installed and available in your system PATH
|
|
21
|
+
|
|
22
|
+
### Install FFMPEG Python Helper
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install ffmpeg-python-helper
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or install from source:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
git clone https://github.com/yourusername/ffmpeg-python-helper.git
|
|
32
|
+
cd ffmpeg-python-helper
|
|
33
|
+
pip install -e .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from ffmpeg_python_helper import FFMPEG
|
|
40
|
+
|
|
41
|
+
# Initialize the FFMPEG wrapper
|
|
42
|
+
ffmpeg = FFMPEG()
|
|
43
|
+
|
|
44
|
+
# Check if FFMPEG is available
|
|
45
|
+
print(f"FFMPEG executable found at: {ffmpeg.executable}")
|
|
46
|
+
|
|
47
|
+
# Convert a video file
|
|
48
|
+
output = ffmpeg.reformat("input.mp4", "output.avi")
|
|
49
|
+
print(output.decode())
|
|
50
|
+
|
|
51
|
+
# Create a GIF from video
|
|
52
|
+
ffmpeg.gif("video.mp4", "animation.gif", fps=15, scale=480)
|
|
53
|
+
|
|
54
|
+
# Trim a video
|
|
55
|
+
ffmpeg.trim("video.mp4", "short_clip.mp4", start=10.5, duration=5.0)
|
|
56
|
+
|
|
57
|
+
# Extract audio from video
|
|
58
|
+
ffmpeg.extract_audio("video.mp4", "audio.m4a")
|
|
59
|
+
|
|
60
|
+
# Create GIF from in-memory video data
|
|
61
|
+
with open("video.mp4", "rb") as f:
|
|
62
|
+
video_data = f.read()
|
|
63
|
+
gif_data = ffmpeg.gifs(video_data, fps=15, scale=480)
|
|
64
|
+
with open("memory.gif", "wb") as f:
|
|
65
|
+
f.write(gif_data)
|
|
66
|
+
|
|
67
|
+
# Trim video in memory
|
|
68
|
+
trimmed_data = ffmpeg.trims(video_data, start=0, duration=30)
|
|
69
|
+
with open("trimmed.mp4", "wb") as f:
|
|
70
|
+
f.write(trimmed_data)
|
|
71
|
+
|
|
72
|
+
# Extract audio in memory
|
|
73
|
+
audio_data = ffmpeg.extract_audios(video_data, output_format="m4a")
|
|
74
|
+
with open("audio.m4a", "wb") as f:
|
|
75
|
+
f.write(audio_data)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## API Reference
|
|
79
|
+
|
|
80
|
+
### `FFMPEG` Class
|
|
81
|
+
|
|
82
|
+
The main class that wraps FFMPEG functionality.
|
|
83
|
+
|
|
84
|
+
#### Constructor
|
|
85
|
+
```python
|
|
86
|
+
FFMPEG()
|
|
87
|
+
```
|
|
88
|
+
Creates a new FFMPEG instance. Automatically searches for FFMPEG in the system PATH.
|
|
89
|
+
- **Raises**: `FileNotFoundError` if FFMPEG is not found in PATH
|
|
90
|
+
|
|
91
|
+
#### Properties
|
|
92
|
+
- `executable` (str): The path to the FFMPEG executable found in the system
|
|
93
|
+
|
|
94
|
+
#### Class Methods
|
|
95
|
+
```python
|
|
96
|
+
@classmethod
|
|
97
|
+
def api(cls) -> "FFMPEG"
|
|
98
|
+
```
|
|
99
|
+
Factory method that returns a new FFMPEG instance.
|
|
100
|
+
- **Returns**: `FFMPEG` instance
|
|
101
|
+
|
|
102
|
+
#### Instance Methods
|
|
103
|
+
|
|
104
|
+
##### `execute(*args: str, input_data: bytes | None = None) -> tuple[bytes, bytes]`
|
|
105
|
+
Execute raw FFMPEG commands with the given arguments.
|
|
106
|
+
|
|
107
|
+
**Parameters:**
|
|
108
|
+
- `*args` (str): FFMPEG command-line arguments
|
|
109
|
+
- `input_data` (bytes | None, optional): Optional bytes to send to FFMPEG's stdin
|
|
110
|
+
|
|
111
|
+
**Returns:**
|
|
112
|
+
- `tuple[bytes, bytes]`: A tuple containing (stdout, stderr) as bytes
|
|
113
|
+
|
|
114
|
+
**Raises:**
|
|
115
|
+
- `FileNotFoundError`: If FFMPEG executable is not found
|
|
116
|
+
- `RuntimeError`: If FFMPEG command returns a non-zero exit code
|
|
117
|
+
|
|
118
|
+
**Example:**
|
|
119
|
+
```python
|
|
120
|
+
stdout, stderr = ffmpeg.execute("-version")
|
|
121
|
+
print(stdout.decode())
|
|
122
|
+
|
|
123
|
+
# Process data from memory
|
|
124
|
+
video_data = b"...video bytes..."
|
|
125
|
+
stdout, stderr = ffmpeg.execute("-i", "pipe:0", "-f", "null", "-", input_data=video_data)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
##### `reformat(input_file: str, output_file: str) -> bytes`
|
|
129
|
+
Convert a video file from one format to another.
|
|
130
|
+
|
|
131
|
+
**Parameters:**
|
|
132
|
+
- `input_file` (str): Path to the input video file
|
|
133
|
+
- `output_file` (str): Path for the output video file
|
|
134
|
+
|
|
135
|
+
**Returns:**
|
|
136
|
+
- `bytes`: FFMPEG output (stdout or stderr) as bytes
|
|
137
|
+
|
|
138
|
+
**Raises:**
|
|
139
|
+
- `FileNotFoundError`: If input file doesn't exist
|
|
140
|
+
|
|
141
|
+
**Example:**
|
|
142
|
+
```python
|
|
143
|
+
output = ffmpeg.reformat("input.mov", "output.mp4")
|
|
144
|
+
print(output.decode())
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
##### `gif(input_file: str, output_file: str, fps: int = 10, scale: int = 320) -> bytes`
|
|
148
|
+
Convert a video file to an optimized GIF.
|
|
149
|
+
|
|
150
|
+
**Parameters:**
|
|
151
|
+
- `input_file` (str): Path to the input video file
|
|
152
|
+
- `output_file` (str): Path for the output GIF file
|
|
153
|
+
- `fps` (int, optional): Frames per second for the GIF (default: 10)
|
|
154
|
+
- `scale` (int, optional): Width of the GIF in pixels, height is auto-scaled (default: 320)
|
|
155
|
+
|
|
156
|
+
**Returns:**
|
|
157
|
+
- `bytes`: FFMPEG output (stdout or stderr) as bytes
|
|
158
|
+
|
|
159
|
+
**Raises:**
|
|
160
|
+
- `FileNotFoundError`: If input file doesn't exist
|
|
161
|
+
- `RuntimeError`: If GIF file was not created successfully
|
|
162
|
+
|
|
163
|
+
**Example:**
|
|
164
|
+
```python
|
|
165
|
+
output = ffmpeg.gif("video.mp4", "output.gif", fps=15, scale=640)
|
|
166
|
+
print(output.decode())
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
##### `gifs(input_byte: bytes, fps: int = 10, scale: int = 320) -> bytes`
|
|
170
|
+
Convert video data from bytes to an optimized GIF (in-memory processing).
|
|
171
|
+
|
|
172
|
+
**Parameters:**
|
|
173
|
+
- `input_byte` (bytes): Video data as bytes to convert to GIF
|
|
174
|
+
- `fps` (int, optional): Frames per second for the GIF (default: 10)
|
|
175
|
+
- `scale` (int, optional): Width of the GIF in pixels, height is auto-scaled (default: 320)
|
|
176
|
+
|
|
177
|
+
**Returns:**
|
|
178
|
+
- `bytes`: The generated GIF data as bytes
|
|
179
|
+
|
|
180
|
+
**Raises:**
|
|
181
|
+
- `RuntimeError`: If GIF conversion fails
|
|
182
|
+
|
|
183
|
+
**Example:**
|
|
184
|
+
```python
|
|
185
|
+
# Read video data from a file
|
|
186
|
+
with open("video.mp4", "rb") as f:
|
|
187
|
+
video_data = f.read()
|
|
188
|
+
|
|
189
|
+
# Convert to GIF in memory
|
|
190
|
+
gif_data = ffmpeg.gifs(video_data, fps=15, scale=480)
|
|
191
|
+
|
|
192
|
+
# Save the GIF
|
|
193
|
+
with open("output.gif", "wb") as f:
|
|
194
|
+
f.write(gif_data)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
##### `trim(input_file: str, output_file: str, start: float = 0, duration: float | None = None) -> bytes`
|
|
198
|
+
Trim a video file.
|
|
199
|
+
|
|
200
|
+
**Parameters:**
|
|
201
|
+
- `input_file` (str): Path to the input video file
|
|
202
|
+
- `output_file` (str): Path for the output trimmed video
|
|
203
|
+
- `start` (float, optional): Start time in seconds (default: 0)
|
|
204
|
+
- `duration` (float | None, optional): Duration in seconds, or None for remaining video (default: None)
|
|
205
|
+
|
|
206
|
+
**Returns:**
|
|
207
|
+
- `bytes`: FFMPEG output (stdout or stderr) as bytes
|
|
208
|
+
|
|
209
|
+
**Raises:**
|
|
210
|
+
- `FileNotFoundError`: If input file doesn't exist
|
|
211
|
+
- `ValueError`: If start is negative or duration is non-positive
|
|
212
|
+
- `RuntimeError`: If trimmed video was not created successfully
|
|
213
|
+
|
|
214
|
+
**Example:**
|
|
215
|
+
```python
|
|
216
|
+
# Trim from 5 seconds to 10 seconds (5-second clip)
|
|
217
|
+
output = ffmpeg.trim("video.mp4", "clip.mp4", start=5, duration=5)
|
|
218
|
+
print(output.decode())
|
|
219
|
+
|
|
220
|
+
# Trim from 10 seconds to the end of video
|
|
221
|
+
output = ffmpeg.trim("video.mp4", "ending.mp4", start=10)
|
|
222
|
+
print(output.decode())
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Advanced Usage
|
|
226
|
+
|
|
227
|
+
### Custom FFMPEG Commands
|
|
228
|
+
For operations not covered by the built-in methods, use the `execute` method:
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
# Extract audio from video
|
|
232
|
+
ffmpeg.execute("-i", "video.mp4", "-q:a", "0", "-map", "a", "audio.mp3")
|
|
233
|
+
|
|
234
|
+
# Add watermark to video
|
|
235
|
+
ffmpeg.execute("-i", "video.mp4", "-i", "watermark.png",
|
|
236
|
+
"-filter_complex", "overlay=10:10", "output.mp4")
|
|
237
|
+
|
|
238
|
+
# Change video bitrate
|
|
239
|
+
ffmpeg.execute("-i", "input.mp4", "-b:v", "1M", "output.mp4")
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Error Handling
|
|
243
|
+
```python
|
|
244
|
+
from ffmpeg_python_helper import FFMPEG
|
|
245
|
+
import sys
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
ffmpeg = FFMPEG()
|
|
249
|
+
ffmpeg.gif("video.mp4", "output.gif")
|
|
250
|
+
except FileNotFoundError as e:
|
|
251
|
+
print(f"FFMPEG not found: {e}", file=sys.stderr)
|
|
252
|
+
sys.exit(1)
|
|
253
|
+
except RuntimeError as e:
|
|
254
|
+
print(f"Processing failed: {e}", file=sys.stderr)
|
|
255
|
+
sys.exit(1)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Common Use Cases
|
|
259
|
+
|
|
260
|
+
### Batch Processing
|
|
261
|
+
```python
|
|
262
|
+
import os
|
|
263
|
+
from ffmpeg_python_helper import FFMPEG
|
|
264
|
+
|
|
265
|
+
ffmpeg = FFMPEG()
|
|
266
|
+
videos = ["video1.mp4", "video2.mp4", "video3.mp4"]
|
|
267
|
+
|
|
268
|
+
for video in videos:
|
|
269
|
+
if os.path.exists(video):
|
|
270
|
+
base_name = os.path.splitext(video)[0]
|
|
271
|
+
ffmpeg.gif(video, f"{base_name}.gif", fps=12, scale=400)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Video Compilation
|
|
275
|
+
```python
|
|
276
|
+
from ffmpeg_python_helper import FFMPEG
|
|
277
|
+
|
|
278
|
+
ffmpeg = FFMPEG()
|
|
279
|
+
|
|
280
|
+
# Trim interesting parts
|
|
281
|
+
ffmpeg.trim("concert.mp4", "intro.mp4", start=0, duration=30)
|
|
282
|
+
ffmpeg.trim("concert.mp4", "chorus.mp4", start=120, duration=45)
|
|
283
|
+
ffmpeg.trim("concert.mp4", "finale.mp4", start=300, duration=60)
|
|
284
|
+
|
|
285
|
+
# Later, use FFMPEG to concatenate trimmed parts
|
|
286
|
+
ffmpeg.execute("-f", "concat", "-safe", "0", "-i", "parts.txt", "highlight_reel.mp4")
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Troubleshooting
|
|
290
|
+
|
|
291
|
+
### FFMPEG Not Found
|
|
292
|
+
If you get `FileNotFoundError` when creating an FFMPEG instance:
|
|
293
|
+
|
|
294
|
+
1. **Install FFMPEG**:
|
|
295
|
+
- **Windows**: Download from [ffmpeg.org](https://ffmpeg.org/download.html)
|
|
296
|
+
- **macOS**: `brew install ffmpeg`
|
|
297
|
+
- **Linux**: `sudo apt install ffmpeg` (Ubuntu/Debian) or `sudo yum install ffmpeg` (Fedora/RHEL)
|
|
298
|
+
|
|
299
|
+
2. **Add to PATH**:
|
|
300
|
+
- Ensure FFMPEG is in your system PATH
|
|
301
|
+
- Test with `ffmpeg -version` in your terminal
|
|
302
|
+
|
|
303
|
+
### File Not Found Errors
|
|
304
|
+
- Ensure input file paths are correct and files exist
|
|
305
|
+
- Use absolute paths if working with files in different directories
|
|
306
|
+
- Check file permissions
|
|
307
|
+
|
|
308
|
+
### GIF Creation Issues
|
|
309
|
+
- Lower FPS or scale if GIF file is too large
|
|
310
|
+
- Ensure input video has sufficient quality
|
|
311
|
+
- Check available disk space
|
|
312
|
+
|
|
313
|
+
## Development
|
|
314
|
+
|
|
315
|
+
### Running Tests
|
|
316
|
+
```bash
|
|
317
|
+
python -m pytest tests/
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Building Documentation
|
|
321
|
+
```bash
|
|
322
|
+
# Install documentation dependencies
|
|
323
|
+
pip install pdoc3
|
|
324
|
+
|
|
325
|
+
# Generate API documentation
|
|
326
|
+
pdoc --html ffmpeg_python_helper --output-dir docs
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Contributing
|
|
330
|
+
1. Fork the repository
|
|
331
|
+
2. Create a feature branch
|
|
332
|
+
3. Add tests for your changes
|
|
333
|
+
4. Ensure all tests pass
|
|
334
|
+
5. Submit a pull request
|
|
335
|
+
|
|
336
|
+
## License
|
|
337
|
+
|
|
338
|
+
MIT License - see LICENSE file for details
|
|
339
|
+
|
|
340
|
+
## Support
|
|
341
|
+
|
|
342
|
+
- **Issues**: [GitHub Issues](https://github.com/yourusername/ffmpeg-python-helper/issues)
|
|
343
|
+
- **Documentation**: [ReadTheDocs](https://ffmpeg-python-helper.readthedocs.io)
|
|
344
|
+
- **Email**: marjongodito@gmanmi.com
|
|
345
|
+
|
|
346
|
+
## Acknowledgments
|
|
347
|
+
|
|
348
|
+
- FFMPEG team for the amazing multimedia framework
|
|
349
|
+
- Python community for excellent tooling and libraries
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ffmpeg-python-helper"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "
|
|
3
|
+
version = "3.0.0"
|
|
4
|
+
description = "A Python wrapper for FFMPEG that provides a simple, intuitive API for common video processing tasks including format conversion, GIF creation, and video trimming."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.14"
|
|
7
7
|
dependencies = []
|