【问题标题】:Flashing White Screen In Different Resolution of JavaFx ApplicationJavaFx 应用程序在不同分辨率下闪烁白屏
【发布时间】:2018-11-09 12:33:29
【问题描述】:

我们正在使用 JavaFx 和 JavaCv 开发视频流应用程序。 我们有 8X8 的 GridPane,每个单元格包含窗格布局和每个窗格 包含 ImageView。

每当用户将 url 拖到特定位置时,我都会调用 play 函数 细胞。 我们有 64 个 Url,所以我们调用 play 函数 64 次(所有 64 个 url 都在播放 在后台线程中)。

for(int i=0;i<8;i++){
        for(int j=0;j<8;j++){
            //grid08(8X8)
            Pane p=new Pane();
            ImageView im=new ImageView();
            Label l=new Label("");
            im.fitWidthProperty().bind(p.widthProperty());
            im.fitHeightProperty().bind(p.heightProperty());
            l.prefWidthProperty().bind(p.widthProperty());
            l.prefHeightProperty().bind(p.heightProperty());
            p.getChildren().addAll(im,l);
            l.setVisible(false);
            l.setStyle("-fx-text-fill: #fff; -fx-font-size: 12px");
            l.setAlignment(Pos.CENTER);
            p.setStyle("-fx-background-color: black;");
            grid.add(p,j,i);//grid->instance of gridPane
            p.setOnDragOver(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
            if(!l.isVisible()){
                event.acceptTransferModes(TransferMode.ANY);
                   }
                }
            });
            p.setOnDragDropped(new EventHandler<DragEvent>() {
                @Override
                public void handle(DragEvent event) {
                   play(im,event.getDragboard().getString());
                }
            });
      }
     }

 play(ImageView im,String Url){
   new Thread(new Runnable(){
         frameGrabber = new FFmpegFrameGrabber(Url);
         frameGrabber.setVideoOption("preset","ultrafast");
         frameGrabber.setOption("rtsp_transport","tcp");
         frameGrabber.setOption("stimeout" , "60000");
         frameGrabber.setAudioChannels(0);
         frameGrabber.setAudioCodec(0);
        try {
        frameGrabber.start();
        start=true;
        } catch (Exception e) {
        }
        JavaFXFrameConverter jconverter=new JavaFXFrameConverter();
        while(true){
        Frame frame = frameGrabber.grabImage();
        Image image=jconverter.convert(frame);
        Platform.runlater(new Runnable(){
         im.setImage(image);
         });
        }
      }).start();  
 }

问题: 我们正面临白屏问题,在增加一些阈值宽度和 高度。 在这里,我附加了具有不同屏幕尺寸的应用程序的 Snap;

屏幕1

由于我们长期以来一直面临这个问题。 任何潜在客户都将是非常可观的。 提前致谢。

【问题讨论】:

  • 1.您可以修复代码以使其编译吗? 2. 打电话frameGrabber.start()时是否也检查一下是否有异常? 3. 当它处于“自然”分辨率(即图像视图与图像大小相同)时,您是否看到空白屏幕?

标签: java multithreading javafx fxml javacv


【解决方案1】:

这里只是一个猜测,但是当图像视图与图像大小不同时,当您调用setImage(...) 时,图像视图有很多工作要做(它必须调整图像大小)。由于您有很多这样的事情发生,可能是每个脉冲,您向Platform.runLater(...) 提交的可运行文件可能比它可以处理的要多(即,在从同一线程提交的前一个可以完成之前,您提交另一个Platform.runLater(...))。这会导致渲染问题,因为渲染系统跟不上。

我无法对此进行测试,所以我不确定它是否能解决问题,但最好只在前一个调用完成后向Platform.runLater(...) 提交一个新调用(即你应该这样做即使这不是问题的原因)。

你可以这样做

