Douyin ad first frame: black at most 60%, check with stills
Douyin in-feed ads need a first frame that is at most 60% black. Pull stills from your render with Sume video inspect and measure the first frame before upload.

Douyin in-feed ad video needs a first frame that is no more than 60% black, and you can check that before upload by pulling the first frame from your render with Sume video inspect and measuring it yourself. The figures below come from a secondary summary of the Oceanengine ad platform, so confirm them on the live page.
The requirements as summarized
| Item | Requirement |
|---|---|
| Size | 540x960 |
| File size | Up to 500 MB |
| Length | 5-60 s |
| Audio | Needs background music |
| First frame | Black at most 60% |
Get the first frame as a still
Video inspect reads one clip already on media.sume.com and never re-encodes it. Pass frames with at set to [0] to get the still at time zero as a durable image artifact. The route defaults to sync mode and needs an Idempotency-Key. Import the clip first with the media import route; off-host URLs are rejected.
Set frames.max_edge to the source edge when you want an unscaled still; the default max edge is 768.
curl -X POST https://api.sume.com/v1/video-inspect \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: douyin-first-frame-001" \
-d '{
"video_url": "https://media.sume.com/artifacts/artf_demo/ad.mp4",
"frames": { "at": [0], "format": "png", "max_edge": 960 }
}'Measure the black share
The platform's definition of black is not in the summary I read, so the threshold below is my own assumption: a pixel counts as black when its luma is under 16 of 255. It tells you whether you are near the limit; it is not the platform's verdict. The script needs Pillow.
from PIL import Image
def black_share(path: str, luma_max: int = 16) -> float:
px = list(Image.open(path).convert('L').getdata())
return sum(1 for v in px if v < luma_max) / len(px)
share = black_share('first_frame.png')
print(f'{share:.1%} black', 'OK' if share <= 0.60 else 'too dark')Fix the size and the music in one render
Timeline 1.0 takes output width and height as even integers from 256 to 2160, so 540 by 960 is a valid output. A soundtrack field adds a music bed. The default output is 1080 by 1920, so set the output explicitly. Timeline costs $0.10 per output minute, and the docs say to confirm live in the catalog.
If the first frame is too dark, put a bright title card or product still as the first slot, since stills are static holds.
Sources
Related posts
More in Media tools
- Edits carousels: four matching images per call
Instagram Edits now supports carousels, per secondary reports. Sume image models with an n range of 1-4 return up to four matching images per request.
- Faithful vs generative upscale: which to pick
The key question for any upscaler is whether it may invent detail. Compare Real-ESRGAN and SeedVR scale ranges, then run a test through Sume's upscale tools.
- FTC insider reviews: burn the disclosure into the clip
FTC rule section 465.5 requires a clear and conspicuous disclosure of insider reviews. Burn a disclosure line into the clip with Sume's video captions cues.
- Gemini 3.8 Flash TTS voices for a Sume Timeline cut
Gemini 3.8 Flash TTS went GA with voice design and replication. How to bring a voiceover into Sume as the Timeline audio spine, or make it with tts_create.
Written by Sume