/[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 33 by dpavlin, Mon Oct 1 20:26:13 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 121  sub x { Line 123  sub x {
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 "## next_part %s - %d 0x%x bytes\n", $part, $len, $len if $debug;          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    
# Line 157  sub quality { Line 163  sub quality {
163          return $out;          return $out;
164  }  }
165    
 sub mp3_frame {  
         my $frame = join('',  
                 # Frame sync (all bits set)  
                 1 x 11 .  
                 # MPEG Audio version ID  
                 # 00 - MPEG Version 2.5 (unofficial)  
                 # 01 - reserved  
                 # 10 - MPEG Version 2 (ISO/IEC 13818-3)  
                 # 11 - MPEG Version 1 (ISO/IEC 11172-3)  
                 1,0,  
                 # Layer description  
                 # 00 - reserved  
                 # 01 - Layer III  
                 # 10 - Layer II  
                 # 11 - Layer I  
                 0,1,  
                 # Protection bit  
                 # 0 - Protected by CRC (16bit crc follows header)  
                 # 1 - Not protected  
                 0,  
                 # Bitrate index  
                 0,0,0,0,  
                 # Sampling rate frequency index (22050)  
                 0,0,  
                 # Padding bit  
                 # 0 - frame is not padded  
                 # 1 - frame is padded with one extra slot  
                 0,  
                 # Private bit  
                 0,  
                 # Channel Mode  
                 # 00 - Stereo  
                 # 01 - Joint stereo (Stereo)  
                 # 10 - Dual channel (2 mono channels)  
                 # 11 - Single channel (Mono)  
                 1,1,  
                 # Mode extension (Only if Joint stereo)  
                 0,0,  
                 # Copyright  
                 0,  
                 # Original  
                 0,  
                 # Emphasis  
                 # 00 - none  
                 # 01 - 50/15 ms  
                 # 10 - reserved  
                 # 11 - CCIT J.17  
                 0,0,  
         );  
   
         die "frame must have 32 bits, not ", length($frame), " for $frame" if length($frame) != 32;  
   
         my $bits = pack("b32", $frame);  
   
         die "packed bits must be 4 bytes, not $bits" if length($bits) != 4;  
   
         my $t = $frame;  
         $t =~ s/(.{8})/$1 /g;  
         warn "## mp3 frame frame = $t\n";  
   
         return $bits;  
 }  
   
166  my @subframes;  my @subframes;
167  my $frame_nr = 1;  my $frame_nr = 1;
168    
# Line 387  sub mkjpg { Line 330  sub mkjpg {
330          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;
331  }  }
332    
333  my ( $riff, $amv ) = x(12, 'Z4x4Z4');  #
334  die "$path not RIFF but $riff" if $riff ne 'RIFF';  # IMA ADPCM decoder
335  die "$path not AMV but $amv" if $amv ne 'AMV ';  #
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 $apath = "$dump_dir/audio.wav";  my $pred_val = 0;
352  open(my $audio_fh, '>', $apath) || die "can't open audio file $apath: $!";  my $step_idx = 0;
353    
354  print $audio_fh pack 'a4Va4a4VvvVVv4', (  # This code is "borrowed" from the ALSA library
355          # header 'RIFF', size  # http://www.alsa-project.org
356          'RIFF',-1,  
357          # type: 'WAVE'  sub adpcm_decode_sample {
358          'WAVE',          my $code = shift;
359          'fmt ',0x14,  
360          # format: DVI (IMA) ADPCM Wave Type          my $pred_diff;  # Predicted difference to next sample
361          0x11,          my $step;               # holds previous step_size value
362          # channels  
363          1,          # Separate sign and magnitude
364          # samples/sec          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,          22050,
415          # avg. bytes/sec (for esimation)          #channels
416          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,  
417  );  );
418    
419  print $audio_fh pack 'a4VVa4V', (  sub audio_frame {
420          # time length of the data in samples          my $data = shift || die "no data?";
         'fact',4,  
         220500,  
         #  
         'data',-1,  
 );  
421    
422  my $riff_header_len = tell($audio_fh);          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');
443    die "$path not RIFF but $riff" if $riff ne 'RIFF';
444    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');
# Line 446  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 460  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 - part %d jpeg %d 0x%x bytes\n", $name, $frame, $len, $len if $verbose;  
                         mkjpg( x($len) );  
   
                         $len = next_part( '01wb' );  
                         printf "<< %s 01wb - part %d audio %d 0x%x bytes\n", $name, $frame, $len, $len if $verbose;  
   
                         my $audio_frame = x( $len );  
   
                         if ( $dump_audio ) {  
                                 printf "#### dumping audio frame %d 0x%x bytes\n", length($audio_frame), length($audio_frame);  
                                 hex_dump( $audio_frame );  
                         }  
487    
488                          # remove 8 bytes of something                          my $parts = 0;
                         $audio_frame = substr( $audio_frame, 8 );  
489    
490                          if ( length($audio_frame) % 2 == 0 ) {                          while ( $parts < 2 ) {
                                 print "#### even sized frame!";  
 #                               $audio_frame = substr( $audio_frame, 0, -1 );  
                         }  
491    
492  #                       print $audio_fh mp3_frame;                                  my ( $len, $part ) = next_part();
493                          print $audio_fh $audio_frame || die "can't write audio frame in $apath: $!";  
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++;                          $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 {
# Line 497  while ( ! defined($d->{eof}) ) { Line 536  while ( ! defined($d->{eof}) ) {
536          }          }
537  }  }
538    
539  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";
540  system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";  system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";
541    
542  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.33

  ViewVC Help
Powered by ViewVC 1.1.26