@Override public void run() { Logger.debug("run()"); try { hHook = USER32_INSTANCE.SetWindowsHookEx( WinUser.WH_MOUSE_LL, WindowsMouseHook.this, Kernel32.INSTANCE.GetModuleHandle(null), 0); MSG msg = new MSG(); while ((USER32_INSTANCE.GetMessage(msg, null, 0, 0)) != 0) { // This code is never reached USER32_INSTANCE.TranslateMessage(msg); USER32_INSTANCE.DispatchMessage(msg); if (getHook() == null) { break; } } } catch (Exception e) { Logger.error("Mouse hook failure", e); } Logger.debug("mouse hook runnable exits"); }
/** * Get the VLC installation directory. * * <p>If vlc is installed correctly, this should not be needed. * * @return fully-qualified directory name, or <code>null</code> if the value could not be obtained */ public static String getVlcInstallDir() { Logger.debug("getVlcInstallDir()"); try { return Advapi32Util.registryGetStringValue( WinReg.HKEY_LOCAL_MACHINE, VLC_REGISTRY_KEY, VLC_INSTALL_DIR_KEY); } catch (Exception e) { Logger.warn("Failed to get VLC installation directory from the registry", e); return null; } }
public synchronized void release() { Logger.debug("release()"); HHOOK hook = getHook(); if (hook != null) { USER32_INSTANCE.UnhookWindowsHookEx(hHook); hook = null; // TODO ordinarily I'd interrupt the thread to force it to exit if it's // blocked, but in this case a fatal VM failure would occur // hookThread.interrupt(); } Logger.debug("released"); }
/** * Create a new mouse hook. * * @param relativeTo component to report mouse coordinates relative to */ public WindowsMouseHook(Component relativeTo) { Logger.debug("WindowsMouseHook(relativeTo={})", relativeTo); if (!Platform.isWindows()) { throw new IllegalStateException("Windows only"); } this.relativeTo = relativeTo; }
/** * Fire a mouse event to the registered listeners. * * @param eventType * @param button * @param lParam */ private void fireMouseEvent(int eventType, int button, MSLLHOOKSTRUCT lParam) { Logger.trace("fireMouseEvent(eventType={},button={},lParam={})", eventType, button, lParam); MouseListener[] listeners = listenerList.getListeners(MouseListener.class); if (listeners.length > 0) { MouseEvent evt = createMouseEvent(eventType, button, lParam); for (int i = listeners.length - 1; i >= 0; i--) { switch (eventType) { case MouseEvent.MOUSE_PRESSED: listeners[i].mousePressed(evt); break; case MouseEvent.MOUSE_RELEASED: listeners[i].mouseReleased(evt); break; case MouseEvent.MOUSE_ENTERED: listeners[i].mouseEntered(evt); break; case MouseEvent.MOUSE_EXITED: listeners[i].mouseExited(evt); break; } } } }
public static void main(final String[] args) throws Exception { LibVlc libVlc = LibVlcFactory.factory().create(); Logger.info(" version: {}", libVlc.libvlc_get_version()); Logger.info(" compiler: {}", libVlc.libvlc_get_compiler()); Logger.info("changeset: {}", libVlc.libvlc_get_changeset()); setLookAndFeel(); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { new TestPlayer(args); } }); }
/** Start the hook. */ public void start() { Logger.debug("start()"); if (hookThread != null) { throw new IllegalStateException("Mouse hook already installed"); } hookThread = new MouseHookThread(); hookThread.start(); }
/** @param enable */ @SuppressWarnings("unused") private void enableMousePointer(boolean enable) { Logger.debug("enableMousePointer(enable={})", enable); if (enable) { videoSurface.setCursor(null); } else { Image blankImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); videoSurface.setCursor( Toolkit.getDefaultToolkit().createCustomCursor(blankImage, new Point(0, 0), "")); } }
/** * Fire a mouse wheel event to the registered listeners. * * @param eventType * @param button * @param lParam */ private void fireMouseWheelEvent(int eventType, MSLLHOOKSTRUCT lParam) { Logger.trace("fireMouseWheelEvent(eventType={},lParam={})", eventType, lParam); MouseWheelListener[] listeners = listenerList.getListeners(MouseWheelListener.class); if (listeners.length > 0) { MouseWheelEvent evt = createMouseWheelEvent(eventType, lParam); for (int i = listeners.length - 1; i >= 0; i--) { switch (eventType) { case MouseEvent.MOUSE_WHEEL: listeners[i].mouseWheelMoved(evt); break; } } } }
@Override public void playing(MediaPlayer mediaPlayer) { Logger.debug("playing(mediaPlayer={})", mediaPlayer); MediaDetails mediaDetails = mediaPlayer.getMediaDetails(); Logger.info("mediaDetails={}", mediaDetails); }
/** @param listener */ public void removeMouseWheelListener(MouseWheelListener listener) { Logger.debug("removeMouseWheelListener(listener={})", listener); listenerList.remove(MouseWheelListener.class, listener); }
/** @param listener */ public void addMouseWheelListener(MouseWheelListener listener) { Logger.debug("addMouseWheelListener(listener={})", listener); listenerList.add(MouseWheelListener.class, listener); }
@Override public void stopped(MediaPlayer mediaPlayer) { Logger.debug("stopped(mediaPlayer={})", mediaPlayer); }
@Override public void videoOutput(MediaPlayer mediaPlayer, int newCount) { Logger.debug("videoOutput(mediaPlayer={},newCount={})", mediaPlayer, newCount); if (newCount == 0) { return; } MediaDetails mediaDetails = mediaPlayer.getMediaDetails(); Logger.info("mediaDetails={}", mediaDetails); MediaMeta mediaMeta = mediaPlayer.getMediaMeta(); Logger.info("mediaMeta={}", mediaMeta); final Dimension dimension = mediaPlayer.getVideoDimension(); Logger.debug("dimension={}", dimension); if (dimension != null) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { videoSurface.setSize(dimension); mainFrame.pack(); } }); } // You can set a logo like this if you like... File logoFile = new File("./etc/vlcj-logo.png"); if (logoFile.exists()) { mediaPlayer.setLogoFile(logoFile.getAbsolutePath()); mediaPlayer.setLogoOpacity(0.5f); mediaPlayer.setLogoLocation(10, 10); mediaPlayer.enableLogo(true); } // Demo the marquee mediaPlayer.setMarqueeText("vlcj java bindings for vlc"); mediaPlayer.setMarqueeSize(40); mediaPlayer.setMarqueeOpacity(95); mediaPlayer.setMarqueeColour(Color.white); mediaPlayer.setMarqueeTimeout(5000); mediaPlayer.setMarqueeLocation(50, 120); mediaPlayer.enableMarquee(true); // Not quite sure how crop geometry is supposed to work... // // Assertions in libvlc code: // // top + height must be less than visible height // left + width must be less than visible width // // With DVD source material: // // Reported size is 1024x576 - this is what libvlc reports when you call // get video size // // mpeg size is 720x576 - this is what is reported in the native log // // The crop geometry relates to the mpeg size, not the size reported // through the API // // For 720x576, attempting to set geometry to anything bigger than // 719x575 results in the assertion failures above (seems like it should // allow 720x576) to me // mediaPlayer.setCropGeometry("4:3"); }
@Override public void mediaDurationChanged(MediaPlayer mediaPlayer, long newDuration) { Logger.debug("mediaDurationChanged(mediaPlayer={},newDuration={})", mediaPlayer, newDuration); }
@Override public void finished(MediaPlayer mediaPlayer) { Logger.debug("finished(mediaPlayer={})", mediaPlayer); }
@Override public void mouseWheelMoved(MouseWheelEvent e) { Logger.debug("mouseWheelMoved(e={})", e); }
@Override public void mediaChanged(MediaPlayer mediaPlayer, libvlc_media_t media, String mrl) { Logger.debug("mediaChanged(mediaPlayer={},media={},mrl={})", mediaPlayer, media, mrl); }
@Override public void error(MediaPlayer mediaPlayer) { Logger.debug("error(mediaPlayer={})", mediaPlayer); }
@Override public void mediaMetaChanged(MediaPlayer mediaPlayer, int metaType) { Logger.debug("mediaMetaChanged(mediaPlayer={},metaType={})", mediaPlayer, metaType); }
@Override public void mediaStateChanged(MediaPlayer mediaPlayer, int newState) { Logger.debug("mediaStateChanged(mediaPlayer={},newState={})", mediaPlayer, newState); }
@Override public void mediaFreed(MediaPlayer mediaPlayer) { Logger.debug("mediaFreed(mediaPlayer={})", mediaPlayer); }
@Override public void mediaParsedChanged(MediaPlayer mediaPlayer, int newStatus) { Logger.debug("mediaParsedChanged(mediaPlayer={},newStatus={})", mediaPlayer, newStatus); }
@Override public void paused(MediaPlayer mediaPlayer) { Logger.debug("paused(mediaPlayer={})", mediaPlayer); }
@Override public LRESULT callback(int nCode, WPARAM wParam, MSLLHOOKSTRUCT lParam) { Logger.trace("callback(nCode={},wParam={},lParam={})", nCode, wParam, lParam); if (nCode >= 0) { Window window = SwingUtilities.getWindowAncestor(relativeTo); Logger.trace("window={}", window); // Is the window active... if (window != null && window.isActive()) { Logger.trace("window is active"); // Is the component showing... // TODO is this still needed or is isActive good enough? if (relativeTo.isShowing() && relativeTo.isValid()) { Logger.trace("window is visible"); // Did the event occur inside the component bounds... int absX = lParam.pt.x; int absY = lParam.pt.y; // FIXME there is a race here where relativeTo may no longer be visible, should // I lock the component tree - is that OK from non-EDT? Point componentPoint = relativeTo.getLocationOnScreen(); int relX = componentPoint.x; int relY = componentPoint.y; int relW = relX + relativeTo.getWidth(); int relH = relY + relativeTo.getHeight(); if (absX >= relX && absY >= relY && absX < relW && absY < relH) { Logger.trace("event inside component bounds"); if (!this.mouseEntered) { this.mouseEntered = true; fireMouseEvent(MouseEvent.MOUSE_ENTERED, MouseEvent.NOBUTTON, lParam); } // The event did occur inside the component bounds, so translate it... switch (wParam.intValue()) { case WM_MOUSEMOVE: fireMouseMotionEvent(MouseEvent.MOUSE_MOVED, MouseEvent.NOBUTTON, lParam); break; case WM_LBUTTONDOWN: fireMouseEvent(MouseEvent.MOUSE_PRESSED, MouseEvent.BUTTON1, lParam); break; case WM_LBUTTONUP: fireMouseEvent(MouseEvent.MOUSE_RELEASED, MouseEvent.BUTTON1, lParam); break; case WM_RBUTTONDOWN: fireMouseEvent(MouseEvent.MOUSE_PRESSED, MouseEvent.BUTTON2, lParam); break; case WM_RBUTTONUP: fireMouseEvent(MouseEvent.MOUSE_RELEASED, MouseEvent.BUTTON2, lParam); break; case WM_MBUTTONDOWN: fireMouseEvent(MouseEvent.MOUSE_PRESSED, MouseEvent.BUTTON3, lParam); break; case WM_MBUTTONUP: fireMouseEvent(MouseEvent.MOUSE_RELEASED, MouseEvent.BUTTON3, lParam); break; case WM_MOUSEWHEEL: fireMouseWheelEvent(MouseEvent.MOUSE_WHEEL, lParam); break; default: break; } } else { Logger.trace("event outside component bounds"); if (this.mouseEntered) { this.mouseEntered = false; fireMouseEvent(MouseEvent.MOUSE_EXITED, MouseEvent.NOBUTTON, lParam); } } } } } return USER32_INSTANCE.CallNextHookEx(hHook, nCode, wParam, lParam.getPointer()); }
@Override public void mouseExited(MouseEvent e) { Logger.debug("mouseExited(e={})", e); }
@Override public void keyTyped(KeyEvent e) { Logger.debug("keyTyped(e={})", e); }
@Override public void mediaSubItemAdded(MediaPlayer mediaPlayer, libvlc_media_t subItem) { Logger.debug("mediaSubItemAdded(mediaPlayer={},subItem={})", mediaPlayer, subItem); }
@Override public void mouseMoved(MouseEvent e) { Logger.trace("mouseMoved(e={})", e); }
public TestPlayer(String[] args) { if (RuntimeUtil.isWindows()) { // If running on Windows and you want the mouse/keyboard event hack... videoSurface = new WindowsCanvas(); } else { videoSurface = new Canvas(); } Logger.debug("videoSurface={}", videoSurface); videoSurface.setBackground(Color.black); videoSurface.setSize(800, 600); // Only for initial layout // Since we're mixing lightweight Swing components and heavyweight AWT // components this is probably a good idea JPopupMenu.setDefaultLightWeightPopupEnabled(false); TestPlayerMouseListener mouseListener = new TestPlayerMouseListener(); videoSurface.addMouseListener(mouseListener); videoSurface.addMouseMotionListener(mouseListener); videoSurface.addMouseWheelListener(mouseListener); videoSurface.addKeyListener(new TestPlayerKeyListener()); List<String> vlcArgs = new ArrayList<String>(); vlcArgs.add("--no-plugins-cache"); vlcArgs.add("--no-video-title-show"); vlcArgs.add("--no-snapshot-preview"); vlcArgs.add("--quiet"); vlcArgs.add("--quiet-synchro"); vlcArgs.add("--intf"); vlcArgs.add("dummy"); // Special case to help out users on Windows (supposedly this is not actually needed)... // if(RuntimeUtil.isWindows()) { // vlcArgs.add("--plugin-path=" + WindowsRuntimeUtil.getVlcInstallDir() + "\\plugins"); // } // else { // vlcArgs.add("--plugin-path=/home/linux/vlc/lib"); // } // vlcArgs.add("--plugin-path=" + System.getProperty("user.home") + "/.vlcj"); Logger.debug("vlcArgs={}", vlcArgs); mainFrame = new JFrame("VLCJ Test Player"); mainFrame.setIconImage( new ImageIcon(getClass().getResource("/icons/vlcj-logo.png")).getImage()); FullScreenStrategy fullScreenStrategy = new DefaultFullScreenStrategy(mainFrame); mediaPlayerFactory = new MediaPlayerFactory(vlcArgs.toArray(new String[vlcArgs.size()])); mediaPlayerFactory.setUserAgent("vlcj test player"); List<AudioOutput> audioOutputs = mediaPlayerFactory.getAudioOutputs(); Logger.debug("audioOutputs={}", audioOutputs); mediaPlayer = mediaPlayerFactory.newEmbeddedMediaPlayer(fullScreenStrategy); mediaPlayer.setVideoSurface(mediaPlayerFactory.newVideoSurface(videoSurface)); mediaPlayer.setPlaySubItems(true); mediaPlayer.setEnableKeyInputHandling(false); mediaPlayer.setEnableMouseInputHandling(false); controlsPanel = new PlayerControlsPanel(mediaPlayer); videoAdjustPanel = new PlayerVideoAdjustPanel(mediaPlayer); mainFrame.setLayout(new BorderLayout()); mainFrame.setBackground(Color.black); mainFrame.add(videoSurface, BorderLayout.CENTER); mainFrame.add(controlsPanel, BorderLayout.SOUTH); mainFrame.add(videoAdjustPanel, BorderLayout.EAST); mainFrame.setJMenuBar(buildMenuBar()); mainFrame.pack(); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainFrame.addWindowListener( new WindowAdapter() { @Override public void windowClosing(WindowEvent evt) { Logger.debug("windowClosing(evt={})", evt); if (videoSurface instanceof WindowsCanvas) { ((WindowsCanvas) videoSurface).release(); } if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } if (mediaPlayerFactory != null) { mediaPlayerFactory.release(); mediaPlayerFactory = null; } } }); // Global AWT key handler, you're better off using Swing's InputMap and // ActionMap with a JFrame - that would solve all sorts of focus issues too Toolkit.getDefaultToolkit() .addAWTEventListener( new AWTEventListener() { @Override public void eventDispatched(AWTEvent event) { if (event instanceof KeyEvent) { KeyEvent keyEvent = (KeyEvent) event; if (keyEvent.getID() == KeyEvent.KEY_PRESSED) { if (keyEvent.getKeyCode() == KeyEvent.VK_F12) { controlsPanel.setVisible(!controlsPanel.isVisible()); videoAdjustPanel.setVisible(!videoAdjustPanel.isVisible()); mainFrame.getJMenuBar().setVisible(!mainFrame.getJMenuBar().isVisible()); mainFrame.invalidate(); mainFrame.validate(); } else if (keyEvent.getKeyCode() == KeyEvent.VK_A) { mediaPlayer.setAudioDelay(mediaPlayer.getAudioDelay() - 50000); } else if (keyEvent.getKeyCode() == KeyEvent.VK_S) { mediaPlayer.setAudioDelay(mediaPlayer.getAudioDelay() + 50000); } // else if(keyEvent.getKeyCode() == KeyEvent.VK_N) { // mediaPlayer.nextFrame(); // } else if (keyEvent.getKeyCode() == KeyEvent.VK_1) { mediaPlayer.setTime(60000 * 1); } else if (keyEvent.getKeyCode() == KeyEvent.VK_2) { mediaPlayer.setTime(60000 * 2); } else if (keyEvent.getKeyCode() == KeyEvent.VK_3) { mediaPlayer.setTime(60000 * 3); } else if (keyEvent.getKeyCode() == KeyEvent.VK_4) { mediaPlayer.setTime(60000 * 4); } else if (keyEvent.getKeyCode() == KeyEvent.VK_5) { mediaPlayer.setTime(60000 * 5); } else if (keyEvent.getKeyCode() == KeyEvent.VK_6) { mediaPlayer.setTime(60000 * 6); } else if (keyEvent.getKeyCode() == KeyEvent.VK_7) { mediaPlayer.setTime(60000 * 7); } else if (keyEvent.getKeyCode() == KeyEvent.VK_8) { mediaPlayer.setTime(60000 * 8); } else if (keyEvent.getKeyCode() == KeyEvent.VK_9) { mediaPlayer.setTime(60000 * 9); } } } } }, AWTEvent.KEY_EVENT_MASK); mainFrame.setVisible(true); mediaPlayer.addMediaPlayerEventListener(new TestPlayerMediaPlayerEventListener()); // Won't work with OpenJDK or JDK1.7, requires a Sun/Oracle JVM (currently) boolean transparentWindowsSupport = true; try { Class.forName("com.sun.awt.AWTUtilities"); } catch (Exception e) { transparentWindowsSupport = false; } Logger.debug("transparentWindowsSupport={}", transparentWindowsSupport); if (transparentWindowsSupport) { final Window test = new Window(null, WindowUtils.getAlphaCompatibleGraphicsConfiguration()) { private static final long serialVersionUID = 1L; @Override public void paint(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); g.setColor(Color.white); g.fillRoundRect(100, 150, 100, 100, 32, 32); g.setFont(new Font("Sans", Font.BOLD, 32)); g.drawString("Heavyweight overlay test", 100, 300); } }; AWTUtilities.setWindowOpaque(test, false); // Doesn't work in full-screen exclusive // mode, you would have to use 'simulated' // full-screen - requires Sun/Oracle JDK test.setBackground(new Color(0, 0, 0, 0)); // This is what you do in JDK7 // mediaPlayer.setOverlay(test); // mediaPlayer.enableOverlay(true); } // This might be useful // enableMousePointer(false); }