File Coverage

blib/lib/Video/Info/ASF.pm
Criterion Covered Total %
statement 209 216 96.7
branch 53 74 71.6
condition 8 13 61.5
subroutine 33 33 100.0
pod 0 3 0.0
total 303 339 89.3


line stmt bran cond sub pod time code
1             package Video::Info::ASF;
2              
3 2     2   22956 use strict;
  2         5  
  2         123  
4 2     2   12 use constant DEBUG => 0;
  2         4  
  2         182  
5             our $VERSION = '1.01';
6              
7 2     2   807 use Video::Info;
  2         7  
  2         80  
8              
9 2     2   16 use base qw(Video::Info);
  2         6  
  2         292  
10              
11             #########################################################
12             # ASF GUID signatures
13             #
14             #base ASF object guids
15 2     2   13 use constant Header => 0x75b22630;
  2         5  
  2         123  
16 2     2   11 use constant data => 0x75b22636;
  2         4  
  2         667  
17 2     2   14 use constant simple_index => 0x33000890;
  2         43  
  2         125  
18              
19             #header object guids
20 2     2   12 use constant file_properties => 0x8cabdca1;
  2         3  
  2         106  
21 2     2   12 use constant stream_properties => 0xb7dc0791;
  2         2  
  2         95  
22 2     2   11 use constant stream_bitrate_properties => 0x7bf875ce;
  2         5  
  2         85  
23 2     2   29 use constant content_description => 0x75b22633;
  2         5  
  2         91  
24 2     2   11 use constant extended_content_encryption => 0x298ae614;
  2         3  
  2         84  
25 2     2   9 use constant script_command => 0x1efb1a30;
  2         4  
  2         191  
26 2     2   22 use constant marker => 0xf487cd01;
  2         3  
  2         95  
27 2     2   10 use constant header_extension => 0x5fbf03b5;
  2         14  
  2         103  
28 2     2   9 use constant bitrate_mutual_exclusion => 0xd6e229dc;
  2         5  
  2         90  
29 2     2   10 use constant codec_list => 0x86d15240;
  2         5  
  2         94  
30 2     2   11 use constant extended_content_description => 0xd2d0a440;
  2         2  
  2         93  
31 2     2   11 use constant error_correction => 0x75b22635;
  2         3  
  2         256  
32 2     2   11 use constant stream_bitrate_porperties => 0x7bf875ce;
  2         5  
  2         92  
33 2     2   10 use constant padding => 0x1806d474;
  2         10  
  2         88  
34              
35             #stream properties object stream type guids
36 2     2   11 use constant audio_media => 0xf8699e40;
  2         4  
  2         94  
37 2     2   11 use constant video_media => 0xbc19efc0;
  2         3  
  2         106  
38 2     2   10 use constant command_media => 0x59dacfc0;
  2         4  
  2         146  
39              
40             #stream properties object error correction type guids
41 2     2   17 use constant no_error_correction => 0x20fb5700;
  2         8  
  2         207  
42 2     2   11 use constant audio_spread => 0xbfc3cd50;
  2         3  
  2         105  
43              
44             #mutual exclusion object exclusion type guids
45 2     2   11 use constant mutex_bitrate => 0xd6e22a01;
  2         3  
  2         81  
46 2     2   11 use constant mutex_unknown => 0xd6e22a02;
  2         2  
  2         91  
47              
48             #from mplayer
49 2     2   11 use constant audio_conceal_none => 0x49f1a440;
  2         4  
  2         87  
50 2     2   10 use constant header_2_0 => 0xD6E229D1;
  2         4  
  2         16958  
