Version 0.3
This commit is contained in:
parent
0d69145ec3
commit
ad3a5af623
130 changed files with 7283 additions and 2627 deletions
80
src/FFMpeg/FFProbe/DataMapping/AbstractData.php
Normal file
80
src/FFMpeg/FFProbe/DataMapping/AbstractData.php
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?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\FFProbe\DataMapping;
|
||||
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
|
||||
abstract class AbstractData implements \Countable
|
||||
{
|
||||
private $properties;
|
||||
|
||||
public function __construct(array $properties)
|
||||
{
|
||||
$this->properties = $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if data has property
|
||||
*
|
||||
* @param string $property
|
||||
* @return Boolean
|
||||
*/
|
||||
public function has($property)
|
||||
{
|
||||
return isset($this->properties[$property]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property value given its name
|
||||
*
|
||||
* @param string $property
|
||||
* @return mixed
|
||||
*
|
||||
* @throws InvalidArgumentException In case the data does not have the property
|
||||
*/
|
||||
public function get($property)
|
||||
{
|
||||
if (!isset($this->properties[$property])) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid property `%s`.', $property));
|
||||
}
|
||||
|
||||
return $this->properties[$property];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all property names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function keys()
|
||||
{
|
||||
return array_keys($this->properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all properties and their values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->properties);
|
||||
}
|
||||
}
|
||||
16
src/FFMpeg/FFProbe/DataMapping/Format.php
Normal file
16
src/FFMpeg/FFProbe/DataMapping/Format.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?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\FFProbe\DataMapping;
|
||||
|
||||
class Format extends AbstractData
|
||||
{
|
||||
}
|
||||
35
src/FFMpeg/FFProbe/DataMapping/Stream.php
Normal file
35
src/FFMpeg/FFProbe/DataMapping/Stream.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?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\FFProbe\DataMapping;
|
||||
|
||||
class Stream extends AbstractData
|
||||
{
|
||||
/**
|
||||
* Returns true if the stream is an audio stream
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isAudio()
|
||||
{
|
||||
return $this->has('codec_type') ? 'audio' === $this->get('codec_type') : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the stream is a video stream
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isVideo()
|
||||
{
|
||||
return $this->has('codec_type') ? 'video' === $this->get('codec_type') : false;
|
||||
}
|
||||
}
|
||||
99
src/FFMpeg/FFProbe/DataMapping/StreamCollection.php
Normal file
99
src/FFMpeg/FFProbe/DataMapping/StreamCollection.php
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<?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\FFProbe\DataMapping;
|
||||
|
||||
class StreamCollection implements \Countable, \IteratorAggregate
|
||||
{
|
||||
private $streams;
|
||||
|
||||
public function __construct(array $streams = array())
|
||||
{
|
||||
$this->streams = array_values($streams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first stream of the collection, null if the collection is
|
||||
* empty.
|
||||
*
|
||||
* @return null|Stream
|
||||
*/
|
||||
public function first()
|
||||
{
|
||||
$stream = reset($this->streams);
|
||||
|
||||
return $stream ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a stream to the collection
|
||||
*
|
||||
* @param Stream $stream
|
||||
*
|
||||
* @return StreamCollection
|
||||
*/
|
||||
public function add(Stream $stream)
|
||||
{
|
||||
$this->streams[] = $stream;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new StreamCollection with only video streams
|
||||
*
|
||||
* @return StreamCollection
|
||||
*/
|
||||
public function videos()
|
||||
{
|
||||
return new static(array_filter($this->streams, function (Stream $stream) {
|
||||
return $stream->isVideo();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new StreamCollection with only audio streams
|
||||
*
|
||||
* @return StreamCollection
|
||||
*/
|
||||
public function audios()
|
||||
{
|
||||
return new static(array_filter($this->streams, function (Stream $stream) {
|
||||
return $stream->isAudio();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->streams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of contained streams
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return $this->streams;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator($this->streams);
|
||||
}
|
||||
}
|
||||
54
src/FFMpeg/FFProbe/Mapper.php
Normal file
54
src/FFMpeg/FFProbe/Mapper.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?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\FFProbe;
|
||||
|
||||
use FFMpeg\FFProbe;
|
||||
use FFMpeg\FFProbe\DataMapping\Format;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
|
||||
class Mapper implements MapperInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function map($type, $data)
|
||||
{
|
||||
switch ($type) {
|
||||
case FFProbe::TYPE_FORMAT:
|
||||
return $this->mapFormat($data);
|
||||
case FFProbe::TYPE_STREAMS:
|
||||
return $this->mapStreams($data);
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid type `%s`.', $type
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private function mapFormat($data)
|
||||
{
|
||||
return new Format($data['format']);
|
||||
}
|
||||
|
||||
private function mapStreams($data)
|
||||
{
|
||||
$streams = new StreamCollection();
|
||||
|
||||
foreach ($data['streams'] as $properties) {
|
||||
$streams->add(new Stream($properties));
|
||||
}
|
||||
|
||||
return $streams;
|
||||
}
|
||||
}
|
||||
27
src/FFMpeg/FFProbe/MapperInterface.php
Normal file
27
src/FFMpeg/FFProbe/MapperInterface.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?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\FFProbe;
|
||||
|
||||
interface MapperInterface
|
||||
{
|
||||
/**
|
||||
* Maps data given its type
|
||||
*
|
||||
* @param string $type One of FFProbe::TYPE_* constant
|
||||
* @param string $data The data
|
||||
*
|
||||
* @return Format|Stream
|
||||
*
|
||||
* @throws InvalidArgumentException In case the type is not supported
|
||||
*/
|
||||
public function map($type, $data);
|
||||
}
|
||||
64
src/FFMpeg/FFProbe/OptionsTester.php
Normal file
64
src/FFMpeg/FFProbe/OptionsTester.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?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\FFProbe;
|
||||
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
use FFMpeg\Driver\FFProbeDriver;
|
||||
|
||||
class OptionsTester implements OptionsTesterInterface
|
||||
{
|
||||
/** @var FFProbeDriver */
|
||||
private $ffprobe;
|
||||
/** @var Cache */
|
||||
private $cache;
|
||||
|
||||
public function __construct(FFProbeDriver $ffprobe, Cache $cache)
|
||||
{
|
||||
$this->ffprobe = $ffprobe;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
$id = sprintf('option-%s', $name);
|
||||
|
||||
if ($this->cache->contains($id)) {
|
||||
return $this->cache->fetch($id);
|
||||
}
|
||||
|
||||
$output = $this->retrieveHelpOutput();
|
||||
|
||||
$ret = (Boolean) preg_match('/^'.$name.'/m', $output);
|
||||
|
||||
$this->cache->save($id, $ret);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function retrieveHelpOutput()
|
||||
{
|
||||
$id = 'help';
|
||||
|
||||
if ($this->cache->contains($id)) {
|
||||
return $this->cache->fetch($id);
|
||||
}
|
||||
|
||||
$output = $this->ffprobe->command(array('-help', '-loglevel', 'quiet'));
|
||||
|
||||
$this->cache->save($id, $output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
24
src/FFMpeg/FFProbe/OptionsTesterInterface.php
Normal file
24
src/FFMpeg/FFProbe/OptionsTesterInterface.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?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\FFProbe;
|
||||
|
||||
interface OptionsTesterInterface
|
||||
{
|
||||
/**
|
||||
* Tells if the given option is supported by ffprobe
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function has($name);
|
||||
}
|
||||
125
src/FFMpeg/FFProbe/OutputParser.php
Normal file
125
src/FFMpeg/FFProbe/OutputParser.php
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<?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\FFProbe;
|
||||
|
||||
use FFMpeg\FFProbe;
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
|
||||
class OutputParser implements OutputParserInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse($type, $data)
|
||||
{
|
||||
switch ($type) {
|
||||
case FFProbe::TYPE_FORMAT:
|
||||
return $this->parseFormat($data);
|
||||
break;
|
||||
case FFProbe::TYPE_STREAMS:
|
||||
return $this->parseStreams($data);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Unknown data type %s', $type));
|
||||
}
|
||||
}
|
||||
|
||||
private function parseFormat($data)
|
||||
{
|
||||
$ret = array();
|
||||
|
||||
foreach (explode(PHP_EOL, $data) as $line) {
|
||||
|
||||
if (in_array($line, array('[FORMAT]', '[/FORMAT]'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$chunks = explode('=', $line);
|
||||
$key = array_shift($chunks);
|
||||
|
||||
if ('' === trim($key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = trim(implode('=', $chunks));
|
||||
|
||||
if ('nb_streams' === $key) {
|
||||
$value = (int) $value;
|
||||
}
|
||||
|
||||
if (0 === strpos($key, 'TAG:')) {
|
||||
if (!isset($ret['tags'])) {
|
||||
$ret['tags'] = array();
|
||||
}
|
||||
$ret['tags'][substr($key, 4)] = $value;
|
||||
} else {
|
||||
$ret[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return array('format' => $ret);
|
||||
}
|
||||
|
||||
private function parseStreams($data)
|
||||
{
|
||||
$ret = array();
|
||||
$n = -1;
|
||||
|
||||
foreach (explode(PHP_EOL, $data) as $line) {
|
||||
|
||||
if ($line == '[STREAM]') {
|
||||
$n ++;
|
||||
$ret[$n] = array();
|
||||
continue;
|
||||
}
|
||||
if ($line == '[/STREAM]') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$chunks = explode('=', $line);
|
||||
$key = array_shift($chunks);
|
||||
|
||||
if ('' === trim($key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = trim(implode('=', $chunks));
|
||||
|
||||
if ('N/A' === $value) {
|
||||
continue;
|
||||
}
|
||||
if ('profile' === $key && 'unknown' === $value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($key, array('index', 'width', 'height', 'channels', 'bits_per_sample', 'has_b_frames', 'level', 'start_pts', 'duration_ts'))) {
|
||||
$value = (int) $value;
|
||||
}
|
||||
|
||||
if (0 === strpos($key, 'TAG:')) {
|
||||
if (!isset($ret[$n]['tags'])) {
|
||||
$ret[$n]['tags'] = array();
|
||||
}
|
||||
$ret[$n]['tags'][substr($key, 4)] = $value;
|
||||
} elseif (0 === strpos($key, 'DISPOSITION:')) {
|
||||
if (!isset($ret[$n]['disposition'])) {
|
||||
$ret[$n]['disposition'] = array();
|
||||
}
|
||||
$ret[$n]['disposition'][substr($key, 12)] = $value;
|
||||
} else {
|
||||
$ret[$n][$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return array('streams' => $ret);
|
||||
}
|
||||
}
|
||||
27
src/FFMpeg/FFProbe/OutputParserInterface.php
Normal file
27
src/FFMpeg/FFProbe/OutputParserInterface.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?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\FFProbe;
|
||||
|
||||
interface OutputParserInterface
|
||||
{
|
||||
/**
|
||||
* Parses ffprobe raw output
|
||||
*
|
||||
* @param string $type One of FFProbe::TYPE_* constant
|
||||
* @param string $data The data
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws InvalidArgumentException In case the type is not supported
|
||||
*/
|
||||
public function parse($type, $data);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue