ffmpeg - JavaFX MediaPlayer 无法播放本地 m3u8 文件

标签 ffmpeg javafx-8 gstreamer http-live-streaming m3u8

我想使用 MediaPlayer/MediaView 在我的 JavaFX 应用程序中显示网络摄像头的实时流。我的尝试是使用 ffmpeg 录制 HLS 并播放生成的 m3u8 文件,但这会引发以下异常(VLC 播放视频没有问题):

MediaException: UNKNOWN : com.sun.media.jfxmedia.MediaException: Could not create player! : com.sun.media.jfxmedia.MediaException: Could not create player!
    at javafx.scene.media.MediaException.exceptionToMediaException(MediaException.java:146)
    at javafx.scene.media.MediaPlayer.init(MediaPlayer.java:511)
    at javafx.scene.media.MediaPlayer.<init>(MediaPlayer.java:414)
    at de.fraunhofer.iosb.ias.flow.assessment.management.monitor.MonitorViewController.testStream(MonitorViewController.java:203)
    ... 58 more
Caused by: com.sun.media.jfxmedia.MediaException: Could not create player!
    at com.sun.media.jfxmediaimpl.NativeMediaManager.getPlayer(NativeMediaManager.java:274)
    at com.sun.media.jfxmedia.MediaManager.getPlayer(MediaManager.java:118)
    at javafx.scene.media.MediaPlayer.init(MediaPlayer.java:467)
    ... 60 more

我调试了播放器的创建,当 GSTMediaPlayer.gstInitPlayer() 时在 GSTMediaPlayer 的构造函数中发生错误叫做。此 native 方法返回错误代码 257 , javafx 映射到 MediaError.ERROR_MEDIA_NULL .

我使用以下 ffmpeg 命令录制视频:
ffmpeg -hide_banner -y -rtbufsize 250MB -f dshow -pixel_format yuv420p -video_size 960x720 -i video="Logitech HD Pro Webcam C920" -c:v libx264 -crf 20 -pix_fmt yuv420p out.m3u8

我很确定编码匹配 requirements javafx 的,因为如果我将输出容器从 m3u8 更改为 mp4,则使用完全相同的 ffmpeg 命令播放视频时不会出现问题。

这是 m3u8 文件的 ffprobe 的输出:
Input #0, hls,applehttp, from 'out.m3u8':
  Duration: 00:00:24.23, start: 1.466667, bitrate: 0 kb/s
  Program 0
    Metadata:
      variant_bitrate : 0
    Stream #0:0: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p, 960x720, 30 fps, 30 tbr, 90k tbn, 60 tbc

对于 mp4 文件:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'out.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf57.41.100
  Duration: 00:01:04.93, start: 0.000000, bitrate: 1676 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 960x720, 1673 kb/s, 30 fps, 30 tbr, 10000k tbn, 60 tbc (default)
    Metadata:
      handler_name    : VideoHandler

生成的 m3u8 文件如下所示:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:9
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:8.333322,
out0.ts
#EXTINF:8.333333,
out1.ts
#EXTINF:7.133322,
out2.ts
#EXTINF:0.433333,
out3.ts
#EXT-X-ENDLIST

更新:找到后this引用 m3u 文件,我认为问题在于该文件存储在本地,而不是通过 HTTP 传递。视频可以正常播放:
Media media = new Media("http://download.oracle.com/otndocs/products/javafx/JavaRap/prog_index.m3u8");
MediaPlayer player = new MediaPlayer(media);
player.setAutoPlay(true);
mediaView.setMediaPlayer(player);

但是在我下载了引用 m3u 及其所有段并尝试像这样打开本地文件后,错误再次发生:
File video = new File("H://Projects//Tools//ref//prog_index.m3u8");
Media media = new Media(video.toURI().toString());
MediaPlayer player = new MediaPlayer(media);
player.setAutoPlay(true);
mediaView.setMediaPlayer(player);

我试图更改我的 m3u 文件,以便使用绝对路径引用这些段。我尝试了不同的符号( H:\f\out0.tsH:/f/out0.tsH://f//out0.tsfile:/H:/f/out0.tsfile:///H:/f/out0.ts ),但我无法让它工作。

最佳答案

不幸的是,您似乎在这里运气不佳。这是 JDK 内部的相关逻辑:

com.sun.media.jfxmedia.locator.Locator

public ConnectionHolder createConnectionHolder() throws IOException {
    // [...] cache lookup elided
    ConnectionHolder holder;
    if ("file".equals(scheme)) {
        holder = ConnectionHolder.createFileConnectionHolder(uri);
    } else if (uri.toString().endsWith(".m3u8") || uri.toString().endsWith(".m3u")) {
        holder = ConnectionHolder.createHLSConnectionHolder(uri);
    }

如您所见,第一个检查是针对 file方案,此时您会被毫不客气地发送到处理实际媒体文件的逻辑。 HLS 播放列表处理由稍后检查文件扩展名 .m3u8 触发但是到那时为时已晚,您的本地文件已匹配先前的条件并发送到错误的位置。您可能会争辩说这是一个错误并将其归档,尽管它有点极端。

关于ffmpeg - JavaFX MediaPlayer 无法播放本地 m3u8 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43759923/

相关文章:

ffmpeg - 使用 ffmpeg 覆盖图像无限期地运行脚本

ffmpeg - ffplay -noborder 选项缺少参数

progress-bar - 任务完成时 JavaFX 隐藏进度条

java - 长时间运行和阻塞 javafx 任务进度条更新

.net - 为 Xamarin Studio(Gtk#) 安装 gstreamer-sharp

gstreamer - 使用 gstreamer 解码 mp4 视频

filter - ffmpeg 仅对部分视频使用带有 alphamerge 的 complex_filter

ffmpeg - 使用 FFmpeg 删除重复帧

java - 将 POJO 转换为 JavaFX 属性

c - Gstreamer - 收听 RTP 流时延迟过多