我正在寻找一种解决方案,用JavaFx显示一个RTP流。我可以从一个文件中显示jpeg,并接收RTP流,并将其拆分为在RFC2435中指定的所有参数和数据,但我不知道如何将我的JPEG数组转换为一个可显示的图像。我不想自己实现JPEG解码器。有什么想法吗?
发布于 2013-05-23 19:45:28
利用JavaFX内置的jpeg解码器,它应该能够在图像构造函数中解码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的视频流的视频流类(我希望这不是你的作业课)。
根据视频流类的描述,它是一种“专有的MJPEG格式”,因此您需要根据RFC2435对您的标准兼容格式进行自己的解码。
播放器工作,但确实有一个问题,正确解码的JPEG,我还没有调查。要么是“专有MJPEG格式”示例电影中的JPEG没有正确编码,要么是JavaFX JPEG编解码器有错误解码帧。可见的工件是你可以看到的图像,但图像是不正确的颜色(有粉红色的阴影)。它很可能是RT-14647不正确显示JPEG图像的一个实例,因为在错误解码的JPEG中,视频中的粉红色看起来是一样的。您可以在下面的示例代码呈现的视频屏幕截图中清楚地看到粉红色的阴影。该bug只影响一些JPEG图像(我与JavaFX一起使用的绝大多数JPEG图像都显示得很好)。因此,您只需要尝试使用您的视频流来查看JavaFX jpeg解码器是否正确地为您解码jpeg图像。
与每次在图像视图中替换图像不同,使用WritableImage并直接更新它的像素缓冲区可能更有效,但是蛮力替换图像方法对我来说似乎还行。

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<ActionEvent>() {
@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<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
timeline.play();
}
});
Button pause = new Button("Pause");
pause.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
timeline.pause();
}
});
Button restart = new Button("Restart");
restart.setOnAction(new EventHandler<ActionEvent>() {
@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));
}
}更新
我再次尝试使用Java 8u20早期access build 11在Windows 7上运行这个程序,视频播放得很好,没有任何粉红的色彩,所以我想导致这个问题的原因现在已经在后来的Java版本中修复了。

https://stackoverflow.com/questions/16721917
复制相似问题