通过RTP流式Java Swing组件

时间:2011-08-08 14:12:03

标签: java swing rtp

目前,我正在寻找一种选项,通过RTP将JPanel的内容流式传输到接收客户端。 JPanel将例如包含一个JFreeChart和一些应该显示在远程客户端播放器上的标签(事实上它恰好是一个支持RTP的演示软件)。

是否有任何库允许从UI组件生成这样的流并随后通过RTP进行传输?

感谢任何提示和建议 KC

P.S .: 回答Qwerky的问题:只应传播他们的视觉表现(例如他们的形象)。

1 个答案:

答案 0 :(得分:0)

最后,我最终实现了一个基于JMF的组件流包:

JpegHelper:

package ch.beo.streaming.swing;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;

    /**
     * Helper class to convert UI components to JPEG images.
     */
    public final class JpegHelper {
        private JpegHelper() {
    }

    /**
     * Transforms any given UI {@link java.awt.Component Component} to a JPEG
     * image.
     * 
     * @param component
     *            A paintable {@link java.awt.Component Component}.
     * @return The binary representation of JPEG image, representing
     *         <code>component's</code> current visual state.
     */
    public static byte[] componentToJpeg(Component component) {
        Dimension size = component.getSize();
        BufferedImage image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics2d = image.createGraphics();
        component.paint(graphics2d);
        graphics2d.dispose();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "jpg", out);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return out.toByteArray();
    }
}

ComponentBufferStream:

package ch.beo.streaming.swing;

import java.awt.Component;
import java.awt.Dimension;
import java.io.IOException;

import javax.media.Buffer;
import javax.media.Format;
import javax.media.format.VideoFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.PullBufferStream;

import ch.beo.streaming.base.ControlHelper;

/**
 * Implements a {@link javax.media.protocol.PullBufferStream PullBufferStream}
 * based on a given {@link java.awt.Component Component}. The current visual
 * representation of the {@link java.awt.Component component} is continuously
 * provided as a JPEG image.
 */
public class ComponentBufferStream implements PullBufferStream {
    private static final int KEY_FRAME_RATE = 100;
    private final Component component;
    private int frameCount = -1;

    public ComponentBufferStream(Component component) {
        this.component = component;
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.SourceStream#endOfStream()
     */
    @Override
    public boolean endOfStream() {
        return false;
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.SourceStream#getContentDescriptor()
     */
    @Override
    public ContentDescriptor getContentDescriptor() {
        return new ContentDescriptor(ContentDescriptor.RAW);
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.SourceStream#getContentLength()
     */
    @Override
    public long getContentLength() {
        return LENGTH_UNKNOWN;
    }

    /*
     * (non-Javadoc)
     * @see javax.media.Controls#getControl(java.lang.String)
     */
    @Override
    public Object getControl(String controlType) {
        return ControlHelper.getControl(this, controlType);
    }

    /*
     * (non-Javadoc)
     * @see javax.media.Controls#getControls()
     */
    @Override
    public Object[] getControls() {
        return ControlHelper.getControls(this);
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.PullBufferStream#getFormat()
     */
    @Override
    public Format getFormat() {
        Dimension size = component.getSize();
        return new VideoFormat(VideoFormat.JPEG, size, Format.NOT_SPECIFIED, Format.byteArray, 0.1f);
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.PullBufferStream#read(javax.media.Buffer)
     */
    @Override
    public void read(Buffer buffer) throws IOException {
        byte[] image = JpegHelper.componentToJpeg(component);
        byte[] data = (byte[]) buffer.getData();
        if (data != null && data.length - buffer.getOffset() >= image.length) {
            System.arraycopy(image, 0, data, buffer.getOffset(), image.length);
        } else {
            buffer.setData(image);
            buffer.setOffset(0);
        }
        buffer.setLength(image.length);
        buffer.setFormat(getFormat());
        if (isKeyFrame()) {
            buffer.setFlags(buffer.getFlags() | Buffer.FLAG_KEY_FRAME);
        }
    }

    private boolean isKeyFrame() {
        if (++frameCount % KEY_FRAME_RATE == 0) {
            frameCount = 0;
            return true;
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.PullBufferStream#willReadBlock()
     */
    @Override
    public boolean willReadBlock() {
        Dimension dimension = component.getSize();
        return dimension.height > 0 && dimension.width > 0;
    }
}

ComponentDataSource:

package ch.beo.streaming.swing;

import java.awt.Component;
import java.io.IOException;

import javax.media.Time;
import javax.media.protocol.PullBufferDataSource;
import javax.media.protocol.PullBufferStream;

import ch.beo.streaming.base.ControlHelper;

/**
 * Implements a {@link javax.media.protocol.PullBufferDataSource
 * PullBufferDataSource} based on a given {@link java.awt.Component Component}.
 * The current visual representation of the {@link java.awt.Component component}
 * is continuously provided as a JPEG image.
 */
public class ComponentDataSource extends PullBufferDataSource {
    private final PullBufferStream[] streams;

    public ComponentDataSource(Component component) {
        streams = new PullBufferStream[] { new ComponentBufferStream(component) };
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.DataSource#connect()
     */
    @Override
    public void connect() throws IOException {
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.DataSource#disconnect()
     */
    @Override
    public void disconnect() {
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.DataSource#getContentType()
     */
    @Override
    public String getContentType() {
        return streams[0].getContentDescriptor().getContentType();
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.DataSource#getControl(java.lang.String)
     */
    @Override
    public Object getControl(String controlType) {
        return ControlHelper.getControl(this, controlType);
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.DataSource#getControls()
     */
    @Override
    public Object[] getControls() {
        return ControlHelper.getControls(this);
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.DataSource#getDuration()
     */
    @Override
    public Time getDuration() {
        return Time.TIME_UNKNOWN;
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.DataSource#start()
     */
    @Override
    public void start() throws IOException {
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.DataSource#stop()
     */
    @Override
    public void stop() throws IOException {
    }

    /*
     * (non-Javadoc)
     * @see javax.media.protocol.PullBufferDataSource#getStreams()
     */
    @Override
    public PullBufferStream[] getStreams() {
        return streams;
    }
}

除了其他一些辅助类之外,这也是一招。