[FFmpeg-devel] [PATCH 2/2] tools: add make_chlayout_test perl script.

Stefano Sabatini stefasab at gmail.com
Mon Aug 27 10:56:29 CEST 2012


On date Saturday 2012-08-25 21:06:09 +0200, Nicolas George encoded:
> This script uses the flite source to produce files
> suitable to test channels order and layout.
> 
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
>  tools/make_chlayout_test |  120 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 120 insertions(+)
>  create mode 100755 tools/make_chlayout_test
> 
> 
> The doc changed to pod, apart from that unchanged.
> 
> 
> diff --git a/tools/make_chlayout_test b/tools/make_chlayout_test
> new file mode 100755
> index 0000000..cd7b77b
> --- /dev/null
> +++ b/tools/make_chlayout_test
> @@ -0,0 +1,120 @@
> +#!/usr/bin/env perl
> +
> +# Copyright (c) 2012 Nicolas George
> +#
> +# This file is part of FFmpeg.
> +#
> +# FFmpeg is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU Lesser General Public
> +# License as published by the Free Software Foundation; either
> +# version 2.1 of the License, or (at your option) any later version.
> +#
> +# FFmpeg is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> +# See the GNU Lesser General Public License for more details.
> +#
> +# You should have received a copy of the GNU Lesser General Public License
> +# along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
> +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> +
> +=pod
> +
> +=head1 NAME
> +
> +make_chlayout_test - produce a multichannel test file with the channels
> +clearly identified
> +
> +=head1 DESCRIPTION
> +
> +This script uses B<ffmpeg> and B<libflite> to produce a file with audio
> +channels clearly identified by their name. The resulting file can be used to
> +check that the layout and order of channels is correctly handled by a piece
> +of software, either a part of B<FFmpeg> or not.
> +
> +Usage:
> +B<tools/make_chlayout_test> I<channels> I<out options>
> +
> +I<channels> is a list of channels or channel layouts, separated by '+'.
> +
> +I<out options> is a list of valid ffmpeg outout options, including the
> +output file.
> +
> +Note that some output codecs or formats can not handle arbitrary channel
> +layout.
> +
> +This script requires a B<ffmpeg> binary, either in the source tree or in the
> +search path; it must have the flite audio source enabled.
> +
> +=head1 EXAMPLES
> +
> +Check that the speakers are correctly plugged:
> +
> +  tools/make_chlayout_test FL+FR -f alsa default
> +
> +Produce a 5.1 FLAC file:
> +
> +  tools/make_chlayout_test 5.1 surround.flac
> +d
> +=cut
> +
> +use strict;
> +use warnings;
> +
> +sub usage($) {
> +  my ($die) = @_;
> +  my $msg = "Usage: $0 <channels> <out options>\n" .
> +    "perldoc $0 for more information\n";
> +  die $msg if $die;
> +  print $msg;
> +  exit 0;
> +}
> +
> +usage 0 if @ARGV && $ARGV[0] =~ /^-+h(?:elp)?/;
> +usage 1 unless @ARGV >= 2;

Note: maybe the use of use Getopt::Long and Pod::Usage; may made
things much robust/simpler/extensible.

use Getopt::Long;
use Pod::Usage;

GetOptions (
    'help|usage|?|h'           => sub { pod2usage ( { -verbose => 1, -exitval => 0 }) },
    'manpage|m'                => sub { pod2usage ( { -verbose => 2, -exitval => 0 }) },
    # issue an error message and exit
    ) or pod2usage( { -message=> "Parsing error", 
		      -verbose => 1, -exitval => 1 });

> +my $channels = shift @ARGV;
> +my @out_options = @ARGV;
> +
> +my $ffmpeg = exists $ENV{FFMPEG} ? $ENV{FFMPEG} :
> +             $0 =~ /(.*)\// && -e "$1/../ffmpeg" ? "$1/../ffmpeg" :
> +             "ffmpeg";
> +
> +my %channel_label_to_descr;
> +my %layout_to_channels;
> +

> +{
> +  open my $stderr, ">&STDERR";
> +  open STDERR, ">", "/dev/null";
> +  open my $f, "-|", $ffmpeg, "-layouts" or die "$ffmpeg: $!\n";
> +  open STDERR, ">&", $stderr;
> +  while (<$f>) {
> +    chomp;
> +    next if /^NAME/ or /:$/ or /^$/; # skip headings
> +    my ($name, $descr) = split " ", $_, 2;
> +    next unless $descr;
> +    if ($descr =~ /^[[:upper:]]+(?:\+[[:upper:]]+)*$/) {
> +      $layout_to_channels{$name} = [ split /\+/, $descr ];
> +    } else {
> +      $channel_label_to_descr{$name} = $descr;
> +    }
> +  }
> +}

Stateful parsing is in general not very robust, and headers may
change, and even for this I'd consider more robust two distinct
options to fill the two separate hashes %layout_to_channels and
%channel_label_to_descr.

> +
> +my @channels = map { @{$layout_to_channels{$_} // [$_]} } split /\+/, $channels;
> +
> +my $layout = join "+", @channels;
> +my $graph = "";
> +my $concat_in = "";
> +for my $i (0 .. $#channels) {
> +  my $label = $channels[$i];
> +  my $descr = $channel_label_to_descr{$label}
> +    or die "Channel $label not found\n";
> +  $graph .= "flite=text='${descr}', aformat=channel_layouts=mono, " .
> +            "pan=${layout}:${label}=c0 [ch$i] ;\n";
> +  $concat_in .= "[ch$i] ";
> +}
> +$graph .= "${concat_in}concat=v=0:a=1:n=" . scalar(@channels);
> +
> +exec $ffmpeg, "-f", "lavfi", "-i", $graph, @out_options
> +  or die "$ffmpeg: $!\n";

No more comments, feel free to push with or without the suggested
changes.
-- 
FFmpeg = Fierce & Faithful Mean Ponderous Embarassing Generator


More information about the ffmpeg-devel mailing list