void play(ImageView im,String Url){
    new Thread(() -> {
        frameGrabber = new FFmpegFrameGrabber(Url);
        frameGrabber.setVideoOption("preset","ultrafast");
        frameGrabber.setOption("rtsp_transport","tcp");
        frameGrabber.setOption("stimeout" , "60000");
        frameGrabber.setAudioChannels(0);
        frameGrabber.setAudioCodec(0);
        try {
            frameGrabber.start();
            start=true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        JavaFXFrameConverter jconverter=new JavaFXFrameConverter();

        AtomicReference<Image> imageHolder = new AtomicReference<>(null);
        while(true){
            Frame frame = frameGrabber.grabImage();
            Image image=jconverter.convert(frame);
            if (imageHolder.getAndSet(image) == null) {
                Platform.runLater(() -> im.setImage(imageHolder.getAndSet(null)));
            }
        }
    }).start();  
}

请注意,在此代码(和原始代码)中,所有图像都在同一线程(FX 应用程序线程)上调整大小。如果可能的话,在自己的线程中调整每个图像的大小可能会更有效。你不能绝对保证这一点(因为没有办法保证图像视图在后台线程中调整大小的图像和显示图像的图像视图之间不会改变大小),所以你仍然需要绑定fitWidthfitHeight 属性,但这应该会减少 UI 线程上发生的图像大小调整量,从而提高性能。这依赖于您的图像采集卡 API(我不熟悉)中有一些机制来调整图像大小。

for(int i=0;i<8;i++){
    for(int j=0;j<8;j++){
        //grid08(8X8)
        Pane p=new Pane();
        AtomicReference<Bounds> bounds = new AtomicReference<>(p.getBoundsInLocal());
        p.boundsInLocalProperty().addListener((obs, oldBounds, newBounds) -> bounds.set(newBounds));
        ImageView im=new ImageView();
        Label l=new Label("");
        im.fitWidthProperty().bind(p.widthProperty());
        im.fitHeightProperty().bind(p.heightProperty());
        l.prefWidthProperty().bind(p.widthProperty());
        l.prefHeightProperty().bind(p.heightProperty());
        p.getChildren().addAll(im,l);
        l.setVisible(false);
        l.setStyle("-fx-text-fill: #fff; -fx-font-size: 12px");
        l.setAlignment(Pos.CENTER);
        p.setStyle("-fx-background-color: black;");
        grid.add(p,j,i);//grid->instance of gridPane
        p.setOnDragOver(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                if(!l.isVisible()){
                    event.acceptTransferModes(TransferMode.ANY);
                }
            }
        });
        p.setOnDragDropped(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
               play(im,bounds,event.getDragboard().getString());
            }
        });
     }
 }

void play(ImageView im, AtomicReference<Bounds> bounds, String Url){
    new Thread(() -> {
        frameGrabber = new FFmpegFrameGrabber(Url);
        frameGrabber.setVideoOption("preset","ultrafast");
        frameGrabber.setOption("rtsp_transport","tcp");
        frameGrabber.setOption("stimeout" , "60000");
        frameGrabber.setAudioChannels(0);
        frameGrabber.setAudioCodec(0);
        try {
            frameGrabber.start();
            start=true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        JavaFXFrameConverter jconverter=new JavaFXFrameConverter();

        AtomicReference<Image> imageHolder = new AtomicReference<>(null);
        while(true){
            Frame frame = frameGrabber.grabImage();

            Bounds imgBounds = bounds.get();
            double width = imgBounds.getWidth();
            double height = imgBounds.getHeight();

            // resize frame to width, height....

            Image image=jconverter.convert(frame);

            if (imageHolder.getAndSet(image) == null) {
                Platform.runLater(() -> im.setImage(imageHolder.getAndSet(null)));
            }
        }
    }).start();  
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-28
    • 2011-12-23
    • 1970-01-01
    • 2016-07-27
    • 2012-01-21
    相关资源
    最近更新 更多