Skip to content

Smooth DVR playback: native-rate playback (true 720p90 / 1080p60) via the live-video display path#618

Closed
bob9 wants to merge 2 commits into
hd-zero:mainfrom
bob9:dvr-smooth-playback
Closed

Smooth DVR playback: native-rate playback (true 720p90 / 1080p60) via the live-video display path#618
bob9 wants to merge 2 commits into
hd-zero:mainfrom
bob9:dvr-smooth-playback

Conversation

@bob9

@bob9 bob9 commented Jul 16, 2026

Copy link
Copy Markdown

DVR recordings of 60 and 90 fps flights judder on playback because the menu UI drives the panel at 1080p50 while the recording's frames arrive at 60/90 fps. This PR plays them at their native rate: 90 fps recordings at true 720p90 (every frame shown), 60 fps at 1080p60.

Why v2 looks nothing like v1

The first version of this PR retimed the display on the FPGA's UI input path. Hardware bring-up falsified that approach: on both goggle generations the UI path only ever locks 1080p50 — every recipe tried (bare vdpo retime, clock phases, MFPGA setups, OLED timing sets) produced an unlocked panel. I closed the PR, built an in-firmware display bench, and found the route that works: enter the genuine live-video display mode and let the decoded video ride the vdpo overlay plane — the same path the OSD uses in race mode every day.

What's here

  • ts_probe: the platform demuxer reports 0 fps for every goggle TS recording, which silently disabled any retime. Derive the frame rate from video PES PTS spacing instead (validated against 92 real DVR files plus synthetic 90/60/59.94/50/30, B-frame, truncated and junk streams).
  • goggles2 (hardware-verified): 90 fps → 720p90 with the VO layer sized 1280x720; 60 fps → video-path 1080p60, pixel-perfect.
  • goggle v1 (hardware-verified), with two v1-specific findings baked in:
    • the DE wraps a 1920-stride framebuffer at the 720p90 mode's 1280-wide scanout, so the UI re-renders at 1280x720 for the duration (exactly like the race OSD does);
    • the FPGA idles its video input on a green raster and its overlay chroma-key punches near-black pixels through to it — one receiver init per boot leaves a black mute raster behind the key, after which the receiver stays off for playback (prewarmed in the background while the user browses the file list, so no start-up penalty).
  • boxpro: UI already runs 720p60 — no-op stubs.
  • Playback UX: control bar auto-hides after 4 s and wakes on dial input, positioned inside the visible 720p90 window; unplayable files show an explanation instead of a silent black screen; thumbnails load straight off the card (the /tmp staging overflows its tmpfs past a few dozen recordings and silently degrades previews to placeholder icons).
  • Bring-up tooling, kept on purpose: right-click during playback steps an on-hardware display bench (how both goggles were verified), and display/receiver transitions plus playback stalls append to a log on the SD card. Cheap, and invaluable for field diagnosis — happy to gate either behind a build flag if preferred.
  • MP4 stays on the stock display path deliberately; TS-only retiming.

Credit

The live-video-path architecture and the goggles2 verification are @bolagnaise's work; the goggle v1 bring-up, probe validation and playback UX were done on this side. Field-tested on real race footage on both goggle generations.

bob9 added 2 commits July 16, 2026 13:02
DVR playback on the goggles dropped frames badly for two reasons:

- The menu UI drives the panel at 1080p50, so 60fps DVR files lost 10
  frames a second in an uneven 6:5 cadence and 90fps race files lost 40.
  The player now reads the file's frame rate from the demuxer and
  retimes the UI output to 1080p60 for the duration of playback (same
  148.5MHz pixel clock, so OLED/FPGA settings stay valid), restoring
  1080p50 on exit. 90fps files fall into an even 3:2 pulldown, the best
  the panel path can do.

- The recorder muxed with a 1/fps stream time base, rounding every
  capture timestamp to a whole frame slot and baking judder into the
  file (the reason behind the "fps=59 or DVR is wrong" workaround).
  Streams are now muxed on the standard 90kHz clock so timestamps stay
  exact; this also makes recordings play smoother on PCs.
Follow-up to the playback smoothing fix: instead of playing 90fps race
DVR at 60Hz with a 3:2 pulldown, the player now retimes the output to
720p90 while the file plays, showing every frame.

The menu stays at 1080p for browsing; starting a 90fps file switches
the vdpo output to 720p90 reusing the timing, clock phases and OLED
mode already proven by the live 720p90 path, and the video surface is
sized 1280x720 to fill it. Exiting the player restores the stock menu
timing with a full Display_UI_init. 60fps files keep the lighter
1080p60 retime on the same pixel clock.

The retime decision moved from ui_player into the media engine, since
the video output rect has to be sized before the decoder pipeline is
prepared; failure paths restore the menu timing too.
@bob9

bob9 commented Jul 19, 2026

Copy link
Copy Markdown
Author

closing to do some more testing

@bob9 bob9 closed this Jul 19, 2026
@bob9 bob9 changed the title Smooth DVR playback: match display refresh to the file (true 90fps at 720p90) and stop quantizing recorder timestamps Smooth DVR playback: native-rate playback (true 720p90 / 1080p60) via the live-video display path Jul 20, 2026
@bob9

bob9 commented Jul 20, 2026

Copy link
Copy Markdown
Author

Superseded by #619 - same branch, rewritten after hardware bring-up on both goggle generations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant