【Java】简易视频播放器

【效果图】

【功能】

1、当窗口获取焦点后,按空格暂停/播放

2、原速播放键、暂停/播放键、倍速播放键(最高3倍速,每次递增0.5)

3、进度条可点击选择播放位置

4、时间显示、播放速度显示

【项目与工具】

maven、java8、vlc-3.8.0、log4j-1.2.17

【代码】
Window.java

import java.awt.*;
import java.awt.event.*;
import java.util.Comparator;

import javax.swing.*;
import javax.swing.border.EmptyBorder;

import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import utils.FileUtils;

public class Window extends JFrame {
    // private final Logger logger = LoggerFactory.getLogger(Window.class);

    private static final int PROGRESS_HEIGHT = 10;
    private static final int PROGRESS_MIN_VALUE = 0;
    private static final int PROGRESS_MAX_VALUE = 100;
    // 总时间
    private static String TOTAL_TIME;
    // 播放速度
    private float speed;

    // 播放器组件
    private EmbeddedMediaPlayerComponent mediaPlayerComponent;
    // 进度条
    private JProgressBar progress;
    // 暂停按钮
    private Button pauseButton;
    // 显示播放速度的按钮
    private Label displaySpeed;
    // 显示时间
    private Label displayTime;
    // 进度定时器
    private Timer progressTimer;
    // 继续播放定时器
    private Timer continueTimer;
    // 所有视频路径
    private java.util.List<String> videos;
    // 当前播放视频的位置
    private int videoIndex;

    public Window(String videoFolder) {
        initVideoFilesPath(videoFolder);
        // 设置默认速度为原速
        speed = 1.0f;
        // 设置窗口标题
        setTitle("VideoPlayer");
        // 设置窗口焦点监听事件:窗口打开时、窗口获得焦点时设置默认焦点为暂停按钮
        this.addWindowFocusListener(getWindowFocusListener());

        // 窗口关闭事件:释放资源并退出程序
        addWindowListener(closeWindowReleaseMedia());
        // 设置默认窗口关闭事件
        // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 设置窗口位置
        setBounds(100, 100, 800, 600);
        // 最大化显示窗口
        // setExtendedState(JFrame.MAXIMIZED_BOTH);

        // 主面板
        JPanel contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        // ======播放面板======
        JPanel player = new JPanel();
        contentPane.add(player, BorderLayout.CENTER);
        contentPane.add(player);
        player.setLayout(new BorderLayout(0, 0));
        // 创建播放器组件并添加到容器中去
        mediaPlayerComponent = new EmbeddedMediaPlayerComponent();
        player.add(mediaPlayerComponent);
        // 视频表面焦点监听:表面获得焦点时设置默认焦点为暂停按钮
        getVideoSurface().addFocusListener(videoSurfaceFocusAction());
        // getMediaPlayer().setRepeat(true); // 重复播放

        // ======底部面板======
        JPanel bottomPanel = new JPanel();
        BoxLayout boxLayout = new BoxLayout(bottomPanel, BoxLayout.Y_AXIS);
        bottomPanel.setLayout(boxLayout);
        contentPane.add(bottomPanel, BorderLayout.SOUTH);

        // ------进度条组件面板------
        JPanel progressPanel = new JPanel();
        progress = new JProgressBar();
        progress.setMinimum(PROGRESS_MIN_VALUE);
        progress.setMaximum(PROGRESS_MAX_VALUE);
        progress.setPreferredSize(getNewDimension());
        // 设置进度条中间显示进度百分比
        progress.setStringPainted(false);
        // 进度条进度的颜色
        progress.setForeground(new Color(46, 145, 228));
        // 进度条背景的颜色
        progress.setBackground(new Color(220, 220, 220));

        // 点击进度条调整视频播放指针
        progress.addMouseListener(setVideoPlayPoint());
        // 定时器
        progressTimer = getProgressTimer();
        progressTimer.start();

        progressPanel.add(progress);
        progressPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
        bottomPanel.add(progressPanel);
        // contentPane.add(progressPanel, BorderLayout.SOUTH);

        // ------按钮组件面板------
        JPanel buttonPanel = new JPanel();
        // contentPane.add(buttonPanel, BorderLayout.SOUTH);
        buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
        bottomPanel.add(buttonPanel);

        displayTime = new Label();
        displayTime.setText(getTimeString());
        buttonPanel.add(displayTime);

        // 重置按钮:设置播放速度为原速
        Button resetButton = new Button("reset");
        resetButton.setFocusable(false);
        resetButton.addMouseListener(mouseClickedResetSpeed());
        buttonPanel.add(resetButton);

        // 暂停/播放按钮
        pauseButton = new Button("pause");
        pauseButton.addKeyListener(spaceKeyPressMediaPause());
        pauseButton.addMouseListener(mouseClickedMediaPause());
        buttonPanel.add(pauseButton);

        // 倍速播放按钮:每次递增0.5,最大为3倍速
        Button fastForwardButton = new Button(">>>");
        fastForwardButton.setFocusable(false);
        fastForwardButton.addMouseListener(mouseClickedFastForward());
        buttonPanel.add(fastForwardButton);

        // 播放速度显示按钮
        displaySpeed = new Label();
        displaySpeed.setText("x" + speed);
        displaySpeed.setFocusable(false);
        displaySpeed.setEnabled(false);
        buttonPanel.add(displaySpeed);

        // 监听窗口大小,设置进度条宽度为窗口宽度(但是对于最大化和还原窗口无效,原因未知<-_->)
        this.addComponentListener(windowResizedResetProgressWidth());
        // 监听窗口最大化和还原,设置进度条宽度为窗口宽度
        this.addWindowStateListener(windowStateChangedResetProgressWidth());

        continueTimer = getContinueTimer();
        continueTimer.start();
    }

