Class: MPlayer::Worker::Stream

Inherits:
Object
  • Object
show all
Includes:
ColorDebugMessages
Defined in:
lib/easy_mplayer/worker.rb

Constant Summary collapse

MATCH_STDOUT =

:nodoc:

{ # :nodoc:
  :version => {
    :re   => /^MPlayer\s(\S+)\s\(C\)/,
    :stat => [:version]
  },
  :server => {
    :re   => /^Connecting to server (\S+)\[(\d+\.\d+\.\d+\.\d+)\]:/,
    :stat => [:server, :server_ip]
  },
  :stream_info => {
    :re   => /^ICY Info: StreamTitle='(.*?)';StreamUrl='(.*?)';/,
    :stat => [:stream_title, :stream_url]
  },
  :update_position => {
    :re   => /^A:\s+(\d+\.\d+)\s+\(\S+\)\s+of\s+(\d+\.\d+)/,
    :stat => [:played_time, :total_time],
  },
  :audio_info => {
    :re   => /^AUDIO: (\d+) Hz, (\d+) ch, (\S+), ([0-9.]+) kbit/,
    :stat => [:audio_sample_rate, :audio_channels,
              :audio_format, :audio_data_rate],
    :call => :audio_stats
  },
  :video_info => {
    :re   => /^VIDEO:\s+\[(\S{4})\]\s+(\d+)x(\d+)\s+(\d+)bpp\s+(\d+\.\d+)\s+fps/,
    :stat => [:video_fourcc, :video_x_size, :video_y_size,
              :video_bpp, :video_fps],
    :call => :video_stats
  },
  :video_decoder => {
    :re   => /^Opening video decoder: \[(\S+)\]/,
    :stat => [:video_decoder]
  },
  :audio_decoder => {
    :re   => /^Opening audio decoder: \[(\S+)\]/,
    :stat => [:audio_decoder]
  },
  :video_codec => {
    :re   => /^Selected video codec: \[(\S+)\]/,
    :stat => [:video_codec]
  },
  :audio_codec => {
    :re   => /^Selected audio codec: \[(\S+)\]/,
    :stat => [:audio_codec]
  }
}
MATCH_STDERR =

:nodoc:

{ # :nodoc:
  :file_not_found => {
    :re => /^File not found: /,
    :call => :file_error
  }
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(p, w, stream_type, stream_io) ⇒ Stream

Returns a new instance of Stream.



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/easy_mplayer/worker.rb', line 64

def initialize(p, w, stream_type, stream_io)
  @parent  = p
  @worker  = w
  @type    = stream_type
  @io      = stream_io
  @line    = ''
  @outlist = Array.new
  @stats   = Hash.new
  @select_wait_time = p.opts[:select_wait_time]
  @sent_update_position = false
end

Instance Attribute Details

#ioObject (readonly)

Returns the value of attribute io.



62
63
64
# File 'lib/easy_mplayer/worker.rb', line 62

def io
  @io
end

#parentObject (readonly)

Returns the value of attribute parent.



62
63
64
# File 'lib/easy_mplayer/worker.rb', line 62

def parent
  @parent
end

#typeObject (readonly)

Returns the value of attribute type.



62
63
64
# File 'lib/easy_mplayer/worker.rb', line 62

def type
  @type
end

Instance Method Details

#callback!(name, *args) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/easy_mplayer/worker.rb', line 88

def callback!(name, *args)
  case name
  when :update_stat
    stat = args[0]
    val  = args[1]
    if @stats[stat] == val
      return # only propagate changes
    else
      @stats[stat] = val
    end
  end
  @worker.queue_callback [name, args]
end

#check_line(patterns, line) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/easy_mplayer/worker.rb', line 102

def check_line(patterns, line)
  patterns.each_pair do |name, pat|
    if md = pat[:re].match(line)
      args = md.captures.map do |x|
        case x
        when /^\d+$/      then Integer(x)
        when /^\d+\.\d+$/ then Float(x)
        else x
        end
      end
      
      (pat[:stat] || []).each do |field|
        callback! :update_stat, field, args.shift
      end
      
      callback! pat[:call] if pat[:call]
      return name
    end
  end
  nil
end

#cleanupObject



175
176
177
# File 'lib/easy_mplayer/worker.rb', line 175

def cleanup
  @io.close unless @io.closed?
end

#debug(msg) ⇒ Object



80
# File 'lib/easy_mplayer/worker.rb', line 80

def debug(msg); super prefix(msg); end

#info(msg) ⇒ Object



81
# File 'lib/easy_mplayer/worker.rb', line 81

def info(msg);  super prefix(msg); end

#joinObject



184
185
186
187
# File 'lib/easy_mplayer/worker.rb', line 184

def join
  @thread.join if @thread
  @thread = nil
end

#killObject



179
180
181
182
# File 'lib/easy_mplayer/worker.rb', line 179

def kill
  @alive = false
  cleanup
end

#prefix(msg) ⇒ Object



76
77
78
# File 'lib/easy_mplayer/worker.rb', line 76

def prefix(msg)
  "STREAM [#{@type}] #{msg}"
end

#process_lineObject



134
135
136
137
138
139
# File 'lib/easy_mplayer/worker.rb', line 134

def process_line
  # debug "LINE> \"#{@line}\""
  send "process_#{@type}", @line
  # callback! @type, @line
  @line = ''
end

#process_stderr(line) ⇒ Object



128
129
130
131
132
# File 'lib/easy_mplayer/worker.rb', line 128

def process_stderr(line)
  if check_line(MATCH_STDERR, line)
    stream_error(:stderr)
  end
end

#process_stdout(line) ⇒ Object



124
125
126
# File 'lib/easy_mplayer/worker.rb', line 124

def process_stdout(line)
  check_line(MATCH_STDOUT, line)
end

#process_streamObject



141
142
143
144
145
146
147
148
149
150
# File 'lib/easy_mplayer/worker.rb', line 141

def process_stream
  result = IO.select([@io], nil, nil, @select_wait_time)
  return if result.nil? or result.empty?

  c = @io.read(1)
  return stream_error(:eof) if c.nil?
  
  @line << c
  process_line if c == "\n" or c == "\r"
end

#runObject



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/easy_mplayer/worker.rb', line 152

def run
  @thread = Thread.new do
    @alive = true
    begin
      debug "start"
      process_stream while @alive
      debug "clean end!"
    rescue IOError => e
      if e.to_s =~ /stream closed/
        debug "stream closed!"
      else
        raise BadStream, e.to_s
      end
    rescue => e
      warn "Unexpected error when parsing MPlayer's IO stream!"
      warn "error was: #{e}"
      stream_error(:exception)
    ensure
      cleanup
    end
  end
end

#stream_error(type) ⇒ Object



84
85
86
# File 'lib/easy_mplayer/worker.rb', line 84

def stream_error(type)
  @worker.flag_stream_error(type)
end

#warn(msg) ⇒ Object



82
# File 'lib/easy_mplayer/worker.rb', line 82

def warn(msg);  super prefix(msg); end