Video Frame Extractor & Media Probe for AI Agents
Pricing
from $1.00 / 1,000 frame extracteds
Video Frame Extractor & Media Probe for AI Agents
Give AI agents eyes for video: send direct video or audio file links, get ffprobe metadata (duration, codecs, resolution, fps, rotation, 9:16 check), frames at set times, every N seconds or at scene cuts, a contact sheet for vision models, EBU R128 loudness and MP3 audio.
Pricing
from $1.00 / 1,000 frame extracteds
Rating
0.0
(0)
Developer
FFS Marketing
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 hours ago
Last modified
Categories
Security
Limited permissionsShare
Give your AI agent eyes and ears for video. Send a direct link to a video or audio file; get back its metadata (duration, codecs, resolution, frame rate, rotation, aspect ratio), frames at the times you choose, every N seconds or at scene changes, one contact sheet image sized for vision models, EBU R128 loudness, and the audio as an MP3 link. One call, JSON out.
Works as a tool for AI agents. Add it to Claude, ChatGPT, Cursor or any MCP client through Apify's MCP server (https://mcp.apify.com/?tools=fluidfaith/media-probe), or call it with one API request. Agents cannot watch video and cloud agents have no ffmpeg: this Actor is that missing step.
Costs $0.002 per file, $0.001 per frame, $0.005 per contact sheet, $0.002 per loudness measurement and $0.003 per minute of MP3 audio. Failed links and errors are free, and your maximum charge per run is never exceeded.
What an agent can do with it
- See a clip: ask for 6 to 12 evenly spaced frames plus a contact sheet, and pass the sheet to a vision model in one image.
- Check a deliverable before posting: is this reel 9:16, under 90 seconds, with audio, near -14 LUFS?
checks.isVertical916,durationSeconds,checks.hasAudioandloudness.integratedLufsanswer it. - Find the shots: scene mode returns the time of every cut plus one frame per shot.
- Transcribe:
extractAudioreturns a small mono MP3 link ready for a speech-to-text model.
Why use it
Probe, frames, contact sheet and loudness in one call
Most frame grabbers return frames only. This Actor also reads the full ffprobe metadata, runs simple delivery checks and measures loudness, so an agent gets everything it needs about a file in one row.
Long files are not decoded end to end
Frames are taken with a seek before decoding, so asking for 5 frames of a 2-hour file decodes only a few seconds around each time. (Scene detection has to look at the whole video, so it decodes it at 5 frames per second.)
Sized for vision models
Frames default to 768 px wide and are never upscaled. The contact sheet is a grid with time labels that is at most 1568 px on its long side, the size vision models read without shrinking it.
Direct file links only, on purpose
It reads files you can link to directly (your storage bucket, CDN, Apify key-value store, a podcast feed enclosure, a client upload). It does not download from YouTube, TikTok, Instagram, Facebook, X, Vimeo or other social and streaming sites; those links get a clear error and are not charged.
Use it from an agent
Any MCP client
Add https://mcp.apify.com/?tools=fluidfaith/media-probe as a remote MCP server (OAuth or your Apify token). The agent sees one tool with the input fields below.
One API request
curl -X POST "https://api.apify.com/v2/acts/fluidfaith~media-probe/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"urls": ["https://example.com/reel.mp4"], "framesMode": "count", "frameCount": 9, "contactSheet": true, "loudness": true}'
Pricing
Pay per event. You only pay for what is returned.
| Event | Price | Charged when |
|---|---|---|
| File probed | $0.002 | the file's metadata is returned |
| Frame extracted | $0.001 | each frame image returned |
| Contact sheet | $0.005 | each contact sheet returned |
| Loudness measured | $0.002 | loudness numbers are returned |
| Audio minute extracted | $0.003 | each started minute of MP3 returned |
Examples:
| Job | Cost |
|---|---|
Metadata only (framesMode: "none") | $0.002 |
| Metadata + 6 frames (the default) | $0.008 |
| A reel check: metadata + 9 frames + contact sheet + loudness | $0.018 |
| A 12-minute podcast as MP3 for transcription + loudness | $0.040 |
| 20 files, metadata + 6 frames each | $0.16 |
Nothing is charged for blocked or social links, failed downloads, files that are not media, or files that pass a time limit. Set a maximum charge on the run and the Actor stops exactly there: what does not fit is skipped, listed in warnings and not charged, and stoppedAtSpendingCap is true in the run summary.
Input
| Field | Default | What it does |
|---|---|---|
urls | required unless files given | Direct http(s) links to video or audio files (up to 20). |
files | [] | Up to 5 small files as { "name": "clip.mp4", "base64": "..." }, 6 MB each. |
framesMode | count | none, count (evenly spaced), every (every N seconds), times (your list), scene (at cuts). |
frameCount | 6 | Frames for count mode (1 to 100). |
everyNSeconds | 10 | Seconds between frames for every mode. |
frameTimes | [] | Times for times mode: seconds (12.5) or "mm:ss" / "hh:mm:ss". |
sceneThreshold | 0.3 | Scene mode sensitivity, 0.05 (more cuts) to 0.95 (only hard cuts). |
maxFramesPerFile | 100 | Hard limit on frames per file. |
frameWidth | 768 | Frame width in px (64 to 3840), never upscaled. |
frameFormat | jpg | jpg, webp or png. |
contactSheet | false | Also return a grid image of the frames with time labels. |
loudness | false | EBU R128 integrated loudness, loudness range and true peak. |
extractAudio | false | Return the first audio track as MP3. |
audioQuality | speech | speech (mono 64 kbps) or music (stereo 192 kbps). |
audioMaxMinutes | 30 | Audio is cut after this many minutes (up to 180). |
maxFileSizeMb | 500 | Larger files are refused before download (hard limit 2048). |
maxDurationSeconds | 0 | Use only the first N seconds for frames, scenes, loudness and audio (0 = whole file). |
maxConcurrency | 2 | Files at the same time (1 to 4). |
Example:
{"urls": ["https://example.com/reel.mp4"],"framesMode": "scene","contactSheet": true,"loudness": true}
Output
One dataset row per file:
{"source": "https://example.com/reel.mp4","fileName": "reel.mp4","status": "OK","error": null,"durationSeconds": 28.4,"container": "mp4","containerLongName": "QuickTime / MOV","sizeBytes": 9123456,"bitRate": 2570000,"creationTime": "2026-11-02T15:04:11.000000Z","streams": { "video": 1, "audio": 1, "subtitle": 0, "coverArt": 0 },"video": {"codec": "h264", "profile": "High", "width": 1920, "height": 1080,"displayWidth": 1080, "displayHeight": 1920, "rotation": 90,"fps": 29.97, "aspectRatio": "9:16", "pixelFormat": "yuv420p", "bitRate": 2400000, "frameCount": 851},"audio": { "codec": "aac", "profile": "LC", "sampleRate": 48000, "channels": 2, "channelLayout": "stereo", "bitRate": 128000 },"checks": { "hasVideo": true, "hasAudio": true, "isVertical": true, "isVertical916": true, "isHorizontal169": false },"loudness": { "integratedLufs": -14.2, "loudnessRangeLu": 6.1, "truePeakDbtp": -1.3, "thresholdLufs": -24.3, "silent": false },"frames": [{ "index": 1, "timeSeconds": 0.0, "url": "https://api.apify.com/v2/key-value-stores/<id>/records/01-reel-mp4-1a2b3c-frame-001.jpg?signature=<signature>", "key": "01-reel-mp4-1a2b3c-frame-001.jpg", "width": 768, "height": 1366 }],"sceneChanges": [3.2, 7.8, 12.0, 19.4],"contactSheetUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/01-reel-mp4-1a2b3c-contact-sheet.jpg?signature=<signature>","contactSheet": { "columns": 3, "rows": 2, "tiles": 5, "width": 1192, "height": 1550, "timeLabels": true },"audioUrl": null,"audioDurationSeconds": null,"charged": { "probes": 1, "frames": 5, "contactSheets": 1, "loudness": 1, "audioMinutes": 0, "usd": 0.014 },"warnings": []}
status:OK,PARTIAL(metadata returned but something asked for was skipped: spending limit or a frame that could not be read; seewarnings) orERROR(nothing returned, nothing charged; seeerror).rotationis the clockwise rotation a player applies;displayWidthanddisplayHeightare what viewers see, and the checks use them.aspectRatiois the nearest common label within 2% (16:9, 9:16, 4:3, 1:1, 4:5, 21:9 and so on), else the exact ratio.- Frame, contact sheet and MP3 links point to the run's key-value store and follow your Apify storage retention.
The run summary (key-value store record OUTPUT) holds counts, the total charged, stoppedAtSpendingCap and the status of every file.
Limits
- Up to 20 links per run, 100 frames per file, 2048 MB per file (500 MB by default).
- Time limits: download 5 minutes, each ffmpeg step 2 minutes (scene detection, loudness and audio 7 minutes), each file 10 minutes. A file that passes a limit is an
ERRORrow and is not charged. - Formats: whatever ffmpeg reads in mp4, mov, m4a, webm, mkv, avi, flv, ts, mpeg, wmv/asf, mxf, mp3, wav, ogg, opus, flac, aac, aiff and similar containers. Streaming playlists (HLS .m3u8, DASH) are refused: give a direct link to one file.
Privacy and safety
- Files are downloaded into the run's temporary folder and deleted when the file is done. Only the frames, contact sheet and MP3 you asked for are stored, in the run's own storage.
- Only public http(s) links are fetched. Localhost, private networks, cloud metadata addresses and internal host names are refused, also when a redirect or a DNS answer points there.
- ffmpeg only ever reads the downloaded local file: it cannot open network addresses or other files on disk.
- Metadata tags that can hold personal data (GPS location, device owner) are not returned; only
creationTimeis.
FAQ
Why no YouTube, TikTok or Instagram links?
Those sites' terms forbid downloading outside their apps, they change often, and Actors that depend on them fail a lot. This Actor is for files you have a direct link to and the right to process: your own uploads, client deliverables, your storage bucket or CDN. If you have the rights to a social video, download it with the platform's own tools and pass the file link.
My link is a Google Drive or Dropbox share link and it fails.
Share links open a web page. Use the direct download form (Dropbox: change dl=0 to dl=1; Google Drive: a direct download link for public files) or put the file in any storage that gives a direct URL.
How do I check a reel before posting?
{"urls": ["<file>"], "framesMode": "count", "frameCount": 9, "contactSheet": true, "loudness": true}. Read checks.isVertical916, durationSeconds, checks.hasAudio and loudness.integratedLufs (most social platforms normalize near -14 LUFS), and look at the contact sheet.
Is a frame at an exact time exact?
Yes. The seek goes to the keyframe before your time and decodes forward to it, so the frame is the one at (or right after) the time you asked for.
What happens at my spending limit?
Metadata comes first, then frames, the contact sheet, loudness and audio, as far as your maximum charge allows. Anything skipped is listed in warnings, the row is PARTIAL, and nothing past your maximum is ever charged.
Other Actors by Fluid Faith
- Mobile Website Test on iPhone & Android (Mobile QA Gate): PASS or FAIL per page on today's phones, with screenshots. $0.01 per page per phone.
- Lighthouse & Accessibility Audit: Lighthouse scores, Core Web Vitals and axe issues, median of 3 runs, PASS/FAIL and top fixes. $0.02 per URL per form factor.
- PDF to Markdown with Tables: PDF, Word, PowerPoint and Excel to Markdown with every table as JSON rows. $0.002 per page.
Load them together as MCP tools: https://mcp.apify.com/?tools=fluidfaith/mobile-qa-gate,fluidfaith/lighthouse-gate,fluidfaith/pdf-to-markdown-tables,fluidfaith/media-probe
Credits
Built on FFmpeg (ffprobe and ffmpeg, run as separate programs). Made by Fluid Faith Solutions.