Wednesday, September 1, 2010

Issuing commands to VLC and collecting output to file

So, I wanted to play a video using VLC Media Player and collect statistics like lost frames and bit rate into a file every x seconds while the video is running. Seems pretty straight forward considering that the stats can be viewed from the VLC GUI. So it should be a straight forward matter to get them into a file, right? Wrong !!

I tried several approaches including using the rc interface. Pierre gave me a piece of code that solves the problem on his machine:
while true; do echo stats; sleep 2; done | vlc -I rc filename > out.txt

Here, the filename is the name of the file that needs to be played and the number following sleep is the time between two reads of the statistics. As you can see, all this piece of code does is to issue (using pipe |) stats command to the rc interface (denoted by the -I option) every 2 seconds and store the output into out.txt file. For some reason the same code did not work on my machine and I kept getting the error message:
user@machine:~$ while true; do echo stats; sleep 2; done | vlc -I rc 350animation2.mpg > out.txt
VLC media player 1.0.2 Goldeneye
[0x8731750] main interface error: no suitable interface module
[0x8685140] main libvlc error: interface "default" initialization failed
I am using VLC media player 1.0.2 and my OS is Ubuntu Karmic Koala.If anyone has a clue as to what could be causing the problem, please send me a comment. Between, I was able to redirect the output stats to a file using the rc interface. For that I started VLC using vlc --intf rc filename >output.txt and then in the interface that opens, I issued the stats command. What I could not do was to automate the process of issuing the stats command every x seconds.

While trying to resolve the issue, I stumbled upon this "Not a blog" where the author shows how to issue commands to VLC from the command line using netcat and UNIX sockets. I tried to extrapolate from the code and tweak it to channel the collection of stats but it did not work. My super naive attempts basically were along the lines of writing a bash script that starts the video and then runs in an infinite loop trying to collect stats and sleep, as shown below:
echo play 350animation2.mpg
while true
do
echo stats
sleep 2
done
Then I would redirect the input and output to the VLC interface. But the same error message persisted. David Wolinsky came to the rescue. Here is the script that he come up with:
#!/bin/bash

set +o nounset
LC_ALL=C ; LANG=C ; export LC_ALL LANG
version >/dev/null 2>&1 && version "=o" $(_eat $0 $1)
set -o nounset

set -m

run() {
pid=$1
sleep 4
while true; do
echo -n "stats" | nc -U vlc.sock
if [[ ! $(ps uax | grep -v grep | grep $pid) ]]; then
return
fi
sleep 2

done
}

vlc -I rc --rc-unix vlc.sock 350animation2.mpg &> out &
pid=$!
run $pid &
fg %1
As you can see, this code uses the UNIX socket approach as well. After the VLC process is started, the PID is stored and used to start the run script on the top. The output gets stored in the out file. The fg (fore ground) command in the end is apparently necessary.

Thanks to Pierre, David and Andrabr for help with this problem!