swf2ass/src/SWFProcessor.php

117 lines
3.5 KiB
PHP

<?php
namespace swf2ass;
use swf\SWF;
use swf2ass\actions\ActionList;
class SWFProcessor extends SWFTreeProcessor {
const BACKGROUND_OBJECT_ID = 0;
const BACKGROUND_OBJECT_DEPTH = 0;
private FillStyleRecord $background;
private float $frameRate;
private ?AudioStream $audio = null;
private Rectangle $viewPort;
private SWF $swf;
private int $expectedFrameCount;
public function __construct(SWF $swf) {
$this->swf = $swf;
parent::__construct(0, null);
$this->background = new FillStyleRecord(new Color(255, 255, 255));
$this->viewPort = Rectangle::fromArray($this->swf->header["frameSize"]);
$this->frameRate = $this->swf->header["frameRate"];
$this->expectedFrameCount = $this->swf->header["frameCount"];
}
public function getExpectedFrameCount() : int {
return $this->expectedFrameCount;
}
protected function current(): ?array {
return isset($this->swf->tags[$this->index]) ? $this->swf->parseTag($this->swf->tags[$this->index]) : null;
}
public function getFrameRate(): float {
return $this->frameRate;
}
public function getViewPort(): Rectangle {
return $this->viewPort;
}
public function getAudio() : ?AudioStream {
return $this->audio;
}
protected function process(ActionList $actionList): ?string {
$node = $this->current();
if ($node === null) {
return null;
}
switch ($node["tagType"]) {
case "SetBackgroundColor":
//TODO: implement Gradient
$this->background = new FillStyleRecord(Color::fromArray($node["backgroundColor"]));
return $node["tagType"];
case "SoundStreamHead":
case "SoundStreamHead2":
if($this->loops > 0){
break;
}
$this->audio = AudioStream::fromSoundStreamHeadTag($node);
return $node["tagType"];
case "DefineSound":
if($this->loops > 0){
break;
}
$this->audio = new AudioStream(0, 0, 0, 0);
$this->audio->setStartFrame($this->getFrame());
//TODO $this->audio = (object)["node" => $node, "start" => $this->getFrame(), "content" => []];
return $node["tagType"];
case "SoundStreamBlock":
if($this->loops > 0){
break;
}
if($this->audio !== null){
if($this->audio->getStartFrame() === null){
$this->audio->setStartFrame($this->getFrame());
}
$this->audio->addStreamBlock($node);
}
return $node["tagType"];
}
return parent::process($actionList);
}
public function nextFrameOutput(): ?FrameInformation {
$frame = $this->nextFrame();
if ($frame === null) {
return null;
}
if(!$this->isPlaying() and ($this->audio === null or $this->audio->getStartFrame() === null) or $this->getFrame() === 1){ //Force play till finding audio, or first frame is 0
$this->playing = true;
}
//TODO: actions?
$frame->addChild(self::BACKGROUND_OBJECT_DEPTH, new ViewFrame(self::BACKGROUND_OBJECT_ID, new DrawPathList([DrawPath::fill($this->background, new Shape($this->getViewPort()->draw()))])));
return new FrameInformation($this->frame - 1, $this->frameRate, $frame);
}
}