diff options
author | Eric Wong <normalperson@yhbt.net> | 2013-08-25 12:03:11 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2013-08-25 12:27:33 +0000 |
commit | 963d0b4be91e1050ba947a9bbddd511f78321c54 (patch) | |
tree | 7b0f8b0211b0dd96838873285ae5593f398aa8dd /lib/dtas/source/av.rb | |
parent | 0f9bfb784b7bbccf86b7d7d241982ba4e703efd4 (diff) | |
download | dtas-963d0b4be91e1050ba947a9bbddd511f78321c54.tar.gz |
We need to tell sox to use and resample to the _player_ format instead of the source format. Otherwise 48000 Hz audio (common for video?) sounds very slow when attempting to play back on the default 44100 Hz. It is also likely preferable to choose the audio stream which matches the player channel count instead of letting sox automatically invoke the remix effect. Before this change, playing 6-channel, 48000 Hz source into a sink expecting stereo, 44100 Hz is rather disturbing... While we're at it, clarify the spawn code for the sox source, too. We can drop the test_format_from_file test now, since it's probably overkill at this point.
Diffstat (limited to 'lib/dtas/source/av.rb')
-rw-r--r-- | lib/dtas/source/av.rb | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/lib/dtas/source/av.rb b/lib/dtas/source/av.rb index 804a66b..1de0a72 100644 --- a/lib/dtas/source/av.rb +++ b/lib/dtas/source/av.rb @@ -11,9 +11,12 @@ class DTAS::Source::Av # :nodoc: include DTAS::Source::File + AStream = Struct.new(:duration, :channels, :rate) + AV_DEFAULTS = COMMAND_DEFAULTS.merge( "command" => - 'avconv -v error $SSPOS -i "$INFILE" -f sox - | sox -p $SOXFMT - $RGFX', + 'avconv -v error $SSPOS -i "$INFILE" $AMAP -f sox - |' \ + 'sox -p $SOXFMT - $RGFX', "comments" => nil, ) @@ -42,24 +45,23 @@ class DTAS::Source::Av # :nodoc: @comments = {} err = "" s = qx(%W(avprobe -show_streams -show_format #@infile), err: err) + @astreams = [] s.scan(%r{^\[STREAM\]\n(.*?)\n\[/STREAM\]\n}m) do |_| stream = $1 # XXX what to do about multiple streams? if stream =~ /^codec_type=audio$/ - duration = channels = rate = nil - stream =~ /^duration=([\d\.]+)\s*$/m and duration = $1.to_f - stream =~ /^channels=(\d)\s*$/m and channels = $1.to_i - stream =~ /^sample_rate=([\d\.]+)\s*$/m and rate = $1.to_i - if channels > 0 && rate > 0 - @duration = duration - @format.channels = channels - @format.rate = rate - end + as = AStream.new + index = nil + stream =~ /^index=(\d+)\s*$/m and index = $1.to_i + stream =~ /^duration=([\d\.]+)\s*$/m and as.duration = $1.to_f + stream =~ /^channels=(\d)\s*$/m and as.channels = $1.to_i + stream =~ /^sample_rate=([\d\.]+)\s*$/m and as.rate = $1.to_i + @astreams[index] = as if as.channels > 0 && as.rate > 0 end end s.scan(%r{^\[FORMAT\]\n(.*?)\n\[/FORMAT\]\n}m) do |_| f = $1 - f =~ /^duration=([\d\.]+)\s*$/m and @duration ||= $1.to_f + f =~ /^duration=([\d\.]+)\s*$/m and @duration = $1.to_f # TODO: multi-line/multi-value/repeated tags f.gsub!(/^TAG:([^=]+)=(.*)$/i) { |_| @comments[$1.upcase] = $2 } end @@ -71,10 +73,31 @@ class DTAS::Source::Av # :nodoc: sprintf("-ss %0.9g", samples / @format.rate) end - def spawn(format, rg_state, opts) + def spawn(player_format, rg_state, opts) raise "BUG: #{self.inspect}#spawn called twice" if @to_io - e = @format.to_env + amap = nil + found_as = nil + + # try to find an audio stream which matches our channel count + # we need to set @format for sspos() down below + @astreams.each_with_index do |as, index| + if as && as.channels == player_format.channels + @format.channels = as.channels + @format.rate = as.rate + found_as = as + amap = "-map 0:#{index}" + end + end + unless found_as + first_as = @astreams.compact[0] + if first_as + @format.channels = found_as.channels + @format.rate = found_as.rate + end + end + e = player_format.to_env e["INFILE"] = @infile + e["AMAP"] = amap # make sure these are visible to the "current" command... @env["SSPOS"] = @offset ? sspos(@offset) : nil |