Мигающий белый экран в другом разрешении приложения JavaFx - PullRequest
0 голосов
/ 30 мая 2018

Мы разрабатываем приложение для потоковой передачи видео с использованием JavaFx и JavaCv.У нас есть GridPane 8X8, и каждая ячейка содержит макет Pane и каждую панель, содержащую ImageView.

Каждый раз, когда я вызываю функцию воспроизведения, когда пользователь перетаскивает URL в определенную ячейку.у нас 64 URL, поэтому мы вызываем функцию воспроизведения 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 моего приложения с другим размером экрана;Screen1 Screen2 Screen3 Screen4

Screen1

Поскольку мы сталкиваемсяэта проблема с давних времен.Любое руководство будет очень заметно.Заранее спасибо.

1 Ответ

0 голосов
/ 30 мая 2018

Здесь только предположение, но когда размер изображения отличается от размера изображения, при просмотре 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)Тема приложения).Если возможно, возможно, было бы более эффективно изменить размер каждого изображения в отдельном потоке.Вы не можете абсолютно гарантировать это (потому что нет способа гарантировать, что представление изображения не изменяет размер между изменяемым размером изображения в фоновом потоке и представлением изображения, отображающим изображение), поэтому вам все равно нужно связать fitWidthи fitHeight свойств, но это должно уменьшить количество изменения размера изображения, которое происходит в потоке пользовательского интерфейса, и, следовательно, должно повысить производительность.Это зависит от наличия какого-то механизма в вашем 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();  
}
...