    private void initVideoFilesPath(String videoFolder) {
        videos = FileUtils.readFilePath(videoFolder);
        videos.sort(Comparator.naturalOrder());
        videoIndex = 0;
        // System.out.println(videos);
    }

    public void play() {
        getMediaPlayer().playMedia(videos.get(videoIndex));
        setWindowTitle();
        // System.out.println("play video..." + getMediaPlayer().getMediaMeta().getTitle());
    }

    private void setWindowTitle() {
        String title = getMediaPlayer().getMediaMeta().getTitle();
        setTitle("VideoPlayer-" + title);
    }

    private String getTimeString(long curr, long total) {
        return formatSecond2Time(curr) + " / " + formatSecond2Time(total);
    }

    private String getTimeString() {
        setTotalTime();
        return formatSecond2Time(getMediaPlayer().getTime()) + " / " + TOTAL_TIME;
    }

    private void setTotalTime() {
        if (TOTAL_TIME == null) {
            long totalSecond = getMediaPlayer().getLength();
            TOTAL_TIME = formatSecond2Time(totalSecond);
        }
    }

    private String formatSecond2Time(long milliseconds) {
        int second = (int) (milliseconds / 1000);
        int h = second / 3600;
        int m = (second % 3600) / 60;
        int s = (second % 3600) % 60;
        return String.format("%02d", h) + ":" + String.format("%02d", m) + ":"
                + String.format("%02d", s);
    }

