File Coverage

blib/lib/Image/ExifTool/Vorbis.pm
Criterion Covered Total %
statement 42 44 95.4
branch 16 20 80.0
condition 2 2 100.0
subroutine 4 4 100.0
pod 0 1 0.0
total 64 71 90.1


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: Vorbis.pm
3             #
4             # Description: Read Ogg Vorbis audio meta information
5             #
6             # Revisions: 2006/11/10 - P. Harvey Created
7             # 2011/07/12 - PH Moved Ogg to a separate module and added Theora
8             #
9             # References: 1) http://www.xiph.org/vorbis/doc/
10             # 2) http://flac.sourceforge.net/ogg_mapping.html
11             # 3) http://www.theora.org/doc/Theora.pdf
12             #------------------------------------------------------------------------------
13              
14             package Image::ExifTool::Vorbis;
15              
16 3     3   4369 use strict;
  3         10  
  3         108  
17 3     3   16 use vars qw($VERSION);
  3         11  
  3         133  
18 3     3   18 use Image::ExifTool qw(:DataAccess :Utils);
  3         15  
  3         3206  
19              
20             $VERSION = '1.08';
21              
22             sub ProcessComments($$$);
23              
24             # Vorbis header types
25             %Image::ExifTool::Vorbis::Main = (
26             NOTES => q{
27             Information extracted from Ogg Vorbis files. See
28             L for the Vorbis specification.
29             },
30             1 => {
31             Name => 'Identification',
32             SubDirectory => { TagTable => 'Image::ExifTool::Vorbis::Identification' },
33             },
34             3 => {
35             Name => 'Comments',
36             SubDirectory => { TagTable => 'Image::ExifTool::Vorbis::Comments' },
37             },
38             );
39              
40             %Image::ExifTool::Vorbis::Identification = (
41             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
42             GROUPS => { 2 => 'Audio' },
43             0 => {
44             Name => 'VorbisVersion',
45             Format => 'int32u',
46             },
47             4 => 'AudioChannels',
48             5 => {
49             Name => 'SampleRate',
50             Format => 'int32u',
51             },
52             9 => {
53             Name => 'MaximumBitrate',
54             Format => 'int32u',
55             RawConv => '$val || undef',
56             PrintConv => 'ConvertBitrate($val)',
57             },
58             13 => {
59             Name => 'NominalBitrate',
60             Format => 'int32u',
61             RawConv => '$val || undef',
62             PrintConv => 'ConvertBitrate($val)',
63             },
64             17 => {
65             Name => 'MinimumBitrate',
66             Format => 'int32u',
67             RawConv => '$val || undef',
68             PrintConv => 'ConvertBitrate($val)',
69             },
70             );
71              
72             %Image::ExifTool::Vorbis::Comments = (
73             PROCESS_PROC => \&ProcessComments,
74             GROUPS => { 2 => 'Audio' },
75             NOTES => q{
76             The tags below are only some common tags found in the Vorbis comments of Ogg
77             Vorbis and Ogg FLAC audio files, however ExifTool will extract values from
78             any tag found, even if not listed here.
79             },
80             vendor => { Notes => 'from comment header' },
81             TITLE => { Name => 'Title' },
82             VERSION => { Name => 'Version' },
83             ALBUM => { Name => 'Album' },
84             TRACKNUMBER=>{ Name => 'TrackNumber' },
85             ARTIST => { Name => 'Artist', Groups => { 2 => 'Author' }, List => 1 },
86             PERFORMER => { Name => 'Performer', Groups => { 2 => 'Author' }, List => 1 },
87             COPYRIGHT => { Name => 'Copyright', Groups => { 2 => 'Author' } },
88             LICENSE => { Name => 'License', Groups => { 2 => 'Author' } },
89             ORGANIZATION=>{Name => 'Organization', Groups => { 2 => 'Author' } },
90             DESCRIPTION=>{ Name => 'Description' },
91             GENRE => { Name => 'Genre' },
92             DATE => { Name => 'Date', Groups => { 2 => 'Time' } },
93             LOCATION => { Name => 'Location', Groups => { 2 => 'Location' } },
94             CONTACT => { Name => 'Contact', Groups => { 2 => 'Author' }, List => 1 },
95             ISRC => { Name => 'ISRCNumber' },
96             COVERARTMIME => { Name => 'CoverArtMIMEType' },
97             COVERART => {
98             Name => 'CoverArt',
99             Groups => { 2 => 'Preview' },
100             Notes => 'base64-encoded image',
101             ValueConv => q{
102             require Image::ExifTool::XMP;
103             Image::ExifTool::XMP::DecodeBase64($val);
104             },
105             },
106             REPLAYGAIN_TRACK_PEAK => { Name => 'ReplayGainTrackPeak' },
107             REPLAYGAIN_TRACK_GAIN => { Name => 'ReplayGainTrackGain' },
108             REPLAYGAIN_ALBUM_PEAK => { Name => 'ReplayGainAlbumPeak' },
109             REPLAYGAIN_ALBUM_GAIN => { Name => 'ReplayGainAlbumGain' },
110             # observed in "Xiph.Org libVorbis I 20020717" ogg:
111             ENCODED_USING => { Name => 'EncodedUsing' },
112             ENCODED_BY => { Name => 'EncodedBy' },
113             COMMENT => { Name => 'Comment' },
114             # in Theora documentation (ref 3)
115             DIRECTOR => { Name => 'Director' },
116             PRODUCER => { Name => 'Producer' },
117             COMPOSER => { Name => 'Composer' },
118             ACTOR => { Name => 'Actor' },
119             # Opus tags
120             ENCODER => { Name => 'Encoder' },
121             ENCODER_OPTIONS => { Name => 'EncoderOptions' },
122             METADATA_BLOCK_PICTURE => {
123             Name => 'Picture',
124             Binary => 1,
125             # ref https://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
126             RawConv => q{
127             require Image::ExifTool::XMP;
128             Image::ExifTool::XMP::DecodeBase64($val);
129             },
130             SubDirectory => {
131             TagTable => 'Image::ExifTool::FLAC::Picture',
132             ByteOrder => 'BigEndian',
133             },
134             },
135             );
136              
137             # Vorbis composite tags
138             %Image::ExifTool::Vorbis::Composite = (
139             Duration => {
140             Require => {
141             0 => 'Vorbis:NominalBitrate',
142             1 => 'FileSize',
143             },
144             RawConv => '$val[0] ? $val[1] * 8 / $val[0] : undef',
145             PrintConv => 'ConvertDuration($val) . " (approx)"', # (only approximate)
146             },
147             );
148              
149             # add our composite tags
150             Image::ExifTool::AddCompositeTags('Image::ExifTool::Vorbis');
151              
152              
153             #------------------------------------------------------------------------------
154             # Process Vorbis Comments
155             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
156             # Returns: 1 on success, otherwise returns 0 and sets a Warning
157             sub ProcessComments($$$)
158             {
159 4     4 0 48 my ($et, $dirInfo, $tagTablePtr) = @_;
160 4         10 my $dataPt = $$dirInfo{DataPt};
161 4         8 my $dataPos = $$dirInfo{DataPos};
162 4   100     23 my $pos = $$dirInfo{DirStart} || 0;
163 4 100       15 my $end = $$dirInfo{DirLen} ? $pos + $$dirInfo{DirLen} : length $$dataPt;
164 4         9 my ($num, $index);
165              
166 4         15 SetByteOrder('II');
167 4         7 for (;;) {
168 24 50       57 last if $pos + 4 > $end;
169 24         54 my $len = Get32u($dataPt, $pos);
170 24 50       57 last if $pos + 4 + $len > $end;
171 24         37 my $start = $pos + 4;
172 24         52 my $buff = substr($$dataPt, $start, $len);
173 24         36 $pos = $start + $len;
174 24         38 my ($tag, $val);
175 24 100       44 if (defined $num) {
176 20 50       101 $buff =~ /(.*?)=(.*)/s or last;
177 20         85 ($tag, $val) = (uc $1, $2);
178             # Vorbis tag ID's are all capitals, so they may conflict with our internal tags
179             # --> protect against this by adding a trailing underline if necessary
180 20 50       51 $tag .= '_' if $Image::ExifTool::specialTags{$tag};
181             } else {
182 4         9 $tag = 'vendor';
183 4         6 $val = $buff;
184 4 100       29 $num = ($pos + 4 < $end) ? Get32u($dataPt, $pos) : 0;
185 4         46 $et->VPrint(0, " + [Vorbis comments with $num entries]\n");
186 4         10 $pos += 4;
187             }
188             # add tag to table unless it exists already
189 24 100       61 unless ($$tagTablePtr{$tag}) {
190 3         12 my $name = ucfirst(lc($tag));
191             # remove invalid characters in tag name and capitalize following letters
192 3         26 $name =~ s/[^\w-]+(.?)/\U$1/sg;
193 3         9 $name =~ s/([a-z0-9])_([a-z])/$1\U$2/g;
194 3         13 $et->VPrint(0, " | [adding $tag]\n");
195 3         15 AddTagToTable($tagTablePtr, $tag, { Name => $name });
196             }
197 24         75 $et->HandleTag($tagTablePtr, $tag, $et->Decode($val, 'UTF8'),
198             Index => $index,
199             DataPt => $dataPt,
200             DataPos => $dataPos,
201             Start => $start,
202             Size => $len,
203             );
204             # all done if this was our last tag
205 24 100       72 $num-- or return 1;
206 20 100       47 $index = (defined $index) ? $index + 1 : 0;
207             }
208 0           $et->Warn('Format error in Vorbis comments');
209 0           return 0;
210             }
211              
212             1; # end
213              
214             __END__