• amv.pl

    27 28  
    387 387 print ">> created $frame_nr ", $no_jpeg_header ? 'raw' : '', " jpeg $path ", -s $path, " bytes\n" if $verbose;
    388 388 }
    389 389
    390 my ( $riff, $amv ) = x(12, 'Z4x4Z4');
    391 die "$path not RIFF but $riff" if $riff ne 'RIFF';
    392 die "$path not AMV but $amv" if $amv ne 'AMV ';
    390 #
    391 # IMA ADPCM decoder
    392 #
    393 393
    394 my $apath = "$dump_dir/audio.wav";
    395 open(my $audio_fh, '>', $apath) || die "can't open audio file $apath: $!";
    394 my @index_adjust = ( -1, -1, -1, -1, 2, 4, 6, 8 );
    396 395
    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,
    396 my @step_size = (
    397 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
    398 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
    399 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
    400 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
    401 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
    402 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
    403 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
    404 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
    405 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
    420 406 );
    421 407
    422 print $audio_fh pack 'a4VVa4V', (
    423 # time length of the data in samples
    424 'fact',4,
    425 220500,
    426 #
    427 'data',-1,
    408 my $pred_val = 0;
    409 my $step_idx = 0;
    410
    411 # This code is "borrowed" from the ALSA library
    412 # http://www.alsa-project.org
    413
    414 sub adpcm_decode_sample {
    415 my $code = shift;
    416
    417 my $pred_diff; # Predicted difference to next sample
    418 my $step; # holds previous step_size value
    419
    420 # Separate sign and magnitude
    421 my $sign = $code & 0x8;
    422 $code &= 0x7;
    423
    424 # Computes pred_diff = (code + 0.5) * step / 4,
    425 # but see comment in adpcm_coder.
    426
    427 $step = $step_size[$step_idx] || die "no step_size[$step_idx]";
    428
    429 # Compute difference and new predicted value
    430 $pred_diff = $step >> 3;
    431 my $i = 0x4;
    432 while( $i ) {
    433 if ($code & $i) {
    434 $pred_diff += $step;
    435 }
    436 $i >>= 1;
    437 $step >>= 1;
    438 }
    439 $pred_val += $sign ? -$pred_diff : $pred_diff;
    440
    441 # Clamp output value
    442 if ($pred_val > 32767) {
    443 $pred_val = 32767;
    444 } elsif ($pred_val < -32768) {
    445 $pred_val = -32768;
    446 }
    447
    448 # Find new step_size index value
    449 $step_idx += $index_adjust[$code];
    450
    451 if ($step_idx < 0) {
    452 $step_idx = 0;
    453 } elsif ($step_idx > 88) {
    454 $step_idx = 88;
    455 }
    456 return $pred_val;
    457 }
    458
    459 open(my $au_fh, '>', 'out.au') || die "can't open out.au: $!";
    460 print $au_fh pack 'a4N5', (
    461 # magic
    462 '.snd',
    463 # data offset
    464 24,
    465 # data size
    466 -1,
    467 # encoding - 16-bit linear PCM
    468 3,
    469 # sample rate
    470 22050,
    471 #channels
    472 1,
    428 473 );
    429 474
    430 my $riff_header_len = tell($audio_fh);
    475 sub audio_frame {
    476 my $data = shift || die "no data?";
    431 477
    478 my ( $origin, $index, $bytes ) = unpack 'ssL', substr($data,0,8);
    479
    480 warn "audio_frame origin $origin index $index bytes $bytes\n";
    481 hex_dump( substr($data,0,8) );
    482
    483 $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
    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
    432 555 while ( ! defined($d->{eof}) ) {
    433 556 my ( $list, $name ) = x(12,'A4x4A4');
    434 557 die "not LIST but $list" if $list ne 'LIST';
     
    479 602 }
    480 603
    481 604 # remove 8 bytes of something
    482 $audio_frame = substr( $audio_frame, 8 );
    605 # $audio_frame = substr( $audio_frame, 8 );
    483 606
    484 607 if ( length($audio_frame) % 2 == 0 ) {
    485 608 print "#### even sized frame!";
     
    487 610 }
    488 611
    489 612 # print $audio_fh mp3_frame;
    490 print $audio_fh $audio_frame || die "can't write audio frame in $apath: $!";
    613 audio_frame( $audio_frame );
    491 614
    492 615 $frame_nr++;
    493 616 };
     
    500 623 my $cmd = "ffmpeg -i $dump_dir/%04d.jpg -r 16 -y $dump_avi";
    501 624 system($cmd) == 0 || die "can't convert frames to avi using $cmd: $!";
    502 625
    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";
    626 print ">>>> created $frame_nr frames $dump_avi ", -s $dump_avi, "\n";