diff options
-rw-r--r-- | lib/dtas/source/av.rb | 49 | ||||
-rw-r--r-- | lib/dtas/source/sox.rb | 4 | ||||
-rw-r--r-- | test/test_source_av.rb | 13 |
3 files changed, 38 insertions, 28 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 diff --git a/lib/dtas/source/sox.rb b/lib/dtas/source/sox.rb index 954c1a5..235cbbc 100644 --- a/lib/dtas/source/sox.rb +++ b/lib/dtas/source/sox.rb @@ -86,9 +86,9 @@ class DTAS::Source::Sox # :nodoc: tmp 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 + e = player_format.to_env e["INFILE"] = @infile # make sure these are visible to the "current" command... diff --git a/test/test_source_av.rb b/test/test_source_av.rb index 2104b7e..4dba559 100644 --- a/test/test_source_av.rb +++ b/test/test_source_av.rb @@ -98,17 +98,4 @@ class TestSourceAv < Minitest::Unit::TestCase source = DTAS::Source::Av.new(tmp.path, '1') assert_equal 1000000.0, source.offset_us end - - def test_format_from_file - Tempfile.open(%w(tmp .wav)) do |tmp| - # generate an empty file with 1s of audio - cmd = %W(sox -r 96000 -b 24 -c 2 -n #{tmp.path} trim 0 1) - system(*cmd) - assert $?.success?, "#{cmd.inspect} failed: #$?" - fmt = DTAS::Source::Av.new(tmp.path).format - assert_equal 96000, fmt.rate - assert_equal 2, fmt.channels - tmp.unlink - end - end end |