显示RTP MJ​​PEG [英] Display RTP MJPEG

查看:450
本文介绍了显示RTP MJ​​PEG的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个解决方案,以显示使用JavaFX一个RTP JPEG视频流。
我可以从文件中显示JPEG和接收RTP JPEG视频流,并把它分解,以确定所有参数和数据作为 RFC2435规定
但我不知道怎么我的JPEG数组转换为显示图像。
我不想由我自己来实现JPEG德$ C $铬。
任何想法?


解决方案

利用的JavaFX的内置JPEG德codeR,它应该能够去code。在<一个JPEG图像href=\"http://docs.oracle.com/javafx/2/api/javafx/scene/image/Image.html#Image%28java.io.InputStream%29\"相对=nofollow>图像构造。

 类MJPEGViewer扩展了ImageView的{
  MJPEGViewer(){
    //设置,其中处理输入数据流的线程。
    //处理线程调用onNewData每个新的框架。
  }  私人无效onNewData(字节[] jpegData){
    imageView.set(
      新图片(
        新ByteArrayInputStream进行(jpegData);
      )
    );
  }
}

该jpegData是一个字节数组presumed遏制JFIF数据从RTP流中提取帧。

可执行样品

这是从播放电影的MJPEG影片播放器:
http://inst.eecs.berkeley.edu/~ee122/sp06 /ProgAsgns/movie.Mjpeg

根据来自编程任务的视频流类

5:视频流与RTSP和RTP (我希望这不是你的家庭作业类)

根据视频流类描述,它是一个专有格式MJPEG,所以你需要做自己的你的标准兼容的解码格式根据RFC2435。

该播放器的工作原理,但确实有正确解码,我没有调查的JPEG文件的问题。无论是在专有格式MJPEG样品电影JPEG文件没有正确连接codeD或JavaFX的JPEG codeC有错误解码帧。可见神器是,你可以看到图像,但图像是不正确的颜色(有粉红色光)。这是可能的 RT-14647的实例
JPEG图像显示不正确
的在视频中的粉红色光看起来在错误显示的错误去codeD JPEG格式相同。你可以清楚地看到由样本code以下提供的视频截图中的粉红色光。该错误只影响一些JPEG图像(我使用JavaFX使用绝大多数JPEG图像都显示正常)。所以,你只需要尝试与您的视频流,看是否JavaFX的JPEG德codeR正确去codeS中的JPEG图像适合你。

而不是每次都更换了ImageView的图像,它可能是更有效使用的 WritableImage 并更新它的像素缓冲区直接,但蛮力替换图片的方法似乎对我的工作确定。

 进口javafx.animation *。
