File Coverage

blib/lib/Video/Info/MPEG/Audio.pm
Criterion Covered Total %
statement 72 130 55.3
branch 23 80 28.7
condition 2 9 22.2
subroutine 13 18 72.2
pod 0 13 0.0
total 110 250 44.0


line stmt bran cond sub pod time code
1             ##------------------------------------------------------------------------
2             ## Package: Video::Info::MPEG::Audio
3             ## Author: Benjamin R. Ginter
4             ## Notice: Copyright (c) 2001 Benjamin R. Ginter
5             ## Purpose: Parse audio streams
6             ## Comments: None
7             ## CVS: $Id: Audio.pm,v 1.3 2002/11/12 07:19:34 allenday Exp $
8             ##------------------------------------------------------------------------
9              
10             package Video::Info::MPEG::Audio;
11 5     5   25 use strict;
  5         10  
  5         204  
12 5     5   26 use Video::Info::MPEG qw( $AUDIO_BITRATE );
  5         10  
  5         146  
13 5     5   26 use Video::Info::MPEG::Constants;
  5         9  
  5         1130  
14              
15 5     5   30 use constant DEBUG => 0;
  5         9  
  5         437  
16 5     5   28 use base qw(Video::Info::MPEG);
  5         8  
  5         12934  
17              
18             our $AUDIO_BITRATE;
19             our $AUDIO_SAMPLING_RATE;
20              
21             ##------------------------------------------------------------------------
22             ## Preloaded methods go here.
23             ##------------------------------------------------------------------------
24             1;
25              
26             sub init {
27 12     12 0 598 my $self = shift;
28 12         40 my %param = @_;
29 12         328 $self->handle($self->filename($param{-file}));
30 12         129 $self->init_attributes;
31 12         1002 $self->version(0);
32             }
33              
34             ##------------------------------------------------------------------------
35             ## parse()
36             ##
37             ## Parse an audio packet. Since this is in the context of a video stream,
38             ## we only care about the MPEG version, layer, bitrate, sampling rate,
39             ## channels, and emphasis.
40             ##
41             ##------------------------------------------------------------------------
42             sub parse {
43 23     23 0 42 my($self,$offset) = @_;
44              
45 23 100       82 $offset = 0 if !defined $offset;
46 23         45 $self->{offset} = $offset;
47              
48 23         94 $self->{_bytes} = $self->get_header();
49             # printf "0x%08x\n", unpack( "N", pack( "C*", @{$self->{_bytes}} ) );
50              
51 23         48 print "Video::Info::MPEG::Audio::parse( $offset )\n" if DEBUG;
52              
53             #print "parse audio: $offset\n";
54 23 100       73 $self->is_audio() or return 0;
55              
56 5 50 33     23 $self->get_version && $self->get_layer or return 0;
57 5 50 33     26 $self->get_bitrate && $self->get_sampling_freq or return 0;
58             # $self->get_protect;
59 5         31 $self->get_audio_mode();
60             # $self->get_copyright();
61             # $self->get_padding();
62             # $self->get_emphasis();
63             #$self->get_frame_length();
64              
65             #if we made it this far, assume a bona fide MPEG
66 5         160 $self->type('MPEG');
67              
68 5         35 if ( DEBUG ) {
69             print '-' x 74, "\n", 'Parse Audio', "\n", '-' x 74, "\n";
70              
71             print "MPEG-$self->{version} Layer $self->{layer}\n";
72             print " MODE: $self->{mode}\n";
73             print " BITRATE: $self->{bitrate}\n";
74             print " BYTERATE: $self->{byterate}\n";
75             print "SAMPLING RATE: $self->{sampling}\n";
76             print " PADDING: $self->{padding}\n";
77             print " EMPHASIS: $self->{emphasis}\n";
78             print " COPYRIGHT: $self->{copyright}\n";
79             print " PROTECT: $self->{protect}\n";
80             # print " FRAME_LENGTH: $self->{frame_length}\n";
81             print "Audio : Mpeg $self->{version} layer $self->{layer}\n";
82             print "$self->{bitrate} kbps $self->{sampling} Hz\n";
83             print "$self->{mode}, $self->{emphasis}\n";
84             }
85            
86             ## Save off some information to a format Video::Info expects.
87             ## The $self-> hash remains available for the user if needed.
88              
89 5         146 $self->arate ( $self->{byterate} * 8 );
90 5         180 $self->copyright( $self->{copyright} );
91              
92 5         81 return 1;
93             }
94              
95             ##------------------------------------------------------------------------
96             ## is_audio()
97             ##
98             ## Verify we have the proper MPEG audio packet start codes
99             ##------------------------------------------------------------------------
100             sub is_audio {
101 23     23 0 36 my $self = shift;
102 23         44 my $bytes = $self->{_bytes};
103              
104             ## ensure that the first two bytes are FFFx
105 23 100       144 return 0 if $bytes->[0] != 0xFF;
106              
107 5 50       25 if ( ( $bytes->[1] & 0xF0 ) != 0xF0 ) {
108             ## Doesn't start with 12 bits set
109            
110 0 0       0 if ( ( $bytes->[1] & 0xE0 ) != 0xE0 ) {
111             ## Doesn't start with 11 bits set either -- give up
112 0         0 return 0;
113             }
114             # else {
115             ## starts with 11 bits set
116 0         0 $self->{version} = 2.5;
117             # }
118             }
119 5         17 return 1;
120              
121             }
122              
123             ##------------------------------------------------------------------------
124             ## get_version()
125             ##
126             ## Determine the MPEG Version
127             ##------------------------------------------------------------------------
128             sub get_version {
129 5     5 0 13 my $self = shift;
130              
131             ## find mpeg version 1.0 or 2.0
132 5 50       23 if ( $self->{_bytes}->[1] & 0x08 ) {
133 5 50       33 if ( $self->{version} != 2.5 ) {
134 5         13 $self->{version} = 1;
135 5         167 $self->acodecraw(0x50);
136             }
137             else {
138             ## invalid 01 encountered
139 0         0 return 0;
140             }
141             } else {
142 0 0       0 if ( $self->{version} != 2.5 ) {
143 0         0 $self->{version} = 2;
144 0         0 $self->acodecraw(0x50);
145             } else {
146             ## err, isn't this set?
147 0         0 $self->{version} = 3;
148 0         0 $self->acodecraw(0x55);
149             }
150             }
151 5         67 return 1;
152             }
153              
154             ##------------------------------------------------------------------------
155             ## get_layer()
156             ##
157             ## Determine the MPEG layer
158             ##------------------------------------------------------------------------
159             sub get_layer {
160 5     5 0 12 my $self = shift;
161              
162             ## Find layer
163 5         18 my $layer = ( $self->{_bytes}->[1] & 0x06 ) >> 1;
164 5 50       32 if ( $layer == 0 ) {
    100          
    50          
    0          
165 0         0 $self->{layer} = -1;
166 0         0 return 0;
167             }
168             elsif ( $layer == 1 ) {
169 1         2 $self->{layer} = 3;
170             }
171             elsif ( $layer == 2 ) {
172 4         14 $self->{layer} = 2;
173             }
174             elsif ( $layer == 3 ) {
175 0         0 $self->{layer} = 1;
176             }
177             else {
178 0         0 $self->{layer} = $layer;
179 0         0 print "Unknown audio layer index: $layer\n";
180 0         0 return 0;
181             }
182             # undef $layer;
183              
184 5         31 return 1;
185             }
186              
187             ##------------------------------------------------------------------------
188             ## get_audio_mode()
189             ##
190             ## Determine the audio mode (channels, etc.)
191             ##------------------------------------------------------------------------
192             sub get_audio_mode {
193 5     5 0 9 my $self = shift;
194              
195             ## Get the raw audio mode
196 5         17 $self->{mode_raw} = $self->{_bytes}->[3] >> 6;
197 5 50       26 $self->{mode_raw} == 1 ? $self->{modext} = ( $self->{_bytes}->[3] >> 4 ) & 0x03 : $self->{modext} = 1;
198              
199 5         152 $self->achans( 2 );
200              
201             ## Now decode it
202 5 100       63 if ( $self->{mode_raw} == 0 ) {
    50          
    50          
    50          
203 3         9 $self->{mode} = 'Stereo';
204 3         84 $self->achans(2);
205             }
206             elsif ( $self->{mode_raw} == 1 ) {
207 0 0 0     0 if ( $self->{layer} == 1 || $self->{layer} == 2 ) {
208 0 0       0 if ( $self->{modext} == 0 ) {
    0          
    0          
    0          
209 0         0 $self->{mode} = 'Intensity stereo on bands 4-31/32';
210             }
211             elsif ( $self->{modext} == 1 ) {
212 0         0 $self->{mode} = 'Intensity stereo on bands 8-31/32';
213             }
214             elsif ( $self->{modext} == 2 ) {
215 0         0 $self->{mode} = 'Intensity stereo on bands 12-31/32';
216             }
217             elsif ( $self->{modext} == 3 ) {
218 0         0 $self->{mode} = 'Intensity stereo on bands 16-31/32';
219             }
220             else {
221 0         0 $self->{mode} = "Unknown audio mode extension. Mode=$self->{mode_raw} Ext: $self->{modext}";
222 0         0 return 0;
223             }
224             }
225             else {
226             ## mp3
227 0 0       0 if ( $self->{modext} == 0 ) {
    0          
    0          
    0          
228 0         0 $self->{mode} = 'Intensity stereo off, M/S stereo off';
229             }
230             elsif ( $self->{modext} == 1 ) {
231 0         0 $self->{mode} = 'Intensity stereo on, M/S stereo off';
232             }
233             elsif ( $self->{modext} == 2 ) {
234 0         0 $self->{mode} = 'Intensity stereo off, M/S stereo on';
235             }
236             elsif ( $self->{modext} == 3 ) {
237 0         0 $self->{mode} = 'Intensity stereo on, M/S stereo on';
238             }
239             else {
240 0         0 $self->{mode} = "Unknown audio mode extension. Mode=$self->{mode_raw} Ext: $self->{modext}";
241 0         0 return 0;
242             }
243            
244             }
245             }
246             elsif ( $self->{mode_raw} == 2 ) {
247 0         0 $self->{mode} = 'Dual Channel';
248 0         0 $self->achans(2); #not stereo, but still 2, right? brg: yes
249             }
250             elsif ( $self->{mode_raw} == 3 ) {
251 2         6 $self->{mode} = 'Mono';
252 2         56 $self->achans(1);
253             }
254             else {
255 0         0 $self->{mode} = "Unknown audio mode. Mode=$self->{mode_raw} Ext: $self->{modext}";
256 0         0 $self->achans(0);
257 0         0 return 0;
258             }
259              
260 5         34 return 1;
261             }
262              
263             ##------------------------------------------------------------------------
264             ## get_copyright()
265             ##------------------------------------------------------------------------
266             sub get_copyright {
267 0     0 0 0 my $self = shift;
268              
269             ## Set original/copyright bit
270 0 0       0 $self->{_bytes}->[3] & 0x04 ? $self->{copyright} = 1 : $self->{copyright} = 0;
271             }
272              
273             ##------------------------------------------------------------------------
274             ## get_protect()
275             ##
276             ## Extract the protection bit
277             ##------------------------------------------------------------------------
278             sub get_protect {
279 0     0 0 0 my $self = shift;
280              
281             ## Get protection bit
282 0 0       0 $self->{_bytes}->[1] & 0x01 ? $self->{protect} = 0 : $self->{protect} = 1;
283              
284             }
285              
286             ##------------------------------------------------------------------------
287             ## get_bitrate()
288             ##------------------------------------------------------------------------
289             sub get_bitrate {
290 5     5 0 10 my $self = shift;
291              
292             ## Bitrate index and sampling index to pass through the array
293 5         14 my $bitrate_index = $self->{_bytes}->[2] >> 4;
294 5 50       50 return 0 if $bitrate_index == 15;
295              
296 5         116 $self->{bitrate} = $AUDIO_BITRATE->{ $self->{version} }->{ $self->{layer} }->[ $bitrate_index ];
297 5         22 $self->{byterate} = ( $self->{bitrate} * 1000 ) / 8.0;
298              
299 5         34 return 1;
300             }
301              
302             ##------------------------------------------------------------------------
303             ## get_sampling_freq()
304             ##------------------------------------------------------------------------
305             sub get_sampling_freq {
306 5     5 0 30 my $self = shift;
307              
308 5         17 my $sampling_index = ( $self->{_bytes}->[2] & 0x0F ) >> 2;
309             # print "sampling_index: $sampling_index\n";
310              
311 5 50       26 return 0 if $sampling_index == 3;
312              
313 5         25 $self->{sampling} = $AUDIO_SAMPLING_RATE->{ $self->{version} }->[ $sampling_index ];
314 5         38 return 1;
315             }
316              
317             ##------------------------------------------------------------------------
318             ## get_padding()
319             ##------------------------------------------------------------------------
320             sub get_padding {
321 0     0 0   my $self = shift;
322              
323             ## Get padding bit
324 0 0         $self->{_bytes}->[2] & 0x02 ? $self->{padding} = 1 : $self->{padding} = 0;
325             }
326              
327             ##------------------------------------------------------------------------
328             ## get_emphasis()
329             ##------------------------------------------------------------------------
330             sub get_emphasis {
331 0     0 0   my $self = shift;
332              
333             ## Get emphasis
334 0           my $emphasis_index = $self->{_bytes}->[3] & 0x03;
335              
336 0 0         if ( $emphasis_index == 0 ) {
    0          
    0          
    0          
337 0           $self->{emphasis} = 'No Emphasis';
338             }
339             elsif ( $emphasis_index == 1 ) {
340 0           $self->{emphasis} = '50/15us';
341             }
342             elsif ( $emphasis_index == 2 ) {
343 0           $self->{emphasis} = 'Unknown';
344             }
345             elsif ( $emphasis_index == 3 ) {
346 0           $self->{emphasis} = 'CCITT J 17';
347             }
348             else {
349 0           $self->{emphasis} = 'Undefined';
350             }
351              
352             }
353              
354             ##------------------------------------------------------------------------
355             ## get_frame_length()
356             ##------------------------------------------------------------------------
357             sub get_frame_length {
358 0     0 0   my $self = shift;
359              
360             ## Get frame-length
361 0 0         if ( $self->{version} == 1 ) {
362 0 0         if ( $self->{layer} == 1 ) {
363 0           $self->{frame_length} = int( ( 48000 * $self->{bitrate} ) / $self->{sampling} ) + 4 * $self->{padding};
364             }
365             else {
366 0           $self->{frame_length} = int( ( 72000 * $self->{bitrate} ) / $self->{sampling} ) + $self->{padding};
367             }
368             }
369             else {
370 0           print "Audio layer invalid : should be 1 or 2\n";
371 0           return 0;
372             }
373              
374 0 0         if ( $self->{protect} ) {
375 0           $self->{frame_length} += 2;
376             }
377             }
378              
379             1;
380              
381             __END__