Fix RCO menu coordinates and smooth video pacing
RCO object positions are screen-center with +Y up, but the renderer drew them as top-left, pushing menu items off-screen. Convert to top-left in the 480x272 design space before drawing. Also use precise parkNanos pacing and reuse per-frame ARGB/WritableImage buffers to remove the 1.4MB allocations per video frame.
This commit is contained in:
@@ -35,6 +35,7 @@ import javax.sound.sampled.SourceDataLine;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
/** JavaFX application entry point for the UMD player. */
|
||||
public final class PlayerApp extends Application {
|
||||
@@ -60,6 +61,10 @@ public final class PlayerApp extends Application {
|
||||
private volatile long clockOffsetNanos = 0;
|
||||
private long pauseStartNanos = 0;
|
||||
|
||||
private final WritableImage[] videoImages = new WritableImage[2];
|
||||
private final int[][] argbBuffers = new int[2][];
|
||||
private int videoBufferIndex = 0;
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) {
|
||||
// Gradle's --args splits on whitespace; rejoin so paths with spaces work.
|
||||
@@ -197,11 +202,17 @@ public final class PlayerApp extends Application {
|
||||
|
||||
PlaybackEngine.VideoFrame frame;
|
||||
while ((frame = engine.nextVideoFrame()) != null) {
|
||||
int[] argb = YuvConverter.yuvj420ToArgb(frame.width(), frame.height(),
|
||||
int index = videoBufferIndex++ & 1;
|
||||
int[] argb = argbBuffers[index];
|
||||
int pixelCount = frame.width() * frame.height();
|
||||
if (argb == null || argb.length < pixelCount) {
|
||||
argb = argbBuffers[index] = new int[pixelCount];
|
||||
}
|
||||
YuvConverter.yuvj420ToArgb(frame.width(), frame.height(),
|
||||
frame.yPlane(), frame.yStride(),
|
||||
frame.uPlane(), frame.uStride(),
|
||||
frame.vPlane(), frame.vStride());
|
||||
blitVideo(argb, frame.width(), frame.height());
|
||||
frame.vPlane(), frame.vStride(), argb);
|
||||
blitVideo(argb, index, frame.width(), frame.height());
|
||||
|
||||
checkPaused();
|
||||
long targetNanos = baseNanos + clockOffsetNanos + (frame.pts() - basePts) * 1_000_000_000L / PlaybackEngine.MPEG_TIMESTAMP;
|
||||
@@ -275,10 +286,10 @@ public final class PlayerApp extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
private static void sleepUntil(long targetNanos) throws InterruptedException {
|
||||
long sleepNanos = targetNanos - System.nanoTime();
|
||||
if (sleepNanos > 0) {
|
||||
Thread.sleep(sleepNanos / 1_000_000, (int) (sleepNanos % 1_000_000));
|
||||
private static void sleepUntil(long targetNanos) {
|
||||
long remaining;
|
||||
while ((remaining = targetNanos - System.nanoTime()) > 0) {
|
||||
LockSupport.parkNanos(remaining);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,10 +341,15 @@ public final class PlayerApp extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
private void blitVideo(int[] argb, int width, int height) {
|
||||
WritableImage image = new WritableImage(width, height);
|
||||
private void blitVideo(int[] argb, int index, int width, int height) {
|
||||
WritableImage image = videoImages[index];
|
||||
if (image == null || (int) image.getWidth() != width || (int) image.getHeight() != height) {
|
||||
image = new WritableImage(width, height);
|
||||
videoImages[index] = image;
|
||||
}
|
||||
image.getPixelWriter().setPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), argb, 0, width);
|
||||
|
||||
final WritableImage current = image;
|
||||
Platform.runLater(() -> {
|
||||
GraphicsContext g = videoCanvas.getGraphicsContext2D();
|
||||
double canvasWidth = videoCanvas.getWidth();
|
||||
@@ -357,7 +373,7 @@ public final class PlayerApp extends Application {
|
||||
}
|
||||
double x = (canvasWidth - drawW) / 2.0;
|
||||
double y = (canvasHeight - drawH) / 2.0;
|
||||
g.drawImage(image, x, y, drawW, drawH);
|
||||
g.drawImage(current, x, y, drawW, drawH);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,14 @@ public final class RcoRenderer implements Display {
|
||||
int drawHeight = display.getHeight();
|
||||
double w = drawWidth > 0 ? drawWidth : image.getWidth();
|
||||
double h = drawHeight > 0 ? drawHeight : image.getHeight();
|
||||
g.drawImage(image, display.getX(), display.getY(), w, h);
|
||||
|
||||
// RCO positions are screen-center coordinates with +Y up (OpenGL-like).
|
||||
// Convert to top-left within the 480x272 design space.
|
||||
double cx = display.getX();
|
||||
double cy = display.getY();
|
||||
double x = 240.0 + (cx - w / 2.0);
|
||||
double y = 136.0 - (cy + h / 2.0);
|
||||
g.drawImage(image, x, y, w, h);
|
||||
g.setGlobalAlpha(1.0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user