|
| 1 | +# Video Preview |
| 2 | + |
| 3 | +`processVideoPreview` extracts a frame from a video (from either an explicit S3 location or an HTTP/HTTPS URL) and returns it as an image. The image can be resized, rescaled, and converted to WebP or JPEG format with configurable quality. Both memory cache and S3 cache are supported for the generated preview images. |
| 4 | + |
| 5 | +## Endpoint |
| 6 | + |
| 7 | +- Route: `GET /videos/preview/*` - requests are validated and routed to `processVideoPreview`. |
| 8 | + |
| 9 | +## Security |
| 10 | + |
| 11 | +- `processVideoPreview` relies on upstream validation (e.g. `validation.ProcessImageContextFromPath`) to ensure the incoming `params.Url` or `params.CustomObjectKey` is allowed and properly signed when necessary. |
| 12 | +- When `CustomObjectKey` is set, callers must ensure that the key was produced by a server-side signing/validation step; direct client-provided S3 keys are not trusted. |
| 13 | +- S3 presigned URLs are generated with 1-hour expiration for ffmpeg to access the video. |
| 14 | + |
| 15 | +## Key concepts |
| 16 | + |
| 17 | +- Frame extraction: uses ffmpeg to extract a single frame at a specified position (first frame, middle frame, or last frame). |
| 18 | +- Image processing: extracted frames can be resized, rescaled, and encoded to WebP or JPEG. |
| 19 | +- S3 explicit location: when `params.CustomObjectKey` is provided and S3 is configured, the handler reads the video directly from S3 using a presigned URL. |
| 20 | +- HTTP proxy: when no explicit S3 location is given, the handler validates and extracts frames from `params.Url`. |
| 21 | +- Caching: preview images are cached in both memory (Ristretto) and S3 (if enabled) to optimize performance. |
| 22 | + |
| 23 | +## Environment / configuration |
| 24 | + |
| 25 | +- S3 settings (when using explicit location): `S3_ENABLED`, `S3_ENDPOINT`, `S3_BUCKET`, `S3_PREFIX`, etc. The running binary relies on `s3cache` configuration and presence of a MinIO client. |
| 26 | +- Cache settings: `APP_CACHE_TTL` (in-memory cache TTL in seconds), `APP_HTTP_CACHE_TTL` (HTTP Cache-Control max-age). |
| 27 | +- Request validation and signing: upstream validation must be configured (routes use `validation.ProcessImageContextFromPath`). |
| 28 | + |
| 29 | +## Path parameters |
| 30 | + |
| 31 | +The path after `/videos/preview/` is parsed to extract transformation parameters and video URL: |
| 32 | + |
| 33 | +Format: `/videos/preview/{params}/{base64-encoded-url-or-location}` |
| 34 | + |
| 35 | +Supported parameters (can be combined): |
| 36 | +- `q:{quality}` - JPEG/WebP quality (1-100, default varies) |
| 37 | +- `w:{width}` - target width in pixels |
| 38 | +- `h:{height}` - target height in pixels |
| 39 | +- `s:{scale}` - scale factor (e.g., 0.5 for 50%, 2.0 for 200%) |
| 40 | +- `webp` - convert to WebP format (default is JPEG) |
| 41 | +- `f:{position}` - frame position: `first`, `middle`, or `last` (default is `first`) |
| 42 | +- `loc:{location}` - explicit S3 location (requires signature) |
| 43 | +- `i:{interpolation}` - interpolation method for resizing (e.g., `lanczos`, `linear`, `cubic`) |
| 44 | + |
| 45 | +## Request details |
| 46 | + |
| 47 | +### Video sources |
| 48 | + |
| 49 | +1. **S3 location** (when `loc:{location}` parameter is present): |
| 50 | + - The handler validates the S3 object exists and is a video |
| 51 | + - Generates a presigned URL (1-hour expiration) for ffmpeg to access |
| 52 | + - Content-Type is validated from S3 metadata |
| 53 | + |
| 54 | +2. **HTTP/HTTPS URL** (default): |
| 55 | + - The handler performs a HEAD request to validate content type |
| 56 | + - Must return a valid video MIME type |
| 57 | + - URL is passed directly to ffmpeg for frame extraction |
| 58 | + |
| 59 | +### Frame extraction |
| 60 | + |
| 61 | +- Uses ffmpeg to extract a single frame at the specified position |
| 62 | +- Supported positions: |
| 63 | + - `first` - extracts the first frame (default) |
| 64 | + - `middle` - extracts a frame from the middle of the video |
| 65 | + - `last` - extracts the last frame |
| 66 | +- Frame extraction is performed via the `extractFrameFromPosition` function |
| 67 | + |
| 68 | +### Image transformations |
| 69 | + |
| 70 | +Applied in order: |
| 71 | +1. **Resize** (if `w:` or `h:` specified): resizes to exact dimensions |
| 72 | +2. **Rescale** (if `s:` specified): scales by percentage |
| 73 | +3. **Encode**: converts to WebP or JPEG with specified quality |
| 74 | + |
| 75 | +## Caching behavior |
| 76 | + |
| 77 | +1. **Memory cache check**: checks Ristretto cache first |
| 78 | +2. **S3 cache check**: if memory cache misses, checks S3 cache |
| 79 | +3. **Generate preview**: if both caches miss: |
| 80 | + - Validates video source (S3 or HTTP) |
| 81 | + - Extracts frame at specified position |
| 82 | + - Applies transformations (resize, rescale) |
| 83 | + - Encodes to target format (WebP or JPEG) |
| 84 | + - Stores in both memory and S3 caches (if enabled) |
| 85 | + |
| 86 | +## Headers set |
| 87 | + |
| 88 | +- `Content-Type`: `image/webp` or `image/jpeg` depending on output format |
| 89 | +- `Cache-Control`: `public, max-age={APP_HTTP_CACHE_TTL}` for client-side caching |
| 90 | + |
| 91 | +## Errors and status codes |
| 92 | + |
| 93 | +- 200 OK — preview image generated and served successfully |
| 94 | +- 403 Forbidden — invalid content type or video MIME type not allowed |
| 95 | +- 404 Not Found — S3 object not found (when using S3 location) |
| 96 | +- 500 Internal Server Error — failures during: |
| 97 | + - Content type validation |
| 98 | + - Frame extraction |
| 99 | + - Image processing (resize, rescale, encode) |
| 100 | + - S3 operations (stat, presigned URL generation) |
| 101 | + |
| 102 | +## Examples |
| 103 | + |
| 104 | +### Basic preview (first frame, default quality) |
| 105 | + |
| 106 | +```bash |
| 107 | +curl "http://localhost:3000/videos/preview/<base64-encoded-url>" |
| 108 | +``` |
| 109 | + |
| 110 | +### Preview with specific dimensions and WebP format |
| 111 | + |
| 112 | +```bash |
| 113 | +# Extract first frame, resize to 500x300, convert to WebP at quality 80 |
| 114 | +curl "http://localhost:3000/videos/preview/w:500/h:300/q:80/webp/<base64-encoded-url>" |
| 115 | +``` |
| 116 | + |
| 117 | +### Preview from middle of video with scaling |
| 118 | + |
| 119 | +```bash |
| 120 | +# Extract middle frame, scale to 50%, JPEG quality 90 |
| 121 | +curl "http://localhost:3000/videos/preview/f:middle/s:0.5/q:90/<base64-encoded-url>" |
| 122 | +``` |
| 123 | + |
| 124 | +### Preview from S3 location |
| 125 | + |
| 126 | +```bash |
| 127 | +# Extract last frame from S3 object, resize to 800x600 |
| 128 | +curl "http://localhost:3000/videos/preview/loc:<signed-location>/f:last/w:800/h:600/<base64-encoded-url>" |
| 129 | +``` |
| 130 | + |
| 131 | +### High-quality WebP thumbnail |
| 132 | + |
| 133 | +```bash |
| 134 | +# First frame, 300x200, WebP quality 95, Lanczos interpolation |
| 135 | +curl "http://localhost:3000/videos/preview/w:300/h:200/q:95/webp/i:lanczos/<base64-encoded-url>" |
| 136 | +``` |
| 137 | + |
| 138 | +## Performance considerations |
| 139 | + |
| 140 | +- Frame extraction requires ffmpeg and may be CPU-intensive for large videos |
| 141 | +- S3 presigned URLs are generated on-demand (1-hour expiration) |
| 142 | +- Caching significantly improves performance for repeated preview requests |
| 143 | +- Consider pre-generating previews for frequently accessed videos |
| 144 | +- Memory and S3 caches work together to minimize redundant processing |
| 145 | + |
| 146 | +## Integration with video upload |
| 147 | + |
| 148 | +When uploading videos using the single or multi-part upload endpoints, you can generate previews by: |
| 149 | + |
| 150 | +1. Upload video to S3 (single upload or multi-part) |
| 151 | +2. Use the returned `location` in a preview request with `loc:{location}` parameter |
| 152 | +3. Ensure the request is properly signed if required by your security configuration |
| 153 | + |
| 154 | +## MIME type validation |
| 155 | + |
| 156 | +Only video MIME types are accepted: |
| 157 | +- video/mp4 |
| 158 | +- video/quicktime |
| 159 | +- video/x-msvideo |
| 160 | +- video/x-matroska |
| 161 | +- video/webm |
| 162 | +- And other standard video MIME types (validated via `validation.IsVideoMime`) |
0 commit comments