diff --git a/app/src/main/java/com/openipc/pixelpilot/VideoActivity.java b/app/src/main/java/com/openipc/pixelpilot/VideoActivity.java index 0c17d62f..a3588f17 100644 --- a/app/src/main/java/com/openipc/pixelpilot/VideoActivity.java +++ b/app/src/main/java/com/openipc/pixelpilot/VideoActivity.java @@ -134,6 +134,9 @@ public void run() { private Timer recordTimer = null; private int seconds = 0; private boolean isVRMode = false; + // Which view the main video is rendered into. SurfaceView is the low latency + // default; the TextureView is only used when object detection needs getBitmap(). + private boolean videoUsesTextureView = false; private ConstraintLayout constraintLayout; private ConstraintSet constraintSet; private WfbNgLink wfbLink; @@ -395,6 +398,7 @@ private void initializeVideoPlayers() { */ private void setupVRVideoPlayers() { binding.mainVideo.setVisibility(View.GONE); + binding.mainVideoSurface.setVisibility(View.GONE); binding.surfaceViewLeft.getHolder().addCallback(videoPlayer.configure1(0)); binding.surfaceViewRight.getHolder().addCallback(videoPlayer.configure1(1)); } @@ -405,7 +409,30 @@ private void setupVRVideoPlayers() { private void setupStandardVideoPlayer() { binding.surfaceViewRight.setVisibility(View.GONE); binding.surfaceViewLeft.setVisibility(View.GONE); - binding.mainVideo.setSurfaceTextureListener(videoPlayer.configureTextureView(0)); + + // Object detection reads frames back with TextureView.getBitmap(), which forces + // the video through the view hierarchy's GPU composition. Without it a + // SurfaceView is used so the video stays on a hardware overlay plane. + // + // The preference alone is not enough: setObjectDetectionEnabled() turns detection + // back off in onResume when the runtime or the selected model is missing, and returns + // before the renderer swap - which would leave the session on the TextureView with + // nothing reading from it. Both checks are cheap when od_enabled is false, and when + // it is true the runtime check only loads a library that is about to be used anyway. + videoUsesTextureView = getSharedPreferences("general", MODE_PRIVATE) + .getBoolean("od_enabled", false) + && isObjectDetectionRuntimeSupported() + && isSelectedObjectDetectionModelAvailable(); + + if (videoUsesTextureView) { + binding.mainVideoSurface.setVisibility(View.GONE); + binding.mainVideo.setVisibility(View.VISIBLE); + binding.mainVideo.setSurfaceTextureListener(videoPlayer.configureTextureView(0)); + } else { + binding.mainVideo.setVisibility(View.GONE); + binding.mainVideoSurface.setVisibility(View.VISIBLE); + binding.mainVideoSurface.getHolder().addCallback(videoPlayer.configure1(0)); + } } // ---------------------------------------------------------------------------- @@ -1602,6 +1629,7 @@ public void onVideoRatioChanged(final int videoW, final int videoH) { Log.d(TAG, "Set resolution: " + videoW + "x" + videoH); updateViewRatio(R.id.mainVideo, lastVideoW, lastVideoH); + updateViewRatio(R.id.mainVideoSurface, lastVideoW, lastVideoH); updateViewRatio(R.id.surfaceViewLeft, lastVideoW, lastVideoH); updateViewRatio(R.id.surfaceViewRight, lastVideoW, lastVideoH); } @@ -2043,7 +2071,19 @@ private void setObjectDetectionEnabled(boolean enabled) { } isObjectDetectionEnabled = enabled; - prefs.edit().putBoolean("od_enabled", enabled).apply(); + // commit(), not apply(): the restart below ends the process with System.exit() + // before an asynchronous write would be flushed, and the renderer picked on the + // next launch is read from exactly this value. + prefs.edit().putBoolean("od_enabled", enabled).commit(); + + // Enabling / disabling detection swaps the main video renderer. Handing the + // decoder a different surface at runtime would need the receiver lifecycle in + // VideoPlayer reworked, so restart instead - same as the VR mode toggle does. + if (!isVRMode && enabled != videoUsesTextureView) { + Toast.makeText(this, "Restarting to switch video renderer...", Toast.LENGTH_SHORT).show(); + resetApp(); + return; + } if (enabled) { binding.detectionOverlay.setVisibility(View.VISIBLE); @@ -2064,6 +2104,7 @@ private void restartObjectDetector() { private void startObjectDetectionLoop() { if (isVRMode) return; // Standard mode only + if (!videoUsesTextureView) return; // getBitmap() needs the TextureView renderer if (objectDetectionExecutor == null) { objectDetectionExecutor = Executors.newSingleThreadExecutor(); } diff --git a/app/src/main/res/layout/activity_video.xml b/app/src/main/res/layout/activity_video.xml index cabe29e6..8aa7e519 100644 --- a/app/src/main/res/layout/activity_video.xml +++ b/app/src/main/res/layout/activity_video.xml @@ -5,10 +5,24 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + +