Render the main video on a SurfaceView unless object detection needs the TextureView - #114
Render the main video on a SurfaceView unless object detection needs the TextureView#114iflyhere wants to merge 1 commit into
Conversation
…the TextureView OpenIPC#108 replaced the main video SurfaceView with a TextureView so MediaPipe can grab frames via getBitmap(). That swap is unconditional, so every user pays for it even with object detection turned off: the video is no longer eligible for a hardware overlay plane and instead goes through the view hierarchy's GPU composition, which costs GPU time, power and about one frame of latency. The layout now carries both renderers and the active one is picked from the existing "od_enabled" preference: - object detection off (default) -> mainVideoSurface (SurfaceView), the pre-OpenIPC#108 behaviour - object detection on -> mainVideo (TextureView), unchanged Toggling detection in the menu swaps the renderer, which means the decoder needs a different surface. VideoPlayer.stopAndRemoveReceiverDecoder() also stops the UDP receiver and nothing restarts it, so a hot swap is not safe today; the toggle restarts the app instead, the same way the VR mode toggle already does. startObjectDetectionLoop() bails out if the TextureView is not the active renderer.
PR Summary by QodoUse SurfaceView unless object detection requires TextureView
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
1. Restart can lose toggle
|
| if (!isVRMode && enabled != videoUsesTextureView) { | ||
| Toast.makeText(this, "Restarting to switch video renderer...", Toast.LENGTH_SHORT).show(); | ||
| resetApp(); |
There was a problem hiding this comment.
1. Restart can lose toggle 🐞 Bug ☼ Reliability
The new renderer-switch branch calls resetApp() immediately after od_enabled was saved with asynchronous apply(), and resetApp() terminates the process with System.exit(0). If the disk write has not completed, the relaunched activity reads the old value and selects the old renderer, so the user's toggle appears to fail.
Agent Prompt
## Issue description
The renderer restart can terminate the process before the asynchronous `od_enabled` preference write reaches disk, causing the app to restart with the old renderer.
## Issue Context
`resetApp()` immediately starts a fresh task and calls `System.exit(0)`. The existing VR restart path uses synchronous `commit()` before invoking the same reset helper.
## Fix Focus Areas
- app/src/main/java/com/openipc/pixelpilot/VideoActivity.java[2004-2013]
- app/src/main/java/com/openipc/pixelpilot/VideoActivity.java[202-210]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| videoUsesTextureView = getSharedPreferences("general", MODE_PRIVATE) | ||
| .getBoolean("od_enabled", false); |
There was a problem hiding this comment.
2. Disabled detection keeps textureview 🐞 Bug ➹ Performance
setupStandardVideoPlayer() selects the TextureView solely from the persisted flag before onResume() validates runtime and model availability. When that validation disables object detection, it returns without switching or restarting the renderer, leaving the expensive TextureView active for the entire session even though detection is off.
Agent Prompt
## Issue description
Startup can select the TextureView from a stale enabled preference and then automatically disable object detection without returning to the SurfaceView.
## Issue Context
This occurs when a previously enabled model is no longer available or the object-detection runtime is unsupported. The early validation failure clears `od_enabled` but does not execute the new renderer-mismatch restart branch.
## Fix Focus Areas
- app/src/main/java/com/openipc/pixelpilot/VideoActivity.java[389-400]
- app/src/main/java/com/openipc/pixelpilot/VideoActivity.java[1988-2001]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Note
Compile tested only (arm64-v8a + armeabi-v7a). Not yet flown. Object detection
itself is unchanged by this PR, but the renderer switch path deserves a check
on hardware.
The problem
#108 changed the primary renderer from a
SurfaceViewto aTextureView:That is needed for the feature —
TextureView.getBitmap()is how frames reachMediaPipe — but the swap is unconditional. Users with object detection off, i.e.
everybody by default, now get the
TextureViewpath too.The difference is not cosmetic. A
SurfaceViewgets its own layer and can bepromoted to a hardware overlay plane: the decoder writes into it and the display
controller scans it out. A
TextureViewis drawn as part of the view hierarchy,so every decoded frame has to go through GPU composition together with the rest
of the UI. That costs GPU time, power, and roughly one frame of extra latency,
on a receiver whose whole point is low latency.
The change
The layout carries both renderers and the active one is picked from the existing
od_enabledpreference:mainVideoSurface(SurfaceView)mainVideo(TextureView)Details:
setupStandardVideoPlayer()selects the view and records the choice invideoUsesTextureViewsetupVRVideoPlayers()hides both, as beforeonVideoRatioChanged()keeps the aspect ratio of the new view in syncstartObjectDetectionLoop()bails out unless theTextureViewis the activerenderer, so
getBitmap()is never called on the wrong viewWhy the toggle restarts the app
Switching detection on or off means the decoder needs a different surface.
VideoPlayer.stopAndRemoveReceiverDecoder()also callsstop(), which tearsdown the UDP receiver, and nothing restarts it — only
onResume()callsstart(). So a hot surface swap silently kills reception today. Rather thanrework the receiver lifecycle in this PR, the toggle calls
resetApp(), thesame thing the existing VR mode toggle does, and says so with a toast.
Fixing
VideoPlayer's receiver/decoder lifecycle so the surface can be swappedin place would be a good follow-up; it would also let VR mode be toggled without
a restart.
Part of a small series of independent fixes found while profiling the receive path.
Each one is standalone and mergeable on its own, in any order — no dependencies
between them, and no shared files except
VideoActivity.java/VideoPlayer.*,which touch different methods:
All five compile clean for arm64-v8a + armeabi-v7a.