Video editing from Python, without FFmpeg on your machine.
Trim, resize, compress, convert, caption and transcribe by calling one HTTP endpoint per operation. Parameters are validated before anything renders, so a bad call fails as a typed error rather than a broken encode.
What running FFmpeg from Python usually costs
- A binary to install on every machine that runs the code, including the container that gets rebuilt at three in the morning.
- subprocess with a list of arguments you build by hand, where a wrong flag surfaces as a non-zero exit code and a wall of stderr.
- The encode happens in your process, so a long render holds a worker and the memory that goes with it.
Trim a clip and wait for the file
Python
import os, time, requests
KINOPIPE = "https://kinopipe.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['KINOPIPE_API_KEY']}"}
def run(tool, inputs, options=None):
started = requests.post(
f"{KINOPIPE}/tools/{tool}",
headers=HEADERS,
json={"inputs": inputs, "options": options or {}},
timeout=30,
)
started.raise_for_status()
job_id = started.json()["job"]["id"]
while True:
job = requests.get(f"{KINOPIPE}/jobs/{job_id}", headers=HEADERS, timeout=30).json()
if job["job"]["status"] in ("succeeded", "failed"):
return job
time.sleep(2)
job = run(
"trim-video",
[{"id": "main", "url": "https://example.com/interview.mp4"}],
{"start": 12, "end": 48},
)
if job["job"]["status"] == "failed":
raise RuntimeError((job["job"].get("error") or {}).get("message", "the job did not finish"))
print(job["result"]["output"]["downloadUrl"])- The tool slug is the only thing that changes between operations: swap trim-video for resize-video, compress-video or add-subtitles-to-video and keep the same function.
- Send an Idempotency-Key header when you retry, and the retry returns the original job instead of paying for a second render.
- For a file on disk, POST to /api/v1/uploads with the filename, content type and byte size, submit the file to the URL it returns, then use the media URL as the input.
FAQ
ffmpeg-python builds a command line for a binary you install and run yourself. Here the parameters are validated server-side before anything renders, and your process never holds an encode.
Only if you want it to. The call returns a job id immediately; the polling loop above is a convenience, and a webhook is the alternative when you would rather not wait.
Yes. POST /api/v1/jobs takes a recipe of bounded operations and compiles them into a single FFmpeg pass, so trim plus resize plus watermark is one decode and one encode.