Audio-Mad

 view release on metacpan or  search on metacpan

lib/Audio/Mad/Util.pm  view on Meta::CPAN

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();
			
			$h->{s_samplerate} = $frame->samplerate();
			$h->{s_mode}       = $frame->mode();
			$h->{s_layer}      = $frame->layer();
			$h->{s_flags}      = $frame->flags();
			
			## try to parse a xing header out of the first frame.
			mad_parse_xing($h, substr($buf, $stream->this_frame, $stream->next_frame - $stream->this_frame));

			## if we got a xing header,  xing_flags will always
			## be defined.  next we do some vbr specific setup..
			if (defined($h->{xing_flags})) {
				$h->{s_vbr} = 1;

				## we try to believe the xing header is accurate
				## when possible,  but you can always use f_size
				## to get the true file size (possibly for seeking)
				if ($h->{xing_flags} & 0x0002) {
					$h->{s_size} = $h->{xing_bytes};
				}

				if ($h->{xing_flags} & 0x0001) {
					if ($do_toc) {
						## track that it's a vbr file that had it's own
						## xing header with a frame count,  but we were
						## requested to generate our own anyways..
						$h->{s_vbr} = 3;
					} else {
						## otherwise we just believe what the xing header



( run in 1.080 second using v1.01-cache-2.11-cpan-364913b4093 )