diff --git a/AppSinkListener.java b/AppSinkListener.java deleted file mode 100644 index 5309230..0000000 --- a/AppSinkListener.java +++ /dev/null @@ -1,68 +0,0 @@ -package application; - -import java.nio.ByteBuffer; - -import org.freedesktop.gstreamer.Buffer; -import org.freedesktop.gstreamer.FlowReturn; -import org.freedesktop.gstreamer.Sample; -import org.freedesktop.gstreamer.Structure; -import org.freedesktop.gstreamer.elements.AppSink; - - -import javafx.scene.image.Image; -import javafx.scene.image.PixelFormat; -import javafx.scene.image.PixelWriter; -import javafx.scene.image.WritableImage; - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; - - -public class AppSinkListener implements AppSink.NEW_SAMPLE { - - private Image actualFrame; - private int lastWidth = 0; - private int lastHeigth = 0; - private byte[] byteArray; - private ImageContainer imageContainer = new ImageContainer(); - - public ImageContainer getImageContainer(){ - return imageContainer; - } - - @Override - public FlowReturn newSample(AppSink appSink) { - // Try to get a sample - Sample sample = appSink.pullSample(); - Buffer buffer = sample.getBuffer(); - ByteBuffer byteBuffer = buffer.map(false); - if (byteBuffer != null){ - Structure capsStruct = sample.getCaps().getStructure(0); - int width = capsStruct.getInteger("width"); - int height = capsStruct.getInteger("height"); - if (width != lastWidth || height != lastHeigth){ - lastWidth = width; - lastHeigth = height; - byteArray = new byte[width * height * 4]; - } - // Writes the buffer to the byteArray - byteBuffer.get(byteArray); - actualFrame = convertBytesToImage(byteArray, width, height); - // Writes the new Image to the ImageContainer. If an other part of the programm wants to do something like displaying or storing - //with the frames it can set up a changeListener to get a chance to do something with the newest frame. - imageContainer.setImage(actualFrame); - buffer.unmap(); - } - sample.dispose(); - return FlowReturn.OK; - } - - private Image convertBytesToImage(byte[] pixels, int width, int height){ - //Writes a bytearray to a WritableImage. - WritableImage img = new WritableImage(width, height); - PixelWriter pw = img.getPixelWriter(); - pw.setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), pixels, 0, width *4); - return img; - } - -} \ No newline at end of file diff --git a/GstRenderer.java b/GstRenderer.java deleted file mode 100644 index 48462a7..0000000 --- a/GstRenderer.java +++ /dev/null @@ -1,111 +0,0 @@ -package application; - - -import java.nio.ByteOrder; - -import org.freedesktop.gstreamer.Bin; -import org.freedesktop.gstreamer.Bus; -import org.freedesktop.gstreamer.Caps; -import org.freedesktop.gstreamer.Gst; -import org.freedesktop.gstreamer.Message; -import org.freedesktop.gstreamer.Pipeline; -import org.freedesktop.gstreamer.elements.AppSink; - -import javafx.application.Application; -import javafx.application.Platform; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.scene.Scene; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.BorderPane; -import javafx.stage.Stage; - -/* - * The main idea is to create a pipeline that has an appsink to display the images. - * Connect the AppSink to the rest of the pipeline. - * Connect the AppSinkListener to the AppSink. - * The AppSink writes frames to the ImageContainer. - * if you want to display the Videoframes simply add a changeListener to the container who will draw the current - * Image to a Canvas or ImageView. - */ - - -public class GstRenderer extends Application{ - private ImageView imageView; - private AppSink videosink; - private Pipeline pipe; - private Bin bin; - Bus bus; - private StringBuilder caps; - private ImageContainer imageContainer; - public GstRenderer() { - videosink = new AppSink("GstVideoComponent"); - videosink.set("emit-signals", true); - AppSinkListener GstListener = new AppSinkListener(); - videosink.connect(GstListener); - caps = new StringBuilder("video/x-raw, "); - // JNA creates ByteBuffer using native byte order, set masks according to that. - if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) { - caps.append("format=BGRx"); - } else { - caps.append("format=xRGB"); - } - videosink.setCaps(new Caps(caps.toString())); - videosink.set("max-buffers", 5000); - videosink.set("drop", true); - bin = Bin.launch("autovideosrc ! videoconvert ", true); - pipe = new Pipeline(); - pipe.addMany(bin, videosink); - Pipeline.linkMany(bin, videosink); - imageView = new ImageView(); - - imageContainer = GstListener.getImageContainer(); - imageContainer.addListener(new ChangeListener() { - - @Override - public void changed(ObservableValue observable, Image oldValue, final - Image newValue) { - Platform.runLater(new Runnable() { - @Override - public void run() { - imageView.setImage(newValue); - } - }); - - } - - }); - - bus = pipe.getBus(); - bus.connect(new Bus.MESSAGE() { - - @Override - public void busMessage(Bus arg0, Message arg1) { - - System.out.println(arg1.getStructure()); - } - }); - pipe.play(); - - } - - @Override - public void start(Stage primaryStage) throws Exception { - primaryStage.setTitle("Drawing Operations Test"); - BorderPane grid = new BorderPane(); - grid.setCenter(imageView); - imageView.fitWidthProperty().bind(grid.widthProperty()); - imageView.fitHeightProperty().bind(grid.heightProperty()); - imageView.setPreserveRatio(true); - primaryStage.setScene(new Scene(grid, 460, 460)); - primaryStage.show(); - } - - public static void main(String[] args) { - Gst.init("CameraTest",args); - launch(args); - } -} - - diff --git a/ImageContainer.java b/ImageContainer.java deleted file mode 100644 index fb14e59..0000000 --- a/ImageContainer.java +++ /dev/null @@ -1,25 +0,0 @@ -package application; - - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ChangeListener; -import javafx.scene.image.Image; - - -public class ImageContainer { - private ObjectProperty image = new SimpleObjectProperty(); - - public Image getImage() { - return image.get(); - } - - public void setImage(Image image) { - this.image.set(image); - } - - public void addListener(ChangeListener listener){ - image.addListener(listener); - } -} - diff --git a/mediaplayer/GstMediaPlayer.java b/mediaplayer/GstMediaPlayer.java new file mode 100644 index 0000000..013cfaf --- /dev/null +++ b/mediaplayer/GstMediaPlayer.java @@ -0,0 +1,133 @@ +package mediaplayer; + + +import java.net.URI; +import java.util.logging.Logger; + +import org.freedesktop.gstreamer.Bus; +import org.freedesktop.gstreamer.Gst; +import org.freedesktop.gstreamer.GstObject; +import org.freedesktop.gstreamer.elements.AppSink; +import org.freedesktop.gstreamer.elements.PlayBin; +import org.freedesktop.gstreamer.fx.FXImageSink; +import org.freedesktop.gstreamer.message.Message; + +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; + +/* + * The main idea is to use FXImageSink and PlayBin to play a media file in this ImageView. + * A main JavaFX Application can simply add this Node to the scene graph and control the media + * in a very basic way (start/stop/repeat) + */ + + +public class GstMediaPlayer extends ImageView { + + private final static Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + + private AppSink videosink; + + private PlayBin playbin; + + private boolean repeat = false; + + public GstMediaPlayer(double x, double y) { + init(null, x, y); + } + + public GstMediaPlayer() { + init(null, 0, 0); + } + + public GstMediaPlayer(URI video, double x, double y) { + init(video, x, y); + } + + public GstMediaPlayer(URI video) { + init(video, 0, 0); + } + + private void init (URI video, double x, double y) { + + LOGGER.info("Init"); + + setX(x); + setY(y); + + Gst.init("GstMediaPlayer", new String[0]); + + videosink = new AppSink("GstVideoComponent"); + videosink.set("max-buffers", 5000); + videosink.set("drop", true); + + FXImageSink fXImageSink = new FXImageSink(videosink); + fXImageSink.imageProperty().addListener( + imageProperty().bind(fXImageSink.imageProperty()); + + if (video != null) + playbin = new PlayBin("playbin", video); + else + playbin = new PlayBin("playbin"); + playbin.setVideoSink(videosink); + + setPreserveRatio(true); + + playbin.getBus().connect("element", new Bus.MESSAGE() { + @Override + public void busMessage(Bus arg0, Message arg1) { + LOGGER.info("Bus message: " + arg1.getStructure()); + } + }); + + playbin.getBus().connect(new Bus.EOS() { + @Override + public void endOfStream(GstObject source) { + playbin.stop(); + if (repeat) playbin.play(); + } + }); + + } + + public void setURI(URI uri) { + playbin.setURI(uri); + } + + public void close() { + playbin.close(); + } + + public void stop() { + repeat = false; + playbin.stop(); + LOGGER.fine("stopping/stopped "); + } + + public void play() { + playbin.play(); + } + + public void play(URI uri) { + playbin.stop(); + playbin.setURI(uri); + playbin.play(); + } + + public void playAndRepeat() { + playAndRepeat(null); + } + + public void playAndRepeat(URI uri) { + LOGGER.info("playAndRepeat " + uri); + repeat = true; + if (uri != null) { + play(uri); + } else { + playbin.play(); + } + } +} diff --git a/mediaplayer/GstPlayVideo.java b/mediaplayer/GstPlayVideo.java new file mode 100644 index 0000000..af11dd8 --- /dev/null +++ b/mediaplayer/GstPlayVideo.java @@ -0,0 +1,54 @@ +package mediaplayer; + +import java.nio.file.Paths; + + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.event.EventHandler; +import javafx.scene.Scene; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.StackPane; +import javafx.stage.Stage; +import javafx.stage.StageStyle; + +public class GstPlayVideo extends Application { + + + private Scene scene; + + private GstMediaPlayer mpMain; + + public static void main(String[] args) { + System.out.println("STart v08:48+ GstPlayVideo"); + launch(args); + } + + @Override + public void start(Stage primaryStage) throws Exception { + + String video = getParameters().getRaw().get(0); + System.out.println("Playing " + Paths.get("", video).toUri()); + + mpMain = new GstMediaPlayer(Paths.get("", video).toUri()); + + StackPane ap = new StackPane(mpMain); + + scene = new Scene(ap); + + scene.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler() { + @Override + public void handle(MouseEvent event) { + System.out.println("STOP"); + Platform.exit(); + } + }); + + primaryStage.setScene(scene); + primaryStage.initStyle(StageStyle.UNDECORATED); + primaryStage.setFullScreen(true); + primaryStage.show(); + mpMain.play(); + } + +}