| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * This file is part of PHP-FFmpeg. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * (c) Alchemy <info@alchemy.fr> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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 FFMpeg\Coordinate\TimeCode; | 
					
						
							| 
									
										
										
										
											2013-06-26 00:21:12 +02:00
										 |  |  | use FFMpeg\Filters\Audio\SimpleFilter; | 
					
						
							| 
									
										
										
										
											2013-10-10 13:27:06 +02:00
										 |  |  | use FFMpeg\Exception\InvalidArgumentException; | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | use FFMpeg\Exception\RuntimeException; | 
					
						
							|  |  |  | use FFMpeg\Filters\Video\VideoFilters; | 
					
						
							| 
									
										
										
										
											2013-06-25 21:43:01 +02:00
										 |  |  | use FFMpeg\Filters\FilterInterface; | 
					
						
							|  |  |  | use FFMpeg\Format\FormatInterface; | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | use FFMpeg\Format\ProgressableInterface; | 
					
						
							| 
									
										
										
										
											2013-10-10 15:09:10 +02:00
										 |  |  | use FFMpeg\Format\AudioInterface; | 
					
						
							|  |  |  | use FFMpeg\Format\VideoInterface; | 
					
						
							| 
									
										
										
										
											2013-10-10 13:27:06 +02:00
										 |  |  | use Neutron\TemporaryFilesystem\Manager as FsManager; | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 21:43:01 +02:00
										 |  |  | class Video extends Audio | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * {@inheritdoc} | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return VideoFilters | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function filters() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return new VideoFilters($this); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * {@inheritdoc} | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return Video | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2013-06-25 21:43:01 +02:00
										 |  |  |     public function addFilter(FilterInterface $filter) | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         $this->filters->add($filter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2013-06-25 10:40:20 +02:00
										 |  |  |      * Exports the video in the desired format, applies registered filters. | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * | 
					
						
							|  |  |  |      * @param FormatInterface $format | 
					
						
							|  |  |  |      * @param string          $outputPathfile | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return Video | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @throws RuntimeException | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2013-06-25 21:43:01 +02:00
										 |  |  |     public function save(FormatInterface $format, $outputPathfile) | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-06-26 00:21:12 +02:00
										 |  |  |         $commands = array('-y', '-i', $this->pathfile); | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-05 14:19:12 +02:00
										 |  |  |         $filters = clone $this->filters; | 
					
						
							|  |  |  |         $filters->add(new SimpleFilter($format->getExtraParams(), 10)); | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if ($this->driver->getConfiguration()->has('ffmpeg.threads')) { | 
					
						
							| 
									
										
										
										
											2013-08-05 14:19:12 +02:00
										 |  |  |             $filters->add(new SimpleFilter(array('-threads', $this->driver->getConfiguration()->get('ffmpeg.threads')))); | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-08-12 20:49:42 +02:00
										 |  |  |         if ($format instanceof VideoInterface) { | 
					
						
							| 
									
										
										
										
											2013-10-10 15:09:10 +02:00
										 |  |  |             if (null !== $format->getVideoCodec()) { | 
					
						
							|  |  |  |                 $filters->add(new SimpleFilter(array('-vcodec', $format->getVideoCodec()))); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-08-12 20:49:42 +02:00
										 |  |  |         if ($format instanceof AudioInterface) { | 
					
						
							| 
									
										
										
										
											2013-10-10 15:09:10 +02:00
										 |  |  |             if (null !== $format->getAudioCodec()) { | 
					
						
							|  |  |  |                 $filters->add(new SimpleFilter(array('-acodec', $format->getAudioCodec()))); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-06-26 00:21:12 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-05 14:19:12 +02:00
										 |  |  |         foreach ($filters as $filter) { | 
					
						
							| 
									
										
										
										
											2013-06-26 00:21:12 +02:00
										 |  |  |             $commands = array_merge($commands, $filter->apply($this, $format)); | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-12 20:49:42 +02:00
										 |  |  |         if ($format instanceof VideoInterface) { | 
					
						
							| 
									
										
										
										
											2013-10-10 15:09:10 +02:00
										 |  |  |             $commands[] = '-b:v'; | 
					
						
							|  |  |  |             $commands[] = $format->getKiloBitrate() . 'k'; | 
					
						
							|  |  |  |             $commands[] = '-refs'; | 
					
						
							|  |  |  |             $commands[] = '6'; | 
					
						
							|  |  |  |             $commands[] = '-coder'; | 
					
						
							|  |  |  |             $commands[] = '1'; | 
					
						
							|  |  |  |             $commands[] = '-sc_threshold'; | 
					
						
							|  |  |  |             $commands[] = '40'; | 
					
						
							|  |  |  |             $commands[] = '-flags'; | 
					
						
							|  |  |  |             $commands[] = '+loop'; | 
					
						
							|  |  |  |             $commands[] = '-me_range'; | 
					
						
							|  |  |  |             $commands[] = '16'; | 
					
						
							|  |  |  |             $commands[] = '-subq'; | 
					
						
							|  |  |  |             $commands[] = '7'; | 
					
						
							|  |  |  |             $commands[] = '-i_qfactor'; | 
					
						
							|  |  |  |             $commands[] = '0.71'; | 
					
						
							|  |  |  |             $commands[] = '-qcomp'; | 
					
						
							|  |  |  |             $commands[] = '0.6'; | 
					
						
							|  |  |  |             $commands[] = '-qdiff'; | 
					
						
							|  |  |  |             $commands[] = '4'; | 
					
						
							|  |  |  |             $commands[] = '-trellis'; | 
					
						
							|  |  |  |             $commands[] = '1'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-12 20:49:42 +02:00
										 |  |  |         if ($format instanceof AudioInterface) { | 
					
						
							| 
									
										
										
										
											2013-10-10 15:09:10 +02:00
										 |  |  |             if (null !== $format->getAudioKiloBitrate()) { | 
					
						
							|  |  |  |                 $commands[] = '-b:a'; | 
					
						
							|  |  |  |                 $commands[] = $format->getAudioKiloBitrate() . 'k'; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-08-05 14:19:12 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-10 13:27:06 +02:00
										 |  |  |         $fs = FsManager::create(); | 
					
						
							|  |  |  |         $fsId = uniqid('ffmpeg-passes'); | 
					
						
							|  |  |  |         $passPrefix = $fs->createTemporaryDirectory(0777, 50, $fsId) . '/' . uniqid('pass-'); | 
					
						
							|  |  |  |         $passes = array(); | 
					
						
							|  |  |  |         $totalPasses = $format->getPasses(); | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-10 13:27:06 +02:00
										 |  |  |         if (1 > $totalPasses) { | 
					
						
							|  |  |  |             throw new InvalidArgumentException('Pass number should be a positive value.'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for ($i = 1; $i <= $totalPasses; $i++) { | 
					
						
							|  |  |  |             $pass = $commands; | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-10 13:27:06 +02:00
										 |  |  |             if ($totalPasses > 1) { | 
					
						
							|  |  |  |                 $pass[] = '-pass'; | 
					
						
							|  |  |  |                 $pass[] = $i; | 
					
						
							|  |  |  |                 $pass[] = '-passlogfile'; | 
					
						
							|  |  |  |                 $pass[] = $passPrefix; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-10 14:59:38 +02:00
										 |  |  |             $pass[] = $outputPathfile; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-10 13:27:06 +02:00
										 |  |  |             $passes[] = $pass; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $failure = null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-10 13:27:06 +02:00
										 |  |  |         foreach ($passes as $pass => $passCommands) { | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |             try { | 
					
						
							|  |  |  |                 /** add listeners here */ | 
					
						
							|  |  |  |                 $listeners = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if ($format instanceof ProgressableInterface) { | 
					
						
							| 
									
										
										
										
											2013-10-10 13:27:06 +02:00
										 |  |  |                     $listeners = $format->createProgressListener($this, $this->ffprobe, $pass + 1, $totalPasses); | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 $this->driver->command($passCommands, false, $listeners); | 
					
						
							|  |  |  |             } catch (ExecutionFailureException $e) { | 
					
						
							|  |  |  |                 $failure = $e; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-10 13:27:06 +02:00
										 |  |  |         $fs->clean($fsId); | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (null !== $failure) { | 
					
						
							|  |  |  |             throw new RuntimeException('Encoding failed', $failure->getCode(), $failure); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2013-06-25 10:40:20 +02:00
										 |  |  |      * Gets the frame at timecode. | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2013-06-26 15:17:16 +02:00
										 |  |  |      * @param  TimeCode $at | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * @return Frame | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2013-06-26 15:17:16 +02:00
										 |  |  |     public function frame(TimeCode $at) | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-09-04 19:50:38 +02:00
										 |  |  |         return new Frame($this, $this->driver, $this->ffprobe, $at); | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } |