diff --git a/.gitignore b/.gitignore index ce4942f..9ea8c84 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ vendor .php-cs-fixer.cache *.mkv +tags +*.mp3 diff --git a/src/Map.php b/src/Map.php index d2d638f..d18196a 100644 --- a/src/Map.php +++ b/src/Map.php @@ -2,6 +2,9 @@ namespace Danjones\FFMpeg; +use FFMpeg\Format\ProgressableInterface; +use FFMpeg\Format\ProgressListener\AbstractProgressListener; + class Map { use Traits\HasMetadata; @@ -10,6 +13,8 @@ class Map protected string $path; /** @var Stream[] */ protected array $streams = []; + /** @var AbstractProgressListener[] */ + protected array $listeners = []; public function __construct(MappableMedia $media) { @@ -46,10 +51,24 @@ class Map public function saveStream(Stream $stream): static { $this->streams[] = $stream; + $format = $stream->getCodec(); + if ($format instanceof ProgressableInterface) { + $listener = $format->createProgressListener( + $this->media, + $this->media->getFFProbe(), + 1, 1, 0 + ); + $this->listeners = array_merge($this->listeners, $listener); + } return $this; } + public function getListeners(): array + { + return $this->listeners; + } + public function buildCommand(): array { $commands = []; diff --git a/src/MappableMedia.php b/src/MappableMedia.php index 6bede7c..095bab3 100644 --- a/src/MappableMedia.php +++ b/src/MappableMedia.php @@ -3,6 +3,8 @@ namespace Danjones\FFMpeg; use Alchemy\BinaryDriver\Exception\ExecutionFailureException; +use Evenement\EventEmitterInterface; +use Evenement\EventEmitterTrait; use FFMpeg\Driver\FFMpegDriver; use FFMpeg\Exception\RuntimeException; use FFMpeg\FFMpeg; @@ -14,20 +16,23 @@ use FFMpeg\Filters\AdvancedMedia\ComplexFilters; use FFMpeg\Filters\FiltersCollection; use FFMpeg\Format\AudioInterface; use FFMpeg\Format\FormatInterface; -use FFMpeg\Format\ProgressableInterface; use FFMpeg\Format\ProgressListener\AbstractProgressListener; +use FFMpeg\Format\ProgressListener\VideoProgressListener; +use FFMpeg\Format\ProgressableInterface; use FFMpeg\Format\VideoInterface; use FFMpeg\Media\AbstractMediaType; /** - * AdvancedMedia may have multiple inputs and multiple outputs. - * This class accepts only filters for -filter_complex option. + * MappableMedia may have multiple inputs and multiple outputs. + * This class does not accept filters. * But you can set initial and additional parameters of the ffmpeg command. * * @see http://trac.ffmpeg.org/wiki/Creating%20multiple%20outputs */ -class MappableMedia extends AbstractMediaType +class MappableMedia extends AbstractMediaType implements EventEmitterInterface { + use EventEmitterTrait; + /** * @var string[] */ @@ -46,10 +51,8 @@ class MappableMedia extends AbstractMediaType */ protected array $additionalParameters = []; - /** - * @var AbstractProgressListener[] - */ - protected array $listeners = []; + /** @var AbstractProgressListener[] */ + protected array $progressListeners = []; public function __construct(FFMpegDriver $driver, FFProbe $ffprobe) { @@ -152,72 +155,35 @@ class MappableMedia extends AbstractMediaType public function saveMap(Map $map): static { $this->maps[] = $map; + $this->progressListeners = array_merge($this->progressListeners, $map->getListeners()); return $this; } - /** - * Select the streams for output. - * - * @param string[] $outs output labels of the -filter_complex part - * @param FormatInterface $format format of the output file - * @param string $outputFilename output filename - * @param bool $forceDisableAudio - * @param bool $forceDisableVideo - * - * @return $this - * @todo Redo all of this. - * @see https://ffmpeg.org/ffmpeg.html#Manual-stream-selection - */ - private function map2( - array $outs, - FormatInterface $format, - $outputFilename, - $forceDisableAudio = false, - $forceDisableVideo = false - ) { - $commands = []; - foreach ($outs as $label) { - $commands[] = '-map'; - $commands[] = $label; - } - - // Apply format params. - $commands = array_merge( - $commands, - $this->applyFormatParams($format, $forceDisableAudio, $forceDisableVideo) - ); - - // Set output file. - $commands[] = $outputFilename; - - // Create a listener. - if ($format instanceof ProgressableInterface) { - $listener = $format->createProgressListener($this, $this->ffprobe, 1, 1, 0); - $this->listeners = array_merge($this->listeners, $listener); - } - - $this->mapCommands = array_merge($this->mapCommands, $commands); - - return $this; - } - - /** - * Apply added filters and execute ffmpeg command. - * - * @throws RuntimeException - */ public function save(): void { $command = $this->buildCommand(); + $this->addListener(); try { - $this->driver->command($command, false, $this->listeners); + $this->driver->command($command, false, $this->progressListeners); } catch (ExecutionFailureException $e) { throw new RuntimeException('Encoding failed', $e->getCode(), $e); } } + protected function addListener(): void + { + $self = $this; + $listener = new VideoProgressListener($this->ffprobe, $this->getPathfile(), 1, 1, 0); + + $listener->on('progress', function (...$args) use ($self) { + $self->emit('progress', array_merge([$self, null], $args)); + }); + + $this->progressListeners[] = $listener; + } + /** * @param bool $forceDisableAudio * @param bool $forceDisableVideo