2013-06-25 10:03:20 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This file is part of PHP-FFmpeg.
|
|
|
|
|
*
|
|
|
|
|
* (c) Alchemy <info@alchemy.fr>
|
|
|
|
|
*
|
|
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
|
* file that was distributed with this source code.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace FFMpeg\Media;
|
|
|
|
|
|
|
|
|
|
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
|
|
|
|
|
use FFMpeg\Filters\Frame\FrameFilterInterface;
|
|
|
|
|
use FFMpeg\Filters\Frame\FrameFilters;
|
|
|
|
|
use FFMpeg\Driver\FFMpegDriver;
|
|
|
|
|
use FFMpeg\FFProbe;
|
|
|
|
|
use FFMpeg\Exception\RuntimeException;
|
|
|
|
|
use FFMpeg\Coordinate\TimeCode;
|
|
|
|
|
|
|
|
|
|
class Frame extends AbstractMediaType
|
|
|
|
|
{
|
|
|
|
|
/** @var TimeCode */
|
|
|
|
|
private $timecode;
|
2013-09-04 19:50:38 +02:00
|
|
|
/** @var Video */
|
|
|
|
|
private $video;
|
2013-06-25 10:03:20 +02:00
|
|
|
|
2013-09-04 19:50:38 +02:00
|
|
|
public function __construct(Video $video, FFMpegDriver $driver, FFProbe $ffprobe, TimeCode $timecode)
|
2013-06-25 10:03:20 +02:00
|
|
|
{
|
2013-09-04 19:50:38 +02:00
|
|
|
parent::__construct($video->getPathfile(), $driver, $ffprobe);
|
2013-06-25 10:03:20 +02:00
|
|
|
$this->timecode = $timecode;
|
2013-09-04 19:50:38 +02:00
|
|
|
$this->video = $video;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the video related to the frame.
|
|
|
|
|
*
|
|
|
|
|
* @return Video
|
|
|
|
|
*/
|
|
|
|
|
public function getVideo()
|
|
|
|
|
{
|
|
|
|
|
return $this->video;
|
2013-06-25 10:03:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* {@inheritdoc}
|
|
|
|
|
*
|
|
|
|
|
* @return FrameFilters
|
|
|
|
|
*/
|
|
|
|
|
public function filters()
|
|
|
|
|
{
|
|
|
|
|
return new FrameFilters($this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* {@inheritdoc}
|
|
|
|
|
*
|
|
|
|
|
* @return Frame
|
|
|
|
|
*/
|
|
|
|
|
public function addFilter(FrameFilterInterface $filter)
|
|
|
|
|
{
|
|
|
|
|
$this->filters->add($filter);
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return TimeCode
|
|
|
|
|
*/
|
|
|
|
|
public function getTimeCode()
|
|
|
|
|
{
|
|
|
|
|
return $this->timecode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Saves the frame in the given filename.
|
|
|
|
|
*
|
|
|
|
|
* Uses the `unaccurate method by default.`
|
|
|
|
|
*
|
2021-03-02 15:39:45 +01:00
|
|
|
* @param string $pathfile
|
2020-12-23 11:14:24 +01:00
|
|
|
* @param bool $accurate
|
2021-03-02 15:39:45 +01:00
|
|
|
* @param bool $returnBase64
|
2013-06-25 10:03:20 +02:00
|
|
|
*
|
|
|
|
|
* @return Frame
|
|
|
|
|
*
|
|
|
|
|
* @throws RuntimeException
|
|
|
|
|
*/
|
2017-02-14 18:21:07 +01:00
|
|
|
public function save($pathfile, $accurate = false, $returnBase64 = false)
|
2013-06-25 10:03:20 +02:00
|
|
|
{
|
|
|
|
|
/**
|
2013-06-25 10:40:20 +02:00
|
|
|
* might be optimized with http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg
|
2013-06-25 10:03:20 +02:00
|
|
|
* @see http://ffmpeg.org/ffmpeg.html#Main-options
|
|
|
|
|
*/
|
2017-02-14 18:21:07 +01:00
|
|
|
$outputFormat = $returnBase64 ? "image2pipe" : "image2";
|
2013-06-25 10:03:20 +02:00
|
|
|
if (!$accurate) {
|
|
|
|
|
$commands = array(
|
2013-08-06 14:59:28 +02:00
|
|
|
'-y', '-ss', (string) $this->timecode,
|
2013-06-25 10:03:20 +02:00
|
|
|
'-i', $this->pathfile,
|
|
|
|
|
'-vframes', '1',
|
2017-02-14 18:21:07 +01:00
|
|
|
'-f', $outputFormat
|
2013-06-25 10:03:20 +02:00
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
$commands = array(
|
2013-08-06 14:59:28 +02:00
|
|
|
'-y', '-i', $this->pathfile,
|
2013-06-25 10:03:20 +02:00
|
|
|
'-vframes', '1', '-ss', (string) $this->timecode,
|
2017-02-14 18:21:07 +01:00
|
|
|
'-f', $outputFormat
|
2013-06-25 10:03:20 +02:00
|
|
|
);
|
|
|
|
|
}
|
2017-02-14 18:21:07 +01:00
|
|
|
|
|
|
|
|
if($returnBase64) {
|
|
|
|
|
array_push($commands, "-");
|
|
|
|
|
}
|
2013-06-25 10:03:20 +02:00
|
|
|
|
2013-09-04 19:52:24 +02:00
|
|
|
foreach ($this->filters as $filter) {
|
|
|
|
|
$commands = array_merge($commands, $filter->apply($this));
|
|
|
|
|
}
|
2013-12-17 17:39:24 +01:00
|
|
|
|
2018-05-28 14:00:32 +08:00
|
|
|
if (!$returnBase64) {
|
2018-05-17 11:12:58 +08:00
|
|
|
$commands = array_merge($commands, array($pathfile));
|
|
|
|
|
}
|
2013-09-04 19:52:24 +02:00
|
|
|
|
2013-06-25 10:03:20 +02:00
|
|
|
try {
|
2017-02-14 18:21:07 +01:00
|
|
|
if(!$returnBase64) {
|
|
|
|
|
$this->driver->command($commands);
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return $this->driver->command($commands);
|
|
|
|
|
}
|
2013-06-25 10:03:20 +02:00
|
|
|
} catch (ExecutionFailureException $e) {
|
|
|
|
|
$this->cleanupTemporaryFile($pathfile);
|
|
|
|
|
throw new RuntimeException('Unable to save frame', $e->getCode(), $e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|