/[amv]/amv.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /amv.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (show annotations)
Fri Jul 20 16:07:46 2007 UTC (11 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 10723 byte(s)
cleanup dir, generate different huffman tables
1 #!/usr/bin/perl -w
2
3 # amv.pl
4 #
5 # 07/19/07 19:21:39 CEST Dobrica Pavlinusic <dpavlin@rot13.org>
6 #
7 # Various useful links used to produce this:
8 # http://www.moviecodec.com/topics/15431p1.html
9 # http://en.wikipedia.org/wiki/RIFF_(File_format)
10 # http://www.obrador.com/essentialjpeg/HeaderInfo.htm
11 # http://lists.helixcommunity.org/pipermail/datatype-dev/2005-January/001886.html
12
13 use strict;
14
15 use Data::Dump qw/dump/;
16 use Carp qw/confess/;
17 use File::Path;
18
19 my $dump = 0;
20 my $debug = 0;
21
22 my $path = shift @ARGV || die "usage: $0 movie.amv\n";
23
24 my $dump_dir = '/tmp/dump/';
25 rmtree $dump_dir if -e $dump_dir;
26 mkpath $dump_dir || die "can't create $dump_dir: $!";
27
28 open(my $fh, '<', $path) || die "can't open $path: $!";
29
30 # offset in file
31 my $o = 0;
32
33 # shared data hash
34 my $d;
35
36 sub hex_dump {
37 return unless $dump;
38
39 my ( $bytes, $offset ) = @_;
40 return unless $bytes;
41
42 my $old_o;
43 if (defined($offset)) {
44 $old_o = $o;
45 $o = $offset;
46 }
47
48 my $ascii = $bytes;
49 $ascii =~ s/\W/./gs;
50 my $hex = uc( unpack('h*', $bytes) );
51 $hex =~ s/(..)/$1 /g;
52 # calculate number of characters for offset
53 #my $d = length( sprintf("%x",length($bytes)) );
54 my $d = 4;
55 my $prefix = '#.';
56 while ( $hex =~ s/^((?:\w\w\s){1,16})// ) {
57 printf "$prefix %0${d}x | %-48s| %s\n", $o, $1, substr( $ascii, 0, 16 );
58 $prefix = '##';
59 if ( length($ascii) >= 16 ) {
60 $ascii = substr( $ascii, 16 );
61 $o += 16;
62 } else {
63 $o += length($ascii);
64 last;
65 }
66 }
67
68 $o = $old_o if $old_o;
69 }
70
71 sub x {
72 my ($len,$format) = @_;
73
74 my $bytes;
75 read($fh, $bytes, $len);
76
77 my $r_len = length($bytes);
78 confess "read $r_len bytes, expected $len" if $len != $r_len;
79
80 hex_dump( $bytes );
81
82 if ( $bytes eq 'AMV_END_' ) {
83 warn "> end of file marker AMV_END_\n";
84 $d->{eof}++;
85 return;
86 }
87
88 if ( $format ) {
89 my @data = unpack($format, $bytes);
90 warn "## unpacked = ",dump(@data),"\n" if $debug;
91 return @data;
92 } else {
93 return $bytes;
94 }
95 }
96
97 sub next_part {
98 my ( $expected_part, $expected_len, $skip ) = @_;
99 my ( $part, $len ) = x(8,'A4V');
100 return unless $len;
101 confess "not $expected_part but $part" if $expected_part ne $part;
102 if ( $expected_len ) {
103 confess "expected $expected_len bytes for $part got $len" if $len != $expected_len;
104 }
105 printf "<< %s - %d 0x%x bytes\n", $part, $len, $len;
106 x($len) if $skip;
107 return $len;
108 }
109
110 sub huffman {
111
112 # JPEG DHT Segment for YCrCb omitted from MJPG data
113 return
114 "\xFF\xC4\x01\xA2" .
115 "\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00" .
116 "\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x01" .
117 "\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" .
118 "\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x10\x00" .
119 "\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01\x7D" .
120 "\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06\x13\x51\x61" .
121 "\x07\x22\x71\x14\x32\x81\x91\xA1\x08\x23\x42\xB1\xC1\x15\x52" .
122 "\xD1\xF0\x24\x33\x62\x72\x82\x09\x0A\x16\x17\x18\x19\x1A\x25" .
123 "\x26\x27\x28\x29\x2A\x34\x35\x36\x37\x38\x39\x3A\x43\x44\x45" .
124 "\x46\x47\x48\x49\x4A\x53\x54\x55\x56\x57\x58\x59\x5A\x63\x64" .
125 "\x65\x66\x67\x68\x69\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x83" .
126 "\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98\x99" .
127 "\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5\xB6" .
128 "\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2\xD3" .
129 "\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8" .
130 "\xE9\xEA\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\x11\x00\x02" .
131 "\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02\x77\x00" .
132 "\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41\x51\x07\x61\x71" .
133 "\x13\x22\x32\x81\x08\x14\x42\x91\xA1\xB1\xC1\x09\x23\x33\x52" .
134 "\xF0\x15\x62\x72\xD1\x0A\x16\x24\x34\xE1\x25\xF1\x17\x18\x19" .
135 "\x1A\x26\x27\x28\x29\x2A\x35\x36\x37\x38\x39\x3A\x43\x44\x45" .
136 "\x46\x47\x48\x49\x4A\x53\x54\x55\x56\x57\x58\x59\x5A\x63\x64" .
137 "\x65\x66\x67\x68\x69\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x82" .
138 "\x83\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98" .
139 "\x99\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5" .
140 "\xB6\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2" .
141 "\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE2\xE3\xE4\xE5\xE6\xE7\xE8" .
142 "\xE9\xEA\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA";
143
144 }
145
146 sub mkjpg {
147 my ($path,$data) = @_;
148 open(my $fh, '>', $path) || die "can't create $path: $!";
149
150 confess "no SOI marker in data" if substr($data,0,2) ne "\xFF\xD8";
151 $data = substr($data,2);
152
153 my $header =
154 "\xFF\xD8". # Start of Image (SOI) marker
155 #------------------------------------------------------------------
156 "\xFF\xE0". # JFIF marker
157 pack("nZ5CCCnnCC",
158 16, # length
159 'JFIF', # identifier
160 1,1, # version
161 0, # units (none)
162 1,1, # X,Y density
163 0,0, # X,Y thumbnail
164 ).
165 #------------------------------------------------------------------
166 "\xFF\xC0". # Start of frame
167 pack("ncnncc9",
168 17, # len
169 8, # sample precision in bits
170 120,160, # X,Y size
171 3, # number of components
172 1,0x21,0, # Component ID, H+V sampling factors, Quantization table number
173 2,0x11,1,
174 3,0x11,1,
175 ).
176 #------------------------------------------------------------------
177 "\xFF\xDB". # Define Quantization table marker
178 "\x00\x84". # len
179 "\x00". # 8 bit values, (byte) table 0
180 "\x10\x0B\x0C\x0E\x0C".
181 "\x0A\x10\x0E\x0D\x0E".
182 "\x12\x11\x10\x13\x18".
183 "\x28\x1A\x18\x16\x16".
184 "\x18\x31\x23\x25\x1D".
185 "\x28\x3A\x33\x3D\x3C".
186 "\x39\x33\x38\x37\x40".
187 "\x48\x5C\x4E\x40\x44".
188 "\x57\x45\x37\x38\x50".
189 "\x6D\x51\x57\x5F\x62".
190 "\x67\x68\x67\x3E\x4D".
191 "\x71\x79\x70\x64\x78".
192 "\x5C\x65\x67\x63".
193 "\x01". # 8 bit values, (byte) table 1
194 "\x11\x12\x12\x18\x15".
195 "\x18\x2F\x1A\x1A\x2F".
196 "\x63\x42\x38\x42\x63".
197 "\x63\x63\x63\x63\x63".
198 "\x63\x63\x63\x63\x63".
199 "\x63\x63\x63\x63\x63".
200 "\x63\x63\x63\x63\x63".
201 "\x63\x63\x63\x63\x63".
202 "\x63\x63\x63\x63\x63".
203 "\x63\x63\x63\x63\x63".
204 "\x63\x63\x63\x63\x63".
205 "\x63\x63\x63\x63\x63".
206 "\x63\x63\x63\x63".
207 #------------------------------------------------------------------
208 # huffman("\x00"). # 0 DC
209 # huffman("\x01"). # 1 DC
210 # huffman("\x10"). # 0 AC
211 # huffman("\x11"). # 1 AC
212 #------------------------------------------------------------------
213 # Define huffman table (section B.2.4.1)
214 "\xFF\xC4". # Marker
215 "\x00\x1F". # Length (31 bytes)
216 "\x00". # DC, (byte) table 0
217 "\x00\x01\x05\x01\x01".
218 "\x01\x01\x01\x01\x00".
219 "\x00\x00\x00\x00\x00".
220 "\x00\x00\x01\x02\x03".
221 "\x04\x05\x06\x07\x08".
222 "\x09\x0A\x0B".
223 # Define huffman table (section B.2.4.1)
224 "\xFF\xC4". # Marker
225 "\x00\xB5". # Length (181 bytes)
226 "\x10". # AC, (byte) table 0
227 "\x00\x02\x01\x03\x03".
228 "\x02\x04\x03\x05\x05".
229 "\x04\x04\x00\x00\x01".
230 "\x7D\x01\x02\x03\x00".
231 "\x04\x11\x05\x12\x21".
232 "\x31\x41\x06\x13\x51".
233 "\x61\x07\x22\x71\x14".
234 "\x32\x81\x91\xA1\x08".
235 "\x23\x42\xB1\xC1\x15".
236 "\x52\xD1\xF0\x24\x33".
237 "\x62\x72\x82\x09\x0A".
238 "\x16\x17\x18\x19\x1A".
239 "\x25\x26\x27\x28\x29".
240 "\x2A\x34\x35\x36\x37".
241 "\x38\x39\x3A\x43\x44".
242 "\x45\x46\x47\x48\x49".
243 "\x4A\x53\x54\x55\x56".
244 "\x57\x58\x59\x5A\x63".
245 "\x64\x65\x66\x67\x68".
246 "\x69\x6A\x73\x74\x75".
247 "\x76\x77\x78\x79\x7A".
248 "\x83\x84\x85\x86\x87".
249 "\x88\x89\x8A\x92\x93".
250 "\x94\x95\x96\x97\x98".
251 "\x99\x9A\xA2\xA3\xA4".
252 "\xA5\xA6\xA7\xA8\xA9".
253 "\xAA\xB2\xB3\xB4\xB5".
254 "\xB6\xB7\xB8\xB9\xBA".
255 "\xC2\xC3\xC4\xC5\xC6".
256 "\xC7\xC8\xC9\xCA\xD2".
257 "\xD3\xD4\xD5\xD6\xD7".
258 "\xD8\xD9\xDA\xE1\xE2".
259 "\xE3\xE4\xE5\xE6\xE7".
260 "\xE8\xE9\xEA\xF1\xF2".
261 "\xF3\xF4\xF5\xF6\xF7".
262 "\xF8\xF9\xFA".
263 # Define huffman table (section B.2.4.1)
264 "\xFF\xC4". # Marker
265 "\x00\x1F". # Length (31 bytes)
266 "\x01". # DC, (byte) table 1
267 "\x00\x03\x01\x01\x01".
268 "\x01\x01\x01\x01\x01".
269 "\x01\x00\x00\x00\x00".
270 "\x00\x00\x01\x02\x03".
271 "\x04\x05\x06\x07\x08".
272 "\x09\x0A\x0B".
273 # Define huffman table (section B.2.4.1)
274 "\xFF\xC4". # Marker
275 "\x00\xB5". # Length (181 bytes)
276 "\x11". # AC, (byte) table 1
277 "\x00\x02\x01\x02\x04".
278 "\x04\x03\x04\x07\x05".
279 "\x04\x04\x00\x01\x02".
280 "\x77\x00\x01\x02\x03".
281 "\x11\x04\x05\x21\x31".
282 "\x06\x12\x41\x51\x07".
283 "\x61\x71\x13\x22\x32".
284 "\x81\x08\x14\x42\x91".
285 "\xA1\xB1\xC1\x09\x23".
286 "\x33\x52\xF0\x15\x62".
287 "\x72\xD1\x0A\x16\x24".
288 "\x34\xE1\x25\xF1\x17".
289 "\x18\x19\x1A\x26\x27".
290 "\x28\x29\x2A\x35\x36".
291 "\x37\x38\x39\x3A\x43".
292 "\x44\x45\x46\x47\x48".
293 "\x49\x4A\x53\x54\x55".
294 "\x56\x57\x58\x59\x5A".
295 "\x63\x64\x65\x66\x67".
296 "\x68\x69\x6A\x73\x74".
297 "\x75\x76\x77\x78\x79".
298 "\x7A\x82\x83\x84\x85".
299 "\x86\x87\x88\x89\x8A".
300 "\x92\x93\x94\x95\x96".
301 "\x97\x98\x99\x9A\xA2".
302 "\xA3\xA4\xA5\xA6\xA7".
303 "\xA8\xA9\xAA\xB2\xB3".
304 "\xB4\xB5\xB6\xB7\xB8".
305 "\xB9\xBA\xC2\xC3\xC4".
306 "\xC5\xC6\xC7\xC8\xC9".
307 "\xCA\xD2\xD3\xD4\xD5".
308 "\xD6\xD7\xD8\xD9\xDA".
309 "\xE2\xE3\xE4\xE5\xE6".
310 "\xE7\xE8\xE9\xEA\xF2".
311 "\xF3\xF4\xF5\xF6\xF7".
312 "\xF8\xF9\xFA".
313 #------------------------------------------------------------------
314 "\xFF\xDA". # Start of Scan marker
315 pack("nC11",
316 12, # length
317 3, # number of components
318 1,0x00, # Scan 1: use DC/AC huff tables 0/0
319 2,0x11, # Scan 2: use DC/AC huff tables 1/1
320 3,0x11, # Scan 3: use DC/AC huff tables 1/1
321 0,0x3f, # Ss, Se
322 0, # Ah, Ai (not used)
323 );
324 #------------------------------------------------------------------
325
326
327 if ( $dump ) {
328 warn "## created JPEG header...\n";
329 hex_dump( $header, 0 );
330 }
331
332 print $fh $header || die "can't write header into $path: $!";
333 print $fh $data || die "can't write frame into $path: $!";
334 close $fh || die "can't close $path: $!";
335 print ">> created $path ", -s $path, " bytes\n";
336 }
337
338 my ( $riff, $amv ) = x(12, 'Z4x4Z4');
339 die "$path not RIFF but $riff" if $riff ne 'RIFF';
340 die "$path not AMV but $amv" if $amv ne 'AMV ';
341
342 while ( ! defined($d->{eof}) ) {
343 my ( $list, $name ) = x(12,'A4x4A4');
344 die "not LIST but $list" if $list ne 'LIST';
345 print "< $list * $name\n";
346
347 if ( $name eq 'hdrl' ) {
348
349 my $len = next_part( 'amvh', hex(38) );
350
351 my @names = ( qw/ms_per_frame width height fps ss mm hh/ );
352 my $h;
353 map {
354 my $v = $_;
355 my $n = shift @names || die "no more names?";
356 $h->{$n} = $v;
357 } x($len, 'Vx28VVVx8CCv');
358
359 printf "## %s %d*%d %s fps (%d ms/frame) %02d:%02d:%02d\n",
360 $path,
361 $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},
362 $h->{hh}, $h->{mm}, $h->{ss};
363
364 $d->{amvh} = $h;
365
366 } elsif ( $name eq 'strl' ) {
367
368 next_part( 'strh', 0, 1 );
369 next_part( 'strf', 0, 1 );
370
371 } elsif ( $name eq 'movi' ) {
372
373 while (1) {
374 my $frame = $d->{movi}++;
375
376 my $len = next_part( '00dc' );
377 last unless $len;
378 printf "<< %s 00dc - frame %d jpeg %d 0x%x bytes\n", $name, $frame, $len, $len;
379 mkjpg( sprintf("$dump_dir/%03d.jpg", $frame ), x($len) );
380
381 $len = next_part( '01wb', 0, 1 );
382 printf "<< %s 01wb - frame %d audio %d 0x%x bytes\n", $name, $frame, $len, $len;
383 };
384
385 } else {
386 die "unknown $list $name";
387 }
388 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26