diff --git a/app/src/main/java/com/openipc/pixelpilot/VideoActivity.java b/app/src/main/java/com/openipc/pixelpilot/VideoActivity.java index 7261f9ac..1dfea649 100644 --- a/app/src/main/java/com/openipc/pixelpilot/VideoActivity.java +++ b/app/src/main/java/com/openipc/pixelpilot/VideoActivity.java @@ -202,6 +202,10 @@ public static String bytesToHex(byte[] bytes) { } private void resetApp() { + // Finalize an active recording first. System.exit() below skips every lifecycle + // callback, and the MP4 is only closed when the DVR thread exits; stopDvr() joins + // it. No-op when nothing is recording. + stopDvr(); // Restart the app Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName()); if (intent != null) { @@ -685,6 +689,11 @@ private void setupBandwidthSubMenu(PopupMenu popup) { * "Low latency" sets the MediaCodec low-latency and realtime-priority keys. It is on * by default; decoders that misbehave with those keys can be put back on the stock * pipeline here. + * + * The keys are only applied when the codec is configured, and the codec is only torn + * down when its surface goes away, not on a channel change or on VideoPlayer + * stop()/start(). So the toggle restarts the app, the same way the VR mode toggle + * does, instead of promising an "on next video start" that never comes. */ private void setupVideoSubMenu(PopupMenu popup) { SubMenu videoMenu = popup.getMenu().addSubMenu("Video"); @@ -695,13 +704,13 @@ private void setupVideoSubMenu(PopupMenu popup) { lowLatencyItem.setOnMenuItemClickListener(item -> { boolean enabled = !item.isChecked(); item.setChecked(enabled); + // commit(), not apply(): resetApp() ends the process with System.exit() + // before an asynchronous write would be flushed. getSharedPreferences("general", MODE_PRIVATE).edit() - .putBoolean("low_latency_decoder", enabled).apply(); - videoPlayer.setLowLatency(enabled); - Toast.makeText(this, "Low latency " + (enabled ? "enabled" : "disabled") - + ", applies on next video start.", Toast.LENGTH_SHORT).show(); + .putBoolean("low_latency_decoder", enabled).commit(); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); item.setActionView(new View(this)); + resetApp(); return false; }); } diff --git a/app/videonative/src/main/cpp/helper/AndroidMediaFormatHelper.h b/app/videonative/src/main/cpp/helper/AndroidMediaFormatHelper.h index bc3ffa9d..1cda3190 100644 --- a/app/videonative/src/main/cpp/helper/AndroidMediaFormatHelper.h +++ b/app/videonative/src/main/cpp/helper/AndroidMediaFormatHelper.h @@ -37,7 +37,6 @@ static void h264_configureAMediaFormat(KeyFrameFinder& kff, AMediaFormat* format // AMediaFormat_setInt32(format,AMEDIAFORMAT_KEY_FRAME_RATE,60); // AVCProfileBaseline==1 // AMediaFormat_setInt32(decoder.format,AMEDIAFORMAT_KEY_PROFILE,1); - // AMediaFormat_setInt32(decoder.format,AMEDIAFORMAT_KEY_PRIORITY,0); } static void h265_configureAMediaFormat(KeyFrameFinder& kff, AMediaFormat* format) diff --git a/app/videonative/src/main/java/com/openipc/videonative/VideoPlayer.java b/app/videonative/src/main/java/com/openipc/videonative/VideoPlayer.java index e1c49d0f..1545689e 100644 --- a/app/videonative/src/main/java/com/openipc/videonative/VideoPlayer.java +++ b/app/videonative/src/main/java/com/openipc/videonative/VideoPlayer.java @@ -133,6 +133,7 @@ public boolean isRunning() { * Takes effect the next time the decoder is configured. */ public void setLowLatency(boolean enabled) { + verifyApplicationThread(); nativeSetLowLatency(nativeVideoPlayer, enabled); }