File Coverage

blib/lib/Audio/Extract/PCM/Backend/Vorbis.pm
Criterion Covered Total %
statement 17 17 100.0
branch 1 2 50.0
condition n/a
subroutine 6 6 100.0
pod n/a
total 24 25 96.0


line stmt bran cond sub pod time code
1             package Audio::Extract::PCM::Backend::Vorbis;
2 1     1   10 use strict;
  1         3  
  1         47  
3 1     1   7 use warnings;
  1         1  
  1         38  
4 1     1   10 use base qw(Audio::Extract::PCM::Backend);
  1         3  
  1         167  
5 1     1   13 use Audio::Extract::PCM::Format;
  1         2  
  1         10  
6              
7             # If required stuff cannot be found, we must fail with a special error message,
8             # so that AEPCM knows that this is not a real error (otherwise it would show
9             # the error message to the user).
10             BEGIN {
11 1     1   52 use Class::Inspector;
  1         3  
  1         68  
12              
13 1 50   1   5 unless (Class::Inspector->installed('Ogg::Vorbis::Decoder')) {
14 1         422 die __PACKAGE__ . " - trynext\n"; # try next backend
15             }
16             }
17             use Ogg::Vorbis::Decoder;
18              
19             __PACKAGE__->mk_accessors(qw(_decoder));
20              
21              
22             =head1 NAME
23              
24             Audio::Extract::PCM::Backend::Vorbis - ogg/vorbis backend for audio extraction
25              
26             =head1 SYNOPSIS
27              
28             This module makes L capable to use the vorbisfile library
29             (specifically L) for audio extraction.
30              
31             =head1 METHODS
32              
33             =head2 new
34              
35             See L.
36              
37             =cut
38              
39              
40             sub new {
41             my $class = shift;
42             my $this = $class->SUPER::new(@_);
43              
44             return $this;
45             }
46              
47              
48             =head2 open_back
49              
50             See L.
51              
52             =cut
53              
54             sub open_back {
55             my $this = shift;
56             my ($format) = @_;
57              
58             # Avoid passing a file name to Decoder->open. It segfaults if it cannot
59             # open it (bug reported).
60             # Pass a file handle instead.
61              
62             my $fh;
63             unless (open $fh, '<', $this->filename) {
64             $this->error("Couldn't open " . $this->filename . ": $!");
65             return ();
66             }
67              
68             my $decoder = Ogg::Vorbis::Decoder->open($fh);
69             unless ($decoder) {
70             $this->error('Could not open decoder');
71             return ();
72             }
73              
74             $this->_decoder($decoder);
75              
76             my $signed = defined($format->signed) ? $format->signed : 1;
77             my $samplesize = $format->samplesize || 2;
78              
79             if ($samplesize != 1 && $samplesize != 2) {
80             $samplesize = 2;
81             }
82              
83             # And now we get to the undocumented parts of Ogg::Vorbis::Decoder:
84             my $srcfreq = $decoder->{INFO}{rate} or die 'uh, no rate?';
85             my $channels = $decoder->{INFO}{channels} or die 'uh, no channels?';
86              
87             my $endformat = Audio::Extract::PCM::Format->new(
88             freq => $srcfreq,
89             duration => $decoder->time_total(),
90             samplesize => $samplesize,
91             channels => $channels,
92             signed => $signed,
93              
94             # Although libvorbisfile supports the other endianness,
95             # Ogg::Vorbis::Decoder always sets the local one.
96             endian => 'native',
97             );
98             return $endformat;
99             }
100              
101              
102             =head2 read_back
103              
104             See L.
105              
106             =cut
107              
108             sub read_back {
109             my $this = shift;
110             my $buf = \shift;
111             my (%args) = @_;
112              
113             my $format = $this->format;
114              
115             my $bytes = $args{bytes};
116             $bytes = $this->_decoder->raw_total unless defined $bytes;
117              
118             my $workbuf = $args{append} ? do{\my($x)} : $buf;
119             $$workbuf = '';
120              
121             my $l = $this->_decoder->read($$workbuf, $bytes, $format->samplesize, $format->signed);
122             if ($l < 0) {
123             $this->error("Ogg::Vorbis::Decoder::read returned $l");
124             return ();
125             }
126             $$buf .= $$workbuf if $args{append};
127             return $l;
128             }
129              
130              
131             =head2 used_versions
132              
133             Returns a hash ref with the version of L as value.
134              
135             =cut
136              
137             sub used_versions {
138             return {
139             'Ogg::Vorbis::Decoder' => Ogg::Vorbis::Decoder->VERSION,
140             };
141             }
142              
143              
144             our $AVAILABLE = 1;