WhatsApp video: H.264 High profile with B-frames fails on Android

WhatsApp Cloud API says H.264 High profile with B-frames is unsupported on Android and recommends Main or Baseline. What Sume trim does and does not promise.

5 min readSume
All posts

A WhatsApp video can play on iPhone and fail on Android if it is H.264 High profile with B-frames. Meta's Cloud API media page says WhatsApp supports H.264 video and AAC audio, with a single audio stream or none, and a 16 MB limit for .mp4 and .3gp; it adds that the High profile with B-frames is unsupported on Android clients and recommends Main or Baseline (read 2026-10-03). Sume's video trim, in its default exact mode, re-encodes with libx264 and yuv420p, but its docs do not name a profile or B-frame setting, so you cannot assume the output meets that advice.

The way to handle that gap is to measure, not guess. Here is what is known, what is not, and a safe workflow.

What Meta's page says

The video rows are short. Supported types are 3GPP (.3gp, video/3gpp) and MP4 (.mp4, video/mp4), each with a 16 MB limit. Codecs are H.264 for video and AAC for audio, and the audio must be a single stream or absent. The page then gives the Android caveat about the High profile with B-frames and recommends Main or Baseline (read 2026-10-03). Images are JPEG and PNG up to 5 MB, and stickers are WebP only.

WhatsApp video rows from Meta, read 2026-10-03, with Sume's documented behaviour
RequirementMeta's pageSume video trim docs
ContainerMP4 or 3GPMP4 output
Video codecH.264exact re-encodes with libx264, yuv420p
Audio codecAAC, one stream or noneexact remuxes kept audio as AAC; drop removes it
Size16 MB per fileNo size field; measure the result
ProfileMain or Baseline recommended; High with B-frames unsupported on AndroidNot stated, so verify

What trim gives you, and what it does not

Video trim has two precision modes. exact, the default, is a frame-accurate re-encode with libx264 and yuv420p; AAC audio is kept or dropped with audio. keyframe copies the stream, so the profile and B-frames of the source pass through unchanged. That makes exact the better choice for conforming, and keyframe the wrong one if your source is High profile. The docs do not publish the profile or the B-frame setting of the exact output, and they reject client codec and crf fields, so you cannot request Main or Baseline.

Test on real devices. Send the trimmed file to an Android phone through a test number and see whether it plays, and measure its size first. The script below cuts 20 seconds at 720 x 1280 with exact precision, keeps AAC audio, and prints the byte size against 16 MB. A short vertical clip at that size usually fits well inside the limit, but the number is yours to check.

import os, time, requests
BASE = "https://api.sume.com"
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}

def run(path, body, key):
    r = requests.post(BASE + path, headers={**H, "Idempotency-Key": key}, json=body)
    r.raise_for_status()
    job = r.json()["request_id"]
    while True:
        s = requests.get(f"{BASE}/v1/jobs/{job}/status", headers=H).json()["status"]
        if s in ("completed", "failed", "canceled"):
            break
        time.sleep(3)
    return s, (requests.get(f"{BASE}/v1/jobs/{job}/result", headers=H).json() if s == "completed" else None)

status, res = run("/v1/video-trim", {
    "video_url": "https://media.sume.com/artifacts/artf_demo/promo.mp4",
    "start": 0, "duration": 20, "precision": "exact",
    "output": {"width": 720, "height": 1280, "fps": 30}}, "wa-cut-001")
if res:
    size = int(requests.head(res["video_url"], allow_redirects=True).headers["Content-Length"])
    print(res["video_url"], size, "OK" if size <= 16 * 1024 * 1024 else "over 16 MB")
else:
    print(status)

The audio and size rules are easier

Meta's page asks for a single audio stream or none. A trim in exact mode produces one AAC audio track when audio is kept, and none when audio is drop, so that rule is covered by the documented behaviour. If your source has more than one audio track, such as a commentary track, test the result before you trust it, because the Sume docs do not describe how extra tracks are handled.

The 16 MB limit is the one that most often catches teams. A 20-second clip at 720 x 1280 and 30 fps is likely to fit, but a 60-second clip with fast motion may not. Reduce duration, lower output to 540 x 960, or drop to 24 fps and measure again. Sume has no bitrate field, so these three levers are what you have, and each retry is a separate job at $0.02 under the public rate (confirm in GET /v1/catalog).

A safe workflow

Run the cut, download it, and play it on an Android device before you send it to customers. If it fails there, you have two choices: re-encode it with a tool that lets you set the profile, or send a link instead of an attachment. Keep a note of which source and settings played correctly, so the next batch follows the same path.

Sume's video inspect returns probe facts for a hosted clip. The docs on that page do not list a profile field, so read the probe it returns for your file and see whether it reports the codec profile; if it does not, an external probe is the way to check.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume