PHP-FFMpeg has grown and what was a simple H264 encoder is now a bigger library.
To sum up here is what we have :
FFMpeg\FFMpeg
: the main component that opens a file, transcode it to a desired format and can optionnaly extract an image.FFMpeg\FFProbe
: a component that extracts Streams and Formats informations about a file.
- More tests : for the moment the library use mostly functionnal testing. It's a design issue, all processes are instancied from the component, it's not easily mockable.
- More features : there are plenty of features waiting in github issues : cue points, subtitles, rotation and so on.
- More customization : Adding a progress handler was a bit tricky and I don't like the addHandler method (mostly because of its semantic)
To achieve this, we need to split this components in more subclass, make them more testable, and optimize design to fit all our needs
We need to splt FFMpeg/FFMpeg
in a service and an object :
FFMpeg\FFMpeg
is the service that opens and creates FFMpeg\MediaInterface
(FFMpeg\Video
and FFMpeg\Audio
) :
<?php
namespace FFMpeg;
use Psr\LoggerAwreInterface;
class FFMpeg implements LoggerAwareInterface
{
/**
* @param $pathfile
*
* @return MediaInterface
*/
public function open($pathfile);
/**
* @return MediaInterface
*/
public function create();
}
<?php
namespace FFMpeg;
use Symfony\Component\Process\ProcessBuilder;
class Video implements MediaInterface, LogerAwareInterface, EventEmitterInterface
{
/** @var ProcessBuilder */
private $processBuilder;
public function addListener(ListenerInterface $listener);
public function save(FormatInterface $format);
/**
* @return Effects
*/
public function effects();
public function crop(Position $position, Size $size);
public function screenshot(Timecode $at);
public function cut(Timecode $from, Timecode $to);
public function paste(MediaInterface $media, Position $position, Size $size);
}
We can think about FFMpeg\Video
implementing IteratorAggregate
to provide an access to new FFMpeg\Streams
object in the future.
<?php
namespace FFMpeg;
use Symfony\Component\Process\ProcessBuilder;
class Effects
{
public function __construct(ProcessBuilder $builder);
public function verticalFlip();
public function horizontalFlip();
public function blackAndWhite();
public function negative();
public function rotate($angle);
}
Those of you that are friends with Imagine source code would recognize the design I propose.
Listeners :
The first listener to implement is the ProgressListener :
<?php
ProgressListener implements ListenerInterface
{
public function __construct($callable, $event = 'progress.*')
{
$this->callable = $callable;
$this->event = $event;
}
public function register(EventEmitterInterface $emitter)
{
$callable = $this->callable;
$emitter->on($this->event, function ($event, MediaInterface $media, $data) use ($callable) {
// process raw data, get an overall percentage...
call_user_func($callable, array($event, $media, $overall, $data));
})
}
}
@romainneutron we're only using the audio layer so far for simply transcoding from anything to mp3, but i'm familiar with the Imagine API, and adopting this interface to the PHP-FFMpeg library sounds like a good idea.
I guess implementing those changes will result in a lot of BC breaks, but as the library is tagged anyway, this shouldn't be a problem for people not wanting to refactor their existing apps.