diff options
Diffstat (limited to 'lib/dtas/source')
-rw-r--r-- | lib/dtas/source/av.rb | 7 | ||||
-rw-r--r-- | lib/dtas/source/av_ff_common.rb | 43 | ||||
-rw-r--r-- | lib/dtas/source/ff.rb | 8 | ||||
-rw-r--r-- | lib/dtas/source/sox.rb | 5 |
4 files changed, 42 insertions, 21 deletions
diff --git a/lib/dtas/source/av.rb b/lib/dtas/source/av.rb index 39cad6c..dcebcfd 100644 --- a/lib/dtas/source/av.rb +++ b/lib/dtas/source/av.rb @@ -1,4 +1,4 @@ -# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org> +# Copyright (C) all contributors <dtas-all@nongnu.org> # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt> # frozen_string_literal: true require_relative '../../dtas' @@ -13,13 +13,12 @@ class DTAS::Source::Av # :nodoc: 'avconv -v error $SSPOS $PROBE -i "$INFILE" $AMAP -f sox - |' \ 'sox -p $SOXFMT - $TRIMFX $RGFX', - # this is above ffmpeg because this av is the Debian default and - # it's easier for me to test av than ff - "tryorder" => 1, + "tryorder" => 2, ) def initialize command_init(AV_DEFAULTS) + @mcache = nil @av_ff_probe = "avprobe" end diff --git a/lib/dtas/source/av_ff_common.rb b/lib/dtas/source/av_ff_common.rb index 5299fdb..7f197e0 100644 --- a/lib/dtas/source/av_ff_common.rb +++ b/lib/dtas/source/av_ff_common.rb @@ -7,10 +7,10 @@ require_relative '../replaygain' require_relative '../xs' require_relative 'file' -# Common code for libav (avconv/avprobe) and ffmpeg (and ffprobe) -# TODO: newer versions of both *probes support JSON, which will be easier to -# parse. However, the packaged libav version in Debian 7.0 does not -# support JSON, so we have an ugly parser... +# Common code for ffmpeg/ffprobe and the abandoned libav (avconv/avprobe). +# TODO: newer versions of both *probes support JSON, which will be easier +# to parse. libav is abandoned, nowadays, and Debian only packages +# ffmpeg+ffprobe nowadays. module DTAS::Source::AvFfCommon # :nodoc: include DTAS::Source::File include DTAS::XS @@ -21,10 +21,23 @@ module DTAS::Source::AvFfCommon # :nodoc: attr_reader :format attr_reader :duration + CACHE_KEYS = [ :@duration, :@probe_harder, :@comments, :@astreams, + :@format ].freeze + + def mcache_lookup(infile) + (@mcache ||= DTAS::Mcache.new).lookup(infile) do |input, dst| + tmp = source_file_dup(infile, nil, nil) + tmp.av_ff_ok? or return nil + CACHE_KEYS.each { |k| dst[k] = tmp.instance_variable_get(k) } + dst + end + end + def try(infile, offset = nil, trim = nil) - rv = source_file_dup(infile, offset, trim) - rv.av_ff_ok? or return - rv + ent = mcache_lookup(infile) or return + ret = source_file_dup(infile, offset, trim) + CACHE_KEYS.each { |k| ret.instance_variable_set(k, ent[k]) } + ret end def __parse_astream(cmd, stream) @@ -79,7 +92,7 @@ module DTAS::Source::AvFfCommon # :nodoc: err = "".b begin - s = qx(@env, cmd, err_str: err, no_raise: true) + s = qx(@env, cmd, err_str: err, no_raise: true, rlimit_cpu: [ 1, 2 ]) rescue Errno::ENOENT # avprobe/ffprobe not installed return false end @@ -104,13 +117,14 @@ module DTAS::Source::AvFfCommon # :nodoc: prev_cmd = cmd end while incomplete.compact[0] + enc = Encoding.default_external # typically Encoding::UTF_8 # old avprobe s.scan(%r{^\[FORMAT\]\n(.*?)\n\[/FORMAT\]\n}m) do |_| f = $1.dup f =~ /^duration=([\d\.]+)\s*$/nm and @duration = $1.to_f # TODO: multi-line/multi-value/repeated tags f.gsub!(/^TAG:([^=]+)=(.*)$/ni) { |_| - @comments[$1.upcase] = -($2) + @comments[-DTAS.try_enc($1.upcase, enc)] = $2 } end @@ -118,13 +132,22 @@ module DTAS::Source::AvFfCommon # :nodoc: s.scan(%r{^\[format\.tags\]\n(.*?)\n\n}m) do |_| f = $1.dup f.gsub!(/^([^=]+)=(.*)$/ni) { |_| - @comments[$1.upcase] = -$2 + @comments[-DTAS.try_enc($1.upcase, enc)] = $2 } end s.scan(%r{^\[format\]\n(.*?)\n\n}m) do |_| f = $1.dup f =~ /^duration=([\d\.]+)\s*$/nm and @duration = $1.to_f end + comments.each do |k,v| + v.chomp! + comments[k] = -DTAS.try_enc(v, enc) + end + + # ffprobe always uses "track", favor FLAC convention "TRACKNUMBER": + if @comments['TRACK'] && !@comments['TRACKNUMBER'] + @comments['TRACKNUMBER'] = @comments.delete('TRACK') + end ! @astreams.compact.empty? end diff --git a/lib/dtas/source/ff.rb b/lib/dtas/source/ff.rb index 687cd18..c337b42 100644 --- a/lib/dtas/source/ff.rb +++ b/lib/dtas/source/ff.rb @@ -1,12 +1,10 @@ -# Copyright (C) 2013-2020 all contributors <dtas-all@nongnu.org> +# Copyright (C) all contributors <dtas-all@nongnu.org> # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt> # frozen_string_literal: true require_relative '../../dtas' require_relative 'av_ff_common' # ffmpeg support -# note: only tested with the compatibility wrapper in the Debian 7.0 package -# (so still using avconv/avprobe) class DTAS::Source::Ff # :nodoc: include DTAS::Source::AvFfCommon @@ -15,12 +13,12 @@ class DTAS::Source::Ff # :nodoc: 'ffmpeg -v error $SSPOS $PROBE -i "$INFILE" $AMAP -f sox - |' \ 'sox -p $SOXFMT - $TRIMFX $RGFX', - # I haven't tested this much since av is in Debian stable and ff is not - "tryorder" => 2, + "tryorder" => 1, ) def initialize command_init(FF_DEFAULTS) + @mcache = nil @av_ff_probe = "ffprobe" end diff --git a/lib/dtas/source/sox.rb b/lib/dtas/source/sox.rb index 6ca29bc..365c7b6 100644 --- a/lib/dtas/source/sox.rb +++ b/lib/dtas/source/sox.rb @@ -24,7 +24,7 @@ class DTAS::Source::Sox # :nodoc: return if @last_failed == infile @last_failed = infile case msg - when Process::Status then msg = "failed with #{msg.exitstatus}" + when Process::Status then msg = "failed with #{msg.inspect}" when 0 then msg = 'detected zero samples' end warn("soxi #{infile}: #{msg}\n") @@ -39,7 +39,8 @@ class DTAS::Source::Sox # :nodoc: def mcache_lookup(infile) (@mcache ||= DTAS::Mcache.new).lookup(infile) do |input, dst| err = ''.b - out = qx(@env.dup, %W(soxi #{input}), err_str: err, no_raise: true) + out = qx(@env.dup, %W(soxi #{input}), err_str: err, no_raise: true, + rlimit_cpu: [ 1, 2 ]) return soxi_failed(infile, out) if Process::Status === out return soxi_failed(infile, err) if err =~ /soxi FAIL formats:/ out =~ /^Duration\s*:[^=]*= (\d+) samples /n |