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; |