Fix a video that plays over USB but not in the player app

8 min read · Published November 5, 2026

A video that plays from USB in a general player but shows black in the signage app is a codec profile mismatch, not a broken file. Re-encode to H.264 Constrained Baseline, Level 4.0, 1920 x 1080 at 30 fps, AAC audio in MP4, and the same file plays in both. The page includes the MediaInfo check, the FFmpeg command and the delivery checks that catch truncated or renamed copies.

A video that opens and plays from the USB stick but shows a black frame in the signage app is not a broken file. Its H.264 profile sits outside what the app's decoder accepts. The general player you used to check the stick carries its own software decoders and falls back to them. The signage app uses the decoder built into the box, and decoder silicon of the Android 4.x era commonly stops at Baseline. The fix is a re-encode to H.264 Constrained Baseline, Level 4.0, 1920 x 1080 at 30 fps, in an MP4 container with AAC audio. This page gives the check that confirms the fault, the exact command, and the follow-up checks for a file that stays black. If you are choosing the box as well as the files, the digital signage player guide covers that side.

Why does a video play over USB but show black in the app?

The file's H.264 profile sits outside what the app's decoder accepts. A High-profile stream that a gallery player decodes in software shows as a black frame in a player app that calls the decoder built into the box, and decoder silicon of that era stops at Baseline.

The two paths decode the file differently. A gallery or general media player bundles software decoders and falls back to them when the built-in path says no. A signage app asks the platform decoder for the first frame; when the decoder refuses the profile, the app gets a black frame with normal sound and keeps the playlist running. Nothing in the app is misconfigured. The profile is the problem.

H.264, the AVC codec standardized as ITU-T H.264 and MPEG-4 Part 10, writes its feature set into the stream header as a profile and a level. High profile adds B-frames and CABAC arithmetic coding, the two features that cheap decoder silicon of the Android 4.x era skips. Baseline is the subset without them, and the standard defines profiles cumulatively: any decoder that accepts Main or High must also accept Baseline. That is why Baseline is the target that plays everywhere H.264 plays, and why one file can play in software and die in the device path on the same box.

What codec should a signage video be encoded to?

Encode to H.264 Constrained Baseline, Level 4.0, 1920 x 1080 at 30 frames per second, in an MP4 container with AAC-LC audio. That profile is the subset every H.264 decoder accepts, and the level is what 1080p30 needs.

Those numbers come from the decoder side. The H.264 level tables cap macroblocks per second: Level 4.0 allows 8,192 macroblocks per frame and 245,760 per second. A 1920 x 1080 frame is 120 x 68 = 8,160 macroblocks, so the ceiling works out to 245,760 ÷ 8,160 ≈ 30 frames per second. Encoding 1080p above 30 fps needs Level 4.2, which allows about 64. A 1280 x 720 file needs only Level 3.1: its 80 x 45 = 3,600 macroblocks per frame give 108,000 ÷ 3,600 = exactly 30 fps inside that level.

The player on our panel-mount units plays MP4, M4V or WebM, and H.264 MP4 is the documented recommendation because H.265 and VP9 depend on the unit; the file rules are on the IMD Signage Player page. PowerPoint, PDF, HEIC and GIF never play, so a looping video has to come out of those as an MP4 before anything else here applies.

How do I check what a file actually is?

Read the file in MediaInfo, not by its extension. The three lines that decide this fault are Format/Profile, where High Profile at Level 4.0 fails on old boxes and Constrained Baseline at Level 4.0 plays, plus the resolution and the frame rate.

MediaInfo is a free file inspector; drop the file on it and read those lines. High Profile at Level 4.0 is the classic phone-camera output that fails on old boxes. Chroma subsampling should read 4:2:0; a 4:2:2 or 10-bit file fails even at Baseline, because the silicon never handled it. The audio line tells you whether sound survives the app path: AC3 and DTS tracks in an MP4 are what old app decoders refuse.

For the box side, a codec lister app such as Codec Info prints every decoder the device claims, with its profiles and levels. Read the H.264 decoder's list before you encode, and you encode once.

Why does the same file play on a newer box?

A newer box is not more forgiving of your file; it carries more decoders. Old Android 4.x devices usually decode H.264 Baseline only, while Android has shipped VP9 support since version 4.4 and newer silicon adds H.265.

So the same High-profile MP4 finds hardware that takes it on the new box and hardware that refuses it on the old one. Android's codec list has included VP9 since 4.4, and H.265 arrived with newer silicon, but whether a given box decodes either is chip-dependent; that is why our own spec says VP9 and H.265 support depend on the unit. Age moves the accepted profile set, not leniency.

Practical read: one file playing on the new box and failing on the old one points at profile first. A file failing on both points at the container or a truncated copy. Frame rate is the second divider: a 60 fps file the old box cannot clock shows the same black frame, so bring 1080p loops back to 30 fps. Frame rate is a content decision as well as a decoder limit; the planning signage animation frame rate article covers the content side.

What is the exact FFmpeg command to re-encode?

Run this FFmpeg command. It forces Constrained Baseline at Level 4.0, 1920 x 1080 at 30 fps, 6 Mbps video, AAC audio and a front-loaded index, and the output plays in the app and in any general player.

ffmpeg -i input.mp4 -vf scale=1920:1080 -r 30 -c:v libx264 -profile:v baseline -level 4.0 -pix_fmt yuv420p -b:v 6M -maxrate 6M -bufsize 12M -c:a aac -b:a 128k -movflags +faststart output.mp4

