Version 0.3
This commit is contained in:
parent
0d69145ec3
commit
ad3a5af623
130 changed files with 7283 additions and 2627 deletions
248
src/FFMpeg/Coordinate/AspectRatio.php
Normal file
248
src/FFMpeg/Coordinate/AspectRatio.php
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Alchemy <dev.team@alchemy.fr>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Coordinate;
|
||||
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
|
||||
// see http://en.wikipedia.org/wiki/List_of_common_resolutions
|
||||
class AspectRatio
|
||||
{
|
||||
// named 4:3 or 1.33:1 Traditional TV
|
||||
const AR_4_3 = '4/3';
|
||||
// named 16:9 or 1.77:1 HD video standard
|
||||
const AR_16_9 = '16/9';
|
||||
|
||||
// named 3:2 or 1.5:1 see http://en.wikipedia.org/wiki/135_film
|
||||
const AR_3_2 = '3/2';
|
||||
// named 5:3 or 1.66:1 see http://en.wikipedia.org/wiki/Super_16_mm
|
||||
const AR_5_3 = '5/3';
|
||||
|
||||
// mostly used in Photography
|
||||
const AR_5_4 = '5/4';
|
||||
const AR_1_1 = '1/1';
|
||||
|
||||
// 1.85:1 US widescreen cinema standard see http://en.wikipedia.org/wiki/Widescreen#Film
|
||||
const AR_1_DOT_85_1 = '1.85:1';
|
||||
// 2.39:1 or 2.40:1 Current widescreen cinema standard see http://en.wikipedia.org/wiki/Anamorphic_format
|
||||
const AR_2_DOT_39_1 = '2.39:1';
|
||||
|
||||
// Rotated constants
|
||||
|
||||
// Rotated 4:3
|
||||
const AR_ROTATED_3_4 = '3/4';
|
||||
// Rotated 16:9
|
||||
const AR_ROTATED_9_16 = '9/16';
|
||||
|
||||
// Rotated 3:2
|
||||
const AR_ROTATED_2_3 = '2/3';
|
||||
// Rotated 5:3
|
||||
const AR_ROTATED_3_5 = '3/5';
|
||||
|
||||
// Rotated 5:4
|
||||
const AR_ROTATED_4_5 = '4/5';
|
||||
|
||||
// Rotated 1.85
|
||||
const AR_ROTATED_1_DOT_85 = '1/1.85';
|
||||
// Rotated 2.39
|
||||
const AR_ROTATED_2_DOT_39 = '1/2.39';
|
||||
|
||||
/** @var float */
|
||||
private $ratio;
|
||||
|
||||
public function __construct($ratio)
|
||||
{
|
||||
$this->ratio = $ratio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the ratio.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->ratio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the best width for given height and modulus.
|
||||
*
|
||||
* @param Integer $height
|
||||
* @param Integer $modulus
|
||||
*
|
||||
* @return Integer
|
||||
*/
|
||||
public function calculateWidth($height, $modulus = 1)
|
||||
{
|
||||
$maxPossibleWidth = $this->getMultipleUp(ceil($this->ratio * $height), $modulus);
|
||||
$minPossibleWidth = $this->getMultipleDown(floor($this->ratio * $height), $modulus);
|
||||
|
||||
$maxRatioDiff = abs($this->ratio - ($maxPossibleWidth / $height));
|
||||
$minRatioDiff = abs($this->ratio - ($minPossibleWidth / $height));
|
||||
|
||||
return $maxRatioDiff < $minRatioDiff ? $maxPossibleWidth : $minPossibleWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the best height for given width and modulus.
|
||||
*
|
||||
* @param Integer $width
|
||||
* @param Integer $modulus
|
||||
*
|
||||
* @return Integer
|
||||
*/
|
||||
public function calculateHeight($width, $modulus = 1)
|
||||
{
|
||||
$maxPossibleHeight = $this->getMultipleUp(ceil($width / $this->ratio), $modulus);
|
||||
$minPossibleHeight = $this->getMultipleDown(floor($width / $this->ratio), $modulus);
|
||||
|
||||
$maxRatioDiff = abs($this->ratio - ($width / $maxPossibleHeight));
|
||||
$minRatioDiff = abs($this->ratio - ($width / $minPossibleHeight));
|
||||
|
||||
return $maxRatioDiff < $minRatioDiff ? $maxPossibleHeight : $minPossibleHeight;
|
||||
}
|
||||
|
||||
private function getMultipleUp($value, $multiple)
|
||||
{
|
||||
while (0 !== $value % $multiple) {
|
||||
$value++;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function getMultipleDown($value, $multiple)
|
||||
{
|
||||
while (0 !== $value % $multiple) {
|
||||
$value--;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ratio based on Dimension.
|
||||
*
|
||||
* The strategy parameter forces by default to use standardized ratios. If
|
||||
* custom ratio need to be used, disable it.
|
||||
*
|
||||
* @param Dimension $dimension
|
||||
* @param Boolean $forceStandards Whether to force or not standard ratios
|
||||
*
|
||||
* @return AspectRatio
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function create(Dimension $dimension, $forceStandards = true)
|
||||
{
|
||||
$incoming = $dimension->getWidth() / $dimension->getHeight();
|
||||
|
||||
if ($forceStandards) {
|
||||
return new static(static::nearestStrategy($incoming));
|
||||
} else {
|
||||
return new static(static::customStrategy($incoming));
|
||||
}
|
||||
}
|
||||
|
||||
private static function valueFromName($name)
|
||||
{
|
||||
switch ($name) {
|
||||
case static::AR_4_3:
|
||||
return 4 / 3;
|
||||
case static::AR_16_9:
|
||||
return 16 / 9;
|
||||
case static::AR_1_1:
|
||||
return 1 / 1;
|
||||
case static::AR_1_DOT_85_1:
|
||||
return 1.85;
|
||||
case static::AR_2_DOT_39_1:
|
||||
return 2.39;
|
||||
case static::AR_3_2:
|
||||
return 3 / 2;
|
||||
case static::AR_5_3:
|
||||
return 5 / 3;
|
||||
case static::AR_5_4:
|
||||
return 5 / 4;
|
||||
case static::AR_ROTATED_3_4:
|
||||
return 3 / 4;
|
||||
case static::AR_ROTATED_9_16:
|
||||
return 9 / 16;
|
||||
case static::AR_ROTATED_2_3:
|
||||
return 2 / 3;
|
||||
case static::AR_ROTATED_3_5:
|
||||
return 3 / 5;
|
||||
case static::AR_ROTATED_4_5:
|
||||
return 4 / 5;
|
||||
case static::AR_ROTATED_1_DOT_85:
|
||||
return 1 / 1.85;
|
||||
case static::AR_ROTATED_2_DOT_39:
|
||||
return 1 / 2.39;
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Unable to find value for %s', $name));
|
||||
}
|
||||
}
|
||||
|
||||
private static function customStrategy($incoming)
|
||||
{
|
||||
$try = static::nearestStrategy($incoming);
|
||||
|
||||
if (abs($try - $incoming) < $try * 0.05) {
|
||||
return $try;
|
||||
}
|
||||
|
||||
return $incoming;
|
||||
}
|
||||
|
||||
private static function nearestStrategy($incoming)
|
||||
{
|
||||
$availables = array(
|
||||
static::AR_4_3 => static::valueFromName(static::AR_4_3),
|
||||
static::AR_16_9 => static::valueFromName(static::AR_16_9),
|
||||
static::AR_1_1 => static::valueFromName(static::AR_1_1),
|
||||
static::AR_1_DOT_85_1 => static::valueFromName(static::AR_1_DOT_85_1),
|
||||
static::AR_2_DOT_39_1 => static::valueFromName(static::AR_2_DOT_39_1),
|
||||
static::AR_3_2 => static::valueFromName(static::AR_3_2),
|
||||
static::AR_5_3 => static::valueFromName(static::AR_5_3),
|
||||
static::AR_5_4 => static::valueFromName(static::AR_5_4),
|
||||
|
||||
// Rotated
|
||||
static::AR_ROTATED_4_5 => static::valueFromName(static::AR_ROTATED_4_5),
|
||||
static::AR_ROTATED_9_16 => static::valueFromName(static::AR_ROTATED_9_16),
|
||||
static::AR_ROTATED_2_3 => static::valueFromName(static::AR_ROTATED_2_3),
|
||||
static::AR_ROTATED_3_5 => static::valueFromName(static::AR_ROTATED_3_5),
|
||||
static::AR_ROTATED_3_4 => static::valueFromName(static::AR_ROTATED_3_4),
|
||||
static::AR_ROTATED_1_DOT_85 => static::valueFromName(static::AR_ROTATED_1_DOT_85),
|
||||
static::AR_ROTATED_2_DOT_39 => static::valueFromName(static::AR_ROTATED_2_DOT_39),
|
||||
);
|
||||
asort($availables);
|
||||
|
||||
$previous = $current = null;
|
||||
|
||||
foreach ($availables as $name => $value) {
|
||||
$current = $value;
|
||||
if ($incoming <= $value) {
|
||||
break;
|
||||
}
|
||||
$previous = $value;
|
||||
}
|
||||
|
||||
if (null === $previous) {
|
||||
return $current;
|
||||
}
|
||||
|
||||
if (($current - $incoming) < ($incoming - $previous)) {
|
||||
return $current;
|
||||
}
|
||||
|
||||
return $previous;
|
||||
}
|
||||
}
|
||||
72
src/FFMpeg/Coordinate/Dimension.php
Normal file
72
src/FFMpeg/Coordinate/Dimension.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?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\Coordinate;
|
||||
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Dimension object, used for manipulating width and height couples
|
||||
*/
|
||||
class Dimension
|
||||
{
|
||||
private $width;
|
||||
private $height;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @throws InvalidArgumentException when one of the parameteres is invalid
|
||||
*/
|
||||
public function __construct($width, $height)
|
||||
{
|
||||
if ($width <= 0 || $height <= 0) {
|
||||
throw new InvalidArgumentException('Width and height should be positive integer');
|
||||
}
|
||||
|
||||
$this->width = (int) $width;
|
||||
$this->height = (int) $height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return width
|
||||
*
|
||||
* @return width
|
||||
*/
|
||||
public function getWidth()
|
||||
{
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return height
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getHeight()
|
||||
{
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ratio
|
||||
*
|
||||
* @param type $forceStandards Whether or not force the use of standards ratios;
|
||||
*
|
||||
* @return AspectRatio
|
||||
*/
|
||||
public function getRatio($forceStandards = true)
|
||||
{
|
||||
return AspectRatio::create($this, $forceStandards);
|
||||
}
|
||||
}
|
||||
36
src/FFMpeg/Coordinate/FrameRate.php
Normal file
36
src/FFMpeg/Coordinate/FrameRate.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?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\Coordinate;
|
||||
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
|
||||
class FrameRate
|
||||
{
|
||||
private $value;
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
if ($value <= 0) {
|
||||
throw new InvalidArgumentException('Invalid frame rate, must be positive value.');
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
40
src/FFMpeg/Coordinate/Point.php
Normal file
40
src/FFMpeg/Coordinate/Point.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?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\Coordinate;
|
||||
|
||||
class Point
|
||||
{
|
||||
private $x;
|
||||
private $Y;
|
||||
|
||||
public function __construct($x, $y)
|
||||
{
|
||||
$this->x = (int) $x;
|
||||
$this->y = (int) $y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getX()
|
||||
{
|
||||
return $this->x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getY()
|
||||
{
|
||||
return $this->y;
|
||||
}
|
||||
}
|
||||
66
src/FFMpeg/Coordinate/TimeCode.php
Normal file
66
src/FFMpeg/Coordinate/TimeCode.php
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<?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\Coordinate;
|
||||
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
|
||||
class TimeCode
|
||||
{
|
||||
//see http://www.dropframetimecode.org/
|
||||
private $hours;
|
||||
private $minutes;
|
||||
private $seconds;
|
||||
private $frames;
|
||||
|
||||
public function __construct($hours, $minutes, $seconds, $frames)
|
||||
{
|
||||
$this->hours = $hours;
|
||||
$this->minutes = $minutes;
|
||||
$this->seconds = $seconds;
|
||||
$this->frames = $frames;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('%02d:%02d:%02d.%02d', $this->hours, $this->minutes, $this->seconds, $this->frames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates timecode from string
|
||||
*
|
||||
* @param string $timecode
|
||||
*
|
||||
* @return TimeCode
|
||||
*
|
||||
* @throws InvalidArgumentException In case an invalid timecode is supplied
|
||||
*/
|
||||
public static function fromString($timecode)
|
||||
{
|
||||
$days = 0;
|
||||
|
||||
if (preg_match('/^[0-9]+:[0-9]+:[0-9]+:[0-9]+\.[0-9]+$/', $timecode)) {
|
||||
list($days, $hours, $minutes, $seconds, $frames) = sscanf($timecode, '%d:%d:%d:%d.%d');
|
||||
} elseif (preg_match('/^[0-9]+:[0-9]+:[0-9]+:[0-9]+:[0-9]+$/', $timecode)) {
|
||||
list($days, $hours, $minutes, $seconds, $frames) = sscanf($timecode, '%d:%d:%d:%d:%d');
|
||||
} elseif (preg_match('/^[0-9]+:[0-9]+:[0-9]+\.[0-9]+$/', $timecode)) {
|
||||
list($hours, $minutes, $seconds, $frames) = sscanf($timecode, '%d:%d:%d.%s');
|
||||
} elseif (preg_match('/^[0-9]+:[0-9]+:[0-9]+:[0-9]+$/', $timecode)) {
|
||||
list($hours, $minutes, $seconds, $frames) = sscanf($timecode, '%d:%d:%d:%s');
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf('Unable to parse timecode %s', $timecode));
|
||||
}
|
||||
|
||||
$hours += $days * 24;
|
||||
|
||||
return new static($hours, $minutes, $seconds, $frames);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue