Audio-Mad
view release on metacpan or search on metacpan
lib/Audio/Mad/Util.pm view on Meta::CPAN
package Audio::Mad::Util;
require 5.6.0;
use strict;
use warnings;
use Audio::Mad qw(:all);
use Exporter;
our @ISA = ('Exporter');
our @EXPORT_OK = qw(mad_stream_info mad_parse_xing mad_cbr_seek mad_xing_seek);
our %EXPORT_TAGS = ( all => [@EXPORT_OK] );
sub mad_stream_info {
my ($fh, $do_toc, $do_ex) = @_;
my ($h, $buf) = ({}, '');
$do_toc = 0 unless (defined($do_toc) && $do_toc ne '');
$do_ex = 1 unless (defined($do_ex) && $do_ex ne '');
## fail if file is zero bytes in length
return undef if (($h->{f_size} = (stat($fh))[7]) == 0);
## get a new stream object and turn off crc
## checking, as many encoders are broken
## and it isn't too terribly useful in decoding but
## works nicely for checking stream validity.
## creates a mad_stream structure
my $stream = new Audio::Mad::Stream(MAD_OPTION_IGNORECRC);
## creates a mad_frame structure
my $frame = new Audio::Mad::Frame;
## setup some initial counter type things.
$h->{s_frames} = 0;
$h->{s_vbr} = 0;
## s_size is the size of the stream, and we attempt to
## correct this key for ID3 tags and other extraneous
## data -- in the case of a xing header, we use it's
## size variable if possible..
$h->{s_size} = $h->{f_size};
## create a mad_timer structure
$h->{s_duration} = new Audio::Mad::Timer;
## we use these variables to calaculate a toc strucutre
## when requested by the do_toc argument to this sub,
## it provides an easy index for searching through the
## stream.
my $scale = $h->{s_size} / 100;
my @toc = ();
## to start, we cycle on a frame-by-frame basis..
FRAME: while(1) {
## calls mad_frame_decode, and returns the
## same value (-1 for error);
if ($frame->decode_header($stream) == -1) {
## corresponds to MAD_RECOVERABLE(stream->error),
## if it is recoverable, just skip to the next
## frame.
next FRAME if ($stream->err_ok());
## otherwise, if we get an error due to and
## end of buffer condition (BUFLEN), or because
## the buffer was never set (BUFPTR) take action
## to fill the buffer.
if (
$stream->error == MAD_ERROR_BUFLEN ||
$stream->error == MAD_ERROR_BUFPTR
) {
## this is to capture the frame fragment at
## the end of the buffer, if we don't do this
## we lose the frame.
$buf = substr($buf, $stream->next_frame);
## attempt to read more data onto the end of
## the buffer, we drop out of our loop at
## the end of the file.
last FRAME if (sysread($fh, $buf, 128000, length($buf)) == 0);
## call mad_stream_buffer on the newly created buffer.
$stream->buffer($buf);
## from here, we restart our loop on the frame
## we just failed to decode.
redo FRAME;
}
## otherwise, it's a fatal error that we're not
## prepared to deal with..
return undef;
}
## keep a tally of the frames processed during
## this loop, and evaluate this block only
## during the first frame processed..
unless ($h->{s_frames}++) {
## this is some fairly obvious setup..
$h->{s_bitrate} =
$h->{s_avgrate} = $frame->bitrate();
( run in 2.602 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )