/[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

Annotation of /amv.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (hide annotations)
Fri Jul 20 16:07:46 2007 UTC (16 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 10723 byte(s)
cleanup dir, generate different huffman tables
1 dpavlin 3 #!/usr/bin/perl -w
2    
3     # amv.pl
4     #
5     # 07/19/07 19:21:39 CEST Dobrica Pavlinusic <dpavlin@rot13.org>
6 dpavlin 7 #
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 dpavlin 8 # http://www.obrador.com/essentialjpeg/HeaderInfo.htm
11     # http://lists.helixcommunity.org/pipermail/datatype-dev/2005-January/001886.html
12 dpavlin 3
13     use strict;
14    
15     use Data::Dump qw/dump/;
16     use Carp qw/confess/;
17 dpavlin 8 use File::Path;
18 dpavlin 3
19 dpavlin 8 my $dump = 0;
20     my $debug = 0;
21    
22 dpavlin 3 my $path = shift @ARGV || die "usage: $0 movie.amv\n";
23    
24 dpavlin 8 my $dump_dir = '/tmp/dump/';
25 dpavlin 11 rmtree $dump_dir if -e $dump_dir;
26     mkpath $dump_dir || die "can't create $dump_dir: $!";
27 dpavlin 8
28 dpavlin 3 open(my $fh, '<', $path) || die "can't open $path: $!";
29    
30 dpavlin 4 # offset in file
31     my $o = 0;
32    
33     # shared data hash
34     my $d;
35    
36 dpavlin 3 sub hex_dump {
37 dpavlin 8 return unless $dump;
38 dpavlin 3
39 dpavlin 8 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 dpavlin 3 my $ascii = $bytes;
49     $ascii =~ s/\W/./gs;
50 dpavlin 8 my $hex = uc( unpack('h*', $bytes) );
51 dpavlin 3 $hex =~ s/(..)/$1 /g;
52     # calculate number of characters for offset
53 dpavlin 4 #my $d = length( sprintf("%x",length($bytes)) );
54     my $d = 4;
55 dpavlin 6 my $prefix = '#.';
56 dpavlin 3 while ( $hex =~ s/^((?:\w\w\s){1,16})// ) {
57 dpavlin 6 printf "$prefix %0${d}x | %-48s| %s\n", $o, $1, substr( $ascii, 0, 16 );
58     $prefix = '##';
59 dpavlin 3 if ( length($ascii) >= 16 ) {
60     $ascii = substr( $ascii, 16 );
61 dpavlin 4 $o += 16;
62 dpavlin 3 } else {
63 dpavlin 4 $o += length($ascii);
64 dpavlin 3 last;
65     }
66     }
67 dpavlin 8
68     $o = $old_o if $old_o;
69 dpavlin 3 }
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 dpavlin 4 if ( $bytes eq 'AMV_END_' ) {
83 dpavlin 5 warn "> end of file marker AMV_END_\n";
84 dpavlin 4 $d->{eof}++;
85     return;
86     }
87    
88 dpavlin 3 if ( $format ) {
89     my @data = unpack($format, $bytes);
90 dpavlin 8 warn "## unpacked = ",dump(@data),"\n" if $debug;
91 dpavlin 3 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 dpavlin 4 return unless $len;
101 dpavlin 3 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 dpavlin 8 printf "<< %s - %d 0x%x bytes\n", $part, $len, $len;
106 dpavlin 3 x($len) if $skip;
107     return $len;
108     }
109    
110 dpavlin 8 sub huffman {
111 dpavlin 3
112 dpavlin 8 # 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 dpavlin 11 "\xFF\xC0". # Start of frame
167 dpavlin 8 pack("ncnncc9",
168     17, # len
169     8, # sample precision in bits
170     120,160, # X,Y size
171     3, # number of components
172 dpavlin 11 1,0x21,0, # Component ID, H+V sampling factors, Quantization table number
173     2,0x11,1,
174     3,0x11,1,
175 dpavlin 8 ).
176     #------------------------------------------------------------------
177 dpavlin 11 "\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 dpavlin 8 # huffman("\x00"). # 0 DC
209 dpavlin 11 # huffman("\x01"). # 1 DC
210 dpavlin 8 # huffman("\x10"). # 0 AC
211     # huffman("\x11"). # 1 AC
212     #------------------------------------------------------------------
213 dpavlin 11 # 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 dpavlin 8 "\xFF\xDA". # Start of Scan marker
315     pack("nC11",
316     12, # length
317     3, # number of components
318 dpavlin 11 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 dpavlin 8 );
324     #------------------------------------------------------------------
325    
326    
327 dpavlin 11 if ( $dump ) {
328     warn "## created JPEG header...\n";
329     hex_dump( $header, 0 );
330     }
331 dpavlin 8
332 dpavlin 11 print $fh $header || die "can't write header into $path: $!";
333     print $fh $data || die "can't write frame into $path: $!";
334 dpavlin 8 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 dpavlin 4 while ( ! defined($d->{eof}) ) {
343 dpavlin 3 my ( $list, $name ) = x(12,'A4x4A4');
344     die "not LIST but $list" if $list ne 'LIST';
345 dpavlin 8 print "< $list * $name\n";
346 dpavlin 3
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 dpavlin 8 $path,
361 dpavlin 3 $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 dpavlin 4 } elsif ( $name eq 'movi' ) {
372    
373     while (1) {
374     my $frame = $d->{movi}++;
375    
376 dpavlin 8 my $len = next_part( '00dc' );
377 dpavlin 4 last unless $len;
378 dpavlin 8 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 dpavlin 4
381 dpavlin 8 $len = next_part( '01wb', 0, 1 );
382     printf "<< %s 01wb - frame %d audio %d 0x%x bytes\n", $name, $frame, $len, $len;
383 dpavlin 4 };
384    
385 dpavlin 3 } else {
386     die "unknown $list $name";
387     }
388     }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26