001package com.github.sarxos.webcam.ds.vlcj; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.concurrent.atomic.AtomicBoolean; 006 007import uk.co.caprica.vlcj.binding.LibVlc; 008import uk.co.caprica.vlcj.medialist.MediaList; 009import uk.co.caprica.vlcj.medialist.MediaListItem; 010import uk.co.caprica.vlcj.player.MediaPlayerFactory; 011import uk.co.caprica.vlcj.player.discoverer.MediaDiscoverer; 012import uk.co.caprica.vlcj.runtime.RuntimeUtil; 013 014import com.github.sarxos.webcam.WebcamDevice; 015import com.github.sarxos.webcam.WebcamDiscoverySupport; 016import com.github.sarxos.webcam.WebcamDriver; 017import com.github.sarxos.webcam.util.OsUtils; 018import com.sun.jna.Native; 019 020 021/** 022 * This is capture driver which uses <code>vlcj</code> library to gain access to 023 * the camera device. 024 * 025 * @author Bartosz Firyn (SarXos) 026 * @see http://www.capricasoftware.co.uk/projects/vlcj/index.html 027 */ 028public class VlcjDriver implements WebcamDriver, WebcamDiscoverySupport { 029 030 /** 031 * Default webcam discovery scan interval in milliseconds. 032 */ 033 public static final long DEFAULT_SCAN_INTERVAL = 3000; 034 035 /** 036 * Are natives initialized. 037 */ 038 private static final AtomicBoolean initialized = new AtomicBoolean(); 039 040 /** 041 * The scan interval. 042 */ 043 private long scanInterval = -1; 044 045 public VlcjDriver() { 046 if (OsUtils.getOS() == OsUtils.WIN) { 047 System.err.println(String.format("WARNING: %s does not support Windows platform", getClass().getSimpleName())); 048 } 049 initialize(); 050 } 051 052 /** 053 * Initialize natives. 054 */ 055 protected static void initialize() { 056 initialize(true); 057 } 058 059 /** 060 * Initialize natives. If argument is true the natives are being loaded. In 061 * case of false this method do nothing. It's used mostly in unit tests. 062 * 063 * @param load the control to decide whether to load natives or ignore them 064 */ 065 protected static void initialize(boolean load) { 066 if (load && initialized.compareAndSet(false, true)) { 067 Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class); 068 } 069 } 070 071 @Override 072 public final List<WebcamDevice> getDevices() { 073 074 MediaPlayerFactory mediaPlayerFactory = createMediaPlayerFactory(); 075 MediaDiscoverer videoMediaDiscoverer = mediaPlayerFactory.newVideoMediaDiscoverer(); 076 MediaList videoDeviceList = videoMediaDiscoverer.getMediaList(); 077 078 List<WebcamDevice> devices = new ArrayList<WebcamDevice>(); 079 List<MediaListItem> videoDevices = videoDeviceList.items(); 080 081 for (MediaListItem item : videoDevices) { 082 devices.add(mediaListItemToDevice(item)); 083 } 084 085 videoDeviceList.release(); 086 videoMediaDiscoverer.release(); 087 mediaPlayerFactory.release(); 088 089 return devices; 090 } 091 092 /** 093 * Converts media list itemn into webcam device. 094 * 095 * @param item the item to be converted to webcam device instance 096 * @return Webcam device created from media list item 097 */ 098 protected WebcamDevice mediaListItemToDevice(MediaListItem item) { 099 return new VlcjDevice(item); 100 } 101 102 /** 103 * Creates media player factory. 104 * 105 * @return New media player factory 106 */ 107 protected MediaPlayerFactory createMediaPlayerFactory() { 108 return new MediaPlayerFactory(); 109 } 110 111 @Override 112 public boolean isThreadSafe() { 113 return false; 114 } 115 116 @Override 117 public String toString() { 118 return getClass().getSimpleName(); 119 } 120 121 @Override 122 public long getScanInterval() { 123 if (scanInterval <= 0) { 124 return DEFAULT_SCAN_INTERVAL; 125 } 126 return scanInterval; 127 } 128 129 /** 130 * Set new scan interval. Value must be positive number. If negative or zero 131 * is used, then the corresponding getter will return default scan interval 132 * value. 133 * 134 * @param scanInterval the new scan interval in milliseconds 135 * @see VlcjDriver#DEFAULT_SCAN_INTERVAL 136 */ 137 public void setScanInterval(long scanInterval) { 138 this.scanInterval = scanInterval; 139 } 140 141 @Override 142 public boolean isScanPossible() { 143 return true; 144 } 145}