1 | package Ogg::Vorbis::Header::PurePerl;
|
---|
2 |
|
---|
3 | use 5.005;
|
---|
4 | use strict;
|
---|
5 | use warnings;
|
---|
6 |
|
---|
7 | use Fcntl qw/SEEK_END/;
|
---|
8 |
|
---|
9 | our $VERSION = '0.07';
|
---|
10 |
|
---|
11 | sub new
|
---|
12 | {
|
---|
13 | my $class = shift;
|
---|
14 | my $file = shift;
|
---|
15 |
|
---|
16 | return load($class, $file);
|
---|
17 | }
|
---|
18 |
|
---|
19 | sub load
|
---|
20 | {
|
---|
21 | my $class = shift;
|
---|
22 | my $file = shift;
|
---|
23 | my $from_new = shift;
|
---|
24 | my %data;
|
---|
25 | my $self;
|
---|
26 |
|
---|
27 | # there must be a better way...
|
---|
28 | if ($class eq 'Ogg::Vorbis::Header::PurePerl')
|
---|
29 | {
|
---|
30 | $self = bless \%data, $class;
|
---|
31 | }
|
---|
32 | else
|
---|
33 | {
|
---|
34 | $self = $class;
|
---|
35 | }
|
---|
36 |
|
---|
37 | if ($self->{'FILE_LOADED'})
|
---|
38 | {
|
---|
39 | return $self;
|
---|
40 | }
|
---|
41 |
|
---|
42 | $self->{'FILE_LOADED'} = 1;
|
---|
43 |
|
---|
44 | # check that the file exists and is readable
|
---|
45 | unless ( -e $file && -r _ )
|
---|
46 | {
|
---|
47 | warn "File does not exist or cannot be read.";
|
---|
48 | # file does not exist, can't do anything
|
---|
49 | return undef;
|
---|
50 | }
|
---|
51 | # open up the file
|
---|
52 | open FILE, $file;
|
---|
53 | # make sure dos-type systems can handle it...
|
---|
54 | binmode FILE;
|
---|
55 |
|
---|
56 | $data{'filename'} = $file;
|
---|
57 | $data{'fileHandle'} = \*FILE;
|
---|
58 |
|
---|
59 | _init(\%data);
|
---|
60 | _loadInfo(\%data);
|
---|
61 | _loadComments(\%data);
|
---|
62 | _calculateTrackLength(\%data);
|
---|
63 |
|
---|
64 | close FILE;
|
---|
65 |
|
---|
66 | return $self;
|
---|
67 | }
|
---|
68 |
|
---|
69 | sub info
|
---|
70 | {
|
---|
71 | my $self = shift;
|
---|
72 | my $key = shift;
|
---|
73 |
|
---|
74 | # if the user did not supply a key, return the entire hash
|
---|
75 | unless ($key)
|
---|
76 | {
|
---|
77 | return $self->{'INFO'};
|
---|
78 | }
|
---|
79 |
|
---|
80 | # otherwise, return the value for the given key
|
---|
81 | return $self->{'INFO'}{lc $key};
|
---|
82 | }
|
---|
83 |
|
---|
84 | sub comment_tags
|
---|
85 | {
|
---|
86 | my $self = shift;
|
---|
87 |
|
---|
88 | return @{$self->{'COMMENT_KEYS'}};
|
---|
89 | }
|
---|
90 |
|
---|
91 | sub comment
|
---|
92 | {
|
---|
93 | my $self = shift;
|
---|
94 | my $key = shift;
|
---|
95 |
|
---|
96 | # if the user supplied key does not exist, return undef
|
---|
97 | unless($self->{'COMMENTS'}{lc $key})
|
---|
98 | {
|
---|
99 | return undef;
|
---|
100 | }
|
---|
101 |
|
---|
102 | return @{$self->{'COMMENTS'}{lc $key}};
|
---|
103 | }
|
---|
104 |
|
---|
105 | sub add_comments
|
---|
106 | {
|
---|
107 | warn "Ogg::Vorbis::Header::PurePerl add_comments() unimplemented.";
|
---|
108 | }
|
---|
109 |
|
---|
110 | sub edit_comment
|
---|
111 | {
|
---|
112 | warn "Ogg::Vorbis::Header::PurePerl edit_comment() unimplemented.";
|
---|
113 | }
|
---|
114 |
|
---|
115 | sub delete_comment
|
---|
116 | {
|
---|
117 | warn "Ogg::Vorbis::Header::PurePerl delete_comment() unimplemented.";
|
---|
118 | }
|
---|
119 |
|
---|
120 | sub clear_comments
|
---|
121 | {
|
---|
122 | warn "Ogg::Vorbis::Header::PurePerl clear_comments() unimplemented.";
|
---|
123 | }
|
---|
124 |
|
---|
125 | sub path
|
---|
126 | {
|
---|
127 | my $self = shift;
|
---|
128 |
|
---|
129 | return $self->{'fileName'};
|
---|
130 | }
|
---|
131 |
|
---|
132 | sub write_vorbis
|
---|
133 | {
|
---|
134 | warn "Ogg::Vorbis::Header::PurePerl write_vorbis unimplemented.";
|
---|
135 | }
|
---|
136 |
|
---|
137 | # "private" methods
|
---|
138 |
|
---|
139 | sub _init
|
---|
140 | {
|
---|
141 | my $data = shift;
|
---|
142 | my $fh = $data->{'fileHandle'};
|
---|
143 | my $byteCount = 0;
|
---|
144 |
|
---|
145 | # check the header to make sure this is actually an Ogg-Vorbis file
|
---|
146 | $byteCount = _checkHeader($data);
|
---|
147 |
|
---|
148 | unless($byteCount)
|
---|
149 | {
|
---|
150 | # if it's not, we can't do anything
|
---|
151 | return undef;
|
---|
152 | }
|
---|
153 |
|
---|
154 | $data->{'startInfoHeader'} = $byteCount;
|
---|
155 | }
|
---|
156 |
|
---|
157 | sub _checkHeader
|
---|
158 | {
|
---|
159 | my $data = shift;
|
---|
160 | my $fh = $data->{'fileHandle'};
|
---|
161 | my $buffer;
|
---|
162 | my $pageSegCount;
|
---|
163 | my $byteCount = 0; # stores how far into the file we've read,
|
---|
164 | # so later reads into the file can skip right
|
---|
165 | # past all of the header stuff
|
---|
166 |
|
---|
167 | # check that the first four bytes are 'OggS'
|
---|
168 | read($fh, $buffer, 4);
|
---|
169 | if ($buffer ne 'OggS')
|
---|
170 | {
|
---|
171 | warn "This is not an Ogg bitstream (no OggS header).";
|
---|
172 | return undef;
|
---|
173 | }
|
---|
174 | $byteCount += 4;
|
---|
175 |
|
---|
176 | # check the stream structure version (1 byte, should be 0x00)
|
---|
177 | read($fh, $buffer, 1);
|
---|
178 | if (ord($buffer) != 0x00)
|
---|
179 | {
|
---|
180 | warn "This is not an Ogg bitstream (invalid structure version).";
|
---|
181 | return undef;
|
---|
182 | }
|
---|
183 | $byteCount += 1;
|
---|
184 |
|
---|
185 | # check the header type flag
|
---|
186 | # This is a bitfield, so technically we should check all of the bits
|
---|
187 | # that could potentially be set. However, the only value this should
|
---|
188 | # possibly have at the beginning of a proper Ogg-Vorbis file is 0x02,
|
---|
189 | # so we just check for that. If it's not that, we go on anyway, but
|
---|
190 | # give a warning (this behavior may (should?) be modified in the future.
|
---|
191 | read($fh, $buffer, 1);
|
---|
192 | if (ord($buffer) != 0x02)
|
---|
193 | {
|
---|
194 | warn "Invalid header type flag (trying to go ahead anyway).";
|
---|
195 | }
|
---|
196 | $byteCount += 1;
|
---|
197 |
|
---|
198 | # skip to the page_segments count
|
---|
199 | read($fh, $buffer, 20);
|
---|
200 | $byteCount += 20;
|
---|
201 | # we do nothing with this data
|
---|
202 |
|
---|
203 | # read the number of page segments
|
---|
204 | read($fh, $buffer, 1);
|
---|
205 | $pageSegCount = ord($buffer);
|
---|
206 | $byteCount += 1;
|
---|
207 |
|
---|
208 | # read $pageSegCount bytes, then throw 'em out
|
---|
209 | read($fh, $buffer, $pageSegCount);
|
---|
210 | $byteCount += $pageSegCount;
|
---|
211 |
|
---|
212 | # check packet type. Should be 0x01 (for indentification header)
|
---|
213 | read($fh, $buffer, 1);
|
---|
214 | if (ord($buffer) != 0x01)
|
---|
215 | {
|
---|
216 | warn "Wrong vorbis header type, giving up.";
|
---|
217 | return undef;
|
---|
218 | }
|
---|
219 | $byteCount += 1;
|
---|
220 |
|
---|
221 | # check that the packet identifies itself as 'vorbis'
|
---|
222 | read($fh, $buffer, 6);
|
---|
223 | if ($buffer ne 'vorbis')
|
---|
224 | {
|
---|
225 | warn "This does not appear to be a vorbis stream, giving up.";
|
---|
226 | return undef;
|
---|
227 | }
|
---|
228 | $byteCount += 6;
|
---|
229 |
|
---|
230 | # at this point, we assume the bitstream is valid
|
---|
231 | return $byteCount;
|
---|
232 | }
|
---|
233 |
|
---|
234 | sub _loadInfo
|
---|
235 | {
|
---|
236 | my $data = shift;
|
---|
237 | my $start = $data->{'startInfoHeader'};
|
---|
238 | my $fh = $data->{'fileHandle'};
|
---|
239 | my $buffer;
|
---|
240 | my $byteCount = $start;
|
---|
241 | my %info;
|
---|
242 |
|
---|
243 | seek $fh, $start, 0;
|
---|
244 |
|
---|
245 | # read the vorbis version
|
---|
246 | read($fh, $buffer, 4);
|
---|
247 | $info{'version'} = _decodeInt($buffer);
|
---|
248 | $byteCount += 4;
|
---|
249 |
|
---|
250 | # read the number of audio channels
|
---|
251 | read($fh, $buffer, 1);
|
---|
252 | $info{'channels'} = ord($buffer);
|
---|
253 | $byteCount += 1;
|
---|
254 |
|
---|
255 | # read the sample rate
|
---|
256 | read($fh, $buffer, 4);
|
---|
257 | $info{'rate'} = _decodeInt($buffer);
|
---|
258 | $byteCount += 4;
|
---|
259 |
|
---|
260 | # read the bitrate maximum
|
---|
261 | read($fh, $buffer, 4);
|
---|
262 | $info{'bitrate_upper'} = _decodeInt($buffer);
|
---|
263 | $byteCount += 4;
|
---|
264 |
|
---|
265 | # read the bitrate nominal
|
---|
266 | read($fh, $buffer, 4);
|
---|
267 | $info{'bitrate_nominal'} = _decodeInt($buffer);
|
---|
268 | $byteCount += 4;
|
---|
269 |
|
---|
270 | # read the bitrate minimal
|
---|
271 | read($fh, $buffer, 4);
|
---|
272 | $info{'bitrate_lower'} = _decodeInt($buffer);
|
---|
273 | $byteCount += 4;
|
---|
274 |
|
---|
275 | # read the blocksize_0 and blocksize_1
|
---|
276 | read($fh, $buffer, 1);
|
---|
277 | # these are each 4 bit fields, whose actual value is 2 to the power
|
---|
278 | # of the value of the field
|
---|
279 | $info{'blocksize_0'} = 2 << ((ord($buffer) & 0xF0) >> 4);
|
---|
280 | $info{'blocksize_1'} = 2 << (ord($buffer) & 0x0F);
|
---|
281 | $byteCount += 1;
|
---|
282 |
|
---|
283 | # read the framing_flag
|
---|
284 | read($fh, $buffer, 1);
|
---|
285 | $info{'framing_flag'} = ord($buffer);
|
---|
286 | $byteCount += 1;
|
---|
287 |
|
---|
288 | # bitrate_window is -1 in the current version of vorbisfile
|
---|
289 | $info{'bitrate_window'} = -1;
|
---|
290 |
|
---|
291 | $data->{'startCommentHeader'} = $byteCount;
|
---|
292 |
|
---|
293 | $data->{'INFO'} = \%info;
|
---|
294 | }
|
---|
295 |
|
---|
296 | sub _loadComments
|
---|
297 | {
|
---|
298 | my $data = shift;
|
---|
299 | my $fh = $data->{'fileHandle'};
|
---|
300 | my $start = $data->{'startCommentHeader'};
|
---|
301 | my $buffer;
|
---|
302 | my $page_segments;
|
---|
303 | my $vendor_length;
|
---|
304 | my $user_comment_count;
|
---|
305 | my $byteCount = $start;
|
---|
306 | my %comments;
|
---|
307 |
|
---|
308 | seek $fh, $start, 0;
|
---|
309 |
|
---|
310 | # check that the first four bytes are 'OggS'
|
---|
311 | read($fh, $buffer, 4);
|
---|
312 | if ($buffer ne 'OggS')
|
---|
313 | {
|
---|
314 | warn "No comment header?";
|
---|
315 | return undef;
|
---|
316 | }
|
---|
317 | $byteCount += 4;
|
---|
318 |
|
---|
319 | # skip over next ten bytes
|
---|
320 | read($fh, $buffer, 10);
|
---|
321 | $byteCount += 10;
|
---|
322 |
|
---|
323 | # read the stream serial number
|
---|
324 | read($fh, $buffer, 4);
|
---|
325 | push @{$data->{'commentSerialNumber'}}, _decodeInt($buffer);
|
---|
326 | $byteCount += 4;
|
---|
327 |
|
---|
328 | # read the page sequence number (should be 0x01)
|
---|
329 | read($fh, $buffer, 4);
|
---|
330 | if (_decodeInt($buffer) != 0x01)
|
---|
331 | {
|
---|
332 | warn "Comment header page sequence number is not 0x01: " +
|
---|
333 | _decodeInt($buffer);
|
---|
334 | warn "Going to keep going anyway.";
|
---|
335 | }
|
---|
336 | $byteCount += 4;
|
---|
337 |
|
---|
338 | # and ignore the page checksum for now
|
---|
339 | read($fh, $buffer, 4);
|
---|
340 | $byteCount += 4;
|
---|
341 |
|
---|
342 | # get the number of entries in the segment_table...
|
---|
343 | read($fh, $buffer, 1);
|
---|
344 | $page_segments = _decodeInt($buffer);
|
---|
345 | $byteCount += 1;
|
---|
346 | # then skip on past it
|
---|
347 | read($fh, $buffer, $page_segments);
|
---|
348 | $byteCount += $page_segments;
|
---|
349 |
|
---|
350 | # check the header type (should be 0x03)
|
---|
351 | read($fh, $buffer, 1);
|
---|
352 | if (ord($buffer) != 0x03)
|
---|
353 | {
|
---|
354 | warn "Wrong header type: " . ord($buffer);
|
---|
355 | }
|
---|
356 | $byteCount += 1;
|
---|
357 |
|
---|
358 | # now we should see 'vorbis'
|
---|
359 | read($fh, $buffer, 6);
|
---|
360 | if ($buffer ne 'vorbis')
|
---|
361 | {
|
---|
362 | warn "Missing comment header. Should have found 'vorbis', found " .
|
---|
363 | $buffer;
|
---|
364 | }
|
---|
365 | $byteCount += 6;
|
---|
366 |
|
---|
367 | # get the vendor length
|
---|
368 | read($fh, $buffer, 4);
|
---|
369 | $vendor_length = _decodeInt($buffer);
|
---|
370 | $byteCount += 4;
|
---|
371 |
|
---|
372 | # read in the vendor
|
---|
373 | read($fh, $buffer, $vendor_length);
|
---|
374 | $comments{'vendor'} = $buffer;
|
---|
375 | $byteCount += $vendor_length;
|
---|
376 |
|
---|
377 | # read in the number of user comments
|
---|
378 | read($fh, $buffer, 4);
|
---|
379 | $user_comment_count = _decodeInt($buffer);
|
---|
380 | $byteCount += 4;
|
---|
381 |
|
---|
382 | $data->{'COMMENT_KEYS'} = [];
|
---|
383 |
|
---|
384 | # finally, read the comments
|
---|
385 | for (my $i = 0; $i < $user_comment_count; $i++)
|
---|
386 | {
|
---|
387 | # first read the length
|
---|
388 | read($fh, $buffer, 4);
|
---|
389 | my $comment_length = _decodeInt($buffer);
|
---|
390 | $byteCount += 4;
|
---|
391 |
|
---|
392 | # then the comment itself
|
---|
393 | read($fh, $buffer, $comment_length);
|
---|
394 | $byteCount += $comment_length;
|
---|
395 |
|
---|
396 | my ($key) = $buffer =~ /^([^=]+)/;
|
---|
397 | my ($value) = $buffer =~ /=(.*)$/;
|
---|
398 |
|
---|
399 | push @{$comments{lc $key}}, $value;
|
---|
400 | push @{$data->{'COMMENT_KEYS'}}, lc $key;
|
---|
401 | }
|
---|
402 |
|
---|
403 | # read past the framing_bit
|
---|
404 | read($fh, $buffer, 1);
|
---|
405 | $byteCount += 1;
|
---|
406 |
|
---|
407 | $data->{'INFO'}{'offset'} = $byteCount;
|
---|
408 |
|
---|
409 | $data->{'COMMENTS'} = \%comments;
|
---|
410 | }
|
---|
411 |
|
---|
412 | sub _calculateTrackLength
|
---|
413 | {
|
---|
414 | my $data = shift;
|
---|
415 | my $fh = $data->{'fileHandle'};
|
---|
416 | my $buffer;
|
---|
417 | my $pageSize;
|
---|
418 | my $granule_position;
|
---|
419 |
|
---|
420 | seek($fh,-8500,SEEK_END); # that magic number is from vorbisfile.c
|
---|
421 | # in the constant CHUNKSIZE, which comes
|
---|
422 | # with the comment /* a shade over 8k;
|
---|
423 | # anyone using pages well over 8k gets
|
---|
424 | # what they deserve */
|
---|
425 |
|
---|
426 | # we just keep looking through the headers until we get to the last one
|
---|
427 | # (there might be a couple of blocks here)
|
---|
428 | while(_findPage($fh))
|
---|
429 | {
|
---|
430 | # stream structure version - must be 0x00
|
---|
431 | read($fh, $buffer, 1);
|
---|
432 | if (ord($buffer) != 0x00)
|
---|
433 | {
|
---|
434 | warn "Invalid stream structure version: " .
|
---|
435 | sprintf("%x", ord($buffer));
|
---|
436 | return;
|
---|
437 | }
|
---|
438 |
|
---|
439 | # header type flag
|
---|
440 | read($fh, $buffer, 1);
|
---|
441 | # we should check this, but for now we'll just ignore it
|
---|
442 |
|
---|
443 | # absolute granule position - this is what we need!
|
---|
444 | read($fh, $buffer, 8);
|
---|
445 | $granule_position = _decodeInt($buffer);
|
---|
446 |
|
---|
447 | # skip past stream_serial_number, page_sequence_number, and crc
|
---|
448 | read($fh, $buffer, 12);
|
---|
449 |
|
---|
450 | # page_segments
|
---|
451 | read($fh, $buffer, 1);
|
---|
452 | my $page_segments = ord($buffer);
|
---|
453 |
|
---|
454 | # reset pageSize
|
---|
455 | $pageSize = 0;
|
---|
456 |
|
---|
457 | # calculate approx. page size
|
---|
458 | for (my $i = 0; $i < $page_segments; $i++)
|
---|
459 | {
|
---|
460 | read($fh, $buffer, 1);
|
---|
461 | $pageSize += ord($buffer);
|
---|
462 | }
|
---|
463 |
|
---|
464 | seek $fh, $pageSize, 1;
|
---|
465 | }
|
---|
466 |
|
---|
467 | $data->{'INFO'}{'length'} =
|
---|
468 | int($granule_position / $data->{'INFO'}{'rate'});
|
---|
469 | }
|
---|
470 |
|
---|
471 | sub _findPage
|
---|
472 | {
|
---|
473 | # search forward in the file for the 'OggS' page header
|
---|
474 | my $fh = shift;
|
---|
475 | my $char;
|
---|
476 | my $curStr = '';
|
---|
477 |
|
---|
478 | while (read($fh, $char, 1))
|
---|
479 | {
|
---|
480 | $curStr = $char . $curStr;
|
---|
481 | $curStr = substr($curStr, 0, 4);
|
---|
482 |
|
---|
483 | # we are actually looking for the string 'SggO' because we
|
---|
484 | # tack character on to our test string backwards, to make
|
---|
485 | # trimming it to 4 characters easier.
|
---|
486 | if ($curStr eq 'SggO')
|
---|
487 | {
|
---|
488 | return 1;
|
---|
489 | }
|
---|
490 | }
|
---|
491 |
|
---|
492 | return undef;
|
---|
493 | }
|
---|
494 |
|
---|
495 | sub _decodeInt
|
---|
496 | {
|
---|
497 | my $bytes = shift;
|
---|
498 | my $num = 0;
|
---|
499 | my @byteList = split //, $bytes;
|
---|
500 | my $numBytes = @byteList;
|
---|
501 | my $mult = 1;
|
---|
502 |
|
---|
503 | for (my $i = 0; $i < $numBytes; $i ++)
|
---|
504 | {
|
---|
505 | $num += ord($byteList[$i]) * $mult;
|
---|
506 | $mult *= 256;
|
---|
507 | }
|
---|
508 |
|
---|
509 | return $num;
|
---|
510 | }
|
---|
511 |
|
---|
512 | sub _decodeInt5Bit
|
---|
513 | {
|
---|
514 | my $byte = ord(shift);
|
---|
515 |
|
---|
516 | $byte = $byte & 0xF8; # clear out the bottm 3 bits
|
---|
517 | $byte = $byte >> 3; # and shifted down to where it belongs
|
---|
518 |
|
---|
519 | return $byte;
|
---|
520 | }
|
---|
521 |
|
---|
522 | sub _decodeInt4Bit
|
---|
523 | {
|
---|
524 | my $byte = ord(shift);
|
---|
525 |
|
---|
526 | $byte = $byte & 0xFC; # clear out the bottm 4 bits
|
---|
527 | $byte = $byte >> 4; # and shifted down to where it belongs
|
---|
528 |
|
---|
529 | return $byte;
|
---|
530 | }
|
---|
531 |
|
---|
532 | sub _ilog
|
---|
533 | {
|
---|
534 | my $x = shift;
|
---|
535 | my $ret = 0;
|
---|
536 |
|
---|
537 | unless ($x > 0)
|
---|
538 | {
|
---|
539 | return 0;
|
---|
540 | }
|
---|
541 |
|
---|
542 | while ($x > 0)
|
---|
543 | {
|
---|
544 | $ret++;
|
---|
545 | $x = $x >> 1;
|
---|
546 | }
|
---|
547 |
|
---|
548 | return $ret;
|
---|
549 | }
|
---|
550 |
|
---|
551 | 1;
|
---|
552 | __DATA__
|
---|
553 |
|
---|
554 | =head1 NAME
|
---|
555 |
|
---|
556 | Ogg::Vorbis::Header::PurePerl - An object-oriented interface to Ogg Vorbis
|
---|
557 | information and comment fields, implemented entirely in Perl. Intended to be
|
---|
558 | a drop in replacement for Ogg::Vobis::Header.
|
---|
559 |
|
---|
560 | Unlike Ogg::Vorbis::Header, this module will go ahead and fill in all of the
|
---|
561 | information fields as soon as you construct the object. In other words,
|
---|
562 | the C<new> and C<load> constructors have identical behavior.
|
---|
563 |
|
---|
564 | =head1 SYNOPSIS
|
---|
565 |
|
---|
566 | use Ogg::Vorbis::Header::PurePerl;
|
---|
567 | my $ogg = Ogg::Vorbis::Header::PurePerl->new("song.ogg");
|
---|
568 | while (my ($k, $v) = each %{$ogg->info}) {
|
---|
569 | print "$k: $v\n";
|
---|
570 | }
|
---|
571 | foreach my $com ($ogg->comment_tags) {
|
---|
572 | print "$com: $_\n" foreach $ogg->comment($com);
|
---|
573 | }
|
---|
574 |
|
---|
575 | =head1 DESCRIPTION
|
---|
576 |
|
---|
577 | This module is intended to be a drop in replacement for Ogg::Vorbis::Header,
|
---|
578 | implemented entirely in Perl. It provides an object-oriented interface to
|
---|
579 | Ogg Vorbis information and comment fields. (NOTE: This module currently
|
---|
580 | supports only read operations).
|
---|
581 |
|
---|
582 | =head1 CONSTRUCTORS
|
---|
583 |
|
---|
584 | =head2 C<new ($filename)>
|
---|
585 |
|
---|
586 | Opens an Ogg Vorbis file, ensuring that it exists and is actually an
|
---|
587 | Ogg Vorbis stream. This method does not actually read any of the
|
---|
588 | information or comment fields, and closes the file immediately.
|
---|
589 |
|
---|
590 | =head2 C<load ([$filename])>
|
---|
591 |
|
---|
592 | Opens an Ogg Vorbis file, ensuring that it exists and is actually an
|
---|
593 | Ogg Vorbis stream, then loads the information and comment fields. This
|
---|
594 | method can also be used without a filename to load the information
|
---|
595 | and fields of an already constructed instance.
|
---|
596 |
|
---|
597 | =head1 INSTANCE METHODS
|
---|
598 |
|
---|
599 | =head2 C<info ([$key])>
|
---|
600 |
|
---|
601 | Returns a hashref containing information about the Ogg Vorbis file from
|
---|
602 | the file's information header. Hash fields are: version, channels, rate,
|
---|
603 | bitrate_upper, bitrate_nominal, bitrate_lower, bitrate_window, and length.
|
---|
604 | The bitrate_window value is not currently used by the vorbis codec, and
|
---|
605 | will always be -1.
|
---|
606 |
|
---|
607 | The optional parameter, key, allows you to retrieve a single value from
|
---|
608 | the object's hash. Returns C<undef> if the key is not found.
|
---|
609 |
|
---|
610 | =head2 C<comment_tags ()>
|
---|
611 |
|
---|
612 | Returns an array containing the key values for the comment fields.
|
---|
613 | These values can then be passed to C<comment> to retrieve their values.
|
---|
614 |
|
---|
615 | =head2 C<comment ($key)>
|
---|
616 |
|
---|
617 | Returns an array of comment values associated with the given key.
|
---|
618 |
|
---|
619 | =head2 C<add_comments ($key, $value, [$key, $value, ...])>
|
---|
620 |
|
---|
621 | Unimplemented.
|
---|
622 |
|
---|
623 | =head2 C<edit_comment ($key, $value, [$num])>
|
---|
624 |
|
---|
625 | Unimplemented.
|
---|
626 |
|
---|
627 | =head2 C<delete_comment ($key, [$num])>
|
---|
628 |
|
---|
629 | Unimplemented.
|
---|
630 |
|
---|
631 | =head2 C<clear_comments ([@keys])>
|
---|
632 |
|
---|
633 | Unimplemented.
|
---|
634 |
|
---|
635 | =head2 C<write_vorbis ()>
|
---|
636 |
|
---|
637 | Unimplemented.
|
---|
638 |
|
---|
639 | =head2 C<path ()>
|
---|
640 |
|
---|
641 | Returns the path/filename of the file the object represents.
|
---|
642 |
|
---|
643 | =head1 NOTE
|
---|
644 |
|
---|
645 | This is ALPHA SOFTWARE. It may very well be very broken. Do not use it in
|
---|
646 | a production environment. You have been warned.
|
---|
647 |
|
---|
648 | =head1 ACKNOWLEDGEMENTS
|
---|
649 |
|
---|
650 | Dave Brown <[email protected]> made this module significantly faster
|
---|
651 | at calculating the length of ogg files.
|
---|
652 |
|
---|
653 | Robert Moser II <[email protected]> fixed a problem with files that
|
---|
654 | have no comments.
|
---|
655 |
|
---|
656 | =head1 AUTHOR
|
---|
657 |
|
---|
658 | Andrew Molloy E<lt>[email protected]<gt>
|
---|
659 |
|
---|
660 | =head1 COPYRIGHT
|
---|
661 |
|
---|
662 | Copyright (c) 2003, Andrew Molloy. All Rights Reserved.
|
---|
663 |
|
---|
664 | This program is free software; you can redistribute it and/or modify it
|
---|
665 | under the terms of the GNU General Public License as published by the
|
---|
666 | Free Software Foundation; either version 2 of the License, or (at
|
---|
667 | your option) any later version. A copy of this license is included
|
---|
668 | with this module (LICENSE.GPL).
|
---|
669 |
|
---|
670 | =head1 SEE ALSO
|
---|
671 |
|
---|
672 | L<Ogg::Vorbis::Header>, L<Ogg::Vorbis::Decoder>
|
---|
673 |
|
---|
674 | =cut
|
---|