Goals & constraints
- Zero frame drops at 8K (7680×4320) and typical frame rates (29.97/30/50/59.94/60 fps).
- Seamless loop points with no black frame, audio click or rebuffer.
- Local playback with offline cache by default and optional network fallback.
- Operational reliability with checksums, watchdogs and crash-safe update flow.
1) Mastering the encode
For Tizen 6.5 class signage/TVs, we recommend HEVC (H.265) for 8K masters. Use constant frame rate, closed GOPs and a conservative bitrate aligned to the visual complexity of your content.
Suggested video profile
- Codec: HEVC Main10 (10-bit) if your panel pipeline supports it; otherwise Main.
- Resolution: 7680×4320.
- Frame rate: match the source (30 or 60). Keep it constant (CFR).
- Bitrate target: 60–120 Mbps for complex art; 25–60 Mbps for simpler loops.
- GOP length: 1–2 seconds (e.g. 60–120 frames @60 fps). Closed GOPs only.
- B-frames: 2–4 depending on motion; fewer can reduce decoder spikes.
- Chroma: 4:2:0 for SoC compatibility.
Audio track
- For silent loops, include a very low bit rate AAC or no audio at all to avoid priming noise.
- For music, use AAC-LC 128–192 kbps at 48 kHz and ensure perfect cut points (see Looping).
ffmpeg reference encode (HEVC 8K @60 fps, visually complex):
ffmpeg -y -r 60 -i input_8k_master.mov \
-c:v libx265 -preset slow -pix_fmt yuv420p10le \
-x265-params "level=6.2:high-tier=1:vbv-bufsize=120000:vbv-maxrate=120000:hrd=1:keyint=120:min-keyint=120:no-open-gop=1:bframes=3" \
-b:v 100M -maxrate 120M -bufsize 120M -r 60 \
-c:a aac -b:a 160k -ar 48000 -ac 2 \
-movflags +faststart -video_track_timescale 60000 \
output_8k60_hevc.mp4
Why these flags? Closed GOPs and a fixed key-interval keep decoder state predictable at the loop. VBV and HRD prevent bitrate spikes that can cause SoC frame drops. +faststart places moov at the head for instant prep.
2) Muxing for gapless loops
- Ensure the file begins on an IDR keyframe and ends exactly before the next GOP.
- For AAC, avoid encoder delay clicks at the seam by aligning audio to frame boundaries and trimming padding.
# frame-accurate, keyframe-aligned loopable segment
ffmpeg -i output_8k60_hevc.mp4 -ss 00:00:00.000 -to 00:02:00.000 \
-c copy -avoid_negative_ts make_zero loop_2min.mp4
# if you hear an audio tick at the seam, re-encode audio only with exact length
ffmpeg -i loop_2min.mp4 -c:v copy -af "atrim=0:120,asetpts=N/SR/TB,apad=pad_dur=0" loop_2min_audiofix.mp4
3) Files, caching & checksums
- Pre-cache the loop locally (internal storage) and verify integrity with a checksum.
- Keep a shadow file and swap with a temp name to avoid partial-write crashes.
- Store a small
.jsonmanifest beside the file with sha256, byte size, duration, fps and last verification timestamp.
// sample manifest (loop_2min_audiofix.mp4.manifest.json)
{
"filename": "loop_2min_audiofix.mp4",
"sha256": "<digest>",
"bytes": 158734003,
"duration_s": 120.000,
"fps": 60,
"verified_at": "2025-08-01T10:00:00Z"
}
4) Tizen app (AVPlay) setup
In a Tizen web app, use tizen.tvavplay (AVPlay) for local file playback. Below is a minimal pattern that prepares, plays and restarts on ended without visual gaps. Pin a display rectangle and add watchdogs for resilience.
const avplay = tizen.tvavplay;
const LOOP_PATH = 'wgt-private/loops/loop_2min_audiofix.mp4';
function prepareAndPlay() {
try {
avplay.open(`file://${LOOP_PATH}`);
avplay.setDisplayRect(0, 0, screen.width, screen.height);
avplay.setDisplayMethod('PLAYER_DISPLAY_MODE_FULL_SCREEN');
avplay.setTimeoutForBuffering(5 * 1000); // local files: keep small
avplay.setListener({
onbufferingstart: () => console.log('buffering...'),
onbufferingcomplete: () => console.log('buffered'),
onevent: (type, data) => console.log('event', type, data),
onstreamcompleted: () => {
avplay.seekTo(0, () => avplay.play());
},
onerror: e => {
console.error('AVPlay error', e);
restart();
}
});
avplay.prepareAsync(() => avplay.play());
} catch (e) {
console.error('prepare failed', e);
setTimeout(restart, 2000);
}
}
function restart() {
try {
avplay.stop();
avplay.close();
} catch (_) {}
prepareAndPlay();
}
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
try {
avplay.play();
} catch (_) {}
}
});
prepareAndPlay();
Not all firmwares expose identical AVPlay options; keep the loop logic in your app layer so it behaves consistently across minor versions.
5) Looping without gaps
- Video: closed GOP, keyframe at start, exact trim so the last frame ends just before the next GOP.
- Audio: for music, ensure no encoder delay — trim/pad precisely. If silent, omit audio.
- Player: handle
onstreamcompleted→seekTo(0)→play()immediately. - UI: render overlays in separate layers; avoid layout thrash at loop boundaries.
6) Soak testing & telemetry
- Run a 72-hour soak with device telemetry: frame-drop counters, CPU/GPU temperature, free storage.
- Power-cycle and network-bounce during the test; validate auto-recovery and manifest re-verification.
- Export a proof-of-play CSV with start/stop timestamps per loop and device heartbeat.
FAQs & quick fixes
Q: I see a single black frame on repeat.
A: Your loop likely cuts mid-GOP. Re-trim on a keyframe or reduce GOP to 1 s to simplify alignment.
Q: There's an audio click at the loop.
A: Re-encode audio with exact duration (no encoder delay), or omit audio for art loops.
Q: Playback stutters after 30–60 min.
A: Lower max bitrate (VBV), reduce B-frames and verify your local cache/storage speed and file integrity.