    private Timer getContinueTimer() {
        return new Timer(1000, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                long total = getMediaPlayer().getLength();
                long curr = getMediaPlayer().getTime();
                if (curr == total) {
                    videoIndex++;
                    if (videoIndex >= videos.size()) {
                        continueTimer.stop();
                        System.out.println("all videos finished...");
                        return;
                    }
                    getMediaPlayer().playMedia(videos.get(videoIndex));
                    setWindowTitle();
                    setProgress(getMediaPlayer().getTime(), getMediaPlayer().getLength());
                    progressTimer.restart();
                }
            }
        });
    }

    private Timer getProgressTimer() {
        return new Timer(1000, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (getProgress().getValue() >= PROGRESS_MAX_VALUE) {
                    // 结束定时器
                    progressTimer.stop();
                    return;
                }
                // 设置进度值
                long total = getMediaPlayer().getLength();
                long curr = getMediaPlayer().getTime();
                setProgress(curr, total);
            }
        });
    }

    private void setProgress(long curr, long total) {
        float percent = (float) curr / total;
        int value = (int) (percent * 100);
        getProgress().setValue(value);
        displayTime.setText(getTimeString(curr, total));
    }

    private WindowAdapter windowStateChangedResetProgressWidth() {
        return new WindowAdapter() {
            @Override
            public void windowStateChanged(WindowEvent state) {
                // state=1或7为最小化,此处不处理

                if (state.getNewState() == 0) {
                    // System.out.println("窗口恢复到初始状态");
                    setProgressWidthAutoAdaptWindow();
                } else if (state.getNewState() == 6) {
                    // System.out.println("窗口最大化");
                    setProgressWidthAutoAdaptWindow();
                }
            }
        };
    }

    private void setProgressWidthAutoAdaptWindow() {
        getProgress().setPreferredSize(getNewDimension());
    }

    private ComponentAdapter windowResizedResetProgressWidth() {
        return new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                setProgressWidthAutoAdaptWindow();
            }
        };
    }

    private Dimension getNewDimension() {
        return new Dimension(getWidth(), PROGRESS_HEIGHT);
    }

    private MouseAdapter setVideoPlayPoint() {
        return new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int x = e.getX();
                long total = getMediaPlayer().getLength();
                long time = (long) ((float) x / progress.getWidth() * total);
                setProgress(time, total);
                getMediaPlayer().setTime(time);
            }
        };
    }

    private FocusAdapter videoSurfaceFocusAction() {
        return new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {
                setPauseButtonAsDefaultFocus();
            }
        };
    }

    private WindowAdapter closeWindowReleaseMedia() {
        return new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                getMediaPlayer().stop();
                getMediaPlayer().release();
                System.exit(0);
            }
        };
    }

    private MouseListener mouseClickedResetSpeed() {
        return new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (speed == 1.0f) {
                    return;
                }
                speed = 1.0f;
                getMediaPlayer().setRate(speed);
                displaySpeed.setText("x" + speed);
            }
        };
    }

    private MouseListener mouseClickedFastForward() {
        return new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (speed >= 3.0f) {
                    speed = 1.0f;
                } else {
                    speed += 0.5f;
                }
                getMediaPlayer().setRate(speed);
                displaySpeed.setText("x" + speed);
            }
        };
    }

    private MouseAdapter mouseClickedMediaPause() {
        return new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                getMediaPlayer().pause();
                if (progressTimer.isRunning()) {
                    progressTimer.stop();
                } else {
                    progressTimer.restart();
                }
            }
        };
    }

    private WindowFocusListener getWindowFocusListener() {
        return new WindowAdapter() {
            @Override
            public void windowOpened(WindowEvent e) {
                setPauseButtonAsDefaultFocus();
            }

            @Override
            public void windowGainedFocus(WindowEvent e) {
                setPauseButtonAsDefaultFocus();
            }

            @Override
            public void windowLostFocus(WindowEvent e) {}
        };
    }

    private void setPauseButtonAsDefaultFocus() {
        pauseButton.requestFocus();
    }

    private KeyListener spaceKeyPressMediaPause() {
        return new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                    getMediaPlayer().pause();
                }
            }
        };
    }

    private JProgressBar getProgress() {
        return progress;
    }

    private EmbeddedMediaPlayer getMediaPlayer() {
        return mediaPlayerComponent.getMediaPlayer();
    }

    private Canvas getVideoSurface() {
        return mediaPlayerComponent.getVideoSurface();
    }

}

Main.java

import org.apache.log4j.BasicConfigurator;