51             #########################################################
52              
53             sub header {
54 6     6 0 8800 my $self = shift;
55 6         13 my $val = shift;
56 6 50       22 return undef unless ref $self;
57 6 100       29 return $self->{header} unless $val;
58 4         10 $self->{header} = $val;
59 4         6 return $val;
60             }
61              
62             ##------------------------------------------------------------------------
63             ## probe()
64             ##
65             ## Obtain the filehandle from Video::Info and extract the properties from
66             ## the ASF structure.
67             ##------------------------------------------------------------------------
68             sub init {
69 3     3 0 9 my $self = shift;
70              
71 3         22 $self->init_attributes(@_);
72 3         28 return $self;
73             }
74              
75             sub probe {
76 4     4 0 2972 my $self = shift;
77 4         18 my $fh = $self->handle; ## inherited from Video::Info
78 4         169 my $header;
79              
80 4         67 sysread($fh,$header,24);# or die "died probe(): $!";
81              
82 4 50       32 die "not an ASF" unless unpack("V",substr($header,0,4)) == Header;
83 4         120 $self->type('ASF');
84 4         38 my($h1,$h2) = unpack("VV",substr($header,16,8));
85 4         11 my $headersize = ($h2 * 0xffffffff) + $h1;
86 4         94 my $bytes = sysread($fh,$header,$headersize,24);
87 4 50       14 die "probe() sysread: $!" unless $bytes = $headersize;
88             #warn length($header);
89             #exit;
90 4         15 $self->header($header);
91              
92 4         9 my %guid = ();
93              
94 4         17 for(0..$headersize-5){
95 6928         11875 my $window = substr($header,$_,4);
96              
97 6928 100       19112 $guid{codec_list} = $_ if(unpack("V",$window)) == codec_list;
98 6928 100       17547 $guid{header} = $_ if(unpack("V",$window)) == Header;
99 6928 100       40051 $guid{audio_media} = $_ if(unpack("V",$window)) == audio_media;
100 6928 100       19334 $guid{video_media} = $_ if(unpack("V",$window)) == video_media;
101 6928 50       14626 $guid{audio_conceal_none} = $_ if(unpack("V",$window)) == audio_conceal_none;
102 6928 100       14413 $guid{audio_spread} = $_ if(unpack("V",$window)) == audio_spread;
103 6928 100       22498 $guid{content_description}= $_ if(unpack("V",$window)) == content_description;
104 6928 50       18035 $guid{data} = $_ if(unpack("V",$window)) == data;
105 6928 50       16394 $guid{simple_index} = $_ if(unpack("V",$window)) == simple_index;
106 6928 100       26150 $guid{stream_properties} = $_ if(unpack("V",$window)) == stream_properties;
107 6928 50       27966 $guid{header_2_0} = $_ if(unpack("V",$window)) == header_2_0;
108 6928 100       17131 $guid{file_properties} = $_ if(unpack("V",$window)) == file_properties;
109             }
110              
111 4         39 my @guids = map {$_->[0]} sort {$a->[1] <=> $b->[1]} map {[$_,$guid{$_}]} keys %guid;
  31         94  
  61         91  
  31         296  
112              
113 4         37 for(my $i=0;$i
114 31         137 my $thisguid = $guids[$i];
115 31         53 my $nextguid = $guids[$i+1];
116             #print $thisguid,"\t",$nextguid,"\n";
117              
118 31         47 my $thisguidpos = $guid{$thisguid};
119 31 100       66 my $nextguidpos = $nextguid ? $guid{$nextguid} : length($header);
120              
121 31         88 my $head = substr($header,$thisguidpos,$nextguidpos - $thisguidpos - 1);
122              
123 31         66 my $guid = unpack("V",substr($head,0,4));
124              
125             #warn "guid $thisguid: ".$thisguidpos."-".$nextguidpos;
126              
127 31 100 100     199 if($guid == Header){
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    0          
    0          
    0          
128 4         31 warn "Header" if DEBUG;
129             #noop yet. we should switch modes depending on whether or not we have a 1.0 or 2.0 header
130             } elsif($guid == header_2_0){
131 0         0 warn "Header 2.0" if DEBUG;
132             #no exmple yet
133 0         0 die "header_2_0. Please email allenday\@ucla.edu";
134             }
135              
136             elsif($guid == codec_list){
137 3         13 warn "codec_list" if DEBUG;
138 3 50       19 next unless length($head) >= 40; #prevent substr() errors on bad headers
139 3         9 my($codecs) = unpack("V",substr($head,40,4));
140              
141             #print $head, "\n";
142              
143             #print "\ttotal codecs: $codecs\n";
144              
145 3         6 my $offset = 44;
146 3         6 my $i = 0;
147 3         9 while($i < $codecs){
148 6         16 my($type,$namelen) = unpack("vv",substr($head,$offset,4)); $offset += 4;
  6         11  
149              
150             #print "\tcodec type: $type ";
151             #print $type == 0x0000 ? "video\n" : #this is not standard by ASF 1.0
152             # $type == 0x0001 ? "video\n" :
153             # $type == 0x0002 ? "audio\n" :
154             # $type == 0xffff ? "unknown\n" : "huh?\n";
155              
156 6         7 $namelen *= 2; #because it is a unicode string
157 6         12 my $name = substr($head,$offset,$namelen); $offset += $namelen;
  6         10  
158              
159             #print "\t\tname $namelen: $name\n";
160 6 100 66     26 if($type == 0x0000 || $type == 0x0001){
161 3   33     82 $self->vcodec($self->vcodec || $name);
162 3   50     194 $self->vstreams( ($self->vstreams || 0) + 1);
163             }
164              
165 6 100       133 if($type == 0x0002){
166 3 50       14 $self->acodec($name) unless $self->acodec;
167 3   50     97 $self->astreams( ($self->astreams || 0) + 1);
168             }
169              
170             #we don't worry about these (for now)
171 6         148 my($desclen) = unpack("v",substr($head,$offset,2));
172 6         10 $desclen *= 2;
173 6         13 my $desc = substr($head,$offset,$desclen); $offset += $desclen;
  6         8  
174             #print "\t\tdesc: $desc\n";
175              
176 6         21 my($infolen) = unpack("v",substr($head,$offset,2));
177 6         7 $infolen *= 2;
178 6         13 my $info = substr($head,$offset,$infolen); $offset += $infolen;
  6         7  
179             #print "\t\tinfo: $info\n";
180              
181 6         24 $i++;
182             }
183             }
184              
185             elsif($guid == file_properties){
186 4         9 warn "file_properties" if DEBUG;
187 4 50       17 next unless length($head) >= 32; #prevent substr() errors on bad headers
188              
189 4         21 my($size1,$size2,$date1,$date2,$count1,$count2,$dur1,$dur2) = unpack("VVVVVVVV",substr($head,40,32));
190 4         12 my($maxbitrate) = unpack("V",substr($head,100,4));
191              
192             #these are 64bit values, so we have to put them together manually.
193             #some systems (like mine) don't support q and Q unpacking.
194 4         13 my $size = ($size2 * 0xffffffff) + $size1; #filesize in bytes
195 4         15 my $date = (($date2 * 0xffffffff) + $date1) / 1_000; #creation time. i have no idea what format --aday
196 4         9 my $count = ($count2 * 0xffffffff)+ $count1; #number of data packets in the data object
197 4         11 my $dur = (($dur2 * 0xffffffff) + $dur1) / 10_000_000; #was in 100 nanosecond units, zheesh
198              
199             #print "\tsize: $size\n";
200 4         1719 $self->date($date);
201             #print "\tdate: ".$self->date."\n";
202 4         335 $self->packets($count);
203             #print "\tcount: ".$self->count."\n";
204 4         149 $self->duration($dur);
205             #print "\tduration: ".$self->duration."\n";
206 4         146 $self->vrate($maxbitrate);
207             #print "\tmax bitrate: ".$self->vrate."\n";
208             }
209              
210             elsif($guid == content_description){
211 4         8 warn "content_description" if DEBUG;
212 4 50       19 next unless length($head) >= 34; #prevent substr() errors on bad headers
213 4         6 my $offset = 34;
214 4         55 my($titlelen,$authlen,$copylen,$desclen,$ratlen) = unpack("vvvvv",substr($head,24,10));
215 4         13 my $title = substr($head,$offset,$titlelen); $offset += $titlelen;
  4         7  
216 4         11 my $author = substr($head,$offset,$authlen); $offset += $authlen;
  4         6  
217 4         9 my $copyright = substr($head,$offset,$copylen); $offset += $copylen;
  4         7  
218 4         11 my $description = substr($head,$offset,$desclen); $offset += $desclen;
  4         6  
219 4         10 my $rating = substr($head,$offset,$ratlen);
220              
221 4         182 $self->title($title);
222 4         155 $self->author($author);
223 4         226 $self->copyright($copyright);
224 4         146 $self->description($description);
225 4         156 $self->rating($rating);
226             }
227              
228             elsif($guid == video_media){
229 4         90 warn "video_media" if DEBUG;
230 4 50       30 next unless length($head) >= 16; #prevent substr() errors on bad headers
231              
232 4         12 my $codec = substr($head,81,4); #hack. is it really at 81? should be at 16 from 1.0 spec.
233 4         135 $self->vcodec($codec);
234            
235 4         44 my($width,$height,$bpp,$colors) = unpack("VVxxvxxxxxxxxxxxxxxxxV",substr($head,54,32));
236              
237 4         118 $self->width($width);
238 4         138 $self->height($height);
239              
240             #print "\tbpp: $bpp\n";
241             #print "\tcompression ID: $codec\n";
242             #print "\tcolors used: $colors\n";
243             }
244              
245             elsif($guid == audio_spread || $guid == audio_media){
246 8         9 warn "audio" if DEBUG;
247 8 100       39 next unless length($head) >= 18; #prevent substr() errors on bad headers
248 4         19 my($codecID,$achan,$samp,$bpsec,$blk,$bpsamp,$format) = unpack("vvVVvvv",substr($head,38,18));
249              
250             #print "\tcodec ID: $codecID\n";
251             #$self->acodec($codecID) unless $self->acodec; #???
252             #print "\tcodec : ".$self->acodec."\n";
253             #print "\taudio channels: $achan\n";
254 4         120 $self->achans($achan);
255             #print "\tsample rate: $samp\n";
256             #print "\tbytes/second: $bpsec\n";
257 4         151 $self->arate($bpsec * 8);
258             #print "\tblock alignment: $blk\n";
259             #print "\tbits/sample: $bpsamp\n";
260             #print "\tformat: $format\n";
261 4         98 $self->acodec($format);
262             }
263              
264             elsif($guid == script_command) {
265 0         0 warn "script_command" if DEBUG;
266             #hmm, interesting
267 0         0 warn "*********************script_command";
268             # my($rawsize1,$rawsize2) = unpack("VV",substr($head,16,8));
269             # my $objsize = (($rawsize2 * 0xffffffff) + $rawsize1);
270             # my $obj =
271             }
272              
273             elsif($guid == stream_properties){
274 4         13 warn "stream_properties" if DEBUG;
275             #noop
276             }
277              
278             elsif($guid == data){
279 0         0 warn "data" if DEBUG;
280             #noop, this is the movie itself
281             }
282              
283             elsif($guid == simple_index){
284 0         0 warn "simple_index" if DEBUG;
285             #no example yet
286             #warn "******************simple_index";
287             }
288              
289             elsif($guid == audio_conceal_none){
290 0         0 warn "audio_conceal_none" if DEBUG;
291             #no example yet
292             #warn "******************audio_conceal_none";
293             }
294             }
295              
296 4         41 return 1;
297             }
298              
299             1;
300              
301             __END__