From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS22989 209.51.188.0/24 X-Spam-Status: No, score=-4.1 required=3.0 tests=AWL,BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,SPF_HELO_PASS,SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id E44A61F406 for ; Thu, 12 Oct 2023 09:23:28 +0000 (UTC) Authentication-Results: dcvr.yhbt.net; dkim=pass (1024-bit key; unprotected) header.d=80x24.org header.i=@80x24.org header.a=rsa-sha256 header.s=selector1 header.b=IaPNqFb9; dkim-atps=neutral Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qqruI-0006ru-Qm; Thu, 12 Oct 2023 05:23:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqruI-0006rQ-1B for dtas-all@nongnu.org; Thu, 12 Oct 2023 05:23:02 -0400 Received: from dcvr.yhbt.net ([173.255.242.215]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qqruF-0004h9-V6 for dtas-all@nongnu.org; Thu, 12 Oct 2023 05:23:01 -0400 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 3E08D1F461 for ; Thu, 12 Oct 2023 09:22:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1697102571; bh=zE1iZ6/RqTh7HUU5lGKJ+7mb4UG+2HFDjlc3aYm028k=; h=From:To:Subject:Date:From; b=IaPNqFb9yBdAMMwBGTgdqque45jWkIHq9nYcHACeGksx2OV/rX4oOFA0A4T20eASQ DS/DMghw3KL/AjMYRdqmJBI2HXxHNqfkiMU4NpD1y1KokESy863+ysnkw2qlVd9LaR AkVgyp86ohguuXOHbQGKf7QtA3jOKn7XMzloMox4= From: Eric Wong To: dtas-all@nongnu.org Subject: [PATCH] favor ffmpeg over deprecated avconv Date: Thu, 12 Oct 2023 09:22:51 +0000 Message-ID: <20231012092251.3683488-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=173.255.242.215; envelope-from=e@80x24.org; helo=dcvr.yhbt.net X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: dtas-all@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: duct tape audio suite List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dtas-all-bounces+e=80x24.org@nongnu.org Sender: dtas-all-bounces+e=80x24.org@nongnu.org When this project started avconv was favored in Debian, but that hasn't been the case in many years. Increase the priority of ffmpeg to match the current situation in Debian. --- Documentation/dtas-player.pod | 10 +-- Documentation/dtas-sourceedit.pod | 8 +-- lib/dtas/source/av.rb | 6 +- lib/dtas/source/av_ff_common.rb | 8 +-- lib/dtas/source/ff.rb | 7 +- test/test_source_ff.rb | 102 ++++++++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 24 deletions(-) create mode 100644 test/test_source_ff.rb diff --git a/Documentation/dtas-player.pod b/Documentation/dtas-player.pod index 932441a..4cfdd12 100644 --- a/Documentation/dtas-player.pod +++ b/Documentation/dtas-player.pod @@ -70,10 +70,10 @@ To play audio on my favorite USB DAC directly to ALSA, I use: =head2 Seeking/playing audio from large video containers (e.g. VOB) fails This is a problem with large VOBs. We recommend breaking up the -VOB into smaller files or using L or L to extract -the desired audio stream. +VOB into smaller files or using L to extract +the desired audio stream at C<$STREAM_NR>. - avconv -analyzeduration 2G -probesize 2G \ + ffmpeg -analyzeduration 2G -probesize 2G \ -i input.vob -vn -sn -c:a copy -map 0:$STREAM_NR output.ext =head1 ADVANCED EXAMPLES @@ -115,7 +115,7 @@ No subscription is necessary to post to the mailing list. =head1 COPYRIGHT -Copyright 2013-2020 all contributors L +Copyright all contributors L License: GPL-3.0+ L @@ -123,4 +123,4 @@ License: GPL-3.0+ L L, L, L, L, L, L, L, -L, L, L, L +L, L, L diff --git a/Documentation/dtas-sourceedit.pod b/Documentation/dtas-sourceedit.pod index 67ecabf..593bcf5 100644 --- a/Documentation/dtas-sourceedit.pod +++ b/Documentation/dtas-sourceedit.pod @@ -51,11 +51,7 @@ of a previous "dtas-ctl source cat sox" invocation: $ dtas-sourceedit sox < saved.yml -To change the way dtas-player calls avconv (part of libav): - - $ dtas-sourceedit av - -To change the way dtas-player calls ffmpeg (lightly-tested): +To change the way dtas-player calls ffmpeg: $ dtas-sourceedit ff @@ -77,7 +73,7 @@ No subscription is necessary to post to the mailing list. =head1 COPYRIGHT -Copyright 2013-2020 all contributors L +Copyright all contributors L License: GPL-3.0+ L diff --git a/lib/dtas/source/av.rb b/lib/dtas/source/av.rb index 823b29f..dcebcfd 100644 --- a/lib/dtas/source/av.rb +++ b/lib/dtas/source/av.rb @@ -1,4 +1,4 @@ -# Copyright (C) 2013-2020 all contributors +# Copyright (C) all contributors # License: GPL-3.0+ # frozen_string_literal: true require_relative '../../dtas' @@ -13,9 +13,7 @@ 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 diff --git a/lib/dtas/source/av_ff_common.rb b/lib/dtas/source/av_ff_common.rb index 3839272..c600c48 100644 --- a/lib/dtas/source/av_ff_common.rb +++ b/lib/dtas/source/av_ff_common.rb @@ -7,10 +7,10 @@ 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 diff --git a/lib/dtas/source/ff.rb b/lib/dtas/source/ff.rb index 491e580..c337b42 100644 --- a/lib/dtas/source/ff.rb +++ b/lib/dtas/source/ff.rb @@ -1,12 +1,10 @@ -# Copyright (C) 2013-2020 all contributors +# Copyright (C) all contributors # License: GPL-3.0+ # 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,8 +13,7 @@ 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 diff --git a/test/test_source_ff.rb b/test/test_source_ff.rb new file mode 100644 index 0000000..e53e72e --- /dev/null +++ b/test/test_source_ff.rb @@ -0,0 +1,102 @@ +# Copyright (C) all contributors +# License: GPL-3.0+ +# frozen_string_literal: true +require './test/helper' +require 'dtas/source/ff' +require 'tempfile' + +class TestSourceFf < Testcase + def teardown + @tempfiles.each(&:close!) + end + + def setup + @tempfiles = [] + end + + def x(cmd) + system(*cmd) + assert $?.success?, cmd.inspect + end + + def new_file(suffix) + tmp = Tempfile.new(%W(tmp .#{suffix})) + @tempfiles << tmp + cmd = %W(sox -r 44100 -b 16 -c 2 -n #{tmp.path} trim 0 1) + return tmp if system(*cmd) + nil + end + + def test_flac + return if `which metaflac`.strip.size == 0 + tmp = new_file('flac') or return + + x(%W(metaflac --set-tag=FOO=BAR #{tmp.path})) + x(%W(metaflac --add-replay-gain #{tmp.path})) + source = DTAS::Source::Ff.new.try(tmp.path) + assert_equal source.comments["FOO"], "BAR", source.inspect + rg = source.replaygain('track_gain') + assert_kind_of DTAS::ReplayGain, rg + assert_in_delta 0.0, rg.track_peak.to_f, 0.00000001 + assert_in_delta 0.0, rg.album_peak.to_f, 0.00000001 + assert_operator rg.album_gain.to_f, :>, 1 + assert_operator rg.track_gain.to_f, :>, 1 + end + + def test_mp3gain + return if `which mp3gain`.strip.size == 0 + a = new_file('mp3') or return + b = new_file('mp3') or return + + # redirect stdout to /dev/null temporarily, mp3gain is noisy + File.open("/dev/null", "w") do |null| + old_out = $stdout.dup + $stdout.reopen(null) + begin + x(%W(mp3gain -q #{a.path} #{b.path})) + ensure + $stdout.reopen(old_out) + old_out.close + end + end + + source = DTAS::Source::Ff.new.try(a.path) + rg = source.replaygain('track_gain') + assert_kind_of DTAS::ReplayGain, rg + assert_in_delta 0.0, rg.track_peak.to_f, 0.00000001 + assert_in_delta 0.0, rg.album_peak.to_f, 0.00000001 + assert_operator rg.album_gain.to_f, :>, 1 + assert_operator rg.track_gain.to_f, :>, 1 + end + + def test_offset + tmp = new_file('flac') or return + source = DTAS::Source::Ff.new.try(*%W(#{tmp.path} 5s)) + assert_equal 5, source.offset_samples + + source = DTAS::Source::Ff.new.try(*%W(#{tmp.path} 1:00:00.5)) + expect = 1 * 60 * 60 * 44100 + (44100/2) + assert_equal expect, source.offset_samples + + source = DTAS::Source::Ff.new.try(*%W(#{tmp.path} 1:10.5)) + expect = 1 * 60 * 44100 + (10 * 44100) + (44100/2) + assert_equal expect, source.offset_samples + + source = DTAS::Source::Ff.new.try(*%W(#{tmp.path} 10.03)) + expect = (10 * 44100) + (44100 * 3/100.0) + assert_equal expect, source.offset_samples + end + + def test_offset_us + tmp = new_file('flac') or return + source = DTAS::Source::Ff.new.try(*%W(#{tmp.path} 441s)) + assert_equal 10000.0, source.offset_us + + source = DTAS::Source::Ff.new.try(*%W(#{tmp.path} 22050s)) + assert_equal 500000.0, source.offset_us + + source = DTAS::Source::Ff.new.try(tmp.path, '1') + assert_equal 1000000.0, source.offset_us + end +end if `which ffprobe 2>/dev/null` =~ /ffprobe/ && + `which ffmpeg 2>/dev/null` =~ /ffmpeg/