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

  ViewVC Help
Powered by ViewVC 1.1.26