You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java Swing实现视频渲染功能?

Java Swing实现视频渲染方案

Swing本身未内置视频解码渲染能力,核心实现逻辑为:先把视频解码为逐帧的BufferedImage,再定时触发面板重绘替换当前显示的帧即可。你原有代码中将静态图片读取放在paint方法中的写法不合理,每次重绘都会重复执行IO操作,性能极差,可参考以下方案修改:

实现代码示例

可使用封装了FFmpeg的JavaCV库完成视频解码,无需自行处理复杂的编码适配逻辑:

import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public class AuroraPanel extends JPanel {
    private JFrame master;
    // 当前需要渲染的视频帧
    private BufferedImage currentVideoFrame;
    // FFmpeg视频帧抓取器
    private FFmpegFrameGrabber frameGrabber;
    // Frame转BufferedImage转换器
    private Java2DFrameConverter frameConverter = new Java2DFrameConverter();
    // Swing定时刷新器
    private Timer renderTimer;
    // 视频帧率,可根据实际视频参数调整
    private static final int FRAME_RATE = 30;

    public AuroraPanel(JFrame master, String videoResourcePath) {
        this.master = master;
        // 初始化视频解码器
        try {
            frameGrabber = new FFmpegFrameGrabber(getClass().getResource(videoResourcePath).openStream());
            frameGrabber.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 按帧率间隔定时读取帧并触发重绘
        renderTimer = new Timer(1000 / FRAME_RATE, e -> {
            try {
                Frame frame = frameGrabber.grabImage();
                // 帧为空代表视频播放完毕,需要循环的话重置到第一帧即可
                if (frame == null) {
                    frameGrabber.setFrameNumber(0);
                    frame = frameGrabber.grabImage();
                }
                currentVideoFrame = frameConverter.convert(frame);
                repaint();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });
        renderTimer.start();
    }

    @Override
    protected void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);
        Graphics2D g2d = (Graphics2D) graphics;
        // 原有背景绘制逻辑保留
        g2d.setColor(Color.DARK_GRAY);
        g2d.fillRect(0, 0, master.getWidth(), 40);
        g2d.setColor(new Color(0, 0, 0));
        g2d.fillRect(0, 30, master.getWidth(), master.getHeight() - 30);
        // 替换原有静态图片绘制逻辑,渲染当前视频帧
        if (currentVideoFrame != null) {
            g2d.drawImage(currentVideoFrame, 0, 30, this);
        }
        g2d.setColor(Color.DARK_GRAY);
        g2d.fillRect(0, master.getHeight() - 350, master.getWidth(), master.getHeight());
    }

    // 窗口关闭时调用,释放视频解码资源
    public void releaseResource() {
        renderTimer.stop();
        try {
            frameGrabber.stop();
            frameGrabber.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意事项

  • 必须使用Swing Timer触发帧更新和重绘,Swing组件的UI操作必须在事件调度线程执行,否则会出现闪烁、界面错乱等问题
  • 不要将视频帧读取、文件IO等操作放在paintComponent方法中执行,该方法每次重绘都会被调用,会直接导致渲染卡顿
  • 不需要循环播放的话,读取到空帧时直接停止renderTimer即可
  • 窗口关闭时必须手动调用资源释放方法,避免解码资源泄漏

内容的提问来源于stack exchange,提问作者hopes32 _

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 07:12:03