The PNG frames are transparent. The exported video has a black rectangle. Running background removal again seems like the obvious fix, but it can be the wrong step: the alpha channel may have disappeared during encoding, or the player may simply be ignoring it.
To convert an existing transparent PNG sequence to WebM, use FFmpeg with libvpx-vp9 and an alpha-capable pixel format. Then decode the output and check it. Renaming a file to .webm does not create transparency, and a successful encode does not prove that transparency survived.
This walkthrough uses real footage, an opaque control, and a frame-by-frame comparison. There is also a small result worth keeping in mind: in this particular run, the largest alpha difference was one level out of 255, even with the encoder's lossless option enabled.
The source cutout is the public podcast demo from BG Remover Online. Original footage: Mixkit, “Bearded announcer, close up”. The person shown is not affiliated. The processed cutout also removes the microphone; it is not a perfect subject-selection example. The backgrounds in the figure are display layers, not baked into the PNG.
Start with frames that already contain transparency
A PNG can contain alpha, but it can also be completely opaque. Open a frame above two different solid backgrounds. The empty area around the subject should reveal each background. A checkerboard that stays fixed inside the image may be ordinary image pixels.
Keep the frames in a dedicated directory with matching dimensions and continuous numbering:
frames/
frame_0001.png
frame_0002.png
frame_0003.png
...
The command below expects four digits and a first frame numbered 0001. Use %03d for three digits, or change -start_number if your sequence begins elsewhere. A missing number can make a sequence end early. Check how many frames you actually encoded.
For the same conversion in a browser, the PNG sequence to transparent WebM converter accepts a ZIP of PNG frames and outputs VP9-alpha WebM. Google sign-in is required; check the current file limits before uploading. This is an alternative workflow, not the workflow benchmarked below.
This step packages existing cutouts into video. If your starting point is an ordinary MP4 with a room behind the presenter, you still need a separate matting, masking, or keying step. A pixel-format flag cannot identify which parts of that room to remove.
Encode the sequence
Use an FFmpeg build with the libvpx-vp9 encoder. In a terminal, check its availability:
ffmpeg -h encoder=libvpx-vp9
Then run this from the directory containing frames:
ffmpeg -framerate 12 -start_number 1 -i "frames/frame_%04d.png" -c:v libvpx-vp9 -pix_fmt yuva420p -lossless 1 -auto-alt-ref 0 cutout.webm
This is the encoding command used in the experiment. If cutout.webm already exists, FFmpeg asks before overwriting it. Use a new output name when comparing settings.
| Setting | What it controls |
|---|---|
-framerate 12 |
Reads the sequence at 12 frames per second. Set it to the rate your frames were created for. |
-start_number 1 |
Starts at frame_0001.png. |
-c:v libvpx-vp9 |
Selects the VP9 encoder used here. |
-pix_fmt yuva420p |
Requests an alpha-capable pixel format. The a matters. |
-lossless 1 |
Enables the encoder's lossless mode. It does not promise that every conversion around the encoder is numerically lossless. |
-auto-alt-ref 0 |
Disables alternate reference frames; this is the setting used for the tested alpha workflow. |
Input frame rate belongs before -i. In this example, 24 frames at 12 fps produce two seconds of video. Reading the same files at 24 fps produces one second. Neither command reconstructs the original timing of an irregularly timed sequence.
FFmpeg documents the numbering and frame-rate behavior in its image2 input documentation.
The result has no audio because the input contains only images. If you need sound, preserve it separately and align it against the final duration. Do not assume changing the frame rate will keep an existing voice track in sync.
What the real-footage test showed
The test ran on Windows with FFmpeg 8.0.1. Its input was an already processed BG Remover Online demo cutout, not a newly submitted background-removal job.
The setup extracted the first two seconds at 12 fps, resized to 640 × 360, and wrote 24 RGBA PNGs. That extraction explicitly used the libvpx VP9 decoder so the existing WebM alpha could be retained:
ffmpeg -c:v libvpx-vp9 -i podcast-after-alpha.webm -t 2 -vf "fps=12,scale=640:360" -pix_fmt rgba -start_number 1 "frames/frame_%04d.png"
Create the frames directory first. You can skip this extraction entirely when you already have your own PNG sequence. For a browser-based reverse workflow, the video to PNG sequence converter returns RGBA PNG frames in a ZIP.
After encoding, every output frame was decoded to RGBA and its alpha bytes were compared with the corresponding PNG. The result:
| Observation | Result |
|---|---|
| PNG frames read / WebM frames decoded | 24 / 24 |
| Output dimensions | 640 × 360 |
| Output frame rate / duration | 12 fps / 2.000 seconds |
| Output file size | 1,056,049 bytes |
| Alpha range in every decoded frame | 0–255 |
| Largest absolute alpha difference across all 24 frames | 1 |
| Bit-identical alpha across every frame | No |
That last row is easy to miss. On the first frame, 89,034 alpha values differed, but no value differed by more than one. The count of completely transparent pixels remained 137,838. Many near-opaque values became fully opaque.
This does not establish which internal step caused the difference, or predict another FFmpeg build's behavior. It establishes what this complete workflow produced. If your acceptance criterion is “a visible cutout with transparent surroundings,” these observations are relevant. If it is “preserve every alpha byte exactly,” this run fails that stricter requirement.
RGB equality was not tested or claimed. The requested output uses YUV 4:2:0, so preserving alpha is a separate question from retaining all source color detail.
Decode the output before trusting the metadata
First, extract a PNG with the libvpx decoder selected before the input:
ffmpeg -c:v libvpx-vp9 -i cutout.webm -frames:v 1 check.png
Open check.png in an image editor over light and dark backgrounds. For a clearer look at opacity itself, extract the alpha plane:
ffmpeg -c:v libvpx-vp9 -i cutout.webm -vf alphaextract -frames:v 1 alpha.png
In alpha.png, black means transparent, white means opaque, and gray means partially opaque. It is a grayscale diagnostic image, not a second cutout. See FFmpeg's alphaextract documentation.
In this run, ffprobe reported pix_fmt=yuv420p alongside alpha_mode=1 for a file whose decoded frames contained transparency. Therefore, that pixel-format field alone was not a reliable rejection rule. Conversely, alpha metadata alone does not establish that any pixel is actually transparent.
The control made that distinction visible. The same sequence was encoded with yuv420p, without the a. Its first decoded frame had alpha 255 everywhere: an opaque rectangle. That is the sort of output a conversion pipeline can create while still returning a playable video.
Checking the first frame is a quick diagnostic, not a whole-clip guarantee. The 24-frame comparison above inspected this entire short fixture; a longer production export needs its own inspection scope.
Put it over the actual page background
A file-level check does not answer whether the destination browser composites it correctly. Save this next to cutout.webm as preview.html:
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Transparent WebM check</title>
<style>
.stage { max-width: 640px; background: #17263d; }
.stage.light { background: #f5ead6; }
video { display: block; width: 100%; }
</style>
<button type="button" id="background">Switch background</button>
<div class="stage" id="stage">
<video controls muted loop playsinline preload="metadata"
src="cutout.webm"></video>
</div>
<script>
document.querySelector('#background').addEventListener('click', () => {
document.querySelector('#stage').classList.toggle('light');
});
</script>
</html>
Play it, switch backgrounds, and look at hair, fingers, and motion-blurred edges. A flat rectangle suggests opaque pixels or an unsupported playback path. A changing background with halos suggests a different problem: the matte or color edges need work.
Do not use CSS mix-blend-mode: screen as proof that transparency works. It can hide dark pixels while also changing the subject. A real alpha channel should composite without that workaround.
Browser support needs its own check. Chrome documents WebM alpha playback. MDN's codec guide notes that Safari does not support VP9 alpha. This experiment did not test Safari. Keep a tested fallback for browsers outside your validated path; a static transparent PNG may be enough for a decorative animation.
For an editing handoff rather than a web page, the transparent WebM to ProRes 4444 converter provides an alpha-capable MOV workflow for editing software. ProRes is an editing format, not a substitute for a tested browser delivery format. These online converters require sign-in and have usage limits; they were not part of the local FFmpeg benchmark above.
When the result still looks wrong
| Symptom | Check next |
|---|---|
| “Unknown encoder libvpx-vp9” | Use a build that includes the encoder; the filename extension cannot substitute for it. |
| Video stops earlier than expected | Check continuous numbering, the first-frame index, the encoded frame count, and input frame rate. |
| Solid background in the extracted PNG | Confirm the source PNG has alpha, the encoding requested yuva420p, and the decoding used libvpx. |
| PNG is transparent, player shows black | Test another known alpha-aware playback path before repeating background removal. |
| Dark or bright fringes around hair | Inspect the source matte and color treatment on both backgrounds. Conversion does not repair an inaccurate cutout. |
| File is too large | Evaluate a separate constant-quality encode against the lossless baseline, comparing edges and alpha as well as file size. |
For a delivery-sized experiment, a common starting point is -crf 30 -b:v 0 in place of -lossless 1. That variation was not benchmarked in the recorded run. Recheck its output rather than applying the lossless run's measurements to it.
The useful handoff is the encoded file plus a check in its destination. Keep the PNG sequence until both have passed. It is the easiest way to change the encoding later without paying for another matting pass or discarding the best source you have.
Context and reproducibility: This walkthrough accompanies the BG Remover Online project and uses its existing public demo asset. It is a conversion experiment, not an independent product comparison or a claim about all background-removal results. The recorded run was executed on November 1, 2026; its script and raw observations are retained with the draft.
AI disclosure: This article was drafted by an AI agent. The stated FFmpeg experiment was executed; browser compatibility beyond the documented references is not presented as a firsthand test.


Top comments (0)