/[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 11 by dpavlin, Fri Jul 20 16:07:46 2007 UTC revision 34 by dpavlin, Mon Oct 1 20:28:17 2007 UTC
# Line 9  Line 9 
9  # http://en.wikipedia.org/wiki/RIFF_(File_format)  # http://en.wikipedia.org/wiki/RIFF_(File_format)
10  # http://www.obrador.com/essentialjpeg/HeaderInfo.htm  # http://www.obrador.com/essentialjpeg/HeaderInfo.htm
11  # http://lists.helixcommunity.org/pipermail/datatype-dev/2005-January/001886.html  # http://lists.helixcommunity.org/pipermail/datatype-dev/2005-January/001886.html
12    # http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm
13    # http://wiki.multimedia.cx/index.php?title=IMA_ADPCM
14    
15  use strict;  use strict;
16    
17  use Data::Dump qw/dump/;  use Data::Dump qw/dump/;
18  use Carp qw/confess/;  use Carp qw/confess/;
19  use File::Path;  use File::Path;
20    use Getopt::Long;
21    
22  my $dump = 0;  my $dump_amv = 0;
23    my $dump_video = 0;
24    my $dump_jpeg = 0;
25    my $dump_audio = 0;
26  my $debug = 0;  my $debug = 0;
27    my $verbose = 0;
28    my $dump_dir = '/tmp/dump/';
29    my $dump_avi = "dump.avi";
30    my $no_jpeg_header = 0;
31    my $jpeg_q = 100;
32    my $jpegtran;
33    
34    GetOptions(
35            "dump-amv!"             => \$dump_amv,
36            "dump-video!"   => \$dump_video,
37            "dump-jpeg!"    => \$dump_jpeg,
38            "dump-audio!"   => \$dump_audio,
39            "debug!"                => \$debug,
40            "dump-dir=s"    => \$dump_dir,
41            "no-jpeg-headers!" => \$no_jpeg_header,
42            "jpegtran=s"    => \$jpegtran,
43            "verbose!"              => \$verbose,
44    );
45    
46  my $path = shift @ARGV || die "usage: $0 movie.amv\n";  my $path = shift @ARGV || die "usage: $0 movie.amv\n";
47    
48  my $dump_dir = '/tmp/dump/';  # by default, flip frames
49    $jpegtran = '-flip vertical' unless defined($jpegtran);
50    
51  rmtree $dump_dir if -e $dump_dir;  rmtree $dump_dir if -e $dump_dir;
52  mkpath $dump_dir || die "can't create $dump_dir: $!";  mkpath $dump_dir || die "can't create $dump_dir: $!";
53    
54    $| = 1;
55    
56  open(my $fh, '<', $path) || die "can't open $path: $!";  open(my $fh, '<', $path) || die "can't open $path: $!";
57    
58  # offset in file  # offset in file
# Line 34  my $o = 0; Line 62  my $o = 0;
62  my $d;  my $d;
63    
64  sub hex_dump {  sub hex_dump {
         return unless $dump;  
   
65          my ( $bytes, $offset ) = @_;          my ( $bytes, $offset ) = @_;
66          return unless $bytes;          return unless $bytes;
67    
# Line 77  sub x { Line 103  sub x {
103          my $r_len = length($bytes);          my $r_len = length($bytes);
104          confess "read $r_len bytes, expected $len" if $len != $r_len;          confess "read $r_len bytes, expected $len" if $len != $r_len;
105    
106          hex_dump( $bytes );          if ( $dump_amv ) {
107                    print "## raw $len bytes\n";
108                    hex_dump( $bytes );
109            }
110    
111          if ( $bytes eq 'AMV_END_' ) {          if ( $bytes eq 'AMV_END_' ) {
112                  warn "> end of file marker AMV_END_\n";                  print "> end of file marker AMV_END_\n" if $dump_video;
113                  $d->{eof}++;                  $d->{eof}++;
114                  return;                  return;
115          }          }
116    
117          if ( $format ) {          if ( $format ) {
118                  my @data = unpack($format, $bytes);                  my @data = unpack($format, $bytes);
119                  warn "## unpacked = ",dump(@data),"\n" if $debug;                  print "## unpacked = ",dump(@data),"\n" if $debug;
120                  return @data;                  return @data;
121          } else {          } else {
122                  return $bytes;                  return $bytes;
123          }          }
124  }  }
125    
126    # my $len = next_part( 'boob' );
127    # my ( $len, $part ) = next_part();
128    
129  sub next_part {  sub next_part {
130          my ( $expected_part, $expected_len, $skip ) = @_;          my ( $expected_part, $expected_len, $skip ) = @_;
131          my ( $part, $len ) = x(8,'A4V');          my ( $part, $len ) = x(8,'A4V');
132          return unless $len;          return unless $len;
133          confess "not $expected_part but $part" if $expected_part ne $part;          confess "not $expected_part but $part" if $expected_part && $expected_part ne $part;
134          if ( $expected_len ) {          if ( $expected_len ) {
135                  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;
136          }          }
137          printf "<< %s - %d 0x%x bytes\n", $part, $len, $len;          printf "## next_part %s - %d 0x%x bytes\n", $part, $len, $len if $debug;
138          x($len) if $skip;          x($len) if $skip;
139            return ( $len, $part )  if wantarray;
140          return $len;          return $len;
141  }  }
142    
143  sub huffman {  sub quality {
144            my @table = @_;
145            die "quantization matrice needs to have 64 bytes!" if $#table != 63;
146    
147            my $in = join('', map { chr($_) } @table );
148            my $out;
149    
150            foreach my $t ( @table ) {
151                    $t = int( ( $t * $jpeg_q ) / 100 );
152                    $t = 255 if $t > 255;
153                    $out .= chr($t);
154            }
155    
156  # JPEG DHT Segment for YCrCb omitted from MJPG data          if ( $dump_video ) {
157  return                  print "## quantization table original\n";
158  "\xFF\xC4\x01\xA2" .                  hex_dump( $in );
159  "\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00" .                  print "## quantization table for $jpeg_q %\n";
160  "\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x01" .                  hex_dump( $out );
161  "\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" .          }
 "\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x10\x00" .  
 "\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01\x7D" .  
 "\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06\x13\x51\x61" .  
 "\x07\x22\x71\x14\x32\x81\x91\xA1\x08\x23\x42\xB1\xC1\x15\x52" .  
 "\xD1\xF0\x24\x33\x62\x72\x82\x09\x0A\x16\x17\x18\x19\x1A\x25" .  
 "\x26\x27\x28\x29\x2A\x34\x35\x36\x37\x38\x39\x3A\x43\x44\x45" .  
 "\x46\x47\x48\x49\x4A\x53\x54\x55\x56\x57\x58\x59\x5A\x63\x64" .  
 "\x65\x66\x67\x68\x69\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x83" .  
 "\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98\x99" .  
 "\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5\xB6" .  
 "\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2\xD3" .  
 "\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8" .  
 "\xE9\xEA\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\x11\x00\x02" .  
 "\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02\x77\x00" .  
 "\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41\x51\x07\x61\x71" .  
 "\x13\x22\x32\x81\x08\x14\x42\x91\xA1\xB1\xC1\x09\x23\x33\x52" .  
 "\xF0\x15\x62\x72\xD1\x0A\x16\x24\x34\xE1\x25\xF1\x17\x18\x19" .  
 "\x1A\x26\x27\x28\x29\x2A\x35\x36\x37\x38\x39\x3A\x43\x44\x45" .  
 "\x46\x47\x48\x49\x4A\x53\x54\x55\x56\x57\x58\x59\x5A\x63\x64" .  
 "\x65\x66\x67\x68\x69\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x82" .  
 "\x83\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98" .  
 "\x99\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5" .  
 "\xB6\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2" .  
 "\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE2\xE3\xE4\xE5\xE6\xE7\xE8" .  
 "\xE9\xEA\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA";  
162    
163            return $out;
164  }  }
165    
166    my @subframes;
167    my $frame_nr = 1;
168    
169    # how many subframes to join into single frame?
170    my $join_subframes = 0;
171    
172  sub mkjpg {  sub mkjpg {
173          my ($path,$data) = @_;          my ($data) = @_;
         open(my $fh, '>', $path) || die "can't create $path: $!";  
174    
175          confess "no SOI marker in data" if substr($data,0,2) ne "\xFF\xD8";          confess "no SOI marker in data" if substr($data,0,2) ne "\xFF\xD8";
176          $data = substr($data,2);          confess "no EOI marker in data" if substr($data,-2,2) ne "\xFF\xD9";
177            $data = substr($data,2,-2);
178    
179            if ( $#subframes < ( $join_subframes - 1 ) ) {
180                    push @subframes, $data;
181                    print "## saved $frame_nr/", $#subframes + 1, " subframe of ", length($data), " bytes\n" if $debug;
182                    return;
183            }
184    
185            my $w = $d->{amvh}->{width} || die "no width?";
186            my $h = $d->{amvh}->{height} || confess "no height?";
187    
188          my $header =          my $header =
189                  "\xFF\xD8".     # Start of Image (SOI) marker          # Start of Image (SOI) marker
190  #------------------------------------------------------------------          "\xFF\xD8".
191                  "\xFF\xE0".     # JFIF marker          # JFIF marker
192            "\xFF\xE0".
193          pack("nZ5CCCnnCC",          pack("nZ5CCCnnCC",
194                  16,                     # length                  16,                     # length
195                  'JFIF',         # identifier                  'JFIF',         # identifier (JFIF)
196                  1,1,            # version                  1,1,            # version
197                  0,                      # units (none)                  0,                      # units (none)
198                  1,1,            # X,Y density                  1,1,            # X,Y density
199                  0,0,            # X,Y thumbnail                  0,0,            # X,Y thumbnail
200          ).          ).
201  #------------------------------------------------------------------          "\xFF\xFE".
202          "\xFF\xC0".     # Start of frame          "\x00\x3CCREATOR: amv dumper (compat. IJG JPEG v62), quality = 100\n".
203            # quantization table (quaility=100%)
204            "\xFF\xDB".
205            "\x00\x43".
206            # 8 bit values, table 1
207            "\x00".
208            quality(
209        0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E,
210        0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
211        0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
212        0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33,
213        0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44,
214        0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57,
215        0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71,
216        0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63,
217            ).
218            "\xFF\xDB".
219            "\x00\x43".
220            # 8 bit values, table 1
221            "\x01".
222            quality(
223        0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2F, 0x1A,
224        0x1A, 0x2F, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
225        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
226        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
227        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
228        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
229        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
230        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
231            ).
232            # start of frame
233            "\xFF\xC0".
234          pack("ncnncc9",          pack("ncnncc9",
235                  17,                     # len                  17,                     # len
236                  8,                      # sample precision in bits                  8,                      # sample precision in bits
237                  120,160,        # X,Y size                  $h,$w,          # X,Y size
238                  3,                      # number of components                  3,                      # number of components
239                  1,0x21,0,       # Component ID, H+V sampling factors, Quantization table number                  1,0x22,0,       # Component ID, H+V sampling factors, Quantization table number
240                  2,0x11,1,                  2,0x11,1,
241                  3,0x11,1,                  3,0x11,1,
242          ).          ).
 #------------------------------------------------------------------  
         "\xFF\xDB".             # Define Quantization table marker  
         "\x00\x84".             # len  
         "\x00".                 # 8 bit values, (byte) table 0  
         "\x10\x0B\x0C\x0E\x0C".  
         "\x0A\x10\x0E\x0D\x0E".  
         "\x12\x11\x10\x13\x18".  
         "\x28\x1A\x18\x16\x16".  
         "\x18\x31\x23\x25\x1D".  
         "\x28\x3A\x33\x3D\x3C".  
         "\x39\x33\x38\x37\x40".  
         "\x48\x5C\x4E\x40\x44".  
         "\x57\x45\x37\x38\x50".  
         "\x6D\x51\x57\x5F\x62".  
         "\x67\x68\x67\x3E\x4D".  
         "\x71\x79\x70\x64\x78".  
         "\x5C\x65\x67\x63".  
         "\x01".         # 8 bit values, (byte) table 1  
         "\x11\x12\x12\x18\x15".  
         "\x18\x2F\x1A\x1A\x2F".  
         "\x63\x42\x38\x42\x63".  
         "\x63\x63\x63\x63\x63".  
         "\x63\x63\x63\x63\x63".  
         "\x63\x63\x63\x63\x63".  
         "\x63\x63\x63\x63\x63".  
         "\x63\x63\x63\x63\x63".  
         "\x63\x63\x63\x63\x63".  
         "\x63\x63\x63\x63\x63".  
         "\x63\x63\x63\x63\x63".  
         "\x63\x63\x63\x63\x63".  
         "\x63\x63\x63\x63".  
 #------------------------------------------------------------------  
 #       huffman("\x00").        # 0 DC  
 #       huffman("\x01").        # 1 DC  
 #       huffman("\x10").        # 0 AC  
 #       huffman("\x11").        # 1 AC  
 #------------------------------------------------------------------  
243          # Define huffman table (section B.2.4.1)          # Define huffman table (section B.2.4.1)
244          "\xFF\xC4".             # Marker          "\xFF\xC4".     # Marker
245          "\x00\x1F".             # Length (31 bytes)          "\x00\x1F".     # Length (31 bytes)
246          "\x00".                 # DC, (byte) table 0          "\x00".         # DC luminance, table 0
247          "\x00\x01\x05\x01\x01".          "\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00".
248          "\x01\x01\x01\x01\x00".          "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B".
         "\x00\x00\x00\x00\x00".  
         "\x00\x00\x01\x02\x03".  
         "\x04\x05\x06\x07\x08".  
         "\x09\x0A\x0B".  
249          # Define huffman table (section B.2.4.1)          # Define huffman table (section B.2.4.1)
250          "\xFF\xC4".             # Marker          "\xFF\xC4".     # Marker
251          "\x00\xB5".             # Length (181 bytes)          "\x00\xB5".     # Length (181 bytes)
252          "\x10".                 # AC, (byte) table 0          "\x10".         # AC luminance, table 0
253          "\x00\x02\x01\x03\x03".          "\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01\x7D".
254          "\x02\x04\x03\x05\x05".          "\x01\x02\x03\x00\x04\x11\x05\x12".
255          "\x04\x04\x00\x00\x01".          "\x21\x31\x41\x06\x13\x51\x61\x07\x22\x71\x14\x32".
256          "\x7D\x01\x02\x03\x00".          "\x81\x91\xA1\x08\x23\x42\xB1\xC1\x15\x52\xD1\xF0".
257          "\x04\x11\x05\x12\x21".          "\x24\x33\x62\x72\x82\x09\x0A\x16\x17\x18\x19\x1A".
258          "\x31\x41\x06\x13\x51".          "\x25\x26\x27\x28\x29\x2A\x34\x35\x36\x37\x38\x39".
259          "\x61\x07\x22\x71\x14".          "\x3A\x43\x44\x45\x46\x47\x48\x49\x4A\x53\x54\x55".
260          "\x32\x81\x91\xA1\x08".          "\x56\x57\x58\x59\x5A\x63\x64\x65\x66\x67\x68\x69".
261          "\x23\x42\xB1\xC1\x15".          "\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x83\x84\x85".
262          "\x52\xD1\xF0\x24\x33".          "\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98".
263          "\x62\x72\x82\x09\x0A".          "\x99\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2".
264          "\x16\x17\x18\x19\x1A".          "\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5".
265          "\x25\x26\x27\x28\x29".          "\xC6\xC7\xC8\xC9\xCA\xD2\xD3\xD4\xD5\xD6\xD7\xD8".
266          "\x2A\x34\x35\x36\x37".          "\xD9\xDA\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA".
267          "\x38\x39\x3A\x43\x44".          "\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA".
         "\x45\x46\x47\x48\x49".  
         "\x4A\x53\x54\x55\x56".  
         "\x57\x58\x59\x5A\x63".  
         "\x64\x65\x66\x67\x68".  
         "\x69\x6A\x73\x74\x75".  
         "\x76\x77\x78\x79\x7A".  
         "\x83\x84\x85\x86\x87".  
         "\x88\x89\x8A\x92\x93".  
         "\x94\x95\x96\x97\x98".  
         "\x99\x9A\xA2\xA3\xA4".  
         "\xA5\xA6\xA7\xA8\xA9".  
         "\xAA\xB2\xB3\xB4\xB5".  
         "\xB6\xB7\xB8\xB9\xBA".  
         "\xC2\xC3\xC4\xC5\xC6".  
         "\xC7\xC8\xC9\xCA\xD2".  
         "\xD3\xD4\xD5\xD6\xD7".  
         "\xD8\xD9\xDA\xE1\xE2".  
         "\xE3\xE4\xE5\xE6\xE7".  
         "\xE8\xE9\xEA\xF1\xF2".  
         "\xF3\xF4\xF5\xF6\xF7".  
         "\xF8\xF9\xFA".  
268          # Define huffman table (section B.2.4.1)          # Define huffman table (section B.2.4.1)
269          "\xFF\xC4".             # Marker          "\xFF\xC4".     # Marker
270          "\x00\x1F".             # Length (31 bytes)          "\x00\x1F".     # Length (31 bytes)
271          "\x01".                 # DC, (byte) table 1          "\x01".         # DC chrominance, table 1
272          "\x00\x03\x01\x01\x01".          "\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00".
273          "\x01\x01\x01\x01\x01".          "\x00\x00\x00\x00".
274          "\x01\x00\x00\x00\x00".          "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B".
275          "\x00\x00\x01\x02\x03".          #/* Define huffman table (section B.2.4.1) */
276          "\x04\x05\x06\x07\x08".          "\xFF\xC4".     # Marker
277          "\x09\x0A\x0B".          "\x00\xB5".     # Length (181 bytes)
278          # Define huffman table (section B.2.4.1)          "\x11".         # AC chrominance, table 1
279          "\xFF\xC4".             # Marker          "\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04".
280          "\x00\xB5".             # Length (181 bytes)          "\x00\x01\x02\x77".
281          "\x11".                 # AC, (byte) table 1          "\x00\x01\x02\x03\x11\x04\x05\x21".
282          "\x00\x02\x01\x02\x04".          "\x31\x06\x12\x41\x51\x07\x61\x71\x13\x22\x32\x81".
283          "\x04\x03\x04\x07\x05".          "\x08\x14\x42\x91\xA1\xB1\xC1\x09\x23\x33\x52\xF0".
284          "\x04\x04\x00\x01\x02".          "\x15\x62\x72\xD1\x0A\x16\x24\x34\xE1\x25\xF1\x17".
285          "\x77\x00\x01\x02\x03".          "\x18\x19\x1A\x26\x27\x28\x29\x2A\x35\x36\x37\x38".
286          "\x11\x04\x05\x21\x31".          "\x39\x3A\x43\x44\x45\x46\x47\x48\x49\x4A\x53\x54".
287          "\x06\x12\x41\x51\x07".          "\x55\x56\x57\x58\x59\x5A\x63\x64\x65\x66\x67\x68".
288          "\x61\x71\x13\x22\x32".          "\x69\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x82\x83".
289          "\x81\x08\x14\x42\x91".          "\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96".
290          "\xA1\xB1\xC1\x09\x23".          "\x97\x98\x99\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9".
291          "\x33\x52\xF0\x15\x62".          "\xAA\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xC2\xC3".
292          "\x72\xD1\x0A\x16\x24".          "\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2\xD3\xD4\xD5\xD6".
293          "\x34\xE1\x25\xF1\x17".          "\xD7\xD8\xD9\xDA\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9".
294          "\x18\x19\x1A\x26\x27".          "\xEA\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA".
295          "\x28\x29\x2A\x35\x36".          # Start of Scan marker
296          "\x37\x38\x39\x3A\x43".          "\xFF\xDA".
297          "\x44\x45\x46\x47\x48".          pack("nC10",
         "\x49\x4A\x53\x54\x55".  
         "\x56\x57\x58\x59\x5A".  
         "\x63\x64\x65\x66\x67".  
         "\x68\x69\x6A\x73\x74".  
         "\x75\x76\x77\x78\x79".  
         "\x7A\x82\x83\x84\x85".  
         "\x86\x87\x88\x89\x8A".  
         "\x92\x93\x94\x95\x96".  
         "\x97\x98\x99\x9A\xA2".  
         "\xA3\xA4\xA5\xA6\xA7".  
         "\xA8\xA9\xAA\xB2\xB3".  
         "\xB4\xB5\xB6\xB7\xB8".  
         "\xB9\xBA\xC2\xC3\xC4".  
         "\xC5\xC6\xC7\xC8\xC9".  
         "\xCA\xD2\xD3\xD4\xD5".  
         "\xD6\xD7\xD8\xD9\xDA".  
         "\xE2\xE3\xE4\xE5\xE6".  
         "\xE7\xE8\xE9\xEA\xF2".  
         "\xF3\xF4\xF5\xF6\xF7".  
         "\xF8\xF9\xFA".  
 #------------------------------------------------------------------  
                 "\xFF\xDA".     # Start of Scan marker  
         pack("nC11",  
298                  12,                     # length                  12,                     # length
299                  3,                      # number of components                  3,                      # number of components
300                  1,0x00,         # Scan 1: use DC/AC huff tables 0/0                  1,0x00,         # Scan 1: use DC/AC huff tables 0/0
# Line 321  sub mkjpg { Line 303  sub mkjpg {
303                  0,0x3f,         # Ss, Se                  0,0x3f,         # Ss, Se
304                  0,                      # Ah, Ai (not used)                  0,                      # Ah, Ai (not used)
305          );          );
 #------------------------------------------------------------------  
   
306    
307          if ( $dump ) {          if ( $dump_jpeg ) {
308                  warn "## created JPEG header...\n";                  print "## created JPEG header...\n";
309                  hex_dump( $header, 0 );                  hex_dump( $header, 0 );
310          }          }
311    
312          print $fh $header || die "can't write header into $path: $!";          my $frame = join('', @subframes ) . $data;
313          print $fh $data || die "can't write frame into $path: $!";          @subframes = ();
314    
315            my $path = sprintf("$dump_dir/%04d.jpg", $frame_nr );
316    
317            my $fh;
318            if ( $jpegtran ) {
319                    open($fh, '|-', "jpegtran $jpegtran > $path") || die "can't create $path: $!";
320            } else {
321                    open($fh, '>', $path) || die "can't create $path: $!";
322            }
323    
324            if ( ! $no_jpeg_header ) {
325                    print $fh $header . $frame . "\xFF\xD9" || die "can't write jpeg $path: $!";
326            } else {
327                    print $fh $frame || die "can't write raw jpeg $path: $!";
328            }
329          close $fh || die "can't close $path: $!";          close $fh || die "can't close $path: $!";
330          print ">> created $path ", -s $path, " bytes\n";          print ">> created $frame_nr ", $no_jpeg_header ? 'raw' : '', " jpeg $path ", -s $path, " bytes\n" if $verbose;
331    }
332    
333    #
334    # IMA ADPCM decoder
335    #
336    
337    my @index_adjust = ( -1, -1, -1, -1, 2, 4, 6, 8 );
338    
339    my @step_size = (
340            7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
341            19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
342            50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
343            130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
344            337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
345            876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
346            2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
347            5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
348            15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
349    );
350    
351    my $pred_val = 0;
352    my $step_idx = 0;
353    
354    # This code is "borrowed" from the ALSA library
355    # http://www.alsa-project.org
356    
357    sub adpcm_decode_sample {
358            my $code = shift;
359    
360            my $pred_diff;  # Predicted difference to next sample
361            my $step;               # holds previous step_size value
362    
363            # Separate sign and magnitude
364            my $sign = $code & 0x8;
365            $code &= 0x7;
366    
367            # Computes pred_diff = (code + 0.5) * step / 4,
368            # but see comment in adpcm_coder.
369    
370            $step = $step_size[$step_idx] || die "no step_size[$step_idx]";
371    
372            # Compute difference and new predicted value
373            $pred_diff = $step >> 3;
374            my $i = 0x4;
375            while( $i ) {
376                    if ($code & $i) {
377                            $pred_diff += $step;
378                    }
379                    $i >>= 1;
380                    $step >>= 1;
381            }
382            $pred_val += $sign ? -$pred_diff : $pred_diff;
383    
384            # Clamp output value
385            if ($pred_val > 32767) {
386                    $pred_val = 32767;
387            } elsif ($pred_val < -32768) {
388                    $pred_val = -32768;
389            }
390    
391            # Find new step_size index value
392            $step_idx += $index_adjust[$code];
393    
394            if ($step_idx < 0) {
395                    $step_idx = 0;
396            } elsif ($step_idx > 88) {
397                    $step_idx = 88;
398            }
399            return $pred_val;
400  }  }
401    
402    my $au_path = "$dump_dir/sound.au";
403    open(my $au_fh, '>', $au_path) || die "can't open $au_path: $!";
404    print $au_fh pack 'a4N5', (
405            # magic
406            '.snd',
407            # data offset
408            24,
409            # data size
410            -1,
411            # encoding - 16-bit linear PCM
412            3,
413            # sample rate
414            22050,
415            #channels
416            1,
417    );
418    
419    sub audio_frame {
420            my $data = shift || die "no data?";
421    
422            my ( $origin, $index, $bytes ) = unpack 'ssL', substr($data,0,8);
423    
424            $pred_val = $origin;
425            $step_idx = $index;
426    
427            my $size = 0;
428    
429            foreach my $b ( map { ord($_) } split(//, substr($data,8)) ) {
430                    print $au_fh pack 'n', adpcm_decode_sample( $b >> 4 );          
431                    print $au_fh pack 'n', adpcm_decode_sample( $b & 15 );          
432                    $size += 2;
433            }
434    
435            warn "length isn't corrent $bytes != $size" if $bytes != $size;
436    }
437    
438    #
439    # read AMV file
440    #
441    
442  my ( $riff, $amv ) = x(12, 'Z4x4Z4');  my ( $riff, $amv ) = x(12, 'Z4x4Z4');
443  die "$path not RIFF but $riff" if $riff ne 'RIFF';  die "$path not RIFF but $riff" if $riff ne 'RIFF';
444  die "$path not AMV but $amv" if $amv ne 'AMV ';  die "$path not AMV but $amv" if $amv ne 'AMV ';
445    
446    my $fps = 16;
447    my $duration;
448    
449  while ( ! defined($d->{eof}) ) {  while ( ! defined($d->{eof}) ) {
450          my ( $list, $name ) = x(12,'A4x4A4');          my ( $list, $name ) = x(12,'A4x4A4');
451          die "not LIST but $list" if $list ne 'LIST';          die "not LIST but $list" if $list ne 'LIST';
452          print "< $list * $name\n";          print "< $list * $name\n" if $verbose;
453    
454          if ( $name eq 'hdrl' ) {          if ( $name eq 'hdrl' ) {
455    
# Line 356  while ( ! defined($d->{eof}) ) { Line 463  while ( ! defined($d->{eof}) ) {
463                          $h->{$n} = $v;                          $h->{$n} = $v;
464                  } x($len, 'Vx28VVVx8CCv');                  } x($len, 'Vx28VVVx8CCv');
465    
466                  printf "## %s %d*%d %s fps (%d ms/frame) %02d:%02d:%02d\n",                  $duration = sprintf('%02d:%02d:%02d', $h->{hh}, $h->{mm}, $h->{ss} );
467    
468                    printf "## %s %d*%d %s fps (%d ms/frame) %s\n",
469                          $path,                          $path,
470                          $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},                          $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},
471                          $h->{hh}, $h->{mm}, $h->{ss};                          $duration;
472    
473                  $d->{amvh} = $h;                  $d->{amvh} = $h;
474                    $fps = $h->{fps};
475    
476          } elsif ( $name eq 'strl' ) {          } elsif ( $name eq 'strl' ) {
477    
# Line 370  while ( ! defined($d->{eof}) ) { Line 480  while ( ! defined($d->{eof}) ) {
480    
481          } elsif ( $name eq 'movi' ) {          } elsif ( $name eq 'movi' ) {
482    
483                  while (1) {                  my $have_parts = 1;
484    
485                    while ( $have_parts ) {
486                          my $frame = $d->{movi}++;                          my $frame = $d->{movi}++;
                   
                         my $len = next_part( '00dc' );  
                         last unless $len;  
                         printf "<< %s 00dc - frame %d jpeg %d 0x%x bytes\n", $name, $frame, $len, $len;  
                         mkjpg( sprintf("$dump_dir/%03d.jpg", $frame ), x($len) );  
487    
488                          $len = next_part( '01wb', 0, 1 );                          my $parts = 0;
489                          printf "<< %s 01wb - frame %d audio %d 0x%x bytes\n", $name, $frame, $len, $len;  
490                            while ( $parts < 2 ) {
491    
492                                    my ( $len, $part ) = next_part();
493    
494                                    if ( ! $len ) {
495                                            $have_parts = 0;
496                                            last;
497                                    }
498    
499                                    if ( $part eq '00dc' ) {
500    
501                                            printf "<< %s 00dc - part %d jpeg %d 0x%x bytes\n", $name, $frame, $len, $len if $verbose;
502                                            mkjpg( x($len) );
503                                            $parts++;
504    
505                                    } elsif ( $part eq '01wb' ) {
506                                            printf "<< %s 01wb - part %d audio %d 0x%x bytes\n", $name, $frame, $len, $len if $verbose;
507    
508                                            my $audio_frame = x( $len );
509    
510                                            if ( $dump_audio ) {
511                                                    printf "#### dumping audio frame %d 0x%x bytes\n", length($audio_frame), length($audio_frame);
512                                                    hex_dump( $audio_frame );
513                                            }
514    
515                    #                       print $audio_fh mp3_frame;
516                                            audio_frame( $audio_frame );
517    
518                                            $parts++;
519                                    } else {
520                                            warn "unknown next part $part with $len bytes, skipping!";
521                                    }
522    
523                                    warn "## #$frame_nr $name $part has $parts parts\n" if $debug;
524                            }
525    
526                            $frame_nr++;
527    
528                            if ( $frame_nr % $fps == 0 ) {
529                                    print "\n" if ( ( $frame_nr / $fps ) % 60 == 0 );
530                                    print ".";
531                            }
532                  };                  };
533    
534          } else {          } else {
535                  die "unknown $list $name";                  die "unknown $list $name";
536          }          }
537  }  }
538    
539    if ( $fps == 12 ) {
540            warn "fixup $au_path for $fps fps -- 16000 Hz\n";
541            seek($au_fh, 16, 0);    # sample rate offset
542            print $au_fh pack 'N', 16000;
543    }
544    
545    my $cmd = "ffmpeg -r $fps -i $dump_dir/%04d.jpg -i $au_path -y $dump_avi";
546    system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";
547    
548    print ">>>> created $frame_nr frames $dump_avi ", -s $dump_avi, "\n";

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

  ViewVC Help
Powered by ViewVC 1.1.26