-profile:v baseline is the switch that matters: it makes libx264 write a Constrained Baseline stream and drops B-frames and CABAC automatically. -level 4.0 stamps the level. -pix_fmt yuv420p forces 8-bit 4:2:0 chroma, the pixel format old decoders accept. -r 30 sets the frame rate. -c:a aac rewrites an AC3 or DTS track as AAC-LC. -movflags +faststart moves the MP4 index to the front of the file, which is what app players that read the header first want.

The 6M target comes from the usual starting rule of 0.1 bits per pixel per frame: 1920 x 1080 x 30 x 0.1 = 6.2 Mbps, rounded to 6. Raise it for detailed food photography or text-heavy slides; 8 Mbps covers those.

Example: what does a fixed 40-second loop look like?

A cafe loads a 40-second food loop shot on a phone. MediaInfo reads High Profile at Level 4.0, 1920 x 1080, 30 fps with AC3 audio. The gallery plays it and the player app shows a black frame; after the re-encode above the same 31 MB file plays in both.

The fault: High Profile at Level 4.0 needs B-frames, the old box's decoder skips them, the app gets black, the gallery software-decodes. The re-encode produces this MediaInfo read on the output:

  • Format/Profile: Constrained Baseline at Level 4.0
  • Width x height: 1920 x 1080
  • Frame rate: 30 fps
  • Chroma: 4:2:0
  • Audio: AAC-LC, 128 kbps

The numbers behind the file size: 1920 x 1080 = 2,073,600 pixels; 2,073,600 x 30 fps = 62,208,000 pixels per second; 0.1 bit per pixel gives 6,220,800 bit/s, the 6 Mbps target. At 40 seconds, (6,000,000 + 128,000) bit/s x 40 s = 245,120,000 bit, and 245,120,000 ÷ 8 = 30,640,000 bytes, about 31 MB on the card. The loop holds 40 x 30 = 1,200 frames.

Decision: keep the High-profile master for editing, encode a Baseline copy per box generation, and put the copy on the card. One encode serves every screen in the building, old and new.

What if the video still shows black after re-encoding?

Re-read the output in MediaInfo first. If it says Constrained Baseline at Level 4.0 with 4:2:0 chroma, the file is right and what remains is delivery, an old copy in internal memory, a truncated file or a renamed container.

Work the symptom list in order; each entry points at one cause.

  • Black frame, sound keeps playing: the profile is still beyond the decoder; a step was skipped and the file is still High or 10-bit. Re-run the command and confirm the profile line.
  • Plays a few seconds, then stops or freezes: the copy on the card is shorter than the container claims, a truncated file; the truncated MP4 recovery guide shows what that looks like on disk and how to confirm it.
  • Images stay black too: this was never a codec fault; run the checks for a signage image not displaying on screen.
  • The app closes on the file, then the show comes back: the decoder refused the stream hard; the app is designed to recover from a stop, so a screen that returns to the show was handed a file the decoder refuses, and the file is the fix.
  • The file name ends in .mp4 but MediaInfo reads Matroska or QuickTime: a renamed container. Renaming changes nothing inside the file, and the documented playback list is MP4, M4V or WebM.

Two delivery checks close the list. Re-copy the file and compare byte sizes between stick and card; if the file plays straight off the stick but not from the card copy, the stick-side checks in the USB video playback troubleshooting article cover port, format and copy faults. Then reload the card from the player's staff menu so the internal copy of the show takes the new file, because the player keeps that internal copy and an old file keeps playing until the reload happens.

Recommendation: re-encode to H.264 Constrained Baseline, Level 4.0, 1920 x 1080 at 30 fps, AAC audio, faststart, whenever a file plays in a general player and shows black in the signage app, and verify the output in MediaInfo before it goes on the card. Use 6 Mbps for ordinary 1080p30 loops and about 8 Mbps when Baseline has to match a High-profile master. Keep gallery playback as a diagnostic only; a file that needs the gallery to play does not belong on the box.

Questions

Will converting to Baseline visibly lower the picture quality?

Baseline drops B-frames and CABAC, which reduces coding efficiency by roughly 10 to 20 percent, meaning extra bitrate for the same picture. At signage viewing distances the difference is hard to see. You get it back by raising the target: about 8 Mbps instead of 6 for a 1080p30 loop matches a High-profile master. Keep the High original as the editing master and encode the Baseline copy for the box.

Why does the video play but with no sound?

The player ships with sound off by default: videos play muted until sound is turned on in the settings, so silence over a playing picture is a setting, not a missing track. If there is still no audio after sound is enabled, the audio codec is the next suspect: AC3 and DTS tracks inside an MP4 are what old app decoders refuse, and AAC-LC at 128 kbps is the safe rewrite.

Can I use H.265 or VP9 to halve the file size?

Both depend on the decoder in the specific unit, so a file that plays on one screen can be black on the next. Android's codec list has included VP9 since version 4.4, but decoding varies by chip. For a mixed fleet of boxes, H.264 Baseline MP4 is the format that plays on all of them; test H.265 only on a single-screen deployment, with a codec lister app first.

Does the show keep going if the card is pulled or the app stops?

The player is designed to carry the show: a copy sits in internal memory, so the show carries on when the card comes out, and if the app stops it is designed to start again within seconds and go back to playing. After you replace a file on the card, reload the card from the staff menu so the internal copy takes the new file.

Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.

Keep reading

Build your signAsk for a quote