Engineering Playbook

Zero-stutter 8K loops on Tizen 6.5

A practical guide to truly seamless 8K video loops on Samsung Tizen signage: the encoding profile, muxing flags, filesystem strategy, AVPlay code and soak testing we rely on for flawless playback.

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 .json manifest 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 onstreamcompletedseekTo(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.