【问题标题】:Get Bytebuffer from JavaFX Browser从 JavaFX 浏览器获取字节缓冲区
【发布时间】:2015-06-17 15:10:09
【问题描述】:

我目前正在使用 libgdx 开发一个项目。由于我厌倦了糟糕的 UI 库,我想使用 HTML、CSS 和 JS。

在我的第一次尝试中,我尝试了 java-chromium-embedded 并且还设法将它集成到我的项目中。通过一些思考,我能够获得浏览器的字节缓冲区并将其呈现在我的游戏之上。问题是只有预编译的win 64版本,但我也想支持其他平台。

由于我无法自己编译 chromium,所以我查看了 javafx 浏览器。它似乎比嵌入 java-chromium 的 java 代码复杂得多,因此我无法获得字节缓冲区。 也许有人可以帮助我,找到字节缓冲区。

我目前正在搜索:

  • com.sun.webkit.WebPage

    • public void paint(WCGraphicsContext gc, int x, int y, int w, int h)

    • private void paint2GC(WCGraphicsContext gc)

  • com.sun.webkit.graphics.WCRenderQueue

但是缓冲区和缓冲区列表太多了,我现在不知道“真正的”字节缓冲区在哪里。

【问题讨论】:

    标签: java javafx libgdx webkit chromium


    【解决方案1】:

    不建议使用未记录的com.sun API。

    相反,您可以snapshot WebView 节点,并使用来自snapshot ImagePixelReader 来获取像素缓冲区。

    我不确定这是否正是您想要做的。可能还有其他方法可以实现您想要的(例如覆盖窗口而不是使用缓冲区)。

    这是一个将动画 WebView 节点(播放视频)连续拍摄到 ImageView 中的示例。

    图片顶部是原始网页视图。图像的底部是原始图像的快照,其中覆盖了帧速率(当原始源 WebView 调整为全屏时,在 Retina MacBook 上运行时约为 60fps)。可以修改示例代码中的 W 和 H 值,以检查不同图像捕获尺寸的性能。

    import javafx.animation.AnimationTimer;
    import javafx.application.Application;
    import javafx.concurrent.Worker;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.image.*;
    import javafx.scene.layout.*;
    import javafx.scene.web.WebView;
    import javafx.stage.Stage;
    
    public class VideoPlayerWithFrameByFrameSnapshot extends Application {
        private static final int W = 800;
        private static final int H = 400;
    
        private final long[] frameTimes = new long[100];
        private int frameTimeIndex = 0 ;
        private boolean arrayFilled = false ;
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage stage) throws Exception {
            // create a WebView
            WebView webview = new WebView();
            webview.setMinSize(W, H);
            webview.setPrefSize(W, H);
            webview.setMaxSize(W, H);
    
            // create an image viewer for a WebView snapshot
            WritableImage image = new WritableImage(W, H);
            ImageView imageview = new ImageView(image);
    
            Label framerateLabel = new Label();
    
            // continuously snapshot the webview and measure current framerate.
            AnimationTimer timer = new AnimationTimer() {
                @Override
                public void handle(long now) {
                    webview.snapshot(null, image);
    
                    long oldFrameTime = frameTimes[frameTimeIndex] ;
                    frameTimes[frameTimeIndex] = now ;
                    frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length ;
                    if (frameTimeIndex == 0) {
                        arrayFilled = true ;
                    }
                    if (arrayFilled) {
                        long elapsedNanos = now - oldFrameTime ;
                        long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ;
                        double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ;
                        framerateLabel.setText(
                            String.format(
                                "Current frame rate: %.3f", 
                                frameRate
                            )
                        );
                    }
                }
            };
    
            // start the snapshot process once the web view load succeeds. 
            webview.getEngine().getLoadWorker().stateProperty().addListener(
                (observable, oldValue, newValue) -> {
                    System.out.println(newValue);
                    if (Worker.State.SUCCEEDED == newValue) {
                        timer.start();
                    }
                }
            );
    
            // load up the big buck bunny video. 
            webview.getEngine().load(
                    "http://camendesign.com/code/video_for_everybody/test.html"
            );
    
            // layout the scene. 
            VBox layout = new VBox(
                    webview,
                    new StackPane(
                            imageview,
                            framerateLabel
                    )
            );
            StackPane.setAlignment(framerateLabel, Pos.TOP_LEFT);
    
            stage.setScene(new Scene(layout));
            stage.show();
        }
    }
    

    帧率测量代码来自 James_D 的回答:

    顺便说一句:如果你想用纯 HTML UI 制作游戏,那么我不明白你为什么会涉及 libgdx 并希望访问低级绘图原语来捕获嵌入式浏览器的图形输出(而不是不仅仅是在用户的默认浏览器中或直接在游戏附带的嵌入式浏览器中显示 HTML UI),但我想你有理由采用这种方法。将来,我将尽量避免尝试回答动机和目标不明确的问题。这不是一个坏问题,只是一个我认为我无法提供太多帮助的问题。

    【讨论】:

    • 这里的问题是,快照太慢了,因为我的游戏需要 60 fps。
    • 你怎么知道快照太慢了,你试过了吗?为什么你需要在每个游戏帧都拍快照呢?大多数网络内容是静态的,不会发生太大变化。此外,如果您通过网络加载 Web 内容或使用大量 JavaScript,则大部分延迟将是由于网络加载或 JavaScript 处理造成的。您尝试在游戏屏幕上进行快照和叠加的网页中有动画内容吗?页面的像素大小是多少?如果您的问题存在限制条件,则应始终尝试在问题中列出这些限制条件。
    • 还要检查您是否使用了适当的PixelFormat for image data,因为这可能会影响此类操作的性能。
    • 是的,快照实际上是我的第一次尝试。我将整个快照标记为 bytebuffer 进程,结果它出来了,只是方法快照是让它变慢的那个。我想用 HTML 制作整个游戏 UI。因此,我将本地 html 文件加载到浏览器中。页面大小将是播放器显示器的大小。 PS:我已经获得了 60fps 嵌入了 java chromium 并且可以例如观看 youtube 视频。
    • 好的。好像我这样调用快照方法: webview.snapshot(null, NULL);
    猜你喜欢
    • 1970-01-01
    • 2015-07-26
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多