vlc: VideoLAN VLC Media Player Control in Racket

1Introduction

This vlc package permit Racket programs to start and control a VideoLAN VLC media player, for playing video and audio.

VLC itself is a separate computer program, and must be installed
separately.

This package uses the VLC RC interface over TCP. The Racket host OS process’s address space is isolated
from potential memory-handling defects in the various native code libraries
involved in media playing.

For a simple example of using this package, imagine that you are
studying how to improve a corporate training video, and you have a theory that
the video would be more efficacious, were minimum-wage new hires not bored to
catatonia by the CEO’s rambling 10-minute introduction. Fortunately, you have
human subjects available, since the new hires all use a Racket-based training
system that can be modified quickly to add scientific experiments, showing the
CEO’s intro to some subjects but not to others. Unfortunately, you can’t just
edit the training video to make an alternate version without the CEO’s intro,
since the CEO is an aspiring Hollywood actor, who negotiated “points” on DVD
sales. Fortunately, you can use VLC and this Racket vlc package, to launch the pertinent DVD chapter and seek past the
initial 10 minutes of Valium:

(start-vlc"dvd:///dev/dvd#1:2")

(wait-for-vlc-active-playing)

(vlc-seek594)

In addition to highly contrived examples like that, this package is
being used as part of a Racket-based home theatre system being developed.

This package is currently developed using VLC 2.0.3, on Debian
GNU/Linux, and has been observed to also work on Mac OS X. MS Windows is not
currently supported (since, on MS Windows, VLC 2.0.3 does not support the RC
interface, and instead uses something called oldrc).

2Exceptions

In addition to exn:fail, this package raises a few package-specific exceptions:

Exception regarding receiving seemingly bad RC protocol from a
VLC process, but that is not necessarily an error message. For example, a
hypothetical VLC version might change the behavior of a particular command to
return a floating-point number when an integer is expected. When these
exceptions occur, it may be that the process and connection are still viable,
just that this particular command cannot be performed.

Exception regarding running a VLC process or communicating with
with a VLC process. These generally mean that further communication with the
process is futile.

3Processes & Connections

A connection to a VLC process is represented by the vlc object. This connection can be to a process that is started by
the start-vlc procedure, or an existing VLC process (possibly on a host
elsewhere on the network).

Parameter for the vlc to use as the default for most procedures in this package
when the optional #:vlc argument is not supplied to the procedure.

procedure

(connect-to-vlc

#:portport

[

#:hostnamehostname

#:connecting-timeoutconnecting-timeout

#:set-current-vlc?set-current-vlc?])

→

vlc?

port

:

(and/cexact-nonnegative-integer?

(integer-in165535))

hostname:string?="localhost"

connecting-timeout:(and/creal?(not/cnegative?))=5.0

set-current-vlc?:boolean?=#t

Connect to the RC interface on an existing process, at TCP hostname and port, and return a vlc object. If set-current-vlc? is true, which is the default, then the current-vlc parameter is also set.

connecting-timeout is a guideline of the maximum number of seconds total that
should be spend attempting to get a TCP connection to the VLC process and then
exchange certain initial protocol. It is not a hard limit, however. Note that
multiple attempts at the TCP connection may be tried within that limit, for
situations such as waiting for a VLC process to start up.

procedure

(start-vlc

[

#:portport

#:hostnamehostname

#:connecting-timeoutconnecting-timeout

#:loggerlogger

#:logger-levellogger-level

#:set-current-vlc?set-current-vlc?

#:commandcommand

extra-args...])

→

vlc?

port

:

(or/c#f

(and/cexact-nonnegative-integer?

(integer-in165535)))

=

#f

hostname:string?="localhost"

connecting-timeout

:

(or/c#f(and/creal?(not/cnegative?)))

=

60.0

logger:(or/c#flogger?)=(current-logger)

logger-level

:

(or/c'fatal'error'warning'info'debug)

=

'info

set-current-vlc?:boolean?=#t

command:(or/c#fpath-string?)=#f

extra-args:(listof(or/cstring?path?))='()

Start a VLC process on the same machine on which this Racket
program is running, with RC enabled, and connect to it. A vlc object is returned. If set-current-vlc? is true, which is the default, then the current-vlc parameter is also set.

command is a string or path object for the complete path to the VLC executable; or, if the default of #f, then this package attempts to find the VLC executable.

This package supplies some command-line arguments to VLC, to set
up the RC interface. Additional command-line arguments can be supplied as
strings and/or path objects to the extra-args argument of this procedure.

(start-vlc"--snapshot-path=/home/me/film-class/review-screenshots"

"dvd:///dev/dvd")

If logger is #f, then stdout and stderr output is consumed and ignored. Otherwise, such output is
redirected to the logger, with the log level specified by logger-level.

If port is #f, which is the default, then this package attempts to select a
TCP port in the ephemeral range for VLC to use for RC; otherwise, port is the port number to use.

hostname is the string hostname (or the IP address as a string) on which
VLC should listen on the TCP port for RC. By default, this is "localhost", which is what you normally want with start-vlc rather than connect-to-vlc. In the unlikely event that you wish for the RC port of this
VLC process to also be accessible from other hosts, you may supply the hostname
or IP address for a non-localhost interface.

connecting-timeout is as documented for connect-to-vlc.

The VLC process is started under the current custodian. If you are calling start-vlc from a short-lived thread with its own custodian that you
shutdown as the thread exits, such as for an HTTP request that triggers
starting of VLC, you might want to do something like:

(parameterize((current-custodian<long-lived-custodian>))

(start-vlc))

4URLs

URLs may be provided to VLC commands in any of a few different
formats. See documentation for vlc-url?.

procedure

(vlc-url?x)→boolean?

x:any/c

Predicate for whether or not x can (likely) be used as a URL argument to procedures like vlc-add and vlc-enqueue. Specifically, URLs can be represented as one of the following:

String starting with a URL scheme, such as "http://example.com/foo.mp4". Note that this string must contain a %-escaped URL, with no spaces or other problematic characters.

url object, such as is produced by (string->url"http://example.com/bar/foo.mp4").

String not starting with a URL scheme, such as "/home/billybob/tractors.mp4", which is a file path.

path object, such as is produced by (string->path"/home/scotty/sheep.wav").

Byte string of a complete URL in UTF-8 encoding, including %-escaping. This is passed verbatim in the RC protocol.

Note that URLs provided to commands are processed by the VLC
program, which might be on a different computer than the Racket program that is
sending commands. URLs that may be accessed from one computer can’t
necessarily be accessed by another.

procedure

(to-vlc-rc-url-bytesx)→bytes?

x:(or/cstring?path?url?bytes?)

Accepts a VLC URL as described in the documentation for vlc-url? and yields a byte string representation. Note that, if x is a byte string, then it is returned verbatim. This procedure
will not be called directly by most programs using this package.

5Commands

This section lists the various command procedures. Generally, each
procedure corresponds to a VLC RC command. For example, vlc-add corresponds to the RC add command. For the most part, these procedures are defined to “do
whatever the RC command does.” The RC command itself might not be
well-documented. So, for example, if, in the version of VLC being used, the add command results in the the specified URL both being prepended to
the playlist and being played, then that’s what the vlc-add command will do.

Note that some of these commands have asynchronous effects, due to
the design of VLC or of the VLC RC protocol. For example, the vlc-play procedure can return before VLC is actually playing the media.

5.1Playlist

procedure

(vlc-clear[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Clear all items from the playlist.

procedure

(vlc-addthing[#:vlcvlc])→void?

thing:vlc-url?

vlc:vlc?=(current-vlc)

Adds the URL thing to the playlist. This command seems to also cause VLC to start
playing the item.

procedure

(vlc-enqueuething[#:vlcvlc])→void?

thing:vlc-url?

vlc:vlc?=(current-vlc)

Enqueues the URL thing in the playlist.

procedure

(vlc-next[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Start playing the next item in the playlist.

procedure

(vlc-prev[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Start playing the previous item in the playlist.

5.2Repeat / Loop / Random

procedure

(vlc-repeaton?[#:vlcvlc])→void?

on?:boolean

vlc:vlc?=(current-vlc)

Set whether VLC should repeat playing the current stream continuously.

procedure

(vlc-loopon?[#:vlcvlc])→void?

on?:boolean

vlc:vlc?=(current-vlc)

Set whether VLC should repeat playing the playlist continuously.

procedure

(vlc-randomon?[#:vlcvlc])→void?

on?:boolean

vlc:vlc?=(current-vlc)

Set whether VLC should select streams from the playlist randomly,
rather than in order.

5.3Title and Chapter

procedure

(vlc-title-n[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Switch to the next title of the current stream.

procedure

(vlc-title-p[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Switch to the previous title of the current stream.

procedure

(vlc-chapter-n[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Switch to the next chapter of the current stream.

procedure

(vlc-chapter-p[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Switch to the previous chapter of the current stream.

5.4Play, Pause, and Stop

procedure

(vlc-play[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Play the next stream, if not already playing one.

procedure

(vlc-pause[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Toggle the playing pause state.

procedure

(vlc-stop[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Stop playing the current stream, if playing or paused.

procedure

(vlc-is-playing[#:vlcvlc])→number?

vlc:vlc?=(current-vlc)

Yields a boolean value for whether or not a stream is
playing.

5.5Rate

procedure

(vlc-fastforward[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Set rate of playing to maximum.

procedure

(vlc-rewind[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Set rate of playing to maximum reverse.

procedure

(vlc-faster[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Increase the rate of playing of the current stream.

procedure

(vlc-slower[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Lower the rate of playing of the current stream.

procedure

(vlc-normal[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Play the current stream, and at normal speed.

procedure

(vlc-frame[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Set current stream playing to frame-by-frame, or advance one
frame.

procedure

(vlc-raterate[#:vlcvlc])→void?

rate:real?

vlc:vlc?=(current-vlc)

Set playing rate to rate.

5.6Absolute Position

procedure

(vlc-get-time[#:vlcvlc])→number?

vlc:vlc?=(current-vlc)

Get the time position of the current stream, in seconds.

procedure

(vlc-get-length[#:vlcvlc])→number?

vlc:vlc?=(current-vlc)

Get the length of the current stream, in seconds.

procedure

(vlc-seekseconds[#:vlcvlc])→void?

seconds:exact-nonnegative-integer?

vlc:vlc?=(current-vlc)

Seek playing to position seconds.

5.7Audio, Video, and Subtitle Tracks

procedure

(vlc-atrack[#:vlcvlc])

→

integer?

(listof(cons/cstring?(listof(cons/cstring?integer?))))

vlc:vlc?=(current-vlc)

(vlc-atracknum[#:vlcvlc])→void?

num:integer?

vlc:vlc?=(current-vlc)

If num is not provided, yields information about current and available audio
tracks for the current stream.

If numis provided, switches the audio to that track.

procedure

(vlc-vtrack[#:vlcvlc])

→

integer?

(listof(cons/cstring?(listof(cons/cstring?integer?))))

vlc:vlc?=(current-vlc)

(vlc-vtracknum[#:vlcvlc])→void?

num:integer?

vlc:vlc?=(current-vlc)

If num is not provided, yields information about current and available video
tracks for the current stream.

If numis provided, switches the audio to that track.

procedure

(vlc-strack[#:vlcvlc])

→

integer?

(listof(cons/cstring?(listof(cons/cstring?integer?))))

vlc:vlc?=(current-vlc)

(vlc-stracknum[#:vlcvlc])→void?

num:integer?

vlc:vlc?=(current-vlc)

If num is not provided, yields information about current and available
subtitles and captions tracks for the current stream. For example, for one
DVD:

> (vlc-strack)

-1

'(("spu-es"

("Disable". -1)

("Track 1 - [Français]". 14)

("Track 2 - [Español]". 15)

("Closed captions 1". 17)

("Closed captions 2". 18)

("Closed captions 3". 19)

("Closed captions 4". 20)))

If numis provided, switches the subtitles/captions to that track.

5.8Audio Options

5.9Video Options

procedure

(vlc-fullscreenon?[#:vlcvlc])→void?

on?:boolean?

vlc:vlc?=(current-vlc)

Set whether VLC is in fullscreen mode.

5.10Misc. Info

procedure

(vlc-get-title[#:vlcvlc])→string?

vlc:vlc?=(current-vlc)

Get the title of the current stream. For example, a particular
DVD, might give behavior like:

> (vlc-get-title)

"WEST_WING_S7_D3"

Warning: Season 7 is not the best season for West Wing.

procedure

(vlc-status[#:vlcvlc])→(list-of(cons/cbytes?bytes?))

vlc:vlc?=(current-vlc)

Yields an alist of some information about current status. The car of each pair of the alist is a byte string of one of the
following attribute names, and the cdr is a byte string of the attribute value:

#"new input" – URL of the current playlist item.

#"audio volume" – number representing the audio volume.

#"state" – play state; possibly including the following values: #"playing", #"paused", #"stopped".

Which attributes are included depends on VLC.

6Snapshots

procedure

(vlc-snapshot[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Write a snapshot still image of the current video display to a
file. See VLC documentation for command line arguments for controlling where
and how these files are written, such as –snapshot-path.

7Exiting

procedure

(vlc-shutdown[#:vlcvlc])→void?

vlc:vlc?=(current-vlc)

Terminate the VLC process in an orderly fashion.

8Keys

In the RC protocol, some important additional operations are
available through the key command, especially for DVD menu navigation.

The exact keys here are taken from a list of key names from VideoLAN Wiki “How to Use Lirc” page, as viewed on 2012-10-03, which said “This is the complet
[sic] list of supported keys in VLC 0.8.6.”

9Other Operations

In addition to the procedures that correspond to VLC RC commands,
there are some additional procedures that are built atop RC commands.

procedure

(wait-for-vlc-active-playing

[

#:delaydelay

#:vlcvlc])

→

void?

delay:(and/creal?(not/cnegative?))=0.1

vlc:vlc?=(current-vlc)

Wait for VLC to be actively playing, by which we mean that the
stream has actually started playing, not just the RC status command indicating state: playing, when, say, the DVD hasn’t actually started playing. This seems
to be important for some other operations to take effect, such as seeking in
some cases.

Note that this procedure is currently protocol-intensive with the
RC interface. delay is the number of seconds to pause in between repeatedly sending
some RC messages. By default, it is 0.1, meaning one tenth of a second.

10Known Issues

Finish implementing RC commands.

Need to verify that RC uses UTF-8, and consistently.

Should try to verify existence of objects before being added to
the playlist, since otherwise VLC can keep trying them continuously and
flooding with repeated error messages.

The protocol parsing is pretty good, but could still be improved.
In particular, for some messages, it would be better to make the message end
detection sensitive to the syntax of the message. Before doing that, verify
that RC uses UTF-8 consistently.

Add a exn:fail:vlc exception, for ease of handling errors from the protocol, such as
error-message output from RC commands. Currently, these are raised as exn:fail.

Make vlc-status return strings instead of byte strings, after making sure UTF-8 is consistent.

11History

PLaneT 1:4 — 2012-10-03

Added RC key-related procedures.

PLaneT 1:3 — 2012-10-02

Added exception types.

PLaneT 1:2 — 2012-09-27

Documented that VLC 2.0.3 RC does not work on Windows,
so this package does not support Windows.

PLaneT 1:1 — 2012-09-27

When start-vlc can’t find VLC in the executable search path, it will
then try a few “known suspect” paths, including the standard one for Mac OS
X. (Thanks to Greg Hendershott for reporting.)

Documentation for start-vlc regarding custodians has been corrected. (Thanks to
Greg Hendershott for reporting.)

Updated documentation to say that this package has been
reported to work on Mac OS X and Microsoft Windows XP.

PLaneT 1:0 — 2012-09-22

Preliminary release for testing some of the functionality on
various host platforms and with various VLC versions in use. Not all commands
are implemented, and little testing has been done.

12Legal

Copyright 2012 Neil Van Dyke. This program is Free Software; you
can redistribute it and/or modify it under the terms of the GNU Lesser General
Public License as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version. This program is
distributed in the hope that it will be useful, but without any warranty;
without even the implied warranty of merchantability or fitness for a
particular purpose. See http://www.gnu.org/licenses/ for details. For other
licenses and consulting, please contact the author.
VideoLAN, VLC, and VLC media player are trademarks of VideoLAN.