🔀 Merge branch 'release/0.2.0' into stable
Some checks failed
Check & fix styling / php-cs-fixer (push) Has been cancelled
Tests / P8 - prefer-lowest - ubuntu-latest (push) Has been cancelled
Tests / P8 - prefer-stable - ubuntu-latest (push) Has been cancelled
Tests / P8 - prefer-lowest - windows-latest (push) Has been cancelled
Tests / P8 - prefer-stable - windows-latest (push) Has been cancelled

This commit is contained in:
Dan Jones 2022-09-10 23:46:45 -05:00
commit 42c112c942
5 changed files with 119 additions and 7 deletions

View file

@ -2,6 +2,10 @@
All notable changes to `ffmpeg-mappable-media` will be documented in this file.
## 0.2.0
- ✨ Support attachments
## 0.1.3
- ✨ Support progress listeners

View file

@ -98,7 +98,7 @@ use FFMpeg\Format\Video\X264;
MappableMedia::make($ffmpeg)
->addInput('input.mkv')
->map()
->saveAs('output.mk')
->saveAs('output.mkv')
->stream()->setCodec(new X264())->saveStream()
->saveMap()
->save()
@ -112,7 +112,7 @@ The `map` and `stream` methods can take an optional callback, allowing you to se
MappableMedia::make($ffmpeg)
->addInput('input.mkv')
->map(function (Map $map) {
$map->saveAs('output.mk')
$map->saveAs('output.mkv')
->stream(function (Stream $stream) {
$stream->copy()->setInput('0:0');
});
@ -129,7 +129,7 @@ It is possible to set a listener on the individual streams, using the Format cla
MappableMedia::make($ffmpeg)
->addInput('input.mkv')
->map()
->saveAs('output.mk')
->saveAs('output.mkv')
->stream()->copy()->saveStream()
->saveMap()
->on('progress', function (MappableMedia $media, int $percent, int $remaining, int $rate) {
@ -138,6 +138,47 @@ MappableMedia::make($ffmpeg)
->save()
```
### Attachments
Some formats (mkv, for example) support arbitrary data attachments. These can be used as cover art, fonts for subtitles, or any arbitrary data.
FFMpeg does support attachments as an additional input. This works well for images, but can be finicky for other file types. Because of this, FFMpeg also supports an `-attach` flag which can be used to explicitly attach a new stream.
Due to the way FFMpeg handles `-attach` differently than `-i`, these need to be added as streams to a specific map, rather than the whole media. Here are a few examples.
```php
MappableMedia::make($ffmpeg)
->addInput('input.mkv')
->map()
->saveAs('output.mkv')
->stream()->copy()->saveStream()
->attach('image.jpg')
->mime('image/jpeg')
->addMetadata('filename', 'cover.jpg')
->saveAttachment()
->saveMap()
->save();
```
In this example, we added cover art to the file. Notice the use of the `mime` method to specify the mime-type. **This must always be done**. Note that we also specified a different filename so that the media player would recognize it as cover art. If you don't specify a filename, the original will be used.
```php
MappableMedia::make($ffmpeg)
->addInput('input.mkv')
->addInput('subs.ass')
->map()
->saveAs('output.mkv')
->stream()->copy()->saveStream()
->stream()->setInput('1:0')->copy()->saveStream()
->attach(verdana.ttf')
->mime('application/x-truetype-font')
->saveAttachment()
->saveMap()
->save();
```
In this example, we've added a font, which is likely referenced in the subtitle file, `subs.ass`.
## Future Plans
- [ ] Add listeners that return all the stdin/stderr

46
src/Attachment.php Normal file
View file

@ -0,0 +1,46 @@
<?php
namespace Danjones\FFMpeg;
use FFMpeg\Format\FormatInterface;
class Attachment extends Stream
{
protected string $input = '';
public function __construct(Map $map, string $file = '')
{
$this->map = $map;
$this->input = $file;
// Shouldn't be necessary, but just in case
$this->codec = new Format\Copy();
}
public function mime(string $mime): static
{
return $this->addMetadata('mimetype', $mime);
}
public function setCodec(FormatInterface $codec): static
{
return $this;
}
protected function parseCodec(): static
{
return $this;
}
public function saveAttachment(): Map
{
return $this->saveStream();;
}
public function buildCommand(int $idx = 0): array
{
$commands = parent::buildCommand($idx);
$commands[0] = '-attach';
return $commands;
}
}

View file

@ -13,6 +13,8 @@ class Map
protected string $path;
/** @var Stream[] */
protected array $streams = [];
/** @var Attachment[] */
protected array $attachments = [];
/** @var AbstractProgressListener[] */
protected array $listeners = [];
@ -35,9 +37,8 @@ class Map
return $this;
}
public function stream(callable $callback = null): Stream|static
protected function doStream(Stream $stream, callable $callback = null): Stream|static
{
$stream = new Stream($this);
if (!$callback) {
return $stream;
}
@ -48,8 +49,24 @@ class Map
return $this;
}
public function stream(callable $callback = null): Stream|static
{
return $this->doStream(new Stream($this), $callback);
}
public function attach(string $file = '', callable $callback = null): Attachment|static
{
return $this->doStream(new Attachment($this, $file), $callback);
}
public function saveStream(Stream $stream): static
{
if ($stream instanceof Attachment){
$this->attachments[] = $stream;
return $this;
}
$this->streams[] = $stream;
$format = $stream->getCodec();
if ($format instanceof ProgressableInterface) {
@ -72,7 +89,9 @@ class Map
public function buildCommand(): array
{
$commands = [];
foreach ($this->streams as $idx => $stream) {
$streams = $this->streams;
array_push($streams, ...$this->attachments);
foreach ($streams as $idx => $stream) {
array_push($commands, ...$stream->buildCommand($idx));
}
foreach ($this->metadata as $k => $v) {

View file

@ -125,7 +125,9 @@ class MappableMedia extends AbstractMediaType implements EventEmitterInterface
public function getFinalCommand(): string
{
return implode(' ', $this->buildCommand());
$proc = $this->driver->getProcessBuilderFactory()->create($this->buildCommand());
return $proc->getCommandLine();
}
public function map(callable $callback = null): Map|static