about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--lib/dtas/source/av.rb49
-rw-r--r--lib/dtas/source/sox.rb4
-rw-r--r--test/test_source_av.rb13
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