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

Diff of /amv.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3 by dpavlin, Thu Jul 19 20:17:37 2007 UTC revision 11 by dpavlin, Fri Jul 20 16:07:46 2007 UTC
# Line 3  Line 3 
3  # amv.pl  # amv.pl
4  #  #
5  # 07/19/07 19:21:39 CEST Dobrica Pavlinusic <dpavlin@rot13.org>  # 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;  use strict;
14    
15  use Data::Dump qw/dump/;  use Data::Dump qw/dump/;
16  use Carp qw/confess/;  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";  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: $!";  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 {  sub hex_dump {
37          my $bytes = shift || return;          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;          my $ascii = $bytes;
49          $ascii =~ s/\W/./gs;          $ascii =~ s/\W/./gs;
50          my $hex = unpack('h*', $bytes);          my $hex = uc( unpack('h*', $bytes) );
51          $hex =~ s/(..)/$1 /g;          $hex =~ s/(..)/$1 /g;
         my $o = 0;  
52          # calculate number of characters for offset          # calculate number of characters for offset
53          my $d = length( sprintf("%x",length($bytes)) );          #my $d = length( sprintf("%x",length($bytes)) );
54            my $d = 4;
55            my $prefix = '#.';
56          while ( $hex =~ s/^((?:\w\w\s){1,16})// ) {          while ( $hex =~ s/^((?:\w\w\s){1,16})// ) {
57                  printf "## %0${d}x | %-48s| %s\n", $o, $1, substr( $ascii, 0, 16 );                  printf "$prefix %0${d}x | %-48s| %s\n", $o, $1, substr( $ascii, 0, 16 );
58                    $prefix = '##';
59                  if ( length($ascii) >= 16 ) {                  if ( length($ascii) >= 16 ) {
60                          $ascii = substr( $ascii, 16 );                          $ascii = substr( $ascii, 16 );
61                            $o += 16;
62                  } else {                  } else {
63                            $o += length($ascii);
64                          last;                          last;
65                  }                  }
                 $o += 16;  
66          }          }
67    
68            $o = $old_o if $old_o;
69  }  }
70    
71  sub x {  sub x {
# Line 45  sub x { Line 79  sub x {
79    
80          hex_dump( $bytes );          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 ) {          if ( $format ) {
89                  my @data = unpack($format, $bytes);                  my @data = unpack($format, $bytes);
90                  dump(@data);                  warn "## unpacked = ",dump(@data),"\n" if $debug;
91                  return @data;                  return @data;
92          } else {          } else {
93                  return $bytes;                  return $bytes;
# Line 57  sub x { Line 97  sub x {
97  sub next_part {  sub next_part {
98          my ( $expected_part, $expected_len, $skip ) = @_;          my ( $expected_part, $expected_len, $skip ) = @_;
99          my ( $part, $len ) = x(8,'A4V');          my ( $part, $len ) = x(8,'A4V');
100            return unless $len;
101          confess "not $expected_part but $part" if $expected_part ne $part;          confess "not $expected_part but $part" if $expected_part ne $part;
102          if ( $expected_len ) {          if ( $expected_len ) {
103                  confess "expected $expected_len bytes for $part got $len" if $len != $expected_len;                  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;          printf "<< %s - %d 0x%x bytes\n", $part, $len, $len;
106          x($len) if $skip;          x($len) if $skip;
107          return $len;          return $len;
108  }  }
109    
110  my ( $riff, $amv ) = x(12, 'Z8Z4');  sub huffman {
 die "not RIFF but $riff" if $riff ne 'RIFF';  
 die "not AMV but $amv" if $amv ne 'AMV ';  
111    
112  my $d;  # 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  while ( 1 ) {          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');          my ( $list, $name ) = x(12,'A4x4A4');
344          die "not LIST but $list" if $list ne 'LIST';          die "not LIST but $list" if $list ne 'LIST';
345          print "> $list .. $name\n";          print "< $list * $name\n";
346    
347          if ( $name eq 'hdrl' ) {          if ( $name eq 'hdrl' ) {
348    
349                  my $len = next_part( 'amvh', hex(38) );                  my $len = next_part( 'amvh', hex(38) );
           
                 print ">> $name $len\n";  
350    
                 my (  
                         $ms_per_frame,  
                         $width,  
                         $height,  
                         $fps,  
                         $ss,  
                         $mm,  
                         $hh,  
                 ) =  
351                  my @names = ( qw/ms_per_frame width height fps ss mm hh/ );                  my @names = ( qw/ms_per_frame width height fps ss mm hh/ );
352                  my $h;                  my $h;
353                  map {                  map {
# Line 101  while ( 1 ) { Line 357  while ( 1 ) {
357                  } x($len, 'Vx28VVVx8CCv');                  } x($len, 'Vx28VVVx8CCv');
358    
359                  printf "## %s %d*%d %s fps (%d ms/frame) %02d:%02d:%02d\n",                  printf "## %s %d*%d %s fps (%d ms/frame) %02d:%02d:%02d\n",
360                          $h->{path},                          $path,
361                          $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},                          $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},
362                          $h->{hh}, $h->{mm}, $h->{ss};                          $h->{hh}, $h->{mm}, $h->{ss};
363    
# Line 112  while ( 1 ) { Line 368  while ( 1 ) {
368                  next_part( 'strh', 0, 1 );                  next_part( 'strh', 0, 1 );
369                  next_part( 'strf', 0, 1 );                  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 {          } else {
386                  die "unknown $list $name";                  die "unknown $list $name";
387          }          }

Legend:
Removed from v.3  
changed lines
  Added in v.11

  ViewVC Help
Powered by ViewVC 1.1.26