通过 RTP 传输 Java Swing 组件

发布于 2024-11-28 08:39:48 字数 231 浏览 2 评论 0原文

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

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

感谢您的任何提示和建议 KC

附注: 回答 Qwerky 的问题:仅应传输其视觉表示(例如其图像)。

Currently, I am looking for an option to stream the contents of a JPanel over RTP to a receiving client. The JPanel would e.g. contain a JFreeChart and some labels that should be displayed on a remote client player (which in fact happens to be a presentation software with RTP support).

Are there any libraries that would allow such a stream generation from UI components and its subsequent transmission over RTP?

Thanks for any hints and advices
KC

P.S.:
In response to Qwerky's question: Only their visual representation (e.g. their image) should be transmitted.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

尐偏执 2024-12-05 08:39:48

最后,我最终实现了一个基于 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;
    }
}

以及其他一些帮助器类,这达到了目的。

Concludingly, I ended up implementing a JMF-based component stream package:

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

Along with some other helper classes, this did the trick.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文