/*
* Copyright (c) 2008 Peter Bocz
*
* This file is part of gstreamer-java.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* version 3 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gstreamer.swt;
import java.nio.IntBuffer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.gstreamer.elements.RGBDataSink;
public class VideoComponent extends Canvas {
private ImageData currentImageData = null;
private Object currentImageDataLock = new Object();
private Image currentImage;
private final RGBDataSink videosink;
private int alpha = 255;
private String ovText;
private long start = System.currentTimeMillis();
private boolean keepAspect = true;
private boolean showOverlay = false;
private boolean showFPS = false;
private Color bgColor;
private int sizeX = 0, sizeY = 0;
private int newX = 0, newY = 0;
private Font gcFont;
private int redrawFps;
private int redrawInterval;
public VideoComponent(final Composite parent, int style) {
this(parent, style, 25);
}
public VideoComponent(final Composite parent, int style, int redrawFps) {
super(parent, style | SWT.DOUBLE_BUFFERED);
setRedrawFps(redrawFps);
videosink = new RGBDataSink("GstVideoComponent", new RGBListener());
videosink.setPassDirectBuffer(true);
gcFont = new Font(getDisplay(), "Arial", 13, SWT.NORMAL);
addPaintListener();
addDisposeListener();
startRedrawCycle();
}
public int getRedrawFps() {
return redrawFps;
}
public void setRedrawFps(int redrawFps) {
if (redrawFps < 1000 && redrawFps >= 1) {
this.redrawFps = redrawFps;
redrawInterval = 1000 / redrawFps;
}
}
public int getSizeX() {
return sizeX;
}
public int getSizeY() {
return sizeY;
}
public int getNewX() {
return newX;
}
public int getNewY() {
return newY;
}
/**
* Retrieves the Gstreamer element, representing the video component
*
* @return element
*/
public RGBDataSink getElement() {
return videosink;
}
/**
* Set to keep aspect ratio
*
* @param keepAspect
*/
public void setKeepAspect(boolean keepAspect) {
this.keepAspect = keepAspect;
}
/**
* Set the aplpha value of the video component. It works fine when overlay
* is turned off.
*
* @param alpha
*/
public void setAlpha(int alpha) {
this.alpha = alpha;
}
/**
* Set the overlay text of the video component. It works fine when overlay
* is turned off.
*
* @param text
*/
public void setOverlay(String text) {
this.ovText = text;
}
/**
* Set show FPS of the video component. It works fine when overlay is turned
* off.
*
* @param bn
*/
public void showFPS(boolean bn) {
this.showFPS = bn;
}
/**
* Set show overlay text. It works fine when overlay is turned off.
*
* @param bn
*/
public void showOverlay(boolean bn) {
this.showOverlay = bn;
}
/**
* Retrieves the alpha value of the video component
*
* @return alpha value of the video component
*/
public int getAlpha() {
return alpha;
}
/**
* Sets the background color
*
* @param bgColor
*/
public void setBackGroundColor(Color bgColor) {
this.bgColor = bgColor;
}
/**
* Gets the background color
*
* @param bgColor
*/
public Color getBackGroundColorColor() {
return bgColor;
}
public Image getCurrentImage() {
synchronized (currentImageDataLock) {
if (currentImageData != null)
return new Image(getDisplay(), currentImageData);
}
return null;
}
public ImageData getCurrentImageData() {
synchronized (currentImageDataLock) {
if (currentImageData != null)
return (ImageData) currentImageData.clone();
}
return null;
}
private void addPaintListener() {
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
if (!isDisposed()) {
GC gc = event.gc;
Point size = getSize();
if (size.x != 0 && size.y != 0) {
if (gcFont != null && !gcFont.isDisposed())
gc.setFont(gcFont);
if (bgColor != null) {
gc.setBackground(bgColor);
gc.fillRectangle(0, 0, size.x, size.y);
}
synchronized (currentImageDataLock) {
if (currentImageData != null) {
if (currentImage != null && !currentImage.isDisposed())
currentImage.dispose();
newX = 0;
newY = 0;
int fps = 0;
int currentWidth = currentImageData.width;
int currentHeight = currentImageData.height;
if ((currentWidth != size.x) || (currentHeight != size.y)) {
sizeX = size.x;
sizeY = size.y;
gc.setInterpolation(SWT.HIGH);
if (keepAspect) {
if (((float) currentWidth / (float) size.x) > ((float) currentHeight
/ (float) size.y)) {
sizeY = (int) ((float) size.x * (float) currentHeight
/ (float) currentWidth);
newY = (int) (((float) size.y - (float) sizeY) / 2f);
} else {
sizeX = (int) ((float) size.y * (float) currentWidth
/ (float) currentHeight);
newX = (int) (((float) size.x - (float) sizeX) / 2f);
}
}
currentImageData = currentImageData.scaledTo(sizeX, sizeY);
}
if (alpha != gc.getAlpha())
gc.setAlpha(alpha);
currentImage = new Image(getDisplay(), currentImageData);
gc.drawImage(currentImage, newX, newY);
if (showFPS)
fps = (int) (1000 / (System.currentTimeMillis() - start));
if (showOverlay) {
gc.drawText(ovText, newX + 5, newY + 5, false);
newY += 20;
}
if (showFPS) {
gc.drawText(" FPS:" + fps, newX + 5, newY + 5, false);
start = System.currentTimeMillis();
}
}
}
}
}
}
});
}
private void addDisposeListener() {
if (gcFont != null && !gcFont.isDisposed())
gcFont.dispose();
if (currentImage != null && !currentImage.isDisposed())
currentImage.dispose();
}
private void startRedrawCycle() {
getDisplay().timerExec(redrawInterval, new Runnable() {
public void run() {
if (!isDisposed()) {
redraw();
getDisplay().timerExec(redrawInterval, this);
}
}
});
}
private class RGBListener implements RGBDataSink.Listener {
public void rgbFrame(boolean isPrerollFrame, int width, int height, IntBuffer rgb) {
synchronized (currentImageDataLock) {
int[] pixels = new int[width * height];
rgb.get(pixels);
currentImageData = new ImageData(width, height, 24, new PaletteData(0xFF0000, 0x00FF00, 0x0000FF));
currentImageData.setPixels(0, 0, width * height, pixels, 0);
}
}
}
}