Merge branch 'master' into patch-1
This commit is contained in:
commit
b60a6c9922
112 changed files with 3790 additions and 421 deletions
25
.github/ISSUE_TEMPLATE.md
vendored
Normal file
25
.github/ISSUE_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
| Q | A
|
||||
| -------------- | ---
|
||||
| Bug? | no
|
||||
| New Feature? | no
|
||||
| Version Used | Specific tag or commit sha
|
||||
| FFmpeg Version | FFmpeg or AVConv and version
|
||||
| OS | Your OS and version
|
||||
|
||||
#### Actual Behavior
|
||||
|
||||
How does PHP-FFMpeg behave at the moment?
|
||||
|
||||
#### Expected Behavior
|
||||
|
||||
What is the behavior you expect?
|
||||
|
||||
#### Steps to Reproduce
|
||||
|
||||
What are the steps to reproduce this bug? Please add code examples,
|
||||
screenshots or links to GitHub repositories that reproduce the problem.
|
||||
|
||||
#### Possible Solutions
|
||||
|
||||
If you have already ideas how to solve the issue, add them here.
|
||||
Otherwise remove this section.
|
||||
36
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
36
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
| Q | A
|
||||
| ------------------ | ---
|
||||
| Bug fix? | no
|
||||
| New feature? | no
|
||||
| BC breaks? | no
|
||||
| Deprecations? | no
|
||||
| Fixed tickets | fixes #issuenum
|
||||
| Related issues/PRs | #issuenum
|
||||
| License | MIT
|
||||
|
||||
#### What's in this PR?
|
||||
|
||||
Explain the contents of the PR.
|
||||
|
||||
#### Why?
|
||||
|
||||
Which problem does the PR fix?
|
||||
|
||||
#### Example Usage
|
||||
|
||||
```php
|
||||
$foo = new Foo();
|
||||
|
||||
// Now we can do
|
||||
$foo->doSomething();
|
||||
|
||||
// Remove this section if not needed
|
||||
~~~
|
||||
|
||||
#### BC Breaks/Deprecations
|
||||
|
||||
Describe BC breaks/deprecations here (Remove this section if not needed).
|
||||
|
||||
#### To Do
|
||||
|
||||
- [ ] Create tests
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,6 +1,8 @@
|
|||
/nbproject/
|
||||
#/nbproject/
|
||||
/vendor/
|
||||
/docs/build
|
||||
composer.phar
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
|
||||
sami.phar
|
||||
.idea/
|
||||
37
.travis.yml
37
.travis.yml
|
|
@ -1,18 +1,39 @@
|
|||
language: php
|
||||
|
||||
before_script:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install -y ffmpeg libavcodec-extra-53
|
||||
- composer self-update
|
||||
- composer install --no-interaction --prefer-source --dev
|
||||
dist: trusty
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- v1.x
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
- $HOME/.cache
|
||||
|
||||
php:
|
||||
- 5.3.3
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.4
|
||||
env: COMPOSER_FLAGS="--prefer-lowest"
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository ppa:mc3man/trusty-media -y
|
||||
- sudo apt-get update -q
|
||||
- composer self-update
|
||||
- if [ "$COMPOSER_FLAGS" == "--prefer-lowest" ]; then composer require "roave/security-advisories" dev-master --no-update; fi;
|
||||
|
||||
install:
|
||||
- sudo apt-get install -y ffmpeg
|
||||
- composer update --prefer-dist $COMPOSER_FLAGS
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit --verbose
|
||||
- vendor/bin/phpunit --verbose -c phpunit-functional.xml.dist
|
||||
|
|
|
|||
192
CHANGELOG.md
192
CHANGELOG.md
|
|
@ -1,101 +1,173 @@
|
|||
CHANGELOG
|
||||
---------
|
||||
=========
|
||||
|
||||
* 0.6.0 (xx-xx-2015)
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
* AbstractData::get no longer throws exceptions (@sujayjaju).
|
||||
* Add crop filter (@cangelis).
|
||||
* Fix watermark (@sujayjaju).
|
||||
[Unreleased]
|
||||
------------
|
||||
|
||||
* 0.5.1 (08-26-2014)
|
||||
### Added
|
||||
|
||||
* Fix video aspect ratio calculation (@nlegoff).
|
||||
- Add pull request and issue templates.
|
||||
- Usage of new codec "aac" of ffmpeg 3
|
||||
|
||||
* 0.5.0 (08-12-2014)
|
||||
### Changed
|
||||
|
||||
* Add support for Wav and AAC audio formats (@MrHash).
|
||||
* Add watermark filter (@sylvainv).
|
||||
* Add configuration for audio channels (@SimonSimCity).
|
||||
- Updated changelog to follow [keepachangelog.com](http://keepachangelog.com/)
|
||||
style you see now here.
|
||||
|
||||
* 0.4.4 (12-17-2013)
|
||||
[0.7.0] - 2016-12-15
|
||||
--------------------
|
||||
|
||||
* Fix width / height dimensions extraction.
|
||||
- Add support for FFMpeg 3 aac codec (@Nek-)
|
||||
- Add a waveform filter to extract audio waveform images (@Romain)
|
||||
|
||||
* 0.4.3 (12-02-2013)
|
||||
[0.6.1] - 2016-03-08
|
||||
--------------------
|
||||
|
||||
* Fix using rotate and resize filters at the same time (#78)
|
||||
- Support PHP 7 and test against
|
||||
- Unused code cleanup (@haphan)
|
||||
- Composer and tests cleanup (PSR-4 autoloading)
|
||||
- Allow usage of evenement v2.0
|
||||
|
||||
* 0.4.2 (11-29-2013)
|
||||
[0.6.0] - 2016-01-30
|
||||
--------------------
|
||||
|
||||
* Add Rotate filter.
|
||||
* Remove time_start metadata when using synchronize filter
|
||||
* Remove restriction on filesystem resources.
|
||||
- AbstractData::get no longer throws exceptions (@sujayjaju).
|
||||
- Add crop filter (@cangelis).
|
||||
- Fix watermark (@sujayjaju).
|
||||
|
||||
* 0.4.1 (11-26-2013)
|
||||
[0.5.1] - 2016-08-26
|
||||
--------------------
|
||||
|
||||
* Add Clip filter (@guimeira)
|
||||
- Fix video aspect ratio calculation (@nlegoff).
|
||||
|
||||
* 0.4.0 (10-21-2013)
|
||||
[0.5.0] - 2014-08-12
|
||||
--------------------
|
||||
|
||||
* Add support for video to audio transcoding
|
||||
* BC Break : Add FormatInterface::getPasses and FormatInterface::getExtraParams
|
||||
- Add support for Wav and AAC audio formats (@MrHash).
|
||||
- Add watermark filter (@sylvainv).
|
||||
- Add configuration for audio channels (@SimonSimCity).
|
||||
|
||||
* 0.3.5 (10-21-2013)
|
||||
[0.4.4] - 2016-12-17
|
||||
--------------------
|
||||
|
||||
* Add vorbis audio format (@jacobbudin).
|
||||
* Fix #66 : Allow single pass encodings.
|
||||
- Fix width / height dimensions extraction.
|
||||
|
||||
* 0.3.4 (09-05-2013)
|
||||
[0.4.3] - 2013-02-12
|
||||
--------------------
|
||||
|
||||
* Fix Invalid ratio computing.
|
||||
- Fix using rotate and resize filters at the same time (#78)
|
||||
|
||||
* 0.3.3 (09-05-2013)
|
||||
[0.4.2] - 2013-11-29
|
||||
--------------------
|
||||
|
||||
* Add convenient Stream::getDimensions method to extract video dimension.
|
||||
* Add DisplayRatioFixer Frame filter.
|
||||
- Add Rotate filter.
|
||||
- Remove time_start metadata when using synchronize filter
|
||||
- Remove restriction on filesystem resources.
|
||||
|
||||
* 0.3.2 (08-08-2013)
|
||||
[0.4.1] - 2013-11-26
|
||||
--------------------
|
||||
|
||||
* Fix A/V synchronization over flash and HTML5 players.
|
||||
- Add Clip filter (@guimeira)
|
||||
|
||||
* 0.3.1 (08-06-2013)
|
||||
[0.4.0] - 2013-10-21
|
||||
--------------------
|
||||
|
||||
* Allow use of FFProbe on remote URIs.
|
||||
* Fix #47 : MediaTypeInterface::save adds filters depending on the codec.
|
||||
* Save frame to target file without prompt.
|
||||
- Add support for video to audio transcoding
|
||||
- BC Break : Add FormatInterface::getPasses and FormatInterface::getExtraParams
|
||||
|
||||
* 0.3.0 (07-04-2013)
|
||||
[0.3.5] - 2013-10-21
|
||||
--------------------
|
||||
|
||||
* Complete rewrite of the library, lots of BC breaks, check the doc.
|
||||
- Add vorbis audio format (@jacobbudin).
|
||||
- Fix #66 : Allow single pass encodings.
|
||||
|
||||
* 0.2.4 (05-10-2013)
|
||||
[0.3.4] - 2013-09-05
|
||||
--------------------
|
||||
|
||||
* Add Video\ResizableInterface::getModulus method for better output scaling (@retrojunk)
|
||||
* Fix timeout setting on audio/video encoding (@xammep-ua)
|
||||
- Fix Invalid ratio computing.
|
||||
|
||||
* 0.2.3 (04-21-2013)
|
||||
[0.3.3] - 2013-09-05
|
||||
--------------------
|
||||
|
||||
* Add timeout getter and setter on FFMpeg and FFProbe
|
||||
* Add timeout setting via second argument on FFMpeg::load and FFProbe::load
|
||||
- Add convenient Stream::getDimensions method to extract video dimension.
|
||||
- Add DisplayRatioFixer Frame filter.
|
||||
|
||||
* 0.2.2 (02-11-2013)
|
||||
[0.3.2] - 2013-08-08
|
||||
--------------------
|
||||
|
||||
* Add compatibility with FFMpeg 1.1
|
||||
* Upgrade deprecated options (`-ab`, `-qscale` and `-b`)
|
||||
* Use of a custom stat file for each multi-pass encoding (fix #20)
|
||||
* Use larger version range for dependencies
|
||||
- Fix A/V synchronization over flash and HTML5 players.
|
||||
|
||||
* 0.2.1 (02-04-2013)
|
||||
[0.3.1] - 2013-08-06
|
||||
--------------------
|
||||
|
||||
* Parse the output of FFProbe using correct EOL sequences (@ak76)
|
||||
* Add process timeout customization (@pulse00)
|
||||
* Fix `accurate` option (`FFMpeg::extractImage`)
|
||||
- Allow use of FFProbe on remote URIs.
|
||||
- Fix #47 : MediaTypeInterface::save adds filters depending on the codec.
|
||||
- Save frame to target file without prompt.
|
||||
|
||||
* 0.2.0 (12-13-2012)
|
||||
[0.3.0] - 2013-07-04
|
||||
--------------------
|
||||
|
||||
* Add HelperInterface and support for realtime progress ( @pulse00 ).
|
||||
* Add `accurate` option to `FFMpeg::extractImage` method.
|
||||
- Complete rewrite of the library, lots of BC breaks, check the doc.
|
||||
|
||||
* 0.1.0 (10-30-2012)
|
||||
[0.2.4] - 2013-05-10
|
||||
--------------------
|
||||
|
||||
* First stable version.
|
||||
- Add Video\ResizableInterface::getModulus method for better output scaling (@retrojunk)
|
||||
- Fix timeout setting on audio/video encoding (@xammep-ua)
|
||||
|
||||
[0.2.3] - 2013-04-21
|
||||
--------------------
|
||||
|
||||
- Add timeout getter and setter on FFMpeg and FFProbe
|
||||
- Add timeout setting via second argument on FFMpeg::load and FFProbe::load
|
||||
|
||||
[0.2.2] - 2013-02-11
|
||||
--------------------
|
||||
|
||||
- Add compatibility with FFMpeg 1.1
|
||||
- Upgrade deprecated options (`-ab`, `-qscale` and `-b`)
|
||||
- Use of a custom stat file for each multi-pass encoding (fix #20)
|
||||
- Use larger version range for dependencies
|
||||
|
||||
[0.2.1] - 2013-02-04
|
||||
--------------------
|
||||
|
||||
- Parse the output of FFProbe using correct EOL sequences (@ak76)
|
||||
- Add process timeout customization (@pulse00)
|
||||
- Fix `accurate` option (`FFMpeg::extractImage`)
|
||||
|
||||
[0.2.0] - 2012-12-13
|
||||
--------------------
|
||||
|
||||
- Add HelperInterface and support for realtime progress ( @pulse00 ).
|
||||
- Add `accurate` option to `FFMpeg::extractImage` method.
|
||||
|
||||
0.1.0 - 2012-10-30
|
||||
--------------------
|
||||
|
||||
- First stable version.
|
||||
|
||||
[Unreleased]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.6.1...HEAD
|
||||
[0.6.1]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.6.0...0.6.1
|
||||
[0.6.0]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.5.1...0.6.0
|
||||
[0.5.1]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.5.0...0.5.1
|
||||
[0.5.0]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.4.4...0.5.0
|
||||
[0.4.4]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.4.3...0.4.4
|
||||
[0.4.3]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.4.2...0.4.3
|
||||
[0.4.2]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.4.1...0.4.2
|
||||
[0.4.1]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.4.0...0.4.1
|
||||
[0.4.0]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.3.5...0.4.0
|
||||
[0.3.5]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.3.4...0.3.5
|
||||
[0.3.4]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.3.3...0.3.4
|
||||
[0.3.3]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.3.2...0.3.3
|
||||
[0.3.2]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.3.1...0.3.2
|
||||
[0.3.1]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.3.0...0.3.1
|
||||
[0.3.0]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.2.4...0.3.0
|
||||
[0.2.4]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.2.3...0.2.4
|
||||
[0.2.3]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.2.2...0.2.3
|
||||
[0.2.2]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.2.1...0.2.2
|
||||
[0.2.1]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.2.0...0.2.1
|
||||
[0.2.0]: https://github.com/PHP-FFMpeg/PHP-FFMpeg/compare/0.1.0...0.2.0
|
||||
|
|
|
|||
303
README.md
303
README.md
|
|
@ -1,4 +1,4 @@
|
|||
#PHP FFmpeg
|
||||
# PHP FFmpeg
|
||||
|
||||
[](http://travis-ci.org/PHP-FFMpeg/PHP-FFMpeg)
|
||||
|
||||
|
|
@ -6,39 +6,38 @@
|
|||
|
||||
An Object Oriented library to convert video/audio files with FFmpeg / AVConv.
|
||||
|
||||
Check another amazing repo : [PHP FFMpeg extras](https://github.com/alchemy-fr/PHP-FFMpeg-Extras), you will find lots of Audio/Video formats there.
|
||||
Check another amazing repo: [PHP FFMpeg extras](https://github.com/alchemy-fr/PHP-FFMpeg-Extras), you will find lots of Audio/Video formats there.
|
||||
|
||||
## Your attention please
|
||||
|
||||
### How this library works :
|
||||
### How this library works:
|
||||
|
||||
This library requires a working FFMpeg install. You will need both FFMpeg and FFProbe binaries to use it.
|
||||
Be sure that these binaries can be located with system PATH to get the benefit of the binary detection,
|
||||
otherwise you should have to explicitely give the binaries path on load.
|
||||
otherwise you should have to explicitly give the binaries path on load.
|
||||
|
||||
For Windows users : Please find the binaries at http://ffmpeg.zeranoe.com/builds/.
|
||||
|
||||
### Known issues :
|
||||
### Known issues:
|
||||
|
||||
- Using rotate and resize will produce a corrupted output when using
|
||||
[libav](http://libav.org/) 0.8. The bug is fixed in version 9. This bug does not
|
||||
- Using rotate and resize will produce a corrupted output when using
|
||||
[libav](http://libav.org/) 0.8. The bug is fixed in version 9. This bug does not
|
||||
appear in latest ffmpeg version.
|
||||
|
||||
## Installation
|
||||
|
||||
The recommended way to install PHP-FFMpeg is through [Composer](https://getcomposer.org).
|
||||
|
||||
```json
|
||||
{
|
||||
"require": {
|
||||
"php-ffmpeg/php-ffmpeg": "~0.5"
|
||||
}
|
||||
}
|
||||
```bash
|
||||
$ composer require php-ffmpeg/php-ffmpeg
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```php
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
$ffmpeg = FFMpeg\FFMpeg::create();
|
||||
$video = $ffmpeg->open('video.mpg');
|
||||
$video
|
||||
|
|
@ -62,14 +61,14 @@ to browse the source code as it is self-documented.
|
|||
### FFMpeg
|
||||
|
||||
`FFMpeg\FFMpeg` is the main object to use to manipulate medias. To build it,
|
||||
use the static `FFMpeg\FFMpeg::create` :
|
||||
use the static `FFMpeg\FFMpeg::create`:
|
||||
|
||||
```php
|
||||
$ffmpeg = FFMpeg\FFMpeg::create();
|
||||
```
|
||||
|
||||
FFMpeg will autodetect ffmpeg and ffprobe binaries. If you want to give binary
|
||||
paths explicitely, you can pass an array as configuration. A `Psr\Logger\LoggerInterface`
|
||||
paths explicitly, you can pass an array as configuration. A `Psr\Logger\LoggerInterface`
|
||||
can also be passed to log binary executions.
|
||||
|
||||
```php
|
||||
|
|
@ -86,8 +85,8 @@ $ffmpeg = FFMpeg\FFMpeg::create(array(
|
|||
`FFMpeg\FFMpeg` creates media based on URIs. URIs could be either a pointer to a
|
||||
local filesystem resource, an HTTP resource or any resource supported by FFmpeg.
|
||||
|
||||
**Note** : To list all supported resource type of your FFmpeg build, use the
|
||||
`-protocols` command :
|
||||
**Note**: To list all supported resource type of your FFmpeg build, use the
|
||||
`-protocols` command:
|
||||
|
||||
```
|
||||
ffmpeg -protocols
|
||||
|
|
@ -99,12 +98,12 @@ To open a resource, use the `FFMpeg\FFMpeg::open` method.
|
|||
$ffmpeg->open('video.mpeg');
|
||||
```
|
||||
|
||||
Two types of media can be resolved : `FFMpeg\Media\Audio` and `FFMpeg\Media\Video`.
|
||||
Two types of media can be resolved: `FFMpeg\Media\Audio` and `FFMpeg\Media\Video`.
|
||||
A third type, `FFMpeg\Media\Frame`, is available through videos.
|
||||
|
||||
#### Video
|
||||
### Video
|
||||
|
||||
`FFMpeg\Media\Video` can be transcoded, ie : change codec, isolate audio or
|
||||
`FFMpeg\Media\Video` can be transcoded, ie: change codec, isolate audio or
|
||||
video. Frames can be extracted.
|
||||
|
||||
##### Transcoding
|
||||
|
|
@ -115,15 +114,15 @@ pass a `FFMpeg\Format\FormatInterface` for that.
|
|||
Please note that audio and video bitrate are set on the format.
|
||||
|
||||
```php
|
||||
$format = new Format\Video\X264();
|
||||
$format = new FFMpeg\Format\Video\X264();
|
||||
$format->on('progress', function ($video, $format, $percentage) {
|
||||
echo "$percentage % transcoded";
|
||||
});
|
||||
|
||||
$format
|
||||
-> setKiloBitrate(1000)
|
||||
-> setAudioChannels(2)
|
||||
-> setAudioKiloBitrate(256);
|
||||
->setKiloBitrate(1000)
|
||||
->setAudioChannels(2)
|
||||
->setAudioKiloBitrate(256);
|
||||
|
||||
$video->save($format, 'video.avi');
|
||||
```
|
||||
|
|
@ -136,7 +135,7 @@ below for more informations.
|
|||
You can extract a frame at any timecode using the `FFMpeg\Media\Video::frame`
|
||||
method.
|
||||
|
||||
This code return a `FFMpeg\Media\Frame` instance corresponding to the second 42.
|
||||
This code returns a `FFMpeg\Media\Frame` instance corresponding to the second 42.
|
||||
You can pass any `FFMpeg\Coordinate\TimeCode` as argument, see dedicated
|
||||
documentation below for more information.
|
||||
|
||||
|
|
@ -145,6 +144,54 @@ $frame = $video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(42));
|
|||
$frame->save('image.jpg');
|
||||
```
|
||||
|
||||
If you want to extract multiple images from your video, you can use the following filter:
|
||||
|
||||
```php
|
||||
$video
|
||||
->filters()
|
||||
->extractMultipleFrames(FFMpeg\Filters\Video\ExtractMultipleFramesFilter::FRAMERATE_EVERY_10SEC, '/path/to/destination/folder/')
|
||||
->synchronize();
|
||||
|
||||
$video
|
||||
->save(new FFMpeg\Format\Video\X264(), '/path/to/new/file');
|
||||
```
|
||||
|
||||
##### Generate a waveform
|
||||
|
||||
You can generate a waveform of an audio file using the `FFMpeg\Media\Audio::waveform`
|
||||
method.
|
||||
|
||||
This code returns a `FFMpeg\Media\Waveform` instance.
|
||||
You can optionally pass dimensions as the first two arguments and an array of hex string colors for ffmpeg to use for the waveform, see dedicated
|
||||
documentation below for more information.
|
||||
|
||||
The ouput file MUST use the PNG extension.
|
||||
|
||||
```php
|
||||
$waveform = $audio->waveform(640, 120, array('#00FF00'));
|
||||
$waveform->save('waveform.png');
|
||||
```
|
||||
|
||||
If you want to get a waveform from a video, convert it in an audio file first.
|
||||
|
||||
```php
|
||||
// Open your video file
|
||||
$video = $ffmpeg->open( 'video.mp4' );
|
||||
|
||||
// Set an audio format
|
||||
$audio_format = new FFMpeg\Format\Audio\Mp3();
|
||||
|
||||
// Extract the audio into a new file as mp3
|
||||
$video->save($audio_format, 'audio.mp3');
|
||||
|
||||
// Set the audio file
|
||||
$audio = $ffmpeg->open( 'audio.mp3' );
|
||||
|
||||
// Create the waveform
|
||||
$waveform = $audio->waveform();
|
||||
$waveform->save( 'waveform.png' );
|
||||
```
|
||||
|
||||
##### Filters
|
||||
|
||||
You can apply filters on `FFMpeg\Media\Video` with the `FFMpeg\Media\Video::addFilter`
|
||||
|
|
@ -173,9 +220,9 @@ $video->filters()->rotate($angle);
|
|||
|
||||
The `$angle` parameter must be one of the following constants :
|
||||
|
||||
- `FFMpeg\Filters\Video\RotateFilter::ROTATE_90` : 90° clockwise
|
||||
- `FFMpeg\Filters\Video\RotateFilter::ROTATE_180` : 180°
|
||||
- `FFMpeg\Filters\Video\RotateFilter::ROTATE_270` : 90° counterclockwise
|
||||
- `FFMpeg\Filters\Video\RotateFilter::ROTATE_90`: 90° clockwise
|
||||
- `FFMpeg\Filters\Video\RotateFilter::ROTATE_180`: 180°
|
||||
- `FFMpeg\Filters\Video\RotateFilter::ROTATE_270`: 90° counterclockwise
|
||||
|
||||
###### Resize
|
||||
|
||||
|
|
@ -185,12 +232,57 @@ Resizes a video to a given size.
|
|||
$video->filters()->resize($dimension, $mode, $useStandards);
|
||||
```
|
||||
|
||||
The resize filter takes three parameters :
|
||||
The resize filter takes three parameters:
|
||||
|
||||
- `$dimension`, an instance of `FFMpeg\Coordinate\Dimension`
|
||||
- `$mode`, one of the constants `FFMpeg\Filters\Video\ResizeFilter::RESIZEMODE_*` constants
|
||||
- `$useStandards`, a boolean to force the use of the nearest aspect ratio standard.
|
||||
|
||||
If you want a video in a non-standard ratio, you can use the padding filter to resize your video in the desired size, and wrap it into black bars.
|
||||
|
||||
```php
|
||||
$video->filters()->pad($dimension);
|
||||
```
|
||||
|
||||
The pad filter takes one parameter:
|
||||
|
||||
- `$dimension`, an instance of `FFMpeg\Coordinate\Dimension`
|
||||
|
||||
Don't forget to save it afterwards.
|
||||
|
||||
```php
|
||||
$video->save(new FFMpeg\Format\Video\X264(), $new_file);
|
||||
```
|
||||
|
||||
###### Watermark
|
||||
|
||||
Watermark a video with a given image.
|
||||
|
||||
```php
|
||||
$video
|
||||
->filters()
|
||||
->watermark($watermarkPath, array(
|
||||
'position' => 'relative',
|
||||
'bottom' => 50,
|
||||
'right' => 50,
|
||||
));
|
||||
```
|
||||
|
||||
The watermark filter takes two parameters:
|
||||
|
||||
`$watermarkPath`, the path to your watermark file.
|
||||
`$coordinates`, an array defining how you want your watermark positioned. You can use relative positioning as demonstrated above or absolute as such:
|
||||
|
||||
```php
|
||||
$video
|
||||
->filters()
|
||||
->watermark($watermarkPath, array(
|
||||
'position' => 'absolute',
|
||||
'x' => 1180,
|
||||
'y' => 620,
|
||||
));
|
||||
```
|
||||
|
||||
###### Framerate
|
||||
|
||||
Changes the frame rate of the video.
|
||||
|
|
@ -199,7 +291,7 @@ Changes the frame rate of the video.
|
|||
$video->filters()->framerate($framerate, $gop);
|
||||
```
|
||||
|
||||
The framerate filter takes two parameters :
|
||||
The framerate filter takes two parameters:
|
||||
|
||||
- `$framerate`, an instance of `FFMpeg\Coordinate\Framerate`
|
||||
- `$gop`, a [GOP](https://wikipedia.org/wiki/Group_of_pictures) value (integer)
|
||||
|
|
@ -228,9 +320,21 @@ The clip filter takes two parameters:
|
|||
- `$start`, an instance of `FFMpeg\Coordinate\TimeCode`, specifies the start point of the clip
|
||||
- `$duration`, optional, an instance of `FFMpeg\Coordinate\TimeCode`, specifies the duration of the clip
|
||||
|
||||
#### Audio
|
||||
###### Crop
|
||||
|
||||
`FFMpeg\Media\Audio` can be transcoded, ie : change codec, isolate audio or
|
||||
Crops the video based on a width and height(a `Point`)
|
||||
|
||||
```php
|
||||
$video->filters()->crop(new FFMpeg\Coordinate\Point("t*100", 0, true), new FFMpeg\Coordinate\Dimension(200, 600));
|
||||
```
|
||||
|
||||
It takes two parameters:
|
||||
- `$point`, an instance of `FFMpeg\Coordinate\Point`, specifies the point to crop
|
||||
- `$dimension`, an instance of `FFMpeg\Coordinate\Dimension`, specifies the dimension of the output video
|
||||
|
||||
### Audio
|
||||
|
||||
`FFMpeg\Media\Audio` can be transcoded too, ie: change codec, isolate audio or
|
||||
video. Frames can be extracted.
|
||||
|
||||
##### Transcoding
|
||||
|
|
@ -250,8 +354,8 @@ $format->on('progress', function ($audio, $format, $percentage) {
|
|||
});
|
||||
|
||||
$format
|
||||
-> setAudioChannels(2)
|
||||
-> setAudioKiloBitrate(256);
|
||||
->setAudioChannels(2)
|
||||
->setAudioKiloBitrate(256);
|
||||
|
||||
$audio->save($format, 'track.flac');
|
||||
```
|
||||
|
|
@ -267,6 +371,35 @@ method. It only accepts audio filters.
|
|||
You can build your own filters and some are bundled in PHP-FFMpeg - they are
|
||||
accessible through the `FFMpeg\Media\Audio::filters` method.
|
||||
|
||||
##### Clipping
|
||||
Cuts the audio at a desired point.
|
||||
|
||||
```php
|
||||
$audio->filters()->clip(FFMpeg\Coordinate\TimeCode::fromSeconds(30), FFMpeg\Coordinate\TimeCode::fromSeconds(15));
|
||||
```
|
||||
|
||||
|
||||
###### Metadata
|
||||
|
||||
Add metadata to audio files. Just pass an array of key=value pairs of all
|
||||
metadata you would like to add. If no arguments are passed into the filter
|
||||
all metadata will be removed from input file. Currently supported data is
|
||||
title, artist, album, artist, composer, track, year, description, artwork
|
||||
|
||||
```php
|
||||
$audio->filters()->addMetadata(["title" => "Some Title", "track" => 1]);
|
||||
|
||||
//remove all metadata and video streams from audio file
|
||||
$audio->filters()->addMetadata();
|
||||
```
|
||||
|
||||
Add artwork to the audio file
|
||||
```php
|
||||
$audio->filters()->addMetadata(["artwork" => "/path/to/image/file.jpg"]);
|
||||
```
|
||||
NOTE: at present ffmpeg (version 3.2.2) only supports artwork output for .mp3
|
||||
files
|
||||
|
||||
###### Resample
|
||||
|
||||
Resamples an audio file.
|
||||
|
|
@ -293,6 +426,68 @@ $frame->save('target.jpg');
|
|||
This method has a second optional boolean parameter. Set it to true to get
|
||||
accurate images ; it takes more time to execute.
|
||||
|
||||
#### Gif
|
||||
|
||||
A gif is an animated image extracted from a sequence of the video.
|
||||
|
||||
You can save gif files using the `FFMpeg\Media\Gif::save` method.
|
||||
|
||||
```php
|
||||
$video = $ffmpeg->open( '/path/to/video' );
|
||||
$video
|
||||
->gif(FFMpeg\Coordinate\TimeCode::fromSeconds(2), new FFMpeg\Coordinate\Dimension(640, 480), 3)
|
||||
->save($new_file);
|
||||
```
|
||||
|
||||
This method has a third optional boolean parameter, which is the duration of the animation.
|
||||
If you don't set it, you will get a fixed gif image.
|
||||
|
||||
#### Concatenation
|
||||
|
||||
This feature allows you to generate one audio or video file, based on multiple sources.
|
||||
|
||||
There are two ways to concatenate videos, depending on the codecs of the sources.
|
||||
If your sources have all been encoded with the same codec, you will want to use the `FFMpeg\Media\Concatenate::saveFromSameCodecs` which has way better performances.
|
||||
If your sources have been encoded with different codecs, you will want to use the `FFMpeg\Media\Concatenate::saveFromDifferentCodecs`.
|
||||
|
||||
The first function will use the initial codec as the one for the generated file.
|
||||
With the second function, you will be able to choose which codec you want for the generated file.
|
||||
|
||||
You also need to pay attention to the fact that, when using the saveFromDifferentCodecs method,
|
||||
your files MUST have video and audio streams.
|
||||
|
||||
In both cases, you will have to provide an array of files.
|
||||
|
||||
To concatenate videos encoded with the same codec, do as follow:
|
||||
|
||||
```php
|
||||
// In order to instantiate the video object, you HAVE TO pass a path to a valid video file.
|
||||
// We recommand that you put there the path of any of the video you want to use in this concatenation.
|
||||
$video = $ffmpeg->open( '/path/to/video' );
|
||||
$video
|
||||
->concat(array('/path/to/video1', '/path/to/video2'))
|
||||
->saveFromSameCodecs('/path/to/new_file', TRUE);
|
||||
```
|
||||
|
||||
The boolean parameter of the save function allows you to use the copy parameter which accelerates drastically the generation of the encoded file.
|
||||
|
||||
To concatenate videos encoded with the same codec, do as follow:
|
||||
|
||||
```php
|
||||
// In order to instantiate the video object, you HAVE TO pass a path to a valid video file.
|
||||
// We recommand that you put there the path of any of the video you want to use in this concatenation.
|
||||
$video = $ffmpeg->open( '/path/to/video' );
|
||||
|
||||
$format = new FFMpeg\Format\Video\X264();
|
||||
$format->setAudioCodec("libmp3lame");
|
||||
|
||||
$video
|
||||
->concat(array('/path/to/video1', '/path/to/video2'))
|
||||
->saveFromDifferentCodecs($format, '/path/to/new_file');
|
||||
```
|
||||
|
||||
More details about concatenation in FFMPEG can be found [here](https://trac.ffmpeg.org/wiki/Concatenate), [here](https://ffmpeg.org/ffmpeg-formats.html#concat-1) and [here](https://ffmpeg.org/ffmpeg.html#Stream-copy).
|
||||
|
||||
#### Formats
|
||||
|
||||
A format implements `FFMpeg\Format\FormatInterface`. To save to a video file,
|
||||
|
|
@ -305,7 +500,7 @@ informations about the transcoding.
|
|||
Predefined formats already provide progress informations as events.
|
||||
|
||||
```php
|
||||
$format = new Format\Video\X264();
|
||||
$format = new FFMpeg\Format\Video\X264();
|
||||
$format->on('progress', function ($video, $format, $percentage) {
|
||||
echo "$percentage % transcoded";
|
||||
});
|
||||
|
|
@ -315,6 +510,18 @@ $video->save($format, 'video.avi');
|
|||
|
||||
The callback provided for the event can be any callable.
|
||||
|
||||
##### Add additional parameters
|
||||
|
||||
You can add additional parameters to your encoding requests based on your video format.
|
||||
|
||||
The argument of the setAdditionalParameters method is an array.
|
||||
|
||||
```php
|
||||
$format = new FFMpeg\Format\Video\X264();
|
||||
$format->setAdditionalParameters(array('foo', 'bar'));
|
||||
$video->save($format, 'video.avi');
|
||||
```
|
||||
|
||||
##### Create your own format
|
||||
|
||||
The easiest way to create a format is to extend the abstract
|
||||
|
|
@ -355,7 +562,7 @@ FFMpeg use many units for time and space coordinates.
|
|||
- `FFMpeg\Coordinate\AspectRatio` represents an aspect ratio.
|
||||
- `FFMpeg\Coordinate\Dimension` represent a dimension.
|
||||
- `FFMpeg\Coordinate\FrameRate` represent a framerate.
|
||||
- `FFMpeg\Coordinate\Point` represent a point.
|
||||
- `FFMpeg\Coordinate\Point` represent a point. (Supports dynamic points since v0.10.0)
|
||||
- `FFMpeg\Coordinate\TimeCode` represent a timecode.
|
||||
|
||||
### FFProbe
|
||||
|
|
@ -379,9 +586,19 @@ $ffprobe
|
|||
->get('duration'); // returns the duration property
|
||||
```
|
||||
|
||||
##Using with Silex Microframework
|
||||
### Validating media files
|
||||
|
||||
Service provider is easy to set up :
|
||||
(since 0.10.0)
|
||||
You can validate media files using PHP-FFMpeg's FFProbe wrapper.
|
||||
|
||||
```php
|
||||
$ffprobe = FFMpeg\FFProbe::create();
|
||||
$ffprobe->isValid('/path/to/file/to/check'); // returns bool
|
||||
```
|
||||
|
||||
## Using with Silex Microframework
|
||||
|
||||
Service provider is easy to set up:
|
||||
|
||||
```php
|
||||
$app = new Silex\Application();
|
||||
|
|
@ -390,7 +607,7 @@ $app->register(new FFMpeg\FFMpegServiceProvider());
|
|||
$video = $app['ffmpeg']->open('video.mpeg');
|
||||
```
|
||||
|
||||
Available options are as follow :
|
||||
Available options are as follow:
|
||||
|
||||
```php
|
||||
$app->register(new FFMpeg\FFMpegServiceProvider(), array(
|
||||
|
|
@ -405,14 +622,6 @@ $app->register(new FFMpeg\FFMpegServiceProvider(), array(
|
|||
));
|
||||
```
|
||||
|
||||
## API Browser
|
||||
|
||||
Browse the [API](http://readthedocs.org/docs/ffmpeg-php/en/latest/_static/API/)
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [MIT license](http://opensource.org/licenses/MIT).
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,40 +5,60 @@
|
|||
"keywords": ["video processing", "video", "audio processing", "audio", "avconv", "ffmpeg", "avprobe", "ffprobe"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Romain Neutron",
|
||||
"email": "imprec@gmail.com",
|
||||
"homepage": "http://www.lickmychip.com/"
|
||||
},
|
||||
{
|
||||
"name": "Phraseanet Team",
|
||||
"email": "info@alchemy.fr",
|
||||
"homepage": "http://www.phraseanet.com/"
|
||||
}
|
||||
{
|
||||
"name": "Romain Neutron",
|
||||
"email": "imprec@gmail.com",
|
||||
"homepage": "http://www.lickmychip.com/"
|
||||
},
|
||||
{
|
||||
"name": "Phraseanet Team",
|
||||
"email": "info@alchemy.fr",
|
||||
"homepage": "http://www.phraseanet.com/"
|
||||
},
|
||||
{
|
||||
"name": "Patrik Karisch",
|
||||
"email": "patrik@karisch.guru",
|
||||
"homepage": "http://www.karisch.guru"
|
||||
},
|
||||
{
|
||||
"name": "Romain Biard",
|
||||
"email": "romain.biard@gmail.com",
|
||||
"homepage": "https://www.strime.io/"
|
||||
},
|
||||
{
|
||||
"name": "Jens Hausdorf",
|
||||
"email": "hello@jens-hausdorf.de",
|
||||
"homepage": "https://jens-hausdorf.de"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php" : ">=5.3.3",
|
||||
"alchemy/binary-driver" : "~1.5",
|
||||
"doctrine/cache" : "~1.0",
|
||||
"evenement/evenement" : "~1.0",
|
||||
"neutron/temporary-filesystem" : "~2.1, >=2.1.1"
|
||||
"php": "^5.3.9 || ^7.0",
|
||||
"alchemy/binary-driver": "^1.5",
|
||||
"doctrine/cache": "^1.0",
|
||||
"evenement/evenement": "^2.0 || ^1.0",
|
||||
"neutron/temporary-filesystem": "^2.1.1"
|
||||
},
|
||||
"suggest": {
|
||||
"php-ffmpeg/extras" : "A compilation of common audio & video drivers for PHP-FFMpeg"
|
||||
"php-ffmpeg/extras": "A compilation of common audio & video drivers for PHP-FFMpeg"
|
||||
},
|
||||
"require-dev": {
|
||||
"sami/sami" : "~1.0",
|
||||
"silex/silex" : "~1.0",
|
||||
"phpunit/phpunit" : "~3.7"
|
||||
"sami/sami": "~1.0",
|
||||
"silex/silex": "~1.0",
|
||||
"phpunit/phpunit": "^4.8.36"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"FFMpeg": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\FFMpeg\\": "tests"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.5-dev"
|
||||
"dev-master": "0.7-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,17 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
string
|
||||
integer
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_setPasses">setPasses</a>(integer $passes)
|
||||
<p>Sets the number of passes.</p>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
integer
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_getPasses">getPasses</a>()
|
||||
|
|
@ -499,12 +509,37 @@
|
|||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_setPasses">
|
||||
<div class="location">in <a href="../../../FFMpeg/Format/Video/X264.html#method_setPasses"><abbr title="FFMpeg\Format\Video\X264">X264</abbr></a> at line 68</div>
|
||||
<code> public integer
|
||||
<strong>setPasses</strong>(integer $passes)</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>Sets the number of passes.</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
|
||||
<h4>Parameters</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>integer</td>
|
||||
<td>$passes</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_getPasses">
|
||||
<div class="location">at line 68</div>
|
||||
<code> public string
|
||||
<div class="location">in <a href="../../../FFMpeg/Format/Video/X264.html#method_getPasses"><abbr title="FFMpeg\Format\Video\X264">X264</abbr></a> at line 79</div>
|
||||
<code> public integer
|
||||
<strong>getPasses</strong>()</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
|
|
@ -517,7 +552,7 @@
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<td>string</td>
|
||||
<td>integer</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -171,6 +171,16 @@
|
|||
<p>Exports the audio in the desired format, applies registered filters.</p>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Media/Waveform.html"><abbr title="FFMpeg\Media\Audio">Audio</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_waveform">waveform</a>(integer $width, integer $height)
|
||||
<p>Generates an image file representing the waveform of the audio file.</p>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
@ -609,6 +619,59 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_waveform">
|
||||
<div class="location">at line 113</div>
|
||||
<code> public <a href="../../FFMpeg/Media/Waveform.html"><abbr title="FFMpeg\Media\Audio">Audio</abbr></a>
|
||||
<strong>save</strong>(<a href="../../FFMpeg/Format/FormatInterface.html"><abbr title="FFMpeg\Format\FormatInterface">FormatInterface</abbr></a> $format, string $outputPathfile)</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>Exports the audio in the desired format, applies registered filters.</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
<h4>Parameters</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Format/FormatInterface.html"><abbr title="FFMpeg\Format\FormatInterface">FormatInterface</abbr></a></td>
|
||||
<td>$format</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>string</td>
|
||||
<td>$outputPathfile</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Media/Audio.html"><abbr title="FFMpeg\Media\Audio">Audio</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h4>Exceptions</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="http://php.net/RuntimeException"><abbr title="RuntimeException">RuntimeException</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
|
|
|
|||
621
docs/source/API/API/FFMpeg/Media/Waveform.html
Normal file
621
docs/source/API/API/FFMpeg/Media/Waveform.html
Normal file
|
|
@ -0,0 +1,621 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="robots" content="index, follow, all" />
|
||||
<title>FFMpeg\Media\Frame | PHP-FFMpeg API</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../stylesheet.css">
|
||||
</head>
|
||||
<body id="class">
|
||||
<div class="header">
|
||||
<ul>
|
||||
<li><a href="../../classes.html">Classes</a></li>
|
||||
<li><a href="../../namespaces.html">Namespaces</a></li>
|
||||
<li><a href="../../interfaces.html">Interfaces</a></li>
|
||||
<li><a href="../../traits.html">Traits</a></li>
|
||||
<li><a href="../../doc-index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<div id="title">PHP-FFMpeg API</div>
|
||||
|
||||
<div class="type">Class</div>
|
||||
<h1><a href="../../FFMpeg/Media.html">FFMpeg\Media</a>\Frame</h1>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p> class
|
||||
<strong>Frame</strong> extends <a href="../../FFMpeg/Media/AbstractMediaType.html"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Methods</h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td class="type">
|
||||
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method___construct">__construct</a>(<a href="../../FFMpeg/Media/Video.html"><abbr title="FFMpeg\Media\Video">Video</abbr></a> $video, <a href="../../FFMpeg/Driver/FFMpegDriver.html"><abbr title="FFMpeg\Driver\FFMpegDriver">FFMpegDriver</abbr></a> $driver, <a href="../../FFMpeg/FFProbe.html"><abbr title="FFMpeg\FFProbe">FFProbe</abbr></a> $ffprobe, <a href="../../FFMpeg/Coordinate/TimeCode.html"><abbr title="FFMpeg\Coordinate\TimeCode">TimeCode</abbr></a> $timecode)
|
||||
<p>
|
||||
</p>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Driver/FFMpegDriver.html"><abbr title="FFMpeg\Driver\FFMpegDriver">FFMpegDriver</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_getFFMpegDriver">getFFMpegDriver</a>()
|
||||
<p>
|
||||
</p>
|
||||
</td>
|
||||
<td><small>from <a href="../../FFMpeg/Media/AbstractMediaType.html#method_getFFMpegDriver"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_setFFMpegDriver">setFFMpegDriver</a>(<a href="../../FFMpeg/Driver/FFMpegDriver.html"><abbr title="FFMpeg\Driver\FFMpegDriver">FFMpegDriver</abbr></a> $driver)
|
||||
<p>
|
||||
</p>
|
||||
</td>
|
||||
<td><small>from <a href="../../FFMpeg/Media/AbstractMediaType.html#method_setFFMpegDriver"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/FFProbe.html"><abbr title="FFMpeg\FFProbe">FFProbe</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_getFFProbe">getFFProbe</a>()
|
||||
<p>
|
||||
</p>
|
||||
</td>
|
||||
<td><small>from <a href="../../FFMpeg/Media/AbstractMediaType.html#method_getFFProbe"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_setFFProbe">setFFProbe</a>(<a href="../../FFMpeg/FFProbe.html"><abbr title="FFMpeg\FFProbe">FFProbe</abbr></a> $ffprobe)
|
||||
<p>
|
||||
</p>
|
||||
</td>
|
||||
<td><small>from <a href="../../FFMpeg/Media/AbstractMediaType.html#method_setFFProbe"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
string
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_getPathfile">getPathfile</a>()
|
||||
<p>
|
||||
</p>
|
||||
</td>
|
||||
<td><small>from <a href="../../FFMpeg/Media/AbstractMediaType.html#method_getPathfile"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_setFiltersCollection">setFiltersCollection</a>(<a href="../../FFMpeg/Filters/FiltersCollection.html"><abbr title="FFMpeg\Filters\FiltersCollection">FiltersCollection</abbr></a> $filters)
|
||||
<p>
|
||||
</p>
|
||||
</td>
|
||||
<td><small>from <a href="../../FFMpeg/Media/AbstractMediaType.html#method_setFiltersCollection"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_getFiltersCollection">getFiltersCollection</a>()
|
||||
<p>
|
||||
</p>
|
||||
</td>
|
||||
<td><small>from <a href="../../FFMpeg/Media/AbstractMediaType.html#method_getFiltersCollection"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a></small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Media/Video.html"><abbr title="FFMpeg\Media\Video">Video</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_getVideo">getVideo</a>()
|
||||
<p>Returns the video related to the frame.</p>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Filters/Frame/FrameFilters.html"><abbr title="FFMpeg\Filters\Frame\FrameFilters">FrameFilters</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_filters">filters</a>()
|
||||
<p>Returns the available filters.</p>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Media/Frame.html"><abbr title="FFMpeg\Media\Frame">Frame</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_addFilter">addFilter</a>(<a href="../../FFMpeg/Filters/Frame/FrameFilterInterface.html"><abbr title="FFMpeg\Filters\Frame\FrameFilterInterface">FrameFilterInterface</abbr></a> $filter)
|
||||
<p>{@inheritdoc}</p>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Coordinate/TimeCode.html"><abbr title="FFMpeg\Coordinate\TimeCode">TimeCode</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_getTimeCode">getTimeCode</a>()
|
||||
<p>
|
||||
</p>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="type">
|
||||
<a href="../../FFMpeg/Media/Frame.html"><abbr title="FFMpeg\Media\Frame">Frame</abbr></a>
|
||||
</td>
|
||||
<td class="last">
|
||||
<a href="#method_save">save</a>(string $pathfile, Boolean $accurate = false)
|
||||
<p>Saves the frame in the given filename.</p>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h2>Details</h2>
|
||||
|
||||
<h3 id="method___construct">
|
||||
<div class="location">at line 29</div>
|
||||
<code> public
|
||||
<strong>__construct</strong>(<a href="../../FFMpeg/Media/Video.html"><abbr title="FFMpeg\Media\Video">Video</abbr></a> $video, <a href="../../FFMpeg/Driver/FFMpegDriver.html"><abbr title="FFMpeg\Driver\FFMpegDriver">FFMpegDriver</abbr></a> $driver, <a href="../../FFMpeg/FFProbe.html"><abbr title="FFMpeg\FFProbe">FFProbe</abbr></a> $ffprobe, <a href="../../FFMpeg/Coordinate/TimeCode.html"><abbr title="FFMpeg\Coordinate\TimeCode">TimeCode</abbr></a> $timecode)</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
<h4>Parameters</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Media/Video.html"><abbr title="FFMpeg\Media\Video">Video</abbr></a></td>
|
||||
<td>$video</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Driver/FFMpegDriver.html"><abbr title="FFMpeg\Driver\FFMpegDriver">FFMpegDriver</abbr></a></td>
|
||||
<td>$driver</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/FFProbe.html"><abbr title="FFMpeg\FFProbe">FFProbe</abbr></a></td>
|
||||
<td>$ffprobe</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Coordinate/TimeCode.html"><abbr title="FFMpeg\Coordinate\TimeCode">TimeCode</abbr></a></td>
|
||||
<td>$timecode</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_getFFMpegDriver">
|
||||
<div class="location">in <a href="../../FFMpeg/Media/AbstractMediaType.html#method_getFFMpegDriver"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a> at line 40</div>
|
||||
<code> public <a href="../../FFMpeg/Driver/FFMpegDriver.html"><abbr title="FFMpeg\Driver\FFMpegDriver">FFMpegDriver</abbr></a>
|
||||
<strong>getFFMpegDriver</strong>()</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Driver/FFMpegDriver.html"><abbr title="FFMpeg\Driver\FFMpegDriver">FFMpegDriver</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_setFFMpegDriver">
|
||||
<div class="location">in <a href="../../FFMpeg/Media/AbstractMediaType.html#method_setFFMpegDriver"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a> at line 50</div>
|
||||
<code> public <a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a>
|
||||
<strong>setFFMpegDriver</strong>(<a href="../../FFMpeg/Driver/FFMpegDriver.html"><abbr title="FFMpeg\Driver\FFMpegDriver">FFMpegDriver</abbr></a> $driver)</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
<h4>Parameters</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Driver/FFMpegDriver.html"><abbr title="FFMpeg\Driver\FFMpegDriver">FFMpegDriver</abbr></a></td>
|
||||
<td>$driver</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_getFFProbe">
|
||||
<div class="location">in <a href="../../FFMpeg/Media/AbstractMediaType.html#method_getFFProbe"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a> at line 60</div>
|
||||
<code> public <a href="../../FFMpeg/FFProbe.html"><abbr title="FFMpeg\FFProbe">FFProbe</abbr></a>
|
||||
<strong>getFFProbe</strong>()</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/FFProbe.html"><abbr title="FFMpeg\FFProbe">FFProbe</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_setFFProbe">
|
||||
<div class="location">in <a href="../../FFMpeg/Media/AbstractMediaType.html#method_setFFProbe"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a> at line 70</div>
|
||||
<code> public <a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a>
|
||||
<strong>setFFProbe</strong>(<a href="../../FFMpeg/FFProbe.html"><abbr title="FFMpeg\FFProbe">FFProbe</abbr></a> $ffprobe)</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
<h4>Parameters</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/FFProbe.html"><abbr title="FFMpeg\FFProbe">FFProbe</abbr></a></td>
|
||||
<td>$ffprobe</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_getPathfile">
|
||||
<div class="location">in <a href="../../FFMpeg/Media/AbstractMediaType.html#method_getPathfile"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a> at line 80</div>
|
||||
<code> public string
|
||||
<strong>getPathfile</strong>()</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>string</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_setFiltersCollection">
|
||||
<div class="location">in <a href="../../FFMpeg/Media/AbstractMediaType.html#method_setFiltersCollection"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a> at line 90</div>
|
||||
<code> public <a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a>
|
||||
<strong>setFiltersCollection</strong>(<a href="../../FFMpeg/Filters/FiltersCollection.html"><abbr title="FFMpeg\Filters\FiltersCollection">FiltersCollection</abbr></a> $filters)</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
<h4>Parameters</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Filters/FiltersCollection.html"><abbr title="FFMpeg\Filters\FiltersCollection">FiltersCollection</abbr></a></td>
|
||||
<td>$filters</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_getFiltersCollection">
|
||||
<div class="location">in <a href="../../FFMpeg/Media/AbstractMediaType.html#method_getFiltersCollection"><abbr title="FFMpeg\Media\AbstractMediaType">AbstractMediaType</abbr></a> at line 100</div>
|
||||
<code> public <a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a>
|
||||
<strong>getFiltersCollection</strong>()</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Media/MediaTypeInterface.html"><abbr title="FFMpeg\Media\MediaTypeInterface">MediaTypeInterface</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_getVideo">
|
||||
<div class="location">at line 41</div>
|
||||
<code> public <a href="../../FFMpeg/Media/Video.html"><abbr title="FFMpeg\Media\Video">Video</abbr></a>
|
||||
<strong>getVideo</strong>()</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>Returns the video related to the frame.</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Media/Video.html"><abbr title="FFMpeg\Media\Video">Video</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_filters">
|
||||
<div class="location">at line 51</div>
|
||||
<code> public <a href="../../FFMpeg/Filters/Frame/FrameFilters.html"><abbr title="FFMpeg\Filters\Frame\FrameFilters">FrameFilters</abbr></a>
|
||||
<strong>filters</strong>()</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>Returns the available filters.</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Filters/Frame/FrameFilters.html"><abbr title="FFMpeg\Filters\Frame\FrameFilters">FrameFilters</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_addFilter">
|
||||
<div class="location">at line 61</div>
|
||||
<code> public <a href="../../FFMpeg/Media/Frame.html"><abbr title="FFMpeg\Media\Frame">Frame</abbr></a>
|
||||
<strong>addFilter</strong>(<a href="../../FFMpeg/Filters/Frame/FrameFilterInterface.html"><abbr title="FFMpeg\Filters\Frame\FrameFilterInterface">FrameFilterInterface</abbr></a> $filter)</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>{@inheritdoc}</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
<h4>Parameters</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Filters/Frame/FrameFilterInterface.html"><abbr title="FFMpeg\Filters\Frame\FrameFilterInterface">FrameFilterInterface</abbr></a></td>
|
||||
<td>$filter</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Media/Frame.html"><abbr title="FFMpeg\Media\Frame">Frame</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_getTimeCode">
|
||||
<div class="location">at line 71</div>
|
||||
<code> public <a href="../../FFMpeg/Coordinate/TimeCode.html"><abbr title="FFMpeg\Coordinate\TimeCode">TimeCode</abbr></a>
|
||||
<strong>getTimeCode</strong>()</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<div class="tags">
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Coordinate/TimeCode.html"><abbr title="FFMpeg\Coordinate\TimeCode">TimeCode</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 id="method_save">
|
||||
<div class="location">at line 88</div>
|
||||
<code> public <a href="../../FFMpeg/Media/Frame.html"><abbr title="FFMpeg\Media\Frame">Frame</abbr></a>
|
||||
<strong>save</strong>(string $pathfile, Boolean $accurate = false)</code>
|
||||
</h3>
|
||||
<div class="details">
|
||||
<p>Saves the frame in the given filename.</p>
|
||||
<p>Uses the <code>unaccurate method by default.</code></p>
|
||||
<div class="tags">
|
||||
<h4>Parameters</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>string</td>
|
||||
<td>$pathfile</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Boolean</td>
|
||||
<td>$accurate</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h4>Return Value</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="../../FFMpeg/Media/Frame.html"><abbr title="FFMpeg\Media\Frame">Frame</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h4>Exceptions</h4>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="http://php.net/RuntimeException"><abbr title="RuntimeException">RuntimeException</abbr></a></td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
Generated by <a href="http://sami.sensiolabs.org/" target="_top">Sami, the API Documentation Generator</a>.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="true"
|
||||
verbose="false"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="FFMpeg Tests Suite">
|
||||
<directory>tests/FFMpeg/Functional</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<blacklist>
|
||||
<directory>vendor</directory>
|
||||
<directory>tests</directory>
|
||||
</blacklist>
|
||||
</filter>
|
||||
|
||||
</phpunit>
|
||||
|
||||
|
|
@ -12,16 +12,19 @@
|
|||
bootstrap="tests/bootstrap.php"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="FFMpeg Tests Suite">
|
||||
<directory>tests/FFMpeg/Tests</directory>
|
||||
<testsuite name="unit">
|
||||
<directory>tests/Unit</directory>
|
||||
</testsuite>
|
||||
<testsuite name="functional">
|
||||
<directory>tests/Functional</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<blacklist>
|
||||
<directory>vendor</directory>
|
||||
<directory>tests</directory>
|
||||
</blacklist>
|
||||
</filter>
|
||||
|
||||
</phpunit>
|
||||
|
||||
|
|
|
|||
|
|
@ -16,10 +16,15 @@ class Point
|
|||
private $x;
|
||||
private $y;
|
||||
|
||||
public function __construct($x, $y)
|
||||
public function __construct($x, $y, $dynamic = false)
|
||||
{
|
||||
$this->x = (int) $x;
|
||||
$this->y = (int) $y;
|
||||
if ($dynamic) {
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
} else {
|
||||
$this->x = (int)$x;
|
||||
$this->y = (int)$y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -89,4 +89,32 @@ class TimeCode
|
|||
|
||||
return new static($hours, $minutes, $seconds, $frames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this timecode in seconds
|
||||
* @return int
|
||||
*/
|
||||
public function toSeconds() {
|
||||
$seconds = 0;
|
||||
|
||||
$seconds += $this->hours * 60 * 60;
|
||||
$seconds += $this->minutes * 60;
|
||||
$seconds += $this->seconds;
|
||||
|
||||
// TODO: Handle frames?
|
||||
|
||||
return (int) $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function wether `$timecode` is after this one
|
||||
*
|
||||
* @param TimeCode $timecode The Timecode to compare
|
||||
* @return bool
|
||||
*/
|
||||
public function isAfter(TimeCode $timecode) {
|
||||
// convert everything to seconds and compare
|
||||
return ($this->toSeconds() > $timecode->toSeconds());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,6 +170,25 @@ class FFProbe
|
|||
return $this->probe($pathfile, '-show_format', static::TYPE_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
*
|
||||
* Checks wether the given `$pathfile` is considered a valid media file.
|
||||
*
|
||||
* @param string $pathfile
|
||||
* @return bool
|
||||
* @since 0.10.0
|
||||
*/
|
||||
public function isValid($pathfile)
|
||||
{
|
||||
try {
|
||||
return $this->format($pathfile)->get('duration') > 0;
|
||||
} catch(\Exception $e) {
|
||||
// complete invalid data
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
*
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
namespace FFMpeg\FFProbe\DataMapping;
|
||||
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
|
||||
abstract class AbstractData implements \Countable
|
||||
{
|
||||
private $properties;
|
||||
|
|
|
|||
58
src/FFMpeg/Filters/Audio/AddMetadataFilter.php
Normal file
58
src/FFMpeg/Filters/Audio/AddMetadataFilter.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?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\Filters\Audio;
|
||||
|
||||
use FFMpeg\Filters\Audio\AudioFilterInterface;
|
||||
use FFMpeg\Format\AudioInterface;
|
||||
use FFMpeg\Media\Audio;
|
||||
|
||||
class AddMetadataFilter implements AudioFilterInterface
|
||||
{
|
||||
/** @var Array */
|
||||
private $metaArr;
|
||||
/** @var Integer */
|
||||
private $priority;
|
||||
|
||||
function __construct($metaArr = null, $priority = 9)
|
||||
{
|
||||
$this->metaArr = $metaArr;
|
||||
$this->priority = $priority;
|
||||
}
|
||||
|
||||
public function getPriority()
|
||||
{
|
||||
//must be of high priority in case theres a second input stream (artwork) to register with audio
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
public function apply(Audio $audio, AudioInterface $format)
|
||||
{
|
||||
$meta = $this->metaArr;
|
||||
|
||||
if (is_null($meta)) {
|
||||
return ['-map_metadata', '-1', '-vn'];
|
||||
}
|
||||
|
||||
$metadata = [];
|
||||
|
||||
if (array_key_exists("artwork", $meta)) {
|
||||
array_push($metadata, "-i", $meta['artwork'], "-map", "0", "-map", "1");
|
||||
unset($meta['artwork']);
|
||||
}
|
||||
|
||||
foreach ($meta as $k => $v) {
|
||||
array_push($metadata, "-metadata", "$k=$v");
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
}
|
||||
84
src/FFMpeg/Filters/Audio/AudioClipFilter.php
Normal file
84
src/FFMpeg/Filters/Audio/AudioClipFilter.php
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<?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\Filters\Audio;
|
||||
|
||||
use FFMpeg\Coordinate\TimeCode;
|
||||
use FFMpeg\Format\AudioInterface;
|
||||
use FFMpeg\Media\Audio;
|
||||
|
||||
class AudioClipFilter implements AudioFilterInterface {
|
||||
|
||||
/**
|
||||
* @var TimeCode
|
||||
*/
|
||||
private $start;
|
||||
|
||||
/**
|
||||
* @var TimeCode
|
||||
*/
|
||||
private $duration;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $priority;
|
||||
|
||||
|
||||
public function __construct(TimeCode $start, TimeCode $duration = null, $priority = 0) {
|
||||
$this->start = $start;
|
||||
$this->duration = $duration;
|
||||
$this->priority = $priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getPriority() {
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start position the audio is being cutted
|
||||
*
|
||||
* @return TimeCode
|
||||
*/
|
||||
public function getStart() {
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how long the audio is being cutted. Returns null when the duration is infinite,
|
||||
*
|
||||
* @return TimeCode|null
|
||||
*/
|
||||
public function getDuration() {
|
||||
return $this->duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function apply(Audio $audio, AudioInterface $format) {
|
||||
$commands = array('-ss', (string) $this->start);
|
||||
|
||||
if ($this->duration !== null) {
|
||||
$commands[] = '-t';
|
||||
$commands[] = (string) $this->duration;
|
||||
}
|
||||
|
||||
$commands[] = '-acodec';
|
||||
$commands[] = 'copy';
|
||||
|
||||
return $commands;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,8 +1,19 @@
|
|||
<?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\Filters\Audio;
|
||||
|
||||
use FFMpeg\Filters\Audio\AddMetadataFilter;
|
||||
use FFMpeg\Media\Audio;
|
||||
use FFMpeg\Coordinate\TimeCode;
|
||||
|
||||
class AudioFilters
|
||||
{
|
||||
|
|
@ -26,4 +37,38 @@ class AudioFilters
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add metadata to an audio file. If no arguments are given then filter
|
||||
* will remove all metadata from the audio file
|
||||
* @param Array|Null $data If array must contain one of these key/value pairs:
|
||||
* - "title": Title metadata
|
||||
* - "artist": Artist metadata
|
||||
* - "composer": Composer metadata
|
||||
* - "album": Album metadata
|
||||
* - "track": Track metadata
|
||||
* - "artwork": Song artwork. String of file path
|
||||
* - "year": Year metadata
|
||||
* - "genre": Genre metadata
|
||||
* - "description": Description metadata
|
||||
*/
|
||||
public function addMetadata($data = null)
|
||||
{
|
||||
$this->media->addFilter(new AddMetadataFilter($data));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cuts the audio at `$start`, optionally define the end
|
||||
*
|
||||
* @param TimeCode $start Where the clipping starts(seek to time)
|
||||
* @param TimeCode $duration How long the clipped audio should be
|
||||
* @return AudioFilters
|
||||
*/
|
||||
public function clip($start, $duration = null) {
|
||||
$this->media->addFilter(new AudioClipFilter($start, $duration));
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
<?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\Filters\Audio;
|
||||
|
||||
use FFMpeg\Media\Audio;
|
||||
|
|
|
|||
20
src/FFMpeg/Filters/Concat/ConcatFilterInterface.php
Normal file
20
src/FFMpeg/Filters/Concat/ConcatFilterInterface.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Filters\Concat;
|
||||
|
||||
use FFMpeg\Filters\FilterInterface;
|
||||
use FFMpeg\Media\Concat;
|
||||
|
||||
interface ConcatFilterInterface extends FilterInterface
|
||||
{
|
||||
public function apply(Concat $concat);
|
||||
}
|
||||
24
src/FFMpeg/Filters/Concat/ConcatFilters.php
Normal file
24
src/FFMpeg/Filters/Concat/ConcatFilters.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Filters\Concat;
|
||||
|
||||
use FFMpeg\Media\Concat;
|
||||
|
||||
class ConcatFilters
|
||||
{
|
||||
private $concat;
|
||||
|
||||
public function __construct(Concat $concat)
|
||||
{
|
||||
$this->concat = $concat;
|
||||
}
|
||||
}
|
||||
20
src/FFMpeg/Filters/Gif/GifFilterInterface.php
Normal file
20
src/FFMpeg/Filters/Gif/GifFilterInterface.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Filters\Gif;
|
||||
|
||||
use FFMpeg\Filters\FilterInterface;
|
||||
use FFMpeg\Media\Gif;
|
||||
|
||||
interface GifFilterInterface extends FilterInterface
|
||||
{
|
||||
public function apply(Gif $gif);
|
||||
}
|
||||
24
src/FFMpeg/Filters/Gif/GifFilters.php
Normal file
24
src/FFMpeg/Filters/Gif/GifFilters.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Filters\Gif;
|
||||
|
||||
use FFMpeg\Media\Gif;
|
||||
|
||||
class GifFilters
|
||||
{
|
||||
private $gif;
|
||||
|
||||
public function __construct(Gif $gif)
|
||||
{
|
||||
$this->gif = $gif;
|
||||
}
|
||||
}
|
||||
128
src/FFMpeg/Filters/Video/ExtractMultipleFramesFilter.php
Normal file
128
src/FFMpeg/Filters/Video/ExtractMultipleFramesFilter.php
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <romain@strime.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Filters\Video;
|
||||
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
use FFMpeg\Exception\RuntimeException;
|
||||
use FFMpeg\Media\Video;
|
||||
use FFMpeg\Format\VideoInterface;
|
||||
|
||||
class ExtractMultipleFramesFilter implements VideoFilterInterface
|
||||
{
|
||||
/** will extract a frame every second */
|
||||
const FRAMERATE_EVERY_SEC = '1/1';
|
||||
/** will extract a frame every 2 seconds */
|
||||
const FRAMERATE_EVERY_2SEC = '1/2';
|
||||
/** will extract a frame every 5 seconds */
|
||||
const FRAMERATE_EVERY_5SEC = '1/5';
|
||||
/** will extract a frame every 10 seconds */
|
||||
const FRAMERATE_EVERY_10SEC = '1/10';
|
||||
/** will extract a frame every 30 seconds */
|
||||
const FRAMERATE_EVERY_30SEC = '1/30';
|
||||
/** will extract a frame every minute */
|
||||
const FRAMERATE_EVERY_60SEC = '1/60';
|
||||
|
||||
/** @var integer */
|
||||
private $priority;
|
||||
private $frameRate;
|
||||
private $destinationFolder;
|
||||
|
||||
public function __construct($frameRate = self::FRAMERATE_EVERY_SEC, $destinationFolder = __DIR__, $priority = 0)
|
||||
{
|
||||
$this->priority = $priority;
|
||||
$this->frameRate = $frameRate;
|
||||
|
||||
// Make sure that the destination folder has a trailing slash
|
||||
if(strcmp( substr($destinationFolder, -1), "/") != 0)
|
||||
$destinationFolder .= "/";
|
||||
|
||||
// Set the destination folder
|
||||
$this->destinationFolder = $destinationFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFrameRate()
|
||||
{
|
||||
return $this->frameRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDestinationFolder()
|
||||
{
|
||||
return $this->destinationFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(Video $video, VideoInterface $format)
|
||||
{
|
||||
$commands = array();
|
||||
$duration = 0;
|
||||
|
||||
try {
|
||||
// Get the duration of the video
|
||||
foreach ($video->getStreams()->videos() as $stream) {
|
||||
if ($stream->has('duration')) {
|
||||
$duration = $stream->get('duration');
|
||||
}
|
||||
}
|
||||
|
||||
// Get the number of frames per second we have to extract.
|
||||
if(preg_match('/(\d+)(?:\s*)([\+\-\*\/])(?:\s*)(\d+)/', $this->frameRate, $matches) !== FALSE){
|
||||
$operator = $matches[2];
|
||||
|
||||
switch($operator){
|
||||
case '/':
|
||||
$nbFramesPerSecond = $matches[1] / $matches[3];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('The frame rate is not a proper division: ' . $this->frameRate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the number of digits to use in the exported filenames
|
||||
$nbImages = ceil( $duration * $nbFramesPerSecond );
|
||||
|
||||
if($nbImages < 100)
|
||||
$nbDigitsInFileNames = "02";
|
||||
elseif($nbImages < 1000)
|
||||
$nbDigitsInFileNames = "03";
|
||||
else
|
||||
$nbDigitsInFileNames = "06";
|
||||
|
||||
// Set the parameters
|
||||
$commands[] = '-vf';
|
||||
$commands[] = 'fps=' . $this->frameRate;
|
||||
$commands[] = $this->destinationFolder . 'frame-%'.$nbDigitsInFileNames.'d.jpg';
|
||||
}
|
||||
catch (RuntimeException $e) {
|
||||
throw new RuntimeException('An error occured while extracting the frames: ' . $e->getMessage() . '. The code: ' . $e->getCode());
|
||||
}
|
||||
|
||||
return $commands;
|
||||
}
|
||||
}
|
||||
59
src/FFMpeg/Filters/Video/PadFilter.php
Normal file
59
src/FFMpeg/Filters/Video/PadFilter.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Filters\Video;
|
||||
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
use FFMpeg\Media\Video;
|
||||
use FFMpeg\Format\VideoInterface;
|
||||
|
||||
class PadFilter implements VideoFilterInterface
|
||||
{
|
||||
/** @var Dimension */
|
||||
private $dimension;
|
||||
/** @var integer */
|
||||
private $priority;
|
||||
|
||||
public function __construct(Dimension $dimension, $priority = 0)
|
||||
{
|
||||
$this->dimension = $dimension;
|
||||
$this->priority = $priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Dimension
|
||||
*/
|
||||
public function getDimension()
|
||||
{
|
||||
return $this->dimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(Video $video, VideoInterface $format)
|
||||
{
|
||||
$commands = array();
|
||||
|
||||
$commands[] = '-vf';
|
||||
$commands[] = 'scale=iw*min(' . $this->dimension->getWidth() . '/iw\,' . $this->dimension->getHeight() .'/ih):ih*min(' . $this->dimension->getWidth() . '/iw\,' . $this->dimension->getHeight() .'/ih),pad=' . $this->dimension->getWidth() . ':' . $this->dimension->getHeight() . ':(' . $this->dimension->getWidth() . '-iw)/2:(' . $this->dimension->getHeight() .'-ih)/2';
|
||||
|
||||
return $commands;
|
||||
}
|
||||
}
|
||||
|
|
@ -98,8 +98,10 @@ class ResizeFilter implements VideoFilterInterface
|
|||
if (null !== $dimensions) {
|
||||
$dimensions = $this->getComputedDimensions($dimensions, $format->getModulus());
|
||||
|
||||
$commands[] = '-s';
|
||||
$commands[] = $dimensions->getWidth() . 'x' . $dimensions->getHeight();
|
||||
// Using Filter to have ordering
|
||||
$commands[] = '-vf';
|
||||
$commands[] = '[in]scale=' . $dimensions->getWidth() . ':' . $dimensions->getHeight() . ' [out]';
|
||||
|
||||
}
|
||||
|
||||
return $commands;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class VideoFilters extends AudioFilters
|
|||
* Changes the video framerate.
|
||||
*
|
||||
* @param FrameRate $framerate
|
||||
* @param type $gop
|
||||
* @param Integer $gop
|
||||
*
|
||||
* @return VideoFilters
|
||||
*/
|
||||
|
|
@ -57,6 +57,21 @@ class VideoFilters extends AudioFilters
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract multiple frames from the video
|
||||
*
|
||||
* @param string $frameRate
|
||||
* @param string $destinationFolder
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function extractMultipleFrames($frameRate = ExtractMultipleFramesFilter::FRAMERATE_EVERY_2SEC, $destinationFolder = __DIR__)
|
||||
{
|
||||
$this->media->addFilter(new ExtractMultipleFramesFilter($frameRate, $destinationFolder));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes audio and video.
|
||||
*
|
||||
|
|
@ -98,6 +113,20 @@ class VideoFilters extends AudioFilters
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds padding (black bars) to a video.
|
||||
*
|
||||
* @param Dimension $dimension
|
||||
*
|
||||
* @return VideoFilters
|
||||
*/
|
||||
public function pad(Dimension $dimension)
|
||||
{
|
||||
$this->media->addFilter(new PadFilter($dimension));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function rotate($angle)
|
||||
{
|
||||
$this->media->addFilter(new RotateFilter($angle, 30));
|
||||
|
|
@ -132,4 +161,18 @@ class VideoFilters extends AudioFilters
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a custom filter: -vf foo bar
|
||||
*
|
||||
* @param string $parameters
|
||||
*
|
||||
* @return VideoFilters
|
||||
*/
|
||||
public function custom($parameters)
|
||||
{
|
||||
$this->media->addFilter(new CustomFilter($parameters));
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
74
src/FFMpeg/Filters/Waveform/WaveformDownmixFilter.php
Normal file
74
src/FFMpeg/Filters/Waveform/WaveformDownmixFilter.php
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Filters\Waveform;
|
||||
|
||||
use FFMpeg\Exception\RuntimeException;
|
||||
use FFMpeg\Media\Waveform;
|
||||
|
||||
class WaveformDownmixFilter implements WaveformFilterInterface
|
||||
{
|
||||
|
||||
/** @var boolean */
|
||||
private $downmix;
|
||||
/** @var integer */
|
||||
private $priority;
|
||||
|
||||
// By default, the downmix value is set to FALSE.
|
||||
public function __construct($downmix = FALSE, $priority = 0)
|
||||
{
|
||||
$this->downmix = $downmix;
|
||||
$this->priority = $priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDownmix()
|
||||
{
|
||||
return $this->downmix;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(Waveform $waveform)
|
||||
{
|
||||
$commands = array();
|
||||
|
||||
foreach ($waveform->getAudio()->getStreams() as $stream) {
|
||||
if ($stream->isAudio()) {
|
||||
try {
|
||||
|
||||
// If the downmix parameter is set to TRUE, we add an option to the FFMPEG command
|
||||
if($this->downmix == TRUE) {
|
||||
$commands[] = '"aformat=channel_layouts=mono"';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
} catch (RuntimeException $e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $commands;
|
||||
}
|
||||
}
|
||||
20
src/FFMpeg/Filters/Waveform/WaveformFilterInterface.php
Normal file
20
src/FFMpeg/Filters/Waveform/WaveformFilterInterface.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Filters\Waveform;
|
||||
|
||||
use FFMpeg\Filters\FilterInterface;
|
||||
use FFMpeg\Media\Waveform;
|
||||
|
||||
interface WaveformFilterInterface extends FilterInterface
|
||||
{
|
||||
public function apply(Waveform $waveform);
|
||||
}
|
||||
38
src/FFMpeg/Filters/Waveform/WaveformFilters.php
Normal file
38
src/FFMpeg/Filters/Waveform/WaveformFilters.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FFMpeg\Filters\Waveform;
|
||||
|
||||
use FFMpeg\Media\Waveform;
|
||||
|
||||
class WaveformFilters
|
||||
{
|
||||
private $waveform;
|
||||
|
||||
public function __construct(Waveform $waveform)
|
||||
{
|
||||
$this->waveform = $waveform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the downmix of the output waveform.
|
||||
*
|
||||
* If you want a simpler waveform, sets the downmix to TRUE.
|
||||
*
|
||||
* @return WaveformFilters
|
||||
*/
|
||||
public function setDownmix()
|
||||
{
|
||||
$this->waveform->addFilter(new WaveformDownmixFilter());
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
@ -121,10 +121,10 @@ abstract class DefaultAudio extends EventEmitter implements AudioInterface, Prog
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total)
|
||||
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total, $duration = 0)
|
||||
{
|
||||
$format = $this;
|
||||
$listener = new AudioProgressListener($ffprobe, $media->getPathfile(), $pass, $total);
|
||||
$listener = new AudioProgressListener($ffprobe, $media->getPathfile(), $pass, $total, $duration);
|
||||
$listener->on('progress', function () use ($media, $format) {
|
||||
$format->emit('progress', array_merge(array($media, $format), func_get_args()));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -80,12 +80,13 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
|
|||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct(FFProbe $ffprobe, $pathfile, $currentPass, $totalPass)
|
||||
public function __construct(FFProbe $ffprobe, $pathfile, $currentPass, $totalPass, $duration = 0)
|
||||
{
|
||||
$this->ffprobe = $ffprobe;
|
||||
$this->pathfile = $pathfile;
|
||||
$this->currentPass = $currentPass;
|
||||
$this->totalPass = $totalPass;
|
||||
$this->duration = $duration;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -120,6 +121,14 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
|
|||
return $this->totalPass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCurrentTime()
|
||||
{
|
||||
return $this->currentTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -171,6 +180,12 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
|
|||
|
||||
if ($this->lastOutput !== null) {
|
||||
$delta = $currentTime - $this->lastOutput;
|
||||
|
||||
// Check the type of the currentSize variable and convert it to an integer if needed.
|
||||
if(!is_numeric($currentSize)) {
|
||||
$currentSize = (int)$currentSize;
|
||||
}
|
||||
|
||||
$deltaSize = $currentSize - $this->currentSize;
|
||||
$rate = $deltaSize * $delta;
|
||||
if ($rate > 0) {
|
||||
|
|
@ -240,9 +255,8 @@ abstract class AbstractProgressListener extends EventEmitter implements Listener
|
|||
return;
|
||||
}
|
||||
|
||||
$this->totalSize = $format->get('size') / 1024;
|
||||
$this->duration = $format->get('duration');
|
||||
|
||||
$this->duration = (int) $this->duration > 0 ? $this->duration : $format->get('duration');
|
||||
$this->totalSize = $format->get('size') / 1024 * ($this->duration / $format->get('duration'));
|
||||
$this->initialized = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,9 @@ interface ProgressableInterface extends EventEmitterInterface
|
|||
* @param FFProbe $ffprobe
|
||||
* @param Integer $pass The current pas snumber
|
||||
* @param Integer $total The total pass number
|
||||
* @param Integer $duration The new video duration
|
||||
*
|
||||
* @return array An array of listeners
|
||||
*/
|
||||
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total);
|
||||
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total, $duration = 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ abstract class DefaultVideo extends DefaultAudio implements VideoInterface
|
|||
/** @var Integer */
|
||||
protected $modulus = 16;
|
||||
|
||||
/** @var Array */
|
||||
protected $additionalParamaters;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -97,10 +100,35 @@ abstract class DefaultVideo extends DefaultAudio implements VideoInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total)
|
||||
public function getAdditionalParameters()
|
||||
{
|
||||
return $this->additionalParamaters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets additional parameters.
|
||||
*
|
||||
* @param array $additionalParamaters
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function setAdditionalParameters($additionalParamaters)
|
||||
{
|
||||
if (!is_array($additionalParamaters)) {
|
||||
throw new InvalidArgumentException('Wrong additionalParamaters value');
|
||||
}
|
||||
|
||||
$this->additionalParamaters = $additionalParamaters;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createProgressListener(MediaTypeInterface $media, FFProbe $ffprobe, $pass, $total, $duration = 0)
|
||||
{
|
||||
$format = $this;
|
||||
$listeners = array(new VideoProgressListener($ffprobe, $media->getPathfile(), $pass, $total));
|
||||
$listeners = array(new VideoProgressListener($ffprobe, $media->getPathfile(), $pass, $total, $duration));
|
||||
|
||||
foreach ($listeners as $listener) {
|
||||
$listener->on('progress', function () use ($format, $media) {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,6 @@ class WebM extends DefaultVideo
|
|||
*/
|
||||
public function getAvailableVideoCodecs()
|
||||
{
|
||||
return array('libvpx');
|
||||
return array('libvpx', 'libvpx-vp9');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ class X264 extends DefaultVideo
|
|||
/** @var boolean */
|
||||
private $bframesSupport = true;
|
||||
|
||||
/** @var integer */
|
||||
private $passes = 2;
|
||||
|
||||
public function __construct($audioCodec = 'libfaac', $videoCodec = 'libx264')
|
||||
{
|
||||
$this
|
||||
|
|
@ -51,7 +54,7 @@ class X264 extends DefaultVideo
|
|||
*/
|
||||
public function getAvailableAudioCodecs()
|
||||
{
|
||||
return array('libvo_aacenc', 'libfaac', 'libmp3lame', 'libfdk_aac');
|
||||
return array('aac', 'libvo_aacenc', 'libfaac', 'libmp3lame', 'libfdk_aac');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -62,12 +65,23 @@ class X264 extends DefaultVideo
|
|||
return array('libx264');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $passes
|
||||
*
|
||||
* @return X264
|
||||
*/
|
||||
public function setPasses($passes)
|
||||
{
|
||||
$this->passes = $passes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPasses()
|
||||
{
|
||||
return 2;
|
||||
return $this->passes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -54,4 +54,11 @@ interface VideoInterface extends AudioInterface
|
|||
* @return array
|
||||
*/
|
||||
public function getAvailableVideoCodecs();
|
||||
|
||||
/**
|
||||
* Returns the list of available video codecs for this format.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalParameters();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,11 +52,9 @@ class Audio extends AbstractStreamableMedia
|
|||
/**
|
||||
* Exports the audio in the desired format, applies registered filters.
|
||||
*
|
||||
* @param FormatInterface $format
|
||||
* @param string $outputPathfile
|
||||
*
|
||||
* @param FormatInterface $format
|
||||
* @param string $outputPathfile
|
||||
* @return Audio
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function save(FormatInterface $format, $outputPathfile)
|
||||
|
|
@ -64,9 +62,42 @@ class Audio extends AbstractStreamableMedia
|
|||
$listeners = null;
|
||||
|
||||
if ($format instanceof ProgressableInterface) {
|
||||
$listeners = $format->createProgressListener($this, $this->ffprobe, 1, 1);
|
||||
$listeners = $format->createProgressListener($this, $this->ffprobe, 1, 1, 0);
|
||||
}
|
||||
|
||||
$commands = $this->buildCommand($format, $outputPathfile);
|
||||
|
||||
try {
|
||||
$this->driver->command($commands, false, $listeners);
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$this->cleanupTemporaryFile($outputPathfile);
|
||||
throw new RuntimeException('Encoding failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the final command as a string, useful for debugging purposes.
|
||||
*
|
||||
* @param FormatInterface $format
|
||||
* @param string $outputPathfile
|
||||
* @return string
|
||||
* @since 0.11.0
|
||||
*/
|
||||
public function getFinalCommand(FormatInterface $format, $outputPathfile) {
|
||||
return implode(' ', $this->buildCommand($format, $outputPathfile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the command which will be executed with the provided format
|
||||
*
|
||||
* @param FormatInterface $format
|
||||
* @param string $outputPathfile
|
||||
* @return string[] An array which are the components of the command
|
||||
* @since 0.11.0
|
||||
*/
|
||||
protected function buildCommand(FormatInterface $format, $outputPathfile) {
|
||||
$commands = array('-y', '-i', $this->pathfile);
|
||||
|
||||
$filters = clone $this->filters;
|
||||
|
|
@ -93,13 +124,19 @@ class Audio extends AbstractStreamableMedia
|
|||
}
|
||||
$commands[] = $outputPathfile;
|
||||
|
||||
try {
|
||||
$this->driver->command($commands, false, $listeners);
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$this->cleanupTemporaryFile($outputPathfile);
|
||||
throw new RuntimeException('Encoding failed', $e->getCode(), $e);
|
||||
}
|
||||
return $commands;
|
||||
}
|
||||
|
||||
return $this;
|
||||
/**
|
||||
* Gets the waveform of the video.
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param array $colors Array of colors for ffmpeg to use. Color format is #000000 (RGB hex string with #)
|
||||
* @return Waveform
|
||||
*/
|
||||
public function waveform($width = 640, $height = 120, $colors = array(Waveform::DEFAULT_COLOR))
|
||||
{
|
||||
return new Waveform($this, $this->driver, $this->ffprobe, $width, $height, $colors);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
264
src/FFMpeg/Media/Concat.php
Normal file
264
src/FFMpeg/Media/Concat.php
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* 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 Alchemy\BinaryDriver\Exception\InvalidArgumentException;
|
||||
use FFMpeg\Filters\Concat\ConcatFilterInterface;
|
||||
use FFMpeg\Filters\Concat\ConcatFilters;
|
||||
use FFMpeg\Driver\FFMpegDriver;
|
||||
use FFMpeg\FFProbe;
|
||||
use FFMpeg\Filters\Audio\SimpleFilter;
|
||||
use FFMpeg\Exception\RuntimeException;
|
||||
use FFMpeg\Format\FormatInterface;
|
||||
use FFMpeg\Filters\FilterInterface;
|
||||
use FFMpeg\Format\ProgressableInterface;
|
||||
use FFMpeg\Format\AudioInterface;
|
||||
use FFMpeg\Format\VideoInterface;
|
||||
use Neutron\TemporaryFilesystem\Manager as FsManager;
|
||||
|
||||
class Concat extends AbstractMediaType
|
||||
{
|
||||
/** @var array */
|
||||
private $sources;
|
||||
|
||||
public function __construct($sources, FFMpegDriver $driver, FFProbe $ffprobe)
|
||||
{
|
||||
parent::__construct($sources, $driver, $ffprobe);
|
||||
$this->sources = $sources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the sources.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSources()
|
||||
{
|
||||
return $this->sources;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ConcatFilters
|
||||
*/
|
||||
public function filters()
|
||||
{
|
||||
return new ConcatFilters($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return Concat
|
||||
*/
|
||||
public function addFilter(ConcatFilterInterface $filter)
|
||||
{
|
||||
$this->filters->add($filter);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the concatenated video in the given array, considering that the sources videos are all encoded with the same codec.
|
||||
*
|
||||
* @param array $outputPathfile
|
||||
* @param string $streamCopy
|
||||
*
|
||||
* @return Concat
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function saveFromSameCodecs($outputPathfile, $streamCopy = TRUE)
|
||||
{
|
||||
/**
|
||||
* @see https://ffmpeg.org/ffmpeg-formats.html#concat
|
||||
* @see https://trac.ffmpeg.org/wiki/Concatenate
|
||||
*/
|
||||
|
||||
// Create the file which will contain the list of videos
|
||||
$fs = FsManager::create();
|
||||
$sourcesFile = $fs->createTemporaryFile('ffmpeg-concat');
|
||||
|
||||
// Set the content of this file
|
||||
$fileStream = @fopen($sourcesFile, 'w');
|
||||
|
||||
if($fileStream === false) {
|
||||
throw new ExecutionFailureException('Cannot open the temporary file.');
|
||||
}
|
||||
|
||||
$count_videos = 0;
|
||||
if(is_array($this->sources) && (count($this->sources) > 0)) {
|
||||
foreach ($this->sources as $videoPath) {
|
||||
$line = "";
|
||||
|
||||
if($count_videos != 0)
|
||||
$line .= "\n";
|
||||
|
||||
$line .= "file ".$videoPath;
|
||||
|
||||
fwrite($fileStream, $line);
|
||||
|
||||
$count_videos++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new InvalidArgumentException('The list of videos is not a valid array.');
|
||||
}
|
||||
fclose($fileStream);
|
||||
|
||||
|
||||
$commands = array(
|
||||
'-f', 'concat', '-safe', '0',
|
||||
'-i', $sourcesFile
|
||||
);
|
||||
|
||||
// Check if stream copy is activated
|
||||
if($streamCopy === TRUE) {
|
||||
$commands[] = '-c';
|
||||
$commands[] = 'copy';
|
||||
}
|
||||
|
||||
// If not, we can apply filters
|
||||
else {
|
||||
foreach ($this->filters as $filter) {
|
||||
$commands = array_merge($commands, $filter->apply($this));
|
||||
}
|
||||
}
|
||||
|
||||
// Set the output file in the command
|
||||
$commands = array_merge($commands, array($outputPathfile));
|
||||
|
||||
// Execute the command
|
||||
try {
|
||||
$this->driver->command($commands);
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$this->cleanupTemporaryFile($outputPathfile);
|
||||
$this->cleanupTemporaryFile($sourcesFile);
|
||||
throw new RuntimeException('Unable to save concatenated video', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$this->cleanupTemporaryFile($sourcesFile);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the concatenated video in the given filename, considering that the sources videos are all encoded with the same codec.
|
||||
*
|
||||
* @param string $outputPathfile
|
||||
*
|
||||
* @return Concat
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function saveFromDifferentCodecs(FormatInterface $format, $outputPathfile)
|
||||
{
|
||||
/**
|
||||
* @see https://ffmpeg.org/ffmpeg-formats.html#concat
|
||||
* @see https://trac.ffmpeg.org/wiki/Concatenate
|
||||
*/
|
||||
|
||||
// Check the validity of the parameter
|
||||
if(!is_array($this->sources) || (count($this->sources) == 0)) {
|
||||
throw new InvalidArgumentException('The list of videos is not a valid array.');
|
||||
}
|
||||
|
||||
// Create the commands variable
|
||||
$commands = array();
|
||||
|
||||
// Prepare the parameters
|
||||
$nbSources = 0;
|
||||
$files = array();
|
||||
|
||||
// For each source, check if this is a legit file
|
||||
// and prepare the parameters
|
||||
foreach ($this->sources as $videoPath) {
|
||||
$files[] = '-i';
|
||||
$files[] = $videoPath;
|
||||
$nbSources++;
|
||||
}
|
||||
|
||||
$commands = array_merge($commands, $files);
|
||||
|
||||
// Set the parameters of the request
|
||||
$commands[] = '-filter_complex';
|
||||
|
||||
$complex_filter = '';
|
||||
for($i=0; $i<$nbSources; $i++) {
|
||||
$complex_filter .= '['.$i.':v:0] ['.$i.':a:0] ';
|
||||
}
|
||||
$complex_filter .= 'concat=n='.$nbSources.':v=1:a=1 [v] [a]';
|
||||
|
||||
$commands[] = $complex_filter;
|
||||
$commands[] = '-map';
|
||||
$commands[] = '[v]';
|
||||
$commands[] = '-map';
|
||||
$commands[] = '[a]';
|
||||
|
||||
// Prepare the filters
|
||||
$filters = clone $this->filters;
|
||||
$filters->add(new SimpleFilter($format->getExtraParams(), 10));
|
||||
|
||||
if ($this->driver->getConfiguration()->has('ffmpeg.threads')) {
|
||||
$filters->add(new SimpleFilter(array('-threads', $this->driver->getConfiguration()->get('ffmpeg.threads'))));
|
||||
}
|
||||
if ($format instanceof VideoInterface) {
|
||||
if (null !== $format->getVideoCodec()) {
|
||||
$filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec())));
|
||||
}
|
||||
}
|
||||
if ($format instanceof AudioInterface) {
|
||||
if (null !== $format->getAudioCodec()) {
|
||||
$filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec())));
|
||||
}
|
||||
}
|
||||
|
||||
// Add the filters
|
||||
foreach ($this->filters as $filter) {
|
||||
$commands = array_merge($commands, $filter->apply($this));
|
||||
}
|
||||
|
||||
if ($format instanceof AudioInterface) {
|
||||
if (null !== $format->getAudioKiloBitrate()) {
|
||||
$commands[] = '-b:a';
|
||||
$commands[] = $format->getAudioKiloBitrate() . 'k';
|
||||
}
|
||||
if (null !== $format->getAudioChannels()) {
|
||||
$commands[] = '-ac';
|
||||
$commands[] = $format->getAudioChannels();
|
||||
}
|
||||
}
|
||||
|
||||
// If the user passed some additional parameters
|
||||
if ($format instanceof VideoInterface) {
|
||||
if (null !== $format->getAdditionalParameters()) {
|
||||
foreach ($format->getAdditionalParameters() as $additionalParameter) {
|
||||
$commands[] = $additionalParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the output file in the command
|
||||
$commands[] = $outputPathfile;
|
||||
|
||||
$failure = null;
|
||||
|
||||
try {
|
||||
$this->driver->command($commands);
|
||||
} catch (ExecutionFailureException $e) {
|
||||
throw new RuntimeException('Encoding failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
@ -85,26 +85,31 @@ class Frame extends AbstractMediaType
|
|||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function save($pathfile, $accurate = false)
|
||||
public function save($pathfile, $accurate = false, $returnBase64 = false)
|
||||
{
|
||||
/**
|
||||
* might be optimized with http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg
|
||||
* @see http://ffmpeg.org/ffmpeg.html#Main-options
|
||||
*/
|
||||
$outputFormat = $returnBase64 ? "image2pipe" : "image2";
|
||||
if (!$accurate) {
|
||||
$commands = array(
|
||||
'-y', '-ss', (string) $this->timecode,
|
||||
'-i', $this->pathfile,
|
||||
'-vframes', '1',
|
||||
'-f', 'image2'
|
||||
'-f', $outputFormat
|
||||
);
|
||||
} else {
|
||||
$commands = array(
|
||||
'-y', '-i', $this->pathfile,
|
||||
'-vframes', '1', '-ss', (string) $this->timecode,
|
||||
'-f', 'image2'
|
||||
'-f', $outputFormat
|
||||
);
|
||||
}
|
||||
|
||||
if($returnBase64) {
|
||||
array_push($commands, "-");
|
||||
}
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
$commands = array_merge($commands, $filter->apply($this));
|
||||
|
|
@ -113,12 +118,16 @@ class Frame extends AbstractMediaType
|
|||
$commands = array_merge($commands, array($pathfile));
|
||||
|
||||
try {
|
||||
$this->driver->command($commands);
|
||||
if(!$returnBase64) {
|
||||
$this->driver->command($commands);
|
||||
return $this;
|
||||
}
|
||||
else {
|
||||
return $this->driver->command($commands);
|
||||
}
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$this->cleanupTemporaryFile($pathfile);
|
||||
throw new RuntimeException('Unable to save frame', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
137
src/FFMpeg/Media/Gif.php
Normal file
137
src/FFMpeg/Media/Gif.php
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of PHP-FFmpeg.
|
||||
*
|
||||
* (c) Strime <contact@strime.io>
|
||||
*
|
||||
* 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\Gif\GifFilterInterface;
|
||||
use FFMpeg\Filters\Gif\GifFilters;
|
||||
use FFMpeg\Driver\FFMpegDriver;
|
||||
use FFMpeg\FFProbe;
|
||||
use FFMpeg\Exception\RuntimeException;
|
||||
use FFMpeg\Coordinate\TimeCode;
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
|
||||
class Gif extends AbstractMediaType
|
||||
{
|
||||
/** @var TimeCode */
|
||||
private $timecode;
|
||||
/** @var Dimension */
|
||||
private $dimension;
|
||||
/** @var integer */
|
||||
private $duration;
|
||||
/** @var Video */
|
||||
private $video;
|
||||
|
||||
public function __construct(Video $video, FFMpegDriver $driver, FFProbe $ffprobe, TimeCode $timecode, Dimension $dimension, $duration = null)
|
||||
{
|
||||
parent::__construct($video->getPathfile(), $driver, $ffprobe);
|
||||
$this->timecode = $timecode;
|
||||
$this->dimension = $dimension;
|
||||
$this->duration = $duration;
|
||||
$this->video = $video;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the video related to the gif.
|
||||
*
|
||||
* @return Video
|
||||
*/
|
||||
public function getVideo()
|
||||
{
|
||||
return $this->video;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return GifFilters
|
||||
*/
|
||||
public function filters()
|
||||
{
|
||||
return new GifFilters($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return Gif
|
||||
*/
|
||||
public function addFilter(GifFilterInterface $filter)
|
||||
{
|
||||
$this->filters->add($filter);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TimeCode
|
||||
*/
|
||||
public function getTimeCode()
|
||||
{
|
||||
return $this->timecode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Dimension
|
||||
*/
|
||||
public function getDimension()
|
||||
{
|
||||
return $this->dimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the gif in the given filename.
|
||||
*
|
||||
* @param string $pathfile
|
||||
*
|
||||
* @return Gif
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function save($pathfile)
|
||||
{
|
||||
/**
|
||||
* @see http://ffmpeg.org/ffmpeg.html#Main-options
|
||||
*/
|
||||
$commands = array(
|
||||
'-ss', (string)$this->timecode
|
||||
);
|
||||
|
||||
if(null !== $this->duration) {
|
||||
$commands[] = '-t';
|
||||
$commands[] = (string)$this->duration;
|
||||
}
|
||||
|
||||
$commands[] = '-i';
|
||||
$commands[] = $this->pathfile;
|
||||
$commands[] = '-vf';
|
||||
$commands[] = 'scale=' . $this->dimension->getWidth() . ':-1';
|
||||
$commands[] = '-gifflags';
|
||||
$commands[] = '+transdiff';
|
||||
$commands[] = '-y';
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
$commands = array_merge($commands, $filter->apply($this));
|
||||
}
|
||||
|
||||
$commands = array_merge($commands, array($pathfile));
|
||||
|
||||
try {
|
||||
$this->driver->command($commands);
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$this->cleanupTemporaryFile($pathfile);
|
||||
throw new RuntimeException('Unable to save gif', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ namespace FFMpeg\Media;
|
|||
|
||||
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
|
||||
use FFMpeg\Coordinate\TimeCode;
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
use FFMpeg\Filters\Audio\SimpleFilter;
|
||||
use FFMpeg\Exception\InvalidArgumentException;
|
||||
use FFMpeg\Exception\RuntimeException;
|
||||
|
|
@ -23,12 +24,24 @@ use FFMpeg\Format\ProgressableInterface;
|
|||
use FFMpeg\Format\AudioInterface;
|
||||
use FFMpeg\Format\VideoInterface;
|
||||
use Neutron\TemporaryFilesystem\Manager as FsManager;
|
||||
use FFMpeg\Filters\Video\ClipFilter;
|
||||
|
||||
class Video extends Audio
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* FileSystem Manager instance
|
||||
* @var Manager
|
||||
*/
|
||||
protected $fs;
|
||||
|
||||
/**
|
||||
* FileSystem Manager ID
|
||||
* @var int
|
||||
*/
|
||||
protected $fsId;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @return VideoFilters
|
||||
*/
|
||||
public function filters()
|
||||
|
|
@ -37,8 +50,7 @@ class Video extends Audio
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @inheritDoc
|
||||
* @return Video
|
||||
*/
|
||||
public function addFilter(FilterInterface $filter)
|
||||
|
|
@ -51,15 +63,78 @@ class Video extends Audio
|
|||
/**
|
||||
* Exports the video in the desired format, applies registered filters.
|
||||
*
|
||||
* @param FormatInterface $format
|
||||
* @param string $outputPathfile
|
||||
*
|
||||
* @param FormatInterface $format
|
||||
* @param string $outputPathfile
|
||||
* @return Video
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function save(FormatInterface $format, $outputPathfile)
|
||||
{
|
||||
$passes = $this->buildCommand($format, $outputPathfile);
|
||||
|
||||
$failure = null;
|
||||
$totalPasses = $format->getPasses();
|
||||
|
||||
foreach ($passes as $pass => $passCommands) {
|
||||
try {
|
||||
/** add listeners here */
|
||||
$listeners = null;
|
||||
|
||||
if ($format instanceof ProgressableInterface) {
|
||||
$filters = clone $this->filters;
|
||||
$duration = 0;
|
||||
|
||||
// check the filters of the video, and if the video has the ClipFilter then
|
||||
// take the new video duration and send to the
|
||||
// FFMpeg\Format\ProgressListener\AbstractProgressListener class
|
||||
foreach ($filters as $filter) {
|
||||
if($filter instanceof ClipFilter){
|
||||
$duration = $filter->getDuration()->toSeconds();
|
||||
break;
|
||||
}
|
||||
}
|
||||
$listeners = $format->createProgressListener($this, $this->ffprobe, $pass + 1, $totalPasses, $duration);
|
||||
}
|
||||
|
||||
$this->driver->command($passCommands, false, $listeners);
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$failure = $e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->fs->clean($this->fsId);
|
||||
|
||||
if (null !== $failure) {
|
||||
throw new RuntimeException('Encoding failed', $failure->getCode(), $failure);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: This method is different to the Audio's one, because Video is using passes.
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFinalCommand(FormatInterface $format, $outputPathfile) {
|
||||
$finalCommands = array();
|
||||
|
||||
foreach($this->buildCommand($format, $outputPathfile) as $pass => $passCommands) {
|
||||
$finalCommands[] = implode(' ', $passCommands);
|
||||
}
|
||||
|
||||
$this->fs->clean($this->fsId);
|
||||
|
||||
return $finalCommands;
|
||||
}
|
||||
|
||||
/**
|
||||
* **NOTE:** This creates passes instead of a single command!
|
||||
*
|
||||
* @inheritDoc
|
||||
* @return string[][]
|
||||
*/
|
||||
protected function buildCommand(FormatInterface $format, $outputPathfile) {
|
||||
$commands = array('-y', '-i', $this->pathfile);
|
||||
|
||||
$filters = clone $this->filters;
|
||||
|
|
@ -119,17 +194,76 @@ class Video extends Audio
|
|||
}
|
||||
}
|
||||
|
||||
$fs = FsManager::create();
|
||||
$fsId = uniqid('ffmpeg-passes');
|
||||
$passPrefix = $fs->createTemporaryDirectory(0777, 50, $fsId) . '/' . uniqid('pass-');
|
||||
// If the user passed some additional parameters
|
||||
if ($format instanceof VideoInterface) {
|
||||
if (null !== $format->getAdditionalParameters()) {
|
||||
foreach ($format->getAdditionalParameters() as $additionalParameter) {
|
||||
$commands[] = $additionalParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge Filters into one command
|
||||
$videoFilterVars = $videoFilterProcesses = array();
|
||||
for($i=0;$i<count($commands);$i++) {
|
||||
$command = $commands[$i];
|
||||
if ( $command == '-vf' ) {
|
||||
$commandSplits = explode(";", $commands[$i + 1]);
|
||||
if ( count($commandSplits) == 1 ) {
|
||||
$commandSplit = $commandSplits[0];
|
||||
$command = trim($commandSplit);
|
||||
if ( preg_match("/^\[in\](.*?)\[out\]$/is", $command, $match) ) {
|
||||
$videoFilterProcesses[] = $match[1];
|
||||
} else {
|
||||
$videoFilterProcesses[] = $command;
|
||||
}
|
||||
} else {
|
||||
foreach($commandSplits as $commandSplit) {
|
||||
$command = trim($commandSplit);
|
||||
if ( preg_match("/^\[[^\]]+\](.*?)\[[^\]]+\]$/is", $command, $match) ) {
|
||||
$videoFilterProcesses[] = $match[1];
|
||||
} else {
|
||||
$videoFilterVars[] = $command;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($commands[$i]);
|
||||
unset($commands[$i + 1]);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
$videoFilterCommands = $videoFilterVars;
|
||||
$lastInput = 'in';
|
||||
foreach($videoFilterProcesses as $i => $process) {
|
||||
$command = '[' . $lastInput .']';
|
||||
$command .= $process;
|
||||
$lastInput = 'p' . $i;
|
||||
if($i === (count($videoFilterProcesses) - 1)) {
|
||||
$command .= '[out]';
|
||||
} else {
|
||||
$command .= '[' . $lastInput . ']';
|
||||
}
|
||||
|
||||
$videoFilterCommands[] = $command;
|
||||
}
|
||||
$videoFilterCommand = implode(';', $videoFilterCommands);
|
||||
|
||||
if($videoFilterCommand) {
|
||||
$commands[] = '-vf';
|
||||
$commands[] = $videoFilterCommand;
|
||||
}
|
||||
|
||||
$this->fs = FsManager::create();
|
||||
$this->fsId = uniqid('ffmpeg-passes');
|
||||
$passPrefix = $this->fs->createTemporaryDirectory(0777, 50, $this->fsId) . '/' . uniqid('pass-');
|
||||
$passes = array();
|
||||
$totalPasses = $format->getPasses();
|
||||
|
||||
if (1 > $totalPasses) {
|
||||
if(!$totalPasses) {
|
||||
throw new InvalidArgumentException('Pass number should be a positive value.');
|
||||
}
|
||||
|
||||
for ($i = 1; $i <= $totalPasses; $i++) {
|
||||
for($i = 1; $i <= $totalPasses; $i++) {
|
||||
$pass = $commands;
|
||||
|
||||
if ($totalPasses > 1) {
|
||||
|
|
@ -144,31 +278,7 @@ class Video extends Audio
|
|||
$passes[] = $pass;
|
||||
}
|
||||
|
||||
$failure = null;
|
||||
|
||||
foreach ($passes as $pass => $passCommands) {
|
||||
try {
|
||||
/** add listeners here */
|
||||
$listeners = null;
|
||||
|
||||
if ($format instanceof ProgressableInterface) {
|
||||
$listeners = $format->createProgressListener($this, $this->ffprobe, $pass + 1, $totalPasses);
|
||||
}
|
||||
|
||||
$this->driver->command($passCommands, false, $listeners);
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$failure = $e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$fs->clean($fsId);
|
||||
|
||||
if (null !== $failure) {
|
||||
throw new RuntimeException('Encoding failed', $failure->getCode(), $failure);
|
||||
}
|
||||
|
||||
return $this;
|
||||
return $passes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -181,4 +291,28 @@ class Video extends Audio
|
|||
{
|
||||
return new Frame($this, $this->driver, $this->ffprobe, $at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a gif from a sequence of the video.
|
||||
*
|
||||
* @param TimeCode $at
|
||||
* @param Dimension $dimension
|
||||
* @param integer $duration
|
||||
* @return Gif
|
||||
*/
|
||||
public function gif(TimeCode $at, Dimension $dimension, $duration = null)
|
||||
{
|
||||
return new Gif($this, $this->driver, $this->ffprobe, $at, $dimension, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates a list of videos into one unique video.
|
||||
*
|
||||
* @param array $sources
|
||||
* @return Concat
|
||||
*/
|
||||
public function concat($sources)
|
||||
{
|
||||
return new Concat($sources, $this->driver, $this->ffprobe);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
163
src/FFMpeg/Media/Waveform.php
Normal file
163
src/FFMpeg/Media/Waveform.php
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
<?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\Exception\InvalidArgumentException;
|
||||
use FFMpeg\Filters\Waveform\WaveformFilterInterface;
|
||||
use FFMpeg\Filters\Waveform\WaveformFilters;
|
||||
use FFMpeg\Driver\FFMpegDriver;
|
||||
use FFMpeg\FFProbe;
|
||||
use FFMpeg\Exception\RuntimeException;
|
||||
|
||||
class Waveform extends AbstractMediaType
|
||||
{
|
||||
const DEFAULT_COLOR = '#000000';
|
||||
|
||||
/** @var Video */
|
||||
protected $audio;
|
||||
protected $width;
|
||||
protected $height;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $colors;
|
||||
|
||||
public function __construct(Audio $audio, FFMpegDriver $driver, FFProbe $ffprobe, $width, $height, $colors = array(self::DEFAULT_COLOR))
|
||||
{
|
||||
parent::__construct($audio->getPathfile(), $driver, $ffprobe);
|
||||
$this->audio = $audio;
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
|
||||
$this->setColors($colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the audio related to the waveform.
|
||||
*
|
||||
* @return Audio
|
||||
*/
|
||||
public function getAudio()
|
||||
{
|
||||
return $this->audio;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return WaveformFilters
|
||||
*/
|
||||
public function filters()
|
||||
{
|
||||
return new WaveformFilters($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return Waveform
|
||||
*/
|
||||
public function addFilter(WaveformFilterInterface $filter)
|
||||
{
|
||||
$this->filters->add($filter);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter should be an array containing at least one valid color represented as a HTML color string. For
|
||||
* example #FFFFFF or #000000. By default the color is set to black. Keep in mind that if you save the waveform
|
||||
* as jpg file, it will appear completely black and to avoid this you can set the waveform color to white (#FFFFFF).
|
||||
* Saving waveforms to png is strongly suggested.
|
||||
*
|
||||
* @param array $colors
|
||||
*/
|
||||
public function setColors(array $colors)
|
||||
{
|
||||
foreach ($colors as $row => $value)
|
||||
{
|
||||
if (!preg_match('/^#(?:[0-9a-fA-F]{6})$/', $value))
|
||||
{
|
||||
//invalid color
|
||||
//unset($colors[$row]);
|
||||
|
||||
throw new InvalidArgumentException("The provided color '$value' is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
if (count($colors))
|
||||
{
|
||||
$this->colors = $colors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of colors that will be passed to ffmpeg to use for waveform generation. Colors are applied ONLY
|
||||
* to the waveform. Background cannot be controlled that easily and it is probably easier to save the waveform
|
||||
* as a transparent png file and then add background of choice.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getColors()
|
||||
{
|
||||
return $this->colors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the selected colors into a string, using a pipe separator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function compileColors()
|
||||
{
|
||||
return implode('|', $this->colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the waveform in the given filename.
|
||||
*
|
||||
* @param string $pathfile
|
||||
*
|
||||
* @return Waveform
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function save($pathfile)
|
||||
{
|
||||
/**
|
||||
* might be optimized with http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg
|
||||
* @see http://ffmpeg.org/ffmpeg.html#Main-options
|
||||
*/
|
||||
$commands = array(
|
||||
'-y', '-i', $this->pathfile, '-filter_complex',
|
||||
'showwavespic=colors='.$this->compileColors().':s='.$this->width.'x'.$this->height,
|
||||
'-frames:v', '1'
|
||||
);
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
$commands = array_merge($commands, $filter->apply($this));
|
||||
}
|
||||
|
||||
$commands = array_merge($commands, array($pathfile));
|
||||
|
||||
try {
|
||||
$this->driver->command($commands);
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$this->cleanupTemporaryFile($pathfile);
|
||||
throw new RuntimeException('Unable to save waveform', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Coordinate;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use FFMpeg\Coordinate\Point;
|
||||
|
||||
class PointTest extends TestCase
|
||||
{
|
||||
public function testGetters()
|
||||
{
|
||||
$point = new Point(4, 25);
|
||||
$this->assertEquals(4, $point->getX());
|
||||
$this->assertEquals(25, $point->getY());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Functional;
|
||||
namespace Tests\FFMpeg\Functional;
|
||||
|
||||
use FFMpeg\FFProbe;
|
||||
|
||||
|
|
@ -9,13 +9,26 @@ class FFProbeTest extends FunctionalTestCase
|
|||
public function testProbeOnFile()
|
||||
{
|
||||
$ffprobe = FFProbe::create();
|
||||
$this->assertGreaterThan(0, count($ffprobe->streams(__DIR__ . '/../../files/Audio.mp3')));
|
||||
$this->assertGreaterThan(0, count($ffprobe->streams(__DIR__ . '/../files/Audio.mp3')));
|
||||
}
|
||||
|
||||
public function testValidateExistingFile()
|
||||
{
|
||||
$ffprobe = FFProbe::create();
|
||||
$this->assertTrue($ffprobe->isValid(__DIR__ . '/../files/sample.3gp'));
|
||||
}
|
||||
|
||||
|
||||
public function testValidateNonExistingFile()
|
||||
{
|
||||
$ffprobe = FFProbe::create();
|
||||
$this->assertFalse($ffprobe->isValid(__DIR__ . '/../files/WrongFile.mp4'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException FFMpeg\Exception\RuntimeException
|
||||
*/
|
||||
public function testProbeOnUnexistantFile()
|
||||
public function testProbeOnNonExistantFile()
|
||||
{
|
||||
$ffprobe = FFProbe::create();
|
||||
$ffprobe->streams('/path/to/no/file');
|
||||
|
|
@ -24,6 +37,6 @@ class FFProbeTest extends FunctionalTestCase
|
|||
public function testProbeOnRemoteFile()
|
||||
{
|
||||
$ffprobe = FFProbe::create();
|
||||
$this->assertGreaterThan(0, count($ffprobe->streams('http://video-js.zencoder.com/oceans-clip.mp4')));
|
||||
$this->assertGreaterThan(0, count($ffprobe->streams('http://vjs.zencdn.net/v/oceans.mp4')));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Functional;
|
||||
namespace Tests\FFMpeg\Functional;
|
||||
|
||||
use FFMpeg\FFMpeg;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
abstract class FunctionalTestCase extends \PHPUnit_Framework_TestCase
|
||||
abstract class FunctionalTestCase extends TestCase
|
||||
{
|
||||
/**
|
||||
* @return FFMpeg
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Functional;
|
||||
namespace Tests\FFMpeg\Functional;
|
||||
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
use FFMpeg\Filters\Video\ResizeFilter;
|
||||
|
|
@ -18,14 +18,44 @@ class VideoTranscodeTest extends FunctionalTestCase
|
|||
}
|
||||
|
||||
$ffmpeg = $this->getFFMpeg();
|
||||
$video = $ffmpeg->open(__DIR__ . '/../../files/Test.ogv');
|
||||
$video = $ffmpeg->open(__DIR__ . '/../files/Test.ogv');
|
||||
|
||||
$this->assertInstanceOf('FFMpeg\Media\Video', $video);
|
||||
|
||||
$lastPercentage = null;
|
||||
$phpunit = $this;
|
||||
|
||||
$codec = new X264('libvo_aacenc');
|
||||
$codec = new X264('aac');
|
||||
$codec->on('progress', function ($video, $codec, $percentage) use ($phpunit, &$lastPercentage) {
|
||||
if (null !== $lastPercentage) {
|
||||
$phpunit->assertGreaterThanOrEqual($lastPercentage, $percentage);
|
||||
}
|
||||
$lastPercentage = $percentage;
|
||||
$phpunit->assertGreaterThanOrEqual(0, $percentage);
|
||||
$phpunit->assertLessThanOrEqual(100, $percentage);
|
||||
});
|
||||
|
||||
$video->save($codec, $filename);
|
||||
$this->assertFileExists($filename);
|
||||
unlink($filename);
|
||||
}
|
||||
|
||||
public function testAacTranscodeX264()
|
||||
{
|
||||
$filename = __DIR__ . '/output/output-x264_2.mp4';
|
||||
if (is_file($filename)) {
|
||||
unlink(__DIR__ . '/output/output-x264_2.mp4');
|
||||
}
|
||||
|
||||
$ffmpeg = $this->getFFMpeg();
|
||||
$video = $ffmpeg->open(__DIR__ . '/../files/sample.3gp');
|
||||
|
||||
$this->assertInstanceOf('FFMpeg\Media\Video', $video);
|
||||
|
||||
$lastPercentage = null;
|
||||
$phpunit = $this;
|
||||
|
||||
$codec = new X264('aac');
|
||||
$codec->on('progress', function ($video, $codec, $percentage) use ($phpunit, &$lastPercentage) {
|
||||
if (null !== $lastPercentage) {
|
||||
$phpunit->assertGreaterThanOrEqual($lastPercentage, $percentage);
|
||||
|
|
@ -46,16 +76,16 @@ class VideoTranscodeTest extends FunctionalTestCase
|
|||
public function testTranscodeInvalidFile()
|
||||
{
|
||||
$ffmpeg = $this->getFFMpeg();
|
||||
$ffmpeg->open(__DIR__ . '/../../files/UnknownFileTest.ogv');
|
||||
$ffmpeg->open(__DIR__ . '/../files/UnknownFileTest.ogv');
|
||||
}
|
||||
|
||||
public function testSaveInvalidForgedVideo()
|
||||
{
|
||||
$ffmpeg = $this->getFFMpeg();
|
||||
$video = new Video(__DIR__ . '/../../files/UnknownFileTest.ogv', $ffmpeg->getFFMpegDriver(), $ffmpeg->getFFProbe());
|
||||
$video = new Video(__DIR__ . '/../files/UnknownFileTest.ogv', $ffmpeg->getFFMpegDriver(), $ffmpeg->getFFProbe());
|
||||
|
||||
$this->setExpectedException('FFMpeg\Exception\RuntimeException');
|
||||
$video->save(new X264('libvo_aacenc'), __DIR__ . '/output/output-x264.mp4');
|
||||
$video->save(new X264('aac'), __DIR__ . '/output/output-x264.mp4');
|
||||
}
|
||||
|
||||
public function testTranscodePortraitVideo()
|
||||
|
|
@ -72,12 +102,12 @@ class VideoTranscodeTest extends FunctionalTestCase
|
|||
}
|
||||
|
||||
$ffmpeg = $this->getFFMpeg();
|
||||
$video = $ffmpeg->open(__DIR__ . '/../../files/portrait.MOV');
|
||||
$video = $ffmpeg->open(__DIR__ . '/../files/portrait.MOV');
|
||||
|
||||
$video->filters()
|
||||
->resize(new Dimension(320, 240), ResizeFilter::RESIZEMODE_INSET)
|
||||
->rotate(RotateFilter::ROTATE_90);
|
||||
$video->save(new X264('libvo_aacenc'), $filename);
|
||||
$video->save(new X264('aac'), $filename);
|
||||
|
||||
$dimension = $ffmpeg->getFFProbe()
|
||||
->streams($filename)
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Coordinate;
|
||||
namespace Tests\FFMpeg\Unit\Coordinate;
|
||||
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Coordinate\AspectRatio;
|
||||
|
||||
class AspectRatioTest extends TestCase
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Coordinate;
|
||||
namespace Tests\FFMpeg\Unit\Coordinate;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
|
||||
class DimensionTest extends TestCase
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Coordinate;
|
||||
namespace Tests\FFMpeg\Unit\Coordinate;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Coordinate\FrameRate;
|
||||
|
||||
class FrameRateTest extends TestCase
|
||||
23
tests/Unit/Coordinate/PointTest.php
Normal file
23
tests/Unit/Coordinate/PointTest.php
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\FFMpeg\Unit\Coordinate;
|
||||
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Coordinate\Point;
|
||||
|
||||
class PointTest extends TestCase
|
||||
{
|
||||
public function testGetters()
|
||||
{
|
||||
$point = new Point(4, 25);
|
||||
$this->assertEquals(4, $point->getX());
|
||||
$this->assertEquals(25, $point->getY());
|
||||
}
|
||||
|
||||
public function testDynamicPointGetters()
|
||||
{
|
||||
$point = new Point("t*100", "t", true);
|
||||
$this->assertEquals("t*100", $point->getX());
|
||||
$this->assertEquals("t", $point->getY());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Coordinate;
|
||||
namespace Tests\FFMpeg\Unit\Coordinate;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Coordinate\TimeCode;
|
||||
|
||||
class TimeCodeTest extends TestCase
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Driver;
|
||||
namespace Tests\FFMpeg\Unit\Driver;
|
||||
|
||||
use Alchemy\BinaryDriver\Configuration;
|
||||
use FFMpeg\Driver\FFMpegDriver;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use Symfony\Component\Process\ExecutableFinder;
|
||||
|
||||
class FFMpegDriverTest extends TestCase
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Driver;
|
||||
namespace Tests\FFMpeg\Unit\Driver;
|
||||
|
||||
use Alchemy\BinaryDriver\Configuration;
|
||||
use FFMpeg\Driver\FFProbeDriver;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use Symfony\Component\Process\ExecutableFinder;
|
||||
|
||||
class FFProbeDriverTest extends TestCase
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests;
|
||||
namespace Tests\FFMpeg\Unit;
|
||||
|
||||
use FFMpeg\FFMpegServiceProvider;
|
||||
use Silex\Application;
|
||||
use PHPUnit\Framework\TestCase as BaseTestCase;
|
||||
|
||||
class FFMpegServiceProviderTest extends \PHPUnit_Framework_TestCase
|
||||
class FFMpegServiceProviderTest extends BaseTestCase
|
||||
{
|
||||
public function testWithConfig()
|
||||
{
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests;
|
||||
namespace Tests\FFMpeg\Unit;
|
||||
|
||||
use FFMpeg\FFMpeg;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\FFProbe\DataMapping;
|
||||
namespace Tests\FFMpeg\Unit\FFProbe\DataMapping;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\FFProbe\DataMapping\AbstractData;
|
||||
|
||||
class AbstractDataTest extends TestCase
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\FFProbe\DataMapping;
|
||||
namespace Tests\FFMpeg\Unit\FFProbe\DataMapping;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
|
||||
class StreamCollectionTest extends TestCase
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\FFProbe\DataMapping;
|
||||
namespace Tests\FFMpeg\Unit\FFProbe\DataMapping;
|
||||
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
|
||||
class StreamTest extends TestCase
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\FFProbe;
|
||||
namespace Tests\FFMpeg\Unit\FFProbe;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\FFProbe\Mapper;
|
||||
use FFMpeg\FFProbe;
|
||||
use FFMpeg\FFProbe\DataMapping\Format;
|
||||
|
|
@ -31,8 +31,8 @@ class MapperTest extends TestCase
|
|||
|
||||
public function provideMappings()
|
||||
{
|
||||
$format = json_decode(file_get_contents(__DIR__ . '/../../../fixtures/ffprobe/show_format.json'), true);
|
||||
$streams = json_decode(file_get_contents(__DIR__ . '/../../../fixtures/ffprobe/show_streams.json'), true);
|
||||
$format = json_decode(file_get_contents(__DIR__ . '/../../fixtures/ffprobe/show_format.json'), true);
|
||||
$streams = json_decode(file_get_contents(__DIR__ . '/../../fixtures/ffprobe/show_streams.json'), true);
|
||||
|
||||
return array(
|
||||
array(FFProbe::TYPE_FORMAT, $format, new Format($format['format'])),
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\FFProbe;
|
||||
namespace Tests\FFMpeg\Unit\FFProbe;
|
||||
|
||||
use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\FFProbe\OptionsTester;
|
||||
|
||||
class OptionsTesterTest extends TestCase
|
||||
|
|
@ -55,7 +55,7 @@ class OptionsTesterTest extends TestCase
|
|||
|
||||
public function provideOptions()
|
||||
{
|
||||
$data = file_get_contents(__DIR__ . '/../../../fixtures/ffprobe/help.raw');
|
||||
$data = file_get_contents(__DIR__ . '/../../fixtures/ffprobe/help.raw');
|
||||
|
||||
return array(
|
||||
array(true, $data, '-print_format'),
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\FFProbe;
|
||||
namespace Tests\FFMpeg\Unit\FFProbe;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\FFProbe\OutputParser;
|
||||
use FFMpeg\FFProbe;
|
||||
|
||||
|
|
@ -28,11 +28,11 @@ class OutputParserTest extends TestCase
|
|||
|
||||
public function provideTypeDataAndOutput()
|
||||
{
|
||||
$expectedFormat = json_decode(file_get_contents(__DIR__ . '/../../../fixtures/ffprobe/show_format.json'), true);
|
||||
$expectedStreams = json_decode(file_get_contents(__DIR__ . '/../../../fixtures/ffprobe/show_streams.json'), true);
|
||||
$expectedFormat = json_decode(file_get_contents(__DIR__ . '/../../fixtures/ffprobe/show_format.json'), true);
|
||||
$expectedStreams = json_decode(file_get_contents(__DIR__ . '/../../fixtures/ffprobe/show_streams.json'), true);
|
||||
|
||||
$rawFormat = file_get_contents(__DIR__ . '/../../../fixtures/ffprobe/show_format.raw');
|
||||
$rawStreams = file_get_contents(__DIR__ . '/../../../fixtures/ffprobe/show_streams.raw');
|
||||
$rawFormat = file_get_contents(__DIR__ . '/../../fixtures/ffprobe/show_format.raw');
|
||||
$rawStreams = file_get_contents(__DIR__ . '/../../fixtures/ffprobe/show_streams.raw');
|
||||
|
||||
return array(
|
||||
array(FFProbe::TYPE_FORMAT, $rawFormat, $expectedFormat),
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests;
|
||||
namespace Tests\FFMpeg\Unit;
|
||||
|
||||
use FFMpeg\FFProbe;
|
||||
use Symfony\Component\Process\ExecutableFinder;
|
||||
47
tests/Unit/Filters/Audio/AudioClipTest.php
Normal file
47
tests/Unit/Filters/Audio/AudioClipTest.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\FFMpeg\Unit\Filters\Audio;
|
||||
|
||||
use FFMpeg\Filters\Audio\AudioFilters;
|
||||
use FFMpeg\Coordinate\TimeCode;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
|
||||
class AudioClipTest extends TestCase {
|
||||
|
||||
public function testClipping() {
|
||||
$capturedFilter = null;
|
||||
|
||||
$audio = $this->getAudioMock();
|
||||
$audio->expects($this->once())
|
||||
->method('addFilter')
|
||||
->with($this->isInstanceOf('FFMpeg\Filters\Audio\AudioClipFilter'))
|
||||
->will($this->returnCallback(function ($filter) use (&$capturedFilter) {
|
||||
$capturedFilter = $filter;
|
||||
}));
|
||||
$format = $this->getMock('FFMpeg\Format\AudioInterface');
|
||||
|
||||
$filters = new AudioFilters($audio);
|
||||
|
||||
$filters->clip(TimeCode::fromSeconds(5));
|
||||
$this->assertEquals(array(0 => '-ss', 1 => '00:00:05.00', 2 => '-acodec', 3 => 'copy'), $capturedFilter->apply($audio, $format));
|
||||
}
|
||||
|
||||
public function testClippingWithDuration() {
|
||||
$capturedFilter = null;
|
||||
|
||||
$audio = $this->getAudioMock();
|
||||
$audio->expects($this->once())
|
||||
->method('addFilter')
|
||||
->with($this->isInstanceOf('FFMpeg\Filters\Audio\AudioClipFilter'))
|
||||
->will($this->returnCallback(function ($filter) use (&$capturedFilter) {
|
||||
$capturedFilter = $filter;
|
||||
}));
|
||||
$format = $this->getMock('FFMpeg\Format\AudioInterface');
|
||||
|
||||
$filters = new AudioFilters($audio);
|
||||
|
||||
$filters->clip(TimeCode::fromSeconds(5), TimeCode::fromSeconds(5));
|
||||
$this->assertEquals(array(0 => '-ss', 1 => '00:00:05.00', 2 => '-t', 3 => '00:00:05.00', 4 => '-acodec', 5 => 'copy'), $capturedFilter->apply($audio, $format));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Audio;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Audio;
|
||||
|
||||
use FFMpeg\Filters\Audio\AudioFilters;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
|
||||
class AudioFiltersTest extends TestCase
|
||||
{
|
||||
64
tests/Unit/Filters/Audio/AudioMetadataTest.php
Normal file
64
tests/Unit/Filters/Audio/AudioMetadataTest.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\FFMpeg\Unit\Filters\Audio;
|
||||
|
||||
use FFMpeg\Filters\Audio\AudioFilters;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
|
||||
class AudioMetadataTest extends TestCase
|
||||
{
|
||||
public function testAddMetadata()
|
||||
{
|
||||
$capturedFilter = null;
|
||||
|
||||
$audio = $this->getAudioMock();
|
||||
$audio->expects($this->once())
|
||||
->method('addFilter')
|
||||
->with($this->isInstanceOf('FFMpeg\Filters\Audio\AddMetadataFilter'))
|
||||
->will($this->returnCallback(function ($filter) use (&$capturedFilter) {
|
||||
$capturedFilter = $filter;
|
||||
}));
|
||||
$format = $this->getMock('FFMpeg\Format\AudioInterface');
|
||||
|
||||
$filters = new AudioFilters($audio);
|
||||
$filters->addMetadata(array('title' => "Hello World"));
|
||||
$this->assertEquals(array(0 => "-metadata", 1 => "title=Hello World"), $capturedFilter->apply($audio, $format));
|
||||
}
|
||||
|
||||
public function testAddArtwork()
|
||||
{
|
||||
$capturedFilter = null;
|
||||
|
||||
$audio = $this->getAudioMock();
|
||||
$audio->expects($this->once())
|
||||
->method('addFilter')
|
||||
->with($this->isInstanceOf('FFMpeg\Filters\Audio\AddMetadataFilter'))
|
||||
->will($this->returnCallback(function ($filter) use (&$capturedFilter) {
|
||||
$capturedFilter = $filter;
|
||||
}));
|
||||
$format = $this->getMock('FFMpeg\Format\AudioInterface');
|
||||
|
||||
$filters = new AudioFilters($audio);
|
||||
$filters->addMetadata(array('genre' => 'Some Genre', 'artwork' => "/path/to/file.jpg"));
|
||||
$this->assertEquals(array(0 => "-i", 1 => "/path/to/file.jpg", 2 => "-map", 3 => "0", 4 => "-map", 5 => "1", 6 => "-metadata", 7 => "genre=Some Genre"), $capturedFilter->apply($audio, $format));
|
||||
$this->assertEquals(array(0 => "-i", 1 => "/path/to/file.jpg", 2 => "-map", 3 => "0", 4 => "-map", 5 => "1", 6 => "-metadata", 7 => "genre=Some Genre"), $capturedFilter->apply($audio, $format));
|
||||
}
|
||||
|
||||
public function testRemoveMetadata()
|
||||
{
|
||||
$capturedFilter = null;
|
||||
|
||||
$audio = $this->getAudioMock();
|
||||
$audio->expects($this->once())
|
||||
->method('addFilter')
|
||||
->with($this->isInstanceOf('FFMpeg\Filters\Audio\AddMetadataFilter'))
|
||||
->will($this->returnCallback(function ($filter) use (&$capturedFilter) {
|
||||
$capturedFilter = $filter;
|
||||
}));
|
||||
$format = $this->getMock('FFMpeg\Format\AudioInterface');
|
||||
|
||||
$filters = new AudioFilters($audio);
|
||||
$filters->addMetadata();
|
||||
$this->assertEquals(array(0 => "-map_metadata", 1 => "-1", 2 => "-vn"), $capturedFilter->apply($audio, $format));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Audio;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Audio;
|
||||
|
||||
use FFMpeg\Filters\Audio\AudioResamplableFilter;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
|
||||
class AudioResamplableFilterTest extends TestCase
|
||||
{
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters;
|
||||
namespace Tests\FFMpeg\Unit\Filters;
|
||||
|
||||
use FFMpeg\Filters\FiltersCollection;
|
||||
use FFMpeg\Filters\Audio\SimpleFilter;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
|
||||
class FiltersCollectionTest extends TestCase
|
||||
{
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Frame;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Frame;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Filters\Frame\DisplayRatioFixerFilter;
|
||||
use FFMpeg\Media\Frame;
|
||||
use FFMpeg\Coordinate\TimeCode;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Frame;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Frame;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Filters\Frame\FrameFilters;
|
||||
|
||||
class FrameFiltersTest extends TestCase
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Video;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
use FFMpeg\Coordinate\Point;
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
use FFMpeg\Filters\Video\CropFilter;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
|
||||
class CropFilterTest extends TestCase
|
||||
{
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Video;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\Filters\Video\CustomFilter;
|
||||
use FFMpeg\Filters\Video\FrameRateFilter;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Coordinate\FrameRate;
|
||||
|
||||
class CustomFilterTest extends TestCase
|
||||
51
tests/Unit/Filters/Video/ExtractMultipleFramesFilterTest.php
Normal file
51
tests/Unit/Filters/Video/ExtractMultipleFramesFilterTest.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\Filters\Video\ExtractMultipleFramesFilter;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
|
||||
class ExtractMultipleFramesFilterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideFrameRates
|
||||
*/
|
||||
public function testApply($frameRate, $destinationFolder, $duration, $modulus, $expected)
|
||||
{
|
||||
$video = $this->getVideoMock();
|
||||
$pathfile = '/path/to/file'.mt_rand();
|
||||
|
||||
$format = $this->getMock('FFMpeg\Format\VideoInterface');
|
||||
$format->expects($this->any())
|
||||
->method('getModulus')
|
||||
->will($this->returnValue($modulus));
|
||||
|
||||
$streams = new StreamCollection(array(
|
||||
new Stream(array(
|
||||
'codec_type' => 'video',
|
||||
'duration' => $duration,
|
||||
))
|
||||
));
|
||||
|
||||
$video->expects($this->once())
|
||||
->method('getStreams')
|
||||
->will($this->returnValue($streams));
|
||||
|
||||
$filter = new ExtractMultipleFramesFilter($frameRate, $destinationFolder);
|
||||
$this->assertEquals($expected, $filter->apply($video, $format));
|
||||
}
|
||||
|
||||
public function provideFrameRates()
|
||||
{
|
||||
return array(
|
||||
array(ExtractMultipleFramesFilter::FRAMERATE_EVERY_SEC, '/', 100, 2, array('-vf', 'fps=1/1', '/frame-%03d.jpg')),
|
||||
array(ExtractMultipleFramesFilter::FRAMERATE_EVERY_2SEC, '/', 100, 2, array('-vf', 'fps=1/2', '/frame-%02d.jpg')),
|
||||
array(ExtractMultipleFramesFilter::FRAMERATE_EVERY_5SEC, '/', 100, 2, array('-vf', 'fps=1/5', '/frame-%02d.jpg')),
|
||||
array(ExtractMultipleFramesFilter::FRAMERATE_EVERY_10SEC, '/', 100, 2, array('-vf', 'fps=1/10', '/frame-%02d.jpg')),
|
||||
array(ExtractMultipleFramesFilter::FRAMERATE_EVERY_30SEC, '/', 100, 2, array('-vf', 'fps=1/30', '/frame-%02d.jpg')),
|
||||
array(ExtractMultipleFramesFilter::FRAMERATE_EVERY_60SEC, '/', 100, 2, array('-vf', 'fps=1/60', '/frame-%02d.jpg')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Video;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\Filters\Video\FrameRateFilter;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Coordinate\FrameRate;
|
||||
|
||||
class FrameRateFilterTest extends TestCase
|
||||
44
tests/Unit/Filters/Video/PadFilterTest.php
Normal file
44
tests/Unit/Filters/Video/PadFilterTest.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\Filters\Video\PadFilter;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
|
||||
class PadFilterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideDimensions
|
||||
*/
|
||||
public function testApply(Dimension $dimension, $width, $height, $expected)
|
||||
{
|
||||
$video = $this->getVideoMock();
|
||||
$pathfile = '/path/to/file'.mt_rand();
|
||||
|
||||
$format = $this->getMock('FFMpeg\Format\VideoInterface');
|
||||
|
||||
$streams = new StreamCollection(array(
|
||||
new Stream(array(
|
||||
'codec_type' => 'video',
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
))
|
||||
));
|
||||
|
||||
$filter = new PadFilter($dimension);
|
||||
$this->assertEquals($expected, $filter->apply($video, $format));
|
||||
}
|
||||
|
||||
public function provideDimensions()
|
||||
{
|
||||
return array(
|
||||
array(new Dimension(1000, 800), 640, 480, array('-vf', 'scale=iw*min(1000/iw\,800/ih):ih*min(1000/iw\,800/ih),pad=1000:800:(1000-iw)/2:(800-ih)/2')),
|
||||
array(new Dimension(300, 600), 640, 480, array('-vf', 'scale=iw*min(300/iw\,600/ih):ih*min(300/iw\,600/ih),pad=300:600:(300-iw)/2:(600-ih)/2')),
|
||||
array(new Dimension(100, 900), 640, 480, array('-vf', 'scale=iw*min(100/iw\,900/ih):ih*min(100/iw\,900/ih),pad=100:900:(100-iw)/2:(900-ih)/2')),
|
||||
array(new Dimension(1200, 200), 640, 480, array('-vf', 'scale=iw*min(1200/iw\,200/ih):ih*min(1200/iw\,200/ih),pad=1200:200:(1200-iw)/2:(200-ih)/2')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Video;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\Filters\Video\ResizeFilter;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
|
|
@ -42,34 +42,34 @@ class ResizeFilterTest extends TestCase
|
|||
public function provideDimensions()
|
||||
{
|
||||
return array(
|
||||
array(new Dimension(320, 240), ResizeFilter::RESIZEMODE_FIT, 640, 480, 2, array('-s', '320x240')),
|
||||
array(new Dimension(320, 240), ResizeFilter::RESIZEMODE_INSET, 640, 480, 2, array('-s', '320x240')),
|
||||
array(new Dimension(320, 240), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 640, 480, 2, array('-s', '320x240')),
|
||||
array(new Dimension(320, 240), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 640, 480, 2, array('-s', '320x240')),
|
||||
array(new Dimension(320, 240), ResizeFilter::RESIZEMODE_FIT, 640, 480, 2, array('-vf', '[in]scale=320:240 [out]')),
|
||||
array(new Dimension(320, 240), ResizeFilter::RESIZEMODE_INSET, 640, 480, 2, array('-vf', '[in]scale=320:240 [out]')),
|
||||
array(new Dimension(320, 240), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 640, 480, 2, array('-vf', '[in]scale=320:240 [out]')),
|
||||
array(new Dimension(320, 240), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 640, 480, 2, array('-vf', '[in]scale=320:240 [out]')),
|
||||
|
||||
array(new Dimension(640, 480), ResizeFilter::RESIZEMODE_FIT, 320, 240, 2, array('-s', '640x480')),
|
||||
array(new Dimension(640, 480), ResizeFilter::RESIZEMODE_INSET, 320, 240, 2, array('-s', '640x480')),
|
||||
array(new Dimension(640, 480), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 320, 240, 2, array('-s', '640x480')),
|
||||
array(new Dimension(640, 480), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 320, 240, 2, array('-s', '640x480')),
|
||||
array(new Dimension(640, 480), ResizeFilter::RESIZEMODE_FIT, 320, 240, 2, array('-vf', '[in]scale=640:480 [out]')),
|
||||
array(new Dimension(640, 480), ResizeFilter::RESIZEMODE_INSET, 320, 240, 2, array('-vf', '[in]scale=640:480 [out]')),
|
||||
array(new Dimension(640, 480), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 320, 240, 2, array('-vf', '[in]scale=640:480 [out]')),
|
||||
array(new Dimension(640, 480), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 320, 240, 2, array('-vf', '[in]scale=640:480 [out]')),
|
||||
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_FIT, 1280, 720, 2, array('-s', '640x360')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_INSET, 1280, 720, 2, array('-s', '640x360')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 1280, 720, 2, array('-s', '640x360')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 1280, 720, 2, array('-s', '640x360')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_FIT, 1280, 720, 2, array('-vf', '[in]scale=640:360 [out]')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_INSET, 1280, 720, 2, array('-vf', '[in]scale=640:360 [out]')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 1280, 720, 2, array('-vf', '[in]scale=640:360 [out]')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 1280, 720, 2, array('-vf', '[in]scale=640:360 [out]')),
|
||||
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_FIT, 1280, 720, 2, array('-s', '640x360')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_INSET, 1280, 720, 2, array('-s', '640x360')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 1280, 720, 2, array('-s', '640x360')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 1280, 720, 2, array('-s', '640x360')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_FIT, 1280, 720, 2, array('-vf', '[in]scale=640:360 [out]')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_INSET, 1280, 720, 2, array('-vf', '[in]scale=640:360 [out]')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 1280, 720, 2, array('-vf', '[in]scale=640:360 [out]')),
|
||||
array(new Dimension(640, 360), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 1280, 720, 2, array('-vf', '[in]scale=640:360 [out]')),
|
||||
|
||||
// test non standard dimension
|
||||
array(new Dimension(700, 150), ResizeFilter::RESIZEMODE_INSET, 123, 456, 2, array('-s', '62x150'), true),
|
||||
array(new Dimension(700, 150), ResizeFilter::RESIZEMODE_INSET, 123, 456, 2, array('-s', '40x150'), false),
|
||||
array(new Dimension(700, 150), ResizeFilter::RESIZEMODE_INSET, 123, 456, 2, array('-vf', '[in]scale=62:150 [out]'), true),
|
||||
array(new Dimension(700, 150), ResizeFilter::RESIZEMODE_INSET, 123, 456, 2, array('-vf', '[in]scale=40:150 [out]'), false),
|
||||
|
||||
array(new Dimension(320, 320), ResizeFilter::RESIZEMODE_FIT, 640, 480, 2, array('-s', '320x320')),
|
||||
array(new Dimension(320, 320), ResizeFilter::RESIZEMODE_INSET, 640, 480, 2, array('-s', '320x240')),
|
||||
array(new Dimension(320, 320), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 640, 480, 2, array('-s', '320x240')),
|
||||
array(new Dimension(320, 320), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 640, 480, 2, array('-s', '426x320')),
|
||||
array(new Dimension(320, 320), ResizeFilter::RESIZEMODE_FIT, 640, 480, 2, array('-vf', '[in]scale=320:320 [out]')),
|
||||
array(new Dimension(320, 320), ResizeFilter::RESIZEMODE_INSET, 640, 480, 2, array('-vf', '[in]scale=320:240 [out]')),
|
||||
array(new Dimension(320, 320), ResizeFilter::RESIZEMODE_SCALE_HEIGHT, 640, 480, 2, array('-vf', '[in]scale=320:240 [out]')),
|
||||
array(new Dimension(320, 320), ResizeFilter::RESIZEMODE_SCALE_WIDTH, 640, 480, 2, array('-vf', '[in]scale=426:320 [out]')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Video;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
use FFMpeg\Filters\Video\RotateFilter;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
|
||||
class RotateFilterTest extends TestCase
|
||||
{
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Video;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Filters\Video\SynchronizeFilter;
|
||||
|
||||
class SynchronizeFilterTest extends TestCase
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Video;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Filters\Video\VideoFilters;
|
||||
use FFMpeg\Filters\Video\ResizeFilter;
|
||||
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Filters\Video;
|
||||
namespace Tests\FFMpeg\Unit\Filters\Video;
|
||||
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
use FFMpeg\Filters\Video\RotateFilter;
|
||||
use FFMpeg\Filters\Video\WatermarkFilter;
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
|
||||
class WatermarkFilterTest extends TestCase
|
||||
{
|
||||
|
|
@ -19,8 +19,8 @@ class WatermarkFilterTest extends TestCase
|
|||
|
||||
$format = $this->getMock('FFMpeg\Format\VideoInterface');
|
||||
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../../files/watermark.png');
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../../files/watermark.png [watermark]; [in][watermark] overlay=0:0 [out]'), $filter->apply($video, $format));
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../files/watermark.png');
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../files/watermark.png [watermark]; [in][watermark] overlay=0:0 [out]'), $filter->apply($video, $format));
|
||||
|
||||
// check size of video is unchanged
|
||||
$this->assertEquals(320, $stream->get('width'));
|
||||
|
|
@ -33,31 +33,31 @@ class WatermarkFilterTest extends TestCase
|
|||
$format = $this->getMock('FFMpeg\Format\VideoInterface');
|
||||
|
||||
// test position absolute
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../../files/watermark.png', array(
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../files/watermark.png', array(
|
||||
'position' => 'absolute',
|
||||
'x' => 10, 'y' => 5
|
||||
));
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../../files/watermark.png [watermark]; [in][watermark] overlay=10:5 [out]'), $filter->apply($video, $format));
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../files/watermark.png [watermark]; [in][watermark] overlay=10:5 [out]'), $filter->apply($video, $format));
|
||||
|
||||
// test position relative
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../../files/watermark.png', array(
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../files/watermark.png', array(
|
||||
'position' => 'relative',
|
||||
'bottom' => 10, 'left' => 5
|
||||
));
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../../files/watermark.png [watermark]; [in][watermark] overlay=5:main_h - 10 - overlay_h [out]'), $filter->apply($video, $format));
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../files/watermark.png [watermark]; [in][watermark] overlay=5:main_h - 10 - overlay_h [out]'), $filter->apply($video, $format));
|
||||
|
||||
// test position relative
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../../files/watermark.png', array(
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../files/watermark.png', array(
|
||||
'position' => 'relative',
|
||||
'bottom' => 5, 'right' => 4
|
||||
));
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../../files/watermark.png [watermark]; [in][watermark] overlay=main_w - 4 - overlay_w:main_h - 5 - overlay_h [out]'), $filter->apply($video, $format));
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../files/watermark.png [watermark]; [in][watermark] overlay=main_w - 4 - overlay_w:main_h - 5 - overlay_h [out]'), $filter->apply($video, $format));
|
||||
|
||||
// test position relative
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../../files/watermark.png', array(
|
||||
$filter = new WatermarkFilter(__DIR__ . '/../../../files/watermark.png', array(
|
||||
'position' => 'relative',
|
||||
'left' => 5, 'top' => 11
|
||||
));
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../../files/watermark.png [watermark]; [in][watermark] overlay=5:11 [out]'), $filter->apply($video, $format));
|
||||
$this->assertEquals(array('-vf', 'movie='.__DIR__ .'/../../../files/watermark.png [watermark]; [in][watermark] overlay=5:11 [out]'), $filter->apply($video, $format));
|
||||
}
|
||||
}
|
||||
28
tests/Unit/Filters/Waveform/WaveformDownmixFilterTest.php
Normal file
28
tests/Unit/Filters/Waveform/WaveformDownmixFilterTest.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\FFMpeg\Unit\Filters\Waveform;
|
||||
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Filters\Waveform\WaveformDownmixFilter;
|
||||
use FFMpeg\Media\Waveform;
|
||||
use FFMpeg\Coordinate\TimeCode;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
|
||||
class WaveformDownmixFilterTest extends TestCase
|
||||
{
|
||||
public function testApply()
|
||||
{
|
||||
$stream = new Stream(array('codec_type' => 'audio', 'width' => 960, 'height' => 720));
|
||||
$streams = new StreamCollection(array($stream));
|
||||
|
||||
$audio = $this->getAudioMock(__FILE__);
|
||||
$audio->expects($this->once())
|
||||
->method('getStreams')
|
||||
->will($this->returnValue($streams));
|
||||
|
||||
$waveform = new Waveform($audio, $this->getFFMpegDriverMock(), $this->getFFProbeMock(), 640, 120);
|
||||
$filter = new WaveformDownmixFilter(TRUE);
|
||||
$this->assertEquals(array('"aformat=channel_layouts=mono"'), $filter->apply($waveform));
|
||||
}
|
||||
}
|
||||
21
tests/Unit/Filters/Waveform/WaveformFiltersTest.php
Normal file
21
tests/Unit/Filters/Waveform/WaveformFiltersTest.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\FFMpeg\Unit\Filters\Waveform;
|
||||
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Filters\Waveform\WaveformFilters;
|
||||
|
||||
class WaveformFiltersTest extends TestCase
|
||||
{
|
||||
public function testResize()
|
||||
{
|
||||
$Waveform = $this->getWaveformMock();
|
||||
$filters = new WaveformFilters($Waveform);
|
||||
|
||||
$Waveform->expects($this->once())
|
||||
->method('addFilter')
|
||||
->with($this->isInstanceOf('FFMpeg\Filters\Waveform\WaveformDownmixFilter'));
|
||||
|
||||
$filters->setDownmix();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Audio;
|
||||
namespace Tests\FFMpeg\Unit\Format\Audio;
|
||||
|
||||
use FFMpeg\Format\Audio\Aac;
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Audio;
|
||||
namespace Tests\FFMpeg\Unit\Format\Audio;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Format\Audio\DefaultAudio;
|
||||
|
||||
abstract class AudioTestCase extends TestCase
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Audio;
|
||||
namespace Tests\FFMpeg\Unit\Format\Audio;
|
||||
|
||||
use FFMpeg\Format\Audio\Flac;
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Audio;
|
||||
namespace Tests\FFMpeg\Unit\Format\Audio;
|
||||
|
||||
use FFMpeg\Format\Audio\Mp3;
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Audio;
|
||||
namespace Tests\FFMpeg\Unit\Format\Audio;
|
||||
|
||||
use FFMpeg\Format\Audio\Vorbis;
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Audio;
|
||||
namespace Tests\FFMpeg\Unit\Format\Audio;
|
||||
|
||||
use FFMpeg\Format\Audio\Wav;
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\ProgressListener;
|
||||
namespace Tests\FFMpeg\Unit\Format\ProgressListener;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Format\ProgressListener\AudioProgressListener;
|
||||
use FFMpeg\FFProbe\DataMapping\Format;
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\ProgressListener;
|
||||
namespace Tests\FFMpeg\Unit\Format\ProgressListener;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
use FFMpeg\Format\ProgressListener\VideoProgressListener;
|
||||
use FFMpeg\FFProbe\DataMapping\Format;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ class VideoProgressListenerTest extends TestCase
|
|||
/**
|
||||
* @dataProvider provideData
|
||||
*/
|
||||
public function testHandle($size, $duration,
|
||||
public function testHandle($size, $duration, $newVideoDuration,
|
||||
$data, $expectedPercent, $expectedRemaining, $expectedRate,
|
||||
$data2, $expectedPercent2, $expectedRemaining2, $expectedRate2,
|
||||
$currentPass, $totalPass
|
||||
|
|
@ -26,7 +26,7 @@ class VideoProgressListenerTest extends TestCase
|
|||
'duration' => $duration,
|
||||
))));
|
||||
|
||||
$listener = new VideoProgressListener($ffprobe, __FILE__, $currentPass, $totalPass);
|
||||
$listener = new VideoProgressListener($ffprobe, __FILE__, $currentPass, $totalPass, $newVideoDuration);
|
||||
$phpunit = $this;
|
||||
$n = 0;
|
||||
$listener->on('progress', function ($percent, $remaining, $rate) use (&$n, $phpunit, $expectedPercent, $expectedRemaining, $expectedRate, $expectedPercent2, $expectedRemaining2, $expectedRate2) {
|
||||
|
|
@ -57,6 +57,7 @@ class VideoProgressListenerTest extends TestCase
|
|||
array(
|
||||
147073958,
|
||||
281.147533,
|
||||
281.147533,
|
||||
'frame= 206 fps=202 q=10.0 size= 571kB time=00:00:07.12 bitrate= 656.8kbits/s dup=9 drop=0',
|
||||
2,
|
||||
0,
|
||||
|
|
@ -71,6 +72,7 @@ class VideoProgressListenerTest extends TestCase
|
|||
array(
|
||||
147073958,
|
||||
281.147533,
|
||||
281.147533,
|
||||
'frame= 206 fps=202 q=10.0 size= 571kB time=00:00:07.12 bitrate= 656.8kbits/s dup=9 drop=0',
|
||||
1,
|
||||
0,
|
||||
|
|
@ -81,6 +83,21 @@ class VideoProgressListenerTest extends TestCase
|
|||
3868,
|
||||
1,
|
||||
2
|
||||
),
|
||||
array(
|
||||
147073958,
|
||||
281.147533,
|
||||
35,
|
||||
'frame= 206 fps=202 q=10.0 size= 571kB time=00:00:07.12 bitrate= 656.8kbits/s dup=9 drop=0',
|
||||
60,
|
||||
0,
|
||||
0,
|
||||
'frame= 854 fps=113 q=20.0 size= 4430kB time=00:00:33.04 bitrate=1098.5kbits/s dup=36 drop=0',
|
||||
97,
|
||||
0,
|
||||
3868,
|
||||
2,
|
||||
2
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Video;
|
||||
namespace Tests\FFMpeg\Unit\Format\Video;
|
||||
|
||||
use FFMpeg\Format\Video\Ogg;
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Video;
|
||||
namespace Tests\FFMpeg\Unit\Format\Video;
|
||||
|
||||
use FFMpeg\Tests\Format\Audio\AudioTestCase;
|
||||
use Tests\FFMpeg\Unit\Format\Audio\AudioTestCase;
|
||||
|
||||
abstract class VideoTestCase extends AudioTestCase
|
||||
{
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Video;
|
||||
namespace Tests\FFMpeg\Unit\Format\Video;
|
||||
|
||||
use FFMpeg\Format\Video\WMV3;
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Video;
|
||||
namespace Tests\FFMpeg\Unit\Format\Video;
|
||||
|
||||
use FFMpeg\Format\Video\WMV;
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Video;
|
||||
namespace Tests\FFMpeg\Unit\Format\Video;
|
||||
|
||||
use FFMpeg\Format\Video\WebM;
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Format\Video;
|
||||
namespace Tests\FFMpeg\Unit\Format\Video;
|
||||
|
||||
use FFMpeg\Format\Video\X264;
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Media;
|
||||
namespace Tests\FFMpeg\Unit\Media;
|
||||
|
||||
use FFMpeg\Tests\TestCase;
|
||||
use Tests\FFMpeg\Unit\TestCase;
|
||||
|
||||
abstract class AbstractMediaTestCase extends TestCase
|
||||
{
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace FFMpeg\Tests\Media;
|
||||
namespace Tests\FFMpeg\Unit\Media;
|
||||
|
||||
abstract class AbstractStreamableTestCase extends AbstractMediaTestCase
|
||||
{
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue