/[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 21 by dpavlin, Sat Jul 21 15:17:48 2007 UTC revision 25 by dpavlin, Sat Aug 18 11:20:25 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    
14  use strict;  use strict;
15    
# Line 17  use Carp qw/confess/; Line 18  use Carp qw/confess/;
18  use File::Path;  use File::Path;
19  use Getopt::Long;  use Getopt::Long;
20    
21  my $dump = 0;  my $dump_amv = 0;
22    my $dump_video = 0;
23    my $dump_jpeg = 0;
24    my $dump_audio = 0;
25  my $debug = 0;  my $debug = 0;
26    my $verbose = 0;
27  my $dump_dir = '/tmp/dump/';  my $dump_dir = '/tmp/dump/';
28  my $dump_avi = "dump.avi";  my $dump_avi = "dump.avi";
29  my $no_jpeg_header = 0;  my $no_jpeg_header = 0;
30  my $jpeg_q = 100;  my $jpeg_q = 100;
31    my $jpegtran;
32    
33  GetOptions(  GetOptions(
34          "dump!"                 => \$dump,          "dump-amv!"             => \$dump_amv,
35            "dump-video!"   => \$dump_video,
36            "dump-jpeg!"    => \$dump_jpeg,
37            "dump-audio!"   => \$dump_audio,
38          "debug!"                => \$debug,          "debug!"                => \$debug,
39          "dump-dir=s"    => \$dump_dir,          "dump-dir=s"    => \$dump_dir,
40          "no-jpeg-headers!" => \$no_jpeg_header,          "no-jpeg-headers!" => \$no_jpeg_header,
41            "jpegtran=s"    => \$jpegtran,
42            "verbose!"              => \$verbose,
43  );  );
44    
45  my $path = shift @ARGV || die "usage: $0 movie.amv\n";  my $path = shift @ARGV || die "usage: $0 movie.amv\n";
46    
47    # by default, flip frames
48    #$jpegtran = '-flip vertical' unless defined($jpegtran);
49    
50  rmtree $dump_dir if -e $dump_dir;  rmtree $dump_dir if -e $dump_dir;
51  mkpath $dump_dir || die "can't create $dump_dir: $!";  mkpath $dump_dir || die "can't create $dump_dir: $!";
# Line 46  my $o = 0; Line 59  my $o = 0;
59  my $d;  my $d;
60    
61  sub hex_dump {  sub hex_dump {
         return unless $dump;  
   
62          my ( $bytes, $offset ) = @_;          my ( $bytes, $offset ) = @_;
63          return unless $bytes;          return unless $bytes;
64    
# Line 89  sub x { Line 100  sub x {
100          my $r_len = length($bytes);          my $r_len = length($bytes);
101          confess "read $r_len bytes, expected $len" if $len != $r_len;          confess "read $r_len bytes, expected $len" if $len != $r_len;
102    
103          hex_dump( $bytes );          if ( $dump_amv ) {
104                    print "## raw $len bytes\n";
105                    hex_dump( $bytes );
106            }
107    
108          if ( $bytes eq 'AMV_END_' ) {          if ( $bytes eq 'AMV_END_' ) {
109                  print "> end of file marker AMV_END_\n" if $dump;                  print "> end of file marker AMV_END_\n" if $dump_video;
110                  $d->{eof}++;                  $d->{eof}++;
111                  return;                  return;
112          }          }
# Line 114  sub next_part { Line 128  sub next_part {
128          if ( $expected_len ) {          if ( $expected_len ) {
129                  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;
130          }          }
131          printf "<< %s - %d 0x%x bytes\n", $part, $len, $len;          printf "## next_part %s - %d 0x%x bytes\n", $part, $len, $len if $debug;
132          x($len) if $skip;          x($len) if $skip;
133          return $len;          return $len;
134  }  }
# Line 132  sub quality { Line 146  sub quality {
146                  $out .= chr($t);                  $out .= chr($t);
147          }          }
148    
149          if ( $dump ) {          if ( $dump_video ) {
150                  print "## quantization table original\n";                  print "## quantization table original\n";
151                  hex_dump( $in );                  hex_dump( $in );
152                  print "## quantization table for $jpeg_q %\n";                  print "## quantization table for $jpeg_q %\n";
# Line 142  sub quality { Line 156  sub quality {
156          return $out;          return $out;
157  }  }
158    
159    sub mp3_frame {
160            my $frame = join('',
161                    # Frame sync (all bits set)
162                    1 x 11 .
163                    # MPEG Audio version ID
164                    # 00 - MPEG Version 2.5 (unofficial)
165                    # 01 - reserved
166                    # 10 - MPEG Version 2 (ISO/IEC 13818-3)
167                    # 11 - MPEG Version 1 (ISO/IEC 11172-3)
168                    1,0,
169                    # Layer description
170                    # 00 - reserved
171                    # 01 - Layer III
172                    # 10 - Layer II
173                    # 11 - Layer I
174                    0,1,
175                    # Protection bit
176                    # 0 - Protected by CRC (16bit crc follows header)
177                    # 1 - Not protected
178                    0,
179                    # Bitrate index
180                    0,0,0,0,
181                    # Sampling rate frequency index (22050)
182                    0,0,
183                    # Padding bit
184                    # 0 - frame is not padded
185                    # 1 - frame is padded with one extra slot
186                    0,
187                    # Private bit
188                    0,
189                    # Channel Mode
190                    # 00 - Stereo
191                    # 01 - Joint stereo (Stereo)
192                    # 10 - Dual channel (2 mono channels)
193                    # 11 - Single channel (Mono)
194                    1,1,
195                    # Mode extension (Only if Joint stereo)
196                    0,0,
197                    # Copyright
198                    0,
199                    # Original
200                    0,
201                    # Emphasis
202                    # 00 - none
203                    # 01 - 50/15 ms
204                    # 10 - reserved
205                    # 11 - CCIT J.17
206                    0,0,
207            );
208    
209            die "frame must have 32 bits, not ", length($frame), " for $frame" if length($frame) != 32;
210    
211            my $bits = pack("b32", $frame);
212    
213            die "packed bits must be 4 bytes, not $bits" if length($bits) != 4;
214    
215            my $t = $frame;
216            $t =~ s/(.{8})/$1 /g;
217            warn "## mp3 frame frame = $t\n";
218    
219            return $bits;
220    }
221    
222  my @subframes;  my @subframes;
223  my $frame_nr = 1;  my $frame_nr = 1;
224    
# Line 157  sub mkjpg { Line 234  sub mkjpg {
234    
235          if ( $#subframes < ( $join_subframes - 1 ) ) {          if ( $#subframes < ( $join_subframes - 1 ) ) {
236                  push @subframes, $data;                  push @subframes, $data;
237                  print "## saved $frame_nr/", $#subframes + 1, " subframe of ", length($data), " bytes\n";                  print "## saved $frame_nr/", $#subframes + 1, " subframe of ", length($data), " bytes\n" if $debug;
238                  return;                  return;
239          }          }
240    
         my $path = sprintf("$dump_dir/%04d.jpg", $frame_nr++ );  
   
         open(my $fh, '>', $path) || die "can't create $path: $!";  
   
241          my $w = $d->{amvh}->{width} || die "no width?";          my $w = $d->{amvh}->{width} || die "no width?";
242          my $h = $d->{amvh}->{height} || confess "no height?";          my $h = $d->{amvh}->{height} || confess "no height?";
243    
# Line 287  sub mkjpg { Line 360  sub mkjpg {
360                  0,                      # Ah, Ai (not used)                  0,                      # Ah, Ai (not used)
361          );          );
362    
363          if ( $dump ) {          if ( $dump_jpeg ) {
364                  print "## created JPEG header...\n";                  print "## created JPEG header...\n";
365                  hex_dump( $header, 0 );                  hex_dump( $header, 0 );
366          }          }
# Line 295  sub mkjpg { Line 368  sub mkjpg {
368          my $frame = join('', @subframes ) . $data;          my $frame = join('', @subframes ) . $data;
369          @subframes = ();          @subframes = ();
370    
371            my $path = sprintf("$dump_dir/%04d.jpg", $frame_nr );
372    
373            my $fh;
374            if ( $jpegtran ) {
375                    open($fh, '|-', "jpegtran $jpegtran > $path") || die "can't create $path: $!";
376            } else {
377                    open($fh, '>', $path) || die "can't create $path: $!";
378            }
379    
380          if ( ! $no_jpeg_header ) {          if ( ! $no_jpeg_header ) {
381                  print $fh $header, $frame, "\xFF\xD9" || die "can't write jpeg $path: $!";                  print $fh $header . $frame . "\xFF\xD9" || die "can't write jpeg $path: $!";
382          } else {          } else {
383                  print $fh $frame || die "can't write raw jpeg $path: $!";                  print $fh $frame || die "can't write raw jpeg $path: $!";
384          }          }
385          close $fh || die "can't close $path: $!";          close $fh || die "can't close $path: $!";
386          print ">> created $frame_nr ", $no_jpeg_header ? 'raw' : '', " jpeg $path ", -s $path, " bytes\n";          print ">> created $frame_nr ", $no_jpeg_header ? 'raw' : '', " jpeg $path ", -s $path, " bytes\n" if $verbose;
387  }  }
388    
389  my ( $riff, $amv ) = x(12, 'Z4x4Z4');  my ( $riff, $amv ) = x(12, 'Z4x4Z4');
390  die "$path not RIFF but $riff" if $riff ne 'RIFF';  die "$path not RIFF but $riff" if $riff ne 'RIFF';
391  die "$path not AMV but $amv" if $amv ne 'AMV ';  die "$path not AMV but $amv" if $amv ne 'AMV ';
392    
393    my $apath = "$dump_dir/audio.wav";
394    open(my $audio_fh, '>', $apath) || die "can't open audio file $apath: $!";
395    
396    print $audio_fh pack 'a4Va4a4VvvVVv4', (
397            # header 'RIFF', size
398            'RIFF',-1,
399            # type: 'WAVE'
400            'WAVE',
401            'fmt ',0x14,
402            # format: DVI (IMA) ADPCM Wave Type
403            0x11,
404            # channels
405            1,
406            # samples/sec
407            22050,
408            # avg. bytes/sec (for esimation)
409            11567,
410            # block align (size of block)
411            0x800,
412            # bits per sample (mono data)
413            4,
414            # cbSize (ADPCM with 7 soefficient pairs)
415            2,
416            # nSamplesPerBlock
417            # (((nBlockAlign - (7 * nChannels)) * 8) / (wBitsPerSample * nChannels)) + 2
418            0x0ff9,
419    );
420    
421    print $audio_fh pack 'a4VVa4V', (
422            # time length of the data in samples
423            'fact',4,
424            220500,
425            #
426            'data',-1,
427    );
428    
429    my $riff_header_len = tell($audio_fh);
430    
431  while ( ! defined($d->{eof}) ) {  while ( ! defined($d->{eof}) ) {
432          my ( $list, $name ) = x(12,'A4x4A4');          my ( $list, $name ) = x(12,'A4x4A4');
433          die "not LIST but $list" if $list ne 'LIST';          die "not LIST but $list" if $list ne 'LIST';
434          print "< $list * $name\n";          print "< $list * $name\n" if $verbose;
435    
436          if ( $name eq 'hdrl' ) {          if ( $name eq 'hdrl' ) {
437    
# Line 344  while ( ! defined($d->{eof}) ) { Line 464  while ( ! defined($d->{eof}) ) {
464                                    
465                          my $len = next_part( '00dc' );                          my $len = next_part( '00dc' );
466                          last unless $len;                          last unless $len;
467                          printf "<< %s 00dc - frame %d jpeg %d 0x%x bytes\n", $name, $frame, $len, $len;                          printf "<< %s 00dc - part %d jpeg %d 0x%x bytes\n", $name, $frame, $len, $len if $verbose;
468                          mkjpg( x($len) );                          mkjpg( x($len) );
469    
470                          $len = next_part( '01wb', 0, 1 );                          $len = next_part( '01wb' );
471                          printf "<< %s 01wb - frame %d audio %d 0x%x bytes\n", $name, $frame, $len, $len;                          printf "<< %s 01wb - part %d audio %d 0x%x bytes\n", $name, $frame, $len, $len if $verbose;
472    
473                            my $audio_frame = x( $len );
474    
475                            if ( $dump_audio ) {
476                                    printf "#### dumping audio frame %d 0x%x bytes\n", length($audio_frame), length($audio_frame);
477                                    hex_dump( $audio_frame );
478                            }
479    
480                            # remove 8 bytes of something
481                            $audio_frame = substr( $audio_frame, 8 );
482    
483                            if ( length($audio_frame) % 2 == 0 ) {
484                                    print "#### even sized frame!";
485    #                               $audio_frame = substr( $audio_frame, 0, -1 );
486                            }
487    
488    #                       print $audio_fh mp3_frame;
489                            print $audio_fh $audio_frame || die "can't write audio frame in $apath: $!";
490    
491                            $frame_nr++;
492                  };                  };
493    
494          } else {          } else {
# Line 356  while ( ! defined($d->{eof}) ) { Line 496  while ( ! defined($d->{eof}) ) {
496          }          }
497  }  }
498    
499  my $cmd = "ffmpeg -i $dump_dir/%04d.jpg -r 16 -f $dump_avi";  my $cmd = "ffmpeg -i $dump_dir/%04d.jpg -r 16 -y $dump_avi";
500  system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";  system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";
501    
502    my $size = tell($audio_fh);
503    warn "## wav file size: $size\n";
504    
505    seek( $audio_fh, 4, 0 );
506    print $audio_fh pack("V", $size - 8);
507    seek( $audio_fh, $riff_header_len - 4, 0 );
508    print $audio_fh pack("V", $size - $riff_header_len);
509    
510    close($audio_fh) || die "can't close audio file $apath: $!";
511    
512    print ">>>> created $frame_nr frames $dump_avi ", -s $dump_avi, " and $apath ", -s $apath, "\n";

Legend:
Removed from v.21  
changed lines
  Added in v.25

  ViewVC Help
Powered by ViewVC 1.1.26