Archive
Parallel errors
I wanted to know how long I have to wait for ffmpeg to turn *
into AV1. To do so I have to capture STDERR because that’s where ffmpeg outputs the status information while encoding.
my $ffmpeg-out = Channel.new;
my $ffmpeg-err = Channel.new;
react {
whenever $ffmpeg-err -> [ $stream-num, $_ ] {
.say if $verbose;
# boring parsing code goes here
}
}
px{'nice', '/usr/local/bin/ffmpeg', '-i', $input, '-c:v', 'libsvtav1', '-q', '60', '-preset', '5', '-y', $output} |» $ffmpeg-out :stderr($ffmpeg-err);
The solution is quite simple. I use a Channel
to transport lines of text from STDERR to a react block that does the parsing. A nice solution until ffmpeg decides to use STDERR to actually communicate error messages. Those will be gobbled up by the parsing code. As a result the exception that is thrown out of Shell::Piping
has no error message to display, beside that a non-zero error code has been returned.
There are quite a few programs that output status to STDERR while operating, so a general approach would be nice. Where messages land is controlled by the adverb :stderr
. To capture text to be displayed in the exception is done with :stderr(Capture)
. So my first impulse was to use a mixin like :stderr($ffmpeg-err but Capture)
. This would allow me to solve this problem. More complex solutions would be desirable. A user of my module might want to parse STDERR and write everything to a file. Both are currently possible but not at the same time. Providing a list of stream targets would imply order. I’m not sure if I can guarantee that. In the case of multiple channels it would not make sense for sure. In Raku we do have a parallel data type called Junction
. In its current form it is not possible to pull a Junction
apart. A pull request by lizmat to change that did not find a large fellowship. Luckily she also wrote a module called eigenstates
.
use eigenstates;
sub prefix:<\foo> (Str $_, Junction :$err = all Whatever) {
say $_;
say eigenstates $err;
}
\foo "ello" :err(1|2);
# OUTPUT: ello
(1 2)
This allows me to do :stderr($ffmpeg-err & Capture)
and many more complex operations. For now I don’t see a use in the type of Junction
beside all
. Since there are still 95 years left in Rakus life cycle, I’m quite sure something will come along.