进口javafx.application.Application;
导入javafx.event *。
进口javafx.geometry.Pos;
进口javafx.scene.Scene;
进口javafx.scene.control.Button;
导入javafx.scene.image *。
导入javafx.scene.layout *。
进口javafx.stage.Stage;
进口javafx.util.Duration;进口java.io. *;
进口java.util.Arrays中;公共类MjpegPlayer扩展应用{
  公共静态无效的主要(字串[] args){Application.launch(MjpegPlayer.class); }  //调整此位置设置电影文件的位置!
  私有静态最后弦乐MOVIE_FILE =/Users/lilyshard/dev/playfx/src/fruits/movie.Mjpeg;  私人视频流VS;  @覆盖公共无效启动(阶段阶段)抛出异常{
    VS =新的视频流(MOVIE_FILE);    最后ImageView的观众=新ImageView的();
    最终时间表时间表= createTimeline(观众);    垂直框布局=新的垂直框(20);
    layout.setStyle( - FX-背景色:玉米穗黄;);
    layout.setAlignment(Pos.CENTER);
    layout.getChildren()。SETALL(
      浏览器,
      createControls(时间轴)
    );    stage.setScene(新场景(布局,400,400));
    stage.show();    timeline.play();
  }  私人时间轴createTimeline(最终ImageView的查看器){
    最终时间表时间表=新的时间轴();
    最后一个字节[] buf中=新的字节[15000]    timeline.getKeyFrames()。SETALL(
      新的关键帧(Duration.ZERO,新的EventHandler&LT;&ActionEvent的GT;(){
        @覆盖公共无效手柄(ActionEvent的事件){
          尝试{
            INT LEN = vs.getnextframe(BUF);
            如果(LEN == -1){
              timeline.stop();
              返回;
            }
            viewer.setImage(
              新图片(
                新ByteArrayInputStream的(
                  Arrays.copyOf(BUF,LEN)
                )
              )
            );
          }赶上(例外五){
            e.printStackTrace();
          }
        }
      }),
      新的关键帧(Duration.seconds(1.0 / 24))
    );
    timeline.setCycleCount(Timeline.INDEFINITE);    返回时间表;
  }  私人的HBox createControls(最终时间轴时间轴){
    按钮播放=新按钮(播放);
    play.setOnAction(新的EventHandler&LT;&ActionEvent的GT;(){
      @覆盖
      公共无效手柄(ActionEvent的事件){
        timeline.play();
      }
    });    按钮暂停=新按钮(暂停);
    pause.setOnAction(新的EventHandler&LT;&ActionEvent的GT;(){
      @覆盖
      公共无效手柄(ActionEvent的事件){
        timeline.pause();
      }
    });    键,重启=新按钮(重新启动);
    restart.setOnAction(新的EventHandler&LT;&ActionEvent的GT;(){
      @覆盖
      公共无效手柄(ActionEvent的事件){
        尝试{
          timeline.stop();
          VS =新的视频流(MOVIE_FILE);
          timeline.playFromStart();
        }赶上(例外五){
          e.printStackTrace();
        }
      }
    });    HBox中控制=新的HBox(10);
    controls.setAlignment(Pos.CENTER);
    controls.getChildren()。SETALL(
      玩,
      暂停,
      重新开始
    );
    返回控制;
  }
}一流的视频流{  FIS的FileInputStream; //视频文件
  INT frame_nb; //当前帧NB  公共视频流(字符串文件名)抛出异常{    //初始化变量
    FIS =新的FileInputStream(文件名);
    frame_nb = 0;
  }  公众诠释getnextframe(字节[]框)抛出异常
  {
    INT长度= 0;
    串length_string;
    字节[]帧=新的字节[5];    //读取当前帧的长度
    fis.read(帧_,0,5);    //转换帧_为整
    length_string =新的String(帧_);
    尝试{
      长度=的Integer.parseInt(length_string);
    }赶上(例外五){
      返回-1;
    }    回报(fis.read(帧,0,长度));
  }
}

更新

我试图在Windows 7上运行此程序再次使用Java 8u20早日进入建设11个,视频播放罚款没有任何粉红色的色调,所以我想,无论是造成这一问题现已解决在以后的Java构建

I'm looking for a solution to display a RTP JPEG stream with JavaFx. I can display jpeg from a file and receive RTP JPEG stream and split it to identify all parameters and data as specify in RFC2435 But I don't know how to convert my JPEG arrays to a displayable Image. I dont want to implement a JPEG Decoder by myself. Any idea?

解决方案

Leverage JavaFX's built-in jpeg decoder, which should be able to decode the jpeg images in the Image constructor.

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);
      )
    );
  }
}

The jpegData is a byte array presumed to contain the JFIF data for a frame extracted from the RTP stream.

Executable Sample

This is an mjpeg movie player that plays the movie from: http://inst.eecs.berkeley.edu/~ee122/sp06/ProgAsgns/movie.Mjpeg

Based on the video stream class from Programming Assignment 5: Streaming Video with RTSP and RTP (I do hope this is not your homework assignment class).

According to the video stream class description, it is a "proprietary MJPEG format", so you will need to do your own decoding of your standards compliant format according RFC2435.

The player works, but does have an issue correctly decoding the JPEGs which I have not investigated. Either the JPEGs in the "proprietary MJPEG format" sample movie are not correctly encoded, or the JavaFX JPEG codec has errors decoding frames. The visible artifact is that you can see the image, but the image is not correctly colored (has a pink shade). It is likely an instance of RT-14647 Incorrect display of JPEG images as the pink shade in the video looks the same in the incorrectly decoded JPEGs shown in the bug. You can clearly see the pink shade in the screenshot of the video rendered by the sample code below. The bug only effects some JPEG images (the great majority of JPEG image I have used with JavaFX have displayed fine). So you will just need to try with your video stream to see if the JavaFX jpeg decoder correctly decodes the jpeg images for you.

Rather than replacing the Image in the imageview each time, it is probably more efficient to use a WritableImage and update it's pixel buffer directly, but the brute force replace image method seemed to work OK for me.

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));
  }
}

Update

I tried running this program again using Java 8u20 early access build 11 on a Windows 7, and the video played back fine without any pink tinge, so I guess that whatever was causing that issue has now been fixed in a later Java build.

这篇关于显示RTP MJ​​PEG的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