import com.sun.jna.NativeLibrary;

import uk.co.caprica.vlcj.runtime.RuntimeUtil;

public class Main {
    public static void main(String[] args) {
        // 解决日志报错问题
        BasicConfigurator.configure();

        // 关闭日志
        // Logger.getRootLogger().shutdown();

        // 加载dll
        NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), "vlc");

        // 方式一:直接传文件夹
        String videoFolder = "E:\\tmp\\test\\videoTest";
        Window frame = new Window(videoFolder);
        frame.setVisible(true);
        frame.play();

        // 方式二:传文件
        // String filePath = "E:\\tmp\\test\\videoTest\\01_编程语言运行机制.avi";
        // EmbeddedMediaPlayer mediaPlayer = frame.getMediaPlayer();
        // mediaPlayer.playMedia(filePath);

    }

}

FileUtils.java

package utils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Stack;

public class FileUtils {

    public static List<String> readFilePath(String folderPath) {
        List<String> list = new ArrayList<>();
        File folder = new File(folderPath);
        if (!folder.isDirectory()) {
            return list;
        }
        File[] files = folder.listFiles();
        if (Objects.isNull(files) || files.length <= 0) {
            return list;
        }
        for (File file : files) {
            if (!file.isFile()) {
                continue;
            }
            list.add(file.getAbsolutePath());
        }
        return list;
    }

    public static List<String> readAllFilePath(String folderPath) {
        Stack<File> stack = new Stack<>();
        List<String> list = new ArrayList<>();
        File folder = new File(folderPath);
        if (!folder.isDirectory()) {
            return list;
        }
        stack.push(folder);
        while (!stack.isEmpty()) {
            File tmpFile = stack.pop();
            File[] subFiles = tmpFile.listFiles();
            if (subFiles == null) {
                continue;
            }
            for (File subFile : subFiles) {
                if (subFile.isDirectory()) {
                    stack.push(subFile);
                } else {
                    list.add(subFile.getAbsolutePath());
                }
            }
        }
        return list;
    }

}

依赖

<dependencies>

        <!-- https://mvnrepository.com/artifact/uk.co.caprica/vlcj -->
        <dependency>
            <groupId>uk.co.caprica</groupId>
            <artifactId>vlcj</artifactId>
            <version>3.8.0</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.8.0-beta0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.8.0-beta0</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>

vlc

vlc安装目录下的:
libvlc.dll文件
libvlccore.dll文件
plugins文件夹

官网地址:https://www.videolan.org/vlc/

【项目结构】

【参考链接】

1、Java利用VLC开发简易的视频播放器-单向箭头
https://www.cnblogs.com/SnailsRunning/p/10251912.html

2、Java利用VLC开发简易视屏播放器-冷月枫寂
https://www.cnblogs.com/deng-c-q/p/7510418.html

3、使用java创建一个简易的视屏播放器-南柯一梦x
https://blog.csdn.net/nankeyimengxihe/article/details/50419449

4、Java Swing 图形界面开发(目录)-xietansheng
https://blog.csdn.net/xietansheng/article/details/72814492

5、Java制作进度条-晨曦之光Wing
https://blog.csdn.net/qq_36533690/article/details/106448207

6、MediaPlayerForJava(创建一个视频播放器)-FeiHuang
https://www.jianshu.com/p/2c61e3c6aa70

7、SLF4J: No SLF4J providers were found.-香山上的麻雀
https://www.jianshu.com/p/41e0a730347f

8、vlc官方文档
http://javadox.com/uk.co.caprica/vlcj/3.0.1/uk/co/caprica/vlcj/player/MediaPlayer.html

【说明】

没事做着玩一玩,其实也可以用一用,不过vlc会报几个错(好像也不会影响使用),目前暂时还没找到解决方法<-_->。错误比如这个[00000000222fd390] direct3d11 vout display error: SetThumbNailClip failed: 0x800706f4

【GitHub】

https://github.com/cxzgwing/simple-video-player

