ffmpeg-mappable-media/src/FFMpeg/FFProbe.php

269 lines
6 KiB
PHP
Raw Normal View History

2012-04-13 10:20:54 +02:00
<?php
2012-04-13 14:34:53 +02:00
/*
* 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.
*/
2012-04-13 10:20:54 +02:00
namespace FFMpeg;
2013-06-25 10:03:20 +02:00
use Alchemy\BinaryDriver\ConfigurationInterface;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache;
use FFMpeg\Driver\FFProbeDriver;
use FFMpeg\FFProbe\DataMapping\Format;
use FFMpeg\FFProbe\Mapper;
use FFMpeg\FFProbe\MapperInterface;
use FFMpeg\FFProbe\OptionsTester;
use FFMpeg\FFProbe\OptionsTesterInterface;
use FFMpeg\FFProbe\OutputParser;
use FFMpeg\FFProbe\OutputParserInterface;
2012-05-25 16:21:16 +02:00
use FFMpeg\Exception\InvalidArgumentException;
use FFMpeg\Exception\RuntimeException;
2013-06-25 10:03:20 +02:00
use Psr\Log\LoggerInterface;
2012-04-13 15:12:43 +02:00
2013-06-25 10:03:20 +02:00
class FFProbe
2012-04-13 10:20:54 +02:00
{
2013-06-25 10:03:20 +02:00
const TYPE_STREAMS = 'streams';
const TYPE_FORMAT = 'format';
/** @var Cache */
private $cache;
/** @var OptionsTesterInterface */
private $optionsTester;
/** @var OutputParserInterface */
private $parser;
/** @var FFProbeDriver */
private $ffprobe;
/** @var MapperInterface */
private $mapper;
public function __construct(FFProbeDriver $ffprobe, Cache $cache)
{
$this->ffprobe = $ffprobe;
$this->optionsTester = new OptionsTester($ffprobe, $cache);
$this->parser = new OutputParser();
$this->mapper = new Mapper();
$this->cache = $cache;
}
2012-04-13 10:20:54 +02:00
2013-06-25 10:03:20 +02:00
/**
* @return OutputParserInterface
*/
public function getParser()
{
return $this->parser;
}
2012-04-13 15:12:43 +02:00
/**
2013-06-25 10:03:20 +02:00
* @param OutputParserInterface $parser
2012-05-31 16:16:35 +02:00
*
2013-06-25 10:03:20 +02:00
* @return FFProbe
2012-04-13 15:12:43 +02:00
*/
2013-06-25 10:03:20 +02:00
public function setParser(OutputParserInterface $parser)
2012-04-13 10:20:54 +02:00
{
2013-06-25 10:03:20 +02:00
$this->parser = $parser;
2012-04-13 10:20:54 +02:00
2013-06-25 10:03:20 +02:00
return $this;
}
2013-06-25 10:03:20 +02:00
/**
* @return FFProbeDriver
*/
public function getFFProbeDriver()
{
return $this->ffprobe;
}
2012-04-13 10:20:54 +02:00
2013-06-25 10:03:20 +02:00
/**
* @param FFProbeDriver $ffprobe
*
* @return FFProbe
*/
public function setFFProbeDriver(FFProbeDriver $ffprobe)
{
$this->ffprobe = $ffprobe;
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
return $this;
}
/**
* @param OptionsTesterInterface $tester
*
* @return FFProbe
*/
public function setOptionsTester(OptionsTesterInterface $tester)
{
$this->optionsTester = $tester;
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
return $this;
}
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
/**
* @return OptionsTesterInterface
*/
public function getOptionsTester()
{
return $this->optionsTester;
}
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
/**
* @param Cache $cache
*
* @return FFProbe
*/
public function setCache(Cache $cache)
{
$this->cache = $cache;
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
return $this;
}
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
/**
* @return Cache
*/
public function getCache()
{
return $this->cache;
}
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
/**
* @return MapperInterface
*/
public function getMapper()
{
return $this->mapper;
}
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
/**
* @param MapperInterface $mapper
*
* @return FFProbe
*/
public function setMapper(MapperInterface $mapper)
{
$this->mapper = $mapper;
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
return $this;
2012-04-13 10:20:54 +02:00
}
2012-04-13 15:12:43 +02:00
/**
2013-06-25 10:03:20 +02:00
* @api
*
* Probe the format of a given file
*
* @param string $pathfile
2012-04-13 15:12:43 +02:00
*
2013-06-25 10:03:20 +02:00
* @return Format A Format object
2012-05-31 16:16:35 +02:00
*
2012-05-25 16:21:16 +02:00
* @throws InvalidArgumentException
* @throws RuntimeException
2012-04-13 15:12:43 +02:00
*/
2013-06-25 10:03:20 +02:00
public function format($pathfile)
2012-04-13 10:20:54 +02:00
{
2013-06-25 10:03:20 +02:00
return $this->probe($pathfile, '-show_format', static::TYPE_FORMAT);
}
2013-06-25 10:03:20 +02:00
/**
* @api
*
* Probe the streams contained in a given file
*
* @param string $pathfile
*
* @return StreamCollection A collection of streams
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function streams($pathfile)
{
return $this->probe($pathfile, '-show_streams', static::TYPE_STREAMS);
}
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
/**
* @api
*
* @param array|ConfigurationInterface $configuration
* @param LoggerInterface $logger
* @param Cache $cache
*
* @return FFProbe
*/
public static function create($configuration = array(), LoggerInterface $logger = null, Cache $cache = null)
{
if (null === $cache) {
$cache = new ArrayCache();
}
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
return new static(FFProbeDriver::create($configuration, $logger), $cache);
}
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
private function probe($pathfile, $command, $type, $allowJson = true)
{
if (!is_file($pathfile)) {
throw new InvalidArgumentException(sprintf(
'Invalid filepath %s, unable to read.', $pathfile
));
}
2012-05-31 15:54:28 +02:00
2013-06-25 10:03:20 +02:00
$id = sprintf('%s-%s', $command, $pathfile);
2013-06-25 10:03:20 +02:00
if ($this->cache->contains($id)) {
return $this->cache->fetch($id);
}
2013-06-25 10:03:20 +02:00
if (!$this->optionsTester->has($command)) {
throw new RuntimeException(sprintf(
'This version of ffprobe is too old and '
. 'does not support `%s` option, please upgrade', $command
));
}
2012-04-13 10:20:54 +02:00
2013-06-25 10:03:20 +02:00
$commands = array($pathfile, $command);
2012-05-25 16:21:16 +02:00
2013-06-25 10:03:20 +02:00
$parseIsToDo = false;
2012-05-25 16:21:16 +02:00
2013-06-25 10:03:20 +02:00
if ($allowJson && $this->optionsTester->has('-print_format')) {
$commands[] = '-print_format';
$commands[] = 'json';
} else {
$parseIsToDo = true;
2012-04-13 15:12:43 +02:00
}
2012-04-13 10:20:54 +02:00
2013-06-25 10:03:20 +02:00
$output = $this->ffprobe->command($commands);
2012-05-25 16:21:16 +02:00
2013-06-25 10:03:20 +02:00
if ($parseIsToDo) {
$data = $this->parser->parse($type, $output);
} else {
try {
// Malformed json may be retrieved
$data = $this->parseJson($output);
} catch (RuntimeException $e) {
return $this->probe($pathfile, $command, $type, false);
}
2012-04-13 10:20:54 +02:00
}
2013-06-25 10:03:20 +02:00
$ret = $this->mapper->map($type, $data);
$this->cache->save($id, $ret);
2012-05-25 16:21:16 +02:00
2013-06-25 10:03:20 +02:00
return $ret;
2012-04-13 10:20:54 +02:00
}
2013-06-25 10:03:20 +02:00
private function parseJson($data)
2012-04-13 10:20:54 +02:00
{
2013-06-25 10:03:20 +02:00
$ret = @json_decode($data, true);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new RuntimeException(sprintf('Unable to parse json %s', $ret));
}
return $ret;
2012-04-13 10:20:54 +02:00
}
}