ffmpegvideo-processingmetadata

What you can extract from a video file, and what you can't

··10 min read
What you can extract from a video file, and what you can't

You ran ffmpeg -i webinar.mp4 -vn -acodec copy audio.mp3, got a file back in under two seconds, and nothing on your machine will play it.

Everything you can extract from video falls into three groups, and the group decides the command. Audio tracks, text subtitle tracks and header metadata already exist inside the container as separate streams, so they copy out byte for byte with no re-encode. Frames, thumbnails and bitmap subtitle pictures are not stored as files anywhere in there, so they have to be decoded and rendered. Burned-in on-screen text and spoken words were never streams at all, which makes those OCR and transcription jobs rather than extraction.

The unplayable file is group one with the wrong container stapled on. Probing first would have told you that in half a second.

ffprobe shows which streams exist before you pick an operation

ffprobe reads the file and reports what is inside it without touching the media. Per FFmpeg's ffprobe documentation, -show_streams prints one section per media stream and -show_format prints one section for the container, which is exactly the information that decides whether your extract job is a copy, a render, or the wrong job entirely.

ffprobe -v error -print_format json -show_format -show_streams input.mp4

Read three fields per stream and you have your answer: codec_type (video, audio, subtitle, data), codec_name (h264, aac, subrip, hdmv_pgs_subtitle), and index for the -map argument. The format object gives you format_name, duration and size. Container signatures beat file extensions here, so a .mp4 that is really a Matroska file shows up as one.

To extract video metadata without a local install, the same probe is one POST:

curl -X POST https://api.ffmpeg-micro.com/v1/ffprobe \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "media_url": "https://cdn.example.com/webinar.mp4" }'

The response is the same streams array and format object you would get on the command line, which means you can branch on it in code. The full payload shape and the field-by-field walkthrough are in ffprobe: How to Inspect Video Metadata Before Processing and the FFprobe API reference.

Audio, text subtitles and header metadata copy out with no re-encode

Three things in your file are already finished streams, and pulling them out costs almost no CPU. FFmpeg's documentation describes -c copy as selecting a copy "encoder" that moves already-compressed packets into a new container and decodes nothing, with one condition: the destination container has to be able to carry that codec.

ffmpeg -i input.mp4 -map 0:a:0 -c:a copy audio.m4a
ffmpeg -i input.mkv -map 0:s:0 -c:s copy subs.srt

That condition is what broke the .mp3. An MP4 almost always carries AAC audio, and the MP3 muxer accepts exactly one MP3 stream, so copying AAC into a .mp3 gives you this:

[mp3 @ 0x55d3f8] Invalid audio stream. Exactly one MP3 audio stream is required.
Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument

Two correct endings exist. Put the AAC in a container that holds it (audio.m4a or audio.aac) and stay lossless, or accept a re-encode and get a real MP3 with -c:a libmp3lame -q:a 2. Which one you want is a container question, not a quality question, and the difference between the two is the same remux-versus-encode line covered in What transcode means: transcode vs encode vs remux vs compress.

Header metadata is the third copyable thing, and it is physically separate from the media. In an MP4 or ISOBMFF file the moov atom holds per-track headers and the index with no media bytes in it, while mdat holds the coded audio and video (quick-dive-into-mp4). Descriptive tags live in a udta user-data atom inside moov (QuickTime File Format), which is why reading titles, creation time and encoder strings never touches a single video frame. The per-format recipes are in How to Extract Audio from Video with FFmpeg (MP3, WAV, API) and Extract Subtitles from MKV and MP4 with FFmpeg, No Re-encoding.

Frames and bitmap subtitles have to be decoded and rendered

Frames are not sitting in the file as images. Your video is a compressed sequence where most frames are described as differences from other frames, so a thumbnail means decoding to that point and then encoding a JPEG or PNG. That is real work, and it is why frame extraction is slower per second of input than an audio copy.

ffmpeg -ss 00:00:05 -i input.mp4 -frames:v 1 -q:v 2 frame.jpg
ffmpeg -i input.mp4 -vf fps=1 frame_%04d.jpg

Bitmap subtitles land in this same group for a different reason. Blu-ray PGS, DVD VobSub and DVB subtitle streams can only be copied by FFmpeg, never converted to a text format (FFMPEG An Intermediate Guide), because a PGS stream stores rendered images of the text rather than the characters (Presentation Graphic Stream). Aim -c:s srt at one and FFmpeg stops you:

Subtitle encoding currently only possible from text to text or bitmap to bitmap

Getting SRT out of a PGS track is an OCR pipeline, not a stream copy. pgsrip is the usual route, driving tesseract over the extracted images. Timing comes free because it is in the stream; the words have to be recognized. Frame selection, timestamps and scaled output are covered in How to Extract Frames from Video with FFmpeg.

Burned-in text and spoken words were never in the file

Two things people ask to extract do not exist as data in the container at any level. Burned-in on-screen text is pixels in the video frames, identical to a tree or a face, so no -map argument reaches it. Recovering it means frame-by-frame OCR with tooling like videocr or VideoSubFinder paired with an OCR engine, and the accuracy you get depends on the font, the contrast and the compression.

Speech is the same story with a different fix. The audio stream is extractable; the words in it are not. Extraction gets you a WAV or an MP3, and a transcription model turns that into text. Where this bites is the handoff: OpenAI's speech-to-text endpoints cap the request at 25 MB, so a 90-minute recording has to be compressed down or split into chunks before it goes anywhere. n8n builders hit this constantly, and the community thread on extracting audio and splitting it into 15-minute chunks is the honest version of the problem: the extract is the easy half.

What each extract job costs in tokens

Pricing on an extraction tracks the length of the input, not which branch you landed in, because the meter is seconds of video processed. One token buys 10 seconds of input, metered per second, with no rounding up to the minute. Here is the arithmetic on four real jobs.

Extract jobSeconds of input billedTokens
12-minute Zoom recording to MP372072
30-second clip pulled from a 60-minute recording303
90-minute webinar to audio for a transcription step5,400540
A job that dies on a corrupt input00

Row two is the one that differs from how most media platforms meter. Trim 30 seconds out of a one-hour recording and the bill is 30 seconds, not the hour the file happens to be. Row four matters more than it looks on a page about extraction, because an extract run against a file nobody probed is the job most likely to fail, and failed jobs are never billed. When one does fail, the status response tells you why, and Why your transcode job failed (and what to do in the poll loop) covers reading that in your polling code.

A new account gets 200 tokens at sign-up with no card, which is about 33 minutes of input, enough to work through every branch above on your own files. The free tier caps input at 100 MB per file, so that 90-minute webinar needs Starter at $19.99 for 2,500 tokens and a 1,024 MB cap, where the same extract works out to roughly $4.32. Top-ups run 500 tokens for $5 on any plan, including Free, and purchased tokens don't expire while the account is open. Full numbers are on the pricing page.

The output is a file you download. Nothing is kept as an asset in a media library you then have to pay to pull an original back out of, which is the distinction worked through in Cloudinary alternative for video: which ones hand the file back.

Extracting audio in n8n or Make, where there is no command line

n8n Cloud and Make give you no shell, so every ffmpeg -vn recipe on the web is unusable there even though the question is the most common one in those communities. The route that works is an HTTP Request node: POST the job, poll the status endpoint, pass the output URL to the next node.

curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [{ "url": "https://cdn.example.com/recording.mp4" }],
    "outputFormat": "mp3",
    "options": [
      { "option": "-vn" },
      { "option": "-c:a", "argument": "mp3" },
      { "option": "-b:a", "argument": "128k" }
    ]
  }'

The response carries an id and status: "pending". Poll GET /v1/transcodes/{id} until status is completed and read output_url. More than 300 builders already run FFmpeg Micro from Make or n8n this way, and dropping -b:a to 128k or 96k on a long recording is also how the extracted audio stays under a transcription API's size limit. The submit-and-poll pattern for both tools is in FFmpeg with n8n Cloud.

FAQ about extracting from video files

Why won't my extracted .mp3 play?

An MP3 container cannot carry an AAC stream, and MP4 files almost always hold AAC, so -acodec copy with a .mp3 filename produces a file no player accepts. Write the copied stream to .m4a instead, or re-encode with -c:a libmp3lame if you specifically need MP3.

My MP4 has no subtitle track. Can I still extract subtitles?

No extraction can create a subtitle track that was never in the file. Check codec_type: "subtitle" in your ffprobe output first; if nothing is there, the job you want is transcription of the audio stream, and if the text is visible in the picture it is frame OCR.

If I extract a 30-second clip from a one-hour recording, am I billed for the hour?

FFmpeg Micro bills 30 seconds for a 30-second clip, because the meter counts seconds of input processed with no rounding up to a minute. The source file's total length does not enter the calculation.

How do I tell whether a subtitle track is text or pictures?

The codec_name field in ffprobe's stream output answers it: subrip, ass and mov_text are text and convert freely, while hdmv_pgs_subtitle, dvd_subtitle and dvb_subtitle are images and can only be copied or run through OCR.

Does the extracted file come back to me, or stay in a media library?

Each job returns an output URL you download, and the file is yours from there. There is no hosted asset you later have to pay to retrieve an original from.

Whichever branch your file landed in, the specific recipe is already written: audio, frames, subtitles and metadata each have their own walkthrough on the learn hub, and the probe above tells you which one to open. Sign up free if you'd rather run the extract than maintain the binary that does it: 200 tokens and an API key, no servers and no FFmpeg install, callable from your own code, from n8n, Make and Zapier, or from your AI agents.

About Javid Jamae

Founder & CEO at FFmpeg Micro

Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free