Add MP3 audio extraction

This commit is contained in:
DataHoarder 2022-01-07 21:03:03 +01:00
parent 7b81712ef8
commit fa58baceda
3 changed files with 116 additions and 11 deletions

100
src/AudioStream.php Normal file
View file

@ -0,0 +1,100 @@
<?php
namespace swf2ass;
class AudioStream{
const FORMAT_UNCOMPRESSED_NATIVE_ENDIAN = 0;
const FORMAT_UNCOMPRESSED_LITTLE_ENDIAN = 3;
const FORMAT_ADPCM = 1;
const FORMAT_MP3 = 2;
const FORMAT_NELLYMOSER_16 = 4;
const FORMAT_NELLYMOSER_8 = 5;
const FORMAT_NELLYMOSER = 6;
const FORMAT_SPEEX = 11;
private int $format;
private int $sampleRate;
private int $sampleSize;
private int $channels;
private ?int $start = null;
private array $frames = [];
public function __construct(int $format, int $sampleRate, int $sampleSize, int $channels){
$this->format = $format;
$this->sampleRate = $sampleRate;
$this->sampleSize = $sampleSize;
$this->channels = $channels;
}
public function getFormat() : int{
return $this->format;
}
public function setStartFrame(?int $start){
$this->start = $start;
}
public function getStartFrame() : ?int{
return $this->start;
}
public function addStreamBlock(array $node){
if($node["tagType"] !== "SoundStreamBlock"){
throw new \Exception("Invalid tag ". $node["tagType"] );
}
switch ($this->format){
case self::FORMAT_MP3:
$this->addMP3SoundData($node["soundStreamData"]);
break;
}
}
private function addMP3SoundData(string $bin){
$offset = 0;
[,$sampleCount] = unpack("v", $bin, $offset);
$offset += 2;
[,$seekSamples] = unpack("s", $bin, $offset);
$offset += 2;
$frameSize = $this->sampleRate <= 11025 ? 576 : 1152;
$this->frames[] = substr($bin, $offset);
}
public function getAudioData() : string{
//TODO: header?
return implode("", $this->frames);
}
public static function fromSoundStreamHeadTag(array $node) : ?AudioStream{
if(!isset($node["streamSoundCompression"]) or !isset($node["streamSoundRate"]) or !isset($node["streamSoundSize"]) or !isset($node["streamSoundType"])){
return null;
}
$rate = null;
switch ($node["streamSoundRate"]){
case 0:
$rate = 5512;
break;
case 1:
$rate = 11025;
break;
case 2:
$rate = 22050;
break;
case 3:
$rate = 44100;
break;
}
return new AudioStream($node["streamSoundCompression"], $rate, $node["streamSoundSize"] === 1 ? 16 : 8, $node["streamSoundType"] === 1 ? 2 : 1);
}
}

View file

@ -14,7 +14,7 @@ class SWFProcessor extends SWFTreeProcessor {
private float $frameRate;
private $audio = null;
private ?AudioStream $audio = null;
private Rectangle $viewPort;
@ -51,7 +51,7 @@ class SWFProcessor extends SWFTreeProcessor {
return $this->viewPort;
}
public function getAudio() {
public function getAudio() : ?AudioStream {
return $this->audio;
}
@ -68,18 +68,17 @@ class SWFProcessor extends SWFTreeProcessor {
return $node["tagType"];
case "SoundStreamHead":
case "SoundStreamHead2":
$this->audio = (object)["node" => $node, "start" => null, "content" => [],];
$this->audio = AudioStream::fromSoundStreamHeadTag($node);
return $node["tagType"];
case "DefineSound":
$this->audio = (object)["node" => $node, "start" => $this->getFrame(), "content" => []];
//TODO $this->audio = (object)["node" => $node, "start" => $this->getFrame(), "content" => []];
return $node["tagType"];
case "SoundStreamBlock":
if ($this->audio !== null) {
if ($this->audio->start === null) {
$this->audio->start = $this->getFrame();
if($this->audio !== null){
if($this->audio->getStartFrame() === null){
$this->audio->setStartFrame($this->getFrame());
}
//$audio .= substr($data, 2);
$this->audio->content[] = [$this->getFrame(), $node["soundStreamData"]];
$this->audio->addStreamBlock($node);
}
return $node["tagType"];
}

View file

@ -127,10 +127,10 @@ if ($swf->header["signature"]) {
while(($frame = $processor->nextFrameOutput()) !== null){
$audio = $processor->getAudio();
if($audio !== null and $frameOffset === 0){
if($audio->start === null){
if($audio->getStartFrame() === null){
continue;
}
$frameOffset = $audio->start;
$frameOffset = $audio->getStartFrame();
}
$lastFrame = $frame;
@ -222,6 +222,12 @@ if ($swf->header["signature"]) {
foreach ($assRenderer->flush($lastFrame) as $line){
fwrite($fp, $line . "\n");
}
if($processor->getAudio() !== null and $processor->getAudio()->getFormat() === \swf2ass\AudioStream::FORMAT_MP3){
$audioFp = fopen($argv[2] . ".mp3", "w+");
fwrite($audioFp, $processor->getAudio()->getAudioData());
fclose($audioFp);
}
}
if(count($testVectors) > 0){