Using MPlayer identify with Ruby

For a project I need to fetch some metadata from WAV recordings. Mplayer can extract this information nicely with the -identify command. I’m using Ruby Sessions for executing the external mplayer command, although a simple IO.POpen() might do fine too. The code wrapper class looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
require 'rubygems'
require_gem 'session'

class MediafileInfo
        MPLAYER_BINARY = "mplayer"
        MPLAYER_IDENTIFY = "-identify -vo null -ao null -frames 0"

        def initialize(filename)
                stdout, stderr = '', ''
                shell = Session::Shell.new
                shell.execute "#{MPLAYER_BINARY} #{MPLAYER_IDENTIFY} #{filename}", :stdout => stdout, :stderr => stderr

                vars = (stdout.split(/\n/).collect! { |o| o if o =~ /^ID_/ } ).compact!

                vars.each { |v|
                        a, b = v.split("=")
                        eval "@#{a.to_s.downcase} = \"#{b}\""
                }
        end

        # Intercept calls
        def method_missing(method_name, *args)
                value = eval "@id_#{method_name.to_s.downcase}"
        end
end



All ID_* lines that mplayer spits out will now be method calls (and instance variables) of your MediafileInfo object. The method_missing call is there to do proper value defaulting if the variable doesn’t exist, but I’m not using it as such right now. To get the playing time of every type of mediafile that mplayer understands you simply do someting like:

1
2
3
info = MediafileInfo.new("voicemail.wav")

puts "Voicemail playtime: #{info.length.to_i} seconds"

Ruby 0wnz! :)


This entry was posted in Home and tagged , , . Bookmark the permalink.

4 Responses to Using MPlayer identify with Ruby

  1. p3t0r says:

    Cool hack!

    I tried to figure out why you use the <em>compact!</em> function… doesn’t this return nil if it didn’t make any changes?
    <pre>

    irb(main):001:0> ["a","b","c"].compact!
    => nil
    irb(main):002:0> ["a","b","c",nil].compact!
    => ["a", "b", "c"]
    irb(main):003:0> ["a","b","c",nil].compact
    => ["a", "b", "c"]

    </pre>

    Using <em>compact</em> seems safer to me…

  2. andy says:

    According to the specs yes, but this is never an issue in this case. But you are right, it is still safer to use compact, nice catch :)

    -andy

  3. albert says:

    I had to do something similar. Check out my version, based on yours.

    http://pastie.caboo.se/40788

  4. andy says:

    @albert: much more robust implementation, nice!<br/>
    <br/>
    thx,<br/>
    andy