Audio Clip (#314)

* add missing headers
* add audio clip filter and improve timecode
* php 5.4 :(
* prevent audio from being reencoded
* php 5.x: Really?
* fix tests... I need to concentrate...
This commit is contained in:
Jens Hausdorf 2017-03-06 14:17:12 +01:00 committed by Romain Biard
commit ecd50cd5f1
6 changed files with 201 additions and 0 deletions

View file

@ -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());
}
}

View file

@ -1,4 +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\Filters\Audio\AudioFilterInterface;

View 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;
}
}

View file

@ -1,9 +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
{
@ -48,4 +58,17 @@ class AudioFilters
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;
}
}

View file

@ -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;

View 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));
}
}