Video Processing
Upload and process videos with HLS streaming powered by Mux.
Upload a Video
Videos are uploaded the same way as images:
javascript
const formData = new FormData();
formData.append('file', videoFile); // Video file
formData.append('tags', 'tutorial,demo');
const response = await fetch('https://api.reimage.dev/upload/', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.REIMAGE_API_KEY}`
},
body: formData
});
const data = await response.json();
console.log(data);
/*
{
"object_id": "vid-abc123",
"object_url": "https://files.reimage.dev/dirname/vid-abc123/",
"video_url": "https://files.reimage.dev/dirname/vid-abc123/original.m3u8",
"size": 5242.88,
"type": "video/mp4"
}
*/python
import requests
with open('video.mp4', 'rb') as f:
files = {'file': f}
data = {'tags': 'tutorial,demo'}
headers = {'Authorization': 'Bearer YOUR_API_KEY'}
response = requests.post(
'https://api.reimage.dev/upload/',
files=files,
data=data,
headers=headers
)
result = response.json()
print(f"Video URL: {result['video_url']}")php
<?php
$filePath = 'video.mp4';
$cfile = new CURLFile($filePath, 'video/mp4', 'video.mp4');
$postData = [
'file' => $cfile,
'tags' => 'tutorial,demo'
];
$ch = curl_init('https://api.reimage.dev/upload/');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer YOUR_API_KEY'
]);
$response = curl_exec($ch);
$result = json_decode($response, true);
echo "Video URL: " . $result['video_url'];
?>Video Response
Videos have a special vid- prefix in their object ID:
json
{
"object_id": "vid-abc123",
"video_url": "https://files.reimage.dev/dirname/vid-abc123/original.m3u8"
}HLS Streaming
Videos are automatically processed for HLS (HTTP Live Streaming):
https://files.reimage.dev/{dirname}/{vid-object_id}/original.m3u8This provides:
- Adaptive bitrate streaming
- Multiple quality levels
- Efficient bandwidth usage
- Broad device compatibility
Playing Videos
HTML5 Video with HLS.js
html
<video id="video" controls style="width: 100%; max-width: 800px;"></video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
const video = document.getElementById('video');
const videoUrl = 'https://files.reimage.dev/dirname/vid-abc123/original.m3u8';
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(videoUrl);
hls.attachMedia(video);
}
// Native HLS support (Safari)
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = videoUrl;
}
</script>React Video Player
jsx
import { useEffect, useRef } from 'react';
import Hls from 'hls.js';
function VideoPlayer({ videoUrl }) {
const videoRef = useRef(null);
useEffect(() => {
const video = videoRef.current;
if (!video) return;
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(videoUrl);
hls.attachMedia(video);
return () => {
hls.destroy();
};
}
// Native HLS support (Safari)
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = videoUrl;
}
}, [videoUrl]);
return (
<video
ref={videoRef}
controls
style={{ width: '100%', maxWidth: '800px' }}
/>
);
}
// Usage
<VideoPlayer videoUrl="https://files.reimage.dev/dirname/vid-abc123/original.m3u8" />Using Video.js
html
<link href="https://vjs.zencdn.net/8.3.0/video-js.css" rel="stylesheet" />
<script src="https://vjs.zencdn.net/8.3.0/video.min.js"></script>
<video
id="my-video"
class="video-js"
controls
preload="auto"
width="800"
height="450"
>
<source
src="https://files.reimage.dev/dirname/vid-abc123/original.m3u8"
type="application/x-mpegURL"
/>
</video>
<script>
const player = videojs('my-video');
</script>Video Storage Limits
Video storage is measured in minutes, not kilobytes:
javascript
const user = await fetch('https://api.reimage.dev/user/', {
headers: { 'Authorization': `Bearer ${API_KEY}` }
}).then(r => r.json());
console.log(`Video: ${user.video_storage_used} / ${user.video_storage_limit} minutes`);Storage Limits by Tier
| Tier | Video Minutes |
|---|---|
| Free | 0 minutes |
| Pro | 120 minutes |
| Enterprise | Custom |
Processing Status
Videos are processed asynchronously:
- Upload returns immediately with
video_url - Video is processed in the background by Mux
- HLS stream becomes available when processing completes
- Webhook notification sent when ready (if configured)
Check if Video is Ready
javascript
async function isVideoReady(videoUrl) {
try {
const response = await fetch(videoUrl, { method: 'HEAD' });
return response.ok;
} catch {
return false;
}
}
// Usage
const ready = await isVideoReady(videoData.video_url);
if (ready) {
console.log('Video is ready to play');
} else {
console.log('Video still processing...');
}Supported Video Formats
- MP4 (.mp4)
- MOV (.mov)
- AVI (.avi)
- WebM (.webm)
- MKV (.mkv)
- And most other common formats
Video Upload Progress
jsx
function VideoUploader() {
const [uploading, setUploading] = useState(false);
const [progress, setProgress] = useState(0);
const [videoData, setVideoData] = useState(null);
const handleUpload = async (file) => {
setUploading(true);
const formData = new FormData();
formData.append('file', file);
formData.append('tags', 'user-video');
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
const percent = (e.loaded / e.total) * 100;
setProgress(percent);
}
});
xhr.addEventListener('load', () => {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
setVideoData(data);
setUploading(false);
}
});
xhr.open('POST', 'https://api.reimage.dev/upload/');
xhr.setRequestHeader('Authorization', `Bearer ${process.env.REACT_APP_REIMAGE_API_KEY}`);
xhr.send(formData);
};
return (
<div>
<input
type="file"
accept="video/*"
onChange={(e) => handleUpload(e.target.files[0])}
disabled={uploading}
/>
{uploading && (
<div>
<progress value={progress} max="100" />
<span>{progress.toFixed(0)}%</span>
</div>
)}
{videoData && (
<div>
<h3>Upload Complete!</h3>
<p>Video is processing... This may take a few minutes.</p>
<VideoPlayer videoUrl={videoData.video_url} />
</div>
)}
</div>
);
}Best Practices
- Compress before upload - Use H.264 codec for best compatibility
- Reasonable resolutions - 1080p is usually sufficient
- Monitor usage - Keep track of video minutes used
- Handle processing time - Videos aren't immediately available
- Use HLS.js - For broad browser compatibility
Thumbnail Generation
Video thumbnails are not automatically generated. You can:
- Extract a frame client-side
- Upload a separate thumbnail image
- Use a video poster image
html
<video
controls
poster="https://files.reimage.dev/dirname/thumbnail/w-800.jpg"
>
<source src="video.m3u8" type="application/x-mpegURL" />
</video>Error Handling
javascript
async function uploadVideo(file) {
// Check user's video storage before upload
const user = await fetch('https://api.reimage.dev/user/', {
headers: { 'Authorization': `Bearer ${API_KEY}` }
}).then(r => r.json());
if (user.video_storage_used >= user.video_storage_limit) {
throw new Error('Video storage limit exceeded');
}
// Proceed with upload
const formData = new FormData();
formData.append('file', file);
const response = await fetch('https://api.reimage.dev/upload/', {
method: 'POST',
headers: { 'Authorization': `Bearer ${API_KEY}` },
body: formData
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Upload failed');
}
return await response.json();
}Next Steps
- Upload API - Detailed upload documentation
- User API - Check video storage usage
- Error Handling - Handle upload errors