Pi-Desktop

10-bit VP9 frame loss on RK3588

The MPP video library bundled with jellyfin-ffmpeg silently drops about 30 % of a long 10-bit VP9 transcode on RK3588 boards. One reverted line causes it. Measured 3 October 2026 on an Orange Pi 5B; nobody outside this bench has reproduced it yet, and that is the thing this page is asking for.

Bar chart: frames missing per five minutes of a 100-minute 4K 10-bit VP9 title. Jellyfin's bundled library loses nothing for the first forty minutes, then 3,000 to 4,400 frames of every 7,200 for the rest of the title. An upstream-lineage library loses none at any point.
Same board, same 100-minute 4K 10-bit VP9 title, same afternoon. Orange, Jellyfin's bundled MPP: 100,131 frames of 143,641. Green, an upstream-lineage MPP: all of them.

What a user sees

A long title transcodes perfectly for about forty minutes, then starts freezing for up to six seconds at a time, repeatedly, for the rest of playback. Nothing appears in the Jellyfin log. ffmpeg reports no errors and exits cleanly. The container's timestamps still span the full runtime, so the player shows the correct duration with holes in it. It looks exactly like a bad file or a failing disk.

Underneath, the video decoder is faulting and the kernel is resetting it hundreds of times a minute. Frames decoded during each reset are never produced, and nothing in the API says so.

The cause: one reverted line

Rockchip disabled parallel VP9 decode for the RK3588 upstream in August 2023, in hal_vp9d. The fork of MPP that jellyfin-ffmpeg builds from reverts that guard:

         cfg->support_fast_mode = 1;
         if (mpp_get_soc_type() == ROCKCHIP_SOC_RK3588)
-            cfg->support_fast_mode = 0;      // upstream: one decode task at a time
+            cfg->cfg->status.hal_task_count = 2;  // fork: two, across both decoder cores

That is the only behavioural change to the VP9 decoder among the eleven commits the fork carries above upstream. jellyfin-ffmpeg pins it in builder/scripts.d/50-rkmpp.sh, identically on 7.1.4-3 and every 8.x release including the current one.

The guard is VP9-specific on purpose

Worth stating, because it rules out the obvious alternative — that the chip simply cannot decode two things at once. It can, for HEVC. Every H.265 path in MPP enables parallel decode on this SoC with no exception, in both upstream and the fork. VP9 is the only codec Rockchip guards here. The measurements agree: HEVC Main 10 ran 70,464 frames clean, zero resets, on the very library that fails on VP9 at around 65,000.

Measurements

Decoder pathInputFrames out / inResetsWhat ffmpeg said
jellyfin-ffmpeg 8.1.3-1, bundled MPPsynthetic 1080p60 VP9 Profile 2, 72,600 frames71,382 / 72,60070“0 decode errors”, exit 0
system ffmpeg → VA-API → upstream-lineage MPPthe same clip72,600 / 72,6000clean, exit 0
jellyfin-ffmpeg 8.1.3-1, full pipeline to a filereal 4K24 VP9 Profile 2 title, 143,641 frames100,131 / 143,64111,5200 error lines, exit 0
system ffmpeg → VA-API → upstream-lineage MPPthe same title143,641 / 143,6410clean, exit 0

All on one Orange Pi 5B, RK3588S, Armbian vendor kernel 6.1.172, both decoder cores verified evenly loaded. The failure begins after roughly 65,000 frames in a single job: about 18 minutes at 60 fps, about 45 at 24. Short items never reach it, because every job starts a fresh decoder.

The synthetic clip matters: it is a testsrc2 pattern at 1080p, so the trigger is the number of frames decoded in one session — not 4K, not HDR metadata, not any particular file.

Not affected

HEVC Main 10, 8-bit H.264 and VP9, direct play (which never touches the server's decoder), and anything short. VP9 Profile 2 sources are mostly YouTube-origin HDR downloads, which is why libraries rarely hit this and why it looks like a bad file when they do.

Reproduce it in ten minutes

Any RK3588 board with jellyfin-ffmpeg and a 10-bit VP9 file longer than about 20 minutes. To make one:

ffmpeg -f lavfi -i "testsrc2=size=1920x1080:rate=60:duration=1210,format=yuv420p10le" \
       -c:v libvpx-vp9 -profile:v 2 -pix_fmt yuv420p10le -deadline realtime \
       -cpu-used 8 -row-mt 1 -b:v 1500k test.webm

Then watch the kernel while it decodes:

sudo journalctl -k --since now -f | grep --line-buffered 'resetting for err' &
/usr/lib/jellyfin-ffmpeg/ffmpeg -c:v vp9_rkmpp -i test.webm -an -f null -

Compare the final frame= against the file's real frame count (ffprobe -count_packets -select_streams v:0 -show_entries stream=nb_read_packets test.webm). On an affected build the resets begin partway through and the count comes up short. On an unaffected MPP the numbers match and nothing is printed.

A negative result is just as useful. If your board stays silent and the frame counts match, please say so — everything on this page was measured on one bench, by one person, and that is its main weakness.

Fix and workaround

Scope beyond Jellyfin

The same revert is carried by the two Ubuntu PPAs most RK3588 desktop images use for MPP, so browsers and players on those images meet it too during long 10-bit VP9 playback — YouTube HDR at 4K60 reaches the threshold in about eighteen minutes. Pi-Desktop 4.0 ships an upstream-lineage MPP with the guard intact and is not affected; that is the green line in the chart.

Reports and corrections

Filed as jellyfin/jellyfin-ffmpeg#765 and rockchip-linux/mpp#972. The first could not be reproduced by the maintainer and was closed; upstream MPP is not at fault, so the second was closed too. An earlier version of my evidence table had two mislabelled rows; both issues now carry a correction, and the corrected figures are the ones on this page.

Logs, the test scripts, the frame-gap analysis and frame grabs from either side of the failure are available on request.