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]
  },
  :position_percent => {
    :re   => /^ANS_PERCENT_POSITION=(\d+[.0-9]*)/,
    :stat => [:position]
  },
  :position_seconds => {
    :re   => /^ANS_TIME_POSITION=(\d+[.0-9]*)/,
    :stat => [:played_seconds]
  },
  :total_time => {
    :re   => /^ANS_LENGTH=(\d+[.0-9]*)/,
    :stat => [: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.



74
75
76
77
78
79
80
81
82
83
84
# File 'lib/easy_mplayer/worker.rb', line 74

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.



72
73
74
# File 'lib/easy_mplayer/worker.rb', line 72

def io
  @io
end

#parentObject (readonly)

Returns the value of attribute parent.



72
73
74
# File 'lib/easy_mplayer/worker.rb', line 72

def parent
  @parent
end

#typeObject (readonly)

Returns the value of attribute type.



72
73
74
# File 'lib/easy_mplayer/worker.rb', line 72

def type
  @type
end

Instance Method Details

#callback!(name, *args) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/easy_mplayer/worker.rb', line 98

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



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/easy_mplayer/worker.rb', line 112

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



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

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

#debug(msg) ⇒ Object



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

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

#info(msg) ⇒ Object



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

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

#joinObject



190
191
192
193
# File 'lib/easy_mplayer/worker.rb', line 190

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

#killObject



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

def kill
  @alive = false
  cleanup
end

#prefix(msg) ⇒ Object



86
87
88
# File 'lib/easy_mplayer/worker.rb', line 86

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

#process_line(line) ⇒ Object



144
145
146
147
148
# File 'lib/easy_mplayer/worker.rb', line 144

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

#process_stderr(line) ⇒ Object



138
139
140
141
142
# File 'lib/easy_mplayer/worker.rb', line 138

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

#process_stdout(line) ⇒ Object



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

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

#process_streamObject



150
151
152
153
154
155
# File 'lib/easy_mplayer/worker.rb', line 150

def process_stream
  lines = @io.gets("\r") or return stream_error(:eof)
  lines.split(/\n/).each do |line|
    process_line(line.chomp)
  end
end

#runObject



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/easy_mplayer/worker.rb', line 157

def run
  @thread = Thread.new do
    @alive = true
    begin
      # @io.fcntl(Fcntl::F_SETFL,Fcntl::O_NONBLOCK)
      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



94
95
96
# File 'lib/easy_mplayer/worker.rb', line 94

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

#warn(msg) ⇒ Object



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

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