Revision 8

Date:
2007/07/20 11:13:55
Author:
dpavlin
Revision Log:
- dump all frames into (currently still invaild) jpeg files
- hex_dump can accept offset to dump data which is not from file (e.g. jpeg header)
- better output
Files:

Legend:

 
Added
 
Removed
 
Modified
  • amv.pl

     
    7 7 # Various useful links used to produce this:
    8 8 # http://www.moviecodec.com/topics/15431p1.html
    9 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
    10 12
    11 13 use strict;
    12 14
    13 15 use Data::Dump qw/dump/;
    14 16 use Carp qw/confess/;
    17 use File::Path;
    15 18
    19 my $dump = 0;
    20 my $debug = 0;
    21
    16 22 my $path = shift @ARGV || die "usage: $0 movie.amv\n";
    17 23
    24 my $dump_dir = '/tmp/dump/';
    25 if ( ! -e $dump_dir ) {
    26 mkpath $dump_dir || die "can't create $dump_dir: $!";
    27 }
    28
    18 29 open(my $fh, '<', $path) || die "can't open $path: $!";
    19 30
    20 31 # offset in file
     
    24 35 my $d;
    25 36
    26 37 sub hex_dump {
    27 my $bytes = shift || return;
    38 return unless $dump;
    28 39
    40 my ( $bytes, $offset ) = @_;
    41 return unless $bytes;
    42
    43 my $old_o;
    44 if (defined($offset)) {
    45 $old_o = $o;
    46 $o = $offset;
    47 }
    48
    29 49 my $ascii = $bytes;
    30 50 $ascii =~ s/\W/./gs;
    31 my $hex = unpack('h*', $bytes);
    51 my $hex = uc( unpack('h*', $bytes) );
    32 52 $hex =~ s/(..)/$1 /g;
    33 53 # calculate number of characters for offset
    34 54 #my $d = length( sprintf("%x",length($bytes)) );
     
    45 65 last;
    46 66 }
    47 67 }
    68
    69 $o = $old_o if $old_o;
    48 70 }
    49 71
    50 72 sub x {
     
    66 88
    67 89 if ( $format ) {
    68 90 my @data = unpack($format, $bytes);
    69 warn "## unpacked = ",dump(@data),"\n";
    91 warn "## unpacked = ",dump(@data),"\n" if $debug;
    70 92 return @data;
    71 93 } else {
    72 94 return $bytes;
     
    81 103 if ( $expected_len ) {
    82 104 confess "expected $expected_len bytes for $part got $len" if $len != $expected_len;
    83 105 }
    84 printf ">> %s - %d 0x%x bytes\n", $part, $len, $len;
    106 printf "<< %s - %d 0x%x bytes\n", $part, $len, $len;
    85 107 x($len) if $skip;
    86 108 return $len;
    87 109 }
    88 110
    89 my ( $riff, $amv ) = x(12, 'Z8Z4');
    90 die "not RIFF but $riff" if $riff ne 'RIFF';
    91 die "not AMV but $amv" if $amv ne 'AMV ';
    111 sub huffman {
    92 112
    113 # JPEG DHT Segment for YCrCb omitted from MJPG data
    114 return
    115 "\xFF\xC4\x01\xA2" .
    116 "\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00" .
    117 "\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x01" .
    118 "\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" .
    119 "\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x10\x00" .
    120 "\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01\x7D" .
    121 "\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06\x13\x51\x61" .
    122 "\x07\x22\x71\x14\x32\x81\x91\xA1\x08\x23\x42\xB1\xC1\x15\x52" .
    123 "\xD1\xF0\x24\x33\x62\x72\x82\x09\x0A\x16\x17\x18\x19\x1A\x25" .
    124 "\x26\x27\x28\x29\x2A\x34\x35\x36\x37\x38\x39\x3A\x43\x44\x45" .
    125 "\x46\x47\x48\x49\x4A\x53\x54\x55\x56\x57\x58\x59\x5A\x63\x64" .
    126 "\x65\x66\x67\x68\x69\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x83" .
    127 "\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98\x99" .
    128 "\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5\xB6" .
    129 "\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2\xD3" .
    130 "\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8" .
    131 "\xE9\xEA\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\x11\x00\x02" .
    132 "\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02\x77\x00" .
    133 "\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41\x51\x07\x61\x71" .
    134 "\x13\x22\x32\x81\x08\x14\x42\x91\xA1\xB1\xC1\x09\x23\x33\x52" .
    135 "\xF0\x15\x62\x72\xD1\x0A\x16\x24\x34\xE1\x25\xF1\x17\x18\x19" .
    136 "\x1A\x26\x27\x28\x29\x2A\x35\x36\x37\x38\x39\x3A\x43\x44\x45" .
    137 "\x46\x47\x48\x49\x4A\x53\x54\x55\x56\x57\x58\x59\x5A\x63\x64" .
    138 "\x65\x66\x67\x68\x69\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x82" .
    139 "\x83\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98" .
    140 "\x99\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5" .
    141 "\xB6\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2" .
    142 "\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE2\xE3\xE4\xE5\xE6\xE7\xE8" .
    143 "\xE9\xEA\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA";
    144
    145 }
    146
    147 sub mkjpg {
    148 my ($path,$data) = @_;
    149 open(my $fh, '>', $path) || die "can't create $path: $!";
    150
    151 confess "no SOI marker in data" if substr($data,0,2) ne "\xFF\xD8";
    152 $data = substr($data,2);
    153
    154 my $header =
    155 "\xFF\xD8". # Start of Image (SOI) marker
    156 #------------------------------------------------------------------
    157 "\xFF\xE0". # JFIF marker
    158 pack("nZ5CCCnnCC",
    159 16, # length
    160 'JFIF', # identifier
    161 1,1, # version
    162 0, # units (none)
    163 1,1, # X,Y density
    164 0,0, # X,Y thumbnail
    165 ).
    166 #------------------------------------------------------------------
    167 "\xFF\xDB". # Define Quantization table marker
    168 "\x00\x43". # len
    169 "\x00". # the precision and the quantization table index
    170 "\x00" x 64 .
    171 #------------------------------------------------------------------
    172 "\xFF\xC0". # Start of frame
    173 pack("ncnncc9",
    174 17, # len
    175 8, # sample precision in bits
    176 120,160, # X,Y size
    177 3, # number of components
    178 1,0x22,0, # Component ID, H+V sampling factors, Quantization table number
    179 2,0x11,0,
    180 3,0x11,0,
    181 ).
    182 #------------------------------------------------------------------
    183 # huffman("\x00"). # 0 DC
    184 huffman("\x01"). # 1 DC
    185 # huffman("\x10"). # 0 AC
    186 # huffman("\x11"). # 1 AC
    187 #------------------------------------------------------------------
    188 "\xFF\xDA". # Start of Scan marker
    189 pack("nC11",
    190 12, # length
    191 3, # number of components
    192 1,0, # components DC+AC table numbers
    193 2,17,
    194 3,17,
    195 0,63, # Ss, Se
    196 0,165, # Ah, Ai
    197 );
    198 #------------------------------------------------------------------
    199
    200
    201 warn "## created JPEG header...", dump( $header );
    202 hex_dump( $header, 0 );
    203
    204 print $fh $header . $data || die "can't write frame into $path: $!";
    205 close $fh || die "can't close $path: $!";
    206 print ">> created $path ", -s $path, " bytes\n";
    207 }
    208
    209 my ( $riff, $amv ) = x(12, 'Z4x4Z4');
    210 die "$path not RIFF but $riff" if $riff ne 'RIFF';
    211 die "$path not AMV but $amv" if $amv ne 'AMV ';
    212
    93 213 while ( ! defined($d->{eof}) ) {
    94 214 my ( $list, $name ) = x(12,'A4x4A4');
    95 215 die "not LIST but $list" if $list ne 'LIST';
    96 print "> $list .. $name\n";
    216 print "< $list * $name\n";
    97 217
    98 218 if ( $name eq 'hdrl' ) {
    99 219
     
    108 228 } x($len, 'Vx28VVVx8CCv');
    109 229
    110 230 printf "## %s %d*%d %s fps (%d ms/frame) %02d:%02d:%02d\n",
    111 $h->{path},
    231 $path,
    112 232 $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},
    113 233 $h->{hh}, $h->{mm}, $h->{ss};
    114 234
     
    124 244 while (1) {
    125 245 my $frame = $d->{movi}++;
    126 246
    127 my $len = next_part( '00dc', 0, 1 );
    247 my $len = next_part( '00dc' );
    128 248 last unless $len;
    129 printf ">> %s 00dc - frame %d jpeg %d 0x%x bytes\n", $name, $frame, $len, $len;
    249 printf "<< %s 00dc - frame %d jpeg %d 0x%x bytes\n", $name, $frame, $len, $len;
    250 mkjpg( sprintf("$dump_dir/%03d.jpg", $frame ), x($len) );
    130 251
    131 my $len = next_part( '01wb', 0, 1 );
    132 printf ">> %s 01wb - frame %d audio %d 0x%x bytes\n", $name, $frame, $len, $len;
    252 $len = next_part( '01wb', 0, 1 );
    253 printf "<< %s 01wb - frame %d audio %d 0x%x bytes\n", $name, $frame, $len, $len;
    133 254 };
    134 255
    135 256 } else {