use tag cache
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9734 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
f9bfd73a24
commit
3215ed2e85
2 changed files with 0 additions and 2855 deletions
2123
tools/songdb.pl
2123
tools/songdb.pl
File diff suppressed because it is too large
Load diff
|
@ -1,732 +0,0 @@
|
|||
#############################################################################
|
||||
# This is
|
||||
# http://search.cpan.org/~amolloy/Ogg-Vorbis-Header-PurePerl-0.07/PurePerl.pm
|
||||
# written by Andrew Molloy
|
||||
# Code under GNU GENERAL PUBLIC LICENCE v2
|
||||
# $Id$
|
||||
#############################################################################
|
||||
|
||||
package vorbiscomm;
|
||||
|
||||
use 5.005;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Fcntl qw/SEEK_END/;
|
||||
|
||||
our $VERSION = '0.07';
|
||||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $file = shift;
|
||||
|
||||
return load($class, $file);
|
||||
}
|
||||
|
||||
sub load
|
||||
{
|
||||
my $class = shift;
|
||||
my $file = shift;
|
||||
my $from_new = shift;
|
||||
my %data;
|
||||
my $self;
|
||||
|
||||
# there must be a better way...
|
||||
if ($class eq 'vorbiscomm')
|
||||
{
|
||||
$self = bless \%data, $class;
|
||||
}
|
||||
else
|
||||
{
|
||||
$self = $class;
|
||||
}
|
||||
|
||||
if ($self->{'FILE_LOADED'})
|
||||
{
|
||||
return $self;
|
||||
}
|
||||
|
||||
$self->{'FILE_LOADED'} = 1;
|
||||
|
||||
# check that the file exists and is readable
|
||||
unless ( -e $file && -r _ )
|
||||
{
|
||||
warn "File does not exist or cannot be read.";
|
||||
# file does not exist, can't do anything
|
||||
return undef;
|
||||
}
|
||||
# open up the file
|
||||
open FILE, $file;
|
||||
# make sure dos-type systems can handle it...
|
||||
binmode FILE;
|
||||
|
||||
$data{'filename'} = $file;
|
||||
$data{'fileHandle'} = \*FILE;
|
||||
|
||||
if (_init(\%data)) {
|
||||
_loadInfo(\%data);
|
||||
_loadComments(\%data);
|
||||
_calculateTrackLength(\%data);
|
||||
}
|
||||
|
||||
close FILE;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub info
|
||||
{
|
||||
my $self = shift;
|
||||
my $key = shift;
|
||||
|
||||
# if the user did not supply a key, return the entire hash
|
||||
unless ($key)
|
||||
{
|
||||
return $self->{'INFO'};
|
||||
}
|
||||
|
||||
# otherwise, return the value for the given key
|
||||
return $self->{'INFO'}{lc $key};
|
||||
}
|
||||
|
||||
sub comment_tags
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
if ( $self && $self->{'COMMENT_KEYS'} ) {
|
||||
return @{$self->{'COMMENT_KEYS'}};
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub comment
|
||||
{
|
||||
my $self = shift;
|
||||
my $key = shift;
|
||||
|
||||
# if the user supplied key does not exist, return undef
|
||||
unless($self->{'COMMENTS'}{lc $key})
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
return @{$self->{'COMMENTS'}{lc $key}};
|
||||
}
|
||||
|
||||
sub add_comments
|
||||
{
|
||||
warn "Ogg::Vorbis::Header::PurePerl add_comments() unimplemented.";
|
||||
}
|
||||
|
||||
sub edit_comment
|
||||
{
|
||||
warn "Ogg::Vorbis::Header::PurePerl edit_comment() unimplemented.";
|
||||
}
|
||||
|
||||
sub delete_comment
|
||||
{
|
||||
warn "Ogg::Vorbis::Header::PurePerl delete_comment() unimplemented.";
|
||||
}
|
||||
|
||||
sub clear_comments
|
||||
{
|
||||
warn "Ogg::Vorbis::Header::PurePerl clear_comments() unimplemented.";
|
||||
}
|
||||
|
||||
sub path
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->{'fileName'};
|
||||
}
|
||||
|
||||
sub write_vorbis
|
||||
{
|
||||
warn "Ogg::Vorbis::Header::PurePerl write_vorbis unimplemented.";
|
||||
}
|
||||
|
||||
# "private" methods
|
||||
|
||||
sub _init
|
||||
{
|
||||
my $data = shift;
|
||||
my $fh = $data->{'fileHandle'};
|
||||
my $byteCount = 0;
|
||||
|
||||
# check the header to make sure this is actually an Ogg-Vorbis file
|
||||
$byteCount = _checkHeader($data);
|
||||
|
||||
unless($byteCount)
|
||||
{
|
||||
# if it's not, we can't do anything
|
||||
return undef;
|
||||
}
|
||||
|
||||
$data->{'startInfoHeader'} = $byteCount;
|
||||
return 1; # Success
|
||||
}
|
||||
|
||||
sub _checkHeader
|
||||
{
|
||||
my $data = shift;
|
||||
my $fh = $data->{'fileHandle'};
|
||||
my $buffer;
|
||||
my $pageSegCount;
|
||||
my $byteCount = 0; # stores how far into the file we've read,
|
||||
# so later reads into the file can skip right
|
||||
# past all of the header stuff
|
||||
|
||||
# check that the first four bytes are 'OggS'
|
||||
read($fh, $buffer, 4);
|
||||
if ($buffer ne 'OggS')
|
||||
{
|
||||
warn "This is not an Ogg bitstream (no OggS header).";
|
||||
return undef;
|
||||
}
|
||||
$byteCount += 4;
|
||||
|
||||
# check the stream structure version (1 byte, should be 0x00)
|
||||
read($fh, $buffer, 1);
|
||||
if (ord($buffer) != 0x00)
|
||||
{
|
||||
warn "This is not an Ogg bitstream (invalid structure version).";
|
||||
return undef;
|
||||
}
|
||||
$byteCount += 1;
|
||||
|
||||
# check the header type flag
|
||||
# This is a bitfield, so technically we should check all of the bits
|
||||
# that could potentially be set. However, the only value this should
|
||||
# possibly have at the beginning of a proper Ogg-Vorbis file is 0x02,
|
||||
# so we just check for that. If it's not that, we go on anyway, but
|
||||
# give a warning (this behavior may (should?) be modified in the future.
|
||||
read($fh, $buffer, 1);
|
||||
if (ord($buffer) != 0x02)
|
||||
{
|
||||
warn "Invalid header type flag (trying to go ahead anyway).";
|
||||
}
|
||||
$byteCount += 1;
|
||||
|
||||
# skip to the page_segments count
|
||||
read($fh, $buffer, 20);
|
||||
$byteCount += 20;
|
||||
# we do nothing with this data
|
||||
|
||||
# read the number of page segments
|
||||
read($fh, $buffer, 1);
|
||||
$pageSegCount = ord($buffer);
|
||||
$byteCount += 1;
|
||||
|
||||
# read $pageSegCount bytes, then throw 'em out
|
||||
read($fh, $buffer, $pageSegCount);
|
||||
$byteCount += $pageSegCount;
|
||||
|
||||
# check packet type. Should be 0x01 (for indentification header)
|
||||
read($fh, $buffer, 1);
|
||||
if (ord($buffer) != 0x01)
|
||||
{
|
||||
warn "Wrong vorbis header type, giving up.";
|
||||
return undef;
|
||||
}
|
||||
$byteCount += 1;
|
||||
|
||||
# check that the packet identifies itself as 'vorbis'
|
||||
read($fh, $buffer, 6);
|
||||
if ($buffer ne 'vorbis')
|
||||
{
|
||||
warn "This does not appear to be a vorbis stream, giving up.";
|
||||
return undef;
|
||||
}
|
||||
$byteCount += 6;
|
||||
|
||||
# at this point, we assume the bitstream is valid
|
||||
return $byteCount;
|
||||
}
|
||||
|
||||
sub _loadInfo
|
||||
{
|
||||
my $data = shift;
|
||||
my $start = $data->{'startInfoHeader'};
|
||||
my $fh = $data->{'fileHandle'};
|
||||
my $buffer;
|
||||
my $byteCount = $start;
|
||||
my %info;
|
||||
|
||||
seek $fh, $start, 0;
|
||||
|
||||
# read the vorbis version
|
||||
read($fh, $buffer, 4);
|
||||
$info{'version'} = _decodeInt($buffer);
|
||||
$byteCount += 4;
|
||||
|
||||
# read the number of audio channels
|
||||
read($fh, $buffer, 1);
|
||||
$info{'channels'} = ord($buffer);
|
||||
$byteCount += 1;
|
||||
|
||||
# read the sample rate
|
||||
read($fh, $buffer, 4);
|
||||
$info{'rate'} = _decodeInt($buffer);
|
||||
$byteCount += 4;
|
||||
|
||||
# read the bitrate maximum
|
||||
read($fh, $buffer, 4);
|
||||
$info{'bitrate_upper'} = _decodeInt($buffer);
|
||||
$byteCount += 4;
|
||||
|
||||
# read the bitrate nominal
|
||||
read($fh, $buffer, 4);
|
||||
$info{'bitrate_nominal'} = _decodeInt($buffer);
|
||||
$byteCount += 4;
|
||||
|
||||
# read the bitrate minimal
|
||||
read($fh, $buffer, 4);
|
||||
$info{'bitrate_lower'} = _decodeInt($buffer);
|
||||
$byteCount += 4;
|
||||
|
||||
# read the blocksize_0 and blocksize_1
|
||||
read($fh, $buffer, 1);
|
||||
# these are each 4 bit fields, whose actual value is 2 to the power
|
||||
# of the value of the field
|
||||
$info{'blocksize_0'} = 2 << ((ord($buffer) & 0xF0) >> 4);
|
||||
$info{'blocksize_1'} = 2 << (ord($buffer) & 0x0F);
|
||||
$byteCount += 1;
|
||||
|
||||
# read the framing_flag
|
||||
read($fh, $buffer, 1);
|
||||
$info{'framing_flag'} = ord($buffer);
|
||||
$byteCount += 1;
|
||||
|
||||
# bitrate_window is -1 in the current version of vorbisfile
|
||||
$info{'bitrate_window'} = -1;
|
||||
|
||||
$data->{'startCommentHeader'} = $byteCount;
|
||||
|
||||
$data->{'INFO'} = \%info;
|
||||
}
|
||||
|
||||
sub _loadComments
|
||||
{
|
||||
my $data = shift;
|
||||
my $fh = $data->{'fileHandle'};
|
||||
my $start = $data->{'startCommentHeader'};
|
||||
my $buffer;
|
||||
my $page_segments;
|
||||
my $vendor_length;
|
||||
my $user_comment_count;
|
||||
my $byteCount = $start;
|
||||
my %comments;
|
||||
|
||||
seek $fh, $start, 0;
|
||||
|
||||
# check that the first four bytes are 'OggS'
|
||||
read($fh, $buffer, 4);
|
||||
if ($buffer ne 'OggS')
|
||||
{
|
||||
warn "No comment header?";
|
||||
return undef;
|
||||
}
|
||||
$byteCount += 4;
|
||||
|
||||
# skip over next ten bytes
|
||||
read($fh, $buffer, 10);
|
||||
$byteCount += 10;
|
||||
|
||||
# read the stream serial number
|
||||
read($fh, $buffer, 4);
|
||||
push @{$data->{'commentSerialNumber'}}, _decodeInt($buffer);
|
||||
$byteCount += 4;
|
||||
|
||||
# read the page sequence number (should be 0x01)
|
||||
read($fh, $buffer, 4);
|
||||
if (_decodeInt($buffer) != 0x01)
|
||||
{
|
||||
warn "Comment header page sequence number is not 0x01: " +
|
||||
_decodeInt($buffer);
|
||||
warn "Going to keep going anyway.";
|
||||
}
|
||||
$byteCount += 4;
|
||||
|
||||
# and ignore the page checksum for now
|
||||
read($fh, $buffer, 4);
|
||||
$byteCount += 4;
|
||||
|
||||
# get the number of entries in the segment_table...
|
||||
read($fh, $buffer, 1);
|
||||
$page_segments = _decodeInt($buffer);
|
||||
$byteCount += 1;
|
||||
# then skip on past it
|
||||
read($fh, $buffer, $page_segments);
|
||||
$byteCount += $page_segments;
|
||||
|
||||
# check the header type (should be 0x03)
|
||||
read($fh, $buffer, 1);
|
||||
if (ord($buffer) != 0x03)
|
||||
{
|
||||
warn "Wrong header type: " . ord($buffer);
|
||||
}
|
||||
$byteCount += 1;
|
||||
|
||||
# now we should see 'vorbis'
|
||||
read($fh, $buffer, 6);
|
||||
if ($buffer ne 'vorbis')
|
||||
{
|
||||
warn "Missing comment header. Should have found 'vorbis', found " .
|
||||
$buffer;
|
||||
}
|
||||
$byteCount += 6;
|
||||
|
||||
# get the vendor length
|
||||
read($fh, $buffer, 4);
|
||||
$vendor_length = _decodeInt($buffer);
|
||||
$byteCount += 4;
|
||||
|
||||
# read in the vendor
|
||||
read($fh, $buffer, $vendor_length);
|
||||
$comments{'vendor'} = $buffer;
|
||||
$byteCount += $vendor_length;
|
||||
|
||||
# read in the number of user comments
|
||||
read($fh, $buffer, 4);
|
||||
$user_comment_count = _decodeInt($buffer);
|
||||
$byteCount += 4;
|
||||
|
||||
$data->{'COMMENT_KEYS'} = [];
|
||||
|
||||
# finally, read the comments
|
||||
for (my $i = 0; $i < $user_comment_count; $i++)
|
||||
{
|
||||
# first read the length
|
||||
read($fh, $buffer, 4);
|
||||
my $comment_length = _decodeInt($buffer);
|
||||
$byteCount += 4;
|
||||
|
||||
# then the comment itself
|
||||
read($fh, $buffer, $comment_length);
|
||||
$byteCount += $comment_length;
|
||||
|
||||
my ($key) = $buffer =~ /^([^=]+)/;
|
||||
my ($value) = $buffer =~ /=(.*)$/;
|
||||
|
||||
push @{$comments{lc $key}}, $value;
|
||||
push @{$data->{'COMMENT_KEYS'}}, lc $key;
|
||||
}
|
||||
|
||||
# read past the framing_bit
|
||||
read($fh, $buffer, 1);
|
||||
$byteCount += 1;
|
||||
|
||||
$data->{'INFO'}{'offset'} = $byteCount;
|
||||
|
||||
$data->{'COMMENTS'} = \%comments;
|
||||
|
||||
# Now find the offset of the first page
|
||||
# with audio data.
|
||||
while(_findPage($fh))
|
||||
{
|
||||
$byteCount = tell($fh) - 4;
|
||||
|
||||
# version flag
|
||||
read($fh, $buffer, 1);
|
||||
if (ord($buffer) != 0x00)
|
||||
{
|
||||
warn "Invalid stream structure version: " .
|
||||
sprintf("%x", ord($buffer));
|
||||
return;
|
||||
}
|
||||
|
||||
# header type flag
|
||||
read($fh, $buffer, 1);
|
||||
# Audio data starts as a fresh packet on a new page, so
|
||||
# if header_type is odd it's not a fresh packet
|
||||
next if ( ord($buffer) % 2 );
|
||||
|
||||
# skip past granule position, stream_serial_number,
|
||||
# page_sequence_number, and crc
|
||||
read($fh, $buffer, 20);
|
||||
|
||||
# page_segments
|
||||
read($fh, $buffer, 1);
|
||||
my $page_segments = ord($buffer);
|
||||
|
||||
# skip past the segment table
|
||||
read($fh, $buffer, $page_segments);
|
||||
|
||||
# read packet_type byte
|
||||
read($fh, $buffer, 1);
|
||||
|
||||
# Not an audio packet. All audio packet numbers are even
|
||||
next if ( ord($buffer) % 2 );
|
||||
|
||||
# Found the first audio packet
|
||||
last;
|
||||
}
|
||||
|
||||
$data->{'INFO'}{'audio_offset'} = $byteCount;
|
||||
}
|
||||
|
||||
sub _calculateTrackLength
|
||||
{
|
||||
my $data = shift;
|
||||
my $fh = $data->{'fileHandle'};
|
||||
my $buffer;
|
||||
my $pageSize;
|
||||
my $granule_position;
|
||||
|
||||
seek($fh,-8500,SEEK_END); # that magic number is from vorbisfile.c
|
||||
# in the constant CHUNKSIZE, which comes
|
||||
# with the comment /* a shade over 8k;
|
||||
# anyone using pages well over 8k gets
|
||||
# what they deserve */
|
||||
|
||||
# we just keep looking through the headers until we get to the last one
|
||||
# (there might be a couple of blocks here)
|
||||
while(_findPage($fh))
|
||||
{
|
||||
# stream structure version - must be 0x00
|
||||
read($fh, $buffer, 1);
|
||||
if (ord($buffer) != 0x00)
|
||||
{
|
||||
warn "Invalid stream structure version: " .
|
||||
sprintf("%x", ord($buffer));
|
||||
return;
|
||||
}
|
||||
|
||||
# header type flag
|
||||
read($fh, $buffer, 1);
|
||||
# we should check this, but for now we'll just ignore it
|
||||
|
||||
# absolute granule position - this is what we need!
|
||||
read($fh, $buffer, 8);
|
||||
$granule_position = _decodeInt($buffer);
|
||||
|
||||
# skip past stream_serial_number, page_sequence_number, and crc
|
||||
read($fh, $buffer, 12);
|
||||
|
||||
# page_segments
|
||||
read($fh, $buffer, 1);
|
||||
my $page_segments = ord($buffer);
|
||||
|
||||
# reset pageSize
|
||||
$pageSize = 0;
|
||||
|
||||
# calculate approx. page size
|
||||
for (my $i = 0; $i < $page_segments; $i++)
|
||||
{
|
||||
read($fh, $buffer, 1);
|
||||
$pageSize += ord($buffer);
|
||||
}
|
||||
|
||||
seek $fh, $pageSize, 1;
|
||||
}
|
||||
|
||||
$data->{'INFO'}{'length'} =
|
||||
int($granule_position / $data->{'INFO'}{'rate'});
|
||||
}
|
||||
|
||||
sub _findPage
|
||||
{
|
||||
# search forward in the file for the 'OggS' page header
|
||||
my $fh = shift;
|
||||
my $char;
|
||||
my $curStr = '';
|
||||
|
||||
while (read($fh, $char, 1))
|
||||
{
|
||||
$curStr = $char . $curStr;
|
||||
$curStr = substr($curStr, 0, 4);
|
||||
|
||||
# we are actually looking for the string 'SggO' because we
|
||||
# tack character on to our test string backwards, to make
|
||||
# trimming it to 4 characters easier.
|
||||
if ($curStr eq 'SggO')
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub _decodeInt
|
||||
{
|
||||
my $bytes = shift;
|
||||
my $num = 0;
|
||||
my @byteList = split //, $bytes;
|
||||
my $numBytes = @byteList;
|
||||
my $mult = 1;
|
||||
|
||||
for (my $i = 0; $i < $numBytes; $i ++)
|
||||
{
|
||||
$num += ord($byteList[$i]) * $mult;
|
||||
$mult *= 256;
|
||||
}
|
||||
|
||||
return $num;
|
||||
}
|
||||
|
||||
sub _decodeInt5Bit
|
||||
{
|
||||
my $byte = ord(shift);
|
||||
|
||||
$byte = $byte & 0xF8; # clear out the bottm 3 bits
|
||||
$byte = $byte >> 3; # and shifted down to where it belongs
|
||||
|
||||
return $byte;
|
||||
}
|
||||
|
||||
sub _decodeInt4Bit
|
||||
{
|
||||
my $byte = ord(shift);
|
||||
|
||||
$byte = $byte & 0xFC; # clear out the bottm 4 bits
|
||||
$byte = $byte >> 4; # and shifted down to where it belongs
|
||||
|
||||
return $byte;
|
||||
}
|
||||
|
||||
sub _ilog
|
||||
{
|
||||
my $x = shift;
|
||||
my $ret = 0;
|
||||
|
||||
unless ($x > 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ($x > 0)
|
||||
{
|
||||
$ret++;
|
||||
$x = $x >> 1;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
1;
|
||||
__DATA__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Ogg::Vorbis::Header::PurePerl - An object-oriented interface to Ogg Vorbis
|
||||
information and comment fields, implemented entirely in Perl. Intended to be
|
||||
a drop in replacement for Ogg::Vobis::Header.
|
||||
|
||||
Unlike Ogg::Vorbis::Header, this module will go ahead and fill in all of the
|
||||
information fields as soon as you construct the object. In other words,
|
||||
the C<new> and C<load> constructors have identical behavior.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Ogg::Vorbis::Header::PurePerl;
|
||||
my $ogg = Ogg::Vorbis::Header::PurePerl->new("song.ogg");
|
||||
while (my ($k, $v) = each %{$ogg->info}) {
|
||||
print "$k: $v\n";
|
||||
}
|
||||
foreach my $com ($ogg->comment_tags) {
|
||||
print "$com: $_\n" foreach $ogg->comment($com);
|
||||
}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module is intended to be a drop in replacement for Ogg::Vorbis::Header,
|
||||
implemented entirely in Perl. It provides an object-oriented interface to
|
||||
Ogg Vorbis information and comment fields. (NOTE: This module currently
|
||||
supports only read operations).
|
||||
|
||||
=head1 CONSTRUCTORS
|
||||
|
||||
=head2 C<new ($filename)>
|
||||
|
||||
Opens an Ogg Vorbis file, ensuring that it exists and is actually an
|
||||
Ogg Vorbis stream. This method does not actually read any of the
|
||||
information or comment fields, and closes the file immediately.
|
||||
|
||||
=head2 C<load ([$filename])>
|
||||
|
||||
Opens an Ogg Vorbis file, ensuring that it exists and is actually an
|
||||
Ogg Vorbis stream, then loads the information and comment fields. This
|
||||
method can also be used without a filename to load the information
|
||||
and fields of an already constructed instance.
|
||||
|
||||
=head1 INSTANCE METHODS
|
||||
|
||||
=head2 C<info ([$key])>
|
||||
|
||||
Returns a hashref containing information about the Ogg Vorbis file from
|
||||
the file's information header. Hash fields are: version, channels, rate,
|
||||
bitrate_upper, bitrate_nominal, bitrate_lower, bitrate_window, and length.
|
||||
The bitrate_window value is not currently used by the vorbis codec, and
|
||||
will always be -1.
|
||||
|
||||
The optional parameter, key, allows you to retrieve a single value from
|
||||
the object's hash. Returns C<undef> if the key is not found.
|
||||
|
||||
=head2 C<comment_tags ()>
|
||||
|
||||
Returns an array containing the key values for the comment fields.
|
||||
These values can then be passed to C<comment> to retrieve their values.
|
||||
|
||||
=head2 C<comment ($key)>
|
||||
|
||||
Returns an array of comment values associated with the given key.
|
||||
|
||||
=head2 C<add_comments ($key, $value, [$key, $value, ...])>
|
||||
|
||||
Unimplemented.
|
||||
|
||||
=head2 C<edit_comment ($key, $value, [$num])>
|
||||
|
||||
Unimplemented.
|
||||
|
||||
=head2 C<delete_comment ($key, [$num])>
|
||||
|
||||
Unimplemented.
|
||||
|
||||
=head2 C<clear_comments ([@keys])>
|
||||
|
||||
Unimplemented.
|
||||
|
||||
=head2 C<write_vorbis ()>
|
||||
|
||||
Unimplemented.
|
||||
|
||||
=head2 C<path ()>
|
||||
|
||||
Returns the path/filename of the file the object represents.
|
||||
|
||||
=head1 NOTE
|
||||
|
||||
This is ALPHA SOFTWARE. It may very well be very broken. Do not use it in
|
||||
a production environment. You have been warned.
|
||||
|
||||
=head1 ACKNOWLEDGEMENTS
|
||||
|
||||
Dave Brown <cpan@dagbrown.com> made this module significantly faster
|
||||
at calculating the length of ogg files.
|
||||
|
||||
Robert Moser II <rlmoser@earthlink.net> fixed a problem with files that
|
||||
have no comments.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Andrew Molloy E<lt>amolloy@kaizolabs.comE<gt>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (c) 2003, Andrew Molloy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version. A copy of this license is included
|
||||
with this module (LICENSE.GPL).
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Ogg::Vorbis::Header>, L<Ogg::Vorbis::Decoder>
|
||||
|
||||
=cut
|
Loading…
Reference in a new issue