Controlling VLC from Java

by 12/05/2013 05:26:00 PM 5 comments
I'm the author of a project for managing video annotations. The bulk of our videos are stored on video tapes. However, we are slooooowly moving over to video file storage. Our annotation system, which is written in Java, does work with video files, but via the very, very antiquated and deprecated QuickTime for Java libraries. I'm currently exploring alternatives to beef up video files support. Current candidates include JavaFX, AVFoundation (via JNI) and VLC (via its rc interface). Each of these options has strengths and weaknesses.

VLC Strengths

  • Works on the platforms I care about (Mac OS X, Linux, and Windows)
  • Has a very capable remote interface that can be accessed via TCP. Seems pretty straightforward to implement
  • Supports a wide variety of codecs and media containers
  • Supports frame capture (snapshots) from videos

VLC Weaknesses

  • Not Java, so there will be some configuration and install hassles for users
  • Java will need to launch it via Runtime.getRuntime().exec("..."); and manage the external process.
  • The command for launching VLC is different for different operating systems
  • Near as I can tell, it doesn't support timecode tracks. This will be a problem for my organization.
  • Lousy time resolution when indexing media remotely; it only indexes to the nearest second.

Example code

This is just a quick example. I'm working on a Mac so for simplicity I launched VLC from a terminal window using:

/Applications/VLC.app/Contents/MacOS/VLC --extraintf rc --rc-host=localhost:8080

The above command launches the default user interface (called macosx on Macs) as well as the rc network interface. In the future, I'll expect to use that command to launch VLC directly from Java.


Here's a bit of Java code for interacting with VLC:


import java.net.InetAddress;
import java.net.Socket;
import java.io.*;

// VLC RC Command references/examples
//   - https://github.com/mguinada/vlc-client/blob/master/lib/vlc-client/client/media_controls.rb
//   - http://getluky.net/2006/04/19/vlcs-awesome-rc-interface/
class VLCTest {
  
  private static BufferedReader in;
  private static OutputStream out;
  
  public static void main(String[] args) throws Exception {
    InetAddress localhost = InetAddress.getByName("localhost");
    Socket socket = new Socket(localhost, 8080);
    out = socket.getOutputStream();
    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    // Just read responses from VLC in a seperate thread.
    Thread readerThread = new Thread(new Runnable() {
      public void run() {
        boolean ok = true;
       while(ok) {
         try {
           System.out.println(in.readLine());           
         }
         catch (Exception e) {
           System.out.println("Whoops: " + e.getMessage());
           ok = false;
         }
       } 
      }
    });
    readerThread.setDaemon(true);
    readerThread.start();
    out.write("clear\n".getBytes());

    // !!!! CHANGE THIS LINE TO POINT AT A FILE YOU WANT TO PLAY !!!!
    out.write("add /Users/brian/Desktop/brittlestars.mov\n".getBytes());

    out.write("stop\n".getBytes());
    out.write("info\n".getBytes());
    out.write("get_length\n".getBytes());
    out.write("get_time\n".getBytes());
    out.write("get_title\n".getBytes());
    Thread.sleep(200);
    out.write("is_playing\n".getBytes());
    out.write("play\n".getBytes());
    Thread.sleep(200);
    out.write("is_playing\n".getBytes());
    Thread.sleep(2000);
    out.write("get_time\n".getBytes());
    Thread.sleep(200);
    out.write("get_time\n".getBytes());
    Thread.sleep(200);
    out.write("pause\n".getBytes());
    out.close();
    in.close();
    socket.close();
    System.exit(0);
  }

}



Full List of RC Command

On a Mac, to see the full list of commands available for the rc interface you can do the following:

Start a local rc session in a terminal:
/Applications/VLC.app/Contents/MacOS/VLC --intf rc

Then at the terminal prompt enter longhelp. As of today, the output from this command was:
+----[ CLI commands ]
| add XYZ  . . . . . . . . . . . . . . . . . . . . add XYZ to playlist
| enqueue XYZ  . . . . . . . . . . . . . . . . . queue XYZ to playlist
| playlist . . . . . . . . . . . . .  show items currently in playlist
| search [string]  . .  search for items in playlist (or reset search)
| delete [X] . . . . . . . . . . . . . . . . delete item X in playlist
| move [X][Y]  . . . . . . . . . . . . move item X in playlist after Y
| sort key . . . . . . . . . . . . . . . . . . . . . sort the playlist
| sd [sd]  . . . . . . . . . . . . . show services discovery or toggle
| play . . . . . . . . . . . . . . . . . . . . . . . . . . play stream
| stop . . . . . . . . . . . . . . . . . . . . . . . . . . stop stream
| next . . . . . . . . . . . . . . . . . . . . . .  next playlist item
| prev . . . . . . . . . . . . . . . . . . . .  previous playlist item
| goto, gotoitem . . . . . . . . . . . . . . . . .  goto item at index
| repeat [on|off]  . . . . . . . . . . . . . .  toggle playlist repeat
| loop [on|off]  . . . . . . . . . . . . . . . .  toggle playlist loop
| random [on|off]  . . . . . . . . . . . . . .  toggle playlist random
| clear  . . . . . . . . . . . . . . . . . . . . .  clear the playlist
| status . . . . . . . . . . . . . . . . . . . current playlist status
| title [X]  . . . . . . . . . . . . . . set/get title in current item
| title_n  . . . . . . . . . . . . . . . .  next title in current item
| title_p  . . . . . . . . . . . . . .  previous title in current item
| chapter [X]  . . . . . . . . . . . . set/get chapter in current item
| chapter_n  . . . . . . . . . . . . . .  next chapter in current item
| chapter_p  . . . . . . . . . . . .  previous chapter in current item
|
| seek X . . . . . . . . . . . seek in seconds, for instance `seek 12'
| pause  . . . . . . . . . . . . . . . . . . . . . . . .  toggle pause
| fastforward  . . . . . . . . . . . . . . . . . . set to maximum rate
| rewind . . . . . . . . . . . . . . . . . . . . . set to minimum rate
| faster . . . . . . . . . . . . . . . . . .  faster playing of stream
| slower . . . . . . . . . . . . . . . . . .  slower playing of stream
| normal . . . . . . . . . . . . . . . . . .  normal playing of stream
| rate [playback rate] . . . . . . . . . .  set playback rate to value
| frame  . . . . . . . . . . . . . . . . . . . . . play frame by frame
| fullscreen, f, F [on|off]  . . . . . . . . . . . . toggle fullscreen
| info . . . . . . . . . . . . .  information about the current stream
| stats  . . . . . . . . . . . . . . . .  show statistical information
| get_time . . . . . . . . .  seconds elapsed since stream's beginning
| is_playing . . . . . . . . . . . .  1 if a stream plays, 0 otherwise
| get_title  . . . . . . . . . . . . . the title of the current stream
| get_length . . . . . . . . . . . .  the length of the current stream
|
| volume [X] . . . . . . . . . . . . . . . . . .  set/get audio volume
| volup [X]  . . . . . . . . . . . . . . .  raise audio volume X steps
| voldown [X]  . . . . . . . . . . . . . .  lower audio volume X steps
| achan [X]  . . . . . . . . . . . .  set/get stereo audio output mode
| atrack [X] . . . . . . . . . . . . . . . . . . . set/get audio track
| vtrack [X] . . . . . . . . . . . . . . . . . . . set/get video track
| vratio [X] . . . . . . . . . . . . . . .  set/get video aspect ratio
| vcrop, crop [X]  . . . . . . . . . . . . . . . .  set/get video crop
| vzoom, zoom [X]  . . . . . . . . . . . . . . . .  set/get video zoom
| vdeinterlace [X] . . . . . . . . . . . . . set/get video deinterlace
| vdeinterlace_mode [X]  . . . . . . .  set/get video deinterlace mode
| snapshot . . . . . . . . . . . . . . . . . . . . take video snapshot
| strack [X] . . . . . . . . . . . . . . . . .  set/get subtitle track
| hotkey, key [hotkey name]  . . . . . . . . . . simulate hotkey press
|
| vlm  . . . . . . . . . . . . . . . . . . . . . . . . .  load the VLM
| set [var [value]]  . . . . . . . . . . . . . . . . . set/get env var
| save_env . . . . . . . . . . . .  save env vars (for future clients)
| alias [cmd]  . . . . . . . . . . . . . . . . set/get command aliases
| description  . . . . . . . . . . . . . . . . .  describe this module
| license  . . . . . . . . . . . . . . . . print VLC's license message
| help, ? [pattern]  . . . . . . . . . . . . . . . . .  a help message
| longhelp [pattern] . . . . . . . . . . . . . . a longer help message
| lock . . . . . . . . . . . . . . . . . . . .  lock the telnet prompt
| logout . . . . . . . . . . . . . .  exit (if in a socket connection)
| quit . . . . . . . .  quit VLC (or logout if in a socket connection)
| shutdown . . . . . . . . . . . . . . . . . . . . . . .  shutdown VLC
+----[ end of help ]

Brian Schlining

Developer

Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.

5 comments:

ZeroLinux said...

Hello,

Which is the version of the VLC that show that longhelp?. The version that im running does not support some options like "delete" and "move" in playlist section :/

Brian Schlining said...

I was running VCL 2.1.1

Shahid Satti said...

Hi Brian,

Thanks for the nice insight into controlling vlc from java. I have a question.

Instead of initiating vlc with the command "vlc --extraintf rc --rc-host=localhost:8080", I start it with "vlc -I rc -f --no-video-deco --no-embedded-video --hotkeys-mousewheel-mode=2 --no-mouse-events --mouse-hide-timeout=10". Now if I run your java program, vlc seems to ignore the attributes mentioned in the command line, the video plays but the attributes mentioned in the command line dont take effect. However, manually playing the video file will playout with all the attributes I give in the vlc initiation command line. My question is, is there a way to keep the attributes when initiating vlc in the rc mode? Waiting reply. Thanks again for the insight.

REgards

Shahid

Brian Schlining said...

Sorry Shahid, I don't know the answer to your question. You should try the VLC mailing list. Good Luck. Brian.

raghwendra singh said...

This program refuses the connection what i do