DocsGuides
Compress and convert
Re-encode a video to a smaller file or another format with JSON: codec, quality, container and frame rate.
Re-encode a video to a smaller file, another codec or another container. You choose the codec and a quality; the API writes the encoder settings, keeps the shape and size of the picture, and puts an MP4's index at the front so it starts playing before the download ends.
The request#
curl "$VIDEXO_API_URL/v1/transcode" \
-H "Authorization: Bearer $VIDEXO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "https://example.com/talk.mp4",
"filename": "talk-small.mp4",
"video": {
"codec": "h264",
"crf": 28,
"encoder_preset": "veryfast"
},
"audio": {
"codec": "aac",
"bitrate": "128k"
}
}'Copy failed. The text is selected; copy it with your keyboard.
const response = await fetch(`${process.env.VIDEXO_API_URL}/v1/transcode`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIDEXO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"input": "https://example.com/talk.mp4",
"filename": "talk-small.mp4",
"video": {
"codec": "h264",
"crf": 28,
"encoder_preset": "veryfast"
},
"audio": {
"codec": "aac",
"bitrate": "128k"
}
}),
});
const job = await response.json();Copy failed. The text is selected; copy it with your keyboard.
ffmpeg \
-i https://example.com/talk.mp4 \
-map 0:v:0 \
-vf "scale='min(trunc(iw/2)*2,min(7680,min(trunc(7680*iw/ih/2)*2,trunc(sqrt(33554432*iw/ih)/2)*2)))':-2" \
-c:v libx264 -preset veryfast -crf 28 -pix_fmt yuv420p \
-map "0:a:0?" \
-c:a aac -b:a 128k -movflags +faststart \
talk-small.mp4Copy failed. The text is selected; copy it with your keyboard.
talk-small.mp4: H.264 video at CRF 28 with AAC audio at 128 kbit/s, its index at the front so it plays before the whole file has arrived.
Options that matter#
video.codec:h264plays everywhere;h265andav1are smaller at the same quality,vp9andav1go in WebM. VP9 and AV1 take several times longer to encode, which counts against your plan's longest job.video.quality(low,medium,high,lossless) orvideo.crf: constant quality. A lower CRF is a better picture and a larger file (Quality).video.max_bitrate: a ceiling for players and networks that need one.format, or the extension offilename:mp4,mov,webm,mkvorts.
WebM for browsers#
curl "$VIDEXO_API_URL/v1/transcode" \
-H "Authorization: Bearer $VIDEXO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "https://example.com/talk.mp4",
"filename": "talk.webm",
"video": {
"codec": "vp9",
"crf": 32,
"max_bitrate": "2M"
},
"audio": {
"codec": "opus",
"bitrate": "96k"
}
}'Copy failed. The text is selected; copy it with your keyboard.
const response = await fetch(`${process.env.VIDEXO_API_URL}/v1/transcode`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIDEXO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"input": "https://example.com/talk.mp4",
"filename": "talk.webm",
"video": {
"codec": "vp9",
"crf": 32,
"max_bitrate": "2M"
},
"audio": {
"codec": "opus",
"bitrate": "96k"
}
}),
});
const job = await response.json();Copy failed. The text is selected; copy it with your keyboard.
ffmpeg \
-i https://example.com/talk.mp4 \
-map 0:v:0 \
-vf "scale='min(trunc(iw/2)*2,min(7680,min(trunc(7680*iw/ih/2)*2,trunc(sqrt(33554432*iw/ih)/2)*2)))':-2" \
-c:v libvpx-vp9 -crf 32 -b:v 2M -pix_fmt yuv420p \
-map "0:a:0?" \
-c:a libopus -b:a 96k \
talk.webmCopy failed. The text is selected; copy it with your keyboard.
talk.webm: VP9 video at CRF 32 capped at 2 Mbit/s, with Opus audio at 96 kbit/s.
A constant frame rate#
curl "$VIDEXO_API_URL/v1/transcode" \
-H "Authorization: Bearer $VIDEXO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "https://example.com/talk.mp4",
"filename": "talk-30fps.mp4",
"fps": 30,
"audio": {
"codec": "copy"
}
}'Copy failed. The text is selected; copy it with your keyboard.
const response = await fetch(`${process.env.VIDEXO_API_URL}/v1/transcode`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIDEXO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"input": "https://example.com/talk.mp4",
"filename": "talk-30fps.mp4",
"fps": 30,
"audio": {
"codec": "copy"
}
}),
});
const job = await response.json();Copy failed. The text is selected; copy it with your keyboard.
ffmpeg \
-i https://example.com/talk.mp4 \
-map 0:v:0 \
-vf "scale='min(trunc(iw/2)*2,min(7680,min(trunc(7680*iw/ih/2)*2,trunc(sqrt(33554432*iw/ih)/2)*2)))':-2,fps=30" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p \
-map "0:a:0?" \
-c:a copy -movflags +faststart \
talk-30fps.mp4Copy failed. The text is selected; copy it with your keyboard.
talk-30fps.mp4: the video at a constant 30 frames a second, the audio copied as it was.
Only change the container#
"codec": "copy" passes the streams through without re-encoding, which takes seconds instead of
minutes. Options that change the picture or the sound are rejected with it.
curl "$VIDEXO_API_URL/v1/transcode" \
-H "Authorization: Bearer $VIDEXO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "https://example.com/talk.mp4",
"filename": "talk.mkv",
"video": {
"codec": "copy"
},
"audio": {
"codec": "copy"
}
}'Copy failed. The text is selected; copy it with your keyboard.
const response = await fetch(`${process.env.VIDEXO_API_URL}/v1/transcode`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIDEXO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"input": "https://example.com/talk.mp4",
"filename": "talk.mkv",
"video": {
"codec": "copy"
},
"audio": {
"codec": "copy"
}
}),
});
const job = await response.json();Copy failed. The text is selected; copy it with your keyboard.
ffmpeg \
-i https://example.com/talk.mp4 \
-map 0:v:0 \
-c:v copy \
-map "0:a:0?" \
-c:a copy \
talk.mkvCopy failed. The text is selected; copy it with your keyboard.