在做的我的开源项目IceoLogy壁纸时,由于要做视频壁纸,javafx自带的mediaView性能并不理想,支持的格式也挺少的,几经搜索发现开源的VLC media player播放器有口皆碑,挺不错的,使用开源的demo运行发现cpu占用异常的高,我i7-9750H的CPU也占到了40%,稳定在25%左右,几经搜寻在外网找到了加入视屏缓冲区来优化的解决方案,加入缓冲区后播放同一视频cpu使用率稳定在8%左右
<!-- vlc 播放器-->
<dependency>
<groupId>uk.co.caprica</groupId>
<artifactId>vlcj-javafx</artifactId>
<version>1.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx</artifactId>
<version>16</version>
<type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-fxml -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
</dependency>
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelBuffer;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import ui.util.CommonConst;
import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.base.MediaPlayer;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.player.embedded.videosurface.CallbackVideoSurface;
import uk.co.caprica.vlcj.player.embedded.videosurface.VideoSurfaceAdapters;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.BufferFormat;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.BufferFormatCallback;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.RenderCallback;
import uk.co.caprica.vlcj.player.embedded.videosurface.callback.format.RV32BufferFormat;
import java.nio.ByteBuffer;
/**
* This is a very simple example of a video player which uses the new WritableImage
* of JavaFX with support for Buffers. The idea is to let VLC directly render into
* this buffer and use the image directly in an ImageView without any explicit rendering
* into a canvas or such thing. Only this brings the desired performance boost.
* <p>
* What I have not yet considered yet is any kind of synchronization.
* I think an extension of the PixelBuffer to support some kine of double-buffering
* would be the right thing to do.
* <p>
* The following dependencies should be enough to compile this example with OpenJDK 12.
*
* <dependencies>
* <dependency>
* <groupId>uk.co.caprica</groupId>
* <artifactId>vlcj</artifactId>
* <version>4.2.0</version>
* </dependency>
* <dependency>
* <groupId>org.openjfx</groupId>
* <artifactId>javafx-controls</artifactId>
* <version>13-ea+12</version>
* </dependency>
* </dependencies>
* <!-- vlc 播放器-->
* <dependency>
* <groupId>uk.co.caprica</groupId>
* <artifactId>vlcj-javafx</artifactId>
* <version>1.0.2</version>
* </dependency>
*
* @author Michael Paus
*/
public class WritableImageVideoDemo extends Application {
private MediaPlayerFactory mediaPlayerFactory;
private EmbeddedMediaPlayer embeddedMediaPlayer;
private WritableImage videoImage;
private PixelBuffer<ByteBuffer> videoPixelBuffer;
private ImageView videoImageView;
@Override
public void init() {
mediaPlayerFactory = new MediaPlayerFactory();
embeddedMediaPlayer = mediaPlayerFactory.mediaPlayers().newEmbeddedMediaPlayer();
embeddedMediaPlayer.videoSurface().set(new FXCallbackVideoSurface());
}
@Override
public final void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
root.setStyle("-fx-background-color: black;");
videoImageView = new ImageView();
videoImageView.setPreserveRatio(true);
videoImageView.fitWidthProperty().bind(root.widthProperty());
videoImageView.fitHeightProperty().bind(root.heightProperty());
root.getChildren().add(videoImageView);
setMedia("D:\\desserts\\2.mp4");
Scene scene = new Scene(root, 1920, 1080);
primaryStage.setScene(scene);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.show();
}
@Override
public final void stop() throws Exception {
embeddedMediaPlayer.controls().stop();
embeddedMediaPlayer.release();
mediaPlayerFactory.release();
}
private class FXCallbackVideoSurface extends CallbackVideoSurface {
FXCallbackVideoSurface() {
super(new FXBufferFormatCallback(), new FXRenderCallback(), true, VideoSurfaceAdapters.getVideoSurfaceAdapter());
}
}
private class FXBufferFormatCallback implements BufferFormatCallback {
private int sourceWidth;
private int sourceHeight;
@Override
public BufferFormat getBufferFormat(int sourceWidth, int sourceHeight) {
this.sourceWidth = sourceWidth;
this.sourceHeight = sourceHeight;
return new RV32BufferFormat(sourceWidth, sourceHeight);
}
@Override
public void allocatedBuffers(ByteBuffer[] buffers) {
assert buffers[0].capacity() == sourceWidth * sourceHeight * 4;
PixelFormat<ByteBuffer> pixelFormat = PixelFormat.getByteBgraPreInstance();
videoPixelBuffer = new PixelBuffer<>(sourceWidth, sourceHeight, buffers[0], pixelFormat);
videoImage = new WritableImage(videoPixelBuffer);
videoImageView.setImage(videoImage);
}
}
private class FXRenderCallback implements RenderCallback {
@Override
public void display(MediaPlayer mediaPlayer, ByteBuffer[] nativeBuffers, BufferFormat bufferFormat) {
Platform.runLater(() -> {
videoPixelBuffer.updateBuffer(pb -> null);
});
}
}
public void setMedia(String path) {
embeddedMediaPlayer.media().play(path
, ":no-audio"
, ":rtsp=tcp"
, ":codec=ffmpeg"
, ":vout=any"
, ":avcodec-threads=1"
, ":avcodec-hw=any"
, ":network-caching=200"
, ":prefetch-buffer-size=1024"
, ":prefetch-read-size=65535"
, ":file-caching=1000"
);
//循环播放
embeddedMediaPlayer.controls().setRepeat(true);
}
public static void main(String[] args) {
launch(args);
}
}
// Launch via this class to avoid module system headaches.
class WritableImageVideoDemoLauncher {
public static void main(String[] args) {
WritableImageVideoDemo.main(args);
}
}
但是有个缺点就是需要安装VLC media player播放器,没有安装是不能播放的,可以使用以下代码通过扫描注册表检测是否安装VLC media player播放器。
<!-- https://mvnrepository.com/artifact/com.jianggujin/JRegistry -->
<dependency>
<groupId>com.jianggujin</groupId>
<artifactId>JRegistry</artifactId>
<version>1.0.0</version>
</dependency>
import com.jianggujin.registry.JExecResult;
import com.jianggujin.registry.JQueryOptions;
import com.jianggujin.registry.JRegistry;
import java.io.IOException;
public class JTest {
public static void main(String[] args) throws IOException, InterruptedException {
JExecResult result = JRegistry.query("HKEY_CLASSES_ROOT\\Applications\\",
new JQueryOptions().useF("\"vlc.exe\""));
JRegistry.dump(result);
System.out.println("is install vlc video player:"+result.isSuccess());
}
}