Concatenation feature (#287)
* Creation of a feature to concatenate files into a new one. * Update of the README * Creation of the tests for the concatenation * We use an array of videos instead of a path to a text files * We use the bundle Temporary File System instead of getcwd
This commit is contained in:
		
					parent
					
						
							
								a6f6bbcb1e
							
						
					
				
			
			
				commit
				
					
						21c28dea25
					
				
			
		
					 8 changed files with 541 additions and 1 deletions
				
			
		
							
								
								
									
										58
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										58
									
								
								README.md
									
										
									
									
									
								
							|  | @ -405,7 +405,7 @@ accurate images ; it takes more time to execute. | ||||||
| 
 | 
 | ||||||
| #### Gif | #### Gif | ||||||
| 
 | 
 | ||||||
| A gif is an animated image extracted from a sequence of the video ;. | A gif is an animated image extracted from a sequence of the video. | ||||||
| 
 | 
 | ||||||
| You can save gif files using the `FFMpeg\Media\Gif::save` method. | You can save gif files using the `FFMpeg\Media\Gif::save` method. | ||||||
| 
 | 
 | ||||||
|  | @ -419,6 +419,62 @@ $video | ||||||
| This method has a third optional boolean parameter, which is the duration of the animation. | This method has a third optional boolean parameter, which is the duration of the animation. | ||||||
| If you don't set it, you will get a fixed gif image. | If you don't set it, you will get a fixed gif image. | ||||||
| 
 | 
 | ||||||
|  | #### Concatenation | ||||||
|  | 
 | ||||||
|  | This feature allows you to generate one audio or video file, based on multiple sources. | ||||||
|  | 
 | ||||||
|  | There are two ways to concatenate videos, depending on the codecs of the sources. | ||||||
|  | If your sources have all been encoded with the same codec, you will want to use the `FFMpeg\Media\Concatenate::saveFromSameCodecs` which has way better performances. | ||||||
|  | If your sources have been encoded with different codecs, you will want to use the `FFMpeg\Media\Concatenate::saveFromDifferentCodecs`. | ||||||
|  | 
 | ||||||
|  | The first function will use the initial codec as the one for the generated file. | ||||||
|  | With the second function, you will be able to choose which codec you want for the generated file. | ||||||
|  | 
 | ||||||
|  | You also need to pay attention to the fact that, when using the saveFromDifferentCodecs method, | ||||||
|  | your files MUST have video and audio streams. | ||||||
|  | 
 | ||||||
|  | In both cases, you will have to provide a list of files in a TXT file. | ||||||
|  | The TXT file will one path per line. Here is an example: | ||||||
|  | 
 | ||||||
|  | `txt | ||||||
|  | file './concat-1.mp4' | ||||||
|  | file 'concat-2.mp4' | ||||||
|  | #file 'concat-3.mp4' | ||||||
|  | ` | ||||||
|  | 
 | ||||||
|  | In this example, the third file will be ignored. | ||||||
|  | Please refer to the [documentation](https://trac.ffmpeg.org/wiki/Concatenate) for more details. | ||||||
|  | 
 | ||||||
|  | To concatenate videos encoded with the same codec, do as follow: | ||||||
|  | 
 | ||||||
|  | ```php | ||||||
|  | // In order to instantiate the video object, you HAVE TO pass a path to a valid video file. | ||||||
|  | // We recommand that you put there the path of any of the video you want to use in this concatenation. | ||||||
|  | $video = $ffmpeg->open( '/path/to/video' ); | ||||||
|  | $video | ||||||
|  |     ->concat('/path/to/list.txt') | ||||||
|  |     ->saveFromSameCodecs('/path/to/new_file', TRUE); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The boolean parameter of the save function allows you to use the copy parameter which accelerates drastically the generation of the encoded file. | ||||||
|  | 
 | ||||||
|  | To concatenate videos encoded with the same codec, do as follow: | ||||||
|  | 
 | ||||||
|  | ```php | ||||||
|  | // In order to instantiate the video object, you HAVE TO pass a path to a valid video file. | ||||||
|  | // We recommand that you put there the path of any of the video you want to use in this concatenation. | ||||||
|  | $video = $ffmpeg->open( '/path/to/video' ); | ||||||
|  | 
 | ||||||
|  | $format = new FFMpeg\Format\Video\X264(); | ||||||
|  | $format->setAudioCodec("libmp3lame"); | ||||||
|  | 
 | ||||||
|  | $video | ||||||
|  |     ->concat('/path/to/list.txt') | ||||||
|  |     ->saveFromDifferentCodecs($format, '/path/to/new_file'); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | More details about concatenation in FFMPEG can be found [here](https://trac.ffmpeg.org/wiki/Concatenate), [here](https://ffmpeg.org/ffmpeg-formats.html#concat-1) and [here](https://ffmpeg.org/ffmpeg.html#Stream-copy). | ||||||
|  | 
 | ||||||
| #### Formats | #### Formats | ||||||
| 
 | 
 | ||||||
| A format implements `FFMpeg\Format\FormatInterface`. To save to a video file, | A format implements `FFMpeg\Format\FormatInterface`. To save to a video file, | ||||||
|  |  | ||||||
							
								
								
									
										20
									
								
								src/FFMpeg/Filters/Concat/ConcatFilterInterface.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/FFMpeg/Filters/Concat/ConcatFilterInterface.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * This file is part of PHP-FFmpeg. | ||||||
|  |  * | ||||||
|  |  * (c) Strime <contact@strime.io> | ||||||
|  |  * | ||||||
|  |  * For the full copyright and license information, please view the LICENSE | ||||||
|  |  * file that was distributed with this source code. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace FFMpeg\Filters\Concat; | ||||||
|  | 
 | ||||||
|  | use FFMpeg\Filters\FilterInterface; | ||||||
|  | use FFMpeg\Media\Concat; | ||||||
|  | 
 | ||||||
|  | interface ConcatFilterInterface extends FilterInterface | ||||||
|  | { | ||||||
|  |     public function apply(Concat $concat); | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								src/FFMpeg/Filters/Concat/ConcatFilters.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/FFMpeg/Filters/Concat/ConcatFilters.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * This file is part of PHP-FFmpeg. | ||||||
|  |  * | ||||||
|  |  * (c) Strime <contact@strime.io> | ||||||
|  |  * | ||||||
|  |  * For the full copyright and license information, please view the LICENSE | ||||||
|  |  * file that was distributed with this source code. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace FFMpeg\Filters\Concat; | ||||||
|  | 
 | ||||||
|  | use FFMpeg\Media\Concat; | ||||||
|  | 
 | ||||||
|  | class ConcatFilters | ||||||
|  | { | ||||||
|  |     private $concat; | ||||||
|  | 
 | ||||||
|  |     public function __construct(Concat $concat) | ||||||
|  |     { | ||||||
|  |         $this->concat = $concat; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										259
									
								
								src/FFMpeg/Media/Concat.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								src/FFMpeg/Media/Concat.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,259 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * This file is part of PHP-FFmpeg. | ||||||
|  |  * | ||||||
|  |  * (c) Strime <contact@strime.io> | ||||||
|  |  * | ||||||
|  |  * For the full copyright and license information, please view the LICENSE | ||||||
|  |  * file that was distributed with this source code. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace FFMpeg\Media; | ||||||
|  | 
 | ||||||
|  | use Alchemy\BinaryDriver\Exception\ExecutionFailureException; | ||||||
|  | use Alchemy\BinaryDriver\Exception\InvalidArgumentException; | ||||||
|  | use FFMpeg\Filters\Concat\ConcatFilterInterface; | ||||||
|  | use FFMpeg\Filters\Concat\ConcatFilters; | ||||||
|  | use FFMpeg\Driver\FFMpegDriver; | ||||||
|  | use FFMpeg\FFProbe; | ||||||
|  | use FFMpeg\Filters\Audio\SimpleFilter; | ||||||
|  | use FFMpeg\Exception\RuntimeException; | ||||||
|  | use FFMpeg\Format\FormatInterface; | ||||||
|  | use FFMpeg\Filters\FilterInterface; | ||||||
|  | use FFMpeg\Format\ProgressableInterface; | ||||||
|  | use FFMpeg\Format\AudioInterface; | ||||||
|  | use FFMpeg\Format\VideoInterface; | ||||||
|  | use Neutron\TemporaryFilesystem\Manager as FsManager; | ||||||
|  | 
 | ||||||
|  | class Concat extends AbstractMediaType | ||||||
|  | { | ||||||
|  |     /** @var array */ | ||||||
|  |     private $sources; | ||||||
|  | 
 | ||||||
|  |     public function __construct($sources, FFMpegDriver $driver, FFProbe $ffprobe) | ||||||
|  |     { | ||||||
|  |         parent::__construct($sources, $driver, $ffprobe); | ||||||
|  |         $this->sources = $sources; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Returns the path to the sources. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getSources() | ||||||
|  |     { | ||||||
|  |         return $this->sources; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      * | ||||||
|  |      * @return ConcatFilters | ||||||
|  |      */ | ||||||
|  |     public function filters() | ||||||
|  |     { | ||||||
|  |         return new ConcatFilters($this); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      * | ||||||
|  |      * @return Concat | ||||||
|  |      */ | ||||||
|  |     public function addFilter(ConcatFilterInterface $filter) | ||||||
|  |     { | ||||||
|  |         $this->filters->add($filter); | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Saves the concatenated video in the given array, considering that the sources videos are all encoded with the same codec. | ||||||
|  |      * | ||||||
|  |      * @param array   $outputPathfile | ||||||
|  |      * @param string  $streamCopy | ||||||
|  |      * | ||||||
|  |      * @return Concat | ||||||
|  |      * | ||||||
|  |      * @throws RuntimeException | ||||||
|  |      */ | ||||||
|  |     public function saveFromSameCodecs($outputPathfile, $streamCopy = TRUE) | ||||||
|  |     { | ||||||
|  |         /** | ||||||
|  |          * @see https://ffmpeg.org/ffmpeg-formats.html#concat
 | ||||||
|  |          * @see https://trac.ffmpeg.org/wiki/Concatenate | ||||||
|  |          */ | ||||||
|  | 
 | ||||||
|  |         // Create the file which will contain the list of videos
 | ||||||
|  |         $fs = FsManager::create(); | ||||||
|  |         $sourcesFile = $fs->createTemporaryFile('ffmpeg-concat'); | ||||||
|  | 
 | ||||||
|  |         // Set the content of this file
 | ||||||
|  |         $fileStream = fopen($sourcesFile, 'w') or die("Cannot open file."); | ||||||
|  |         $count_videos = 0; | ||||||
|  |         if(is_array($this->sources) && (count($this->sources) > 0)) { | ||||||
|  |             foreach ($this->sources as $videoPath) { | ||||||
|  |                 $line = ""; | ||||||
|  |                  | ||||||
|  |                 if($count_videos != 0) | ||||||
|  |                     $line .= "\n"; | ||||||
|  |                  | ||||||
|  |                 $line .= "file ".$videoPath; | ||||||
|  |                  | ||||||
|  |                 fwrite($fileStream, $line); | ||||||
|  |                  | ||||||
|  |                 $count_videos++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             throw new InvalidArgumentException('The list of videos is not a valid array.'); | ||||||
|  |         } | ||||||
|  |         fclose($fileStream); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         $commands = array( | ||||||
|  |             '-f', 'concat', '-safe', '0', | ||||||
|  |             '-i', $sourcesFile | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         // Check if stream copy is activated
 | ||||||
|  |         if($streamCopy === TRUE) { | ||||||
|  |             $commands[] = '-c'; | ||||||
|  |             $commands[] = 'copy'; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // If not, we can apply filters
 | ||||||
|  |         else { | ||||||
|  |             foreach ($this->filters as $filter) { | ||||||
|  |                 $commands = array_merge($commands, $filter->apply($this)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Set the output file in the command
 | ||||||
|  |         $commands = array_merge($commands, array($outputPathfile)); | ||||||
|  | 
 | ||||||
|  |         // Execute the command
 | ||||||
|  |         try { | ||||||
|  |             $this->driver->command($commands); | ||||||
|  |         } catch (ExecutionFailureException $e) { | ||||||
|  |             $this->cleanupTemporaryFile($outputPathfile); | ||||||
|  |             $this->cleanupTemporaryFile($sourcesFile); | ||||||
|  |             throw new RuntimeException('Unable to save concatenated video', $e->getCode(), $e); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $this->cleanupTemporaryFile($sourcesFile); | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Saves the concatenated video in the given filename, considering that the sources videos are all encoded with the same codec. | ||||||
|  |      * | ||||||
|  |      * @param string  $outputPathfile | ||||||
|  |      * | ||||||
|  |      * @return Concat | ||||||
|  |      * | ||||||
|  |      * @throws RuntimeException | ||||||
|  |      */ | ||||||
|  |     public function saveFromDifferentCodecs(FormatInterface $format, $outputPathfile) | ||||||
|  |     { | ||||||
|  |         /** | ||||||
|  |          * @see https://ffmpeg.org/ffmpeg-formats.html#concat
 | ||||||
|  |          * @see https://trac.ffmpeg.org/wiki/Concatenate | ||||||
|  |          */ | ||||||
|  | 
 | ||||||
|  |         // Check the validity of the parameter
 | ||||||
|  |         if(!is_array($this->sources) || (count($this->sources) == 0)) { | ||||||
|  |             throw new InvalidArgumentException('The list of videos is not a valid array.'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Create the commands variable
 | ||||||
|  |         $commands = array(); | ||||||
|  | 
 | ||||||
|  |         // Prepare the parameters
 | ||||||
|  |         $nbSources = 0; | ||||||
|  |         $files = array(); | ||||||
|  | 
 | ||||||
|  |         // For each source, check if this is a legit file
 | ||||||
|  |         // and prepare the parameters
 | ||||||
|  |         foreach ($this->sources as $videoPath) { | ||||||
|  |             $files[] = '-i'; | ||||||
|  |             $files[] = $videoPath; | ||||||
|  |             $nbSources++; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $commands = array_merge($commands, $files); | ||||||
|  | 
 | ||||||
|  |         // Set the parameters of the request
 | ||||||
|  |         $commands[] = '-filter_complex'; | ||||||
|  | 
 | ||||||
|  |         $complex_filter = ''; | ||||||
|  |         for($i=0; $i<$nbSources; $i++) { | ||||||
|  |             $complex_filter .= '['.$i.':v:0] ['.$i.':a:0] '; | ||||||
|  |         } | ||||||
|  |         $complex_filter .= 'concat=n='.$nbSources.':v=1:a=1 [v] [a]'; | ||||||
|  |          | ||||||
|  |         $commands[] = $complex_filter; | ||||||
|  |         $commands[] = '-map'; | ||||||
|  |         $commands[] = '[v]'; | ||||||
|  |         $commands[] = '-map'; | ||||||
|  |         $commands[] = '[a]'; | ||||||
|  | 
 | ||||||
|  |         // Prepare the filters
 | ||||||
|  |         $filters = clone $this->filters; | ||||||
|  |         $filters->add(new SimpleFilter($format->getExtraParams(), 10)); | ||||||
|  | 
 | ||||||
|  |         if ($this->driver->getConfiguration()->has('ffmpeg.threads')) { | ||||||
|  |             $filters->add(new SimpleFilter(array('-threads', $this->driver->getConfiguration()->get('ffmpeg.threads')))); | ||||||
|  |         } | ||||||
|  |         if ($format instanceof VideoInterface) { | ||||||
|  |             if (null !== $format->getVideoCodec()) { | ||||||
|  |                 $filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec()))); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if ($format instanceof AudioInterface) { | ||||||
|  |             if (null !== $format->getAudioCodec()) { | ||||||
|  |                 $filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec()))); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Add the filters
 | ||||||
|  |         foreach ($this->filters as $filter) { | ||||||
|  |             $commands = array_merge($commands, $filter->apply($this)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if ($format instanceof AudioInterface) { | ||||||
|  |             if (null !== $format->getAudioKiloBitrate()) { | ||||||
|  |                 $commands[] = '-b:a'; | ||||||
|  |                 $commands[] = $format->getAudioKiloBitrate() . 'k'; | ||||||
|  |             } | ||||||
|  |             if (null !== $format->getAudioChannels()) { | ||||||
|  |                 $commands[] = '-ac'; | ||||||
|  |                 $commands[] = $format->getAudioChannels(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // If the user passed some additional parameters
 | ||||||
|  |         if ($format instanceof VideoInterface) { | ||||||
|  |             if (null !== $format->getAdditionalParameters()) { | ||||||
|  |                 foreach ($format->getAdditionalParameters() as $additionalParameter) { | ||||||
|  |                     $commands[] = $additionalParameter; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Set the output file in the command
 | ||||||
|  |         $commands[] = $outputPathfile; | ||||||
|  | 
 | ||||||
|  |         $failure = null; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             $this->driver->command($commands); | ||||||
|  |         } catch (ExecutionFailureException $e) { | ||||||
|  |             throw new RuntimeException('Encoding failed', $e->getCode(), $e); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -204,4 +204,15 @@ class Video extends Audio | ||||||
|     { |     { | ||||||
|         return new Gif($this, $this->driver, $this->ffprobe, $at, $dimension, $duration); |         return new Gif($this, $this->driver, $this->ffprobe, $at, $dimension, $duration); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Concatenates a list of videos into one unique video. | ||||||
|  |      * | ||||||
|  |      * @param  string $sources | ||||||
|  |      * @return Concat | ||||||
|  |      */ | ||||||
|  |     public function concat($sources) | ||||||
|  |     { | ||||||
|  |         return new Concat($sources, $this->driver, $this->ffprobe); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										147
									
								
								tests/Unit/Media/ConcatTest.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								tests/Unit/Media/ConcatTest.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,147 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Tests\FFMpeg\Unit\Media; | ||||||
|  | 
 | ||||||
|  | use FFMpeg\Media\Concat; | ||||||
|  | use Neutron\TemporaryFilesystem\Manager as FsManager; | ||||||
|  | 
 | ||||||
|  | class ConcatTest extends AbstractMediaTestCase | ||||||
|  | { | ||||||
|  |     public function testGetSources() | ||||||
|  |     { | ||||||
|  |         $driver = $this->getFFMpegDriverMock(); | ||||||
|  |         $ffprobe = $this->getFFProbeMock(); | ||||||
|  | 
 | ||||||
|  |         $concat = new Concat(array(__FILE__, __FILE__), $driver, $ffprobe); | ||||||
|  |         $this->assertSame(array(__FILE__, __FILE__), $concat->getSources()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testFiltersReturnFilters() | ||||||
|  |     { | ||||||
|  |         $driver = $this->getFFMpegDriverMock(); | ||||||
|  |         $ffprobe = $this->getFFProbeMock(); | ||||||
|  | 
 | ||||||
|  |         $concat = new Concat(array(__FILE__, __FILE__), $driver, $ffprobe); | ||||||
|  |         $this->assertInstanceOf('FFMpeg\Filters\Concat\ConcatFilters', $concat->filters()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function testAddFiltersAddsAFilter() | ||||||
|  |     { | ||||||
|  |         $driver = $this->getFFMpegDriverMock(); | ||||||
|  |         $ffprobe = $this->getFFProbeMock(); | ||||||
|  | 
 | ||||||
|  |         $filters = $this->getMockBuilder('FFMpeg\Filters\FiltersCollection') | ||||||
|  |             ->disableOriginalConstructor() | ||||||
|  |             ->getMock(); | ||||||
|  | 
 | ||||||
|  |         $filter = $this->getMock('FFMpeg\Filters\Concat\ConcatFilterInterface'); | ||||||
|  | 
 | ||||||
|  |         $filters->expects($this->once()) | ||||||
|  |             ->method('add') | ||||||
|  |             ->with($filter); | ||||||
|  | 
 | ||||||
|  |         $concat = new Concat(array(__FILE__, __FILE__), $driver, $ffprobe); | ||||||
|  |         $concat->setFiltersCollection($filters); | ||||||
|  |         $concat->addFilter($filter); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @dataProvider provideSaveFromSameCodecsOptions | ||||||
|  |      */ | ||||||
|  |     public function testSaveFromSameCodecs($streamCopy, $commands) | ||||||
|  |     { | ||||||
|  |         $driver = $this->getFFMpegDriverMock(); | ||||||
|  |         $ffprobe = $this->getFFProbeMock(); | ||||||
|  | 
 | ||||||
|  |         $pathfile = '/target/destination'; | ||||||
|  | 
 | ||||||
|  |         array_push($commands, $pathfile); | ||||||
|  | 
 | ||||||
|  |         $driver->expects($this->exactly(1)) | ||||||
|  |             ->method('command') | ||||||
|  |             ->with($this->isType('array'), false, $this->anything()) | ||||||
|  |             ->will($this->returnCallback(function ($commands, $errors, $listeners) {})); | ||||||
|  | 
 | ||||||
|  |         $concat = new Concat(array(__FILE__, 'concat-2.mp4'), $driver, $ffprobe); | ||||||
|  |         $concat->saveFromSameCodecs($pathfile, $streamCopy); | ||||||
|  | 
 | ||||||
|  |         $this->assertEquals('-f', $commands[0]); | ||||||
|  |         $this->assertEquals('concat', $commands[1]); | ||||||
|  |         $this->assertEquals('-safe', $commands[2]); | ||||||
|  |         $this->assertEquals('0', $commands[3]); | ||||||
|  |         $this->assertEquals('-i', $commands[4]); | ||||||
|  |         if(isset($commands[6]) && (strcmp($commands[6], "-c") == 0)) { | ||||||
|  |             $this->assertEquals('-c', $commands[6]); | ||||||
|  |             $this->assertEquals('copy', $commands[7]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function provideSaveFromSameCodecsOptions() | ||||||
|  |     { | ||||||
|  |         $fs = FsManager::create(); | ||||||
|  |         $tmpFile = $fs->createTemporaryFile('ffmpeg-concat'); | ||||||
|  | 
 | ||||||
|  |         return array( | ||||||
|  |             array( | ||||||
|  |                 TRUE, | ||||||
|  |                 array( | ||||||
|  |                     '-f', 'concat', | ||||||
|  |                     '-safe', '0', | ||||||
|  |                     '-i', $tmpFile, | ||||||
|  |                     '-c', 'copy' | ||||||
|  |                 ), | ||||||
|  |             ), | ||||||
|  |             array( | ||||||
|  |                 FALSE, | ||||||
|  |                 array( | ||||||
|  |                     '-f', 'concat', | ||||||
|  |                     '-safe', '0', | ||||||
|  |                     '-i', $tmpFile | ||||||
|  |                 ) | ||||||
|  |             ), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @dataProvider provideSaveFromDifferentCodecsOptions | ||||||
|  |      */ | ||||||
|  |     public function testSaveFromDifferentCodecs($commands) | ||||||
|  |     { | ||||||
|  |         $driver = $this->getFFMpegDriverMock(); | ||||||
|  |         $ffprobe = $this->getFFProbeMock(); | ||||||
|  |         $format = $this->getFormatInterfaceMock(); | ||||||
|  | 
 | ||||||
|  |         $pathfile = '/target/destination'; | ||||||
|  | 
 | ||||||
|  |         array_push($commands, $pathfile); | ||||||
|  | 
 | ||||||
|  |         $configuration = $this->getMock('Alchemy\BinaryDriver\ConfigurationInterface'); | ||||||
|  | 
 | ||||||
|  |         $driver->expects($this->any()) | ||||||
|  |             ->method('getConfiguration') | ||||||
|  |             ->will($this->returnValue($configuration)); | ||||||
|  | 
 | ||||||
|  |         $driver->expects($this->once()) | ||||||
|  |             ->method('command') | ||||||
|  |             ->with($commands); | ||||||
|  | 
 | ||||||
|  |         $concat = new Concat(array(__FILE__, 'concat-2.mp4'), $driver, $ffprobe); | ||||||
|  |         $this->assertSame($concat, $concat->saveFromDifferentCodecs($format, $pathfile)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function provideSaveFromDifferentCodecsOptions() | ||||||
|  |     { | ||||||
|  |         return array( | ||||||
|  |             array( | ||||||
|  |                 array( | ||||||
|  |                     '-i', __FILE__, | ||||||
|  |                     '-i', 'concat-2.mp4', | ||||||
|  |                     '-filter_complex',  | ||||||
|  |                     '[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]', | ||||||
|  |                     '-map', '[v]',  | ||||||
|  |                     '-map', '[a]' | ||||||
|  |                 ), | ||||||
|  |             ), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -148,4 +148,24 @@ class TestCase extends \PHPUnit_Framework_TestCase | ||||||
| 
 | 
 | ||||||
|         return $video; |         return $video; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     public function getConcatMock() | ||||||
|  |     { | ||||||
|  |         return $this->getMockBuilder('FFMpeg\Media\Concat') | ||||||
|  |             ->disableOriginalConstructor() | ||||||
|  |             ->getMock(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getFormatInterfaceMock() | ||||||
|  |     { | ||||||
|  |         $FormatInterface = $this->getMockBuilder('FFMpeg\Format\FormatInterface') | ||||||
|  |             ->disableOriginalConstructor() | ||||||
|  |             ->getMock(); | ||||||
|  | 
 | ||||||
|  |         $FormatInterface->expects($this->any()) | ||||||
|  |             ->method('getExtraParams') | ||||||
|  |             ->will($this->returnValue(array())); | ||||||
|  | 
 | ||||||
|  |         return $FormatInterface; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								tests/files/concat-list.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tests/files/concat-list.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | file './concat-1.mp4' | ||||||
|  | file 'concat-2.mp4' | ||||||
|  | #file 'concat-3.mp4' | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue