Tom Ehrlich
Tom Ehrlich

Reputation: 6651

Write mplayer's output to fifo and read it

I'm trying write simple notify app in bash. I want to read output from mplayer, parse it and display through notify-send.

I can get desired info from mplayer using this:

mplayer <url> | grep ICY

and then parse in using sed.

I create named pipe, tell mplayer to write it and then I'm reading from it. Unfortunately, it doesn't work. Here's my script:

$fifo=~/.rp/fifo
mkfifo $fifo

mplayer <url> 2>/dev/null | grep ICY 1> $fifo &

while read line < $fifo; do
    echo $line
done

wait

Program keeps waiting to input from $fifo. I tried following in other terminal, while this script is running:

  1. Run

    echo "Test" > .rp/fifo
    

    Terminal with running script shows "Test"

  2. Run

    echo "ICY" | grep ICY > .rp/fifo
    

    also works.

  3. Run

    mplayer <url> | grep ICY > .rp/fifo
    

    and it doesn't work.

Is I said above, the combination of mplayer | grep works fine. grep > $fifo works fine. I don't understand why mplayer | grep > $fifo doesn't work.

Upvotes: 4

Views: 7544

Answers (3)

podcast
podcast

Reputation: 141

I start mplayer in slave mode, using FIFO file.

mkfifo /tmp/mpfifo

mplayer -slave -input file=/tmp/mpfifo video.mp4

I am able to control the video player from another terminal.

echo "pause" >> /tmp/mpfifo
echo "volume 50" > /tmp/mpfifo

I want to get value (for example current position of playing video). So I tried:

echo "get_time_pos" > /tmp/mpfifo

But no value returned. I searched for hours, but no success. Then I thought to redirect mplayer output to a file:

mplayer -slave -input file=/tmp/mpfifo video.mp4 > /tmp/mpout.txt

After that when like following commands executed:

echo "get_time_pos" > /tmp/mpfifo
echo "get_property length" > /tmp/mpfifo

The outputs in /tmp/mpout.txt was like:

.......
.......
ANS_TIME_POSITION=113.6
ANS_length=2534.602031

If the result of each command would return to the command line would be very nice. Even it may need some works, the output file can be parsed, though.

Upvotes: 2

F. Hauri  - Give Up GitHub
F. Hauri - Give Up GitHub

Reputation: 70967

You could do unbuffered grep with:

$ mplayer ...  2>&1 | grep --line-buffered "ICY"

or better:

$ mplayer ...  2>&1 | sed -une 's/^.*ICY[^:]*: //p'

or even, why not (sed is very nice for grep and formatting), this will grep ICY lines and even split line containing - in a first field of 30 chars length separed by a : from a second field:

$ mplayer ...  2>&1 |
    sed -une "
        /ICY/{
            s/^.*ICY[^:]*:.*'\([^']*\)';/\1/;
            s/^\(.*\) - /\1                              - /;
            s/^\(.\{30\}\) *- /\1: /;
            p;
    }"

could give something like:

Artist name                  : Song title
Other artist                 : Other song
Unsplited line
Artist                       : Title

Upvotes: 4

Bernd Jendrissek
Bernd Jendrissek

Reputation: 1088

I suspect you might be experiencing the C library's fully buffered mode for streams. You don't say that you're running the GNU userspace, but if you are, you can look into stdbuf(1) to modify the buffering regime.

You might try first running just grep as a child of stdbuf(1), like this:

mplayer <url> | stdbuf -o L grep ICY > .rp/fifo

If that doesn't work, moar is bettar!

stdbuf -o 0 mplayer <url> | stdbuf -o L grep ICY > .rp/fifo

And if that still doesn't work, then it's possible that mplayer isn't writing to stdout, but directly to /dev/tty. In which case, you will need to read up on expect(1).

Upvotes: 5

Related Questions