Contributions to this page are welcome!
How media works on a TV before you write any code: which formats it takes, who does the decoding, and how video and your UI end up on screen together.
Media covers the APIs and how to call them.
What a TV Accepts
LG publishes the list itself, in Video and Audio Specifications. Start there for what a TV claims to accept. This page is for the rest: what that list leaves out, and the files a TV takes on paper and refuses in practice.
Hardware and Software Decoding
Use the hardware decoder. A TV has a capable one, and a slow CPU beside it.
Decoding in software is a last resort, not a fallback you can lean on. For anything at real size and frame rate it will not keep up, and what you get is dropped frames and audio that drifts away from the picture. If the hardware decoder refuses your file, the answer is usually to re-encode into something it accepts, not to decode it yourself.
Changing the Video Size Restarts the Pipeline
The dimensions of a stream are not a property you can set on the fly. Changing them means tearing the pipeline down and building it again, so expect a visible gap in playback each time.
Keep it away from anything that fires often. A resize driven by every layout change will stall playback rather than adjust it.
Video and the UI Are Separate Layers
The TV composites video on its own layer, underneath the UI layer. Your window never draws the picture. It sits on top of it.
So you have to punch a hole. Leave the region where the video belongs fully transparent, and the compositor shows the video layer through it. Paint an opaque background there instead and you cover the video completely, while playback runs on happily and reports nothing wrong. A player with sound and no picture is usually this and not a decoding fault.
Media has the calls that tell the compositor which rectangle the video gets.
Troubleshooting
Nothing Appears, but the Sound Is There
Start with the layering above. The video is behind your UI, so anything opaque where the video belongs hides it, and the pipeline reports no error at all.
For a GL app there is a step before that. A surface with no alpha channel has nothing to be transparent with, whatever you draw. Ask for one before you make the window:
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
/* then SDL_CreateWindow */
SDL only adds EGL_ALPHA_SIZE to the EGL config when that attribute is non-zero, and it
defaults to zero, so leaving it out costs you the alpha channel quietly. Clear with a
transparent colour as well, glClearColor(0, 0, 0, 0), or you fill the hole with opaque
black on the first frame.
If the layering is right and only some sources go black, look at the codec level. webOS declares H.265 up to level 5.1 on 4K models, and 5.2 is accepted in practice. Some models hold to that and refuse anything above it. The decoder takes your stream, returns nothing, and reports no error, so it looks exactly like the two causes above.
AMD's AMF encoder defaults to H.265 level 6.2, which is how this usually turns up. moonlight-tv#355 tracks it, on 4K models from 2021 to 2023. Encode at a level the TV declares. Dropping to H.264 also clears it, at a cost.
The App Crashes During Playback
Suspect threading and timing before anything else. The pipeline runs on its own threads and you are feeding it from yours.
Do not go looking for the decoded frames. You hand the pipeline encoded data, NALUs for
H.264 and the equivalent for anything else, and the TV decodes and draws it on its own
layer. Every webOS backend in SS4S reports SS4S_VIDEO_CAP_OUTPUT_DIRECT, which means
exactly that: it renders to its own sink, and there is no frame callback to attach. Nothing
gives you the decoded picture back.
Note
The specific traps here are not written up yet. If you have chased a crash down to a particular ordering or a particular thread, the page needs it.