File Coverage

blib/lib/File/Headerinfo.pm
Criterion Covered Total %
statement 46 48 95.8
branch 9 14 64.2
condition 1 3 33.3
subroutine 13 15 86.6
pod 10 10 100.0
total 79 90 87.7


line stmt bran cond sub pod time code
1             package File::Headerinfo;
2              
3 1     1   30794 use strict;
  1         2  
  1         40  
4 1     1   6 use Carp;
  1         3  
  1         109  
5              
6 1     1   5 use vars qw( $VERSION $AUTOLOAD );
  1         12  
  1         777  
7             $VERSION = '0.03';
8              
9             =head1 NAME
10              
11             File::Headerinfo - a general purpose extractor of header information from media files. Can handle most image, video and audio file types.
12              
13             =head1 SYNOPSIS
14              
15             use File::Headerinfo;
16             my $headerdata = File::Headerinfo->read('/path/to/file.ext');
17              
18             or
19            
20             my $reader = File::Headerinfo->new;
21             my %filedata = map { $_ => $reader->read($_) } @files;
22            
23             =head1 DESCRIPTION
24              
25             I is little more than a collection of wrappers around existing modules like MP3::Info and Image::Size. It gathers them all behind a simple, friendly interface and offers an easy way to get header information from almost any kind of media file.
26              
27             The main Headerinfo modules is a very simple factory class: the real work is done by a set of dedicated subclasses each able to read a different sort of file. A dispatch table in the factory class maps each file suffix onto the subclass that can read that kind of file.
28              
29             In normal use that minor complexity is hidden from view: all you have to do is pass a file to the read() method and it will do the right thing.
30              
31             =head1 METHODS
32              
33             =head2 read( $path, $type)
34              
35             Examines the file we have been supplied with, creates an object of the appropriate class and tells it to examine the file.
36              
37             Loading of the subclasses is deferred until it's necessary, as some of them use quite chunky modules to do the file-reading work for them.
38              
39             You can force a file to be treated as a particular type by supplying the appropriate three or four letter file suffix as a second parameter:
40              
41             my $fileinfo = File::Headerinfo->read('/path/to/file', 'mpeg');
42              
43             =cut
44              
45             sub read {
46 5     5 1 16457 my $base = shift;
47 5         32 my $class = $base->subclass(@_);
48 5 50       19 return unless $class;
49 5         550 eval "require $class;";
50 5 100       513 Carp::croak($@) if $@;
51 4         53 my $self = $class->new(@_);
52 4         18 $self->parse_file;
53 4         35 return $self->report;
54             }
55              
56             =head2 new()
57              
58             A very simple constructor that is rarely called directly. It is inherited by all the specific-format subclasses, so you could do this:
59              
60             my $reader = File::Headerinfo::SWF->new('/path/to/file.swf');
61             $reader->parse_file;
62             my $report = $reader->report;
63              
64             but needn't bother, since the same thing is achieved by writing:
65              
66             my $report = File::Headerinfo->read('/path/to/file.swf');
67              
68             =cut
69              
70             sub new {
71 5     5 1 33 my $class = shift;
72 5         36 return bless {
73             _path => $_[0],
74             }, $class;
75             }
76              
77             =head2 path()
78              
79             Gets or sets the full path to the file we're trying to examine.
80              
81             =cut
82              
83             sub path {
84 4     4 1 72 my $self = shift;
85 4 50       15 return $self->{_path} = $_[0] if @_;
86 4         40 return $self->{_path};
87             }
88              
89             =head2 subclass( $path, $type )
90              
91             Identifies the subclass (or other class) that is meant to read files of the type supplied.
92              
93             =cut
94              
95             sub subclass {
96 5     5 1 33 my ($base, $path, $type) = @_;
97 5 50       55 return unless $path;
98 5         28 my $media_classes = $base->media_classes;
99 5 50 33     43 my $class = $media_classes->{ $type || _suffix($path) } or $base->default_media_class;
100 5         43 return $class;
101             }
102              
103             =head2 _suffix( $path )
104              
105             Not a method: just a useful helper. Returns the file suffix, with no dot. Useful if we have no other way of identifying the file type.
106              
107             =cut
108              
109             sub _suffix {
110 5     5   9 my $path = shift;
111 5         33 $path =~ /\.(\w+)$/;
112 5         61 return $1;
113             }
114              
115             =head2 parse_file()
116              
117             Each format-specific subclass has its own way of parsing the media file. This is just a placeholder.
118              
119             =cut
120              
121             sub parse_file {
122 0     0 1 0 Carp::croak("File::Headerinfo::parse_file should not be called directly: use the right subclass for your file.");
123             }
124              
125             =head2 media_classes()
126              
127             Returns a hashref that maps media types onto class names. The types can come from stored information or from the suffix of the file.
128              
129             =cut
130              
131             sub media_classes {
132             return {
133 5     5 1 175 gif => 'File::Headerinfo::Image',
134             jpg => 'File::Headerinfo::Image',
135             jpeg => 'File::Headerinfo::Image',
136             png => 'File::Headerinfo::Image',
137             mng => 'File::Headerinfo::Image',
138             xbm => 'File::Headerinfo::Image',
139             xpm => 'File::Headerinfo::Image',
140             tif => 'File::Headerinfo::Image',
141             tiff => 'File::Headerinfo::Image',
142             psd => 'File::Headerinfo::Image',
143             ppm => 'File::Headerinfo::Image',
144             mp3 => 'File::Headerinfo::MP3',
145             wav => 'File::Headerinfo::WAV',
146             swf => 'File::Headerinfo::SWF',
147             mov => 'File::Headerinfo::Video',
148             moov => 'File::Headerinfo::Video',
149             aiff => 'File::Headerinfo::Video',
150             mpeg => 'File::Headerinfo::Video',
151             mpg => 'File::Headerinfo::Video',
152             asf => 'File::Headerinfo::Video',
153             avi => 'File::Headerinfo::Video',
154             divx => 'File::Headerinfo::Video',
155             dvx => 'File::Headerinfo::Video',
156             };
157             }
158              
159             =head2 default_media_class()
160              
161             returns the class name we'll try to use if we can't think of anything else.
162              
163             =cut
164              
165 0     0 1 0 sub default_media_class { 'File::Headerinfo::Video' }
166              
167             =head2 fields()
168              
169             Defines the list of parameters that will be provided by each subclass, which is currently: height, width, duration, filetype, fps, filesize, freq, datarate, vcodec, metadata.
170              
171             This list is used by AUTOLOAD to create get and set methods, and by report to build its hash of discovered values. It can be overridden by the format-specific subclass if it needs to be extended, but no harm will come from having unused fields here.
172              
173             =cut
174              
175             sub fields {
176 67     67 1 206 return qw(height width duration filetype freq fps filesize datarate vcodec metadata version);
177             }
178              
179             =head2 allowed_field( $fieldname )
180              
181             Returns true if the supplied value is in the list of allowed fields.
182              
183             =cut
184              
185             sub allowed_field {
186 63     63 1 93 my ($self, $f) = @_;
187 63         3548 my %fields = map {$_ => 1 } $self->fields;
  693         1152  
188 63         338 return $fields{$f};
189             }
190              
191             =head2 report()
192              
193             Returns a hashref containing all the available file information. This method is usually called by read() to return everything at once.
194              
195             =cut
196              
197             sub report {
198 4     4 1 8 my $self = shift;
199 4         10 my %report = map { $_ => $self->$_() } $self->fields;
  44         235  
200 4         91 return \%report;
201             }
202              
203             sub AUTOLOAD {
204 63     63   132 my $self = shift;
205 63         91 my $field = $AUTOLOAD;
206 63         250 $field =~ s/.*://;
207 63 50       230 return unless $self->allowed_field($field);
208 63 100       189 return $self->{$field} = $_[0] if @_;
209 45         370 return $self->{$field};
210             }
211              
212             =head1 COPYRIGHT
213              
214             Copyright 2004 William Ross (wross@cpan.org)
215              
216             This library is free software; you can redistribute it
217             and/or modify it under the same terms as Perl itself.
218              
219             =cut
220              
221             1;