Compare commits
	
		
			5 commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 42c112c942 | |||
| 249a559c12 | |||
| cb892134ca | |||
| 77cf08260a | |||
| 82d2fdaeae | 
					 5 changed files with 119 additions and 7 deletions
				
			
		|  | @ -2,6 +2,10 @@ | ||||||
| 
 | 
 | ||||||
| All notable changes to `ffmpeg-mappable-media` will be documented in this file. | All notable changes to `ffmpeg-mappable-media` will be documented in this file. | ||||||
| 
 | 
 | ||||||
|  | ## 0.2.0 | ||||||
|  | 
 | ||||||
|  | -  ✨ Support attachments | ||||||
|  | 
 | ||||||
| ## 0.1.3 | ## 0.1.3 | ||||||
| 
 | 
 | ||||||
| - ✨ Support progress listeners | - ✨ Support progress listeners | ||||||
|  |  | ||||||
							
								
								
									
										47
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										47
									
								
								README.md
									
										
									
									
									
								
							|  | @ -98,7 +98,7 @@ use FFMpeg\Format\Video\X264; | ||||||
| MappableMedia::make($ffmpeg) | MappableMedia::make($ffmpeg) | ||||||
|     ->addInput('input.mkv') |     ->addInput('input.mkv') | ||||||
|     ->map() |     ->map() | ||||||
|         ->saveAs('output.mk') |         ->saveAs('output.mkv') | ||||||
|         ->stream()->setCodec(new X264())->saveStream() |         ->stream()->setCodec(new X264())->saveStream() | ||||||
|         ->saveMap() |         ->saveMap() | ||||||
|     ->save() |     ->save() | ||||||
|  | @ -112,7 +112,7 @@ The `map` and `stream` methods can take an optional callback, allowing you to se | ||||||
| MappableMedia::make($ffmpeg) | MappableMedia::make($ffmpeg) | ||||||
|     ->addInput('input.mkv') |     ->addInput('input.mkv') | ||||||
|     ->map(function (Map $map) { |     ->map(function (Map $map) { | ||||||
|         $map->saveAs('output.mk') |         $map->saveAs('output.mkv') | ||||||
|             ->stream(function (Stream $stream) { |             ->stream(function (Stream $stream) { | ||||||
|                 $stream->copy()->setInput('0:0'); |                 $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) | MappableMedia::make($ffmpeg) | ||||||
|     ->addInput('input.mkv') |     ->addInput('input.mkv') | ||||||
|     ->map() |     ->map() | ||||||
|         ->saveAs('output.mk') |         ->saveAs('output.mkv') | ||||||
|         ->stream()->copy()->saveStream() |         ->stream()->copy()->saveStream() | ||||||
|         ->saveMap() |         ->saveMap() | ||||||
|     ->on('progress', function (MappableMedia $media, int $percent, int $remaining, int $rate) { |     ->on('progress', function (MappableMedia $media, int $percent, int $remaining, int $rate) { | ||||||
|  | @ -138,6 +138,47 @@ MappableMedia::make($ffmpeg) | ||||||
|     ->save() |     ->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 | ## Future Plans | ||||||
| 
 | 
 | ||||||
| - [ ] Add listeners that return all the stdin/stderr | - [ ] Add listeners that return all the stdin/stderr | ||||||
|  |  | ||||||
							
								
								
									
										46
									
								
								src/Attachment.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/Attachment.php
									
										
									
									
									
										Normal 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; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								src/Map.php
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								src/Map.php
									
										
									
									
									
								
							|  | @ -13,6 +13,8 @@ class Map | ||||||
|     protected string $path; |     protected string $path; | ||||||
|     /** @var Stream[] */ |     /** @var Stream[] */ | ||||||
|     protected array $streams = []; |     protected array $streams = []; | ||||||
|  |     /** @var Attachment[] */ | ||||||
|  |     protected array $attachments = []; | ||||||
|     /** @var AbstractProgressListener[] */ |     /** @var AbstractProgressListener[] */ | ||||||
|     protected array $listeners = []; |     protected array $listeners = []; | ||||||
| 
 | 
 | ||||||
|  | @ -35,9 +37,8 @@ class Map | ||||||
|         return $this; |         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) { |         if (!$callback) { | ||||||
|             return $stream; |             return $stream; | ||||||
|         } |         } | ||||||
|  | @ -48,8 +49,24 @@ class Map | ||||||
|         return $this; |         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 |     public function saveStream(Stream $stream): static | ||||||
|     { |     { | ||||||
|  |         if ($stream instanceof Attachment){ | ||||||
|  |             $this->attachments[] = $stream; | ||||||
|  | 
 | ||||||
|  |             return $this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $this->streams[] = $stream; |         $this->streams[] = $stream; | ||||||
|         $format = $stream->getCodec(); |         $format = $stream->getCodec(); | ||||||
|         if ($format instanceof ProgressableInterface) { |         if ($format instanceof ProgressableInterface) { | ||||||
|  | @ -72,7 +89,9 @@ class Map | ||||||
|     public function buildCommand(): array |     public function buildCommand(): array | ||||||
|     { |     { | ||||||
|         $commands = []; |         $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)); |             array_push($commands, ...$stream->buildCommand($idx)); | ||||||
|         } |         } | ||||||
|         foreach ($this->metadata as $k => $v) { |         foreach ($this->metadata as $k => $v) { | ||||||
|  |  | ||||||
|  | @ -125,7 +125,9 @@ class MappableMedia extends AbstractMediaType implements EventEmitterInterface | ||||||
| 
 | 
 | ||||||
|     public function getFinalCommand(): string |     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 |     public function map(callable $callback = null): Map|static | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue