log = $log; $this->width = $width; $this->height = $height; $this->frameRateNum = $frameRateNum; $this->frameRateDen = $frameRateDen; $this->outputFile = $outputFile; $this->images = []; $this->log->info('Initialized MeltProject ' . $this); } public function __toString() { return 'width:'.$this->width.' height:'.$this->height . ' framerate:'. $this->frameRateNum . ' outputFile ' . $this->outputFile; } public function addImage(string $path, int $in, int $out): void { $this->images[] = [ 'path' => $path, 'in' => $in, 'out' => $out ]; $this->log->info('Adding image', end($this->images)); } /** * Set the voiceover audio track. * * @param string $path */ public function setVoiceover(string $path): void { $this->audioFile = $path; $this->log->info('Adding audio track: ' . $path); } /** * Generate the XML document. * * @return DOMDocument The generated XML object. */ public function generateXml(): DOMDocument { $xml = new DOMDocument('1.0', 'utf-8'); $xml->formatOutput = true; $mlt = $this->createMltElement($xml); $xml->appendChild($mlt); $profile = $this->createProfileElement($xml); $mlt->appendChild($profile); $count = 0; $playlist = $this->createPlaylistElement($xml); foreach ($this->images as $image) { $producer = $this->createProducerElement($xml, $image, $count); $mlt->appendChild($producer); $entry = $this->createEntryElement($xml, $image, $count); $playlist->appendChild($entry); $count++; } $mlt->appendChild($playlist); $tractor0 = $this->createTractorElement($xml, 'tractor0'); $mlt->appendChild($tractor0); $multitrack0 = $this->createMultitrackElement($xml); $tractor0->appendChild($multitrack0); $imageTrack = $this->createImageTrackElement($xml); $multitrack0->appendChild($imageTrack); if ($this->audioFile !== null) { $voiceoverProducer = $this->createVoiceoverProducerElement($xml, $this->audioFile); $mlt->appendChild($voiceoverProducer); $voiceoverPlaylist = $this->createVoiceoverPlaylistElement($xml); $mlt->appendChild($voiceoverPlaylist); $voiceoverEntry = $this->createVoiceoverEntryElement($xml); $voiceoverPlaylist->appendChild($voiceoverEntry); $tractor1 = $this->createTractorElement($xml, 'tractor1'); $mlt->appendChild($tractor1); $multitrack1 = $this->createMultitrackElement($xml); $tractor1->appendChild($multitrack1); $trackForTractor0 = $this->createTrackElement($xml, 'tractor0'); $multitrack1->appendChild($trackForTractor0); $trackForVoiceoverPlaylist = $this->createTrackElement($xml, 'voiceover_playlist'); $multitrack1->appendChild($trackForVoiceoverPlaylist); } return $xml; } private function createMltElement(DOMDocument $xml): DOMElement { $mlt = $xml->createElement('mlt'); $mlt->setAttribute('LC_NUMERIC', 'C'); $mlt->setAttribute('producer', 'main_bin'); $mlt->setAttribute('version', '7.12.0'); $mlt->setAttribute('root', '/home/kash'); return $mlt; } private function createProfileElement(DOMDocument $xml): DOMElement { $profile = $xml->createElement('profile'); $profile->setAttribute('description', 'HD 1080p 25 fps'); $profile->setAttribute('width', $this->width); $profile->setAttribute('height', $this->height); $profile->setAttribute('progressive', '1'); $profile->setAttribute('sample_aspect_num', '1'); $profile->setAttribute('sample_aspect_den', '1'); $profile->setAttribute('display_aspect_num', '16'); $profile->setAttribute('display_aspect_den', '9'); $profile->setAttribute('frame_rate_num', $this->frameRateNum); $profile->setAttribute('frame_rate_den', $this->frameRateDen); $profile->setAttribute('colorspace', '709'); return $profile; } private function createPlaylistElement(DOMDocument $xml): DOMElement { $playlist = $xml->createElement('playlist'); $playlist->setAttribute('id', 'playlist0'); return $playlist; } private function createProducerElement(DOMDocument $xml, array $image, int $count): DOMElement { $producer = $xml->createElement('producer'); $producer->setAttribute('id', 'producer' . $count); $producer->setAttribute('in', $image['in']); $producer->setAttribute('out', $image['out']); $resource = $xml->createElement('property', $image['path']); $resource->setAttribute('name', 'resource'); $producer->appendChild($resource); $length = $xml->createElement('property', $image['out'] + 1); $length->setAttribute('name', 'length'); $producer->appendChild($length); return $producer; } private function createEntryElement(DOMDocument $xml, array $image, int $count): DOMElement { $entry = $xml->createElement('entry'); $entry->setAttribute('producer', 'producer' . $count); $entry->setAttribute('in', $image['in']); $entry->setAttribute('out', $image['out']); return $entry; } public function createTractorElement(DOMDocument $xml, string $id): DOMElement { $tractor = $xml->createElement('tractor'); $tractor->setAttribute('id', $id); return $tractor; } public function createTrackElement(DOMDocument $xml, string $producerId): DOMElement { $track = $xml->createElement('track'); $track->setAttribute('producer', $producerId); return $track; } private function createTransitionElement(DOMDocument $xml): DOMElement { $transition = $xml->createElement('transition'); $transition->setAttribute('in', '0'); $transition->setAttribute('out', $this->images[0]['out']); $transition->setAttribute('a_track', '0'); $transition->setAttribute('b_track', '1'); return $transition; } private function createTransitionProperties(): array { return [ ['mlt_service', 'mix'], ['start', '0'], ['end', $this->images[0]['out']], ['a_track', '0'], ['b_track', '1'], ]; } private function createPropertyElement(DOMDocument $xml, array $property): DOMElement { $prop = $xml->createElement('property', $property[1]); $prop->setAttribute('name', $property[0]); return $prop; } private function createVoiceoverProducerElement(DOMDocument $xml, string $path): DOMElement { $producer = $xml->createElement('producer'); $producer->setAttribute('id', 'voiceover'); $resource = $xml->createElement('property', $path); $resource->setAttribute('name', 'resource'); $producer->appendChild($resource); return $producer; } private function createVoiceoverPlaylistElement(DOMDocument $xml): DOMElement { $playlist = $xml->createElement('playlist'); $playlist->setAttribute('id', 'voiceover_playlist'); return $playlist; } private function createVoiceoverEntryElement(DOMDocument $xml): DOMElement { $entry = $xml->createElement('entry'); $entry->setAttribute('producer', 'voiceover'); return $entry; } private function createMultitrackElement(DOMDocument $xml): DOMElement { $multitrack = $xml->createElement('multitrack'); return $multitrack; } private function createVoiceoverTrackElement(DOMDocument $xml): DOMElement { $track = $xml->createElement('track'); $track->setAttribute('producer', 'voiceover_playlist'); return $track; } private function createImageTrackElement(DOMDocument $xml): DOMElement { $track = $xml->createElement('track'); $track->setAttribute('producer', 'playlist0'); return $track; } /** * Save the MLT project to a file. * * @param string $path * @return bool */ public function save(DOMDocument $xml, string $path): bool { return $xml->save($path) !== false; } }