FFmpy
ffmpy is a simple Python wrapper for FFmpeg, allowing execution of FFmpeg commands from Python. It's designed for straightforward use cases rather than full feature parity with FFmpeg's extensive options. The current version is 1.0.0, released after a significant rewrite, marking an infrequent but active development cadence.
Warnings
- gotcha ffmpy is a wrapper around the FFmpeg executable, not a pure Python implementation. You must have FFmpeg installed on your system and available in your system's PATH for ffmpy to function.
- breaking Version 1.0.0 represents a significant rewrite. Key changes include renaming the main class from `FFMPEG` to `FFmpeg`, and substantial modifications to the constructor signature and method interfaces. Code written for 0.x versions will not work with 1.0.0 without adaptation.
- gotcha FFmpeg options are typically passed as a single string per input/output file in the `inputs` and `outputs` dictionaries. It does not accept a global list or string of options, which is a common mistake for users familiar with `ffmpeg-python` or complex CLI usage.
- gotcha ffmpy is designed as a 'simple' wrapper. It offers a direct way to run FFmpeg commands but does not aim to expose all of FFmpeg's vast feature set or provide deep programmatic control over every parameter like more complex wrappers (e.g., `ffmpeg-python`).
Install
-
pip install ffmpy
Imports
- FFmpeg
from ffmpy import FFmpeg
Quickstart
import os
import struct
from ffmpy import FFmpeg, FFExecutableNotFoundError, FFRuntimeError
dummy_input_path = "dummy_input.wav"
dummy_output_path = "dummy_output.mp3"
try:
# Create a dummy 1-second 8kHz mono 8-bit silent WAV file
# RIFF header
chunk_id = b'RIFF'
chunk_size = 36 + 8000 # Header (36) + data (8000 samples * 1 byte/sample)
format_str = b'WAVE'
# FMT sub-chunk
subchunk1_id = b'fmt '
subchunk1_size = 16
audio_format = 1 # PCM
num_channels = 1 # Mono
sample_rate = 8000
byte_rate = sample_rate * num_channels * 1 # 8000 * 1 * 1
block_align = num_channels * 1 # 1 * 1
bits_per_sample = 8
# DATA sub-chunk
subchunk2_id = b'data'
subchunk2_size = 8000 # 1 second of 8-bit 8kHz mono
with open(dummy_input_path, 'wb') as f:
f.write(chunk_id)
f.write(struct.pack('<I', chunk_size))
f.write(format_str)
f.write(subchunk1_id)
f.write(struct.pack('<I', subchunk1_size))
f.write(struct.pack('<H', audio_format))
f.write(struct.pack('<H', num_channels))
f.write(struct.pack('<I', sample_rate))
f.write(struct.pack('<I', byte_rate))
f.write(struct.pack('<H', block_align))
f.write(struct.pack('<H', bits_per_sample))
f.write(subchunk2_id)
f.write(struct.pack('<I', subchunk2_size))
f.write(b'\x80' * subchunk2_size) # 8-bit unsigned silence is 0x80 (128)
ff = FFmpeg(
inputs={dummy_input_path: None},
outputs={dummy_output_path: '-codec:a libmp3lame -q:a 2'}
)
print(f"Executing FFmpeg command: {ff.cmd}")
ff.run()
print(f"Successfully converted '{dummy_input_path}' to '{dummy_output_path}'")
except FFExecutableNotFoundError:
print("Error: FFmpeg executable not found. Please ensure FFmpeg is installed and in your system's PATH.")
except FFRuntimeError as e:
print(f"Error during FFmpeg execution. Exit code: {e.exit_code}")
print(f"FFmpeg stderr: {e.stderr.decode('utf-8')}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
if os.path.exists(dummy_input_path):
os.remove(dummy_input_path)
if os.path.exists(dummy_output_path):
os.remove(dummy_output_path)
print("Cleaned up dummy files.")