Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

Locked History Actions

vlcj/JavaFx2

= JavaFXでの利用2 ==

これも同じく

を参考にし、簡単化、かつ拡張した。ウインドウの大きさに応じてスクリーンも拡縮する。プレイバック位置を示し操作できるスライダを追加。

import java.nio.*;

import com.google.common.eventbus.*;
import com.sun.jna.*;

import javafx.animation.*;
import javafx.application.*;
import javafx.application.Platform;
import javafx.beans.property.*;
import javafx.beans.value.*;
import javafx.event.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.stage.*;
import javafx.util.*;
import uk.co.caprica.vlcj.component.*;
import uk.co.caprica.vlcj.discovery.*;
import uk.co.caprica.vlcj.player.direct.*;
import uk.co.caprica.vlcj.player.direct.format.*;

public class Resizable extends Application {

  // "c:/users/admin/desktop/video.mp4"ではだめ、native(Windows)に渡されるため
  private static final String VIDEO_FILE = "c:\\users\\admin\\desktop\\video.mp4";

  // mediaPlayerComponentはGUI階層に加えられず、機能が利用されるだけ。ここで保持しておく必要がある。
  private DirectMediaPlayerComponent mediaPlayerComponent;

  private DirectMediaPlayer mediaPlayer;

  @Override
  public void start(Stage stage) throws Exception {

    // 動画スクリーンを作成する
    final MediaScreen mediaScreen = new MediaScreen();

    // プレイバック位置スライダ
    PositionSlider positionSlider = new PositionSlider();
    positionSlider.eventBus.register(new Object() {
      @Subscribe
      public void accept(Long value) {
        mediaPlayer.setTime(value);
      }
    });

    // 定期的な処理を行うためのタイマー
    TimeInterpolator interpolator = new TimeInterpolator();
    Timeline timer = new Timeline(new KeyFrame(new Duration(200), new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        long time = mediaPlayer.getTime();
        time = interpolator.getCurrentTime(time);
        positionSlider.setTime(time);
      }
    }));

    // メディアプレイヤーコンポーネント
    mediaPlayerComponent = new CanvasPlayerComponent(mediaScreen.getPixelWriter(), new MediaCallback() {
      public void mediaCallback(int width, int height) {
        long length = mediaPlayer.getLength();
        positionSlider.setLength(length);
        mediaScreen.setMediaSize(mediaPlayer, width, height);
      }
    });
    mediaPlayer = mediaPlayerComponent.getMediaPlayer();

    // レイアウト
    BorderPane borderPane = new BorderPane();
    borderPane.setCenter(mediaScreen.getNode());
    positionSlider.setHeight(30);
    borderPane.setBottom(positionSlider.getNode());
    Scene scene = new Scene(borderPane);
    stage.setScene(scene);
    mediaPlayerComponent.getMediaPlayer().prepareMedia(VIDEO_FILE);
    mediaPlayerComponent.getMediaPlayer().start();
    stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
      @Override
      public void handle(WindowEvent event) {
        Platform.exit();
        System.exit(0);
      }
    });
    stage.show();

    // タイマーの開始
    timer.setCycleCount(Timeline.INDEFINITE);
    timer.play();
  }

  /** 動画表示スクリーン */
  public static class MediaScreen {

    Pane pane;
    ImageView imageView;
    WritableImage writableImage;
    private FloatProperty videoSourceRatioProperty;

    public MediaScreen() {
      this.pane = new Pane();

      pane.widthProperty().addListener((observable, oldValue, newValue) -> {
        fitImageViewSize(newValue.floatValue(), (float) pane.getHeight());
      });
      pane.heightProperty().addListener((observable, oldValue, newValue) -> {
        fitImageViewSize((float) pane.getWidth(), newValue.floatValue());
      });

      Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
      int screenWidth = (int) visualBounds.getWidth();
      int screenHeight = (int) visualBounds.getHeight();
      writableImage = new WritableImage(screenWidth, screenHeight);

      imageView = new ImageView(writableImage);
      pane.setPrefSize(screenWidth / 2, screenHeight / 2);

      pane.getChildren().add(imageView);
      videoSourceRatioProperty = new SimpleFloatProperty(0.4f);
      videoSourceRatioProperty.addListener((observable, oldValue, newValue) -> {
        fitImageViewSize((float) pane.getWidth(), (float) pane.getHeight());
      });
    }

    public Node getNode() {
      return pane;
    }

    public PixelWriter getPixelWriter() {
      return writableImage.getPixelWriter();
    }

    public void setMediaSize(DirectMediaPlayer mp, int width, int height) {
      videoSourceRatioProperty.set((float) height / (float) width);
    }

    private void fitImageViewSize(float width, float height) {
      float fitHeight = videoSourceRatioProperty.get() * width;
      if (fitHeight > height) {
        imageView.setFitHeight(height);
        double fitWidth = height / videoSourceRatioProperty.get();
        imageView.setFitWidth(fitWidth);
        imageView.setX((width - fitWidth) / 2);
        imageView.setY(0);
      } else {
        imageView.setFitWidth(width);
        imageView.setFitHeight(fitHeight);
        imageView.setY((height - fitHeight) / 2);
        imageView.setX(0);
      }
    }
  }

  /** プレイバック位置スライダ */
  public static class PositionSlider {
    Slider slider;
    EventBus eventBus = new EventBus();
    boolean setting = false;

    PositionSlider() {
      slider = new Slider();
      slider.valueProperty().addListener((ObservableValue<? extends Number> ov, Number oldValue, Number newValue) -> {
        if (setting)
          return;
        eventBus.post(newValue.longValue());
      });
    }

    public Node getNode() {
      return slider;
    }

    public void setHeight(int height) {
      slider.setPrefHeight(30);
      slider.setMaxHeight(30);
    }

    public void setLength(long length) {
      setting = true;
      try {
        slider.setMax(length);
      } finally {
        setting = false;
      }
    }

    public void setTime(long time) {
      setting = true;
      try {
        slider.setValue(time);
      } finally {
        setting = false;
      }
    }
  }

  /** メディアプレーヤーコンポーネント */
  static private class CanvasPlayerComponent extends DirectMediaPlayerComponent {

    private PixelWriter pixelWriter;
    PixelFormat<ByteBuffer> pixelFormat;

    public CanvasPlayerComponent(PixelWriter pixelWriter, final MediaCallback mediaCallback) {
      super(new BufferFormatCallback() {
        @Override
        public BufferFormat getBufferFormat(int sourceWidth, int sourceHeight) {
          Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
          Platform.runLater(() -> {
            mediaCallback.mediaCallback(sourceWidth, sourceHeight);
          });
          return new RV32BufferFormat((int) visualBounds.getWidth(), (int) visualBounds.getHeight());
        }
      });
      this.pixelWriter = pixelWriter;
      pixelFormat = PixelFormat.getByteBgraPreInstance();
    }

    @Override
    public void display(DirectMediaPlayer mediaPlayer, Memory[] nativeBuffers, BufferFormat bufferFormat) {
      Platform.runLater(() -> {
        Memory nativeBuffer = mediaPlayer.lock()[0];
        try {
          ByteBuffer byteBuffer = nativeBuffer.getByteBuffer(0, nativeBuffer.size());
          pixelWriter.setPixels(0, 0, bufferFormat.getWidth(), bufferFormat.getHeight(), pixelFormat, byteBuffer,
              bufferFormat.getPitches()[0]);
        } finally {
          mediaPlayer.unlock();
        }
      });
    }
  }

  public interface MediaCallback {
    public void mediaCallback(int with, int height);
  }

  /**
   * MediaPlayerの返す「時刻」は荒い値なので補完する。
   * 
   * @see https://github.com/caprica/vlcj/issues/74
   */
  public static class TimeInterpolator {
    private long lastPlayTime = 0;
    private long lastPlayTimeGlobal = 0;

    public long getCurrentTime(long currentTime) {
      if (lastPlayTime == currentTime && lastPlayTime != 0) {
        currentTime += System.currentTimeMillis() - lastPlayTimeGlobal;
      } else {
        lastPlayTime = currentTime;
        lastPlayTimeGlobal = System.currentTimeMillis();
      }
      return currentTime;
    }
  }

  public static void main(String[] args) {
    new NativeDiscovery().discover();
    Application.launch(Resizable.class);
  }

}