/** * @param string $filename * @param Output $output * @param callable|null $callback * * @return Media */ public function save(string $filename, Output $output, callable $callback = null) : Media { $commandBuilder = new CommandBuilder($this, $output); $tmpDir = sys_get_temp_dir() . '/' . sha1(uniqid()) . '/'; $this->fs->mkdir($tmpDir); $passes = $output->getPasses(); $this->setCallbackProperty($callback, 'totalPasses', $passes); for ($i = 0, $l = $passes; $i < $l; ++$i) { if (null !== $callback) { $this->setCallbackProperty($callback, 'currentPass', $i + 1)->setCallbackProperty($callback, 'currentFrame', 0)->setCallbackProperty($callback, 'totalFrames', $this->getFrameCount($output)); } $this->ffmpeg->run(sprintf('%s %s %s %s "%s" -y', $commandBuilder->computeInputs(), $commandBuilder->computePasses($i, $passes, $tmpDir), $commandBuilder->computeFormatFilters(), $commandBuilder->computeParams(), $filename), get_class($callback) == 'Closure' || null === $callback ? $callback : array($callback, 'callback')); } $this->fs->remove($tmpDir); return $this; }
/** * @return string */ public function computeParams() : string { if (null === $this->output) { return ''; } if (null !== $this->output->getWidth() || null !== $this->output->getHeight()) { $originalWidth = $this->media->streams()->videos()->first()->get('width'); $originalHeight = $this->media->streams()->videos()->first()->get('height'); $originalRatio = $originalWidth / $originalHeight; if (null === $this->output->getWidth()) { $this->output->setWidth(round($this->output->getHeight() * $originalRatio)); } else { $this->output->setHeight(round($this->output->getWidth() / $originalRatio)); } if ($this->output->getUpscale()) { $this->output->addExtraParam('sws_flags', 'neighbor'); if ('h264' == $this->output->getVideoCodec()) { $this->output->addExtraParam('qp', 0); } } else { if ($this->output->getWidth() > $originalWidth || $this->output->getHeight() > $originalHeight) { $this->output->setWidth($originalWidth); $this->output->setHeight($originalHeight); } } $this->output->addExtraParam('s', sprintf('%sx%s', $this->output->getWidth(), $this->output->getHeight())); } $result = []; $params = $this->output->getParams(); if (true === $this->dryRun) { $params['acodec'] = 'copy'; $params['vcodec'] = 'copy'; $params['f'] = 'avi'; } foreach ($params as $param => $value) { if ('maps' == $param) { foreach ($value as $map) { $result[] = "-map {$map}"; } } else { $result[] = "-{$param} {$value}"; } } return implode(' ', $result); }
public function testFilter() { $video = FFMpeg::openFile($this->filenameVideo); $rotationFilter = new RotationFilter(RotationFilter::ROTATION_90); $video->format()->filters()->add(new ClipFilter(Timecode::createFromSeconds(10), Timecode::createFromSeconds(5))); $video->format()->filters()->add($rotationFilter); $output = Output::create()->setVideoKiloBitrate(1200)->setHeight($video->streams()->videos()->first()->get('height') * 2)->setUpscale(1)->setPasses(2); $commandBuilder = new CommandBuilder($video, $output); $inputs = $commandBuilder->computeInputs(); $this->assertTrue(is_numeric(strpos($inputs, sprintf('-i "%s"', $this->filenameVideo)))); $filters = $commandBuilder->computeFormatFilters(); $this->assertTrue(is_numeric(strpos($filters, sprintf('-ss %s', Timecode::createFromSeconds(5))))); $this->assertTrue(is_numeric(strpos($filters, sprintf('-t %s', Timecode::createFromSeconds(10))))); $this->assertTrue(is_numeric(strpos($filters, 'transpose=1'))); $video->save($this->filenameDestination, $output); $this->assertTrue(file_exists($this->filenameDestination)); $check = FFMpeg::openFile($this->filenameDestination); $this->assertEquals(10, floor($check->format()->get('duration'))); $this->assertEquals(2, $video->format()->filters()->count()); $video->format()->filters()->clear(); $this->assertEquals(0, $video->format()->filters()->count()); }