/[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 25 by dpavlin, Sat Aug 18 11:20:25 2007 UTC revision 30 by dpavlin, Fri Sep 14 19:35:32 2007 UTC
# Line 10  Line 10 
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  # 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 45  GetOptions( Line 46  GetOptions(
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  # by default, flip frames
49  #$jpegtran = '-flip vertical' unless defined($jpegtran);  $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 386  sub mkjpg { Line 389  sub mkjpg {
389          print ">> created $frame_nr ", $no_jpeg_header ? 'raw' : '', " jpeg $path ", -s $path, " bytes\n" if $verbose;          print ">> created $frame_nr ", $no_jpeg_header ? 'raw' : '', " jpeg $path ", -s $path, " bytes\n" if $verbose;
390  }  }
391    
392  my ( $riff, $amv ) = x(12, 'Z4x4Z4');  #
393  die "$path not RIFF but $riff" if $riff ne 'RIFF';  # IMA ADPCM decoder
394  die "$path not AMV but $amv" if $amv ne 'AMV ';  #
395    
396    my @index_adjust = ( -1, -1, -1, -1, 2, 4, 6, 8 );
397    
398    my @step_size = (
399            7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
400            19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
401            50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
402            130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
403            337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
404            876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
405            2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
406            5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
407            15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
408    );
409    
410  my $apath = "$dump_dir/audio.wav";  my $pred_val = 0;
411  open(my $audio_fh, '>', $apath) || die "can't open audio file $apath: $!";  my $step_idx = 0;
412    
413  print $audio_fh pack 'a4Va4a4VvvVVv4', (  # This code is "borrowed" from the ALSA library
414          # header 'RIFF', size  # http://www.alsa-project.org
415          'RIFF',-1,  
416          # type: 'WAVE'  sub adpcm_decode_sample {
417          'WAVE',          my $code = shift;
418          'fmt ',0x14,  
419          # format: DVI (IMA) ADPCM Wave Type          my $pred_diff;  # Predicted difference to next sample
420          0x11,          my $step;               # holds previous step_size value
421          # channels  
422          1,          # Separate sign and magnitude
423          # samples/sec          my $sign = $code & 0x8;
424            $code &= 0x7;
425    
426            # Computes pred_diff = (code + 0.5) * step / 4,
427            # but see comment in adpcm_coder.
428    
429            $step = $step_size[$step_idx] || die "no step_size[$step_idx]";
430    
431            # Compute difference and new predicted value
432            $pred_diff = $step >> 3;
433            my $i = 0x4;
434            while( $i ) {
435                    if ($code & $i) {
436                            $pred_diff += $step;
437                    }
438                    $i >>= 1;
439                    $step >>= 1;
440            }
441            $pred_val += $sign ? -$pred_diff : $pred_diff;
442    
443            # Clamp output value
444            if ($pred_val > 32767) {
445                    $pred_val = 32767;
446            } elsif ($pred_val < -32768) {
447                    $pred_val = -32768;
448            }
449    
450            # Find new step_size index value
451            $step_idx += $index_adjust[$code];
452    
453            if ($step_idx < 0) {
454                    $step_idx = 0;
455            } elsif ($step_idx > 88) {
456                    $step_idx = 88;
457            }
458            return $pred_val;
459    }
460    
461    my $au_path = "$dump_dir/sound.au";
462    open(my $au_fh, '>', $au_path) || die "can't open $au_path: $!";
463    print $au_fh pack 'a4N5', (
464            # magic
465            '.snd',
466            # data offset
467            24,
468            # data size
469            -1,
470            # encoding - 16-bit linear PCM
471            3,
472            # sample rate
473          22050,          22050,
474          # avg. bytes/sec (for esimation)          #channels
475          11567,          1,
         # block align (size of block)  
         0x800,  
         # bits per sample (mono data)  
         4,  
         # cbSize (ADPCM with 7 soefficient pairs)  
         2,  
         # nSamplesPerBlock  
         # (((nBlockAlign - (7 * nChannels)) * 8) / (wBitsPerSample * nChannels)) + 2  
         0x0ff9,  
476  );  );
477    
478  print $audio_fh pack 'a4VVa4V', (  sub audio_frame {
479          # time length of the data in samples          my $data = shift || die "no data?";
480          'fact',4,  
481          220500,          my ( $origin, $index, $bytes ) = unpack 'ssL', substr($data,0,8);
482          #  
483          'data',-1,          $pred_val = $origin;
484  );          $step_idx = $index;
485    
486            my $size = 0;
487    
488  my $riff_header_len = tell($audio_fh);          foreach my $b ( map { ord($_) } split(//, substr($data,8)) ) {
489                    print $au_fh pack 'n', adpcm_decode_sample( $b >> 4 );          
490                    print $au_fh pack 'n', adpcm_decode_sample( $b & 15 );          
491                    $size += 2;
492            }
493    
494            warn "length isn't corrent $bytes != $size" if $bytes != $size;
495    }
496    
497    
498    sub x_audio_frame {
499            my $data = shift || die "no data?";
500    
501            my $apath = sprintf("$dump_dir/%04d.wav", $frame_nr );
502            open(my $audio_fh, '>', $apath) || die "can't open audio file $apath: $!";
503    
504            print $audio_fh pack 'a4Va4a4VvvVVv4', (
505                    # header 'RIFF', size
506                    'RIFF',-1,
507                    # type: 'WAVE'
508                    'WAVE',
509                    'fmt ',0x14,
510                    # format: DVI (IMA) ADPCM Wave Type
511                    0x11,
512                    # channels
513                    1,
514                    # samples/sec
515                    22050,
516                    # avg. bytes/sec (for esimation)
517                    11567,
518                    # block align (size of block)
519                    0x800,
520                    # bits per sample (mono data)
521                    4,
522                    # cbSize (ADPCM with 7 soefficient pairs)
523                    2,
524                    # nSamplesPerBlock
525                    # (((nBlockAlign - (7 * nChannels)) * 8) / (wBitsPerSample * nChannels)) + 2
526                    0x03f9,
527            );
528    
529            print $audio_fh pack 'a4VVa4V', (
530                    # time length of the data in samples
531                    'fact',4,
532                    220500,
533                    #
534                    'data',-1,
535            );
536    
537            my $riff_header_len = tell($audio_fh);
538    
539            print $audio_fh $data;
540    
541            my $size = tell($audio_fh);
542            warn "## wav file $apath size: $size\n";
543    
544            seek( $audio_fh, 4, 0 );
545            print $audio_fh pack("V", $size - 8);
546            seek( $audio_fh, $riff_header_len - 4, 0 );
547            print $audio_fh pack("V", $size - $riff_header_len);
548    
549            close($audio_fh) || die "can't close audio file $apath: $!";
550    }
551    
552    #
553    # read AMV file
554    #
555    
556    my ( $riff, $amv ) = x(12, 'Z4x4Z4');
557    die "$path not RIFF but $riff" if $riff ne 'RIFF';
558    die "$path not AMV but $amv" if $amv ne 'AMV ';
559    
560    my $fps = 16;
561    my $duration;
562    
563  while ( ! defined($d->{eof}) ) {  while ( ! defined($d->{eof}) ) {
564          my ( $list, $name ) = x(12,'A4x4A4');          my ( $list, $name ) = x(12,'A4x4A4');
# Line 445  while ( ! defined($d->{eof}) ) { Line 577  while ( ! defined($d->{eof}) ) {
577                          $h->{$n} = $v;                          $h->{$n} = $v;
578                  } x($len, 'Vx28VVVx8CCv');                  } x($len, 'Vx28VVVx8CCv');
579    
580                  printf "## %s %d*%d %s fps (%d ms/frame) %02d:%02d:%02d\n",                  $duration = sprintf('%02d:%02d:%02d', $h->{hh}, $h->{mm}, $h->{ss} );
581    
582                    printf "## %s %d*%d %s fps (%d ms/frame) %s\n",
583                          $path,                          $path,
584                          $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},                          $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},
585                          $h->{hh}, $h->{mm}, $h->{ss};                          $duration;
586    
587                  $d->{amvh} = $h;                  $d->{amvh} = $h;
588                    $fps = $h->{fps};
589    
590          } elsif ( $name eq 'strl' ) {          } elsif ( $name eq 'strl' ) {
591    
# Line 477  while ( ! defined($d->{eof}) ) { Line 612  while ( ! defined($d->{eof}) ) {
612                                  hex_dump( $audio_frame );                                  hex_dump( $audio_frame );
613                          }                          }
614    
                         # remove 8 bytes of something  
                         $audio_frame = substr( $audio_frame, 8 );  
   
                         if ( length($audio_frame) % 2 == 0 ) {  
                                 print "#### even sized frame!";  
 #                               $audio_frame = substr( $audio_frame, 0, -1 );  
                         }  
   
615  #                       print $audio_fh mp3_frame;  #                       print $audio_fh mp3_frame;
616                          print $audio_fh $audio_frame || die "can't write audio frame in $apath: $!";                          audio_frame( $audio_frame );
617    
618                          $frame_nr++;                          $frame_nr++;
619    
620                            if ( $frame_nr % $fps == 0 ) {
621                                    print "\n" if ( ( $frame_nr / $fps ) % 60 == 0 );
622                                    print ".";
623                            }
624                  };                  };
625    
626          } else {          } else {
# Line 496  while ( ! defined($d->{eof}) ) { Line 628  while ( ! defined($d->{eof}) ) {
628          }          }
629  }  }
630    
631  my $cmd = "ffmpeg -i $dump_dir/%04d.jpg -r 16 -y $dump_avi";  my $cmd = "ffmpeg -r $fps -i $dump_dir/%04d.jpg -i $au_path -y $dump_avi";
632  system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";  system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";
633    
634  my $size = tell($audio_fh);  print ">>>> created $frame_nr frames $dump_avi ", -s $dump_avi, "\n";
 warn "## wav file size: $size\n";  
   
 seek( $audio_fh, 4, 0 );  
 print $audio_fh pack("V", $size - 8);  
 seek( $audio_fh, $riff_header_len - 4, 0 );  
 print $audio_fh pack("V", $size - $riff_header_len);  
   
 close($audio_fh) || die "can't close audio file $apath: $!";  
   
 print ">>>> created $frame_nr frames $dump_avi ", -s $dump_avi, " and $apath ", -s $apath, "\n";  

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

  ViewVC Help
Powered by ViewVC 1.1.26