【后记】

2020.06.09

GitHub中的项目,截止到2020.06.09,简易播放器新增以下功能(共12个commits):

1、声音控制模块:音量百分比显示、点击音量进度条设置音量、鼠标轮滑滚动设置音量

2、选择文件按钮:支持多选文件(暂未判断文件类型)

3、查看播放文件列表(半透明效果):列表中文件名支持换行显示

4、播放/暂停按钮文案动态显示

5、升级了log4j版本,1.2.17升级到2.13.3

(最新版本与本文展示的源码版本差距有一丢丢大,嘻嘻(#^.^#),播放模式也改了,之前是写好路径,运行窗口就播放,最新版本是选择文件后点击播放按钮或按空格才播放)

【升级版本项目地址】

cxzgwing/video-player: Java简易视频播放器 升级版 (github.com)

【升级版本效果图】

 

  • 12
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
要创建一个简易视频播放器,你需要掌握以下几个步骤: 1. 导入所需的包和库 在Java中,你需要使用javax.swing包来创建用户界面,同时还需要使用Java Media Framework(JMF)库来处理视频。你可以从官方网站下载并安装JMF。 2. 创建用户界面 使用Swing包中的JFrame类创建一个窗口,然后添加一个JPanel组件作为视频播放区域。你还可以添加其他组件,如按钮和菜单项,以实现播放器的控制功能。 3. 加载视频文件 使用JMF库中的Player类加载视频文件,然后将视频显示在JPanel组件中。 4. 实现播放器控制功能 为播放器添加控制按钮和菜单项,如播放、暂停、停止和调整音量等。 5. 处理视频事件 使用JMF库中的相应类处理视频事件,如开始播放、暂停、停止和完成等。 下面是一个简单的示例代码,可以创建一个简单的视频播放器: ``` import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import javax.media.Manager; import javax.media.Player; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; public class VideoPlayer extends JFrame implements ActionListener { private Player player; private File file; private JButton openButton, playButton, pauseButton, stopButton; private JFileChooser fileChooser; public VideoPlayer() { super("Video Player"); setSize(640, 480); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel playerPanel = new JPanel(); getContentPane().add(playerPanel, BorderLayout.CENTER); openButton = new JButton("Open"); openButton.addActionListener(this); getContentPane().add(openButton, BorderLayout.NORTH); JPanel controlPanel = new JPanel(); playButton = new JButton("Play"); playButton.addActionListener(this); pauseButton = new JButton("Pause"); pauseButton.addActionListener(this); stopButton = new JButton("Stop"); stopButton.addActionListener(this); controlPanel.add(playButton); controlPanel.add(pauseButton); controlPanel.add(stopButton); getContentPane().add(controlPanel, BorderLayout.SOUTH); fileChooser = new JFileChooser(); } public void actionPerformed(ActionEvent e) { if (e.getSource() == openButton) { int result = fileChooser.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { file = fileChooser.getSelectedFile(); playVideo(); } } else if (e.getSource() == playButton) { player.start(); } else if (e.getSource() == pauseButton) { player.stop(); } else if (e.getSource() == stopButton) { player.stop(); player.setMediaTime(new Time(0)); } } private void playVideo() { try { player = Manager.createPlayer(file.toURI().toURL()); player.realize(); player.prefetch(); getContentPane().validate(); player.start(); } catch (Exception ex) { JOptionPane.showMessageDialog(this, "Invalid file or player error: " + ex.getMessage()); } } public static void main(String[] args) { VideoPlayer player = new VideoPlayer(); player.setVisible(true); } } ``` 这段代码创建了一个简单的视频播放器,包括一个打开按钮和三个控制按钮(播放、暂停和停止)。当用户点击打开按钮时,会弹出文件选择器,允许用户选择要播放的视频文件。播放器使用JMF库中的Player类来加载视频文件并将其显示在窗口中。用户可以使用控制按钮来播放、暂停或停止视频。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值