Convert Video Formats
Convert between video formats like MP4, WebM, MOV, AVI, and MKV.
Convert Video Formats
Video format conversion is one of the most common FFmpeg operations. Different platforms and devices require different container formats and codecs. RenderIO makes it easy to convert between any formats that FFmpeg supports.
MP4 to WebM (VP9)
WebM with VP9 is the preferred format for web playback. The -crf 30 flag controls quality (lower is better), and -b:v 0 enables constant quality mode.
ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}MOV to MP4 (H.264)
Apple's MOV files are common from iPhone and Final Cut Pro exports. Converting to MP4 with H.264 gives you the widest compatibility across browsers and devices.
ffmpeg -i {{in_video}} -c:v libx264 -c:a aac {{out_video}}AVI to MP4
Legacy AVI files can be modernized to MP4 with the same H.264/AAC encoding.
ffmpeg -i {{in_video}} -c:v libx264 -c:a aac {{out_video}}MKV to MP4 (stream copy)
When both containers support the same codecs, you can copy streams directly without re-encoding. This is nearly instant and preserves the original quality.
ffmpeg -i {{in_video}} -c copy {{out_video}}Stream copy only works when the codecs inside the MKV file are compatible with the MP4 container (e.g., H.264 video and AAC audio). If you get errors, switch to re-encoding with -c:v libx264 -c:a aac.
Full API example
Convert an MP4 file to WebM with VP9 video and Opus audio.
curl -X POST https://renderio.dev/api/v1/run-ffmpeg-command \
-H "Content-Type: application/json" \
-H "X-API-KEY: ffsk_your_api_key_here" \
-d '{
"input_files": {
"in_video": "https://example.com/source.mp4"
},
"output_files": {
"out_video": "converted.webm"
},
"ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}"
}'import requests
response = requests.post(
"https://renderio.dev/api/v1/run-ffmpeg-command",
headers={
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
json={
"input_files": {
"in_video": "https://example.com/source.mp4",
},
"output_files": {
"out_video": "converted.webm",
},
"ffmpeg_command": "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}",
},
)
data = response.json()
print("Command ID:", data["command_id"])interface RunCommandResponse {
command_id: string;
}
const response = await fetch("https://renderio.dev/api/v1/run-ffmpeg-command", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify({
input_files: {
in_video: "https://example.com/source.mp4",
},
output_files: {
out_video: "converted.webm",
},
ffmpeg_command:
"ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}",
}),
});
const { command_id } = (await response.json()) as RunCommandResponse;
console.log("Command ID:", command_id);const response = await fetch("https://renderio.dev/api/v1/run-ffmpeg-command", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": "ffsk_your_api_key_here",
},
body: JSON.stringify({
input_files: {
in_video: "https://example.com/source.mp4",
},
output_files: {
out_video: "converted.webm",
},
ffmpeg_command:
"ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}",
}),
});
const { command_id } = await response.json();
console.log("Command ID:", command_id);<?php
$ch = curl_init("https://renderio.dev/api/v1/run-ffmpeg-command");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Content-Type: application/json",
"X-API-KEY: ffsk_your_api_key_here",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"input_files" => [
"in_video" => "https://example.com/source.mp4",
],
"output_files" => [
"out_video" => "converted.webm",
],
"ffmpeg_command" => "ffmpeg -i {{in_video}} -c:v libvpx-vp9 -crf 30 -b:v 0 -c:a libopus {{out_video}}",
]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo "Command ID: " . $data["command_id"] . "\n";The API returns a command_id immediately. Poll GET /api/v1/commands/:commandId to check when the conversion is complete, then download the output from the storage_url in the response.
Tips and variations
- Container vs. codec: A container (MP4, WebM, MKV) is the file wrapper. A codec (H.264, VP9, AAC) is the compression algorithm inside it. The same codec can live in different containers, and the same container can hold different codecs.
- Codec compatibility: Not every codec works in every container. H.264 + AAC works in MP4 and MKV but not WebM. VP9 + Opus works in WebM and MKV but not MP4.
- Stream copy when possible: If you only need to change the container and the codecs are compatible, use
-c copyto avoid re-encoding. This is faster and lossless. - Quality control: For H.264, use
-crf 23(default) for good quality. Range is 0-51 where lower is better. For VP9,-crf 30with-b:v 0is a good starting point. - Audio codec pairing: Use AAC (
-c:a aac) with MP4, Opus (-c:a libopus) with WebM, and Vorbis (-c:a libvorbis) as a WebM fallback.
Related guides
- Compress Video -- reduce file size with CRF or bitrate targeting
- Batch Processing -- convert multiple files to different formats in parallel
Further reading
- FFmpeg Transcode Video: Complete Codec Conversion Guide -- deep dive into H.265, AV1, VP9, and hardware-accelerated transcoding
- How to Convert MP4 to GIF with FFmpeg -- palette optimization, batch conversion, and GIF alternatives
- FFmpeg Cheat Sheet: 50 Commands -- quick reference for common FFmpeg operations