如何在使用 JavaFx 播放之前寻找视频位置
How to seek to a video position before playing with JavaFx
我需要能够在使用 JavaFx 16 开始播放视频之前找到一个位置
当在 play() 之前调用 MediaPlayers seek() 或 setStartTime() 时,它会中断视频输出并且不再更新任何帧(声音仍在播放)。
视频的时长是已知的,不是不确定的。侦听器不会打印任何错误,也不会出现任何有意义的停顿(仅在开始时通过 https 加载视频时才会出现),但本地文件也会出现同样的问题。所以我觉得这个可以排除。我正在使用 Maven 运行 构建应用程序,mvn clean javafx:run
。
我尝试分别调用这些方法,并在准备好的侦听器内部和启动方法外部依次调用。
我正在使用 JDK 11 (11.0.11+9-Ubuntu-0ubuntu2)、maven 3.6.3 和 openjfx 16 GNU/Linux (Ubuntu 21.04 )).
我组装了一个最小的例子,我在下面的代码中做错了吗?您知道如何处理或解决这个问题吗?提前致谢。
App.java
package org.openjfx;
import javafx.application.Application;
import javafx.scene.control.Label;
import javafx.scene.Group;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.event.EventHandler;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.KeyCode;
public class App extends Application {
private Scene scene;
private MediaPlayer mediaPlayer;
private final Runnable onReadyStateListener = new Runnable() {
@Override
public void run() {
registerMinimalKeyEventHandling();
// Calling seek or setStartTime will break video playback, frames won't be updated anymore (and only the sound keeps playing)
Duration startTime = new Duration(6000L);
mediaPlayer.seek(startTime);
mediaPlayer.setStartTime(startTime);
mediaPlayer.play();
}
};
@Override
public void start(Stage stage) {
scene = new Scene(new Group(), 1600, 900);
stage.setScene(scene);
// The same issue occurs to local as well as remote videos
//Media media = new Media("file:///tmp/big_buck_bunny_720p_10mb.mp4");
Media media = new Media("https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_10mb.mp4");
mediaPlayer = new MediaPlayer(media);
mediaPlayer.setOnReady(onReadyStateListener);
mediaPlayer.setOnStalled(onStalledListener);
mediaPlayer.setOnError(onErrorListener);
MediaView mediaView = new MediaView(mediaPlayer);
mediaView.setFitWidth(1600);
mediaView.setFitHeight(900);
((Group) scene.getRoot()).getChildren().add(mediaView);
stage.show();
}
private void registerMinimalKeyEventHandling() {
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.SPACE) {
if (mediaPlayer.getStatus() == MediaPlayer.Status.PLAYING) {
mediaPlayer.pause();
return;
}
mediaPlayer.play();
} else if (event.getCode() == KeyCode.RIGHT) {
Duration seekTo = mediaPlayer.getCurrentTime().add(new Duration(1000L));
if (seekTo.greaterThan(mediaPlayer.getMedia().getDuration()) ) {
mediaPlayer.stop();
return;
}
mediaPlayer.seek(seekTo);
}
}
});
}
private final Runnable onStalledListener = new Runnable() {
@Override
public void run() { System.out.println(mediaPlayer.getCurrentTime().toString() + ": Video stalled"); }
};
private final Runnable onErrorListener = new Runnable() {
@Override
public void run() { System.out.println( mediaPlayer.getCurrentTime().toString() + ": Error occurred (" + mediaPlayer.getError().getLocalizedMessage() + ")"); }
};
public static void main(String[] args) { launch(); }
}
测试视频是 big_buck_bunny_720p_10mb.mp4 来自示例-videos.com。
此视频在 VLC (3.0.12 Vetinari) 和 mplayer (1.4) 中播放没有任何问题,并且可以寻求其他位置。
ffprobe 的输出:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/tmp/SampleVideo_1280x720_10mb.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
creation_time : 1970-01-01T00:00:00.000000Z
encoder : Lavf53.24.2
Duration: 00:01:02.32, start: 0.000000, bitrate: 1347 kb/s
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9],
959 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc (default)
Metadata:
creation_time : 1970-01-01T00:00:00.000000Z
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 383 kb/s (default)
Metadata:
creation_time : 1970-01-01T00:00:00.000000Z
handler_name : SoundHandler
项目设置:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.openjfx</groupId>
<artifactId>sample</artifactId>
<version>1.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>16</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.3</version>
<configuration>
<mainClass>org.openjfx.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
模块-info.java
module org.openjfx {
requires javafx.controls;
requires javafx.media;
exports org.openjfx;
}
这是一个known bug,这是JavaFX 14中引入的回归错误。它已在JavaFX 17中解决。最好的解决方法是将JavaFX版本更改为17(或更高版本;17是当前版本撰写本文时的版本)。如果由于某种原因无法做到这一点,可以恢复到版本 13 或更早版本,但在视频准备好之前您会看到更长的等待时间。
在 pom 中,更改为
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>17</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>17</version>
</dependency>
</dependencies>
我需要能够在使用 JavaFx 16 开始播放视频之前找到一个位置
当在 play() 之前调用 MediaPlayers seek() 或 setStartTime() 时,它会中断视频输出并且不再更新任何帧(声音仍在播放)。
视频的时长是已知的,不是不确定的。侦听器不会打印任何错误,也不会出现任何有意义的停顿(仅在开始时通过 https 加载视频时才会出现),但本地文件也会出现同样的问题。所以我觉得这个可以排除。我正在使用 Maven 运行 构建应用程序,mvn clean javafx:run
。
我尝试分别调用这些方法,并在准备好的侦听器内部和启动方法外部依次调用。
我正在使用 JDK 11 (11.0.11+9-Ubuntu-0ubuntu2)、maven 3.6.3 和 openjfx 16 GNU/Linux (Ubuntu 21.04 )).
我组装了一个最小的例子,我在下面的代码中做错了吗?您知道如何处理或解决这个问题吗?提前致谢。
App.java
package org.openjfx;
import javafx.application.Application;
import javafx.scene.control.Label;
import javafx.scene.Group;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.event.EventHandler;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.KeyCode;
public class App extends Application {
private Scene scene;
private MediaPlayer mediaPlayer;
private final Runnable onReadyStateListener = new Runnable() {
@Override
public void run() {
registerMinimalKeyEventHandling();
// Calling seek or setStartTime will break video playback, frames won't be updated anymore (and only the sound keeps playing)
Duration startTime = new Duration(6000L);
mediaPlayer.seek(startTime);
mediaPlayer.setStartTime(startTime);
mediaPlayer.play();
}
};
@Override
public void start(Stage stage) {
scene = new Scene(new Group(), 1600, 900);
stage.setScene(scene);
// The same issue occurs to local as well as remote videos
//Media media = new Media("file:///tmp/big_buck_bunny_720p_10mb.mp4");
Media media = new Media("https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_10mb.mp4");
mediaPlayer = new MediaPlayer(media);
mediaPlayer.setOnReady(onReadyStateListener);
mediaPlayer.setOnStalled(onStalledListener);
mediaPlayer.setOnError(onErrorListener);
MediaView mediaView = new MediaView(mediaPlayer);
mediaView.setFitWidth(1600);
mediaView.setFitHeight(900);
((Group) scene.getRoot()).getChildren().add(mediaView);
stage.show();
}
private void registerMinimalKeyEventHandling() {
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.SPACE) {
if (mediaPlayer.getStatus() == MediaPlayer.Status.PLAYING) {
mediaPlayer.pause();
return;
}
mediaPlayer.play();
} else if (event.getCode() == KeyCode.RIGHT) {
Duration seekTo = mediaPlayer.getCurrentTime().add(new Duration(1000L));
if (seekTo.greaterThan(mediaPlayer.getMedia().getDuration()) ) {
mediaPlayer.stop();
return;
}
mediaPlayer.seek(seekTo);
}
}
});
}
private final Runnable onStalledListener = new Runnable() {
@Override
public void run() { System.out.println(mediaPlayer.getCurrentTime().toString() + ": Video stalled"); }
};
private final Runnable onErrorListener = new Runnable() {
@Override
public void run() { System.out.println( mediaPlayer.getCurrentTime().toString() + ": Error occurred (" + mediaPlayer.getError().getLocalizedMessage() + ")"); }
};
public static void main(String[] args) { launch(); }
}
测试视频是 big_buck_bunny_720p_10mb.mp4 来自示例-videos.com。 此视频在 VLC (3.0.12 Vetinari) 和 mplayer (1.4) 中播放没有任何问题,并且可以寻求其他位置。
ffprobe 的输出:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/tmp/SampleVideo_1280x720_10mb.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
creation_time : 1970-01-01T00:00:00.000000Z
encoder : Lavf53.24.2
Duration: 00:01:02.32, start: 0.000000, bitrate: 1347 kb/s
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9],
959 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc (default)
Metadata:
creation_time : 1970-01-01T00:00:00.000000Z
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 383 kb/s (default)
Metadata:
creation_time : 1970-01-01T00:00:00.000000Z
handler_name : SoundHandler
项目设置:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.openjfx</groupId>
<artifactId>sample</artifactId>
<version>1.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>16</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.3</version>
<configuration>
<mainClass>org.openjfx.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
模块-info.java
module org.openjfx {
requires javafx.controls;
requires javafx.media;
exports org.openjfx;
}
这是一个known bug,这是JavaFX 14中引入的回归错误。它已在JavaFX 17中解决。最好的解决方法是将JavaFX版本更改为17(或更高版本;17是当前版本撰写本文时的版本)。如果由于某种原因无法做到这一点,可以恢复到版本 13 或更早版本,但在视频准备好之前您会看到更长的等待时间。
在 pom 中,更改为
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>17</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>17</version>
</dependency>
</dependencies>