File Coverage

blib/lib/Flv/Info/Lite.pm
Criterion Covered Total %
statement 129 130 99.2
branch 25 32 78.1
condition 3 3 100.0
subroutine 12 12 100.0
pod 0 8 0.0
total 169 185 91.3


line stmt bran cond sub pod time code
1             package Flv::Info::Lite;
2              
3 2     2   42484 use 5.008008;
  2         7  
  2         67  
4 2     2   11 use strict;
  2         2  
  2         71  
5 2     2   17 use warnings;
  2         12  
  2         2527  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10             our @EXPORT_OK = qw( flv_info );
11             our @EXPORT = qw();
12             our $VERSION = '0.01';
13              
14             sub flv_info
15             {
16 1     1 0 10 my %tag_type = (
17             8 => 'audio',
18             9 => 'video',
19             18 => 'script',
20             );
21              
22 1         15 my %audio_format = (
23             0 => 'uncompressed',
24             1 => 'ADPCM',
25             2 => 'MP3',
26             3 => 'Linear_PCM_little_endian',
27             4 => 'Nellymoser_16kHz_mono',
28             5 => 'Nellymoser_8kHz_mono',
29             6 => 'Nellymoser',
30             7 => 'G.711_A-law',
31             8 => 'G.711_mu-law',
32             10 => 'AAC',
33             11 => 'Speex',
34             14 => 'MP3_8kHz',
35             15 => 'Device-specific_sound',
36             );
37              
38 1         4 my %audio_rate = (
39             0 => '5518Hz',
40             1 => '11025Hz',
41             2 => '22050Hz',
42             3 => '44100Hz',
43             );
44              
45 1         4 my %audio_size = (
46             0 => '8bit',
47             1 => '16bit',
48             );
49              
50 1         2 my %audio_type = (
51             0 => 'mono',
52             1 => 'stereo',
53             );
54              
55 1         6 my %video_codec = (
56             1 => 'JPEG',
57             2 => 'Sorenson_H.263',
58             3 => 'Screen_video',
59             4 => 'On2_VP6',
60             5 => 'On2_VP6_alpha',
61             6 => 'Screen_video_v2',
62             7 => 'AVC',
63             );
64              
65 1         4 my %video_type = (
66             1 => 'keyframe',
67             2 => 'interframe',
68             3 => 'disposable_interframe',
69             4 => 'generated_keyframe',
70             5 => 'video_info/command_frame',
71             );
72              
73 1         15 my %avc_packet_type = (
74             0 => 'avc_seq_header',
75             1 => 'avc_nalu',
76             2 => 'avc_seq_end',
77             );
78              
79 1         3 my $input = shift;
80 1         2 my %flv_info;
81 1         2 $flv_info{frame_count} = 0;
82              
83 1 50       3 if ( $input eq '-' ) {
84 0         0 open FH, "<-";
85             }
86             else {
87 1         36 open FH, "<", $input;
88             }
89 1         3 binmode FH;
90 1         1 my $buf;
91              
92 1         26 read( FH, $buf, 3 ); #File Header
93              
94 1         3 read( FH, $buf, 1 ); #Version
95              
96 1         2 read( FH, $buf, 1 ); # jump Type Flags
97 1         3 my $flags = unpack 'C', substr( $buf, 0, 1 );
98 1         3 my $type_flags_audio = ( ( $flags >> 2 ) & 0x01 );
99 1         1 my $type_flags_video = $flags & 0x01;
100 1         2 $flv_info{have_audio} = $type_flags_audio;
101 1         2 $flv_info{have_video} = $type_flags_video;
102              
103 1         2 read( FH, $buf, 4 ); #Header Size
104              
105 1         1 read( FH, $buf, 4 ); # jump PreviousTagSize0
106              
107 1         1 my $tag_id = 0;
108              
109 1         4 while ( read( FH, $buf, 8 ) ) {
110 171         133 $tag_id++;
111              
112 171         163 my ( $tag_type, $data_size, $ts, @datasize, @timestamp );
113             (
114 171         431 $tag_type, $datasize[0], $datasize[1], $datasize[2],
115             $timestamp[1], $timestamp[2], $timestamp[3], $timestamp[0]
116             ) = unpack 'CCCCCCCC', $buf;
117              
118 171         225 $data_size = ( $datasize[0] * 256 + $datasize[1] ) * 256 + $datasize[2];
119 171         322 $ts =
120             ( ( $timestamp[0] * 256 + $timestamp[1] ) * 256 + $timestamp[2] ) * 256 +
121             $timestamp[3];
122              
123 171         293 read( FH, $buf, 3 ); # jump SteamID, Always 0.
124 171         513 read( FH, $buf, $data_size );
125              
126 171         228 $tag_type = $tag_type{$tag_type};
127              
128 171 100       322 if ( $tag_type eq 'audio' ) {
    100          
    50          
129 65         71 my $flags = unpack 'C', substr( $buf, 0, 1 );
130 65         69 my $format = ( ( $flags >> 4 ) & 0x0f );
131 65         61 my $rate = ( ( $flags >> 2 ) & 0x03 );
132 65         54 my $size = ( ( $flags >> 1 ) & 0x01 );
133 65         45 my $type = $flags & 0x01;
134 65         72 my $audio_format = $audio_format{$format};
135 65         65 my $audio_rate = $audio_rate{$rate}; # Always 44100 when AAC
136 65         62 my $audio_size = $audio_size{$size};
137 65         92 my $audio_type = $audio_type{$type};
138             }
139             elsif ( $tag_type eq 'video' ) {
140 105         129 my $flags = unpack 'C', substr( $buf, 0, 1 );
141 105         112 my $type = ( $flags >> 4 ) & 0x0f;
142 105         86 my $codec = $flags & 0x0f;
143 105         106 my $video_type = $video_type{$type};
144 105         97 my $video_codec = $video_codec{$codec};
145 105         88 my $if_real_frame = 1;
146 105 50       169 if ( $video_codec eq 'AVC' ) {
147 105         199 my @avc_time;
148 105         101 my $avc_header = substr( $buf, 1, 4 );
149 105         78 my $avc_packet_type;
150 105         186 ( $avc_packet_type, $avc_time[0], $avc_time[1], $avc_time[2] ) =
151             unpack 'CCCC', $avc_header;
152 105         133 my $composition_time =
153             ( $avc_time[0] * 256 + $avc_time[1] ) * 256 + $avc_time[2];
154 105         113 $avc_packet_type = $avc_packet_type{$avc_packet_type};
155 105 100 100     360 $if_real_frame = 0 if $avc_packet_type eq 'avc_seq_header' or $avc_packet_type eq 'avc_seq_end';
156             }
157 105 100       203 $flv_info{frame_count}++ if $if_real_frame;
158             }
159             elsif ( $tag_type eq 'script' ) {
160 1         4 my %meta_info = extract_amf0($buf);
161 1         5 foreach (keys %meta_info)
162             {
163 14         22 $flv_info{$_} = $meta_info{$_};
164             }
165             }
166             else {
167             }
168              
169 171         627 read( FH, $buf, 4 ); # jump PreviousTagSize
170             }
171 1         25 return %flv_info;
172             }
173              
174             sub extract_amf0
175             {
176 1     1 0 2 my %amf0;
177 1         2 $amf0{data} = shift;
178 1         2 $amf0{pos} = 0;
179              
180 1         21 my %data;
181              
182 1         4 my $type = ord(amf0_read(\%amf0, 1));
183 1 50       4 if($type == 2)
184             {
185 1         3 my $string = amf0_read_string(\%amf0);
186             }
187 1         3 amf0_read_unit(\%amf0);
188              
189 1         11 while( length($amf0{data}) > $amf0{pos} )
190             {
191 14         22 my $key = amf0_read_string(\%amf0);
192 14         517 my $value = amf0_read_unit(\%amf0);
193 14         42 $data{$key} = $value;
194             }
195 1         12 return %data;
196             }
197              
198             sub amf0_read_unit
199             {
200 15     15 0 16 my $amf0 = shift;
201              
202 15         20 my $type = ord(amf0_read($amf0, 1));
203 15 100       70 if($type == 8)
    100          
    100          
    100          
204             {
205 1         3 amf0_read($amf0, 4);
206 1         1 return 1;
207             }
208             elsif($type == 2)
209             {
210 1         1 my $string = amf0_read_string($amf0);
211 1         2 return $string;
212             }
213             elsif ($type == 1)
214             {
215 1         2 my $boolean = amf0_read_boolean($amf0);
216 1         2 return $boolean;
217             }
218             elsif ($type == 0)
219             {
220 11         15 my $double = amf0_read_double($amf0);
221 11         18 return $double;
222             }
223              
224             }
225              
226             sub amf0_read
227             {
228 77     77 0 71 my $amf0 = shift;
229 77         94 my $read_bytes = shift;
230              
231 77         105 my $bytes = substr($amf0->{data}, $amf0->{pos}, $read_bytes);
232 77         77 $amf0->{pos} += $read_bytes;
233              
234 77         149 return $bytes;
235             }
236              
237             sub amf0_read_int
238             {
239 16     16 0 16 my $amf0 = shift;
240              
241 16         19 my $first_byte = amf0_read($amf0, 1);
242 16         22 my $second_byte = amf0_read($amf0, 1);
243              
244 16 50       29 my $first_num = defined($first_byte) ? ord($first_byte) : 0;
245 16 50       22 my $second_num = defined($second_byte) ? ord($second_byte) : 0;
246            
247 16         18 my $amf0_int = (($first_num) << 8) | $second_num;
248 16         24 return $amf0_int;
249             }
250              
251             sub amf0_read_boolean
252             {
253 1     1 0 2 my $amf0 = shift;
254 1         3 my $data = amf0_read($amf0, 1);
255 2     2   11 no warnings 'numeric';
  2         4  
  2         482  
256 1 50       5 my $boolean = $data == 1 ? 1 : 0;
257 1         2 return $boolean;
258             }
259              
260             sub amf0_read_string
261             {
262 16     16 0 18 my $amf0 = shift;
263 16         23 my $string_length = amf0_read_int($amf0);
264 16         24 my $string = amf0_read($amf0, $string_length);
265 16         25 return $string;
266             }
267              
268             sub amf0_read_double
269             {
270 11     11 0 13 my $amf0 = shift;
271 11         16 my @data = split //, amf0_read($amf0, 8);
272 11         12 my $data;
273 11         16 foreach (reverse @data)
274             {
275 88 100       133 $_ = "0" unless $_;
276 88         86 $data .= $_;
277             }
278 11         28 my @zz = unpack("d", $data);
279 11         25 return $zz[0];
280             }
281              
282              
283             1;
284             __END__