JavaSwing_基于VLC media player内核制作一个简单的视频播放器

本文档介绍了如何利用VLCj库在Java中创建一个基于VLCmediaplayer的视频播放器。首先从VideoLAN官网下载VLCmediaplayer,然后引入vlcj库的必要jar包。在开发过程中,需要设置VLC播放器的系统库路径,创建窗体并添加组件,实现视频的播放、暂停、停止等功能。同时,还展示了如何处理视频的进度条和音量控制,以及添加字幕和文件选择器的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、VLC media player的下载与安装

提示:VideoLAN 的官网下载 VLC media player,制作的视频播放器内核需要调用 VLC media player

VideoLAN:http://www.videolan.org/

VLC command-line help:https://wiki.videolan.org/VLC_command-line_help/

二、下载相关的在线开源库:vlcj

提示:只需要加载必备的 5 个 jar 包就可以:

所需jar包

三、开发步骤

1.1、创建项目并引入所需jar包

项目结构如下:
项目结构

1.2、核心代码

1.2.1、VideoPlayer.java(主类):

代码如下(示例):

package com.siwuxie095.view;

import java.awt.EventQueue;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.SwingWorker;

import com.siwuxie095.main.MainWindow;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import uk.co.caprica.vlcj.binding.LibVlc;
import uk.co.caprica.vlcj.discovery.NativeDiscovery;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;

public class VideoPlayer {

	/**
	 * 
	 * VLC播放器系统库的路径:D:\VLC media player\VLC
	 * 
	 * 注意需要将路径中的反斜杠改为斜杠,或 使用双反斜杠(即通过转义符进行转义)
	 * 
	 * 系统库一般是在含有 libvlc.dll、libvlccore.dll 的路径
	 * 
	 */

	private static final String NATIVE_LIBRARY_SEARCH_PATH = "D:/VLC media player/VLC";
	// 将声明转移到类中,并设为 static
	static MainWindow frame;

	public static void main(String[] args) {
		// (1)法一:首先要找到本机库(VLC播放器的系统库),这是自动搜索本机库的位置
		boolean found = new NativeDiscovery().discover();
		System.out.println(found);
		System.out.println(LibVlc.INSTANCE.libvlc_get_version());
		// 判断当前的系统是否是Windows
		// 还可以判断Mac和Linux,以传入不同的路径
		if (RuntimeUtil.isWindows()) {
			// (2)法二:手动设置本机库(VLC播放器的系统库)的路径
			NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), NATIVE_LIBRARY_SEARCH_PATH);
			System.out.println(LibVlc.INSTANCE.libvlc_get_version());
		}
		// 加载VLC播放器的系统库
		Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
		// 在主方法中创建窗体
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					frame = new MainWindow();
					frame.setVisible(true);
					// 字幕的编码
					String options = "--subsdec-encoding=GB18030";
					/**
					 * prepareMedia() 先准备而不是马上播放 可传入视频文件的路径(和播放参数,如:字幕编码) 这里使用双反斜杠(通过转义符进行转义)
					 * 关于播放参数,可以参考 VLC command-line
					 * 链接:https://wiki.videolan.org/VLC_command-line_help/ 进入后搜索 subsdec 设定字幕编码
					 * 还可以传入更多播放参数
					 */
					frame.getMediaPlayer().prepareMedia("C:\\Users\\siwux\\Desktop\\" + "testvideo\\test.mp4", options);
					frame.getMediaPlayer().toggleFullScreen();
					// 创建一个 SwingWorker 线程,用于实时调节进度
					// 注意:创建完毕,最后要 execute() 将它运行起来
					new SwingWorker<String, Integer>() {
						@Override
						protected String doInBackground() throws Exception {
							while (true) {
								// 视频总时长,以毫秒计
								long total = frame.getMediaPlayer().getLength();
								// 当前所看时长,以毫秒计
								long curr = frame.getMediaPlayer().getTime();
								// 百分比,并强转为 float
								float percent = (float) curr / total;
								// 因为进度条不是按百分比进行计算,而是 0-100 的数值范围
								// 所以要乘 100,并强转为 int,publish() 到 process()
								// (进度条范围可设置,如果改为 0-120,就要乘 120)
								publish((int) (percent * 100));
								// 每隔 0.1 秒(100毫秒)更新一次进度条,如果不加则刷新过快
								Thread.sleep(100);
							}
						}

						protected void process(java.util.List<Integer> chunks) {
							// 创建int型变量 value 接收 chunks 中的值
							for (int value : chunks) {
								frame.getProgressBar().setValue(value);
							}
						};
					}.execute();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	// 播放
	public static void play() {

		frame.getMediaPlayer().play();

	}

	// 暂停
	public static void pause() {
		frame.getMediaPlayer().pause();
	}

	// 停止
	public static void stop() {
		frame.getMediaPlayer().stop();
	}

	public static void jumpTo(float to) {
		// 为跳转设定时间:百分比乘以视频时间的总长
		frame.getMediaPlayer().setTime((long) (to * frame.getMediaPlayer().getLength()));

	}

	public static void openVideo() {
		// 创建文件选择器:JFileChooser
		JFileChooser chooser = new JFileChooser();
		// 将父级窗体设置成 null
		int v = chooser.showOpenDialog(null);
		if (v == JFileChooser.APPROVE_OPTION) {
			File file = chooser.getSelectedFile();
			// 获取到文件的绝对路径,开始播放
			frame.getMediaPlayer().playMedia(file.getAbsolutePath());
		}
	}

	public static void openSubtitle() {
		JFileChooser chooser = new JFileChooser();
		int v = chooser.showOpenDialog(null);
		if (v == JFileChooser.APPROVE_OPTION) {
			File file = chooser.getSelectedFile();
			// 设定字幕,直接传入 file 对象
			frame.getMediaPlayer().setSubTitleFile(file);
		}
	}

	public static void exit() {
		// 在退出之前,先释放播放器的资源
		frame.getMediaPlayer().release();
		System.exit(0);
	}

	public static void setVol(int vol) {
		// 设定音量
		frame.getMediaPlayer().setVolume(vol);
	}
}

1.2.2、MainWindow.java:

代码如下(示例):

package com.siwuxie095.main;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper;

import com.siwuxie095.view.VideoPlayer;

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

@SuppressWarnings("serial")
public class MainWindow extends JFrame {

	private JPanel contentPane;
	// 创建播放器的界面需要使用 EmbeddedMediaPlayerComponent
	EmbeddedMediaPlayerComponent playerComponent;
	private JPanel bottomPane;
	private JButton btnPlay;
	private JButton btnPause;
	private JButton btnStop;
	private JPanel controlPane;
	private JProgressBar progress;
	private JMenuBar menuBar;
	private JMenu mnFile;
	private JMenuItem mntmOpenvideo;
	private JMenuItem mntmOpensubtitle;
	private JMenuItem mntmExit;
	private JSlider slider;

	/**
	 * 
	 * Create the frame.
	 * 
	 */

	public MainWindow() {

		try {
			// 设置是否显示右上角设置按钮;
			UIManager.put("RootPane.setupButtonVisible", false);
			// 让JToolBar的UI不使用渐变图片而使用传统的纯色来填充背景
			UIManager.put("ToolBar.isPaintPlainBackground", Boolean.TRUE);
			// 开启/关闭窗口在不活动时的半透明效果
			BeautyEyeLNFHelper.translucencyAtFrameInactive = true;
			// 加载beautyeye的javaSwing风格,强立体半透明边框;
			BeautyEyeLNFHelper.frameBorderStyle = BeautyEyeLNFHelper.FrameBorderStyle.translucencyAppleLike;
			// 设置主题为BeautyEye
			org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper.launchBeautyEyeLNF();
		} catch (Exception e) {
			e.printStackTrace();
		}

		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		mnFile = new JMenu("File");
		menuBar.add(mnFile);
		mntmOpenvideo = new JMenuItem("OpenVideo");
		mntmOpenvideo.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				VideoPlayer.openVideo();
			}
		});

		mnFile.add(mntmOpenvideo);
		mntmOpensubtitle = new JMenuItem("OpenSubtitle");
		mntmOpensubtitle.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				VideoPlayer.openSubtitle();
			}
		});

		mnFile.add(mntmOpensubtitle);
		mntmExit = new JMenuItem("Exit");
		mntmExit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				VideoPlayer.exit();
			}
		});
		mnFile.add(mntmExit);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		JPanel videoPane = new JPanel();
		contentPane.add(videoPane, BorderLayout.CENTER);
		videoPane.setLayout(new BorderLayout(0, 0));
		// 在 videoPane 创建之后实例化 playerComponent
		playerComponent = new EmbeddedMediaPlayerComponent();
		// 将 playerComponent 添加到 videoPane 中,并指定布局
		videoPane.add(playerComponent, BorderLayout.CENTER);
		bottomPane = new JPanel();
		videoPane.add(bottomPane, BorderLayout.SOUTH);
		bottomPane.setLayout(new BorderLayout(0, 0));
		controlPane = new JPanel();
		bottomPane.add(controlPane);
		btnStop = new JButton("Stop");
		controlPane.add(btnStop);
		btnStop.setFocusable(false);
		btnPlay = new JButton("Play");
		controlPane.add(btnPlay);
		btnPlay.setFocusable(false);
		btnPause = new JButton("Pause");
		controlPane.add(btnPause);
		btnPause.setFocusable(false);
		slider = new JSlider();
		slider.setFocusable(false);
		// 关于默认音量的设定要在 stateChanged 事件之前
		// 如果要设定最大音量和最小音量也是如此
		slider.setValue(20);
		// 为音量调节 slider 添加 stateChanged 事件
		slider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				VideoPlayer.setVol(slider.getValue());
			}
		});

		controlPane.add(slider);
		progress = new JProgressBar();
		progress.setFocusable(false);
		// 为进度条 progress 添加 mouseClicked 事件
		progress.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				// 获取鼠标点击在进度条上的位置
				int x = e.getX();
				// 计算点击位置占进度条总长的百分比
				float per = (float) x / progress.getWidth();
				VideoPlayer.jumpTo(per);
			}
		});

		// 让进度条 progress 显示数字百分比
		progress.setStringPainted(true);
		bottomPane.add(progress, BorderLayout.NORTH);
		// 为 Stop 按钮添加 mouseClicked 事件
		btnStop.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				VideoPlayer.stop();
			}
		});

		// 为 Play 按钮添加 mouseClicked 事件

		btnPlay.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				VideoPlayer.play();
			}
		});

		// 为 Pause 按钮添加 mouseClicked 事件
		btnPause.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {

				VideoPlayer.pause();
			}
		});

	}

	// 返回媒体播放器的实例
	public EmbeddedMediaPlayer getMediaPlayer() {
		return playerComponent.getMediaPlayer();
	}

	// 返回JProgressBar的实例
	public JProgressBar getProgressBar() {
		return progress;
	}
}

四、运行效果图

运行效果图

项目链接

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值