显示RTP MJPEG

我正在寻找一种使用JavaFx显示RTP JPEG流的解决方案。 我可以从文件中显示jpeg并接收RTP JPEG流并将其拆分以识别RFC2435中指定的所有参数和数据但我不知道如何将我的JPEG数组转换为可显示的图像。 我不想自己实现JPEG解码器。 任何想法?

利用JavaFX的内置jpeg解码器,它应该能够解码Image构造函数中的jpeg图像。

class MJPEGViewer extends ImageView { MJPEGViewer() { // setup a thread which processes the input stream. // the processing thread invokes onNewData for each new frame. } private void onNewData(byte[] jpegData) { imageView.set( new Image( new ByteArrayInputStream(jpegData); ) ); } } 

jpegData是一个字节数组,假定包含从RTP流中提取的帧的JFIF数据。

可执行样本

这是一部播放电影的mjpeg电影播放器​​: http : //inst.eecs.berkeley.edu/~ee122/sp06/ProgAsgns/movie.Mjpeg

基于编程作业5:使用RTSP和RTP流式传输video的video流类(我希望这不是您的作业分配类)。

根据video流类描述,它是“专有的MJPEG格式”,因此您需要根据RFC2435自行解码符合标准的格式。

播放器工作,但确实有一个问题正确解码我没有调查过的JPEG。 “专有MJPEG格式”样本影片中的JPEG未正确编码,或者JavaFX JPEG编解码器在解码帧时出错。 可见的神器是你可以看到图像,但图像没有正确着色(有一个粉红色的阴影)。 这可能是RT-14647的一个实例JPEG图像显示不正确,因为video中的粉色阴影在错误显示的错误解码的JPEG中看起来相同。 您可以在下面的示例代码呈现的video的屏幕截图中清楚地看到粉色阴影。 这个bug只会影响一些JPEG图像(我用过JavaFX的绝大多数JPEG图像都显示得很好)。 因此,您只需尝试使用video流来查看JavaFX jpeg解码器是否正确解码了jpeg图像。

而不是每次都替换imageview中的Image,使用WritableImage并直接更新它的像素缓冲区可能更有效,但是暴力替换图像方法对我来说似乎没问题。

pinkvid

 import javafx.animation.*; import javafx.application.Application; import javafx.event.*; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.image.*; import javafx.scene.layout.*; import javafx.stage.Stage; import javafx.util.Duration; import java.io.*; import java.util.Arrays; public class MjpegPlayer extends Application { public static void main(String[] args) { Application.launch(MjpegPlayer.class); } // ADJUST THIS LOCATION TO SET THE LOCATION OF YOUR MOVIE FILE!! private static final String MOVIE_FILE = "/Users/lilyshard/dev/playfx/src/fruits/movie.Mjpeg"; private VideoStream vs; @Override public void start(Stage stage) throws Exception { vs = new VideoStream(MOVIE_FILE); final ImageView viewer = new ImageView(); final Timeline timeline = createTimeline(viewer); VBox layout = new VBox(20); layout.setStyle("-fx-background-color: cornsilk;"); layout.setAlignment(Pos.CENTER); layout.getChildren().setAll( viewer, createControls(timeline) ); stage.setScene(new Scene(layout, 400, 400)); stage.show(); timeline.play(); } private Timeline createTimeline(final ImageView viewer) { final Timeline timeline = new Timeline(); final byte[] buf = new byte[15000]; timeline.getKeyFrames().setAll( new KeyFrame(Duration.ZERO, new EventHandler() { @Override public void handle(ActionEvent event) { try { int len = vs.getnextframe(buf); if (len == -1) { timeline.stop(); return; } viewer.setImage( new Image( new ByteArrayInputStream( Arrays.copyOf(buf, len) ) ) ); } catch (Exception e) { e.printStackTrace(); } } }), new KeyFrame(Duration.seconds(1.0/24)) ); timeline.setCycleCount(Timeline.INDEFINITE); return timeline; } private HBox createControls(final Timeline timeline) { Button play = new Button("Play"); play.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { timeline.play(); } }); Button pause = new Button("Pause"); pause.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { timeline.pause(); } }); Button restart = new Button("Restart"); restart.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { try { timeline.stop(); vs = new VideoStream(MOVIE_FILE); timeline.playFromStart(); } catch (Exception e) { e.printStackTrace(); } } }); HBox controls = new HBox(10); controls.setAlignment(Pos.CENTER); controls.getChildren().setAll( play, pause, restart ); return controls; } } class VideoStream { FileInputStream fis; //video file int frame_nb; //current frame nb public VideoStream(String filename) throws Exception{ //init variables fis = new FileInputStream(filename); frame_nb = 0; } public int getnextframe(byte[] frame) throws Exception { int length = 0; String length_string; byte[] frame_length = new byte[5]; //read current frame length fis.read(frame_length,0,5); //transform frame_length to integer length_string = new String(frame_length); try { length = Integer.parseInt(length_string); } catch (Exception e) { return -1; } return(fis.read(frame,0,length)); } } 

更新

我尝试在Windows 7上使用Java 8u20早期访问版本11再次运行此程序,并且video播放时没有任何粉红色调,所以我想无论是什么导致该问题现在已经在以后的Java版本中得到修复。

mjpegcap固定