Я хочу показать прямой эфир с веб-камеры в моем приложении JavaFX с помощью MediaPlayer / MediaView. Моя попытка заключалась в том, чтобы использовать 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 при вызове GSTMediaPlayer.gstInitPlayer()
. Этот собственный метод возвращает код ошибки 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
Я почти уверен, что кодировка соответствует требования javafx, потому что если я изменю выходной контейнер с m3u8 на mp4, видео будет воспроизводиться без проблем с использованием той же самой команды ffmpeg.
Это результат ffprobe для файла m3u8:
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
Обновление: после того, как я нашел это ссылка на файл 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.ts
, H:/f/out0.ts
, H://f//out0.ts
, file:/H:/f/out0.ts
, file:///H:/f/out0.ts
), но не смог заставить его работать.