/[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 27 by dpavlin, Sat Aug 18 11:21:40 2007 UTC revision 29 by dpavlin, Sun Aug 19 19:23:03 2007 UTC
# Line 46  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 387  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            foreach my $b ( map { ord($_) } split(//, substr($data,8)) ) {
487                    print $au_fh pack 'n', adpcm_decode_sample( $b >> 4 );          
488                    print $au_fh pack 'n', adpcm_decode_sample( $b & 15 );          
489            }
490    }
491    
492  my $riff_header_len = tell($audio_fh);  
493    sub x_audio_frame {
494            my $data = shift || die "no data?";
495    
496            my $apath = sprintf("$dump_dir/%04d.wav", $frame_nr );
497            open(my $audio_fh, '>', $apath) || die "can't open audio file $apath: $!";
498    
499            print $audio_fh pack 'a4Va4a4VvvVVv4', (
500                    # header 'RIFF', size
501                    'RIFF',-1,
502                    # type: 'WAVE'
503                    'WAVE',
504                    'fmt ',0x14,
505                    # format: DVI (IMA) ADPCM Wave Type
506                    0x11,
507                    # channels
508                    1,
509                    # samples/sec
510                    22050,
511                    # avg. bytes/sec (for esimation)
512                    11567,
513                    # block align (size of block)
514                    0x800,
515                    # bits per sample (mono data)
516                    4,
517                    # cbSize (ADPCM with 7 soefficient pairs)
518                    2,
519                    # nSamplesPerBlock
520                    # (((nBlockAlign - (7 * nChannels)) * 8) / (wBitsPerSample * nChannels)) + 2
521                    0x03f9,
522            );
523    
524            print $audio_fh pack 'a4VVa4V', (
525                    # time length of the data in samples
526                    'fact',4,
527                    220500,
528                    #
529                    'data',-1,
530            );
531    
532            my $riff_header_len = tell($audio_fh);
533    
534            print $audio_fh $data;
535    
536            my $size = tell($audio_fh);
537            warn "## wav file $apath size: $size\n";
538    
539            seek( $audio_fh, 4, 0 );
540            print $audio_fh pack("V", $size - 8);
541            seek( $audio_fh, $riff_header_len - 4, 0 );
542            print $audio_fh pack("V", $size - $riff_header_len);
543    
544            close($audio_fh) || die "can't close audio file $apath: $!";
545    }
546    
547    #
548    # read AMV file
549    #
550    
551    my ( $riff, $amv ) = x(12, 'Z4x4Z4');
552    die "$path not RIFF but $riff" if $riff ne 'RIFF';
553    die "$path not AMV but $amv" if $amv ne 'AMV ';
554    
555    my $fps = 16;
556    my $duration;
557    
558  while ( ! defined($d->{eof}) ) {  while ( ! defined($d->{eof}) ) {
559          my ( $list, $name ) = x(12,'A4x4A4');          my ( $list, $name ) = x(12,'A4x4A4');
# Line 446  while ( ! defined($d->{eof}) ) { Line 572  while ( ! defined($d->{eof}) ) {
572                          $h->{$n} = $v;                          $h->{$n} = $v;
573                  } x($len, 'Vx28VVVx8CCv');                  } x($len, 'Vx28VVVx8CCv');
574    
575                  printf "## %s %d*%d %s fps (%d ms/frame) %02d:%02d:%02d\n",                  $duration = sprintf('%02d:%02d:%02d', $h->{hh}, $h->{mm}, $h->{ss} );
576    
577                    printf "## %s %d*%d %s fps (%d ms/frame) %s\n",
578                          $path,                          $path,
579                          $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},                          $h->{width}, $h->{height}, $h->{fps}, $h->{ms_per_frame},
580                          $h->{hh}, $h->{mm}, $h->{ss};                          $duration;
581    
582                  $d->{amvh} = $h;                  $d->{amvh} = $h;
583                    $fps = $h->{fps};
584    
585          } elsif ( $name eq 'strl' ) {          } elsif ( $name eq 'strl' ) {
586    
# Line 478  while ( ! defined($d->{eof}) ) { Line 607  while ( ! defined($d->{eof}) ) {
607                                  hex_dump( $audio_frame );                                  hex_dump( $audio_frame );
608                          }                          }
609    
                         # 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 );  
                         }  
   
610  #                       print $audio_fh mp3_frame;  #                       print $audio_fh mp3_frame;
611                          print $audio_fh $audio_frame || die "can't write audio frame in $apath: $!";                          audio_frame( $audio_frame );
612    
613                          $frame_nr++;                          $frame_nr++;
614    
615                            if ( $frame_nr % $fps == 0 ) {
616                                    print "\n" if ( ( $frame_nr / $fps ) % 60 == 0 );
617                                    print ".";
618                            }
619                  };                  };
620    
621          } else {          } else {
# Line 497  while ( ! defined($d->{eof}) ) { Line 623  while ( ! defined($d->{eof}) ) {
623          }          }
624  }  }
625    
626  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";
627  system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";  system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";
628    
629  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.27  
changed lines
  Added in v.29

  ViewVC Help
Powered by ViewVC 1.1.26